From 73c1a577b83999f3bd208bbc6955f21d82b7f9ac Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Mon, 15 Apr 2019 10:13:49 -0400 Subject: media: atmel: atmel-isc: reworked white balance feature Reworked auto white balance feature (awb) to cope with all four channels. Implemented stretching and grey world algorithms. Using the histogram, the ISC will auto adjust the white balance during frame captures. Because each histogram needs a frame, it will take 4 frames for one adjustment. When the gains were updated by previous code, the registers for the gains were updated only on new streaming start. Now, after each full histogram the registers are updated with new gains. Also, on previous code, if the streaming stopped but not all 3 histograms finished, a new histogram was started either way. This used to lead to an error "timeout to update profile" when streaming was stopped. According to the hardware, histogram can only work together with the capture, not independently. Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-regs.h | 6 +- drivers/media/platform/atmel/atmel-isc.c | 200 +++++++++++++++++++++++--- 2 files changed, 181 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 8f7f8efc71a7..c1283fb21bf6 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -100,13 +100,15 @@ #define ISC_WB_O_RGR 0x00000060 /* ISC White Balance Offset for B, GB Register */ -#define ISC_WB_O_BGR 0x00000064 +#define ISC_WB_O_BGB 0x00000064 /* ISC White Balance Gain for R, GR Register */ #define ISC_WB_G_RGR 0x00000068 /* ISC White Balance Gain for B, GB Register */ -#define ISC_WB_G_BGR 0x0000006c +#define ISC_WB_G_BGB 0x0000006c + +#define ISC_WB_O_ZERO_VAL (1 << 13) /* ISC Color Filter Array Control Register */ #define ISC_CFA_CTRL 0x00000070 diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 94cb309fdb52..0ac595347573 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -169,13 +169,17 @@ struct isc_ctrls { u8 gamma_index; u8 awb; - u32 r_gain; - u32 b_gain; + /* one for each component : GR, R, GB, B */ + u32 gain[HIST_BAYER]; + u32 offset[HIST_BAYER]; u32 hist_entry[HIST_ENTRIES]; u32 hist_count[HIST_BAYER]; u8 hist_id; u8 hist_stat; +#define HIST_MIN_INDEX 0 +#define HIST_MAX_INDEX 1 + u32 hist_minmax[HIST_BAYER][2]; }; #define ISC_PIPE_LINE_NODE_NUM 11 @@ -209,6 +213,7 @@ struct isc_device { struct work_struct awb_work; struct mutex lock; + spinlock_t awb_lock; struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; @@ -395,6 +400,40 @@ module_param(sensor_preferred, uint, 0644); MODULE_PARM_DESC(sensor_preferred, "Sensor is preferred to output the specified format (1-on 0-off), default 1"); +static inline void isc_update_awb_ctrls(struct isc_device *isc) +{ + struct isc_ctrls *ctrls = &isc->ctrls; + + regmap_write(isc->regmap, ISC_WB_O_RGR, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); + regmap_write(isc->regmap, ISC_WB_O_BGB, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); + regmap_write(isc->regmap, ISC_WB_G_RGR, + ctrls->gain[ISC_HIS_CFG_MODE_R] | + (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); + regmap_write(isc->regmap, ISC_WB_G_BGB, + ctrls->gain[ISC_HIS_CFG_MODE_B] | + (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); +} + +static inline void isc_reset_awb_ctrls(struct isc_device *isc) +{ + int c; + + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* gains have a fixed point at 9 decimals */ + isc->ctrls.gain[c] = 1 << 9; + /* offsets are in 2's complements, the value + * will be substracted from ISC_WB_O_ZERO_VAL to obtain + * 2's complement of a value between 0 and + * ISC_WB_O_ZERO_VAL >> 1 + */ + isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; + } +} + static int isc_wait_clk_stable(struct clk_hw *hw) { struct isc_clk *isc_clk = to_isc_clk(hw); @@ -775,7 +814,9 @@ static void isc_start_dma(struct isc_device *isc) dctrl_dview = isc->config.dctrl_dview; regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); + spin_lock(&isc->awb_lock); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); + spin_unlock(&isc->awb_lock); } static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) @@ -797,11 +838,11 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) bay_cfg = isc->config.sd_format->cfa_baycfg; + if (!ctrls->awb) + isc_reset_awb_ctrls(isc); + regmap_write(regmap, ISC_WB_CFG, bay_cfg); - regmap_write(regmap, ISC_WB_O_RGR, 0x0); - regmap_write(regmap, ISC_WB_O_BGR, 0x0); - regmap_write(regmap, ISC_WB_G_RGR, ctrls->r_gain | (0x1 << 25)); - regmap_write(regmap, ISC_WB_G_BGR, ctrls->b_gain | (0x1 << 25)); + isc_update_awb_ctrls(isc); regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); @@ -851,13 +892,13 @@ static void isc_set_histogram(struct isc_device *isc, bool enable) if (enable) { regmap_write(regmap, ISC_HIS_CFG, - ISC_HIS_CFG_MODE_R | + ISC_HIS_CFG_MODE_GR | (isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) | ISC_HIS_CFG_RAR); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); - ctrls->hist_id = ISC_HIS_CFG_MODE_R; + ctrls->hist_id = ISC_HIS_CFG_MODE_GR; isc_update_profile(isc); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); @@ -900,7 +941,7 @@ static int isc_configure(struct isc_device *isc) isc_set_pipeline(isc, pipeline); /* - * The current implemented histogram is available for RAW R, B, GB + * The current implemented histogram is available for RAW R, B, GB, GR * channels. We need to check if sensor is outputting RAW BAYER */ if (isc->ctrls.awb && @@ -1475,6 +1516,12 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) return ret; isc->fmt = *f; + + if (isc->try_config.sd_format && isc->config.sd_format && + isc->try_config.sd_format != isc->config.sd_format) { + isc->ctrls.hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); + } /* make the try configuration active */ isc->config = isc->try_config; @@ -1758,7 +1805,7 @@ static irqreturn_t isc_interrupt(int irq, void *dev_id) return ret; } -static void isc_hist_count(struct isc_device *isc) +static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; @@ -1766,25 +1813,99 @@ static void isc_hist_count(struct isc_device *isc) u32 *hist_entry = &ctrls->hist_entry[0]; u32 i; + *min = 0; + *max = HIST_ENTRIES; + regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); *hist_count = 0; - for (i = 0; i < HIST_ENTRIES; i++) + /* + * we deliberately ignore the end of the histogram, + * the most white pixels + */ + for (i = 1; i < HIST_ENTRIES; i++) { + if (*hist_entry && !*min) + *min = i; + if (*hist_entry) + *max = i; *hist_count += i * (*hist_entry++); + } + + if (!*min) + *min = 1; } static void isc_wb_update(struct isc_ctrls *ctrls) { u32 *hist_count = &ctrls->hist_count[0]; - u64 g_count = (u64)hist_count[ISC_HIS_CFG_MODE_GB] << 9; - u32 hist_r = hist_count[ISC_HIS_CFG_MODE_R]; - u32 hist_b = hist_count[ISC_HIS_CFG_MODE_B]; + u32 c, offset[4]; + u64 avg = 0; + /* We compute two gains, stretch gain and grey world gain */ + u32 s_gain[4], gw_gain[4]; - if (hist_r) - ctrls->r_gain = div_u64(g_count, hist_r); + /* + * According to Grey World, we need to set gains for R/B to normalize + * them towards the green channel. + * Thus we want to keep Green as fixed and adjust only Red/Blue + * Compute the average of the both green channels first + */ + avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + + (u64)hist_count[ISC_HIS_CFG_MODE_GB]; + avg >>= 1; + + /* Green histogram is null, nothing to do */ + if (!avg) + return; - if (hist_b) - ctrls->b_gain = div_u64(g_count, hist_b); + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* + * the color offset is the minimum value of the histogram. + * we stretch this color to the full range by substracting + * this value from the color component. + */ + offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; + /* + * The offset is always at least 1. If the offset is 1, we do + * not need to adjust it, so our result must be zero. + * the offset is computed in a histogram on 9 bits (0..512) + * but the offset in register is based on + * 12 bits pipeline (0..4096). + * we need to shift with the 3 bits that the histogram is + * ignoring + */ + ctrls->offset[c] = (offset[c] - 1) << 3; + + /* the offset is then taken and converted to 2's complements */ + if (!ctrls->offset[c]) + ctrls->offset[c] = ISC_WB_O_ZERO_VAL; + + /* + * the stretch gain is the total number of histogram bins + * divided by the actual range of color component (Max - Min) + * If we compute gain like this, the actual color component + * will be stretched to the full histogram. + * We need to shift 9 bits for precision, we have 9 bits for + * decimals + */ + s_gain[c] = (HIST_ENTRIES << 9) / + (ctrls->hist_minmax[c][HIST_MAX_INDEX] - + ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); + + /* + * Now we have to compute the gain w.r.t. the average. + * Add/lose gain to the component towards the average. + * If it happens that the component is zero, use the + * fixed point value : 1.0 gain. + */ + if (hist_count[c]) + gw_gain[c] = div_u64(avg << 9, hist_count[c]); + else + gw_gain[c] = 1 << 9; + + /* multiply both gains and adjust for decimals */ + ctrls->gain[c] = s_gain[c] * gw_gain[c]; + ctrls->gain[c] >>= 9; + } } static void isc_awb_work(struct work_struct *w) @@ -1795,27 +1916,56 @@ static void isc_awb_work(struct work_struct *w) struct isc_ctrls *ctrls = &isc->ctrls; u32 hist_id = ctrls->hist_id; u32 baysel; + unsigned long flags; + u32 min, max; + + /* streaming is not active anymore */ + if (isc->stop) + return; if (ctrls->hist_stat != HIST_ENABLED) return; - isc_hist_count(isc); + isc_hist_count(isc, &min, &max); + ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; + ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; if (hist_id != ISC_HIS_CFG_MODE_B) { hist_id++; } else { isc_wb_update(ctrls); - hist_id = ISC_HIS_CFG_MODE_R; + hist_id = ISC_HIS_CFG_MODE_GR; } ctrls->hist_id = hist_id; baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; + /* if no more auto white balance, reset controls. */ + if (!ctrls->awb) + isc_reset_awb_ctrls(isc); + pm_runtime_get_sync(isc->dev); + /* + * only update if we have all the required histograms and controls + * if awb has been disabled, we need to reset registers as well. + */ + if (hist_id == ISC_HIS_CFG_MODE_GR || !ctrls->awb) { + /* + * It may happen that DMA Done IRQ will trigger while we are + * updating white balance registers here. + * In that case, only parts of the controls have been updated. + * We can avoid that by locking the section. + */ + spin_lock_irqsave(&isc->awb_lock, flags); + isc_update_awb_ctrls(isc); + spin_unlock_irqrestore(&isc->awb_lock, flags); + } regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); isc_update_profile(isc); - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + /* if awb has been disabled, we don't need to start another histogram */ + if (ctrls->awb) + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); pm_runtime_put_sync(isc->dev); } @@ -1839,8 +1989,7 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_AUTO_WHITE_BALANCE: ctrls->awb = ctrl->val; if (ctrls->hist_stat != HIST_ENABLED) { - ctrls->r_gain = 0x1 << 9; - ctrls->b_gain = 0x1 << 9; + isc_reset_awb_ctrls(isc); } break; default: @@ -1862,11 +2011,15 @@ static int isc_ctrl_init(struct isc_device *isc) int ret; ctrls->hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); ret = v4l2_ctrl_handler_init(hdl, 4); if (ret < 0) return ret; + ctrls->brightness = 0; + ctrls->contrast = 256; + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); @@ -2034,6 +2187,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) /* Init video dma queues */ INIT_LIST_HEAD(&isc->dma_queue); spin_lock_init(&isc->dma_queue_lock); + spin_lock_init(&isc->awb_lock); ret = isc_formats_init(isc); if (ret < 0) { -- cgit v1.2.3-59-g8ed1b From a0816e5088baab82aa738d61a55513114a673c8e Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Mon, 15 Apr 2019 10:13:51 -0400 Subject: media: v4l2-ctrl: fix flags for DO_WHITE_BALANCE Control DO_WHITE_BALANCE is a button, with read only and execute-on-write flags. Adding this control in the proper list in the fill function. After adding it here, we can see output of v4l2-ctl -L do_white_balance 0x0098090d (button) : flags=write-only, execute-on-write Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 89a1fe564675..420e3fc237cd 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1157,6 +1157,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_FLASH_STROBE_STOP: case V4L2_CID_AUTO_FOCUS_START: case V4L2_CID_AUTO_FOCUS_STOP: + case V4L2_CID_DO_WHITE_BALANCE: *type = V4L2_CTRL_TYPE_BUTTON; *flags |= V4L2_CTRL_FLAG_WRITE_ONLY | V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; -- cgit v1.2.3-59-g8ed1b From 90a493a349177cf03070866b7bb3becd0aed7bf3 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Mon, 15 Apr 2019 10:13:54 -0400 Subject: media: atmel: atmel-isc: add support for DO_WHITE_BALANCE This adds support for the 'button' control DO_WHITE_BALANCE This feature will enable the ISC to compute the white balance coefficients in a one time shot, at the user discretion. This can be used if a color chart/grey chart is present in front of the camera. The ISC will adjust the coefficients and have them fixed until next balance or until sensor mode is changed. This is particularly useful for white balance adjustment in different lighting scenarios, and then taking photos to similar scenery. The old auto white balance stays in place, where the ISC will adjust every 4 frames to the current scenery lighting, if the scenery is approximately grey in average, otherwise grey world algorithm fails. One time white balance adjustments needs streaming to be enabled, such that capture is enabled and the histogram has data to work with. Histogram without capture does not work in this hardware module. To start the one time white balance procedure: v4l2-ctl --set-ctrl=do_white_balance=1 This feature works only if the sensor is streaming RAW data, as the hardware supports a histogram only for RAW bayer components. If the auto white balance is enabled, do_white_balance does nothing. If the streaming is disabled, or the sensor does not output RAW data, the control is inactive. User controls now include the do_white_balance ctrl: User Controls brightness 0x00980900 (int) : min=-1024 max=1023 step=1 default=0 value=0 flags=slider contrast 0x00980901 (int) : min=-2048 max=2047 step=1 default=256 value=256 flags=slider white_balance_automatic 0x0098090c (bool) : default=1 value=0 do_white_balance 0x0098090d (button) : flags=write-only, execute-on-write gamma 0x00980910 (int) : min=0 max=2 step=1 default=2 value=2 flags=slider Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 66 ++++++++++++++++++++++++++++---- 1 file changed, 59 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 0ac595347573..777e27f325f2 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -167,6 +167,9 @@ struct isc_ctrls { u32 brightness; u32 contrast; u8 gamma_index; +#define ISC_WB_NONE 0 +#define ISC_WB_AUTO 1 +#define ISC_WB_ONETIME 2 u8 awb; /* one for each component : GR, R, GB, B */ @@ -210,6 +213,7 @@ struct isc_device { struct fmt_config try_config; struct isc_ctrls ctrls; + struct v4l2_ctrl *do_wb_ctrl; struct work_struct awb_work; struct mutex lock; @@ -838,7 +842,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) bay_cfg = isc->config.sd_format->cfa_baycfg; - if (!ctrls->awb) + if (ctrls->awb == ISC_WB_NONE) isc_reset_awb_ctrls(isc); regmap_write(regmap, ISC_WB_CFG, bay_cfg); @@ -993,6 +997,10 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) spin_unlock_irqrestore(&isc->dma_queue_lock, flags); + /* if we streaming from RAW, we can do one-shot white balance adj */ + if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + v4l2_ctrl_activate(isc->do_wb_ctrl, true); + return 0; err_configure: @@ -1017,6 +1025,8 @@ static void isc_stop_streaming(struct vb2_queue *vq) struct isc_buffer *buf; int ret; + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + isc->stop = true; /* Wait until the end of the current frame */ @@ -1941,7 +1951,7 @@ static void isc_awb_work(struct work_struct *w) baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; /* if no more auto white balance, reset controls. */ - if (!ctrls->awb) + if (ctrls->awb == ISC_WB_NONE) isc_reset_awb_ctrls(isc); pm_runtime_get_sync(isc->dev); @@ -1950,7 +1960,7 @@ static void isc_awb_work(struct work_struct *w) * only update if we have all the required histograms and controls * if awb has been disabled, we need to reset registers as well. */ - if (hist_id == ISC_HIS_CFG_MODE_GR || !ctrls->awb) { + if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { /* * It may happen that DMA Done IRQ will trigger while we are * updating white balance registers here. @@ -1960,6 +1970,16 @@ static void isc_awb_work(struct work_struct *w) spin_lock_irqsave(&isc->awb_lock, flags); isc_update_awb_ctrls(isc); spin_unlock_irqrestore(&isc->awb_lock, flags); + + /* + * if we are doing just the one time white balance adjustment, + * we are basically done. + */ + if (ctrls->awb == ISC_WB_ONETIME) { + v4l2_info(&isc->v4l2_dev, + "Completed one time white-balance adjustment.\n"); + ctrls->awb = ISC_WB_NONE; + } } regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); isc_update_profile(isc); @@ -1976,6 +1996,9 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) struct isc_device, ctrls.handler); struct isc_ctrls *ctrls = &isc->ctrls; + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + switch (ctrl->id) { case V4L2_CID_BRIGHTNESS: ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; @@ -1987,10 +2010,33 @@ static int isc_s_ctrl(struct v4l2_ctrl *ctrl) ctrls->gamma_index = ctrl->val; break; case V4L2_CID_AUTO_WHITE_BALANCE: - ctrls->awb = ctrl->val; - if (ctrls->hist_stat != HIST_ENABLED) { + if (ctrl->val == 1) + ctrls->awb = ISC_WB_AUTO; + else + ctrls->awb = ISC_WB_NONE; + + /* we did not configure ISC yet */ + if (!isc->config.sd_format) + break; + + if (ctrls->hist_stat != HIST_ENABLED) isc_reset_awb_ctrls(isc); - } + + if (isc->ctrls.awb == ISC_WB_AUTO && + vb2_is_streaming(&isc->vb2_vidq) && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + + break; + case V4L2_CID_DO_WHITE_BALANCE: + /* if AWB is enabled, do nothing */ + if (ctrls->awb == ISC_WB_AUTO) + return 0; + + ctrls->awb = ISC_WB_ONETIME; + isc_set_histogram(isc, true); + v4l2_dbg(1, debug, &isc->v4l2_dev, + "One time white-balance started.\n"); break; default: return -EINVAL; @@ -2013,7 +2059,7 @@ static int isc_ctrl_init(struct isc_device *isc) ctrls->hist_stat = HIST_INIT; isc_reset_awb_ctrls(isc); - ret = v4l2_ctrl_handler_init(hdl, 4); + ret = v4l2_ctrl_handler_init(hdl, 5); if (ret < 0) return ret; @@ -2025,6 +2071,12 @@ static int isc_ctrl_init(struct isc_device *isc) v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + /* do_white_balance is a button, so min,max,step,default are ignored */ + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, + 0, 0, 0, 0); + + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + v4l2_ctrl_handler_setup(hdl); return 0; -- cgit v1.2.3-59-g8ed1b From 5490ba5645f27829e5c7f7c6fd3a9249cc14198e Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Mon, 15 Apr 2019 10:13:56 -0400 Subject: media: atmel: atmel-isc: make try_fmt error less verbose In case the sensor refuses to set the format, avoid printing the error message that no compatible format was found. This means that the try_fmt will be less verbose. The error will be printed only if really a format cannot be found. Some application try all possible formats in a row (gstreamer e.g.) which will flood the console with error messages until a working one is found. Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 777e27f325f2..da3b441e7961 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1487,7 +1487,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) - goto isc_try_fmt_err; + goto isc_try_fmt_subdev_err; v4l2_fill_pix_format(pixfmt, &format.format); @@ -1502,6 +1502,7 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, isc_try_fmt_err: v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); +isc_try_fmt_subdev_err: memset(&isc->try_config, 0, sizeof(isc->try_config)); return ret; -- cgit v1.2.3-59-g8ed1b From 31e71dbcc1fd57eaccc1010c9078d03c642d5cd1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:23 -0400 Subject: media: coda: move register debugging to coda_debug level 3 This allows to use coda_debug level 2 for verbose but not quite as verbose debug logging. Register access level logging is of limited use anyway, as this includes busy polling of status bits. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 1d96cca61547..c263be0b45e7 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -78,7 +78,7 @@ MODULE_PARM_DESC(enable_bwb, "Enable BWB unit for decoding, may crash on certain void coda_write(struct coda_dev *dev, u32 data, u32 reg) { - v4l2_dbg(2, coda_debug, &dev->v4l2_dev, + v4l2_dbg(3, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); writel(data, dev->regs_base + reg); } @@ -88,7 +88,7 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg) u32 data; data = readl(dev->regs_base + reg); - v4l2_dbg(2, coda_debug, &dev->v4l2_dev, + v4l2_dbg(3, coda_debug, &dev->v4l2_dev, "%s: data=0x%x, reg=0x%x\n", __func__, data, reg); return data; } -- cgit v1.2.3-59-g8ed1b From 736a33d2054659765e809711c74809e736d9e12e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:24 -0400 Subject: media: coda: move job ready message to coda_debug level 2 Use the newly freed verbose debug level 2 for job ready debug messages. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index c263be0b45e7..1c2181d3fe04 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1416,7 +1416,7 @@ static int coda_job_ready(void *m2m_priv) return 0; } - coda_dbg(1, ctx, "job ready\n"); + coda_dbg(2, ctx, "job ready\n"); return 1; } -- cgit v1.2.3-59-g8ed1b From 8e7479c7e72586497713b584c0f3258422152f03 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:25 -0400 Subject: media: coda: add coda_frame_type_char helper Add a function to translate from V4L2 buffer flags to 'I'/'P'/'B' characters for debug output. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index eaa86737fa04..a0dbee2262e9 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1456,6 +1456,13 @@ static int coda_prepare_encode(struct coda_ctx *ctx) return 0; } +static char coda_frame_type_char(u32 flags) +{ + return (flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : + (flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : + (flags & V4L2_BUF_FLAG_BFRAME) ? 'B' : '?'; +} + static void coda_finish_encode(struct coda_ctx *ctx) { struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -1512,8 +1519,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) ctx->gopcounter = ctx->params.gop_size - 1; coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n", - (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : 'P', - dst_buf->sequence); + coda_frame_type_char(dst_buf->flags), dst_buf->sequence); } static void coda_seq_end_work(struct work_struct *work) @@ -2241,8 +2247,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n", - (dst_buf->flags & V4L2_BUF_FLAG_KEYFRAME) ? 'I' : - ((dst_buf->flags & V4L2_BUF_FLAG_PFRAME) ? 'P' : 'B'), + coda_frame_type_char(dst_buf->flags), dst_buf->sequence, ctx->qsequence); } else { coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n", -- cgit v1.2.3-59-g8ed1b From e94bb8d269ff2d81b319f25db888a91621e2af71 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:26 -0400 Subject: media: coda: improve decoder job finished debug message Print a single line containing the following information: - which frame was decoded, including its type, - if no frame was decoded, the reason (code) why - which decoded frame was returned, copied out by either rotator or VODA, - if no frame was returned, the reason (code) why, and - the output queue sequence number, which is only useful in case each queued coded buffer corresponds to exactly one frame. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index a0dbee2262e9..228743b82ace 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2246,12 +2246,36 @@ static void coda_finish_decode(struct coda_ctx *ctx) else coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); - coda_dbg(1, ctx, "job finished: decoded %c frame (%u/%u)\n", - coda_frame_type_char(dst_buf->flags), - dst_buf->sequence, ctx->qsequence); + if (decoded_idx >= 0 && + decoded_idx < ctx->num_internal_frames) { + coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", + coda_frame_type_char(ctx->frame_types[decoded_idx]), + ctx->frame_metas[decoded_idx].sequence, + coda_frame_type_char(dst_buf->flags), + ctx->frame_metas[ctx->display_idx].sequence, + dst_buf->sequence, ctx->qsequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? + " (last)" : ""); + } else { + coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", + decoded_idx, + coda_frame_type_char(dst_buf->flags), + ctx->frame_metas[ctx->display_idx].sequence, + dst_buf->sequence, ctx->qsequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? + " (last)" : ""); + } } else { - coda_dbg(1, ctx, "job finished: no frame decoded (%u/%u)\n", - ctx->osequence, ctx->qsequence); + if (decoded_idx >= 0 && + decoded_idx < ctx->num_internal_frames) { + coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", + coda_frame_type_char(ctx->frame_types[decoded_idx]), + ctx->frame_metas[decoded_idx].sequence, + ctx->display_idx); + } else { + coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", + decoded_idx, ctx->display_idx); + } } /* The rotator will copy the current display frame next time */ -- cgit v1.2.3-59-g8ed1b From 74135fb1847dbf2c6564c820add9d5bbecf4f6d2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:27 -0400 Subject: media: coda: demote s_ctrl debug messages to level 2 Otherwise the default initialization would always swamp the debug log. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 1c2181d3fe04..15d49de6becb 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1860,7 +1860,7 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) struct coda_ctx *ctx = container_of(ctrl->handler, struct coda_ctx, ctrls); - coda_dbg(1, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", ctrl->id, ctrl->name, ctrl->val); switch (ctrl->id) { -- cgit v1.2.3-59-g8ed1b From 8a618957257aba5c42ea04c828d8bc6525ebd494 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:28 -0400 Subject: media: coda: add menu strings to s_ctrl debug output When a menu control is updated via s_ctrl, print the corresponding menu entry string in addition to the numerical value it is set to. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 15d49de6becb..171a3db72b30 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1857,11 +1857,16 @@ static const struct vb2_ops coda_qops = { static int coda_s_ctrl(struct v4l2_ctrl *ctrl) { + const char * const *val_names = v4l2_ctrl_get_menu(ctrl->id); struct coda_ctx *ctx = container_of(ctrl->handler, struct coda_ctx, ctrls); - coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", - ctrl->id, ctrl->name, ctrl->val); + if (val_names) + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d (\"%s\")\n", + ctrl->id, ctrl->name, ctrl->val, val_names[ctrl->val]); + else + coda_dbg(2, ctx, "s_ctrl: id = 0x%x, name = \"%s\", val = %d\n", + ctrl->id, ctrl->name, ctrl->val); switch (ctrl->id) { case V4L2_CID_HFLIP: -- cgit v1.2.3-59-g8ed1b From e45cf927f3a5fb2072e2e804b25592fb67448190 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:29 -0400 Subject: media: coda: update profile and level controls after sequence initialization The header report return value from decoder sequence initialization is available on CodaHx4 and CODA7541 already. Use the profile and level identification values reported by the firmware to update codec specific profile and level controls after sequence initialization has succeeded. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 11 ++++++ drivers/media/platform/coda/coda-common.c | 66 ++++++++++++++++++------------- drivers/media/platform/coda/coda.h | 3 ++ drivers/media/platform/coda/coda_regs.h | 2 +- 4 files changed, 54 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 228743b82ace..d774a5aaa422 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1814,6 +1814,17 @@ static int __coda_start_decoding(struct coda_ctx *ctx) (top_bottom & 0x3ff); } + if (dev->devtype->product != CODA_DX6) { + u8 profile, level; + + val = coda_read(dev, CODA7_RET_DEC_SEQ_HEADER_REPORT); + profile = val & 0xff; + level = (val >> 8) & 0x7f; + + if (profile || level) + coda_update_profile_level_ctrls(ctx, profile, level); + } + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 171a3db72b30..1856b782fdde 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1567,42 +1567,53 @@ static void coda_update_menu_ctrl(struct v4l2_ctrl *ctrl, int value) v4l2_ctrl_unlock(ctrl); } -static void coda_update_h264_profile_ctrl(struct coda_ctx *ctx) +void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, + u8 level_idc) { const char * const *profile_names; + const char * const *level_names; + struct v4l2_ctrl *profile_ctrl; + struct v4l2_ctrl *level_ctrl; + const char *codec_name; + u32 profile_cid; + u32 level_cid; int profile; + int level; - profile = coda_h264_profile(ctx->params.h264_profile_idc); - if (profile < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Profile: %u\n", - ctx->params.h264_profile_idc); + switch (ctx->codec->src_fourcc) { + case V4L2_PIX_FMT_H264: + codec_name = "H264"; + profile_cid = V4L2_CID_MPEG_VIDEO_H264_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_H264_LEVEL; + profile_ctrl = ctx->h264_profile_ctrl; + level_ctrl = ctx->h264_level_ctrl; + profile = coda_h264_profile(profile_idc); + level = coda_h264_level(level_idc); + break; + default: return; } - coda_update_menu_ctrl(ctx->h264_profile_ctrl, profile); - - profile_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_PROFILE); + profile_names = v4l2_ctrl_get_menu(profile_cid); + level_names = v4l2_ctrl_get_menu(level_cid); - coda_dbg(1, ctx, "Parsed H264 Profile: %s\n", profile_names[profile]); -} - -static void coda_update_h264_level_ctrl(struct coda_ctx *ctx) -{ - const char * const *level_names; - int level; + if (profile < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s profile: %u\n", + codec_name, profile_idc); + } else { + coda_dbg(1, ctx, "Parsed %s profile: %s\n", codec_name, + profile_names[profile]); + coda_update_menu_ctrl(profile_ctrl, profile); + } - level = coda_h264_level(ctx->params.h264_level_idc); if (level < 0) { - v4l2_warn(&ctx->dev->v4l2_dev, "Invalid H264 Level: %u\n", - ctx->params.h264_level_idc); - return; + v4l2_warn(&ctx->dev->v4l2_dev, "Invalid %s level: %u\n", + codec_name, level_idc); + } else { + coda_dbg(1, ctx, "Parsed %s level: %s\n", codec_name, + level_names[level]); + coda_update_menu_ctrl(level_ctrl, level); } - - coda_update_menu_ctrl(ctx->h264_level_ctrl, level); - - level_names = v4l2_ctrl_get_menu(V4L2_CID_MPEG_VIDEO_H264_LEVEL); - - coda_dbg(1, ctx, "Parsed H264 Level: %s\n", level_names[level]); } static void coda_buf_queue(struct vb2_buffer *vb) @@ -1635,8 +1646,9 @@ static void coda_buf_queue(struct vb2_buffer *vb) */ if (!ctx->params.h264_profile_idc) { coda_sps_parse_profile(ctx, vb); - coda_update_h264_profile_ctrl(ctx); - coda_update_h264_level_ctrl(ctx); + coda_update_profile_level_ctrls(ctx, + ctx->params.h264_profile_idc, + ctx->params.h264_level_idc); } } diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 31c80bda2c0b..1c822dfdb3ce 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -328,6 +328,9 @@ int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, int *size, int max_size); +void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, + u8 level_idc); + bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_jpeg_write_tables(struct coda_ctx *ctx); void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality); diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index e675e38f3475..35cec9f83085 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -181,7 +181,7 @@ #define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8 #define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4 #define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8 -#define CODA9_RET_DEC_SEQ_HEADER_REPORT 0x1ec +#define CODA7_RET_DEC_SEQ_HEADER_REPORT 0x1ec /* Decoder Picture Run */ #define CODA_CMD_DEC_PIC_ROT_MODE 0x180 -- cgit v1.2.3-59-g8ed1b From a132459d400908434a12812b8331a34d85585fa7 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 26 Feb 2019 03:17:46 -0500 Subject: media: venus: core: fix max load for msm8996 and sdm845 Patch commit de5a0bafcfc4 ("media: venus: core: correct maximum hardware load for sdm845") meant to increase the maximum hardware load for sdm845, but ended up changing the one for msm8996 instead. Fixes: de5a0bafcfc4 ("media: venus: core: correct maximum hardware load for sdm845") Signed-off-by: Alexandre Courbot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index 739366744e0f..435c7b68bbed 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -455,7 +455,7 @@ static const struct venus_resources msm8996_res = { .reg_tbl_size = ARRAY_SIZE(msm8996_reg_preset), .clks = {"core", "iface", "bus", "mbus" }, .clks_num = 4, - .max_load = 3110400, /* 4096x2160@90 */ + .max_load = 2563200, .hfi_version = HFI_VERSION_3XX, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, @@ -478,7 +478,7 @@ static const struct venus_resources sdm845_res = { .freq_tbl_size = ARRAY_SIZE(sdm845_freq_table), .clks = {"core", "iface", "bus" }, .clks_num = 3, - .max_load = 2563200, + .max_load = 3110400, /* 4096x2160@90 */ .hfi_version = HFI_VERSION_4XX, .vmem_id = VIDC_RESOURCE_NONE, .vmem_size = 0, -- cgit v1.2.3-59-g8ed1b From cd396c8cbfcdd75a4ff2681493be7017f6f60e6e Mon Sep 17 00:00:00 2001 From: Kelvin Lawson Date: Mon, 10 Dec 2018 09:11:45 -0500 Subject: media: venus: Add support for H265 controls Add support for V4L2 H265 controls: * V4L2_CID_MPEG_VIDEO_HEVC_PROFILE * V4L2_CID_MPEG_VIDEO_HEVC_LEVEL Signed-off-by: Kelvin Lawson Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/venc_ctrls.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index ac1e1d26f341..bd4538accf13 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -117,6 +117,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_PROFILE: ctr->profile.h264 = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE: + ctr->profile.hevc = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: ctr->profile.vpx = ctrl->val; break; @@ -126,6 +129,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_H264_LEVEL: ctr->level.h264 = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL: + ctr->level.hevc = ctrl->val; + break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ctr->h264_i_qp = ctrl->val; break; @@ -217,7 +223,7 @@ int venc_ctrl_init(struct venus_inst *inst) { int ret; - ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 28); + ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 30); if (ret) return ret; @@ -245,6 +251,19 @@ int venc_ctrl_init(struct venus_inst *inst) V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0); + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_PROFILE, + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10, + ~((1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE) | + (1 << V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10)), + V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN); + + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, + V4L2_CID_MPEG_VIDEO_HEVC_LEVEL, + V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2, + 0, V4L2_MPEG_VIDEO_HEVC_LEVEL_1); + v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH, -- cgit v1.2.3-59-g8ed1b From 3d7f0d7126e0f3695a5f743d5e7b8d9deecad651 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Tue, 15 Jan 2019 12:12:57 -0500 Subject: media: venus: hfi_cmds: add more not-implemented properties Add two more not-implemented properties for Venus v4. Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/hfi_cmds.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c index 87a441488e15..faf1ca0d0db4 100644 --- a/drivers/media/platform/qcom/venus/hfi_cmds.c +++ b/drivers/media/platform/qcom/venus/hfi_cmds.c @@ -1214,6 +1214,8 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt, break; } case HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE: + case HFI_PROPERTY_CONFIG_VDEC_POST_LOOP_DEBLOCKER: + case HFI_PROPERTY_PARAM_BUFFER_ALLOC_MODE: /* not implemented on Venus 4xx */ return -ENOTSUPP; default: -- cgit v1.2.3-59-g8ed1b From bc8c479a5b19bd44f7379e42e627170957985ee9 Mon Sep 17 00:00:00 2001 From: Stanimir Varbanov Date: Wed, 16 Jan 2019 05:08:28 -0500 Subject: media: venus: helpers: fix dynamic buffer mode for v4 Venus v4 doesn't send ALLOC_MODE property and thus parser doesn't recognize it as dynamic buffer (for OUTPUT/OUTPUT2 type of buffers) make it obvious in the helper function. Signed-off-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/helpers.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c index 5cad601d4c57..86105de81af2 100644 --- a/drivers/media/platform/qcom/venus/helpers.c +++ b/drivers/media/platform/qcom/venus/helpers.c @@ -467,6 +467,13 @@ static bool is_dynamic_bufmode(struct venus_inst *inst) struct venus_core *core = inst->core; struct venus_caps *caps; + /* + * v4 doesn't send BUFFER_ALLOC_MODE_SUPPORTED property and supports + * dynamic buffer mode by default for HFI_BUFFER_OUTPUT/OUTPUT2. + */ + if (IS_V4(core)) + return true; + caps = venus_caps_by_codec(core, inst->hfi_codec, inst->session_type); if (!caps) return false; -- cgit v1.2.3-59-g8ed1b From 4a0bbf4815f168b2097d394257eef052c0ea928a Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 20 Dec 2018 13:54:44 -0500 Subject: media: si2168: add frequency data to frontend info Minimum, maximum, and stepsize taken from Silicon Labs reference. Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/si2168.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 324493e05f9f..17301c6701d4 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -683,8 +683,11 @@ static const struct dvb_frontend_ops si2168_ops = { .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, .info = { .name = "Silicon Labs Si2168", - .symbol_rate_min = 1000000, - .symbol_rate_max = 7200000, + .frequency_min_hz = 48 * MHz, + .frequency_max_hz = 870 * MHz, + .frequency_stepsize_hz = 62500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 7200000, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | -- cgit v1.2.3-59-g8ed1b From 24e4cf770371df6ad49ed873f21618d9878f64c8 Mon Sep 17 00:00:00 2001 From: Daniel Gomez Date: Mon, 22 Apr 2019 15:10:20 -0400 Subject: media: spi: IR LED: add missing of table registration MODULE_DEVICE_TABLE(of, should be called to complete DT OF mathing mechanism and register it. Before this patch: modinfo drivers/media/rc/ir-spi.ko | grep alias After this patch: modinfo drivers/media/rc/ir-spi.ko | grep alias alias: of:N*T*Cir-spi-ledC* alias: of:N*T*Cir-spi-led Reported-by: Javier Martinez Canillas Signed-off-by: Daniel Gomez Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-spi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index 66334e8d63ba..c58f2d38a458 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -161,6 +161,7 @@ static const struct of_device_id ir_spi_of_match[] = { { .compatible = "ir-spi-led" }, {}, }; +MODULE_DEVICE_TABLE(of, ir_spi_of_match); static struct spi_driver ir_spi_driver = { .probe = ir_spi_probe, -- cgit v1.2.3-59-g8ed1b From 6cf97230cd5f36b7665099083272595c55d72be7 Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 30 Apr 2019 09:07:36 -0400 Subject: media: dvb: usb: fix use after free in dvb_usb_device_exit dvb_usb_device_exit() frees and uses the device name in that order. Fix by storing the name in a buffer before freeing it. Signed-off-by: Oliver Neukum Reported-by: syzbot+26ec41e9f788b3eba396@syzkaller.appspotmail.com Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dvb-usb-init.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index 99951e02a880..dd063a736df5 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -287,12 +287,15 @@ EXPORT_SYMBOL(dvb_usb_device_init); void dvb_usb_device_exit(struct usb_interface *intf) { struct dvb_usb_device *d = usb_get_intfdata(intf); - const char *name = "generic DVB-USB module"; + const char *default_name = "generic DVB-USB module"; + char name[40]; usb_set_intfdata(intf, NULL); if (d != NULL && d->desc != NULL) { - name = d->desc->name; + strscpy(name, d->desc->name, sizeof(name)); dvb_usb_exit(d); + } else { + strscpy(name, default_name, sizeof(name)); } info("%s successfully deinitialized and disconnected.", name); -- cgit v1.2.3-59-g8ed1b From 6d0d1ff9ff21fbb06b867c13a1d41ce8ddcd8230 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sun, 19 May 2019 15:28:22 -0400 Subject: media: au0828: fix null dereference in error path au0828_usb_disconnect() gets the au0828_dev struct via usb_get_intfdata, so it needs to set up for the error paths. Reported-by: syzbot+357d86bcb4cca1a2f572@syzkaller.appspotmail.com Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 925a80437822..e306d5d5bebb 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -729,6 +729,12 @@ static int au0828_usb_probe(struct usb_interface *interface, /* Setup */ au0828_card_setup(dev); + /* + * Store the pointer to the au0828_dev so it can be accessed in + * au0828_usb_disconnect + */ + usb_set_intfdata(interface, dev); + /* Analog TV */ retval = au0828_analog_register(dev, interface); if (retval) { @@ -747,12 +753,6 @@ static int au0828_usb_probe(struct usb_interface *interface, /* Remote controller */ au0828_rc_register(dev); - /* - * Store the pointer to the au0828_dev so it can be accessed in - * au0828_usb_disconnect - */ - usb_set_intfdata(interface, dev); - pr_info("Registered device AU0828 [%s]\n", dev->board.name == NULL ? "Unset" : dev->board.name); -- cgit v1.2.3-59-g8ed1b From dd5f551b58a8b557fd7fc93f238dc0dc29526e32 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Sun, 19 May 2019 07:18:29 -0400 Subject: media: dvb-usb-v2: Report error on all error paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit actual_length != wlen is the only error path which does not generate an error message. Adding an error message here allows to report a more specific error and to remove the error reporting from the call sites. Also clean up the error paths - in case of an error, the remaining code is skipped, and ret is returned. Skip setting ret and return immediately (no cleanup necessary). Signed-off-by: Stefan Brüns Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c index 5bafeb6486be..6d43cf496458 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_urb.c @@ -37,14 +37,19 @@ static int dvb_usb_v2_generic_io(struct dvb_usb_device *d, ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev, d->props->generic_bulk_ctrl_endpoint), wbuf, wlen, &actual_length, 2000); - if (ret < 0) + if (ret) { dev_err(&d->udev->dev, "%s: usb_bulk_msg() failed=%d\n", KBUILD_MODNAME, ret); - else - ret = actual_length != wlen ? -EIO : 0; + return ret; + } + if (actual_length != wlen) { + dev_err(&d->udev->dev, "%s: usb_bulk_msg() write length=%d, actual=%d\n", + KBUILD_MODNAME, wlen, actual_length); + return -EIO; + } - /* an answer is expected, and no error before */ - if (!ret && rbuf && rlen) { + /* an answer is expected */ + if (rbuf && rlen) { if (d->props->generic_bulk_ctrl_delay) usleep_range(d->props->generic_bulk_ctrl_delay, d->props->generic_bulk_ctrl_delay -- cgit v1.2.3-59-g8ed1b From fec2e415cb18f98c736539e0f971e93a0598c1b2 Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Sun, 19 May 2019 07:18:30 -0400 Subject: media: dvbsky: Remove duplicate error reporting for dvbsky_usb_generic_rw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Errors are already reported by the common code in dvb_usb_v2_generic_io (which dvbsky_usb_generic_rw is a wrapper of), so there is no reason report the error again. Signed-off-by: Stefan Brüns Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/dvbsky.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index ae0814dd202a..3ff9833597e5 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -100,8 +100,6 @@ static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value) obuf[1] = gport; obuf[2] = value; ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); return ret; } @@ -139,8 +137,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[3] = msg[0].addr; ret = dvbsky_usb_generic_rw(d, obuf, 4, ibuf, msg[0].len + 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); if (!ret) memcpy(msg[0].buf, &ibuf[1], msg[0].len); } else { @@ -151,8 +147,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(&obuf[3], msg[0].buf, msg[0].len); ret = dvbsky_usb_generic_rw(d, obuf, msg[0].len + 3, ibuf, 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); } } else { if ((msg[0].len > 60) || (msg[1].len > 60)) { @@ -170,9 +164,6 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(&obuf[4], msg[0].buf, msg[0].len); ret = dvbsky_usb_generic_rw(d, obuf, msg[0].len + 4, ibuf, msg[1].len + 1); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); - if (!ret) memcpy(msg[1].buf, &ibuf[1], msg[1].len); } @@ -201,8 +192,6 @@ static int dvbsky_rc_query(struct dvb_usb_device *d) obuf[0] = 0x10; ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2); - if (ret) - dev_err(&d->udev->dev, "failed=%d\n", ret); if (ret == 0) code = (ibuf[0] << 8) | ibuf[1]; if (code != 0xffff) { -- cgit v1.2.3-59-g8ed1b From f16888a3e8a91af44329414c125e5a95660f567e Mon Sep 17 00:00:00 2001 From: Stefan Brüns Date: Sun, 19 May 2019 07:18:31 -0400 Subject: media: af9035: Remove duplicate error reporting for dvbsky_usb_generic_rw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All error cases inside the function already report errors via dev_err(), and dvb_usb_v2_generic_rw also reports all error cases, so there is no silent code path when an error has occurred. Signed-off-by: Stefan Brüns Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/af9035.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 1b7f1af399fb..15643e2f9395 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -120,8 +120,6 @@ static int af9035_ctrl_msg(struct dvb_usb_device *d, struct usb_req *req) memcpy(req->rbuf, &state->buf[ACK_HDR_LEN], req->rlen); exit: mutex_unlock(&d->usb_mutex); - if (ret < 0) - dev_dbg(&intf->dev, "failed=%d\n", ret); return ret; } -- cgit v1.2.3-59-g8ed1b From 9390467c2d3bd19778ec23b39dde5424151ec37d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Mon, 20 May 2019 10:03:43 -0400 Subject: media: rc: meson-ir: update with SPDX Licence identifier Remove comment and replace with the appropriate SPDX identifier. Signed-off-by: Neil Armstrong Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 9914c83fecb9..02914da8cce5 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -1,14 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Driver for Amlogic Meson IR remote receiver * * Copyright (C) 2014 Beniamino Galvani - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ #include -- cgit v1.2.3-59-g8ed1b From 354cf00339b12da6e685770e9e411ebe05d3e3a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 10 May 2019 11:15:04 -0400 Subject: media: cec: mark devnode as registered before actually registering it The cec device node can be used right after it was created, but that leaves a race condition where the device was created, but devnode->registered was still false. So an ioctl() would result in an error. So set it to true before calling cdev_device_add() and to false again if cdev_device_add returned an error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index f5d1578e256a..db7adffcdc76 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -128,13 +128,14 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, devnode->cdev.owner = owner; kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); + devnode->registered = true; ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret) { + devnode->registered = false; pr_err("%s: cdev_device_add failed\n", __func__); goto clr_bit; } - devnode->registered = true; return 0; clr_bit: -- cgit v1.2.3-59-g8ed1b From 00ccd263ee085c7428e2a1102c2f39e4a6927978 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 20 May 2019 10:38:40 -0400 Subject: media: cec-gpio: use disable/enable_irq Due to limitations in gpiolib it was impossible to disable the interrupt of an input gpio and then switch it to gpio output and drive it. The only way to achieve that was to free the interrupt first, then switch the direction. When going back to gpio input and using interrupts to read the gpio pin you had to request the irq again. This limitation was lifted in gpiolib in kernel 4.20, but the cec-gpio driver was still using the old workaround implementation. This patch updates the cec-gpio driver to just enable and disable the irq. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/cec-gpio/cec-gpio.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/cec-gpio/cec-gpio.c b/drivers/media/platform/cec-gpio/cec-gpio.c index d2861749d640..5b17d3a31896 100644 --- a/drivers/media/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/platform/cec-gpio/cec-gpio.c @@ -17,7 +17,6 @@ struct cec_gpio { struct gpio_desc *cec_gpio; int cec_irq; bool cec_is_low; - bool cec_have_irq; struct gpio_desc *hpd_gpio; int hpd_irq; @@ -55,9 +54,6 @@ static void cec_gpio_low(struct cec_adapter *adap) if (cec->cec_is_low) return; - if (WARN_ON_ONCE(cec->cec_have_irq)) - free_irq(cec->cec_irq, cec); - cec->cec_have_irq = false; cec->cec_is_low = true; gpiod_set_value(cec->cec_gpio, 0); } @@ -114,14 +110,7 @@ static bool cec_gpio_enable_irq(struct cec_adapter *adap) { struct cec_gpio *cec = cec_get_drvdata(adap); - if (cec->cec_have_irq) - return true; - - if (request_irq(cec->cec_irq, cec_gpio_irq_handler, - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, - adap->name, cec)) - return false; - cec->cec_have_irq = true; + enable_irq(cec->cec_irq); return true; } @@ -129,9 +118,7 @@ static void cec_gpio_disable_irq(struct cec_adapter *adap) { struct cec_gpio *cec = cec_get_drvdata(adap); - if (cec->cec_have_irq) - free_irq(cec->cec_irq, cec); - cec->cec_have_irq = false; + disable_irq(cec->cec_irq); } static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) @@ -139,8 +126,7 @@ static void cec_gpio_status(struct cec_adapter *adap, struct seq_file *file) struct cec_gpio *cec = cec_get_drvdata(adap); seq_printf(file, "mode: %s\n", cec->cec_is_low ? "low-drive" : "read"); - if (cec->cec_have_irq) - seq_printf(file, "using irq: %d\n", cec->cec_irq); + seq_printf(file, "using irq: %d\n", cec->cec_irq); if (cec->hpd_gpio) seq_printf(file, "hpd: %s\n", cec->hpd_is_high ? "high" : "low"); @@ -215,6 +201,14 @@ static int cec_gpio_probe(struct platform_device *pdev) if (IS_ERR(cec->adap)) return PTR_ERR(cec->adap); + ret = devm_request_irq(dev, cec->cec_irq, cec_gpio_irq_handler, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + cec->adap->name, cec); + if (ret) + return ret; + + cec_gpio_disable_irq(cec->adap); + if (cec->hpd_gpio) { cec->hpd_irq = gpiod_to_irq(cec->hpd_gpio); ret = devm_request_threaded_irq(dev, cec->hpd_irq, -- cgit v1.2.3-59-g8ed1b From 63d171f85fb15247600bdd38b1dbf72bcba0dc8a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Apr 2019 08:37:39 -0400 Subject: media: cec: cec_transmit_msg_fh: do sanity checks first The code that fills in the CEC_MSG_CDC_MESSAGE physical address is now done after the sanity checks. It also only does this if the message length is >= 4 (i.e. there is room for the physical address). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index f1261cc2b6fa..b6102510e203 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -740,11 +740,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, else msg->flags = 0; - if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { - msg->msg[2] = adap->phys_addr >> 8; - msg->msg[3] = adap->phys_addr & 0xff; - } - /* Sanity checks */ if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { dprintk(1, "%s: invalid length %d\n", __func__, msg->len); @@ -765,6 +760,12 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, dprintk(1, "%s: can't reply to poll msg\n", __func__); return -EINVAL; } + + if (msg->len >= 4 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { + msg->msg[2] = adap->phys_addr >> 8; + msg->msg[3] = adap->phys_addr & 0xff; + } + if (msg->len == 1) { if (cec_msg_destination(msg) == 0xf) { dprintk(1, "%s: invalid poll message\n", __func__); -- cgit v1.2.3-59-g8ed1b From e76cbec85eac714a93a7945c9c41dcd8819b31c5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Apr 2019 08:43:30 -0400 Subject: media: cec: move check from cec_transmit to cec_transmit_msg_fh This ensures all the cec_msg checks are done in the same place. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 5 +++++ drivers/media/cec/cec-api.c | 8 -------- 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index b6102510e203..5b9232b6e663 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -761,6 +761,11 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, return -EINVAL; } + /* A CDC-Only device can only send CDC messages */ + if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && + (msg->len == 1 || msg->msg[1] != CEC_MSG_CDC_MESSAGE)) + return -EINVAL; + if (msg->len >= 4 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { msg->msg[2] = adap->phys_addr >> 8; msg->msg[3] = adap->phys_addr & 0xff; diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 156a0d76ab2a..12d676484472 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -198,19 +198,11 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, if (copy_from_user(&msg, parg, sizeof(msg))) return -EFAULT; - /* A CDC-Only device can only send CDC messages */ - if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && - (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE)) - return -EINVAL; - mutex_lock(&adap->lock); if (adap->log_addrs.num_log_addrs == 0) err = -EPERM; else if (adap->is_configuring) err = -ENONET; - else if (!adap->is_configured && - (adap->needs_hpd || msg.msg[0] != 0xf0)) - err = -ENONET; else if (cec_is_busy(adap, fh)) err = -EBUSY; else -- cgit v1.2.3-59-g8ed1b From aa50accfda60468fd132573b8f83e158ff45cb3d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Apr 2019 08:44:59 -0400 Subject: media: cec: add CEC_MSG_FL_RAW flag and msg_is_raw helper function This adds the userspace API to send raw unchecked CEC messages. This will require root permissions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-priv.h | 5 +++++ include/uapi/linux/cec.h | 1 + 2 files changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h index 804e38f849c7..7bdf855aaecd 100644 --- a/drivers/media/cec/cec-priv.h +++ b/drivers/media/cec/cec-priv.h @@ -20,6 +20,11 @@ /* devnode to cec_adapter */ #define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode) +static inline bool msg_is_raw(const struct cec_msg *msg) +{ + return msg->flags & CEC_MSG_FL_RAW; +} + /* cec-core.c */ extern int cec_debug; int cec_get_device(struct cec_devnode *devnode); diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h index 3094af68b6e7..5704fa0292b5 100644 --- a/include/uapi/linux/cec.h +++ b/include/uapi/linux/cec.h @@ -144,6 +144,7 @@ static inline void cec_msg_set_reply_to(struct cec_msg *msg, /* cec_msg flags field */ #define CEC_MSG_FL_REPLY_TO_FOLLOWERS (1 << 0) +#define CEC_MSG_FL_RAW (1 << 1) /* cec_msg tx/rx_status field */ #define CEC_TX_STATUS_OK (1 << 0) -- cgit v1.2.3-59-g8ed1b From 89db242aa3c5fc631ff58faf5a0f7c604c84a9db Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Apr 2019 08:48:22 -0400 Subject: media: cec: support CEC_MSG_FL_RAW If this flag is set, then check for root permissions and skip all message checks expect for the core checks (i.e. validate the length etc.). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 107 +++++++++++++++++++++++++------------------ 1 file changed, 62 insertions(+), 45 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 5b9232b6e663..9a1ec9299aca 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -720,6 +720,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, struct cec_fh *fh, bool block) { struct cec_data *data; + bool is_raw = msg_is_raw(msg); msg->rx_ts = 0; msg->tx_ts = 0; @@ -735,10 +736,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, /* Make sure the timeout isn't 0. */ msg->timeout = 1000; } - if (msg->timeout) - msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; - else - msg->flags = 0; + msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS | CEC_MSG_FL_RAW; + + if (!msg->timeout) + msg->flags &= ~CEC_MSG_FL_REPLY_TO_FOLLOWERS; /* Sanity checks */ if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { @@ -761,54 +762,70 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, return -EINVAL; } - /* A CDC-Only device can only send CDC messages */ - if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && - (msg->len == 1 || msg->msg[1] != CEC_MSG_CDC_MESSAGE)) - return -EINVAL; + if (is_raw) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + } else { + /* A CDC-Only device can only send CDC messages */ + if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && + (msg->len == 1 || msg->msg[1] != CEC_MSG_CDC_MESSAGE)) { + dprintk(1, "%s: not a CDC message\n", __func__); + return -EINVAL; + } - if (msg->len >= 4 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { - msg->msg[2] = adap->phys_addr >> 8; - msg->msg[3] = adap->phys_addr & 0xff; - } + if (msg->len >= 4 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { + msg->msg[2] = adap->phys_addr >> 8; + msg->msg[3] = adap->phys_addr & 0xff; + } - if (msg->len == 1) { - if (cec_msg_destination(msg) == 0xf) { - dprintk(1, "%s: invalid poll message\n", __func__); + if (msg->len == 1) { + if (cec_msg_destination(msg) == 0xf) { + dprintk(1, "%s: invalid poll message\n", + __func__); + return -EINVAL; + } + if (cec_has_log_addr(adap, cec_msg_destination(msg))) { + /* + * If the destination is a logical address our + * adapter has already claimed, then just NACK + * this. It depends on the hardware what it will + * do with a POLL to itself (some OK this), so + * it is just as easy to handle it here so the + * behavior will be consistent. + */ + msg->tx_ts = ktime_get_ns(); + msg->tx_status = CEC_TX_STATUS_NACK | + CEC_TX_STATUS_MAX_RETRIES; + msg->tx_nack_cnt = 1; + msg->sequence = ++adap->sequence; + if (!msg->sequence) + msg->sequence = ++adap->sequence; + return 0; + } + } + if (msg->len > 1 && !cec_msg_is_broadcast(msg) && + cec_has_log_addr(adap, cec_msg_destination(msg))) { + dprintk(1, "%s: destination is the adapter itself\n", + __func__); return -EINVAL; } - if (cec_has_log_addr(adap, cec_msg_destination(msg))) { - /* - * If the destination is a logical address our adapter - * has already claimed, then just NACK this. - * It depends on the hardware what it will do with a - * POLL to itself (some OK this), so it is just as - * easy to handle it here so the behavior will be - * consistent. - */ - msg->tx_ts = ktime_get_ns(); - msg->tx_status = CEC_TX_STATUS_NACK | - CEC_TX_STATUS_MAX_RETRIES; - msg->tx_nack_cnt = 1; - msg->sequence = ++adap->sequence; - if (!msg->sequence) - msg->sequence = ++adap->sequence; - return 0; + if (msg->len > 1 && adap->is_configured && + !cec_has_log_addr(adap, cec_msg_initiator(msg))) { + dprintk(1, "%s: initiator has unknown logical address %d\n", + __func__, cec_msg_initiator(msg)); + return -EINVAL; + } + if (!adap->is_configured && !adap->is_configuring && + msg->msg[0] != 0xf0) { + dprintk(1, "%s: adapter is unconfigured\n", __func__); + return -ENONET; } } - if (msg->len > 1 && !cec_msg_is_broadcast(msg) && - cec_has_log_addr(adap, cec_msg_destination(msg))) { - dprintk(1, "%s: destination is the adapter itself\n", __func__); - return -EINVAL; - } - if (msg->len > 1 && adap->is_configured && - !cec_has_log_addr(adap, cec_msg_initiator(msg))) { - dprintk(1, "%s: initiator has unknown logical address %d\n", - __func__, cec_msg_initiator(msg)); - return -EINVAL; - } + if (!adap->is_configured && !adap->is_configuring) { - if (adap->needs_hpd || msg->msg[0] != 0xf0) { - dprintk(1, "%s: adapter is unconfigured\n", __func__); + if (adap->needs_hpd) { + dprintk(1, "%s: adapter is unconfigured and needs HPD\n", + __func__); return -ENONET; } if (msg->reply) { -- cgit v1.2.3-59-g8ed1b From b6c96e15682549a5b5cb9d0301f44949a012741a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Apr 2019 08:14:01 -0400 Subject: media: cec: allow any initiator for Ping and Image/Text View On Some displays pull down the HPD when in standby, but CEC is still active and the display can be woken up by sending an Image View On or Text View On CEC command. The CEC specification doesn't tell you what the initiator should be for such a command (without a HPD it's unclear if the CEC adapter can claim a logical address). This patch allows any initiator value when there is no HPD for the Image/Text View On commands and for the Ping command. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 9a1ec9299aca..5827d8c3742a 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -809,14 +809,23 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, __func__); return -EINVAL; } - if (msg->len > 1 && adap->is_configured && + if (adap->is_configured && !cec_has_log_addr(adap, cec_msg_initiator(msg))) { dprintk(1, "%s: initiator has unknown logical address %d\n", __func__, cec_msg_initiator(msg)); return -EINVAL; } + /* + * Special case: allow Ping and IMAGE/TEXT_VIEW_ON to be + * transmitted to a TV, even if the adapter is unconfigured. + * This makes it possible to detect or wake up displays that + * pull down the HPD when in standby. + */ if (!adap->is_configured && !adap->is_configuring && - msg->msg[0] != 0xf0) { + (msg->len > 2 || + cec_msg_destination(msg) != CEC_LOG_ADDR_TV || + (msg->len == 2 && msg->msg[1] != CEC_MSG_IMAGE_VIEW_ON && + msg->msg[1] != CEC_MSG_TEXT_VIEW_ON))) { dprintk(1, "%s: adapter is unconfigured\n", __func__); return -ENONET; } -- cgit v1.2.3-59-g8ed1b From cfe7cc383cfadff6d3596296c86d7ab7487fc6f4 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 17 Apr 2019 10:06:38 -0400 Subject: media: ov7740: fix unbalanced pm_runtime_get/put Avoid returning without decrement the usage count in s_ctrl(). Cc: Wenyou Yang Cc: Eugen Hristev Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7740.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 54e80a60aa57..d122e350478c 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -561,16 +561,16 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_AUTOGAIN: if (!ctrl->val) - return ov7740_set_gain(regmap, ov7740->gain->val); - - ret = ov7740_set_autogain(regmap, ctrl->val); + ret = ov7740_set_gain(regmap, ov7740->gain->val); + else + ret = ov7740_set_autogain(regmap, ctrl->val); break; case V4L2_CID_EXPOSURE_AUTO: if (ctrl->val == V4L2_EXPOSURE_MANUAL) - return ov7740_set_exp(regmap, ov7740->exposure->val); - - ret = ov7740_set_autoexp(regmap, ctrl->val); + ret = ov7740_set_exp(regmap, ov7740->exposure->val); + else + ret = ov7740_set_autoexp(regmap, ctrl->val); break; default: ret = -EINVAL; -- cgit v1.2.3-59-g8ed1b From 6e4ab830ac6d6a0d7cd7f87dc5d6536369bf24a8 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 17 Apr 2019 10:06:39 -0400 Subject: media: ov7740: avoid invalid framesize setting If the requested framesize by VIDIOC_SUBDEV_S_FMT is larger than supported framesizes, it causes an out of bounds array access and the resulting framesize is unexpected. Avoid out of bounds array access and select the default framesize. Cc: Wenyou Yang Cc: Eugen Hristev Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7740.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index d122e350478c..5c0dfdf6756a 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -785,7 +785,11 @@ static int ov7740_try_fmt_internal(struct v4l2_subdev *sd, fsize++; } - + if (i >= ARRAY_SIZE(ov7740_framesizes)) { + fsize = &ov7740_framesizes[0]; + fmt->width = fsize->width; + fmt->height = fsize->height; + } if (ret_frmsize != NULL) *ret_frmsize = fsize; -- cgit v1.2.3-59-g8ed1b From eed6b2e7c9ca964658b4f3bab5e28032f424a45c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 17 Apr 2019 10:06:40 -0400 Subject: media: ov7740: fix vertical flip control Setting the value of the V4L2_CID_VFLIP control is currently ignored. Because V4L2_CID_HFLIP and V4L2_CID_VFLIP are independently controlled in s_ctrl() but these controls belong to the same cluster and the first control is V4L2_CID_HFLIP. Fix it by not clustering these controls. Also correct erroneous updating register bit for vertical flip. Cc: Wenyou Yang Cc: Eugen Hristev Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7740.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 5c0dfdf6756a..352658bc6494 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -532,7 +532,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) struct i2c_client *client = v4l2_get_subdevdata(&ov7740->subdev); struct regmap *regmap = ov7740->regmap; int ret; - u8 val = 0; + u8 val; if (!pm_runtime_get_if_in_use(&client->dev)) return 0; @@ -551,6 +551,7 @@ static int ov7740_set_ctrl(struct v4l2_ctrl *ctrl) ret = ov7740_set_contrast(regmap, ctrl->val); break; case V4L2_CID_VFLIP: + val = ctrl->val ? REG0C_IMG_FLIP : 0x00; ret = regmap_update_bits(regmap, REG_REG0C, REG0C_IMG_FLIP, val); break; @@ -1030,7 +1031,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740) v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, V4L2_EXPOSURE_MANUAL, true); - v4l2_ctrl_cluster(2, &ov7740->hflip); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; -- cgit v1.2.3-59-g8ed1b From d7ac8b1bd281df8996b54044c8708d698de1203e Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Wed, 17 Apr 2019 10:06:41 -0400 Subject: media: ov7740: remove redundant V4L2_CTRL_FLAG_VOLATILE set If the v4l2 controls are set up for autofoo/foo-type handling by calling v4l2_ctrl_auto_cluster() with the last set_volatile argument setting true, each non-auto control doesn't need to be flagged V4L2_CTRL_FLAG_VOLATILE. Cc: Wenyou Yang Cc: Eugen Hristev Signed-off-by: Akinobu Mita Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov7740.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 352658bc6494..70bb870b1d08 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1012,8 +1012,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740) ov7740->gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, V4L2_CID_GAIN, 0, 1023, 1, 500); - if (ov7740->gain) - ov7740->gain->flags |= V4L2_CTRL_FLAG_VOLATILE; ov7740->auto_gain = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); -- cgit v1.2.3-59-g8ed1b From f8075c1cdc79002a0a8ce141c0c2e8c627a46c66 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 3 May 2019 06:39:41 -0400 Subject: media: v4l: fwnode: C-PHY has no clock lane C-PHY doesn't use a clock lane, hence the test for the clock lane when there isn't one is faulty. Rework the test for the conflicting clock lane. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index ea1ed88f9dc8..dea8917fd912 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -212,10 +212,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, have_clk_lane = true; } - if (lanes_used & BIT(clock_lane)) { - if (have_clk_lane || !use_default_lane_mapping) - pr_warn("duplicated lane %u in clock-lanes, using defaults\n", - v); + if (have_clk_lane && lanes_used & BIT(clock_lane) && + !use_default_lane_mapping) { + pr_warn("duplicated lane %u in clock-lanes, using defaults\n", + v); use_default_lane_mapping = true; } -- cgit v1.2.3-59-g8ed1b From 0c7aa32966dab0b8a7424e1b34c7f206817953ec Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 5 May 2019 10:00:23 -0400 Subject: media: marvell-ccic: fix DMA s/g desc number calculation The commit d790b7eda953 ("[media] vb2-dma-sg: move dma_(un)map_sg here") left dma_desc_nent unset. It previously contained the number of DMA descriptors as returned from dma_map_sg(). We can now (since the commit referred to above) obtain the same value from the sg_table and drop dma_desc_nent altogether. Tested on OLPC XO-1.75 machine. Doesn't affect the OLPC XO-1's Cafe driver, since that one doesn't do DMA. [mchehab+samsung@kernel.org: fix a checkpatch warning] Fixes: d790b7eda953 ("[media] vb2-dma-sg: move dma_(un)map_sg here") Signed-off-by: Lubomir Rintel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index f1b301810260..0a6411b877e9 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -200,7 +200,6 @@ struct mcam_vb_buffer { struct list_head queue; struct mcam_dma_desc *dma_desc; /* Descriptor virtual address */ dma_addr_t dma_desc_pa; /* Descriptor physical address */ - int dma_desc_nent; /* Number of mapped descriptors */ }; static inline struct mcam_vb_buffer *vb_to_mvb(struct vb2_v4l2_buffer *vb) @@ -608,9 +607,11 @@ static void mcam_dma_contig_done(struct mcam_camera *cam, int frame) static void mcam_sg_next_buffer(struct mcam_camera *cam) { struct mcam_vb_buffer *buf; + struct sg_table *sg_table; buf = list_first_entry(&cam->buffers, struct mcam_vb_buffer, queue); list_del_init(&buf->queue); + sg_table = vb2_dma_sg_plane_desc(&buf->vb_buf.vb2_buf, 0); /* * Very Bad Not Good Things happen if you don't clear * C1_DESC_ENA before making any descriptor changes. @@ -618,7 +619,7 @@ static void mcam_sg_next_buffer(struct mcam_camera *cam) mcam_reg_clear_bit(cam, REG_CTRL1, C1_DESC_ENA); mcam_reg_write(cam, REG_DMA_DESC_Y, buf->dma_desc_pa); mcam_reg_write(cam, REG_DESC_LEN_Y, - buf->dma_desc_nent*sizeof(struct mcam_dma_desc)); + sg_table->nents * sizeof(struct mcam_dma_desc)); mcam_reg_write(cam, REG_DESC_LEN_U, 0); mcam_reg_write(cam, REG_DESC_LEN_V, 0); mcam_reg_set_bit(cam, REG_CTRL1, C1_DESC_ENA); -- cgit v1.2.3-59-g8ed1b From c3cc51032689c6f472ee4da5e6d61379b246a851 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 5 May 2019 10:00:24 -0400 Subject: media: marvell-ccic: don't generate EOF on parallel bus The commit 05fed81625bf ("[media] marvell-ccic: add MIPI support for marvell-ccic driver") that claimed to add CSI2 turned on C0_EOF_VSYNC for parallel bus without a very good explanation. That broke camera on OLPC XO-1.75 which precisely uses a sensor on a parallel bus. Revert that chunk. Tested on an OLPC XO-1.75. Fixes: 05fed81625bf ("[media] marvell-ccic: add MIPI support for marvell-ccic driver") Signed-off-by: Lubomir Rintel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 0a6411b877e9..040fe9501415 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -792,12 +792,6 @@ static void mcam_ctlr_image(struct mcam_camera *cam) * Make sure it knows we want to use hsync/vsync. */ mcam_reg_write_mask(cam, REG_CTRL0, C0_SIF_HVSYNC, C0_SIFM_MASK); - /* - * This field controls the generation of EOF(DVP only) - */ - if (cam->bus_type != V4L2_MBUS_CSI2_DPHY) - mcam_reg_set_bit(cam, REG_CTRL0, - C0_EOF_VSYNC | C0_VEDGE_CTRL); } -- cgit v1.2.3-59-g8ed1b From a1038ee8ca9f857d4d2e809a02bfe69ecb085b25 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Wed, 8 May 2019 11:11:53 -0400 Subject: media: smiapp: core: add small range to usleep_range No need for a high-accuracy delay here as long as it is more than 2 milliseconds this should be ok - as it is non-atomic context it will be not be precise 2 milliseconds so giving the hrtimer subsystem 50 microseconds to merge timers and reduce interrupts. Signed-off-by: Nicholas Mc Guire Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-quirk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index 95c0272bb014..59cb2a51758a 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -202,7 +202,7 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) return rval; /* Wait for 1 ms + one line => 2 ms is likely enough */ - usleep_range(2000, 2000); + usleep_range(2000, 2050); /* Restore it */ rval = smiapp_write_8(sensor, 0x3205, 0x00); -- cgit v1.2.3-59-g8ed1b From defcdc5d89ced780fb45196d539d6570ec5b1ba5 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 12 Dec 2018 07:27:10 -0500 Subject: media: videobuf2-core: Prevent size alignment wrapping buffer size to 0 PAGE_ALIGN() may wrap the buffer size around to 0. Prevent this by checking that the aligned value is not smaller than the unaligned one. Note on backporting to stable: the file used to be under drivers/media/v4l2-core, it was moved to the current location after 4.14. Signed-off-by: Sakari Ailus Cc: stable@vger.kernel.org Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 3cf25abf5807..cfccee87909a 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -207,6 +207,10 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) for (plane = 0; plane < vb->num_planes; ++plane) { unsigned long size = PAGE_ALIGN(vb->planes[plane].length); + /* Did it wrap around? */ + if (size < vb->planes[plane].length) + goto free; + mem_priv = call_ptr_memop(vb, alloc, q->alloc_devs[plane] ? : q->dev, q->dma_attrs, size, q->dma_dir, q->gfp_flags); -- cgit v1.2.3-59-g8ed1b From 14f28f5cea9e3998442de87846d1907a531b6748 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 12 Dec 2018 07:44:14 -0500 Subject: media: videobuf2-dma-sg: Prevent size from overflowing buf->size is an unsigned long; casting that to int will lead to an overflow if buf->size exceeds INT_MAX. Fix this by changing the type to unsigned long instead. This is possible as the buf->size is always aligned to PAGE_SIZE, and therefore the size will never have values lesser than 0. Note on backporting to stable: the file used to be under drivers/media/v4l2-core, it was moved to the current location after 4.14. Signed-off-by: Sakari Ailus Cc: stable@vger.kernel.org Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 4a4c49d6085c..0f06f08346ba 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -59,7 +59,7 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf, gfp_t gfp_flags) { unsigned int last_page = 0; - int size = buf->size; + unsigned long size = buf->size; while (size > 0) { struct page *pages; -- cgit v1.2.3-59-g8ed1b From b29ecab178b074be999afd5d6bf6e5b4c2bb782b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 12 Dec 2018 07:40:48 -0500 Subject: media: videobuf2-core.h: Document the alloc memop size argument as page aligned The size argument of the alloc memop, which allocates buffer memory, is page aligned. Document it as such in the only caller as well as ops documentation. Signed-off-by: Sakari Ailus Reviewed-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-core.c | 1 + include/media/videobuf2-core.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index cfccee87909a..4489744fbbd9 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -205,6 +205,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb) * NOTE: mmapped areas should be page aligned */ for (plane = 0; plane < vb->num_planes; ++plane) { + /* Memops alloc requires size to be page aligned. */ unsigned long size = PAGE_ALIGN(vb->planes[plane].length); /* Did it wrap around? */ diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 22f3ff76a8b5..c03ef7cc5071 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -54,7 +54,8 @@ struct vb2_threadio_data; * will then be passed as @buf_priv argument to other ops in this * structure. Additional gfp_flags to use when allocating the * are also passed to this operation. These flags are from the - * gfp_flags field of vb2_queue. + * gfp_flags field of vb2_queue. The size argument to this function + * shall be *page aligned*. * @put: inform the allocator that the buffer will no longer be used; * usually will result in the allocator freeing the buffer (if * no other users of this buffer are present); the @buf_priv -- cgit v1.2.3-59-g8ed1b From 8169cf0a02caafd87ee33e66c12f7a35606a6b0c Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 11 Jan 2019 10:49:51 -0500 Subject: media: Kconfig: allow to select drivers if EMBEDDED Embedded systems often connect to sensors or other multimedia subdevices directly. Currently, to be able to select such a subdevice (e.g. CONFIG_VIDEO_OV5640) disabling of the auto- select config option is needed (CONFIG_MEDIA_SUBDRV_AUTOSELECT). This is inconvenient as the ancillary drivers for a particular device then need to be selected manually. Allow to select drivers manually while keeping the auto-select feature in case EXPERT (selected by EMBEDDED) is enabled. Signed-off-by: Stefan Agner Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 2 +- drivers/media/i2c/Kconfig | 4 ++-- drivers/media/spi/Kconfig | 2 +- drivers/media/tuners/Kconfig | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 847da72d1256..ea5450fcb616 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,5 +1,5 @@ menu "Customise DVB Frontends" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT comment "Multistandard (satellite) frontends" depends on DVB_CORE diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 7793358ab8b3..730cad8a53da 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -5,7 +5,7 @@ if VIDEO_V4L2 config VIDEO_IR_I2C - tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT + tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT || EXPERT depends on I2C && RC_CORE default y help @@ -22,7 +22,7 @@ config VIDEO_IR_I2C # menu "I2C Encoders, decoders, sensors and other helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT comment "Audio decoders, processors and mixers" diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index df169ecf0c27..a20f84faba67 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -1,7 +1,7 @@ if VIDEO_V4L2 menu "SPI helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT config VIDEO_GS1662 tristate "Gennum Serializers video" diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig index 147f3cd0bb95..97c46e7368e1 100644 --- a/drivers/media/tuners/Kconfig +++ b/drivers/media/tuners/Kconfig @@ -15,7 +15,7 @@ config MEDIA_TUNER select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT menu "Customize TV tuners" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST + visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST || EXPERT depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT config MEDIA_TUNER_SIMPLE -- cgit v1.2.3-59-g8ed1b From 94b7ddb91c16226fb48ed85d2c66e863009a19da Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 25 Jan 2019 01:54:17 -0500 Subject: media: coda: remove -I$(src) header search path Remove the header search path to the current directory. The compiler will search headers in the current directory by using #include "..." instead of #include <...> Also, change TRACE_INCLUDE_PATH to point to the location of trace.h. Signed-off-by: Masahiro Yamada Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 -- drivers/media/platform/coda/coda-h264.c | 3 ++- drivers/media/platform/coda/trace.h | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 858284328af9..3eed82137257 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,5 +1,3 @@ -ccflags-y += -I$(src) - coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c index 635356a839cf..6da82d13eb21 100644 --- a/drivers/media/platform/coda/coda-h264.c +++ b/drivers/media/platform/coda/coda-h264.c @@ -14,7 +14,8 @@ #include #include #include -#include + +#include "coda.h" static const u8 coda_filler_size[8] = { 0, 7, 14, 13, 12, 11, 10, 9 }; diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h index a672bfc4c6ba..6cf58237fff2 100644 --- a/drivers/media/platform/coda/trace.h +++ b/drivers/media/platform/coda/trace.h @@ -157,7 +157,7 @@ DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done, #endif /* __CODA_TRACE_H__ */ #undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_PATH ../../drivers/media/platform/coda #undef TRACE_INCLUDE_FILE #define TRACE_INCLUDE_FILE trace -- cgit v1.2.3-59-g8ed1b From e08f0761234def47961d3252eac09ccedfe4c6a0 Mon Sep 17 00:00:00 2001 From: Kangjie Lu Date: Fri, 22 Mar 2019 22:51:06 -0400 Subject: media: vpss: fix a potential NULL pointer dereference In case ioremap fails, the fix returns -ENOMEM to avoid NULL pointer dereference. Signed-off-by: Kangjie Lu Acked-by: Lad, Prabhakar Reviewed-by: Mukesh Ojha Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpss.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index 19cf6853411e..89a86c19579b 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -518,6 +518,11 @@ static int __init vpss_init(void) return -EBUSY; oper_cfg.vpss_regs_base2 = ioremap(VPSS_CLK_CTRL, 4); + if (unlikely(!oper_cfg.vpss_regs_base2)) { + release_mem_region(VPSS_CLK_CTRL, 4); + return -ENOMEM; + } + writel(VPSS_CLK_CTRL_VENCCLKEN | VPSS_CLK_CTRL_DACCLKEN, oper_cfg.vpss_regs_base2); -- cgit v1.2.3-59-g8ed1b From 8aef94beadc51c8fa768ef1d5ae5ca1b4c328eb0 Mon Sep 17 00:00:00 2001 From: Mukesh Ojha Date: Tue, 26 Mar 2019 08:17:54 -0400 Subject: media: vpss: fix the order of resource clean up Clean up of resources should be in reverse order of vpss_init(). Fix this inside vpss_exit(). Signed-off-by: Mukesh Ojha Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpss.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index 89a86c19579b..b4ff3f1961a1 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -507,9 +507,9 @@ static struct platform_driver vpss_driver = { static void vpss_exit(void) { + platform_driver_unregister(&vpss_driver); iounmap(oper_cfg.vpss_regs_base2); release_mem_region(VPSS_CLK_CTRL, 4); - platform_driver_unregister(&vpss_driver); } static int __init vpss_init(void) -- cgit v1.2.3-59-g8ed1b From f49308878d7202e07d8761238e01bd0e5fce2750 Mon Sep 17 00:00:00 2001 From: Jungo Lin Date: Tue, 2 Apr 2019 21:44:27 -0400 Subject: media: media_device_enum_links32: clean a reserved field In v4l2-compliance utility, test MEDIA_IOC_ENUM_ENTITIES will check whether reserved field of media_links_enum filled with zero. However, for 32 bit program, the reserved field is missing copy from kernel space to user space in media_device_enum_links32 function. This patch adds the cleaning a reserved field logic in media_device_enum_links32 function. Signed-off-by: Jungo Lin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index b8ec88612df7..6893843edada 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -502,6 +502,7 @@ static long media_device_enum_links32(struct media_device *mdev, { struct media_links_enum links; compat_uptr_t pads_ptr, links_ptr; + int ret; memset(&links, 0, sizeof(links)); @@ -513,7 +514,13 @@ static long media_device_enum_links32(struct media_device *mdev, links.pads = compat_ptr(pads_ptr); links.links = compat_ptr(links_ptr); - return media_device_enum_links(mdev, &links); + ret = media_device_enum_links(mdev, &links); + if (ret) + return ret; + + memset(ulinks->reserved, 0, sizeof(ulinks->reserved)); + + return 0; } #define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) -- cgit v1.2.3-59-g8ed1b From 3d3515312f97582136644a7327ed262c7bb7ea31 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 May 2019 05:27:30 -0400 Subject: media: rc-main: clean-up two warnings While correct, the code is too complex for smatch to undersdand that protocol will always be initialized: drivers/media/rc/rc-main.c:1531 store_wakeup_protocols() error: uninitialized symbol 'protocol'. drivers/media/rc/rc-main.c:1541 store_wakeup_protocols() error: uninitialized symbol 'protocol'. So, change it a little bit in order to avoid such warning. Signed-off-by: Mauro Carvalho Chehab Acked-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index be5fd129d728..13da4c5c7d17 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1502,7 +1502,7 @@ static ssize_t store_wakeup_protocols(struct device *device, const char *buf, size_t len) { struct rc_dev *dev = to_rc_dev(device); - enum rc_proto protocol; + enum rc_proto protocol = RC_PROTO_UNKNOWN; ssize_t rc; u64 allowed; int i; @@ -1511,9 +1511,7 @@ static ssize_t store_wakeup_protocols(struct device *device, allowed = dev->allowed_wakeup_protocols; - if (sysfs_streq(buf, "none")) { - protocol = RC_PROTO_UNKNOWN; - } else { + if (!sysfs_streq(buf, "none")) { for (i = 0; i < ARRAY_SIZE(protocols); i++) { if ((allowed & (1ULL << i)) && sysfs_streq(buf, protocols[i].name)) { -- cgit v1.2.3-59-g8ed1b From 2f39cce963637eee1c58740859c7c63356c29099 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 12 Apr 2019 06:27:40 -0400 Subject: media: remove redundant 'default n' from Kconfig-s 'default n' is the default value for any bool or tristate Kconfig setting so there is no need to write it explicitly. Also since commit f467c5640c29 ("kconfig: only write '# CONFIG_FOO is not set' for visible symbols") the Kconfig behavior is the same regardless of 'default n' being present or not: ... One side effect of (and the main motivation for) this change is making the following two definitions behave exactly the same: config FOO bool config FOO bool default n With this change, neither of these will generate a '# CONFIG_FOO is not set' line (assuming FOO isn't selected/implied). That might make it clearer to people that a bare 'default n' is redundant. ... Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 3 --- drivers/media/dvb-core/Kconfig | 3 --- drivers/media/dvb-frontends/Kconfig | 1 - drivers/media/pci/ddbridge/Kconfig | 1 - drivers/media/pci/dt3155/Kconfig | 1 - drivers/media/pci/ivtv/Kconfig | 2 -- drivers/media/platform/Kconfig | 12 ------------ drivers/media/platform/omap/Kconfig | 1 - drivers/media/platform/vicodec/Kconfig | 1 - drivers/media/platform/vimc/Kconfig | 1 - drivers/media/platform/vivid/Kconfig | 1 - drivers/media/radio/Kconfig | 1 - drivers/media/usb/s2255/Kconfig | 1 - drivers/media/v4l2-core/Kconfig | 2 -- 14 files changed, 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 8efaf99243e0..dee5766fb146 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -113,7 +113,6 @@ config MEDIA_CONTROLLER_DVB config MEDIA_CONTROLLER_REQUEST_API bool "Enable Media controller Request API (EXPERIMENTAL)" depends on MEDIA_CONTROLLER && STAGING_MEDIA - default n help DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. @@ -163,7 +162,6 @@ config DVB_MMAP depends on DVB_CORE depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE select VIDEOBUF2_VMALLOC - default n help This option enables DVB experimental memory-mapped API, which reduces the number of context switches to read DVB buffers, as @@ -189,7 +187,6 @@ config DVB_NET config TTPCI_EEPROM tristate depends on I2C - default n source "drivers/media/dvb-core/Kconfig" diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index f004aea352e0..08e0900ae161 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -18,7 +18,6 @@ config DVB_MAX_ADAPTERS config DVB_DYNAMIC_MINORS bool "Dynamic DVB minor allocation" depends on DVB_CORE - default n help If you say Y here, the DVB subsystem will use dynamic minor allocation for any device that uses the DVB major number. @@ -31,7 +30,6 @@ config DVB_DYNAMIC_MINORS config DVB_DEMUX_SECTION_LOSS_LOG bool "Enable DVB demux section packet loss log" depends on DVB_CORE - default n help Enable extra log messages meant to detect packet loss inside the Kernel. @@ -44,7 +42,6 @@ config DVB_DEMUX_SECTION_LOSS_LOG config DVB_ULE_DEBUG bool "Enable DVB net ULE packet debug messages" depends on DVB_CORE - default n help Enable extra log messages meant to detect problems while handling DVB network ULE packet loss inside the Kernel. diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index ea5450fcb616..dc43749177df 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -945,5 +945,4 @@ comment "Tools to develop new frontends" config DVB_DUMMY_FE tristate "Dummy frontend driver" depends on DVB_CORE - default n endmenu diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index fc98b6d575d9..2577ad308282 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -35,7 +35,6 @@ config DVB_DDBRIDGE_MSIENABLE bool "Enable Message Signaled Interrupts (MSI) per default (EXPERIMENTAL)" depends on DVB_DDBRIDGE depends on PCI_MSI - default n help Use PCI MSI (Message Signaled Interrupts) per default. Enabling this might lead to I2C errors originating from the bridge in conjunction diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig index d770eec541d4..1f2fe7cdbdb2 100644 --- a/drivers/media/pci/dt3155/Kconfig +++ b/drivers/media/pci/dt3155/Kconfig @@ -2,7 +2,6 @@ config VIDEO_DT3155 tristate "DT3155 frame grabber" depends on PCI && VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG - default n help Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. Say Y here if you have this hardware. diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index e96b3c182a2f..1342a95f6997 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -31,7 +31,6 @@ config VIDEO_IVTV config VIDEO_IVTV_DEPRECATED_IOCTLS bool "enable the DVB ioctls abuse on ivtv driver" depends on VIDEO_IVTV - default n help Enable the usage of the a DVB set of ioctls that were abused by IVTV driver for a while. @@ -76,7 +75,6 @@ config VIDEO_FB_IVTV config VIDEO_FB_IVTV_FORCE_PAT bool "force cx23415 framebuffer init with x86 PAT enabled" depends on VIDEO_FB_IVTV && X86_PAT - default n help With PAT enabled, the cx23415 framebuffer driver does not utilize write-combined caching on the framebuffer memory. diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 011c1c2fcf19..853330c642f1 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -5,7 +5,6 @@ menuconfig V4L_PLATFORM_DRIVERS bool "V4L platform devices" depends on MEDIA_CAMERA_SUPPORT - default n help Say Y here to enable support for platform-specific V4L drivers. @@ -154,7 +153,6 @@ config VIDEO_TI_CAL depends on SOC_DRA7XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - default n help Support for the TI CAL (Camera Adaptation Layer) block found on DRA72X SoC. @@ -167,7 +165,6 @@ menuconfig V4L_MEM2MEM_DRIVERS bool "Memory-to-memory multimedia devices" depends on VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - default n help Say Y here to enable selecting drivers for V4L devices that use system memory for both source and destination buffers, as opposed @@ -235,7 +232,6 @@ config VIDEO_MEDIATEK_MDP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU - default n help It is a v4l2 driver and present in Mediatek MT8173 SoCs. The driver supports for scaling and color space conversion. @@ -251,7 +247,6 @@ config VIDEO_MEDIATEK_VCODEC select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU - default n help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats @@ -275,7 +270,6 @@ config VIDEO_SAMSUNG_S5P_G2D depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - default n help This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D 2d graphics accelerator. @@ -295,7 +289,6 @@ config VIDEO_SAMSUNG_S5P_MFC depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG - default n help MFC 5.1 and 6.x driver for V4L2 @@ -458,7 +451,6 @@ config VIDEO_ROCKCHIP_RGA depends on ARCH_ROCKCHIP || COMPILE_TEST select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV - default n help This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator. Rockchip RGA is a separate 2D raster graphic acceleration unit. @@ -476,7 +468,6 @@ config VIDEO_TI_VPE select VIDEO_TI_VPDMA select VIDEO_TI_SC select VIDEO_TI_CSC - default n help Support for the TI VPE(Video Processing Engine) block found on DRA7XX SoC. @@ -529,7 +520,6 @@ config VIDEO_VIM2M depends on VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV - default n help This is a virtual test device for the memory-to-memory driver framework. @@ -541,7 +531,6 @@ endif #V4L_TEST_DRIVERS menuconfig DVB_PLATFORM_DRIVERS bool "DVB platform devices" depends on MEDIA_DIGITAL_TV_SUPPORT - default n help Say Y here to enable support for platform-specific Digital TV drivers. @@ -677,7 +666,6 @@ endif #CEC_PLATFORM_DRIVERS menuconfig SDR_PLATFORM_DRIVERS bool "SDR platform devices" depends on MEDIA_SDR_SUPPORT - default n help Say Y here to enable support for platform-specific SDR Drivers. diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 30ce2ba120a1..0af804bfe641 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -13,6 +13,5 @@ config VIDEO_OMAP2_VOUT select VIDEOBUF_DMA_CONTIG select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FRAME_VECTOR - default n help V4L2 Display driver support for OMAP2/3 based boards. diff --git a/drivers/media/platform/vicodec/Kconfig b/drivers/media/platform/vicodec/Kconfig index ad13329e3461..6b662e2f5020 100644 --- a/drivers/media/platform/vicodec/Kconfig +++ b/drivers/media/platform/vicodec/Kconfig @@ -3,7 +3,6 @@ config VIDEO_VICODEC depends on VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV - default n help Driver for a Virtual Codec diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig index 1de9bc9aa49b..12ee961e4f23 100644 --- a/drivers/media/platform/vimc/Kconfig +++ b/drivers/media/platform/vimc/Kconfig @@ -3,7 +3,6 @@ config VIDEO_VIMC depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC select VIDEO_V4L2_TPG - default n help Skeleton driver for Virtual Media Controller diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index 4b51d4d6cf93..a90719a45014 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig @@ -10,7 +10,6 @@ config VIDEO_VIVID select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG - default n help Enables a virtual video driver. This driver emulates a webcam, TV, S-Video and HDMI capture hardware, including VBI support for diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 9cd00f64af32..2ffc10442d50 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -232,7 +232,6 @@ source "drivers/media/radio/wl128x/Kconfig" menuconfig V4L_RADIO_ISA_DRIVERS bool "ISA radio devices" depends on ISA || COMPILE_TEST - default n help Say Y here to enable support for these ISA drivers. diff --git a/drivers/media/usb/s2255/Kconfig b/drivers/media/usb/s2255/Kconfig index 8c3fceef9a09..6bc5df1c1e4e 100644 --- a/drivers/media/usb/s2255/Kconfig +++ b/drivers/media/usb/s2255/Kconfig @@ -2,7 +2,6 @@ config USB_S2255 tristate "USB Sensoray 2255 video capture device" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - default n help Say Y here if you want support for the Sensoray 2255 USB device. This driver can be compiled as a module, called s2255drv. diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 8402096f7796..15e94296662e 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -12,7 +12,6 @@ config VIDEO_V4L2 config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality on V4L2 drivers" - default n help Say Y here to enable advanced debugging functionality on some V4L devices. @@ -20,7 +19,6 @@ config VIDEO_ADV_DEBUG config VIDEO_FIXED_MINOR_RANGES bool "Enable old-style fixed minor ranges on drivers/video devices" - default n help Say Y here to enable the old-style fixed-range minor assignments. Only useful if you rely on the old behavior and use mknod instead of udev. -- cgit v1.2.3-59-g8ed1b From 4a96f5e10eb9490616b969d5f65a68f8508073e9 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 5 May 2019 11:11:09 -0400 Subject: media: exynos4-is: Add missing of_node_put to fix reference leaks Drop the reference to "parallel-ports" and remote endpoint's parent nodes obtained previously with of_get_child_by_name() and of_get_parent() respectively. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 463f2d84553e..d1d5041cdae5 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -449,6 +449,7 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, pd->fimc_bus_type = FIMC_BUS_TYPE_ISP_WRITEBACK; else pd->fimc_bus_type = pd->sensor_bus_type; + of_node_put(np); if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) { of_node_put(rem); @@ -474,7 +475,8 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd, static int fimc_md_register_sensor_entities(struct fimc_md *fmd) { struct device_node *parent = fmd->pdev->dev.of_node; - struct device_node *node, *ports; + struct device_node *ports = NULL; + struct device_node *node; int index = 0; int ret; @@ -523,12 +525,14 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd) } index++; } + of_node_put(ports); rpm_put: pm_runtime_put(fmd->pmf); return 0; cleanup: + of_node_put(ports); v4l2_async_notifier_cleanup(&fmd->subdev_notifier); pm_runtime_put(fmd->pmf); return ret; -- cgit v1.2.3-59-g8ed1b From 2c41cc0be07b5ee2f1167f41cd8a86fc5b53d82c Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 6 May 2019 03:05:15 -0400 Subject: media: venus: firmware: fix leaked of_node references The call to of_parse_phandle returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. Detected by coccinelle with the following warnings: drivers/media/platform/qcom/venus/firmware.c:90:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 82, but without a corresponding object release within this function. drivers/media/platform/qcom/venus/firmware.c:94:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 82, but without a corresponding object release within this function. drivers/media/platform/qcom/venus/firmware.c:128:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 82, but without a corresponding object release within this function. Signed-off-by: Wen Yang Acked-by: Stanimir Varbanov Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/qcom/venus/firmware.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c index 6cfa8021721e..f81449b400c4 100644 --- a/drivers/media/platform/qcom/venus/firmware.c +++ b/drivers/media/platform/qcom/venus/firmware.c @@ -87,11 +87,11 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, ret = of_address_to_resource(node, 0, &r); if (ret) - return ret; + goto err_put_node; ret = request_firmware(&mdt, fwname, dev); if (ret < 0) - return ret; + goto err_put_node; fw_size = qcom_mdt_get_size(mdt); if (fw_size < 0) { @@ -125,6 +125,8 @@ static int venus_load_fw(struct venus_core *core, const char *fwname, memunmap(mem_va); err_release_fw: release_firmware(mdt); +err_put_node: + of_node_put(node); return ret; } -- cgit v1.2.3-59-g8ed1b From 4914425e28fb90c39fa986016373845de5453e97 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 24 Apr 2019 05:37:49 -0400 Subject: media: coda/venus/s5p_mfc: fix control typo These two slice modes used by the V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE control had a silly typo: V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES SICE should be SLICE. Rename these enum values, keeping the old ones (under #ifndef __KERNEL__) for backwards compatibility reasons. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 ++-- drivers/media/platform/coda/coda-common.c | 2 +- drivers/media/platform/qcom/venus/venc_ctrls.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 4 ++-- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c | 8 ++++---- include/uapi/linux/v4l2-controls.h | 5 +++++ 7 files changed, 16 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index d774a5aaa422..a25f3742ecde 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1043,7 +1043,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: value = 0; break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB: + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; @@ -1051,7 +1051,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) << CODA_SLICING_UNIT_OFFSET; value |= 1 & CODA_SLICING_MODE_MASK; break; - case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES: + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 1856b782fdde..614943e8a7a2 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2061,7 +2061,7 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) } v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, 0x0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0x0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB, 1, 0x3fffffff, 1, 1); diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c index bd4538accf13..7b7186ef6dd2 100644 --- a/drivers/media/platform/qcom/venus/venc_ctrls.c +++ b/drivers/media/platform/qcom/venus/venc_ctrls.c @@ -293,7 +293,7 @@ int venc_ctrl_init(struct venus_inst *inst) v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, 0, V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE); v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 8fcf627dedfb..5505e4fc2090 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -134,7 +134,7 @@ static struct mfc_control controls[] = { .id = V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE, .type = V4L2_CTRL_TYPE_MENU, .minimum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, - .maximum = V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES, + .maximum = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES, .default_value = V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE, .menu_skip_mask = 0, }, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c index 6144e95f6425..e83ede3efca7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -695,9 +695,9 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) /* multi-slice control */ /* multi-slice MB number or bit size */ mfc_write(dev, p->slice_mode, S5P_FIMV_ENC_MSLICE_CTRL); - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { mfc_write(dev, p->slice_mb, S5P_FIMV_ENC_MSLICE_MB); - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { mfc_write(dev, p->slice_bit, S5P_FIMV_ENC_MSLICE_BIT); } else { mfc_write(dev, 0, S5P_FIMV_ENC_MSLICE_MB); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c index 281699ab7fe1..d75511190e47 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c @@ -736,10 +736,10 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx) /* multi-slice control */ /* multi-slice MB number or bit size */ writel(ctx->slice_mode, mfc_regs->e_mslice_mode); - if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { writel(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb); } else if (ctx->slice_mode == - V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { writel(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits); } else { writel(0x0, mfc_regs->e_mslice_size_mb); @@ -779,11 +779,11 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) /* multi-slice MB number or bit size */ ctx->slice_mode = p->slice_mode; reg = 0; - if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) { + if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB) { reg |= (0x1 << 3); writel(reg, mfc_regs->e_enc_options); ctx->slice_size.mb = p->slice_mb; - } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) { + } else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES) { reg |= (0x1 << 3); writel(reg, mfc_regs->e_enc_options); ctx->slice_size.bits = p->slice_bit; diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 37807f23231e..9cad9fd969e3 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -392,8 +392,13 @@ enum v4l2_mpeg_video_header_mode { #define V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE (V4L2_CID_MPEG_BASE+221) enum v4l2_mpeg_video_multi_slice_mode { V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE = 0, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB = 1, + V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES = 2, +#ifndef __KERNEL__ + /* Kept for backwards compatibility reasons. Stupid typo... */ V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB = 1, V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES = 2, +#endif }; #define V4L2_CID_MPEG_VIDEO_VBV_SIZE (V4L2_CID_MPEG_BASE+222) #define V4L2_CID_MPEG_VIDEO_DEC_PTS (V4L2_CID_MPEG_BASE+223) -- cgit v1.2.3-59-g8ed1b From c612e54fca55d9380c1378eaa623d74ed89b62db Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 2 May 2019 09:42:31 -0400 Subject: media: move drivers/media/media-* to drivers/media/mc/mc-* It is really weird that the media controller sources are all top-level in drivers/media. It is a bit of a left-over from long ago when most media sources were all at the top-level. At some point we reorganized the directory structure, but the media-*.c sources where never moved to their own directory. So create a new mc directory and move all sources there. Also rename the prefix from media- to mc-. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 34 +- drivers/media/Makefile | 13 +- drivers/media/mc/Kconfig | 33 ++ drivers/media/mc/Makefile | 10 + drivers/media/mc/mc-dev-allocator.c | 135 +++++ drivers/media/mc/mc-device.c | 909 ++++++++++++++++++++++++++++++ drivers/media/mc/mc-devnode.c | 336 ++++++++++++ drivers/media/mc/mc-entity.c | 1036 +++++++++++++++++++++++++++++++++++ drivers/media/mc/mc-request.c | 503 +++++++++++++++++ drivers/media/media-dev-allocator.c | 135 ----- drivers/media/media-device.c | 909 ------------------------------ drivers/media/media-devnode.c | 336 ------------ drivers/media/media-entity.c | 1036 ----------------------------------- drivers/media/media-request.c | 503 ----------------- 14 files changed, 2965 insertions(+), 2963 deletions(-) create mode 100644 drivers/media/mc/Kconfig create mode 100644 drivers/media/mc/Makefile create mode 100644 drivers/media/mc/mc-dev-allocator.c create mode 100644 drivers/media/mc/mc-device.c create mode 100644 drivers/media/mc/mc-devnode.c create mode 100644 drivers/media/mc/mc-entity.c create mode 100644 drivers/media/mc/mc-request.c delete mode 100644 drivers/media/media-dev-allocator.c delete mode 100644 drivers/media/media-device.c delete mode 100644 drivers/media/media-devnode.c delete mode 100644 drivers/media/media-entity.c delete mode 100644 drivers/media/media-request.c (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index ce6782bc53ef..21cd9c02960b 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -89,39 +89,7 @@ config MEDIA_CEC_SUPPORT source "drivers/media/cec/Kconfig" -# -# Media controller -# Selectable only for webcam/grabbers, as other drivers don't use it -# - -config MEDIA_CONTROLLER - bool "Media Controller API" - depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT - help - Enable the media controller API used to query media devices internal - topology and configure it dynamically. - - This API is mostly used by camera interfaces in embedded platforms. - -config MEDIA_CONTROLLER_DVB - bool "Enable Media controller for DVB (EXPERIMENTAL)" - depends on MEDIA_CONTROLLER && DVB_CORE - help - Enable the media controller API support for DVB. - - This is currently experimental. - -config MEDIA_CONTROLLER_REQUEST_API - bool "Enable Media controller Request API (EXPERIMENTAL)" - depends on MEDIA_CONTROLLER && STAGING_MEDIA - help - DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. - - This option enables the Request API for the Media controller and V4L2 - interfaces. It is currently needed by a few stateless codec drivers. - - There is currently no intention to provide API or ABI stability for - this new API as of yet. +source "drivers/media/mc/Kconfig" # # Video4Linux support diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 4a330d0e5e40..f215f0a89f9e 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -3,15 +3,6 @@ # Makefile for the kernel multimedia device drivers. # -media-objs := media-device.o media-devnode.o media-entity.o \ - media-request.o - -ifeq ($(CONFIG_MEDIA_CONTROLLER),y) - ifeq ($(CONFIG_USB),y) - media-objs += media-dev-allocator.o - endif -endif - # # I2C drivers should come before other drivers, otherwise they'll fail # when compiled as builtin drivers @@ -20,10 +11,10 @@ obj-y += i2c/ tuners/ obj-$(CONFIG_DVB_CORE) += dvb-frontends/ # -# Now, let's link-in the media core +# Now, let's link-in the media controller core # ifeq ($(CONFIG_MEDIA_CONTROLLER),y) - obj-$(CONFIG_MEDIA_SUPPORT) += media.o + obj-$(CONFIG_MEDIA_SUPPORT) += mc/ endif obj-$(CONFIG_VIDEO_DEV) += v4l2-core/ diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig new file mode 100644 index 000000000000..3b9795cfcb36 --- /dev/null +++ b/drivers/media/mc/Kconfig @@ -0,0 +1,33 @@ +# +# Media controller +# Selectable only for webcam/grabbers, as other drivers don't use it +# + +config MEDIA_CONTROLLER + bool "Media Controller API" + depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT + help + Enable the media controller API used to query media devices internal + topology and configure it dynamically. + + This API is mostly used by camera interfaces in embedded platforms. + +config MEDIA_CONTROLLER_DVB + bool "Enable Media controller for DVB (EXPERIMENTAL)" + depends on MEDIA_CONTROLLER && DVB_CORE + help + Enable the media controller API support for DVB. + + This is currently experimental. + +config MEDIA_CONTROLLER_REQUEST_API + bool "Enable Media controller Request API (EXPERIMENTAL)" + depends on MEDIA_CONTROLLER && STAGING_MEDIA + help + DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. + + This option enables the Request API for the Media controller and V4L2 + interfaces. It is currently needed by a few stateless codec drivers. + + There is currently no intention to provide API or ABI stability for + this new API as of yet. diff --git a/drivers/media/mc/Makefile b/drivers/media/mc/Makefile new file mode 100644 index 000000000000..119037f0e686 --- /dev/null +++ b/drivers/media/mc/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 + +mc-objs := mc-device.o mc-devnode.o mc-entity.o \ + mc-request.o + +ifeq ($(CONFIG_USB),y) + mc-objs += mc-dev-allocator.o +endif + +obj-$(CONFIG_MEDIA_SUPPORT) += mc.o diff --git a/drivers/media/mc/mc-dev-allocator.c b/drivers/media/mc/mc-dev-allocator.c new file mode 100644 index 000000000000..ae17887dec59 --- /dev/null +++ b/drivers/media/mc/mc-dev-allocator.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * media-dev-allocator.c - Media Controller Device Allocator API + * + * Copyright (c) 2019 Shuah Khan + * + * Credits: Suggested by Laurent Pinchart + */ + +/* + * This file adds a global refcounted Media Controller Device Instance API. + * A system wide global media device list is managed and each media device + * includes a kref count. The last put on the media device releases the media + * device instance. + * + */ + +#include +#include +#include +#include + +#include +#include + +static LIST_HEAD(media_device_list); +static DEFINE_MUTEX(media_device_lock); + +struct media_device_instance { + struct media_device mdev; + struct module *owner; + struct list_head list; + struct kref refcount; +}; + +static inline struct media_device_instance * +to_media_device_instance(struct media_device *mdev) +{ + return container_of(mdev, struct media_device_instance, mdev); +} + +static void media_device_instance_release(struct kref *kref) +{ + struct media_device_instance *mdi = + container_of(kref, struct media_device_instance, refcount); + + dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__); + + mutex_lock(&media_device_lock); + + media_device_unregister(&mdi->mdev); + media_device_cleanup(&mdi->mdev); + + list_del(&mdi->list); + mutex_unlock(&media_device_lock); + + kfree(mdi); +} + +/* Callers should hold media_device_lock when calling this function */ +static struct media_device *__media_device_get(struct device *dev, + const char *module_name, + struct module *owner) +{ + struct media_device_instance *mdi; + + list_for_each_entry(mdi, &media_device_list, list) { + if (mdi->mdev.dev != dev) + continue; + + kref_get(&mdi->refcount); + + /* get module reference for the media_device owner */ + if (owner != mdi->owner && !try_module_get(mdi->owner)) + dev_err(dev, + "%s: module %s get owner reference error\n", + __func__, module_name); + else + dev_dbg(dev, "%s: module %s got owner reference\n", + __func__, module_name); + return &mdi->mdev; + } + + mdi = kzalloc(sizeof(*mdi), GFP_KERNEL); + if (!mdi) + return NULL; + + mdi->owner = owner; + kref_init(&mdi->refcount); + list_add_tail(&mdi->list, &media_device_list); + + dev_dbg(dev, "%s: Allocated media device for owner %s\n", + __func__, module_name); + return &mdi->mdev; +} + +struct media_device *media_device_usb_allocate(struct usb_device *udev, + const char *module_name, + struct module *owner) +{ + struct media_device *mdev; + + mutex_lock(&media_device_lock); + mdev = __media_device_get(&udev->dev, module_name, owner); + if (!mdev) { + mutex_unlock(&media_device_lock); + return ERR_PTR(-ENOMEM); + } + + /* check if media device is already initialized */ + if (!mdev->dev) + __media_device_usb_init(mdev, udev, udev->product, + module_name); + mutex_unlock(&media_device_lock); + return mdev; +} +EXPORT_SYMBOL_GPL(media_device_usb_allocate); + +void media_device_delete(struct media_device *mdev, const char *module_name, + struct module *owner) +{ + struct media_device_instance *mdi = to_media_device_instance(mdev); + + mutex_lock(&media_device_lock); + /* put module reference for the media_device owner */ + if (mdi->owner != owner) { + module_put(mdi->owner); + dev_dbg(mdi->mdev.dev, + "%s: module %s put owner module reference\n", + __func__, module_name); + } + mutex_unlock(&media_device_lock); + kref_put(&mdi->refcount, media_device_instance_release); +} +EXPORT_SYMBOL_GPL(media_device_delete); diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c new file mode 100644 index 000000000000..6893843edada --- /dev/null +++ b/drivers/media/mc/mc-device.c @@ -0,0 +1,909 @@ +/* + * Media device + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifdef CONFIG_MEDIA_CONTROLLER + +/* + * Legacy defines from linux/media.h. This is the only place we need this + * so we just define it here. The media.h header doesn't expose it to the + * kernel to prevent it from being used by drivers, but here (and only here!) + * we need it to handle the legacy behavior. + */ +#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff +#define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_F_OLD_BASE | \ + MEDIA_ENT_SUBTYPE_MASK) + +/* ----------------------------------------------------------------------------- + * Userspace API + */ + +static inline void __user *media_get_uptr(__u64 arg) +{ + return (void __user *)(uintptr_t)arg; +} + +static int media_device_open(struct file *filp) +{ + return 0; +} + +static int media_device_close(struct file *filp) +{ + return 0; +} + +static long media_device_get_info(struct media_device *dev, void *arg) +{ + struct media_device_info *info = arg; + + memset(info, 0, sizeof(*info)); + + if (dev->driver_name[0]) + strscpy(info->driver, dev->driver_name, sizeof(info->driver)); + else + strscpy(info->driver, dev->dev->driver->name, + sizeof(info->driver)); + + strscpy(info->model, dev->model, sizeof(info->model)); + strscpy(info->serial, dev->serial, sizeof(info->serial)); + strscpy(info->bus_info, dev->bus_info, sizeof(info->bus_info)); + + info->media_version = LINUX_VERSION_CODE; + info->driver_version = info->media_version; + info->hw_revision = dev->hw_revision; + + return 0; +} + +static struct media_entity *find_entity(struct media_device *mdev, u32 id) +{ + struct media_entity *entity; + int next = id & MEDIA_ENT_ID_FLAG_NEXT; + + id &= ~MEDIA_ENT_ID_FLAG_NEXT; + + media_device_for_each_entity(entity, mdev) { + if (((media_entity_id(entity) == id) && !next) || + ((media_entity_id(entity) > id) && next)) { + return entity; + } + } + + return NULL; +} + +static long media_device_enum_entities(struct media_device *mdev, void *arg) +{ + struct media_entity_desc *entd = arg; + struct media_entity *ent; + + ent = find_entity(mdev, entd->id); + if (ent == NULL) + return -EINVAL; + + memset(entd, 0, sizeof(*entd)); + + entd->id = media_entity_id(ent); + if (ent->name) + strscpy(entd->name, ent->name, sizeof(entd->name)); + entd->type = ent->function; + entd->revision = 0; /* Unused */ + entd->flags = ent->flags; + entd->group_id = 0; /* Unused */ + entd->pads = ent->num_pads; + entd->links = ent->num_links - ent->num_backlinks; + + /* + * Workaround for a bug at media-ctl <= v1.10 that makes it to + * do the wrong thing if the entity function doesn't belong to + * either MEDIA_ENT_F_OLD_BASE or MEDIA_ENT_F_OLD_SUBDEV_BASE + * Ranges. + * + * Non-subdevices are expected to be at the MEDIA_ENT_F_OLD_BASE, + * or, otherwise, will be silently ignored by media-ctl when + * printing the graphviz diagram. So, map them into the devnode + * old range. + */ + if (ent->function < MEDIA_ENT_F_OLD_BASE || + ent->function > MEDIA_ENT_F_TUNER) { + if (is_media_entity_v4l2_subdev(ent)) + entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; + else if (ent->function != MEDIA_ENT_F_IO_V4L) + entd->type = MEDIA_ENT_T_DEVNODE_UNKNOWN; + } + + memcpy(&entd->raw, &ent->info, sizeof(ent->info)); + + return 0; +} + +static void media_device_kpad_to_upad(const struct media_pad *kpad, + struct media_pad_desc *upad) +{ + upad->entity = media_entity_id(kpad->entity); + upad->index = kpad->index; + upad->flags = kpad->flags; +} + +static long media_device_enum_links(struct media_device *mdev, void *arg) +{ + struct media_links_enum *links = arg; + struct media_entity *entity; + + entity = find_entity(mdev, links->entity); + if (entity == NULL) + return -EINVAL; + + if (links->pads) { + unsigned int p; + + for (p = 0; p < entity->num_pads; p++) { + struct media_pad_desc pad; + + memset(&pad, 0, sizeof(pad)); + media_device_kpad_to_upad(&entity->pads[p], &pad); + if (copy_to_user(&links->pads[p], &pad, sizeof(pad))) + return -EFAULT; + } + } + + if (links->links) { + struct media_link *link; + struct media_link_desc __user *ulink_desc = links->links; + + list_for_each_entry(link, &entity->links, list) { + struct media_link_desc klink_desc; + + /* Ignore backlinks. */ + if (link->source->entity != entity) + continue; + memset(&klink_desc, 0, sizeof(klink_desc)); + media_device_kpad_to_upad(link->source, + &klink_desc.source); + media_device_kpad_to_upad(link->sink, + &klink_desc.sink); + klink_desc.flags = link->flags; + if (copy_to_user(ulink_desc, &klink_desc, + sizeof(*ulink_desc))) + return -EFAULT; + ulink_desc++; + } + } + memset(links->reserved, 0, sizeof(links->reserved)); + + return 0; +} + +static long media_device_setup_link(struct media_device *mdev, void *arg) +{ + struct media_link_desc *linkd = arg; + struct media_link *link = NULL; + struct media_entity *source; + struct media_entity *sink; + + /* Find the source and sink entities and link. + */ + source = find_entity(mdev, linkd->source.entity); + sink = find_entity(mdev, linkd->sink.entity); + + if (source == NULL || sink == NULL) + return -EINVAL; + + if (linkd->source.index >= source->num_pads || + linkd->sink.index >= sink->num_pads) + return -EINVAL; + + link = media_entity_find_link(&source->pads[linkd->source.index], + &sink->pads[linkd->sink.index]); + if (link == NULL) + return -EINVAL; + + memset(linkd->reserved, 0, sizeof(linkd->reserved)); + + /* Setup the link on both entities. */ + return __media_entity_setup_link(link, linkd->flags); +} + +static long media_device_get_topology(struct media_device *mdev, void *arg) +{ + struct media_v2_topology *topo = arg; + struct media_entity *entity; + struct media_interface *intf; + struct media_pad *pad; + struct media_link *link; + struct media_v2_entity kentity, __user *uentity; + struct media_v2_interface kintf, __user *uintf; + struct media_v2_pad kpad, __user *upad; + struct media_v2_link klink, __user *ulink; + unsigned int i; + int ret = 0; + + topo->topology_version = mdev->topology_version; + + /* Get entities and number of entities */ + i = 0; + uentity = media_get_uptr(topo->ptr_entities); + media_device_for_each_entity(entity, mdev) { + i++; + if (ret || !uentity) + continue; + + if (i > topo->num_entities) { + ret = -ENOSPC; + continue; + } + + /* Copy fields to userspace struct if not error */ + memset(&kentity, 0, sizeof(kentity)); + kentity.id = entity->graph_obj.id; + kentity.function = entity->function; + kentity.flags = entity->flags; + strscpy(kentity.name, entity->name, + sizeof(kentity.name)); + + if (copy_to_user(uentity, &kentity, sizeof(kentity))) + ret = -EFAULT; + uentity++; + } + topo->num_entities = i; + topo->reserved1 = 0; + + /* Get interfaces and number of interfaces */ + i = 0; + uintf = media_get_uptr(topo->ptr_interfaces); + media_device_for_each_intf(intf, mdev) { + i++; + if (ret || !uintf) + continue; + + if (i > topo->num_interfaces) { + ret = -ENOSPC; + continue; + } + + memset(&kintf, 0, sizeof(kintf)); + + /* Copy intf fields to userspace struct */ + kintf.id = intf->graph_obj.id; + kintf.intf_type = intf->type; + kintf.flags = intf->flags; + + if (media_type(&intf->graph_obj) == MEDIA_GRAPH_INTF_DEVNODE) { + struct media_intf_devnode *devnode; + + devnode = intf_to_devnode(intf); + + kintf.devnode.major = devnode->major; + kintf.devnode.minor = devnode->minor; + } + + if (copy_to_user(uintf, &kintf, sizeof(kintf))) + ret = -EFAULT; + uintf++; + } + topo->num_interfaces = i; + topo->reserved2 = 0; + + /* Get pads and number of pads */ + i = 0; + upad = media_get_uptr(topo->ptr_pads); + media_device_for_each_pad(pad, mdev) { + i++; + if (ret || !upad) + continue; + + if (i > topo->num_pads) { + ret = -ENOSPC; + continue; + } + + memset(&kpad, 0, sizeof(kpad)); + + /* Copy pad fields to userspace struct */ + kpad.id = pad->graph_obj.id; + kpad.entity_id = pad->entity->graph_obj.id; + kpad.flags = pad->flags; + kpad.index = pad->index; + + if (copy_to_user(upad, &kpad, sizeof(kpad))) + ret = -EFAULT; + upad++; + } + topo->num_pads = i; + topo->reserved3 = 0; + + /* Get links and number of links */ + i = 0; + ulink = media_get_uptr(topo->ptr_links); + media_device_for_each_link(link, mdev) { + if (link->is_backlink) + continue; + + i++; + + if (ret || !ulink) + continue; + + if (i > topo->num_links) { + ret = -ENOSPC; + continue; + } + + memset(&klink, 0, sizeof(klink)); + + /* Copy link fields to userspace struct */ + klink.id = link->graph_obj.id; + klink.source_id = link->gobj0->id; + klink.sink_id = link->gobj1->id; + klink.flags = link->flags; + + if (copy_to_user(ulink, &klink, sizeof(klink))) + ret = -EFAULT; + ulink++; + } + topo->num_links = i; + topo->reserved4 = 0; + + return ret; +} + +static long media_device_request_alloc(struct media_device *mdev, + int *alloc_fd) +{ +#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API + if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) + return -ENOTTY; + + return media_request_alloc(mdev, alloc_fd); +#else + return -ENOTTY; +#endif +} + +static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd) +{ + if ((_IOC_DIR(cmd) & _IOC_WRITE) && + copy_from_user(karg, uarg, _IOC_SIZE(cmd))) + return -EFAULT; + + return 0; +} + +static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd) +{ + if ((_IOC_DIR(cmd) & _IOC_READ) && + copy_to_user(uarg, karg, _IOC_SIZE(cmd))) + return -EFAULT; + + return 0; +} + +/* Do acquire the graph mutex */ +#define MEDIA_IOC_FL_GRAPH_MUTEX BIT(0) + +#define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user) \ + [_IOC_NR(MEDIA_IOC_##__cmd)] = { \ + .cmd = MEDIA_IOC_##__cmd, \ + .fn = (long (*)(struct media_device *, void *))func, \ + .flags = fl, \ + .arg_from_user = from_user, \ + .arg_to_user = to_user, \ + } + +#define MEDIA_IOC(__cmd, func, fl) \ + MEDIA_IOC_ARG(__cmd, func, fl, copy_arg_from_user, copy_arg_to_user) + +/* the table is indexed by _IOC_NR(cmd) */ +struct media_ioctl_info { + unsigned int cmd; + unsigned short flags; + long (*fn)(struct media_device *dev, void *arg); + long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd); + long (*arg_to_user)(void __user *uarg, void *karg, unsigned int cmd); +}; + +static const struct media_ioctl_info ioctl_info[] = { + MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX), + MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX), + MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX), + MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX), + MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX), + MEDIA_IOC(REQUEST_ALLOC, media_device_request_alloc, 0), +}; + +static long media_device_ioctl(struct file *filp, unsigned int cmd, + unsigned long __arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *dev = devnode->media_dev; + const struct media_ioctl_info *info; + void __user *arg = (void __user *)__arg; + char __karg[256], *karg = __karg; + long ret; + + if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info) + || ioctl_info[_IOC_NR(cmd)].cmd != cmd) + return -ENOIOCTLCMD; + + info = &ioctl_info[_IOC_NR(cmd)]; + + if (_IOC_SIZE(info->cmd) > sizeof(__karg)) { + karg = kmalloc(_IOC_SIZE(info->cmd), GFP_KERNEL); + if (!karg) + return -ENOMEM; + } + + if (info->arg_from_user) { + ret = info->arg_from_user(karg, arg, cmd); + if (ret) + goto out_free; + } + + if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX) + mutex_lock(&dev->graph_mutex); + + ret = info->fn(dev, karg); + + if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX) + mutex_unlock(&dev->graph_mutex); + + if (!ret && info->arg_to_user) + ret = info->arg_to_user(arg, karg, cmd); + +out_free: + if (karg != __karg) + kfree(karg); + + return ret; +} + +#ifdef CONFIG_COMPAT + +struct media_links_enum32 { + __u32 entity; + compat_uptr_t pads; /* struct media_pad_desc * */ + compat_uptr_t links; /* struct media_link_desc * */ + __u32 reserved[4]; +}; + +static long media_device_enum_links32(struct media_device *mdev, + struct media_links_enum32 __user *ulinks) +{ + struct media_links_enum links; + compat_uptr_t pads_ptr, links_ptr; + int ret; + + memset(&links, 0, sizeof(links)); + + if (get_user(links.entity, &ulinks->entity) + || get_user(pads_ptr, &ulinks->pads) + || get_user(links_ptr, &ulinks->links)) + return -EFAULT; + + links.pads = compat_ptr(pads_ptr); + links.links = compat_ptr(links_ptr); + + ret = media_device_enum_links(mdev, &links); + if (ret) + return ret; + + memset(ulinks->reserved, 0, sizeof(ulinks->reserved)); + + return 0; +} + +#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) + +static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + struct media_device *dev = devnode->media_dev; + long ret; + + switch (cmd) { + case MEDIA_IOC_ENUM_LINKS32: + mutex_lock(&dev->graph_mutex); + ret = media_device_enum_links32(dev, + (struct media_links_enum32 __user *)arg); + mutex_unlock(&dev->graph_mutex); + break; + + default: + return media_device_ioctl(filp, cmd, arg); + } + + return ret; +} +#endif /* CONFIG_COMPAT */ + +static const struct media_file_operations media_device_fops = { + .owner = THIS_MODULE, + .open = media_device_open, + .ioctl = media_device_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_device_compat_ioctl, +#endif /* CONFIG_COMPAT */ + .release = media_device_close, +}; + +/* ----------------------------------------------------------------------------- + * sysfs + */ + +static ssize_t show_model(struct device *cd, + struct device_attribute *attr, char *buf) +{ + struct media_devnode *devnode = to_media_devnode(cd); + struct media_device *mdev = devnode->media_dev; + + return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); +} + +static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); + +/* ----------------------------------------------------------------------------- + * Registration/unregistration + */ + +static void media_device_release(struct media_devnode *devnode) +{ + dev_dbg(devnode->parent, "Media device released\n"); +} + +/** + * media_device_register_entity - Register an entity with a media device + * @mdev: The media device + * @entity: The entity + */ +int __must_check media_device_register_entity(struct media_device *mdev, + struct media_entity *entity) +{ + struct media_entity_notify *notify, *next; + unsigned int i; + int ret; + + if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN || + entity->function == MEDIA_ENT_F_UNKNOWN) + dev_warn(mdev->dev, + "Entity type for entity %s was not initialized!\n", + entity->name); + + /* Warn if we apparently re-register an entity */ + WARN_ON(entity->graph_obj.mdev != NULL); + entity->graph_obj.mdev = mdev; + INIT_LIST_HEAD(&entity->links); + entity->num_links = 0; + entity->num_backlinks = 0; + + ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL); + if (ret < 0) + return ret; + entity->internal_idx = ret; + + mutex_lock(&mdev->graph_mutex); + mdev->entity_internal_idx_max = + max(mdev->entity_internal_idx_max, entity->internal_idx); + + /* Initialize media_gobj embedded at the entity */ + media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj); + + /* Initialize objects at the pads */ + for (i = 0; i < entity->num_pads; i++) + media_gobj_create(mdev, MEDIA_GRAPH_PAD, + &entity->pads[i].graph_obj); + + /* invoke entity_notify callbacks */ + list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) + notify->notify(entity, notify->notify_data); + + if (mdev->entity_internal_idx_max + >= mdev->pm_count_walk.ent_enum.idx_max) { + struct media_graph new = { .top = 0 }; + + /* + * Initialise the new graph walk before cleaning up + * the old one in order not to spoil the graph walk + * object of the media device if graph walk init fails. + */ + ret = media_graph_walk_init(&new, mdev); + if (ret) { + mutex_unlock(&mdev->graph_mutex); + return ret; + } + media_graph_walk_cleanup(&mdev->pm_count_walk); + mdev->pm_count_walk = new; + } + mutex_unlock(&mdev->graph_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register_entity); + +static void __media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + struct media_link *link, *tmp; + struct media_interface *intf; + unsigned int i; + + ida_free(&mdev->entity_internal_idx, entity->internal_idx); + + /* Remove all interface links pointing to this entity */ + list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) { + list_for_each_entry_safe(link, tmp, &intf->links, list) { + if (link->entity == entity) + __media_remove_intf_link(link); + } + } + + /* Remove all data links that belong to this entity */ + __media_entity_remove_links(entity); + + /* Remove all pads that belong to this entity */ + for (i = 0; i < entity->num_pads; i++) + media_gobj_destroy(&entity->pads[i].graph_obj); + + /* Remove the entity */ + media_gobj_destroy(&entity->graph_obj); + + /* invoke entity_notify callbacks to handle entity removal?? */ + + entity->graph_obj.mdev = NULL; +} + +void media_device_unregister_entity(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + + if (mdev == NULL) + return; + + mutex_lock(&mdev->graph_mutex); + __media_device_unregister_entity(entity); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_device_unregister_entity); + +/** + * media_device_init() - initialize a media device + * @mdev: The media device + * + * The caller is responsible for initializing the media device before + * registration. The following fields must be set: + * + * - dev must point to the parent device + * - model must be filled with the device model name + */ +void media_device_init(struct media_device *mdev) +{ + INIT_LIST_HEAD(&mdev->entities); + INIT_LIST_HEAD(&mdev->interfaces); + INIT_LIST_HEAD(&mdev->pads); + INIT_LIST_HEAD(&mdev->links); + INIT_LIST_HEAD(&mdev->entity_notify); + + mutex_init(&mdev->req_queue_mutex); + mutex_init(&mdev->graph_mutex); + ida_init(&mdev->entity_internal_idx); + + atomic_set(&mdev->request_id, 0); + + dev_dbg(mdev->dev, "Media device initialized\n"); +} +EXPORT_SYMBOL_GPL(media_device_init); + +void media_device_cleanup(struct media_device *mdev) +{ + ida_destroy(&mdev->entity_internal_idx); + mdev->entity_internal_idx_max = 0; + media_graph_walk_cleanup(&mdev->pm_count_walk); + mutex_destroy(&mdev->graph_mutex); + mutex_destroy(&mdev->req_queue_mutex); +} +EXPORT_SYMBOL_GPL(media_device_cleanup); + +int __must_check __media_device_register(struct media_device *mdev, + struct module *owner) +{ + struct media_devnode *devnode; + int ret; + + devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); + if (!devnode) + return -ENOMEM; + + /* Register the device node. */ + mdev->devnode = devnode; + devnode->fops = &media_device_fops; + devnode->parent = mdev->dev; + devnode->release = media_device_release; + + /* Set version 0 to indicate user-space that the graph is static */ + mdev->topology_version = 0; + + ret = media_devnode_register(mdev, devnode, owner); + if (ret < 0) { + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; + return ret; + } + + ret = device_create_file(&devnode->dev, &dev_attr_model); + if (ret < 0) { + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; + media_devnode_unregister_prepare(devnode); + media_devnode_unregister(devnode); + return ret; + } + + dev_dbg(mdev->dev, "Media device registered\n"); + + return 0; +} +EXPORT_SYMBOL_GPL(__media_device_register); + +int __must_check media_device_register_entity_notify(struct media_device *mdev, + struct media_entity_notify *nptr) +{ + mutex_lock(&mdev->graph_mutex); + list_add_tail(&nptr->list, &mdev->entity_notify); + mutex_unlock(&mdev->graph_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(media_device_register_entity_notify); + +/* + * Note: Should be called with mdev->lock held. + */ +static void __media_device_unregister_entity_notify(struct media_device *mdev, + struct media_entity_notify *nptr) +{ + list_del(&nptr->list); +} + +void media_device_unregister_entity_notify(struct media_device *mdev, + struct media_entity_notify *nptr) +{ + mutex_lock(&mdev->graph_mutex); + __media_device_unregister_entity_notify(mdev, nptr); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); + +void media_device_unregister(struct media_device *mdev) +{ + struct media_entity *entity; + struct media_entity *next; + struct media_interface *intf, *tmp_intf; + struct media_entity_notify *notify, *nextp; + + if (mdev == NULL) + return; + + mutex_lock(&mdev->graph_mutex); + + /* Check if mdev was ever registered at all */ + if (!media_devnode_is_registered(mdev->devnode)) { + mutex_unlock(&mdev->graph_mutex); + return; + } + + /* Clear the devnode register bit to avoid races with media dev open */ + media_devnode_unregister_prepare(mdev->devnode); + + /* Remove all entities from the media device */ + list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) + __media_device_unregister_entity(entity); + + /* Remove all entity_notify callbacks from the media device */ + list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) + __media_device_unregister_entity_notify(mdev, notify); + + /* Remove all interfaces from the media device */ + list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, + graph_obj.list) { + /* + * Unlink the interface, but don't free it here; the + * module which created it is responsible for freeing + * it + */ + __media_remove_intf_links(intf); + media_gobj_destroy(&intf->graph_obj); + } + + mutex_unlock(&mdev->graph_mutex); + + dev_dbg(mdev->dev, "Media device unregistered\n"); + + device_remove_file(&mdev->devnode->dev, &dev_attr_model); + media_devnode_unregister(mdev->devnode); + /* devnode free is handled in media_devnode_*() */ + mdev->devnode = NULL; +} +EXPORT_SYMBOL_GPL(media_device_unregister); + +#if IS_ENABLED(CONFIG_PCI) +void media_device_pci_init(struct media_device *mdev, + struct pci_dev *pci_dev, + const char *name) +{ + mdev->dev = &pci_dev->dev; + + if (name) + strscpy(mdev->model, name, sizeof(mdev->model)); + else + strscpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model)); + + sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev)); + + mdev->hw_revision = (pci_dev->subsystem_vendor << 16) + | pci_dev->subsystem_device; + + media_device_init(mdev); +} +EXPORT_SYMBOL_GPL(media_device_pci_init); +#endif + +#if IS_ENABLED(CONFIG_USB) +void __media_device_usb_init(struct media_device *mdev, + struct usb_device *udev, + const char *board_name, + const char *driver_name) +{ + mdev->dev = &udev->dev; + + if (driver_name) + strscpy(mdev->driver_name, driver_name, + sizeof(mdev->driver_name)); + + if (board_name) + strscpy(mdev->model, board_name, sizeof(mdev->model)); + else if (udev->product) + strscpy(mdev->model, udev->product, sizeof(mdev->model)); + else + strscpy(mdev->model, "unknown model", sizeof(mdev->model)); + if (udev->serial) + strscpy(mdev->serial, udev->serial, sizeof(mdev->serial)); + usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info)); + mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); + + media_device_init(mdev); +} +EXPORT_SYMBOL_GPL(__media_device_usb_init); +#endif + + +#endif /* CONFIG_MEDIA_CONTROLLER */ diff --git a/drivers/media/mc/mc-devnode.c b/drivers/media/mc/mc-devnode.c new file mode 100644 index 000000000000..d5aa30eeff4a --- /dev/null +++ b/drivers/media/mc/mc-devnode.c @@ -0,0 +1,336 @@ +/* + * Media device node + * + * Copyright (C) 2010 Nokia Corporation + * + * Based on drivers/media/video/v4l2_dev.c code authored by + * Mauro Carvalho Chehab (version 2) + * Alan Cox, (version 1) + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + * + * -- + * + * Generic media device node infrastructure to register and unregister + * character devices using a dynamic major number and proper reference + * counting. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MEDIA_NUM_DEVICES 256 +#define MEDIA_NAME "media" + +static dev_t media_dev_t; + +/* + * Active devices + */ +static DEFINE_MUTEX(media_devnode_lock); +static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); + +/* Called when the last user of the media device exits. */ +static void media_devnode_release(struct device *cd) +{ + struct media_devnode *devnode = to_media_devnode(cd); + + mutex_lock(&media_devnode_lock); + /* Mark device node number as free */ + clear_bit(devnode->minor, media_devnode_nums); + mutex_unlock(&media_devnode_lock); + + /* Release media_devnode and perform other cleanups as needed. */ + if (devnode->release) + devnode->release(devnode); + + kfree(devnode); + pr_debug("%s: Media Devnode Deallocated\n", __func__); +} + +static struct bus_type media_bus_type = { + .name = MEDIA_NAME, +}; + +static ssize_t media_read(struct file *filp, char __user *buf, + size_t sz, loff_t *off) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + if (!devnode->fops->read) + return -EINVAL; + if (!media_devnode_is_registered(devnode)) + return -EIO; + return devnode->fops->read(filp, buf, sz, off); +} + +static ssize_t media_write(struct file *filp, const char __user *buf, + size_t sz, loff_t *off) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + if (!devnode->fops->write) + return -EINVAL; + if (!media_devnode_is_registered(devnode)) + return -EIO; + return devnode->fops->write(filp, buf, sz, off); +} + +static __poll_t media_poll(struct file *filp, + struct poll_table_struct *poll) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + if (!media_devnode_is_registered(devnode)) + return EPOLLERR | EPOLLHUP; + if (!devnode->fops->poll) + return DEFAULT_POLLMASK; + return devnode->fops->poll(filp, poll); +} + +static long +__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, + long (*ioctl_func)(struct file *filp, unsigned int cmd, + unsigned long arg)) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + if (!ioctl_func) + return -ENOTTY; + + if (!media_devnode_is_registered(devnode)) + return -EIO; + + return ioctl_func(filp, cmd, arg); +} + +static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); +} + +#ifdef CONFIG_COMPAT + +static long media_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); +} + +#endif /* CONFIG_COMPAT */ + +/* Override for the open function */ +static int media_open(struct inode *inode, struct file *filp) +{ + struct media_devnode *devnode; + int ret; + + /* Check if the media device is available. This needs to be done with + * the media_devnode_lock held to prevent an open/unregister race: + * without the lock, the device could be unregistered and freed between + * the media_devnode_is_registered() and get_device() calls, leading to + * a crash. + */ + mutex_lock(&media_devnode_lock); + devnode = container_of(inode->i_cdev, struct media_devnode, cdev); + /* return ENXIO if the media device has been removed + already or if it is not registered anymore. */ + if (!media_devnode_is_registered(devnode)) { + mutex_unlock(&media_devnode_lock); + return -ENXIO; + } + /* and increase the device refcount */ + get_device(&devnode->dev); + mutex_unlock(&media_devnode_lock); + + filp->private_data = devnode; + + if (devnode->fops->open) { + ret = devnode->fops->open(filp); + if (ret) { + put_device(&devnode->dev); + filp->private_data = NULL; + return ret; + } + } + + return 0; +} + +/* Override for the release function */ +static int media_release(struct inode *inode, struct file *filp) +{ + struct media_devnode *devnode = media_devnode_data(filp); + + if (devnode->fops->release) + devnode->fops->release(filp); + + filp->private_data = NULL; + + /* decrease the refcount unconditionally since the release() + return value is ignored. */ + put_device(&devnode->dev); + + pr_debug("%s: Media Release\n", __func__); + return 0; +} + +static const struct file_operations media_devnode_fops = { + .owner = THIS_MODULE, + .read = media_read, + .write = media_write, + .open = media_open, + .unlocked_ioctl = media_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_compat_ioctl, +#endif /* CONFIG_COMPAT */ + .release = media_release, + .poll = media_poll, + .llseek = no_llseek, +}; + +int __must_check media_devnode_register(struct media_device *mdev, + struct media_devnode *devnode, + struct module *owner) +{ + int minor; + int ret; + + /* Part 1: Find a free minor number */ + mutex_lock(&media_devnode_lock); + minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0); + if (minor == MEDIA_NUM_DEVICES) { + mutex_unlock(&media_devnode_lock); + pr_err("could not get a free minor\n"); + kfree(devnode); + return -ENFILE; + } + + set_bit(minor, media_devnode_nums); + mutex_unlock(&media_devnode_lock); + + devnode->minor = minor; + devnode->media_dev = mdev; + + /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */ + devnode->dev.bus = &media_bus_type; + devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); + devnode->dev.release = media_devnode_release; + if (devnode->parent) + devnode->dev.parent = devnode->parent; + dev_set_name(&devnode->dev, "media%d", devnode->minor); + device_initialize(&devnode->dev); + + /* Part 2: Initialize the character device */ + cdev_init(&devnode->cdev, &media_devnode_fops); + devnode->cdev.owner = owner; + kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); + + /* Part 3: Add the media and char device */ + ret = cdev_device_add(&devnode->cdev, &devnode->dev); + if (ret < 0) { + pr_err("%s: cdev_device_add failed\n", __func__); + goto cdev_add_error; + } + + /* Part 4: Activate this minor. The char device can now be used. */ + set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); + + return 0; + +cdev_add_error: + mutex_lock(&media_devnode_lock); + clear_bit(devnode->minor, media_devnode_nums); + devnode->media_dev = NULL; + mutex_unlock(&media_devnode_lock); + + put_device(&devnode->dev); + return ret; +} + +void media_devnode_unregister_prepare(struct media_devnode *devnode) +{ + /* Check if devnode was ever registered at all */ + if (!media_devnode_is_registered(devnode)) + return; + + mutex_lock(&media_devnode_lock); + clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); + mutex_unlock(&media_devnode_lock); +} + +void media_devnode_unregister(struct media_devnode *devnode) +{ + mutex_lock(&media_devnode_lock); + /* Delete the cdev on this minor as well */ + cdev_device_del(&devnode->cdev, &devnode->dev); + devnode->media_dev = NULL; + mutex_unlock(&media_devnode_lock); + + put_device(&devnode->dev); +} + +/* + * Initialise media for linux + */ +static int __init media_devnode_init(void) +{ + int ret; + + pr_info("Linux media interface: v0.10\n"); + ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, + MEDIA_NAME); + if (ret < 0) { + pr_warn("unable to allocate major\n"); + return ret; + } + + ret = bus_register(&media_bus_type); + if (ret < 0) { + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); + pr_warn("bus_register failed\n"); + return -EIO; + } + + return 0; +} + +static void __exit media_devnode_exit(void) +{ + bus_unregister(&media_bus_type); + unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); +} + +subsys_initcall(media_devnode_init); +module_exit(media_devnode_exit) + +MODULE_AUTHOR("Laurent Pinchart "); +MODULE_DESCRIPTION("Device node registration for media drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c new file mode 100644 index 000000000000..a998a2e0ea1d --- /dev/null +++ b/drivers/media/mc/mc-entity.c @@ -0,0 +1,1036 @@ +/* + * Media entity + * + * Copyright (C) 2010 Nokia Corporation + * + * Contacts: Laurent Pinchart + * Sakari Ailus + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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. + */ + +#include +#include +#include +#include +#include + +static inline const char *gobj_type(enum media_gobj_type type) +{ + switch (type) { + case MEDIA_GRAPH_ENTITY: + return "entity"; + case MEDIA_GRAPH_PAD: + return "pad"; + case MEDIA_GRAPH_LINK: + return "link"; + case MEDIA_GRAPH_INTF_DEVNODE: + return "intf-devnode"; + default: + return "unknown"; + } +} + +static inline const char *intf_type(struct media_interface *intf) +{ + switch (intf->type) { + case MEDIA_INTF_T_DVB_FE: + return "dvb-frontend"; + case MEDIA_INTF_T_DVB_DEMUX: + return "dvb-demux"; + case MEDIA_INTF_T_DVB_DVR: + return "dvb-dvr"; + case MEDIA_INTF_T_DVB_CA: + return "dvb-ca"; + case MEDIA_INTF_T_DVB_NET: + return "dvb-net"; + case MEDIA_INTF_T_V4L_VIDEO: + return "v4l-video"; + case MEDIA_INTF_T_V4L_VBI: + return "v4l-vbi"; + case MEDIA_INTF_T_V4L_RADIO: + return "v4l-radio"; + case MEDIA_INTF_T_V4L_SUBDEV: + return "v4l-subdev"; + case MEDIA_INTF_T_V4L_SWRADIO: + return "v4l-swradio"; + case MEDIA_INTF_T_V4L_TOUCH: + return "v4l-touch"; + default: + return "unknown-intf"; + } +}; + +__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, + int idx_max) +{ + idx_max = ALIGN(idx_max, BITS_PER_LONG); + ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long), + GFP_KERNEL); + if (!ent_enum->bmap) + return -ENOMEM; + + bitmap_zero(ent_enum->bmap, idx_max); + ent_enum->idx_max = idx_max; + + return 0; +} +EXPORT_SYMBOL_GPL(__media_entity_enum_init); + +void media_entity_enum_cleanup(struct media_entity_enum *ent_enum) +{ + kfree(ent_enum->bmap); +} +EXPORT_SYMBOL_GPL(media_entity_enum_cleanup); + +/** + * dev_dbg_obj - Prints in debug mode a change on some object + * + * @event_name: Name of the event to report. Could be __func__ + * @gobj: Pointer to the object + * + * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it + * won't produce any code. + */ +static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj) +{ +#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG) + switch (media_type(gobj)) { + case MEDIA_GRAPH_ENTITY: + dev_dbg(gobj->mdev->dev, + "%s id %u: entity '%s'\n", + event_name, media_id(gobj), + gobj_to_entity(gobj)->name); + break; + case MEDIA_GRAPH_LINK: + { + struct media_link *link = gobj_to_link(gobj); + + dev_dbg(gobj->mdev->dev, + "%s id %u: %s link id %u ==> id %u\n", + event_name, media_id(gobj), + media_type(link->gobj0) == MEDIA_GRAPH_PAD ? + "data" : "interface", + media_id(link->gobj0), + media_id(link->gobj1)); + break; + } + case MEDIA_GRAPH_PAD: + { + struct media_pad *pad = gobj_to_pad(gobj); + + dev_dbg(gobj->mdev->dev, + "%s id %u: %s%spad '%s':%d\n", + event_name, media_id(gobj), + pad->flags & MEDIA_PAD_FL_SINK ? "sink " : "", + pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "", + pad->entity->name, pad->index); + break; + } + case MEDIA_GRAPH_INTF_DEVNODE: + { + struct media_interface *intf = gobj_to_intf(gobj); + struct media_intf_devnode *devnode = intf_to_devnode(intf); + + dev_dbg(gobj->mdev->dev, + "%s id %u: intf_devnode %s - major: %d, minor: %d\n", + event_name, media_id(gobj), + intf_type(intf), + devnode->major, devnode->minor); + break; + } + } +#endif +} + +void media_gobj_create(struct media_device *mdev, + enum media_gobj_type type, + struct media_gobj *gobj) +{ + BUG_ON(!mdev); + + gobj->mdev = mdev; + + /* Create a per-type unique object ID */ + gobj->id = media_gobj_gen_id(type, ++mdev->id); + + switch (type) { + case MEDIA_GRAPH_ENTITY: + list_add_tail(&gobj->list, &mdev->entities); + break; + case MEDIA_GRAPH_PAD: + list_add_tail(&gobj->list, &mdev->pads); + break; + case MEDIA_GRAPH_LINK: + list_add_tail(&gobj->list, &mdev->links); + break; + case MEDIA_GRAPH_INTF_DEVNODE: + list_add_tail(&gobj->list, &mdev->interfaces); + break; + } + + mdev->topology_version++; + + dev_dbg_obj(__func__, gobj); +} + +void media_gobj_destroy(struct media_gobj *gobj) +{ + /* Do nothing if the object is not linked. */ + if (gobj->mdev == NULL) + return; + + dev_dbg_obj(__func__, gobj); + + gobj->mdev->topology_version++; + + /* Remove the object from mdev list */ + list_del(&gobj->list); + + gobj->mdev = NULL; +} + +/* + * TODO: Get rid of this. + */ +#define MEDIA_ENTITY_MAX_PADS 512 + +int media_entity_pads_init(struct media_entity *entity, u16 num_pads, + struct media_pad *pads) +{ + struct media_device *mdev = entity->graph_obj.mdev; + unsigned int i; + + if (num_pads >= MEDIA_ENTITY_MAX_PADS) + return -E2BIG; + + entity->num_pads = num_pads; + entity->pads = pads; + + if (mdev) + mutex_lock(&mdev->graph_mutex); + + for (i = 0; i < num_pads; i++) { + pads[i].entity = entity; + pads[i].index = i; + if (mdev) + media_gobj_create(mdev, MEDIA_GRAPH_PAD, + &entity->pads[i].graph_obj); + } + + if (mdev) + mutex_unlock(&mdev->graph_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(media_entity_pads_init); + +/* ----------------------------------------------------------------------------- + * Graph traversal + */ + +static struct media_entity * +media_entity_other(struct media_entity *entity, struct media_link *link) +{ + if (link->source->entity == entity) + return link->sink->entity; + else + return link->source->entity; +} + +/* push an entity to traversal stack */ +static void stack_push(struct media_graph *graph, + struct media_entity *entity) +{ + if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) { + WARN_ON(1); + return; + } + graph->top++; + graph->stack[graph->top].link = entity->links.next; + graph->stack[graph->top].entity = entity; +} + +static struct media_entity *stack_pop(struct media_graph *graph) +{ + struct media_entity *entity; + + entity = graph->stack[graph->top].entity; + graph->top--; + + return entity; +} + +#define link_top(en) ((en)->stack[(en)->top].link) +#define stack_top(en) ((en)->stack[(en)->top].entity) + +/** + * media_graph_walk_init - Allocate resources for graph walk + * @graph: Media graph structure that will be used to walk the graph + * @mdev: Media device + * + * Reserve resources for graph walk in media device's current + * state. The memory must be released using + * media_graph_walk_free(). + * + * Returns error on failure, zero on success. + */ +__must_check int media_graph_walk_init( + struct media_graph *graph, struct media_device *mdev) +{ + return media_entity_enum_init(&graph->ent_enum, mdev); +} +EXPORT_SYMBOL_GPL(media_graph_walk_init); + +/** + * media_graph_walk_cleanup - Release resources related to graph walking + * @graph: Media graph structure that was used to walk the graph + */ +void media_graph_walk_cleanup(struct media_graph *graph) +{ + media_entity_enum_cleanup(&graph->ent_enum); +} +EXPORT_SYMBOL_GPL(media_graph_walk_cleanup); + +void media_graph_walk_start(struct media_graph *graph, + struct media_entity *entity) +{ + media_entity_enum_zero(&graph->ent_enum); + media_entity_enum_set(&graph->ent_enum, entity); + + graph->top = 0; + graph->stack[graph->top].entity = NULL; + stack_push(graph, entity); + dev_dbg(entity->graph_obj.mdev->dev, + "begin graph walk at '%s'\n", entity->name); +} +EXPORT_SYMBOL_GPL(media_graph_walk_start); + +static void media_graph_walk_iter(struct media_graph *graph) +{ + struct media_entity *entity = stack_top(graph); + struct media_link *link; + struct media_entity *next; + + link = list_entry(link_top(graph), typeof(*link), list); + + /* The link is not enabled so we do not follow. */ + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { + link_top(graph) = link_top(graph)->next; + dev_dbg(entity->graph_obj.mdev->dev, + "walk: skipping disabled link '%s':%u -> '%s':%u\n", + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + return; + } + + /* Get the entity in the other end of the link . */ + next = media_entity_other(entity, link); + + /* Has the entity already been visited? */ + if (media_entity_enum_test_and_set(&graph->ent_enum, next)) { + link_top(graph) = link_top(graph)->next; + dev_dbg(entity->graph_obj.mdev->dev, + "walk: skipping entity '%s' (already seen)\n", + next->name); + return; + } + + /* Push the new entity to stack and start over. */ + link_top(graph) = link_top(graph)->next; + stack_push(graph, next); + dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n", + next->name); +} + +struct media_entity *media_graph_walk_next(struct media_graph *graph) +{ + struct media_entity *entity; + + if (stack_top(graph) == NULL) + return NULL; + + /* + * Depth first search. Push entity to stack and continue from + * top of the stack until no more entities on the level can be + * found. + */ + while (link_top(graph) != &stack_top(graph)->links) + media_graph_walk_iter(graph); + + entity = stack_pop(graph); + dev_dbg(entity->graph_obj.mdev->dev, + "walk: returning entity '%s'\n", entity->name); + + return entity; +} +EXPORT_SYMBOL_GPL(media_graph_walk_next); + +int media_entity_get_fwnode_pad(struct media_entity *entity, + struct fwnode_handle *fwnode, + unsigned long direction_flags) +{ + struct fwnode_endpoint endpoint; + unsigned int i; + int ret; + + if (!entity->ops || !entity->ops->get_fwnode_pad) { + for (i = 0; i < entity->num_pads; i++) { + if (entity->pads[i].flags & direction_flags) + return i; + } + + return -ENXIO; + } + + ret = fwnode_graph_parse_endpoint(fwnode, &endpoint); + if (ret) + return ret; + + ret = entity->ops->get_fwnode_pad(&endpoint); + if (ret < 0) + return ret; + + if (ret >= entity->num_pads) + return -ENXIO; + + if (!(entity->pads[ret].flags & direction_flags)) + return -ENXIO; + + return ret; +} +EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad); + +/* ----------------------------------------------------------------------------- + * Pipeline management + */ + +__must_check int __media_pipeline_start(struct media_entity *entity, + struct media_pipeline *pipe) +{ + struct media_device *mdev = entity->graph_obj.mdev; + struct media_graph *graph = &pipe->graph; + struct media_entity *entity_err = entity; + struct media_link *link; + int ret; + + if (!pipe->streaming_count++) { + ret = media_graph_walk_init(&pipe->graph, mdev); + if (ret) + goto error_graph_walk_start; + } + + media_graph_walk_start(&pipe->graph, entity); + + while ((entity = media_graph_walk_next(graph))) { + DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS); + DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS); + + entity->stream_count++; + + if (entity->pipe && entity->pipe != pipe) { + pr_err("Pipe active for %s. Can't start for %s\n", + entity->name, + entity_err->name); + ret = -EBUSY; + goto error; + } + + entity->pipe = pipe; + + /* Already streaming --- no need to check. */ + if (entity->stream_count > 1) + continue; + + if (!entity->ops || !entity->ops->link_validate) + continue; + + bitmap_zero(active, entity->num_pads); + bitmap_fill(has_no_links, entity->num_pads); + + list_for_each_entry(link, &entity->links, list) { + struct media_pad *pad = link->sink->entity == entity + ? link->sink : link->source; + + /* Mark that a pad is connected by a link. */ + bitmap_clear(has_no_links, pad->index, 1); + + /* + * Pads that either do not need to connect or + * are connected through an enabled link are + * fine. + */ + if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) || + link->flags & MEDIA_LNK_FL_ENABLED) + bitmap_set(active, pad->index, 1); + + /* + * Link validation will only take place for + * sink ends of the link that are enabled. + */ + if (link->sink != pad || + !(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + ret = entity->ops->link_validate(link); + if (ret < 0 && ret != -ENOIOCTLCMD) { + dev_dbg(entity->graph_obj.mdev->dev, + "link validation failed for '%s':%u -> '%s':%u, error %d\n", + link->source->entity->name, + link->source->index, + entity->name, link->sink->index, ret); + goto error; + } + } + + /* Either no links or validated links are fine. */ + bitmap_or(active, active, has_no_links, entity->num_pads); + + if (!bitmap_full(active, entity->num_pads)) { + ret = -ENOLINK; + dev_dbg(entity->graph_obj.mdev->dev, + "'%s':%u must be connected by an enabled link\n", + entity->name, + (unsigned)find_first_zero_bit( + active, entity->num_pads)); + goto error; + } + } + + return 0; + +error: + /* + * Link validation on graph failed. We revert what we did and + * return the error. + */ + media_graph_walk_start(graph, entity_err); + + while ((entity_err = media_graph_walk_next(graph))) { + /* Sanity check for negative stream_count */ + if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) { + entity_err->stream_count--; + if (entity_err->stream_count == 0) + entity_err->pipe = NULL; + } + + /* + * We haven't increased stream_count further than this + * so we quit here. + */ + if (entity_err == entity) + break; + } + +error_graph_walk_start: + if (!--pipe->streaming_count) + media_graph_walk_cleanup(graph); + + return ret; +} +EXPORT_SYMBOL_GPL(__media_pipeline_start); + +__must_check int media_pipeline_start(struct media_entity *entity, + struct media_pipeline *pipe) +{ + struct media_device *mdev = entity->graph_obj.mdev; + int ret; + + mutex_lock(&mdev->graph_mutex); + ret = __media_pipeline_start(entity, pipe); + mutex_unlock(&mdev->graph_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(media_pipeline_start); + +void __media_pipeline_stop(struct media_entity *entity) +{ + struct media_graph *graph = &entity->pipe->graph; + struct media_pipeline *pipe = entity->pipe; + + /* + * If the following check fails, the driver has performed an + * unbalanced call to media_pipeline_stop() + */ + if (WARN_ON(!pipe)) + return; + + media_graph_walk_start(graph, entity); + + while ((entity = media_graph_walk_next(graph))) { + /* Sanity check for negative stream_count */ + if (!WARN_ON_ONCE(entity->stream_count <= 0)) { + entity->stream_count--; + if (entity->stream_count == 0) + entity->pipe = NULL; + } + } + + if (!--pipe->streaming_count) + media_graph_walk_cleanup(graph); + +} +EXPORT_SYMBOL_GPL(__media_pipeline_stop); + +void media_pipeline_stop(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + + mutex_lock(&mdev->graph_mutex); + __media_pipeline_stop(entity); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_pipeline_stop); + +/* ----------------------------------------------------------------------------- + * Links management + */ + +static struct media_link *media_add_link(struct list_head *head) +{ + struct media_link *link; + + link = kzalloc(sizeof(*link), GFP_KERNEL); + if (link == NULL) + return NULL; + + list_add_tail(&link->list, head); + + return link; +} + +static void __media_entity_remove_link(struct media_entity *entity, + struct media_link *link) +{ + struct media_link *rlink, *tmp; + struct media_entity *remote; + + if (link->source->entity == entity) + remote = link->sink->entity; + else + remote = link->source->entity; + + list_for_each_entry_safe(rlink, tmp, &remote->links, list) { + if (rlink != link->reverse) + continue; + + if (link->source->entity == entity) + remote->num_backlinks--; + + /* Remove the remote link */ + list_del(&rlink->list); + media_gobj_destroy(&rlink->graph_obj); + kfree(rlink); + + if (--remote->num_links == 0) + break; + } + list_del(&link->list); + media_gobj_destroy(&link->graph_obj); + kfree(link); +} + +int media_get_pad_index(struct media_entity *entity, bool is_sink, + enum media_pad_signal_type sig_type) +{ + int i; + bool pad_is_sink; + + if (!entity) + return -EINVAL; + + for (i = 0; i < entity->num_pads; i++) { + if (entity->pads[i].flags == MEDIA_PAD_FL_SINK) + pad_is_sink = true; + else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE) + pad_is_sink = false; + else + continue; /* This is an error! */ + + if (pad_is_sink != is_sink) + continue; + if (entity->pads[i].sig_type == sig_type) + return i; + } + return -EINVAL; +} +EXPORT_SYMBOL_GPL(media_get_pad_index); + +int +media_create_pad_link(struct media_entity *source, u16 source_pad, + struct media_entity *sink, u16 sink_pad, u32 flags) +{ + struct media_link *link; + struct media_link *backlink; + + BUG_ON(source == NULL || sink == NULL); + BUG_ON(source_pad >= source->num_pads); + BUG_ON(sink_pad >= sink->num_pads); + + link = media_add_link(&source->links); + if (link == NULL) + return -ENOMEM; + + link->source = &source->pads[source_pad]; + link->sink = &sink->pads[sink_pad]; + link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK; + + /* Initialize graph object embedded at the new link */ + media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK, + &link->graph_obj); + + /* Create the backlink. Backlinks are used to help graph traversal and + * are not reported to userspace. + */ + backlink = media_add_link(&sink->links); + if (backlink == NULL) { + __media_entity_remove_link(source, link); + return -ENOMEM; + } + + backlink->source = &source->pads[source_pad]; + backlink->sink = &sink->pads[sink_pad]; + backlink->flags = flags; + backlink->is_backlink = true; + + /* Initialize graph object embedded at the new link */ + media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK, + &backlink->graph_obj); + + link->reverse = backlink; + backlink->reverse = link; + + sink->num_backlinks++; + sink->num_links++; + source->num_links++; + + return 0; +} +EXPORT_SYMBOL_GPL(media_create_pad_link); + +int media_create_pad_links(const struct media_device *mdev, + const u32 source_function, + struct media_entity *source, + const u16 source_pad, + const u32 sink_function, + struct media_entity *sink, + const u16 sink_pad, + u32 flags, + const bool allow_both_undefined) +{ + struct media_entity *entity; + unsigned function; + int ret; + + /* Trivial case: 1:1 relation */ + if (source && sink) + return media_create_pad_link(source, source_pad, + sink, sink_pad, flags); + + /* Worse case scenario: n:n relation */ + if (!source && !sink) { + if (!allow_both_undefined) + return 0; + media_device_for_each_entity(source, mdev) { + if (source->function != source_function) + continue; + media_device_for_each_entity(sink, mdev) { + if (sink->function != sink_function) + continue; + ret = media_create_pad_link(source, source_pad, + sink, sink_pad, + flags); + if (ret) + return ret; + flags &= ~(MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + } + } + return 0; + } + + /* Handle 1:n and n:1 cases */ + if (source) + function = sink_function; + else + function = source_function; + + media_device_for_each_entity(entity, mdev) { + if (entity->function != function) + continue; + + if (source) + ret = media_create_pad_link(source, source_pad, + entity, sink_pad, flags); + else + ret = media_create_pad_link(entity, source_pad, + sink, sink_pad, flags); + if (ret) + return ret; + flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + } + return 0; +} +EXPORT_SYMBOL_GPL(media_create_pad_links); + +void __media_entity_remove_links(struct media_entity *entity) +{ + struct media_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &entity->links, list) + __media_entity_remove_link(entity, link); + + entity->num_links = 0; + entity->num_backlinks = 0; +} +EXPORT_SYMBOL_GPL(__media_entity_remove_links); + +void media_entity_remove_links(struct media_entity *entity) +{ + struct media_device *mdev = entity->graph_obj.mdev; + + /* Do nothing if the entity is not registered. */ + if (mdev == NULL) + return; + + mutex_lock(&mdev->graph_mutex); + __media_entity_remove_links(entity); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_entity_remove_links); + +static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) +{ + int ret; + + /* Notify both entities. */ + ret = media_entity_call(link->source->entity, link_setup, + link->source, link->sink, flags); + if (ret < 0 && ret != -ENOIOCTLCMD) + return ret; + + ret = media_entity_call(link->sink->entity, link_setup, + link->sink, link->source, flags); + if (ret < 0 && ret != -ENOIOCTLCMD) { + media_entity_call(link->source->entity, link_setup, + link->source, link->sink, link->flags); + return ret; + } + + link->flags = flags; + link->reverse->flags = link->flags; + + return 0; +} + +int __media_entity_setup_link(struct media_link *link, u32 flags) +{ + const u32 mask = MEDIA_LNK_FL_ENABLED; + struct media_device *mdev; + struct media_entity *source, *sink; + int ret = -EBUSY; + + if (link == NULL) + return -EINVAL; + + /* The non-modifiable link flags must not be modified. */ + if ((link->flags & ~mask) != (flags & ~mask)) + return -EINVAL; + + if (link->flags & MEDIA_LNK_FL_IMMUTABLE) + return link->flags == flags ? 0 : -EINVAL; + + if (link->flags == flags) + return 0; + + source = link->source->entity; + sink = link->sink->entity; + + if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && + (source->stream_count || sink->stream_count)) + return -EBUSY; + + mdev = source->graph_obj.mdev; + + if (mdev->ops && mdev->ops->link_notify) { + ret = mdev->ops->link_notify(link, flags, + MEDIA_DEV_NOTIFY_PRE_LINK_CH); + if (ret < 0) + return ret; + } + + ret = __media_entity_setup_link_notify(link, flags); + + if (mdev->ops && mdev->ops->link_notify) + mdev->ops->link_notify(link, flags, + MEDIA_DEV_NOTIFY_POST_LINK_CH); + + return ret; +} +EXPORT_SYMBOL_GPL(__media_entity_setup_link); + +int media_entity_setup_link(struct media_link *link, u32 flags) +{ + int ret; + + mutex_lock(&link->graph_obj.mdev->graph_mutex); + ret = __media_entity_setup_link(link, flags); + mutex_unlock(&link->graph_obj.mdev->graph_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(media_entity_setup_link); + +struct media_link * +media_entity_find_link(struct media_pad *source, struct media_pad *sink) +{ + struct media_link *link; + + list_for_each_entry(link, &source->entity->links, list) { + if (link->source->entity == source->entity && + link->source->index == source->index && + link->sink->entity == sink->entity && + link->sink->index == sink->index) + return link; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(media_entity_find_link); + +struct media_pad *media_entity_remote_pad(const struct media_pad *pad) +{ + struct media_link *link; + + list_for_each_entry(link, &pad->entity->links, list) { + if (!(link->flags & MEDIA_LNK_FL_ENABLED)) + continue; + + if (link->source == pad) + return link->sink; + + if (link->sink == pad) + return link->source; + } + + return NULL; + +} +EXPORT_SYMBOL_GPL(media_entity_remote_pad); + +static void media_interface_init(struct media_device *mdev, + struct media_interface *intf, + u32 gobj_type, + u32 intf_type, u32 flags) +{ + intf->type = intf_type; + intf->flags = flags; + INIT_LIST_HEAD(&intf->links); + + media_gobj_create(mdev, gobj_type, &intf->graph_obj); +} + +/* Functions related to the media interface via device nodes */ + +struct media_intf_devnode *media_devnode_create(struct media_device *mdev, + u32 type, u32 flags, + u32 major, u32 minor) +{ + struct media_intf_devnode *devnode; + + devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); + if (!devnode) + return NULL; + + devnode->major = major; + devnode->minor = minor; + + media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE, + type, flags); + + return devnode; +} +EXPORT_SYMBOL_GPL(media_devnode_create); + +void media_devnode_remove(struct media_intf_devnode *devnode) +{ + media_remove_intf_links(&devnode->intf); + media_gobj_destroy(&devnode->intf.graph_obj); + kfree(devnode); +} +EXPORT_SYMBOL_GPL(media_devnode_remove); + +struct media_link *media_create_intf_link(struct media_entity *entity, + struct media_interface *intf, + u32 flags) +{ + struct media_link *link; + + link = media_add_link(&intf->links); + if (link == NULL) + return NULL; + + link->intf = intf; + link->entity = entity; + link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK; + + /* Initialize graph object embedded at the new link */ + media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK, + &link->graph_obj); + + return link; +} +EXPORT_SYMBOL_GPL(media_create_intf_link); + +void __media_remove_intf_link(struct media_link *link) +{ + list_del(&link->list); + media_gobj_destroy(&link->graph_obj); + kfree(link); +} +EXPORT_SYMBOL_GPL(__media_remove_intf_link); + +void media_remove_intf_link(struct media_link *link) +{ + struct media_device *mdev = link->graph_obj.mdev; + + /* Do nothing if the intf is not registered. */ + if (mdev == NULL) + return; + + mutex_lock(&mdev->graph_mutex); + __media_remove_intf_link(link); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_remove_intf_link); + +void __media_remove_intf_links(struct media_interface *intf) +{ + struct media_link *link, *tmp; + + list_for_each_entry_safe(link, tmp, &intf->links, list) + __media_remove_intf_link(link); + +} +EXPORT_SYMBOL_GPL(__media_remove_intf_links); + +void media_remove_intf_links(struct media_interface *intf) +{ + struct media_device *mdev = intf->graph_obj.mdev; + + /* Do nothing if the intf is not registered. */ + if (mdev == NULL) + return; + + mutex_lock(&mdev->graph_mutex); + __media_remove_intf_links(intf); + mutex_unlock(&mdev->graph_mutex); +} +EXPORT_SYMBOL_GPL(media_remove_intf_links); diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c new file mode 100644 index 000000000000..e3fca436c75b --- /dev/null +++ b/drivers/media/mc/mc-request.c @@ -0,0 +1,503 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Media device request objects + * + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * Copyright (C) 2018 Intel Corporation + * Copyright (C) 2018 Google, Inc. + * + * Author: Hans Verkuil + * Author: Sakari Ailus + */ + +#include +#include +#include + +#include +#include + +static const char * const request_state[] = { + [MEDIA_REQUEST_STATE_IDLE] = "idle", + [MEDIA_REQUEST_STATE_VALIDATING] = "validating", + [MEDIA_REQUEST_STATE_QUEUED] = "queued", + [MEDIA_REQUEST_STATE_COMPLETE] = "complete", + [MEDIA_REQUEST_STATE_CLEANING] = "cleaning", + [MEDIA_REQUEST_STATE_UPDATING] = "updating", +}; + +static const char * +media_request_state_str(enum media_request_state state) +{ + BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE); + + if (WARN_ON(state >= ARRAY_SIZE(request_state))) + return "invalid"; + return request_state[state]; +} + +static void media_request_clean(struct media_request *req) +{ + struct media_request_object *obj, *obj_safe; + + /* Just a sanity check. No other code path is allowed to change this. */ + WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING); + WARN_ON(req->updating_count); + WARN_ON(req->access_count); + + list_for_each_entry_safe(obj, obj_safe, &req->objects, list) { + media_request_object_unbind(obj); + media_request_object_put(obj); + } + + req->updating_count = 0; + req->access_count = 0; + WARN_ON(req->num_incomplete_objects); + req->num_incomplete_objects = 0; + wake_up_interruptible_all(&req->poll_wait); +} + +static void media_request_release(struct kref *kref) +{ + struct media_request *req = + container_of(kref, struct media_request, kref); + struct media_device *mdev = req->mdev; + + dev_dbg(mdev->dev, "request: release %s\n", req->debug_str); + + /* No other users, no need for a spinlock */ + req->state = MEDIA_REQUEST_STATE_CLEANING; + + media_request_clean(req); + + if (mdev->ops->req_free) + mdev->ops->req_free(req); + else + kfree(req); +} + +void media_request_put(struct media_request *req) +{ + kref_put(&req->kref, media_request_release); +} +EXPORT_SYMBOL_GPL(media_request_put); + +static int media_request_close(struct inode *inode, struct file *filp) +{ + struct media_request *req = filp->private_data; + + media_request_put(req); + return 0; +} + +static __poll_t media_request_poll(struct file *filp, + struct poll_table_struct *wait) +{ + struct media_request *req = filp->private_data; + unsigned long flags; + __poll_t ret = 0; + + if (!(poll_requested_events(wait) & EPOLLPRI)) + return 0; + + poll_wait(filp, &req->poll_wait, wait); + spin_lock_irqsave(&req->lock, flags); + if (req->state == MEDIA_REQUEST_STATE_COMPLETE) { + ret = EPOLLPRI; + goto unlock; + } + if (req->state != MEDIA_REQUEST_STATE_QUEUED) { + ret = EPOLLERR; + goto unlock; + } + +unlock: + spin_unlock_irqrestore(&req->lock, flags); + return ret; +} + +static long media_request_ioctl_queue(struct media_request *req) +{ + struct media_device *mdev = req->mdev; + enum media_request_state state; + unsigned long flags; + int ret; + + dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str); + + /* + * Ensure the request that is validated will be the one that gets queued + * next by serialising the queueing process. This mutex is also used + * to serialize with canceling a vb2 queue and with setting values such + * as controls in a request. + */ + mutex_lock(&mdev->req_queue_mutex); + + media_request_get(req); + + spin_lock_irqsave(&req->lock, flags); + if (req->state == MEDIA_REQUEST_STATE_IDLE) + req->state = MEDIA_REQUEST_STATE_VALIDATING; + state = req->state; + spin_unlock_irqrestore(&req->lock, flags); + if (state != MEDIA_REQUEST_STATE_VALIDATING) { + dev_dbg(mdev->dev, + "request: unable to queue %s, request in state %s\n", + req->debug_str, media_request_state_str(state)); + media_request_put(req); + mutex_unlock(&mdev->req_queue_mutex); + return -EBUSY; + } + + ret = mdev->ops->req_validate(req); + + /* + * If the req_validate was successful, then we mark the state as QUEUED + * and call req_queue. The reason we set the state first is that this + * allows req_queue to unbind or complete the queued objects in case + * they are immediately 'consumed'. State changes from QUEUED to another + * state can only happen if either the driver changes the state or if + * the user cancels the vb2 queue. The driver can only change the state + * after each object is queued through the req_queue op (and note that + * that op cannot fail), so setting the state to QUEUED up front is + * safe. + * + * The other reason for changing the state is if the vb2 queue is + * canceled, and that uses the req_queue_mutex which is still locked + * while req_queue is called, so that's safe as well. + */ + spin_lock_irqsave(&req->lock, flags); + req->state = ret ? MEDIA_REQUEST_STATE_IDLE + : MEDIA_REQUEST_STATE_QUEUED; + spin_unlock_irqrestore(&req->lock, flags); + + if (!ret) + mdev->ops->req_queue(req); + + mutex_unlock(&mdev->req_queue_mutex); + + if (ret) { + dev_dbg(mdev->dev, "request: can't queue %s (%d)\n", + req->debug_str, ret); + media_request_put(req); + } + + return ret; +} + +static long media_request_ioctl_reinit(struct media_request *req) +{ + struct media_device *mdev = req->mdev; + unsigned long flags; + + spin_lock_irqsave(&req->lock, flags); + if (req->state != MEDIA_REQUEST_STATE_IDLE && + req->state != MEDIA_REQUEST_STATE_COMPLETE) { + dev_dbg(mdev->dev, + "request: %s not in idle or complete state, cannot reinit\n", + req->debug_str); + spin_unlock_irqrestore(&req->lock, flags); + return -EBUSY; + } + if (req->access_count) { + dev_dbg(mdev->dev, + "request: %s is being accessed, cannot reinit\n", + req->debug_str); + spin_unlock_irqrestore(&req->lock, flags); + return -EBUSY; + } + req->state = MEDIA_REQUEST_STATE_CLEANING; + spin_unlock_irqrestore(&req->lock, flags); + + media_request_clean(req); + + spin_lock_irqsave(&req->lock, flags); + req->state = MEDIA_REQUEST_STATE_IDLE; + spin_unlock_irqrestore(&req->lock, flags); + + return 0; +} + +static long media_request_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + struct media_request *req = filp->private_data; + + switch (cmd) { + case MEDIA_REQUEST_IOC_QUEUE: + return media_request_ioctl_queue(req); + case MEDIA_REQUEST_IOC_REINIT: + return media_request_ioctl_reinit(req); + default: + return -ENOIOCTLCMD; + } +} + +static const struct file_operations request_fops = { + .owner = THIS_MODULE, + .poll = media_request_poll, + .unlocked_ioctl = media_request_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = media_request_ioctl, +#endif /* CONFIG_COMPAT */ + .release = media_request_close, +}; + +struct media_request * +media_request_get_by_fd(struct media_device *mdev, int request_fd) +{ + struct fd f; + struct media_request *req; + + if (!mdev || !mdev->ops || + !mdev->ops->req_validate || !mdev->ops->req_queue) + return ERR_PTR(-EBADR); + + f = fdget(request_fd); + if (!f.file) + goto err_no_req_fd; + + if (f.file->f_op != &request_fops) + goto err_fput; + req = f.file->private_data; + if (req->mdev != mdev) + goto err_fput; + + /* + * Note: as long as someone has an open filehandle of the request, + * the request can never be released. The fdget() above ensures that + * even if userspace closes the request filehandle, the release() + * fop won't be called, so the media_request_get() always succeeds + * and there is no race condition where the request was released + * before media_request_get() is called. + */ + media_request_get(req); + fdput(f); + + return req; + +err_fput: + fdput(f); + +err_no_req_fd: + dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd); + return ERR_PTR(-EINVAL); +} +EXPORT_SYMBOL_GPL(media_request_get_by_fd); + +int media_request_alloc(struct media_device *mdev, int *alloc_fd) +{ + struct media_request *req; + struct file *filp; + int fd; + int ret; + + /* Either both are NULL or both are non-NULL */ + if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free)) + return -ENOMEM; + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) + return fd; + + filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC); + if (IS_ERR(filp)) { + ret = PTR_ERR(filp); + goto err_put_fd; + } + + if (mdev->ops->req_alloc) + req = mdev->ops->req_alloc(mdev); + else + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) { + ret = -ENOMEM; + goto err_fput; + } + + filp->private_data = req; + req->mdev = mdev; + req->state = MEDIA_REQUEST_STATE_IDLE; + req->num_incomplete_objects = 0; + kref_init(&req->kref); + INIT_LIST_HEAD(&req->objects); + spin_lock_init(&req->lock); + init_waitqueue_head(&req->poll_wait); + req->updating_count = 0; + req->access_count = 0; + + *alloc_fd = fd; + + snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d", + atomic_inc_return(&mdev->request_id), fd); + dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str); + + fd_install(fd, filp); + + return 0; + +err_fput: + fput(filp); + +err_put_fd: + put_unused_fd(fd); + + return ret; +} + +static void media_request_object_release(struct kref *kref) +{ + struct media_request_object *obj = + container_of(kref, struct media_request_object, kref); + struct media_request *req = obj->req; + + if (WARN_ON(req)) + media_request_object_unbind(obj); + obj->ops->release(obj); +} + +struct media_request_object * +media_request_object_find(struct media_request *req, + const struct media_request_object_ops *ops, + void *priv) +{ + struct media_request_object *obj; + struct media_request_object *found = NULL; + unsigned long flags; + + if (WARN_ON(!ops || !priv)) + return NULL; + + spin_lock_irqsave(&req->lock, flags); + list_for_each_entry(obj, &req->objects, list) { + if (obj->ops == ops && obj->priv == priv) { + media_request_object_get(obj); + found = obj; + break; + } + } + spin_unlock_irqrestore(&req->lock, flags); + return found; +} +EXPORT_SYMBOL_GPL(media_request_object_find); + +void media_request_object_put(struct media_request_object *obj) +{ + kref_put(&obj->kref, media_request_object_release); +} +EXPORT_SYMBOL_GPL(media_request_object_put); + +void media_request_object_init(struct media_request_object *obj) +{ + obj->ops = NULL; + obj->req = NULL; + obj->priv = NULL; + obj->completed = false; + INIT_LIST_HEAD(&obj->list); + kref_init(&obj->kref); +} +EXPORT_SYMBOL_GPL(media_request_object_init); + +int media_request_object_bind(struct media_request *req, + const struct media_request_object_ops *ops, + void *priv, bool is_buffer, + struct media_request_object *obj) +{ + unsigned long flags; + int ret = -EBUSY; + + if (WARN_ON(!ops->release)) + return -EBADR; + + spin_lock_irqsave(&req->lock, flags); + + if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING)) + goto unlock; + + obj->req = req; + obj->ops = ops; + obj->priv = priv; + + if (is_buffer) + list_add_tail(&obj->list, &req->objects); + else + list_add(&obj->list, &req->objects); + req->num_incomplete_objects++; + ret = 0; + +unlock: + spin_unlock_irqrestore(&req->lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(media_request_object_bind); + +void media_request_object_unbind(struct media_request_object *obj) +{ + struct media_request *req = obj->req; + unsigned long flags; + bool completed = false; + + if (WARN_ON(!req)) + return; + + spin_lock_irqsave(&req->lock, flags); + list_del(&obj->list); + obj->req = NULL; + + if (req->state == MEDIA_REQUEST_STATE_COMPLETE) + goto unlock; + + if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING)) + goto unlock; + + if (req->state == MEDIA_REQUEST_STATE_CLEANING) { + if (!obj->completed) + req->num_incomplete_objects--; + goto unlock; + } + + if (WARN_ON(!req->num_incomplete_objects)) + goto unlock; + + req->num_incomplete_objects--; + if (req->state == MEDIA_REQUEST_STATE_QUEUED && + !req->num_incomplete_objects) { + req->state = MEDIA_REQUEST_STATE_COMPLETE; + completed = true; + wake_up_interruptible_all(&req->poll_wait); + } + +unlock: + spin_unlock_irqrestore(&req->lock, flags); + if (obj->ops->unbind) + obj->ops->unbind(obj); + if (completed) + media_request_put(req); +} +EXPORT_SYMBOL_GPL(media_request_object_unbind); + +void media_request_object_complete(struct media_request_object *obj) +{ + struct media_request *req = obj->req; + unsigned long flags; + bool completed = false; + + spin_lock_irqsave(&req->lock, flags); + if (obj->completed) + goto unlock; + obj->completed = true; + if (WARN_ON(!req->num_incomplete_objects) || + WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) + goto unlock; + + if (!--req->num_incomplete_objects) { + req->state = MEDIA_REQUEST_STATE_COMPLETE; + wake_up_interruptible_all(&req->poll_wait); + completed = true; + } +unlock: + spin_unlock_irqrestore(&req->lock, flags); + if (completed) + media_request_put(req); +} +EXPORT_SYMBOL_GPL(media_request_object_complete); diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c deleted file mode 100644 index ae17887dec59..000000000000 --- a/drivers/media/media-dev-allocator.c +++ /dev/null @@ -1,135 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * media-dev-allocator.c - Media Controller Device Allocator API - * - * Copyright (c) 2019 Shuah Khan - * - * Credits: Suggested by Laurent Pinchart - */ - -/* - * This file adds a global refcounted Media Controller Device Instance API. - * A system wide global media device list is managed and each media device - * includes a kref count. The last put on the media device releases the media - * device instance. - * - */ - -#include -#include -#include -#include - -#include -#include - -static LIST_HEAD(media_device_list); -static DEFINE_MUTEX(media_device_lock); - -struct media_device_instance { - struct media_device mdev; - struct module *owner; - struct list_head list; - struct kref refcount; -}; - -static inline struct media_device_instance * -to_media_device_instance(struct media_device *mdev) -{ - return container_of(mdev, struct media_device_instance, mdev); -} - -static void media_device_instance_release(struct kref *kref) -{ - struct media_device_instance *mdi = - container_of(kref, struct media_device_instance, refcount); - - dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__); - - mutex_lock(&media_device_lock); - - media_device_unregister(&mdi->mdev); - media_device_cleanup(&mdi->mdev); - - list_del(&mdi->list); - mutex_unlock(&media_device_lock); - - kfree(mdi); -} - -/* Callers should hold media_device_lock when calling this function */ -static struct media_device *__media_device_get(struct device *dev, - const char *module_name, - struct module *owner) -{ - struct media_device_instance *mdi; - - list_for_each_entry(mdi, &media_device_list, list) { - if (mdi->mdev.dev != dev) - continue; - - kref_get(&mdi->refcount); - - /* get module reference for the media_device owner */ - if (owner != mdi->owner && !try_module_get(mdi->owner)) - dev_err(dev, - "%s: module %s get owner reference error\n", - __func__, module_name); - else - dev_dbg(dev, "%s: module %s got owner reference\n", - __func__, module_name); - return &mdi->mdev; - } - - mdi = kzalloc(sizeof(*mdi), GFP_KERNEL); - if (!mdi) - return NULL; - - mdi->owner = owner; - kref_init(&mdi->refcount); - list_add_tail(&mdi->list, &media_device_list); - - dev_dbg(dev, "%s: Allocated media device for owner %s\n", - __func__, module_name); - return &mdi->mdev; -} - -struct media_device *media_device_usb_allocate(struct usb_device *udev, - const char *module_name, - struct module *owner) -{ - struct media_device *mdev; - - mutex_lock(&media_device_lock); - mdev = __media_device_get(&udev->dev, module_name, owner); - if (!mdev) { - mutex_unlock(&media_device_lock); - return ERR_PTR(-ENOMEM); - } - - /* check if media device is already initialized */ - if (!mdev->dev) - __media_device_usb_init(mdev, udev, udev->product, - module_name); - mutex_unlock(&media_device_lock); - return mdev; -} -EXPORT_SYMBOL_GPL(media_device_usb_allocate); - -void media_device_delete(struct media_device *mdev, const char *module_name, - struct module *owner) -{ - struct media_device_instance *mdi = to_media_device_instance(mdev); - - mutex_lock(&media_device_lock); - /* put module reference for the media_device owner */ - if (mdi->owner != owner) { - module_put(mdi->owner); - dev_dbg(mdi->mdev.dev, - "%s: module %s put owner module reference\n", - __func__, module_name); - } - mutex_unlock(&media_device_lock); - kref_put(&mdi->refcount, media_device_instance_release); -} -EXPORT_SYMBOL_GPL(media_device_delete); diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c deleted file mode 100644 index 6893843edada..000000000000 --- a/drivers/media/media-device.c +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Media device - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifdef CONFIG_MEDIA_CONTROLLER - -/* - * Legacy defines from linux/media.h. This is the only place we need this - * so we just define it here. The media.h header doesn't expose it to the - * kernel to prevent it from being used by drivers, but here (and only here!) - * we need it to handle the legacy behavior. - */ -#define MEDIA_ENT_SUBTYPE_MASK 0x0000ffff -#define MEDIA_ENT_T_DEVNODE_UNKNOWN (MEDIA_ENT_F_OLD_BASE | \ - MEDIA_ENT_SUBTYPE_MASK) - -/* ----------------------------------------------------------------------------- - * Userspace API - */ - -static inline void __user *media_get_uptr(__u64 arg) -{ - return (void __user *)(uintptr_t)arg; -} - -static int media_device_open(struct file *filp) -{ - return 0; -} - -static int media_device_close(struct file *filp) -{ - return 0; -} - -static long media_device_get_info(struct media_device *dev, void *arg) -{ - struct media_device_info *info = arg; - - memset(info, 0, sizeof(*info)); - - if (dev->driver_name[0]) - strscpy(info->driver, dev->driver_name, sizeof(info->driver)); - else - strscpy(info->driver, dev->dev->driver->name, - sizeof(info->driver)); - - strscpy(info->model, dev->model, sizeof(info->model)); - strscpy(info->serial, dev->serial, sizeof(info->serial)); - strscpy(info->bus_info, dev->bus_info, sizeof(info->bus_info)); - - info->media_version = LINUX_VERSION_CODE; - info->driver_version = info->media_version; - info->hw_revision = dev->hw_revision; - - return 0; -} - -static struct media_entity *find_entity(struct media_device *mdev, u32 id) -{ - struct media_entity *entity; - int next = id & MEDIA_ENT_ID_FLAG_NEXT; - - id &= ~MEDIA_ENT_ID_FLAG_NEXT; - - media_device_for_each_entity(entity, mdev) { - if (((media_entity_id(entity) == id) && !next) || - ((media_entity_id(entity) > id) && next)) { - return entity; - } - } - - return NULL; -} - -static long media_device_enum_entities(struct media_device *mdev, void *arg) -{ - struct media_entity_desc *entd = arg; - struct media_entity *ent; - - ent = find_entity(mdev, entd->id); - if (ent == NULL) - return -EINVAL; - - memset(entd, 0, sizeof(*entd)); - - entd->id = media_entity_id(ent); - if (ent->name) - strscpy(entd->name, ent->name, sizeof(entd->name)); - entd->type = ent->function; - entd->revision = 0; /* Unused */ - entd->flags = ent->flags; - entd->group_id = 0; /* Unused */ - entd->pads = ent->num_pads; - entd->links = ent->num_links - ent->num_backlinks; - - /* - * Workaround for a bug at media-ctl <= v1.10 that makes it to - * do the wrong thing if the entity function doesn't belong to - * either MEDIA_ENT_F_OLD_BASE or MEDIA_ENT_F_OLD_SUBDEV_BASE - * Ranges. - * - * Non-subdevices are expected to be at the MEDIA_ENT_F_OLD_BASE, - * or, otherwise, will be silently ignored by media-ctl when - * printing the graphviz diagram. So, map them into the devnode - * old range. - */ - if (ent->function < MEDIA_ENT_F_OLD_BASE || - ent->function > MEDIA_ENT_F_TUNER) { - if (is_media_entity_v4l2_subdev(ent)) - entd->type = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN; - else if (ent->function != MEDIA_ENT_F_IO_V4L) - entd->type = MEDIA_ENT_T_DEVNODE_UNKNOWN; - } - - memcpy(&entd->raw, &ent->info, sizeof(ent->info)); - - return 0; -} - -static void media_device_kpad_to_upad(const struct media_pad *kpad, - struct media_pad_desc *upad) -{ - upad->entity = media_entity_id(kpad->entity); - upad->index = kpad->index; - upad->flags = kpad->flags; -} - -static long media_device_enum_links(struct media_device *mdev, void *arg) -{ - struct media_links_enum *links = arg; - struct media_entity *entity; - - entity = find_entity(mdev, links->entity); - if (entity == NULL) - return -EINVAL; - - if (links->pads) { - unsigned int p; - - for (p = 0; p < entity->num_pads; p++) { - struct media_pad_desc pad; - - memset(&pad, 0, sizeof(pad)); - media_device_kpad_to_upad(&entity->pads[p], &pad); - if (copy_to_user(&links->pads[p], &pad, sizeof(pad))) - return -EFAULT; - } - } - - if (links->links) { - struct media_link *link; - struct media_link_desc __user *ulink_desc = links->links; - - list_for_each_entry(link, &entity->links, list) { - struct media_link_desc klink_desc; - - /* Ignore backlinks. */ - if (link->source->entity != entity) - continue; - memset(&klink_desc, 0, sizeof(klink_desc)); - media_device_kpad_to_upad(link->source, - &klink_desc.source); - media_device_kpad_to_upad(link->sink, - &klink_desc.sink); - klink_desc.flags = link->flags; - if (copy_to_user(ulink_desc, &klink_desc, - sizeof(*ulink_desc))) - return -EFAULT; - ulink_desc++; - } - } - memset(links->reserved, 0, sizeof(links->reserved)); - - return 0; -} - -static long media_device_setup_link(struct media_device *mdev, void *arg) -{ - struct media_link_desc *linkd = arg; - struct media_link *link = NULL; - struct media_entity *source; - struct media_entity *sink; - - /* Find the source and sink entities and link. - */ - source = find_entity(mdev, linkd->source.entity); - sink = find_entity(mdev, linkd->sink.entity); - - if (source == NULL || sink == NULL) - return -EINVAL; - - if (linkd->source.index >= source->num_pads || - linkd->sink.index >= sink->num_pads) - return -EINVAL; - - link = media_entity_find_link(&source->pads[linkd->source.index], - &sink->pads[linkd->sink.index]); - if (link == NULL) - return -EINVAL; - - memset(linkd->reserved, 0, sizeof(linkd->reserved)); - - /* Setup the link on both entities. */ - return __media_entity_setup_link(link, linkd->flags); -} - -static long media_device_get_topology(struct media_device *mdev, void *arg) -{ - struct media_v2_topology *topo = arg; - struct media_entity *entity; - struct media_interface *intf; - struct media_pad *pad; - struct media_link *link; - struct media_v2_entity kentity, __user *uentity; - struct media_v2_interface kintf, __user *uintf; - struct media_v2_pad kpad, __user *upad; - struct media_v2_link klink, __user *ulink; - unsigned int i; - int ret = 0; - - topo->topology_version = mdev->topology_version; - - /* Get entities and number of entities */ - i = 0; - uentity = media_get_uptr(topo->ptr_entities); - media_device_for_each_entity(entity, mdev) { - i++; - if (ret || !uentity) - continue; - - if (i > topo->num_entities) { - ret = -ENOSPC; - continue; - } - - /* Copy fields to userspace struct if not error */ - memset(&kentity, 0, sizeof(kentity)); - kentity.id = entity->graph_obj.id; - kentity.function = entity->function; - kentity.flags = entity->flags; - strscpy(kentity.name, entity->name, - sizeof(kentity.name)); - - if (copy_to_user(uentity, &kentity, sizeof(kentity))) - ret = -EFAULT; - uentity++; - } - topo->num_entities = i; - topo->reserved1 = 0; - - /* Get interfaces and number of interfaces */ - i = 0; - uintf = media_get_uptr(topo->ptr_interfaces); - media_device_for_each_intf(intf, mdev) { - i++; - if (ret || !uintf) - continue; - - if (i > topo->num_interfaces) { - ret = -ENOSPC; - continue; - } - - memset(&kintf, 0, sizeof(kintf)); - - /* Copy intf fields to userspace struct */ - kintf.id = intf->graph_obj.id; - kintf.intf_type = intf->type; - kintf.flags = intf->flags; - - if (media_type(&intf->graph_obj) == MEDIA_GRAPH_INTF_DEVNODE) { - struct media_intf_devnode *devnode; - - devnode = intf_to_devnode(intf); - - kintf.devnode.major = devnode->major; - kintf.devnode.minor = devnode->minor; - } - - if (copy_to_user(uintf, &kintf, sizeof(kintf))) - ret = -EFAULT; - uintf++; - } - topo->num_interfaces = i; - topo->reserved2 = 0; - - /* Get pads and number of pads */ - i = 0; - upad = media_get_uptr(topo->ptr_pads); - media_device_for_each_pad(pad, mdev) { - i++; - if (ret || !upad) - continue; - - if (i > topo->num_pads) { - ret = -ENOSPC; - continue; - } - - memset(&kpad, 0, sizeof(kpad)); - - /* Copy pad fields to userspace struct */ - kpad.id = pad->graph_obj.id; - kpad.entity_id = pad->entity->graph_obj.id; - kpad.flags = pad->flags; - kpad.index = pad->index; - - if (copy_to_user(upad, &kpad, sizeof(kpad))) - ret = -EFAULT; - upad++; - } - topo->num_pads = i; - topo->reserved3 = 0; - - /* Get links and number of links */ - i = 0; - ulink = media_get_uptr(topo->ptr_links); - media_device_for_each_link(link, mdev) { - if (link->is_backlink) - continue; - - i++; - - if (ret || !ulink) - continue; - - if (i > topo->num_links) { - ret = -ENOSPC; - continue; - } - - memset(&klink, 0, sizeof(klink)); - - /* Copy link fields to userspace struct */ - klink.id = link->graph_obj.id; - klink.source_id = link->gobj0->id; - klink.sink_id = link->gobj1->id; - klink.flags = link->flags; - - if (copy_to_user(ulink, &klink, sizeof(klink))) - ret = -EFAULT; - ulink++; - } - topo->num_links = i; - topo->reserved4 = 0; - - return ret; -} - -static long media_device_request_alloc(struct media_device *mdev, - int *alloc_fd) -{ -#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API - if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) - return -ENOTTY; - - return media_request_alloc(mdev, alloc_fd); -#else - return -ENOTTY; -#endif -} - -static long copy_arg_from_user(void *karg, void __user *uarg, unsigned int cmd) -{ - if ((_IOC_DIR(cmd) & _IOC_WRITE) && - copy_from_user(karg, uarg, _IOC_SIZE(cmd))) - return -EFAULT; - - return 0; -} - -static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd) -{ - if ((_IOC_DIR(cmd) & _IOC_READ) && - copy_to_user(uarg, karg, _IOC_SIZE(cmd))) - return -EFAULT; - - return 0; -} - -/* Do acquire the graph mutex */ -#define MEDIA_IOC_FL_GRAPH_MUTEX BIT(0) - -#define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user) \ - [_IOC_NR(MEDIA_IOC_##__cmd)] = { \ - .cmd = MEDIA_IOC_##__cmd, \ - .fn = (long (*)(struct media_device *, void *))func, \ - .flags = fl, \ - .arg_from_user = from_user, \ - .arg_to_user = to_user, \ - } - -#define MEDIA_IOC(__cmd, func, fl) \ - MEDIA_IOC_ARG(__cmd, func, fl, copy_arg_from_user, copy_arg_to_user) - -/* the table is indexed by _IOC_NR(cmd) */ -struct media_ioctl_info { - unsigned int cmd; - unsigned short flags; - long (*fn)(struct media_device *dev, void *arg); - long (*arg_from_user)(void *karg, void __user *uarg, unsigned int cmd); - long (*arg_to_user)(void __user *uarg, void *karg, unsigned int cmd); -}; - -static const struct media_ioctl_info ioctl_info[] = { - MEDIA_IOC(DEVICE_INFO, media_device_get_info, MEDIA_IOC_FL_GRAPH_MUTEX), - MEDIA_IOC(ENUM_ENTITIES, media_device_enum_entities, MEDIA_IOC_FL_GRAPH_MUTEX), - MEDIA_IOC(ENUM_LINKS, media_device_enum_links, MEDIA_IOC_FL_GRAPH_MUTEX), - MEDIA_IOC(SETUP_LINK, media_device_setup_link, MEDIA_IOC_FL_GRAPH_MUTEX), - MEDIA_IOC(G_TOPOLOGY, media_device_get_topology, MEDIA_IOC_FL_GRAPH_MUTEX), - MEDIA_IOC(REQUEST_ALLOC, media_device_request_alloc, 0), -}; - -static long media_device_ioctl(struct file *filp, unsigned int cmd, - unsigned long __arg) -{ - struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = devnode->media_dev; - const struct media_ioctl_info *info; - void __user *arg = (void __user *)__arg; - char __karg[256], *karg = __karg; - long ret; - - if (_IOC_NR(cmd) >= ARRAY_SIZE(ioctl_info) - || ioctl_info[_IOC_NR(cmd)].cmd != cmd) - return -ENOIOCTLCMD; - - info = &ioctl_info[_IOC_NR(cmd)]; - - if (_IOC_SIZE(info->cmd) > sizeof(__karg)) { - karg = kmalloc(_IOC_SIZE(info->cmd), GFP_KERNEL); - if (!karg) - return -ENOMEM; - } - - if (info->arg_from_user) { - ret = info->arg_from_user(karg, arg, cmd); - if (ret) - goto out_free; - } - - if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX) - mutex_lock(&dev->graph_mutex); - - ret = info->fn(dev, karg); - - if (info->flags & MEDIA_IOC_FL_GRAPH_MUTEX) - mutex_unlock(&dev->graph_mutex); - - if (!ret && info->arg_to_user) - ret = info->arg_to_user(arg, karg, cmd); - -out_free: - if (karg != __karg) - kfree(karg); - - return ret; -} - -#ifdef CONFIG_COMPAT - -struct media_links_enum32 { - __u32 entity; - compat_uptr_t pads; /* struct media_pad_desc * */ - compat_uptr_t links; /* struct media_link_desc * */ - __u32 reserved[4]; -}; - -static long media_device_enum_links32(struct media_device *mdev, - struct media_links_enum32 __user *ulinks) -{ - struct media_links_enum links; - compat_uptr_t pads_ptr, links_ptr; - int ret; - - memset(&links, 0, sizeof(links)); - - if (get_user(links.entity, &ulinks->entity) - || get_user(pads_ptr, &ulinks->pads) - || get_user(links_ptr, &ulinks->links)) - return -EFAULT; - - links.pads = compat_ptr(pads_ptr); - links.links = compat_ptr(links_ptr); - - ret = media_device_enum_links(mdev, &links); - if (ret) - return ret; - - memset(ulinks->reserved, 0, sizeof(ulinks->reserved)); - - return 0; -} - -#define MEDIA_IOC_ENUM_LINKS32 _IOWR('|', 0x02, struct media_links_enum32) - -static long media_device_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct media_devnode *devnode = media_devnode_data(filp); - struct media_device *dev = devnode->media_dev; - long ret; - - switch (cmd) { - case MEDIA_IOC_ENUM_LINKS32: - mutex_lock(&dev->graph_mutex); - ret = media_device_enum_links32(dev, - (struct media_links_enum32 __user *)arg); - mutex_unlock(&dev->graph_mutex); - break; - - default: - return media_device_ioctl(filp, cmd, arg); - } - - return ret; -} -#endif /* CONFIG_COMPAT */ - -static const struct media_file_operations media_device_fops = { - .owner = THIS_MODULE, - .open = media_device_open, - .ioctl = media_device_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = media_device_compat_ioctl, -#endif /* CONFIG_COMPAT */ - .release = media_device_close, -}; - -/* ----------------------------------------------------------------------------- - * sysfs - */ - -static ssize_t show_model(struct device *cd, - struct device_attribute *attr, char *buf) -{ - struct media_devnode *devnode = to_media_devnode(cd); - struct media_device *mdev = devnode->media_dev; - - return sprintf(buf, "%.*s\n", (int)sizeof(mdev->model), mdev->model); -} - -static DEVICE_ATTR(model, S_IRUGO, show_model, NULL); - -/* ----------------------------------------------------------------------------- - * Registration/unregistration - */ - -static void media_device_release(struct media_devnode *devnode) -{ - dev_dbg(devnode->parent, "Media device released\n"); -} - -/** - * media_device_register_entity - Register an entity with a media device - * @mdev: The media device - * @entity: The entity - */ -int __must_check media_device_register_entity(struct media_device *mdev, - struct media_entity *entity) -{ - struct media_entity_notify *notify, *next; - unsigned int i; - int ret; - - if (entity->function == MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN || - entity->function == MEDIA_ENT_F_UNKNOWN) - dev_warn(mdev->dev, - "Entity type for entity %s was not initialized!\n", - entity->name); - - /* Warn if we apparently re-register an entity */ - WARN_ON(entity->graph_obj.mdev != NULL); - entity->graph_obj.mdev = mdev; - INIT_LIST_HEAD(&entity->links); - entity->num_links = 0; - entity->num_backlinks = 0; - - ret = ida_alloc_min(&mdev->entity_internal_idx, 1, GFP_KERNEL); - if (ret < 0) - return ret; - entity->internal_idx = ret; - - mutex_lock(&mdev->graph_mutex); - mdev->entity_internal_idx_max = - max(mdev->entity_internal_idx_max, entity->internal_idx); - - /* Initialize media_gobj embedded at the entity */ - media_gobj_create(mdev, MEDIA_GRAPH_ENTITY, &entity->graph_obj); - - /* Initialize objects at the pads */ - for (i = 0; i < entity->num_pads; i++) - media_gobj_create(mdev, MEDIA_GRAPH_PAD, - &entity->pads[i].graph_obj); - - /* invoke entity_notify callbacks */ - list_for_each_entry_safe(notify, next, &mdev->entity_notify, list) - notify->notify(entity, notify->notify_data); - - if (mdev->entity_internal_idx_max - >= mdev->pm_count_walk.ent_enum.idx_max) { - struct media_graph new = { .top = 0 }; - - /* - * Initialise the new graph walk before cleaning up - * the old one in order not to spoil the graph walk - * object of the media device if graph walk init fails. - */ - ret = media_graph_walk_init(&new, mdev); - if (ret) { - mutex_unlock(&mdev->graph_mutex); - return ret; - } - media_graph_walk_cleanup(&mdev->pm_count_walk); - mdev->pm_count_walk = new; - } - mutex_unlock(&mdev->graph_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(media_device_register_entity); - -static void __media_device_unregister_entity(struct media_entity *entity) -{ - struct media_device *mdev = entity->graph_obj.mdev; - struct media_link *link, *tmp; - struct media_interface *intf; - unsigned int i; - - ida_free(&mdev->entity_internal_idx, entity->internal_idx); - - /* Remove all interface links pointing to this entity */ - list_for_each_entry(intf, &mdev->interfaces, graph_obj.list) { - list_for_each_entry_safe(link, tmp, &intf->links, list) { - if (link->entity == entity) - __media_remove_intf_link(link); - } - } - - /* Remove all data links that belong to this entity */ - __media_entity_remove_links(entity); - - /* Remove all pads that belong to this entity */ - for (i = 0; i < entity->num_pads; i++) - media_gobj_destroy(&entity->pads[i].graph_obj); - - /* Remove the entity */ - media_gobj_destroy(&entity->graph_obj); - - /* invoke entity_notify callbacks to handle entity removal?? */ - - entity->graph_obj.mdev = NULL; -} - -void media_device_unregister_entity(struct media_entity *entity) -{ - struct media_device *mdev = entity->graph_obj.mdev; - - if (mdev == NULL) - return; - - mutex_lock(&mdev->graph_mutex); - __media_device_unregister_entity(entity); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_device_unregister_entity); - -/** - * media_device_init() - initialize a media device - * @mdev: The media device - * - * The caller is responsible for initializing the media device before - * registration. The following fields must be set: - * - * - dev must point to the parent device - * - model must be filled with the device model name - */ -void media_device_init(struct media_device *mdev) -{ - INIT_LIST_HEAD(&mdev->entities); - INIT_LIST_HEAD(&mdev->interfaces); - INIT_LIST_HEAD(&mdev->pads); - INIT_LIST_HEAD(&mdev->links); - INIT_LIST_HEAD(&mdev->entity_notify); - - mutex_init(&mdev->req_queue_mutex); - mutex_init(&mdev->graph_mutex); - ida_init(&mdev->entity_internal_idx); - - atomic_set(&mdev->request_id, 0); - - dev_dbg(mdev->dev, "Media device initialized\n"); -} -EXPORT_SYMBOL_GPL(media_device_init); - -void media_device_cleanup(struct media_device *mdev) -{ - ida_destroy(&mdev->entity_internal_idx); - mdev->entity_internal_idx_max = 0; - media_graph_walk_cleanup(&mdev->pm_count_walk); - mutex_destroy(&mdev->graph_mutex); - mutex_destroy(&mdev->req_queue_mutex); -} -EXPORT_SYMBOL_GPL(media_device_cleanup); - -int __must_check __media_device_register(struct media_device *mdev, - struct module *owner) -{ - struct media_devnode *devnode; - int ret; - - devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); - if (!devnode) - return -ENOMEM; - - /* Register the device node. */ - mdev->devnode = devnode; - devnode->fops = &media_device_fops; - devnode->parent = mdev->dev; - devnode->release = media_device_release; - - /* Set version 0 to indicate user-space that the graph is static */ - mdev->topology_version = 0; - - ret = media_devnode_register(mdev, devnode, owner); - if (ret < 0) { - /* devnode free is handled in media_devnode_*() */ - mdev->devnode = NULL; - return ret; - } - - ret = device_create_file(&devnode->dev, &dev_attr_model); - if (ret < 0) { - /* devnode free is handled in media_devnode_*() */ - mdev->devnode = NULL; - media_devnode_unregister_prepare(devnode); - media_devnode_unregister(devnode); - return ret; - } - - dev_dbg(mdev->dev, "Media device registered\n"); - - return 0; -} -EXPORT_SYMBOL_GPL(__media_device_register); - -int __must_check media_device_register_entity_notify(struct media_device *mdev, - struct media_entity_notify *nptr) -{ - mutex_lock(&mdev->graph_mutex); - list_add_tail(&nptr->list, &mdev->entity_notify); - mutex_unlock(&mdev->graph_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(media_device_register_entity_notify); - -/* - * Note: Should be called with mdev->lock held. - */ -static void __media_device_unregister_entity_notify(struct media_device *mdev, - struct media_entity_notify *nptr) -{ - list_del(&nptr->list); -} - -void media_device_unregister_entity_notify(struct media_device *mdev, - struct media_entity_notify *nptr) -{ - mutex_lock(&mdev->graph_mutex); - __media_device_unregister_entity_notify(mdev, nptr); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify); - -void media_device_unregister(struct media_device *mdev) -{ - struct media_entity *entity; - struct media_entity *next; - struct media_interface *intf, *tmp_intf; - struct media_entity_notify *notify, *nextp; - - if (mdev == NULL) - return; - - mutex_lock(&mdev->graph_mutex); - - /* Check if mdev was ever registered at all */ - if (!media_devnode_is_registered(mdev->devnode)) { - mutex_unlock(&mdev->graph_mutex); - return; - } - - /* Clear the devnode register bit to avoid races with media dev open */ - media_devnode_unregister_prepare(mdev->devnode); - - /* Remove all entities from the media device */ - list_for_each_entry_safe(entity, next, &mdev->entities, graph_obj.list) - __media_device_unregister_entity(entity); - - /* Remove all entity_notify callbacks from the media device */ - list_for_each_entry_safe(notify, nextp, &mdev->entity_notify, list) - __media_device_unregister_entity_notify(mdev, notify); - - /* Remove all interfaces from the media device */ - list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, - graph_obj.list) { - /* - * Unlink the interface, but don't free it here; the - * module which created it is responsible for freeing - * it - */ - __media_remove_intf_links(intf); - media_gobj_destroy(&intf->graph_obj); - } - - mutex_unlock(&mdev->graph_mutex); - - dev_dbg(mdev->dev, "Media device unregistered\n"); - - device_remove_file(&mdev->devnode->dev, &dev_attr_model); - media_devnode_unregister(mdev->devnode); - /* devnode free is handled in media_devnode_*() */ - mdev->devnode = NULL; -} -EXPORT_SYMBOL_GPL(media_device_unregister); - -#if IS_ENABLED(CONFIG_PCI) -void media_device_pci_init(struct media_device *mdev, - struct pci_dev *pci_dev, - const char *name) -{ - mdev->dev = &pci_dev->dev; - - if (name) - strscpy(mdev->model, name, sizeof(mdev->model)); - else - strscpy(mdev->model, pci_name(pci_dev), sizeof(mdev->model)); - - sprintf(mdev->bus_info, "PCI:%s", pci_name(pci_dev)); - - mdev->hw_revision = (pci_dev->subsystem_vendor << 16) - | pci_dev->subsystem_device; - - media_device_init(mdev); -} -EXPORT_SYMBOL_GPL(media_device_pci_init); -#endif - -#if IS_ENABLED(CONFIG_USB) -void __media_device_usb_init(struct media_device *mdev, - struct usb_device *udev, - const char *board_name, - const char *driver_name) -{ - mdev->dev = &udev->dev; - - if (driver_name) - strscpy(mdev->driver_name, driver_name, - sizeof(mdev->driver_name)); - - if (board_name) - strscpy(mdev->model, board_name, sizeof(mdev->model)); - else if (udev->product) - strscpy(mdev->model, udev->product, sizeof(mdev->model)); - else - strscpy(mdev->model, "unknown model", sizeof(mdev->model)); - if (udev->serial) - strscpy(mdev->serial, udev->serial, sizeof(mdev->serial)); - usb_make_path(udev, mdev->bus_info, sizeof(mdev->bus_info)); - mdev->hw_revision = le16_to_cpu(udev->descriptor.bcdDevice); - - media_device_init(mdev); -} -EXPORT_SYMBOL_GPL(__media_device_usb_init); -#endif - - -#endif /* CONFIG_MEDIA_CONTROLLER */ diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c deleted file mode 100644 index d5aa30eeff4a..000000000000 --- a/drivers/media/media-devnode.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Media device node - * - * Copyright (C) 2010 Nokia Corporation - * - * Based on drivers/media/video/v4l2_dev.c code authored by - * Mauro Carvalho Chehab (version 2) - * Alan Cox, (version 1) - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - * - * -- - * - * Generic media device node infrastructure to register and unregister - * character devices using a dynamic major number and proper reference - * counting. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define MEDIA_NUM_DEVICES 256 -#define MEDIA_NAME "media" - -static dev_t media_dev_t; - -/* - * Active devices - */ -static DEFINE_MUTEX(media_devnode_lock); -static DECLARE_BITMAP(media_devnode_nums, MEDIA_NUM_DEVICES); - -/* Called when the last user of the media device exits. */ -static void media_devnode_release(struct device *cd) -{ - struct media_devnode *devnode = to_media_devnode(cd); - - mutex_lock(&media_devnode_lock); - /* Mark device node number as free */ - clear_bit(devnode->minor, media_devnode_nums); - mutex_unlock(&media_devnode_lock); - - /* Release media_devnode and perform other cleanups as needed. */ - if (devnode->release) - devnode->release(devnode); - - kfree(devnode); - pr_debug("%s: Media Devnode Deallocated\n", __func__); -} - -static struct bus_type media_bus_type = { - .name = MEDIA_NAME, -}; - -static ssize_t media_read(struct file *filp, char __user *buf, - size_t sz, loff_t *off) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - if (!devnode->fops->read) - return -EINVAL; - if (!media_devnode_is_registered(devnode)) - return -EIO; - return devnode->fops->read(filp, buf, sz, off); -} - -static ssize_t media_write(struct file *filp, const char __user *buf, - size_t sz, loff_t *off) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - if (!devnode->fops->write) - return -EINVAL; - if (!media_devnode_is_registered(devnode)) - return -EIO; - return devnode->fops->write(filp, buf, sz, off); -} - -static __poll_t media_poll(struct file *filp, - struct poll_table_struct *poll) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - if (!media_devnode_is_registered(devnode)) - return EPOLLERR | EPOLLHUP; - if (!devnode->fops->poll) - return DEFAULT_POLLMASK; - return devnode->fops->poll(filp, poll); -} - -static long -__media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg, - long (*ioctl_func)(struct file *filp, unsigned int cmd, - unsigned long arg)) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - if (!ioctl_func) - return -ENOTTY; - - if (!media_devnode_is_registered(devnode)) - return -EIO; - - return ioctl_func(filp, cmd, arg); -} - -static long media_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - return __media_ioctl(filp, cmd, arg, devnode->fops->ioctl); -} - -#ifdef CONFIG_COMPAT - -static long media_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - return __media_ioctl(filp, cmd, arg, devnode->fops->compat_ioctl); -} - -#endif /* CONFIG_COMPAT */ - -/* Override for the open function */ -static int media_open(struct inode *inode, struct file *filp) -{ - struct media_devnode *devnode; - int ret; - - /* Check if the media device is available. This needs to be done with - * the media_devnode_lock held to prevent an open/unregister race: - * without the lock, the device could be unregistered and freed between - * the media_devnode_is_registered() and get_device() calls, leading to - * a crash. - */ - mutex_lock(&media_devnode_lock); - devnode = container_of(inode->i_cdev, struct media_devnode, cdev); - /* return ENXIO if the media device has been removed - already or if it is not registered anymore. */ - if (!media_devnode_is_registered(devnode)) { - mutex_unlock(&media_devnode_lock); - return -ENXIO; - } - /* and increase the device refcount */ - get_device(&devnode->dev); - mutex_unlock(&media_devnode_lock); - - filp->private_data = devnode; - - if (devnode->fops->open) { - ret = devnode->fops->open(filp); - if (ret) { - put_device(&devnode->dev); - filp->private_data = NULL; - return ret; - } - } - - return 0; -} - -/* Override for the release function */ -static int media_release(struct inode *inode, struct file *filp) -{ - struct media_devnode *devnode = media_devnode_data(filp); - - if (devnode->fops->release) - devnode->fops->release(filp); - - filp->private_data = NULL; - - /* decrease the refcount unconditionally since the release() - return value is ignored. */ - put_device(&devnode->dev); - - pr_debug("%s: Media Release\n", __func__); - return 0; -} - -static const struct file_operations media_devnode_fops = { - .owner = THIS_MODULE, - .read = media_read, - .write = media_write, - .open = media_open, - .unlocked_ioctl = media_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = media_compat_ioctl, -#endif /* CONFIG_COMPAT */ - .release = media_release, - .poll = media_poll, - .llseek = no_llseek, -}; - -int __must_check media_devnode_register(struct media_device *mdev, - struct media_devnode *devnode, - struct module *owner) -{ - int minor; - int ret; - - /* Part 1: Find a free minor number */ - mutex_lock(&media_devnode_lock); - minor = find_next_zero_bit(media_devnode_nums, MEDIA_NUM_DEVICES, 0); - if (minor == MEDIA_NUM_DEVICES) { - mutex_unlock(&media_devnode_lock); - pr_err("could not get a free minor\n"); - kfree(devnode); - return -ENFILE; - } - - set_bit(minor, media_devnode_nums); - mutex_unlock(&media_devnode_lock); - - devnode->minor = minor; - devnode->media_dev = mdev; - - /* Part 1: Initialize dev now to use dev.kobj for cdev.kobj.parent */ - devnode->dev.bus = &media_bus_type; - devnode->dev.devt = MKDEV(MAJOR(media_dev_t), devnode->minor); - devnode->dev.release = media_devnode_release; - if (devnode->parent) - devnode->dev.parent = devnode->parent; - dev_set_name(&devnode->dev, "media%d", devnode->minor); - device_initialize(&devnode->dev); - - /* Part 2: Initialize the character device */ - cdev_init(&devnode->cdev, &media_devnode_fops); - devnode->cdev.owner = owner; - kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); - - /* Part 3: Add the media and char device */ - ret = cdev_device_add(&devnode->cdev, &devnode->dev); - if (ret < 0) { - pr_err("%s: cdev_device_add failed\n", __func__); - goto cdev_add_error; - } - - /* Part 4: Activate this minor. The char device can now be used. */ - set_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); - - return 0; - -cdev_add_error: - mutex_lock(&media_devnode_lock); - clear_bit(devnode->minor, media_devnode_nums); - devnode->media_dev = NULL; - mutex_unlock(&media_devnode_lock); - - put_device(&devnode->dev); - return ret; -} - -void media_devnode_unregister_prepare(struct media_devnode *devnode) -{ - /* Check if devnode was ever registered at all */ - if (!media_devnode_is_registered(devnode)) - return; - - mutex_lock(&media_devnode_lock); - clear_bit(MEDIA_FLAG_REGISTERED, &devnode->flags); - mutex_unlock(&media_devnode_lock); -} - -void media_devnode_unregister(struct media_devnode *devnode) -{ - mutex_lock(&media_devnode_lock); - /* Delete the cdev on this minor as well */ - cdev_device_del(&devnode->cdev, &devnode->dev); - devnode->media_dev = NULL; - mutex_unlock(&media_devnode_lock); - - put_device(&devnode->dev); -} - -/* - * Initialise media for linux - */ -static int __init media_devnode_init(void) -{ - int ret; - - pr_info("Linux media interface: v0.10\n"); - ret = alloc_chrdev_region(&media_dev_t, 0, MEDIA_NUM_DEVICES, - MEDIA_NAME); - if (ret < 0) { - pr_warn("unable to allocate major\n"); - return ret; - } - - ret = bus_register(&media_bus_type); - if (ret < 0) { - unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); - pr_warn("bus_register failed\n"); - return -EIO; - } - - return 0; -} - -static void __exit media_devnode_exit(void) -{ - bus_unregister(&media_bus_type); - unregister_chrdev_region(media_dev_t, MEDIA_NUM_DEVICES); -} - -subsys_initcall(media_devnode_init); -module_exit(media_devnode_exit) - -MODULE_AUTHOR("Laurent Pinchart "); -MODULE_DESCRIPTION("Device node registration for media drivers"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c deleted file mode 100644 index a998a2e0ea1d..000000000000 --- a/drivers/media/media-entity.c +++ /dev/null @@ -1,1036 +0,0 @@ -/* - * Media entity - * - * Copyright (C) 2010 Nokia Corporation - * - * Contacts: Laurent Pinchart - * Sakari Ailus - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ - -#include -#include -#include -#include -#include - -static inline const char *gobj_type(enum media_gobj_type type) -{ - switch (type) { - case MEDIA_GRAPH_ENTITY: - return "entity"; - case MEDIA_GRAPH_PAD: - return "pad"; - case MEDIA_GRAPH_LINK: - return "link"; - case MEDIA_GRAPH_INTF_DEVNODE: - return "intf-devnode"; - default: - return "unknown"; - } -} - -static inline const char *intf_type(struct media_interface *intf) -{ - switch (intf->type) { - case MEDIA_INTF_T_DVB_FE: - return "dvb-frontend"; - case MEDIA_INTF_T_DVB_DEMUX: - return "dvb-demux"; - case MEDIA_INTF_T_DVB_DVR: - return "dvb-dvr"; - case MEDIA_INTF_T_DVB_CA: - return "dvb-ca"; - case MEDIA_INTF_T_DVB_NET: - return "dvb-net"; - case MEDIA_INTF_T_V4L_VIDEO: - return "v4l-video"; - case MEDIA_INTF_T_V4L_VBI: - return "v4l-vbi"; - case MEDIA_INTF_T_V4L_RADIO: - return "v4l-radio"; - case MEDIA_INTF_T_V4L_SUBDEV: - return "v4l-subdev"; - case MEDIA_INTF_T_V4L_SWRADIO: - return "v4l-swradio"; - case MEDIA_INTF_T_V4L_TOUCH: - return "v4l-touch"; - default: - return "unknown-intf"; - } -}; - -__must_check int __media_entity_enum_init(struct media_entity_enum *ent_enum, - int idx_max) -{ - idx_max = ALIGN(idx_max, BITS_PER_LONG); - ent_enum->bmap = kcalloc(idx_max / BITS_PER_LONG, sizeof(long), - GFP_KERNEL); - if (!ent_enum->bmap) - return -ENOMEM; - - bitmap_zero(ent_enum->bmap, idx_max); - ent_enum->idx_max = idx_max; - - return 0; -} -EXPORT_SYMBOL_GPL(__media_entity_enum_init); - -void media_entity_enum_cleanup(struct media_entity_enum *ent_enum) -{ - kfree(ent_enum->bmap); -} -EXPORT_SYMBOL_GPL(media_entity_enum_cleanup); - -/** - * dev_dbg_obj - Prints in debug mode a change on some object - * - * @event_name: Name of the event to report. Could be __func__ - * @gobj: Pointer to the object - * - * Enabled only if DEBUG or CONFIG_DYNAMIC_DEBUG. Otherwise, it - * won't produce any code. - */ -static void dev_dbg_obj(const char *event_name, struct media_gobj *gobj) -{ -#if defined(DEBUG) || defined (CONFIG_DYNAMIC_DEBUG) - switch (media_type(gobj)) { - case MEDIA_GRAPH_ENTITY: - dev_dbg(gobj->mdev->dev, - "%s id %u: entity '%s'\n", - event_name, media_id(gobj), - gobj_to_entity(gobj)->name); - break; - case MEDIA_GRAPH_LINK: - { - struct media_link *link = gobj_to_link(gobj); - - dev_dbg(gobj->mdev->dev, - "%s id %u: %s link id %u ==> id %u\n", - event_name, media_id(gobj), - media_type(link->gobj0) == MEDIA_GRAPH_PAD ? - "data" : "interface", - media_id(link->gobj0), - media_id(link->gobj1)); - break; - } - case MEDIA_GRAPH_PAD: - { - struct media_pad *pad = gobj_to_pad(gobj); - - dev_dbg(gobj->mdev->dev, - "%s id %u: %s%spad '%s':%d\n", - event_name, media_id(gobj), - pad->flags & MEDIA_PAD_FL_SINK ? "sink " : "", - pad->flags & MEDIA_PAD_FL_SOURCE ? "source " : "", - pad->entity->name, pad->index); - break; - } - case MEDIA_GRAPH_INTF_DEVNODE: - { - struct media_interface *intf = gobj_to_intf(gobj); - struct media_intf_devnode *devnode = intf_to_devnode(intf); - - dev_dbg(gobj->mdev->dev, - "%s id %u: intf_devnode %s - major: %d, minor: %d\n", - event_name, media_id(gobj), - intf_type(intf), - devnode->major, devnode->minor); - break; - } - } -#endif -} - -void media_gobj_create(struct media_device *mdev, - enum media_gobj_type type, - struct media_gobj *gobj) -{ - BUG_ON(!mdev); - - gobj->mdev = mdev; - - /* Create a per-type unique object ID */ - gobj->id = media_gobj_gen_id(type, ++mdev->id); - - switch (type) { - case MEDIA_GRAPH_ENTITY: - list_add_tail(&gobj->list, &mdev->entities); - break; - case MEDIA_GRAPH_PAD: - list_add_tail(&gobj->list, &mdev->pads); - break; - case MEDIA_GRAPH_LINK: - list_add_tail(&gobj->list, &mdev->links); - break; - case MEDIA_GRAPH_INTF_DEVNODE: - list_add_tail(&gobj->list, &mdev->interfaces); - break; - } - - mdev->topology_version++; - - dev_dbg_obj(__func__, gobj); -} - -void media_gobj_destroy(struct media_gobj *gobj) -{ - /* Do nothing if the object is not linked. */ - if (gobj->mdev == NULL) - return; - - dev_dbg_obj(__func__, gobj); - - gobj->mdev->topology_version++; - - /* Remove the object from mdev list */ - list_del(&gobj->list); - - gobj->mdev = NULL; -} - -/* - * TODO: Get rid of this. - */ -#define MEDIA_ENTITY_MAX_PADS 512 - -int media_entity_pads_init(struct media_entity *entity, u16 num_pads, - struct media_pad *pads) -{ - struct media_device *mdev = entity->graph_obj.mdev; - unsigned int i; - - if (num_pads >= MEDIA_ENTITY_MAX_PADS) - return -E2BIG; - - entity->num_pads = num_pads; - entity->pads = pads; - - if (mdev) - mutex_lock(&mdev->graph_mutex); - - for (i = 0; i < num_pads; i++) { - pads[i].entity = entity; - pads[i].index = i; - if (mdev) - media_gobj_create(mdev, MEDIA_GRAPH_PAD, - &entity->pads[i].graph_obj); - } - - if (mdev) - mutex_unlock(&mdev->graph_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(media_entity_pads_init); - -/* ----------------------------------------------------------------------------- - * Graph traversal - */ - -static struct media_entity * -media_entity_other(struct media_entity *entity, struct media_link *link) -{ - if (link->source->entity == entity) - return link->sink->entity; - else - return link->source->entity; -} - -/* push an entity to traversal stack */ -static void stack_push(struct media_graph *graph, - struct media_entity *entity) -{ - if (graph->top == MEDIA_ENTITY_ENUM_MAX_DEPTH - 1) { - WARN_ON(1); - return; - } - graph->top++; - graph->stack[graph->top].link = entity->links.next; - graph->stack[graph->top].entity = entity; -} - -static struct media_entity *stack_pop(struct media_graph *graph) -{ - struct media_entity *entity; - - entity = graph->stack[graph->top].entity; - graph->top--; - - return entity; -} - -#define link_top(en) ((en)->stack[(en)->top].link) -#define stack_top(en) ((en)->stack[(en)->top].entity) - -/** - * media_graph_walk_init - Allocate resources for graph walk - * @graph: Media graph structure that will be used to walk the graph - * @mdev: Media device - * - * Reserve resources for graph walk in media device's current - * state. The memory must be released using - * media_graph_walk_free(). - * - * Returns error on failure, zero on success. - */ -__must_check int media_graph_walk_init( - struct media_graph *graph, struct media_device *mdev) -{ - return media_entity_enum_init(&graph->ent_enum, mdev); -} -EXPORT_SYMBOL_GPL(media_graph_walk_init); - -/** - * media_graph_walk_cleanup - Release resources related to graph walking - * @graph: Media graph structure that was used to walk the graph - */ -void media_graph_walk_cleanup(struct media_graph *graph) -{ - media_entity_enum_cleanup(&graph->ent_enum); -} -EXPORT_SYMBOL_GPL(media_graph_walk_cleanup); - -void media_graph_walk_start(struct media_graph *graph, - struct media_entity *entity) -{ - media_entity_enum_zero(&graph->ent_enum); - media_entity_enum_set(&graph->ent_enum, entity); - - graph->top = 0; - graph->stack[graph->top].entity = NULL; - stack_push(graph, entity); - dev_dbg(entity->graph_obj.mdev->dev, - "begin graph walk at '%s'\n", entity->name); -} -EXPORT_SYMBOL_GPL(media_graph_walk_start); - -static void media_graph_walk_iter(struct media_graph *graph) -{ - struct media_entity *entity = stack_top(graph); - struct media_link *link; - struct media_entity *next; - - link = list_entry(link_top(graph), typeof(*link), list); - - /* The link is not enabled so we do not follow. */ - if (!(link->flags & MEDIA_LNK_FL_ENABLED)) { - link_top(graph) = link_top(graph)->next; - dev_dbg(entity->graph_obj.mdev->dev, - "walk: skipping disabled link '%s':%u -> '%s':%u\n", - link->source->entity->name, link->source->index, - link->sink->entity->name, link->sink->index); - return; - } - - /* Get the entity in the other end of the link . */ - next = media_entity_other(entity, link); - - /* Has the entity already been visited? */ - if (media_entity_enum_test_and_set(&graph->ent_enum, next)) { - link_top(graph) = link_top(graph)->next; - dev_dbg(entity->graph_obj.mdev->dev, - "walk: skipping entity '%s' (already seen)\n", - next->name); - return; - } - - /* Push the new entity to stack and start over. */ - link_top(graph) = link_top(graph)->next; - stack_push(graph, next); - dev_dbg(entity->graph_obj.mdev->dev, "walk: pushing '%s' on stack\n", - next->name); -} - -struct media_entity *media_graph_walk_next(struct media_graph *graph) -{ - struct media_entity *entity; - - if (stack_top(graph) == NULL) - return NULL; - - /* - * Depth first search. Push entity to stack and continue from - * top of the stack until no more entities on the level can be - * found. - */ - while (link_top(graph) != &stack_top(graph)->links) - media_graph_walk_iter(graph); - - entity = stack_pop(graph); - dev_dbg(entity->graph_obj.mdev->dev, - "walk: returning entity '%s'\n", entity->name); - - return entity; -} -EXPORT_SYMBOL_GPL(media_graph_walk_next); - -int media_entity_get_fwnode_pad(struct media_entity *entity, - struct fwnode_handle *fwnode, - unsigned long direction_flags) -{ - struct fwnode_endpoint endpoint; - unsigned int i; - int ret; - - if (!entity->ops || !entity->ops->get_fwnode_pad) { - for (i = 0; i < entity->num_pads; i++) { - if (entity->pads[i].flags & direction_flags) - return i; - } - - return -ENXIO; - } - - ret = fwnode_graph_parse_endpoint(fwnode, &endpoint); - if (ret) - return ret; - - ret = entity->ops->get_fwnode_pad(&endpoint); - if (ret < 0) - return ret; - - if (ret >= entity->num_pads) - return -ENXIO; - - if (!(entity->pads[ret].flags & direction_flags)) - return -ENXIO; - - return ret; -} -EXPORT_SYMBOL_GPL(media_entity_get_fwnode_pad); - -/* ----------------------------------------------------------------------------- - * Pipeline management - */ - -__must_check int __media_pipeline_start(struct media_entity *entity, - struct media_pipeline *pipe) -{ - struct media_device *mdev = entity->graph_obj.mdev; - struct media_graph *graph = &pipe->graph; - struct media_entity *entity_err = entity; - struct media_link *link; - int ret; - - if (!pipe->streaming_count++) { - ret = media_graph_walk_init(&pipe->graph, mdev); - if (ret) - goto error_graph_walk_start; - } - - media_graph_walk_start(&pipe->graph, entity); - - while ((entity = media_graph_walk_next(graph))) { - DECLARE_BITMAP(active, MEDIA_ENTITY_MAX_PADS); - DECLARE_BITMAP(has_no_links, MEDIA_ENTITY_MAX_PADS); - - entity->stream_count++; - - if (entity->pipe && entity->pipe != pipe) { - pr_err("Pipe active for %s. Can't start for %s\n", - entity->name, - entity_err->name); - ret = -EBUSY; - goto error; - } - - entity->pipe = pipe; - - /* Already streaming --- no need to check. */ - if (entity->stream_count > 1) - continue; - - if (!entity->ops || !entity->ops->link_validate) - continue; - - bitmap_zero(active, entity->num_pads); - bitmap_fill(has_no_links, entity->num_pads); - - list_for_each_entry(link, &entity->links, list) { - struct media_pad *pad = link->sink->entity == entity - ? link->sink : link->source; - - /* Mark that a pad is connected by a link. */ - bitmap_clear(has_no_links, pad->index, 1); - - /* - * Pads that either do not need to connect or - * are connected through an enabled link are - * fine. - */ - if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) || - link->flags & MEDIA_LNK_FL_ENABLED) - bitmap_set(active, pad->index, 1); - - /* - * Link validation will only take place for - * sink ends of the link that are enabled. - */ - if (link->sink != pad || - !(link->flags & MEDIA_LNK_FL_ENABLED)) - continue; - - ret = entity->ops->link_validate(link); - if (ret < 0 && ret != -ENOIOCTLCMD) { - dev_dbg(entity->graph_obj.mdev->dev, - "link validation failed for '%s':%u -> '%s':%u, error %d\n", - link->source->entity->name, - link->source->index, - entity->name, link->sink->index, ret); - goto error; - } - } - - /* Either no links or validated links are fine. */ - bitmap_or(active, active, has_no_links, entity->num_pads); - - if (!bitmap_full(active, entity->num_pads)) { - ret = -ENOLINK; - dev_dbg(entity->graph_obj.mdev->dev, - "'%s':%u must be connected by an enabled link\n", - entity->name, - (unsigned)find_first_zero_bit( - active, entity->num_pads)); - goto error; - } - } - - return 0; - -error: - /* - * Link validation on graph failed. We revert what we did and - * return the error. - */ - media_graph_walk_start(graph, entity_err); - - while ((entity_err = media_graph_walk_next(graph))) { - /* Sanity check for negative stream_count */ - if (!WARN_ON_ONCE(entity_err->stream_count <= 0)) { - entity_err->stream_count--; - if (entity_err->stream_count == 0) - entity_err->pipe = NULL; - } - - /* - * We haven't increased stream_count further than this - * so we quit here. - */ - if (entity_err == entity) - break; - } - -error_graph_walk_start: - if (!--pipe->streaming_count) - media_graph_walk_cleanup(graph); - - return ret; -} -EXPORT_SYMBOL_GPL(__media_pipeline_start); - -__must_check int media_pipeline_start(struct media_entity *entity, - struct media_pipeline *pipe) -{ - struct media_device *mdev = entity->graph_obj.mdev; - int ret; - - mutex_lock(&mdev->graph_mutex); - ret = __media_pipeline_start(entity, pipe); - mutex_unlock(&mdev->graph_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(media_pipeline_start); - -void __media_pipeline_stop(struct media_entity *entity) -{ - struct media_graph *graph = &entity->pipe->graph; - struct media_pipeline *pipe = entity->pipe; - - /* - * If the following check fails, the driver has performed an - * unbalanced call to media_pipeline_stop() - */ - if (WARN_ON(!pipe)) - return; - - media_graph_walk_start(graph, entity); - - while ((entity = media_graph_walk_next(graph))) { - /* Sanity check for negative stream_count */ - if (!WARN_ON_ONCE(entity->stream_count <= 0)) { - entity->stream_count--; - if (entity->stream_count == 0) - entity->pipe = NULL; - } - } - - if (!--pipe->streaming_count) - media_graph_walk_cleanup(graph); - -} -EXPORT_SYMBOL_GPL(__media_pipeline_stop); - -void media_pipeline_stop(struct media_entity *entity) -{ - struct media_device *mdev = entity->graph_obj.mdev; - - mutex_lock(&mdev->graph_mutex); - __media_pipeline_stop(entity); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_pipeline_stop); - -/* ----------------------------------------------------------------------------- - * Links management - */ - -static struct media_link *media_add_link(struct list_head *head) -{ - struct media_link *link; - - link = kzalloc(sizeof(*link), GFP_KERNEL); - if (link == NULL) - return NULL; - - list_add_tail(&link->list, head); - - return link; -} - -static void __media_entity_remove_link(struct media_entity *entity, - struct media_link *link) -{ - struct media_link *rlink, *tmp; - struct media_entity *remote; - - if (link->source->entity == entity) - remote = link->sink->entity; - else - remote = link->source->entity; - - list_for_each_entry_safe(rlink, tmp, &remote->links, list) { - if (rlink != link->reverse) - continue; - - if (link->source->entity == entity) - remote->num_backlinks--; - - /* Remove the remote link */ - list_del(&rlink->list); - media_gobj_destroy(&rlink->graph_obj); - kfree(rlink); - - if (--remote->num_links == 0) - break; - } - list_del(&link->list); - media_gobj_destroy(&link->graph_obj); - kfree(link); -} - -int media_get_pad_index(struct media_entity *entity, bool is_sink, - enum media_pad_signal_type sig_type) -{ - int i; - bool pad_is_sink; - - if (!entity) - return -EINVAL; - - for (i = 0; i < entity->num_pads; i++) { - if (entity->pads[i].flags == MEDIA_PAD_FL_SINK) - pad_is_sink = true; - else if (entity->pads[i].flags == MEDIA_PAD_FL_SOURCE) - pad_is_sink = false; - else - continue; /* This is an error! */ - - if (pad_is_sink != is_sink) - continue; - if (entity->pads[i].sig_type == sig_type) - return i; - } - return -EINVAL; -} -EXPORT_SYMBOL_GPL(media_get_pad_index); - -int -media_create_pad_link(struct media_entity *source, u16 source_pad, - struct media_entity *sink, u16 sink_pad, u32 flags) -{ - struct media_link *link; - struct media_link *backlink; - - BUG_ON(source == NULL || sink == NULL); - BUG_ON(source_pad >= source->num_pads); - BUG_ON(sink_pad >= sink->num_pads); - - link = media_add_link(&source->links); - if (link == NULL) - return -ENOMEM; - - link->source = &source->pads[source_pad]; - link->sink = &sink->pads[sink_pad]; - link->flags = flags & ~MEDIA_LNK_FL_INTERFACE_LINK; - - /* Initialize graph object embedded at the new link */ - media_gobj_create(source->graph_obj.mdev, MEDIA_GRAPH_LINK, - &link->graph_obj); - - /* Create the backlink. Backlinks are used to help graph traversal and - * are not reported to userspace. - */ - backlink = media_add_link(&sink->links); - if (backlink == NULL) { - __media_entity_remove_link(source, link); - return -ENOMEM; - } - - backlink->source = &source->pads[source_pad]; - backlink->sink = &sink->pads[sink_pad]; - backlink->flags = flags; - backlink->is_backlink = true; - - /* Initialize graph object embedded at the new link */ - media_gobj_create(sink->graph_obj.mdev, MEDIA_GRAPH_LINK, - &backlink->graph_obj); - - link->reverse = backlink; - backlink->reverse = link; - - sink->num_backlinks++; - sink->num_links++; - source->num_links++; - - return 0; -} -EXPORT_SYMBOL_GPL(media_create_pad_link); - -int media_create_pad_links(const struct media_device *mdev, - const u32 source_function, - struct media_entity *source, - const u16 source_pad, - const u32 sink_function, - struct media_entity *sink, - const u16 sink_pad, - u32 flags, - const bool allow_both_undefined) -{ - struct media_entity *entity; - unsigned function; - int ret; - - /* Trivial case: 1:1 relation */ - if (source && sink) - return media_create_pad_link(source, source_pad, - sink, sink_pad, flags); - - /* Worse case scenario: n:n relation */ - if (!source && !sink) { - if (!allow_both_undefined) - return 0; - media_device_for_each_entity(source, mdev) { - if (source->function != source_function) - continue; - media_device_for_each_entity(sink, mdev) { - if (sink->function != sink_function) - continue; - ret = media_create_pad_link(source, source_pad, - sink, sink_pad, - flags); - if (ret) - return ret; - flags &= ~(MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - } - } - return 0; - } - - /* Handle 1:n and n:1 cases */ - if (source) - function = sink_function; - else - function = source_function; - - media_device_for_each_entity(entity, mdev) { - if (entity->function != function) - continue; - - if (source) - ret = media_create_pad_link(source, source_pad, - entity, sink_pad, flags); - else - ret = media_create_pad_link(entity, source_pad, - sink, sink_pad, flags); - if (ret) - return ret; - flags &= ~(MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); - } - return 0; -} -EXPORT_SYMBOL_GPL(media_create_pad_links); - -void __media_entity_remove_links(struct media_entity *entity) -{ - struct media_link *link, *tmp; - - list_for_each_entry_safe(link, tmp, &entity->links, list) - __media_entity_remove_link(entity, link); - - entity->num_links = 0; - entity->num_backlinks = 0; -} -EXPORT_SYMBOL_GPL(__media_entity_remove_links); - -void media_entity_remove_links(struct media_entity *entity) -{ - struct media_device *mdev = entity->graph_obj.mdev; - - /* Do nothing if the entity is not registered. */ - if (mdev == NULL) - return; - - mutex_lock(&mdev->graph_mutex); - __media_entity_remove_links(entity); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_entity_remove_links); - -static int __media_entity_setup_link_notify(struct media_link *link, u32 flags) -{ - int ret; - - /* Notify both entities. */ - ret = media_entity_call(link->source->entity, link_setup, - link->source, link->sink, flags); - if (ret < 0 && ret != -ENOIOCTLCMD) - return ret; - - ret = media_entity_call(link->sink->entity, link_setup, - link->sink, link->source, flags); - if (ret < 0 && ret != -ENOIOCTLCMD) { - media_entity_call(link->source->entity, link_setup, - link->source, link->sink, link->flags); - return ret; - } - - link->flags = flags; - link->reverse->flags = link->flags; - - return 0; -} - -int __media_entity_setup_link(struct media_link *link, u32 flags) -{ - const u32 mask = MEDIA_LNK_FL_ENABLED; - struct media_device *mdev; - struct media_entity *source, *sink; - int ret = -EBUSY; - - if (link == NULL) - return -EINVAL; - - /* The non-modifiable link flags must not be modified. */ - if ((link->flags & ~mask) != (flags & ~mask)) - return -EINVAL; - - if (link->flags & MEDIA_LNK_FL_IMMUTABLE) - return link->flags == flags ? 0 : -EINVAL; - - if (link->flags == flags) - return 0; - - source = link->source->entity; - sink = link->sink->entity; - - if (!(link->flags & MEDIA_LNK_FL_DYNAMIC) && - (source->stream_count || sink->stream_count)) - return -EBUSY; - - mdev = source->graph_obj.mdev; - - if (mdev->ops && mdev->ops->link_notify) { - ret = mdev->ops->link_notify(link, flags, - MEDIA_DEV_NOTIFY_PRE_LINK_CH); - if (ret < 0) - return ret; - } - - ret = __media_entity_setup_link_notify(link, flags); - - if (mdev->ops && mdev->ops->link_notify) - mdev->ops->link_notify(link, flags, - MEDIA_DEV_NOTIFY_POST_LINK_CH); - - return ret; -} -EXPORT_SYMBOL_GPL(__media_entity_setup_link); - -int media_entity_setup_link(struct media_link *link, u32 flags) -{ - int ret; - - mutex_lock(&link->graph_obj.mdev->graph_mutex); - ret = __media_entity_setup_link(link, flags); - mutex_unlock(&link->graph_obj.mdev->graph_mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(media_entity_setup_link); - -struct media_link * -media_entity_find_link(struct media_pad *source, struct media_pad *sink) -{ - struct media_link *link; - - list_for_each_entry(link, &source->entity->links, list) { - if (link->source->entity == source->entity && - link->source->index == source->index && - link->sink->entity == sink->entity && - link->sink->index == sink->index) - return link; - } - - return NULL; -} -EXPORT_SYMBOL_GPL(media_entity_find_link); - -struct media_pad *media_entity_remote_pad(const struct media_pad *pad) -{ - struct media_link *link; - - list_for_each_entry(link, &pad->entity->links, list) { - if (!(link->flags & MEDIA_LNK_FL_ENABLED)) - continue; - - if (link->source == pad) - return link->sink; - - if (link->sink == pad) - return link->source; - } - - return NULL; - -} -EXPORT_SYMBOL_GPL(media_entity_remote_pad); - -static void media_interface_init(struct media_device *mdev, - struct media_interface *intf, - u32 gobj_type, - u32 intf_type, u32 flags) -{ - intf->type = intf_type; - intf->flags = flags; - INIT_LIST_HEAD(&intf->links); - - media_gobj_create(mdev, gobj_type, &intf->graph_obj); -} - -/* Functions related to the media interface via device nodes */ - -struct media_intf_devnode *media_devnode_create(struct media_device *mdev, - u32 type, u32 flags, - u32 major, u32 minor) -{ - struct media_intf_devnode *devnode; - - devnode = kzalloc(sizeof(*devnode), GFP_KERNEL); - if (!devnode) - return NULL; - - devnode->major = major; - devnode->minor = minor; - - media_interface_init(mdev, &devnode->intf, MEDIA_GRAPH_INTF_DEVNODE, - type, flags); - - return devnode; -} -EXPORT_SYMBOL_GPL(media_devnode_create); - -void media_devnode_remove(struct media_intf_devnode *devnode) -{ - media_remove_intf_links(&devnode->intf); - media_gobj_destroy(&devnode->intf.graph_obj); - kfree(devnode); -} -EXPORT_SYMBOL_GPL(media_devnode_remove); - -struct media_link *media_create_intf_link(struct media_entity *entity, - struct media_interface *intf, - u32 flags) -{ - struct media_link *link; - - link = media_add_link(&intf->links); - if (link == NULL) - return NULL; - - link->intf = intf; - link->entity = entity; - link->flags = flags | MEDIA_LNK_FL_INTERFACE_LINK; - - /* Initialize graph object embedded at the new link */ - media_gobj_create(intf->graph_obj.mdev, MEDIA_GRAPH_LINK, - &link->graph_obj); - - return link; -} -EXPORT_SYMBOL_GPL(media_create_intf_link); - -void __media_remove_intf_link(struct media_link *link) -{ - list_del(&link->list); - media_gobj_destroy(&link->graph_obj); - kfree(link); -} -EXPORT_SYMBOL_GPL(__media_remove_intf_link); - -void media_remove_intf_link(struct media_link *link) -{ - struct media_device *mdev = link->graph_obj.mdev; - - /* Do nothing if the intf is not registered. */ - if (mdev == NULL) - return; - - mutex_lock(&mdev->graph_mutex); - __media_remove_intf_link(link); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_remove_intf_link); - -void __media_remove_intf_links(struct media_interface *intf) -{ - struct media_link *link, *tmp; - - list_for_each_entry_safe(link, tmp, &intf->links, list) - __media_remove_intf_link(link); - -} -EXPORT_SYMBOL_GPL(__media_remove_intf_links); - -void media_remove_intf_links(struct media_interface *intf) -{ - struct media_device *mdev = intf->graph_obj.mdev; - - /* Do nothing if the intf is not registered. */ - if (mdev == NULL) - return; - - mutex_lock(&mdev->graph_mutex); - __media_remove_intf_links(intf); - mutex_unlock(&mdev->graph_mutex); -} -EXPORT_SYMBOL_GPL(media_remove_intf_links); diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c deleted file mode 100644 index e3fca436c75b..000000000000 --- a/drivers/media/media-request.c +++ /dev/null @@ -1,503 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Media device request objects - * - * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * Copyright (C) 2018 Intel Corporation - * Copyright (C) 2018 Google, Inc. - * - * Author: Hans Verkuil - * Author: Sakari Ailus - */ - -#include -#include -#include - -#include -#include - -static const char * const request_state[] = { - [MEDIA_REQUEST_STATE_IDLE] = "idle", - [MEDIA_REQUEST_STATE_VALIDATING] = "validating", - [MEDIA_REQUEST_STATE_QUEUED] = "queued", - [MEDIA_REQUEST_STATE_COMPLETE] = "complete", - [MEDIA_REQUEST_STATE_CLEANING] = "cleaning", - [MEDIA_REQUEST_STATE_UPDATING] = "updating", -}; - -static const char * -media_request_state_str(enum media_request_state state) -{ - BUILD_BUG_ON(ARRAY_SIZE(request_state) != NR_OF_MEDIA_REQUEST_STATE); - - if (WARN_ON(state >= ARRAY_SIZE(request_state))) - return "invalid"; - return request_state[state]; -} - -static void media_request_clean(struct media_request *req) -{ - struct media_request_object *obj, *obj_safe; - - /* Just a sanity check. No other code path is allowed to change this. */ - WARN_ON(req->state != MEDIA_REQUEST_STATE_CLEANING); - WARN_ON(req->updating_count); - WARN_ON(req->access_count); - - list_for_each_entry_safe(obj, obj_safe, &req->objects, list) { - media_request_object_unbind(obj); - media_request_object_put(obj); - } - - req->updating_count = 0; - req->access_count = 0; - WARN_ON(req->num_incomplete_objects); - req->num_incomplete_objects = 0; - wake_up_interruptible_all(&req->poll_wait); -} - -static void media_request_release(struct kref *kref) -{ - struct media_request *req = - container_of(kref, struct media_request, kref); - struct media_device *mdev = req->mdev; - - dev_dbg(mdev->dev, "request: release %s\n", req->debug_str); - - /* No other users, no need for a spinlock */ - req->state = MEDIA_REQUEST_STATE_CLEANING; - - media_request_clean(req); - - if (mdev->ops->req_free) - mdev->ops->req_free(req); - else - kfree(req); -} - -void media_request_put(struct media_request *req) -{ - kref_put(&req->kref, media_request_release); -} -EXPORT_SYMBOL_GPL(media_request_put); - -static int media_request_close(struct inode *inode, struct file *filp) -{ - struct media_request *req = filp->private_data; - - media_request_put(req); - return 0; -} - -static __poll_t media_request_poll(struct file *filp, - struct poll_table_struct *wait) -{ - struct media_request *req = filp->private_data; - unsigned long flags; - __poll_t ret = 0; - - if (!(poll_requested_events(wait) & EPOLLPRI)) - return 0; - - poll_wait(filp, &req->poll_wait, wait); - spin_lock_irqsave(&req->lock, flags); - if (req->state == MEDIA_REQUEST_STATE_COMPLETE) { - ret = EPOLLPRI; - goto unlock; - } - if (req->state != MEDIA_REQUEST_STATE_QUEUED) { - ret = EPOLLERR; - goto unlock; - } - -unlock: - spin_unlock_irqrestore(&req->lock, flags); - return ret; -} - -static long media_request_ioctl_queue(struct media_request *req) -{ - struct media_device *mdev = req->mdev; - enum media_request_state state; - unsigned long flags; - int ret; - - dev_dbg(mdev->dev, "request: queue %s\n", req->debug_str); - - /* - * Ensure the request that is validated will be the one that gets queued - * next by serialising the queueing process. This mutex is also used - * to serialize with canceling a vb2 queue and with setting values such - * as controls in a request. - */ - mutex_lock(&mdev->req_queue_mutex); - - media_request_get(req); - - spin_lock_irqsave(&req->lock, flags); - if (req->state == MEDIA_REQUEST_STATE_IDLE) - req->state = MEDIA_REQUEST_STATE_VALIDATING; - state = req->state; - spin_unlock_irqrestore(&req->lock, flags); - if (state != MEDIA_REQUEST_STATE_VALIDATING) { - dev_dbg(mdev->dev, - "request: unable to queue %s, request in state %s\n", - req->debug_str, media_request_state_str(state)); - media_request_put(req); - mutex_unlock(&mdev->req_queue_mutex); - return -EBUSY; - } - - ret = mdev->ops->req_validate(req); - - /* - * If the req_validate was successful, then we mark the state as QUEUED - * and call req_queue. The reason we set the state first is that this - * allows req_queue to unbind or complete the queued objects in case - * they are immediately 'consumed'. State changes from QUEUED to another - * state can only happen if either the driver changes the state or if - * the user cancels the vb2 queue. The driver can only change the state - * after each object is queued through the req_queue op (and note that - * that op cannot fail), so setting the state to QUEUED up front is - * safe. - * - * The other reason for changing the state is if the vb2 queue is - * canceled, and that uses the req_queue_mutex which is still locked - * while req_queue is called, so that's safe as well. - */ - spin_lock_irqsave(&req->lock, flags); - req->state = ret ? MEDIA_REQUEST_STATE_IDLE - : MEDIA_REQUEST_STATE_QUEUED; - spin_unlock_irqrestore(&req->lock, flags); - - if (!ret) - mdev->ops->req_queue(req); - - mutex_unlock(&mdev->req_queue_mutex); - - if (ret) { - dev_dbg(mdev->dev, "request: can't queue %s (%d)\n", - req->debug_str, ret); - media_request_put(req); - } - - return ret; -} - -static long media_request_ioctl_reinit(struct media_request *req) -{ - struct media_device *mdev = req->mdev; - unsigned long flags; - - spin_lock_irqsave(&req->lock, flags); - if (req->state != MEDIA_REQUEST_STATE_IDLE && - req->state != MEDIA_REQUEST_STATE_COMPLETE) { - dev_dbg(mdev->dev, - "request: %s not in idle or complete state, cannot reinit\n", - req->debug_str); - spin_unlock_irqrestore(&req->lock, flags); - return -EBUSY; - } - if (req->access_count) { - dev_dbg(mdev->dev, - "request: %s is being accessed, cannot reinit\n", - req->debug_str); - spin_unlock_irqrestore(&req->lock, flags); - return -EBUSY; - } - req->state = MEDIA_REQUEST_STATE_CLEANING; - spin_unlock_irqrestore(&req->lock, flags); - - media_request_clean(req); - - spin_lock_irqsave(&req->lock, flags); - req->state = MEDIA_REQUEST_STATE_IDLE; - spin_unlock_irqrestore(&req->lock, flags); - - return 0; -} - -static long media_request_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct media_request *req = filp->private_data; - - switch (cmd) { - case MEDIA_REQUEST_IOC_QUEUE: - return media_request_ioctl_queue(req); - case MEDIA_REQUEST_IOC_REINIT: - return media_request_ioctl_reinit(req); - default: - return -ENOIOCTLCMD; - } -} - -static const struct file_operations request_fops = { - .owner = THIS_MODULE, - .poll = media_request_poll, - .unlocked_ioctl = media_request_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = media_request_ioctl, -#endif /* CONFIG_COMPAT */ - .release = media_request_close, -}; - -struct media_request * -media_request_get_by_fd(struct media_device *mdev, int request_fd) -{ - struct fd f; - struct media_request *req; - - if (!mdev || !mdev->ops || - !mdev->ops->req_validate || !mdev->ops->req_queue) - return ERR_PTR(-EBADR); - - f = fdget(request_fd); - if (!f.file) - goto err_no_req_fd; - - if (f.file->f_op != &request_fops) - goto err_fput; - req = f.file->private_data; - if (req->mdev != mdev) - goto err_fput; - - /* - * Note: as long as someone has an open filehandle of the request, - * the request can never be released. The fdget() above ensures that - * even if userspace closes the request filehandle, the release() - * fop won't be called, so the media_request_get() always succeeds - * and there is no race condition where the request was released - * before media_request_get() is called. - */ - media_request_get(req); - fdput(f); - - return req; - -err_fput: - fdput(f); - -err_no_req_fd: - dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd); - return ERR_PTR(-EINVAL); -} -EXPORT_SYMBOL_GPL(media_request_get_by_fd); - -int media_request_alloc(struct media_device *mdev, int *alloc_fd) -{ - struct media_request *req; - struct file *filp; - int fd; - int ret; - - /* Either both are NULL or both are non-NULL */ - if (WARN_ON(!mdev->ops->req_alloc ^ !mdev->ops->req_free)) - return -ENOMEM; - - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) - return fd; - - filp = anon_inode_getfile("request", &request_fops, NULL, O_CLOEXEC); - if (IS_ERR(filp)) { - ret = PTR_ERR(filp); - goto err_put_fd; - } - - if (mdev->ops->req_alloc) - req = mdev->ops->req_alloc(mdev); - else - req = kzalloc(sizeof(*req), GFP_KERNEL); - if (!req) { - ret = -ENOMEM; - goto err_fput; - } - - filp->private_data = req; - req->mdev = mdev; - req->state = MEDIA_REQUEST_STATE_IDLE; - req->num_incomplete_objects = 0; - kref_init(&req->kref); - INIT_LIST_HEAD(&req->objects); - spin_lock_init(&req->lock); - init_waitqueue_head(&req->poll_wait); - req->updating_count = 0; - req->access_count = 0; - - *alloc_fd = fd; - - snprintf(req->debug_str, sizeof(req->debug_str), "%u:%d", - atomic_inc_return(&mdev->request_id), fd); - dev_dbg(mdev->dev, "request: allocated %s\n", req->debug_str); - - fd_install(fd, filp); - - return 0; - -err_fput: - fput(filp); - -err_put_fd: - put_unused_fd(fd); - - return ret; -} - -static void media_request_object_release(struct kref *kref) -{ - struct media_request_object *obj = - container_of(kref, struct media_request_object, kref); - struct media_request *req = obj->req; - - if (WARN_ON(req)) - media_request_object_unbind(obj); - obj->ops->release(obj); -} - -struct media_request_object * -media_request_object_find(struct media_request *req, - const struct media_request_object_ops *ops, - void *priv) -{ - struct media_request_object *obj; - struct media_request_object *found = NULL; - unsigned long flags; - - if (WARN_ON(!ops || !priv)) - return NULL; - - spin_lock_irqsave(&req->lock, flags); - list_for_each_entry(obj, &req->objects, list) { - if (obj->ops == ops && obj->priv == priv) { - media_request_object_get(obj); - found = obj; - break; - } - } - spin_unlock_irqrestore(&req->lock, flags); - return found; -} -EXPORT_SYMBOL_GPL(media_request_object_find); - -void media_request_object_put(struct media_request_object *obj) -{ - kref_put(&obj->kref, media_request_object_release); -} -EXPORT_SYMBOL_GPL(media_request_object_put); - -void media_request_object_init(struct media_request_object *obj) -{ - obj->ops = NULL; - obj->req = NULL; - obj->priv = NULL; - obj->completed = false; - INIT_LIST_HEAD(&obj->list); - kref_init(&obj->kref); -} -EXPORT_SYMBOL_GPL(media_request_object_init); - -int media_request_object_bind(struct media_request *req, - const struct media_request_object_ops *ops, - void *priv, bool is_buffer, - struct media_request_object *obj) -{ - unsigned long flags; - int ret = -EBUSY; - - if (WARN_ON(!ops->release)) - return -EBADR; - - spin_lock_irqsave(&req->lock, flags); - - if (WARN_ON(req->state != MEDIA_REQUEST_STATE_UPDATING)) - goto unlock; - - obj->req = req; - obj->ops = ops; - obj->priv = priv; - - if (is_buffer) - list_add_tail(&obj->list, &req->objects); - else - list_add(&obj->list, &req->objects); - req->num_incomplete_objects++; - ret = 0; - -unlock: - spin_unlock_irqrestore(&req->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(media_request_object_bind); - -void media_request_object_unbind(struct media_request_object *obj) -{ - struct media_request *req = obj->req; - unsigned long flags; - bool completed = false; - - if (WARN_ON(!req)) - return; - - spin_lock_irqsave(&req->lock, flags); - list_del(&obj->list); - obj->req = NULL; - - if (req->state == MEDIA_REQUEST_STATE_COMPLETE) - goto unlock; - - if (WARN_ON(req->state == MEDIA_REQUEST_STATE_VALIDATING)) - goto unlock; - - if (req->state == MEDIA_REQUEST_STATE_CLEANING) { - if (!obj->completed) - req->num_incomplete_objects--; - goto unlock; - } - - if (WARN_ON(!req->num_incomplete_objects)) - goto unlock; - - req->num_incomplete_objects--; - if (req->state == MEDIA_REQUEST_STATE_QUEUED && - !req->num_incomplete_objects) { - req->state = MEDIA_REQUEST_STATE_COMPLETE; - completed = true; - wake_up_interruptible_all(&req->poll_wait); - } - -unlock: - spin_unlock_irqrestore(&req->lock, flags); - if (obj->ops->unbind) - obj->ops->unbind(obj); - if (completed) - media_request_put(req); -} -EXPORT_SYMBOL_GPL(media_request_object_unbind); - -void media_request_object_complete(struct media_request_object *obj) -{ - struct media_request *req = obj->req; - unsigned long flags; - bool completed = false; - - spin_lock_irqsave(&req->lock, flags); - if (obj->completed) - goto unlock; - obj->completed = true; - if (WARN_ON(!req->num_incomplete_objects) || - WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) - goto unlock; - - if (!--req->num_incomplete_objects) { - req->state = MEDIA_REQUEST_STATE_COMPLETE; - wake_up_interruptible_all(&req->poll_wait); - completed = true; - } -unlock: - spin_unlock_irqrestore(&req->lock, flags); - if (completed) - media_request_put(req); -} -EXPORT_SYMBOL_GPL(media_request_object_complete); -- cgit v1.2.3-59-g8ed1b From 1753c7c4367aa1201e1e5d0a601897ab33444af1 Mon Sep 17 00:00:00 2001 From: Andrey Konovalov Date: Thu, 2 May 2019 12:09:26 -0400 Subject: media: pvrusb2: use a different format for warnings When the pvrusb2 driver detects that there's something wrong with the device, it prints a warning message. Right now those message are printed in two different formats: 1. ***WARNING*** message here 2. WARNING: message here There's an issue with the second format. Syzkaller recognizes it as a message produced by a WARN_ON(), which is used to indicate a bug in the kernel. However pvrusb2 prints those warnings to indicate an issue with the device, not the bug in the kernel. This patch changes the pvrusb2 driver to consistently use the first warning message format. This will unblock syzkaller testing of this driver. Reported-by: syzbot+af8f8d2ac0d39b0ed3a0@syzkaller.appspotmail.com Reported-by: syzbot+170a86bf206dd2c6217e@syzkaller.appspotmail.com Signed-off-by: Andrey Konovalov Reviewed-by: Greg Kroah-Hartman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 4 ++-- drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | 6 +++--- drivers/media/usb/pvrusb2/pvrusb2-std.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 816c85786c2a..191439109788 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -1680,7 +1680,7 @@ static int pvr2_decoder_enable(struct pvr2_hdw *hdw,int enablefl) } if (!hdw->flag_decoder_missed) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: No decoder present"); + "***WARNING*** No decoder present"); hdw->flag_decoder_missed = !0; trace_stbit("flag_decoder_missed", hdw->flag_decoder_missed); @@ -2366,7 +2366,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (hdw_desc->flag_is_experimental) { pvr2_trace(PVR2_TRACE_INFO, "**********"); pvr2_trace(PVR2_TRACE_INFO, - "WARNING: Support for this device (%s) is experimental.", + "***WARNING*** Support for this device (%s) is experimental.", hdw_desc->description); pvr2_trace(PVR2_TRACE_INFO, "Important functionality might not be entirely working."); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 8f023085c2d9..43e54bdbd4aa 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -343,11 +343,11 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw, if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Detected a wedged cx25840 chip; the device will not work."); + "***WARNING*** Detected a wedged cx25840 chip; the device will not work."); pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Try power cycling the pvrusb2 device."); + "***WARNING*** Try power cycling the pvrusb2 device."); pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Disabling further access to the device to prevent other foul-ups."); + "***WARNING*** Disabling further access to the device to prevent other foul-ups."); // This blocks all further communication with the part. hdw->i2c_func[0x44] = NULL; pvr2_hdw_render_useless(hdw); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index 6b651f8b54df..37dc299a1ca2 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -353,7 +353,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk); pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "WARNING: Failed to classify the following standard(s): %.*s", + "***WARNING*** Failed to classify the following standard(s): %.*s", bcnt,buf); } -- cgit v1.2.3-59-g8ed1b From ddfef32a33869c34931d1bf9d7758a979ed6289e Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 2 May 2019 18:00:42 -0400 Subject: media: coda: Print a nicer device registered message This is just a cosmetic change to print a more descriptive message, to distinguish decoder from encoder: So, instead of printing coda 2040000.vpu: codec registered as /dev/video[4-5] With this change, the driver now prints coda 2040000.vpu: encoder registered as /dev/video4 coda 2040000.vpu: decoder registered as /dev/video5 Signed-off-by: Ezequiel Garcia Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 614943e8a7a2..3f028d1eec17 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2507,9 +2507,12 @@ err_clk_per: static int coda_register_device(struct coda_dev *dev, int i) { struct video_device *vfd = &dev->vfd[i]; + enum coda_inst_type type; + int ret; if (i >= dev->devtype->num_vdevs) return -EINVAL; + type = dev->devtype->vdevs[i]->type; strscpy(vfd->name, dev->devtype->vdevs[i]->name, sizeof(vfd->name)); vfd->fops = &coda_fops; @@ -2525,7 +2528,12 @@ static int coda_register_device(struct coda_dev *dev, int i) v4l2_disable_ioctl(vfd, VIDIOC_G_CROP); v4l2_disable_ioctl(vfd, VIDIOC_S_CROP); - return video_register_device(vfd, VFL_TYPE_GRABBER, 0); + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (!ret) + v4l2_info(&dev->v4l2_dev, "%s registered as %s\n", + type == CODA_INST_ENCODER ? "encoder" : "decoder", + video_device_node_name(vfd)); + return ret; } static void coda_copy_firmware(struct coda_dev *dev, const u8 * const buf, @@ -2639,9 +2647,6 @@ static void coda_fw_callback(const struct firmware *fw, void *context) } } - v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n", - dev->vfd[0].num, dev->vfd[i - 1].num); - pm_runtime_put_sync(&pdev->dev); return; -- cgit v1.2.3-59-g8ed1b From 766b9b168f6c75c350dd87c3e0bc6a9b322f0013 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 2 May 2019 18:00:43 -0400 Subject: media: coda: Remove unbalanced and unneeded mutex unlock The mutex unlock in the threaded interrupt handler is not paired with any mutex lock. Remove it. This bug has been here for a really long time, so it applies to any stable repo. Reviewed-by: Philipp Zabel Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index a25f3742ecde..19055c6488cc 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2348,7 +2348,6 @@ irqreturn_t coda_irq_handler(int irq, void *data) if (ctx == NULL) { v4l2_err(&dev->v4l2_dev, "Instance released before the end of transaction\n"); - mutex_unlock(&dev->coda_mutex); return IRQ_HANDLED; } -- cgit v1.2.3-59-g8ed1b From 1405bc55e617e3e03339dc2d23423b84d9bd039d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 2 May 2019 18:00:44 -0400 Subject: media: coda: Replace the threaded interrupt with a hard interrupt The current interrupt handler is doing very little, and not doing any non-atomic operations. Pretty much all it does is accessing a couple registers, taking a couple spinlocks and then signalling a completion. There is no reason this should be a threaded interrupt handler, so move the handler to regular hard interrupt context. Reviewed-by: Philipp Zabel Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3f028d1eec17..eb5f76d336fd 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2816,8 +2816,8 @@ static int coda_probe(struct platform_device *pdev) return irq; } - ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler, - IRQF_ONESHOT, dev_name(&pdev->dev), dev); + ret = devm_request_irq(&pdev->dev, irq, coda_irq_handler, 0, + dev_name(&pdev->dev), dev); if (ret < 0) { dev_err(&pdev->dev, "failed to request irq: %d\n", ret); return ret; -- cgit v1.2.3-59-g8ed1b From 2b4116290c20707bd92b7afe9f03b32cb9f76167 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 2 May 2019 18:00:45 -0400 Subject: media: coda: Clear the interrupt reason This commit clears the interrupt reason (INT_REASON) register on the interrupt handler. Without this clearing, the CODA hardware has been observed to get completely stalled on CODA980 variants, requiring a pretty deep hardware reset. The datasheet specifies that the INT_REASON register is set by the CODA hardware, and should be cleared by the host. While the CODA versions that are currently supported by this driver don't seem to need this change, it's a really small change, so it seems a wise thing to do to avoid hitting some rare race-condition in the hardware. Reviewed-by: Philipp Zabel Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 19055c6488cc..a5b2891392b8 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2341,6 +2341,7 @@ irqreturn_t coda_irq_handler(int irq, void *data) /* read status register to attend the IRQ */ coda_read(dev, CODA_REG_BIT_INT_STATUS); + coda_write(dev, 0, CODA_REG_BIT_INT_REASON); coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET, CODA_REG_BIT_INT_CLEAR); -- cgit v1.2.3-59-g8ed1b From bfe819509f4eb58288796e1d3aefd7d18cc6d9af Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Fri, 3 May 2019 07:42:21 -0400 Subject: media: v4l2: Initialize mpeg slice controls Make sure the default value at least passes the std_validate() tests. Signed-off-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 420e3fc237cd..f53d4da3d1c9 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1466,7 +1466,14 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, union v4l2_ctrl_ptr ptr) { - switch (ctrl->type) { + struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + + /* + * The cast is needed to get rid of a gcc warning complaining that + * V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS is not part of the + * v4l2_ctrl_type enum. + */ + switch ((u32)ctrl->type) { case V4L2_CTRL_TYPE_STRING: idx *= ctrl->elem_size; memset(ptr.p_char + idx, ' ', ctrl->minimum); @@ -1491,6 +1498,17 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_U32: ptr.p_u32[idx] = ctrl->default_value; break; + case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: + p_mpeg2_slice_params = ptr.p; + /* 4:2:0 */ + p_mpeg2_slice_params->sequence.chroma_format = 1; + /* 8 bits */ + p_mpeg2_slice_params->picture.intra_dc_precision = 0; + /* interlaced top field */ + p_mpeg2_slice_params->picture.picture_structure = 1; + p_mpeg2_slice_params->picture.picture_coding_type = + V4L2_MPEG2_PICTURE_CODING_TYPE_I; + break; default: idx *= ctrl->elem_size; memset(ptr.p + idx, 0, ctrl->elem_size); -- cgit v1.2.3-59-g8ed1b From 0783525fff6e524532fd613f788e6ce14edba89d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 3 May 2019 10:22:49 -0400 Subject: media: vicodec: correctly support unbinding of the driver Unbinding the driver while streaming caused the driver to hang. The cause of this was failing to use the v4l2_device release function and the use of devm_kmalloc for the state structure. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index bd01a9206aa6..89961257f03f 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -2013,18 +2013,31 @@ static int register_instance(struct vicodec_dev *dev, return 0; } +static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev); + + v4l2_device_unregister(&dev->v4l2_dev); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); + v4l2_m2m_release(dev->stateless_dec.m2m_dev); + kfree(dev); +} + static int vicodec_probe(struct platform_device *pdev) { struct vicodec_dev *dev; int ret; - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - return ret; + goto free_dev; + + dev->v4l2_dev.release = vicodec_v4l2_dev_release; #ifdef CONFIG_MEDIA_CONTROLLER dev->mdev.dev = &pdev->dev; @@ -2102,6 +2115,8 @@ unreg_sf_enc: v4l2_m2m_release(dev->stateful_enc.m2m_dev); unreg_dev: v4l2_device_unregister(&dev->v4l2_dev); +free_dev: + kfree(dev); return ret; } @@ -2120,12 +2135,10 @@ static int vicodec_remove(struct platform_device *pdev) media_device_cleanup(&dev->mdev); #endif - v4l2_m2m_release(dev->stateful_enc.m2m_dev); - v4l2_m2m_release(dev->stateful_dec.m2m_dev); video_unregister_device(&dev->stateful_enc.vfd); video_unregister_device(&dev->stateful_dec.vfd); video_unregister_device(&dev->stateless_dec.vfd); - v4l2_device_unregister(&dev->v4l2_dev); + v4l2_device_put(&dev->v4l2_dev); return 0; } -- cgit v1.2.3-59-g8ed1b From eff73de2b1600ad8230692f00bc0ab49b166512a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 9 May 2019 04:57:09 -0400 Subject: media: cpia2_usb: first wake up, then free in disconnect Kasan reported a use after free in cpia2_usb_disconnect() It first freed everything and then woke up those waiting. The reverse order is correct. Fixes: 6c493f8b28c67 ("[media] cpia2: major overhaul to get it in a working state again") Signed-off-by: Oliver Neukum Reported-by: syzbot+0c90fc937c84f97d0aa6@syzkaller.appspotmail.com Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cpia2/cpia2_usb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index e5d8dee38fe4..44bd7e5ad3eb 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -902,7 +902,6 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) cpia2_unregister_camera(cam); v4l2_device_disconnect(&cam->v4l2_dev); mutex_unlock(&cam->v4l2_lock); - v4l2_device_put(&cam->v4l2_dev); if(cam->buffers) { DBG("Wakeup waiting processes\n"); @@ -911,6 +910,8 @@ static void cpia2_usb_disconnect(struct usb_interface *intf) wake_up_interruptible(&cam->wq_stream); } + v4l2_device_put(&cam->v4l2_dev); + LOG("CPiA2 camera disconnected.\n"); } -- cgit v1.2.3-59-g8ed1b From debb0dd644ce4f304240b37faa360c7cc0b89d7c Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Thu, 9 May 2019 04:59:30 -0400 Subject: media: pwc: convert to BIT macro This converts the driver to using the BIT macro to increase readability Signed-off-by: Oliver Neukum Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pwc/pwc.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/pwc/pwc.h b/drivers/media/usb/pwc/pwc.h index 67010010d2a2..28b2c0cb79ac 100644 --- a/drivers/media/usb/pwc/pwc.h +++ b/drivers/media/usb/pwc/pwc.h @@ -55,15 +55,15 @@ /* Trace certain actions in the driver */ -#define PWC_DEBUG_LEVEL_MODULE (1<<0) -#define PWC_DEBUG_LEVEL_PROBE (1<<1) -#define PWC_DEBUG_LEVEL_OPEN (1<<2) -#define PWC_DEBUG_LEVEL_READ (1<<3) -#define PWC_DEBUG_LEVEL_MEMORY (1<<4) -#define PWC_DEBUG_LEVEL_FLOW (1<<5) -#define PWC_DEBUG_LEVEL_SIZE (1<<6) -#define PWC_DEBUG_LEVEL_IOCTL (1<<7) -#define PWC_DEBUG_LEVEL_TRACE (1<<8) +#define PWC_DEBUG_LEVEL_MODULE BIT(0) +#define PWC_DEBUG_LEVEL_PROBE BIT(1) +#define PWC_DEBUG_LEVEL_OPEN BIT(2) +#define PWC_DEBUG_LEVEL_READ BIT(3) +#define PWC_DEBUG_LEVEL_MEMORY BIT(4) +#define PWC_DEBUG_LEVEL_FLOW BIT(5) +#define PWC_DEBUG_LEVEL_SIZE BIT(6) +#define PWC_DEBUG_LEVEL_IOCTL BIT(7) +#define PWC_DEBUG_LEVEL_TRACE BIT(8) #define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args) #define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args) -- cgit v1.2.3-59-g8ed1b From 20059cbbf981ca954be56f7963ae494d18e2dda1 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Mon, 13 May 2019 03:18:29 -0400 Subject: media: vim2m: fix two double-free issues vim2m_device_release() will be called by video_unregister_device() to release various objects. There are two double-free issue, 1. dev->m2m_dev will be freed twice in error_m2m path/vim2m_device_release 2. the error_v4l2 and error_free path in vim2m_probe() will release same objects, since vim2m_device_release has done. Fixes: ea6c7e34f3b2 ("media: vim2m: replace devm_kzalloc by kzalloc") Cc: Laurent Pinchart Reported-by: Hulk Robot Signed-off-by: Kefeng Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vim2m.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 243c82b5d537..acd3bd48c7e2 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -1359,7 +1359,7 @@ static int vim2m_probe(struct platform_device *pdev) MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto error_m2m; + goto error_dev; } ret = media_device_register(&dev->mdev); @@ -1373,11 +1373,11 @@ static int vim2m_probe(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER error_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); -error_m2m: - v4l2_m2m_release(dev->m2m_dev); #endif error_dev: video_unregister_device(&dev->vfd); + /* vim2m_device_release called by video_unregister_device to release various objects */ + return ret; error_v4l2: v4l2_device_unregister(&dev->v4l2_dev); error_free: -- cgit v1.2.3-59-g8ed1b From 0c310868826eb10b724a21dcd05e19768b6fc3a8 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 15 May 2019 20:35:38 -0400 Subject: media: rcar-csi2: Fix coccinelle warning for PTR_ERR_OR_ZERO() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the PTR_ERR_OR_ZERO() macro instead of construct: if (IS_ERR(foo)) return PTR_ERR(foo); return 0; Fixes: 3ae854cafd76 ("rcar-csi2: Use standby mode instead of resetting") Reported-by: kbuild test robot Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-csi2.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index 8f097e514900..c14af1b929df 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -1019,10 +1019,8 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv, return ret; priv->rstc = devm_reset_control_get(&pdev->dev, NULL); - if (IS_ERR(priv->rstc)) - return PTR_ERR(priv->rstc); - return 0; + return PTR_ERR_OR_ZERO(priv->rstc); } static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { -- cgit v1.2.3-59-g8ed1b From 3e0f724346e96daae7792262c6767449795ac3b5 Mon Sep 17 00:00:00 2001 From: sumitg Date: Fri, 17 May 2019 09:53:42 -0400 Subject: media: v4l2-core: fix use-after-free error Fixing use-after-free within __v4l2_ctrl_handler_setup(). Memory is being freed with kfree(new_ref) for duplicate control reference entry but ctrl->cluster pointer is still referring to freed duplicate entry resulting in error on access. Change done to update cluster pointer only when new control reference is added. ================================================================== BUG: KASAN: use-after-free in __v4l2_ctrl_handler_setup+0x388/0x428 Read of size 8 at addr ffffffc324e78618 by task systemd-udevd/312 Allocated by task 312: Freed by task 312: The buggy address belongs to the object at ffffffc324e78600 which belongs to the cache kmalloc-64 of size 64 The buggy address is located 24 bytes inside of 64-byte region [ffffffc324e78600, ffffffc324e78640) The buggy address belongs to the page: page:ffffffbf0c939e00 count:1 mapcount:0 mapping: (null) index:0xffffffc324e78f80 flags: 0x4000000000000100(slab) raw: 4000000000000100 0000000000000000 ffffffc324e78f80 000000018020001a raw: 0000000000000000 0000000100000001 ffffffc37040fb80 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffffffc324e78500: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ffffffc324e78580: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc >ffffffc324e78600: fb fb fb fb fb fb fb fb fc fc fc fc fc fc fc fc ^ ffffffc324e78680: 00 00 00 00 00 00 00 00 fc fc fc fc fc fc fc fc ffffffc324e78700: 00 00 00 00 00 fc fc fc fc fc fc fc fc fc fc fc ================================================================== Suggested-by: Hans Verkuil Signed-off-by: Sumit Gupta Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f53d4da3d1c9..2ffffd923265 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -2180,15 +2180,6 @@ static int handler_new_ref(struct v4l2_ctrl_handler *hdl, if (size_extra_req) new_ref->p_req.p = &new_ref[1]; - if (ctrl->handler == hdl) { - /* By default each control starts in a cluster of its own. - new_ref->ctrl is basically a cluster array with one - element, so that's perfect to use as the cluster pointer. - But only do this for the handler that owns the control. */ - ctrl->cluster = &new_ref->ctrl; - ctrl->ncontrols = 1; - } - INIT_LIST_HEAD(&new_ref->node); mutex_lock(hdl->lock); @@ -2221,6 +2212,15 @@ insert_in_hash: hdl->buckets[bucket] = new_ref; if (ctrl_ref) *ctrl_ref = new_ref; + if (ctrl->handler == hdl) { + /* By default each control starts in a cluster of its own. + * new_ref->ctrl is basically a cluster array with one + * element, so that's perfect to use as the cluster pointer. + * But only do this for the handler that owns the control. + */ + ctrl->cluster = &new_ref->ctrl; + ctrl->ncontrols = 1; + } unlock: mutex_unlock(hdl->lock); -- cgit v1.2.3-59-g8ed1b From ee1c71a8e1456ab53fe667281d855849edf26a4d Mon Sep 17 00:00:00 2001 From: Helen Koike Date: Fri, 17 May 2019 13:20:11 -0400 Subject: media: vimc: fix component match compare If the system has other devices being registered in the component framework, the compare function will be called with a device that doesn't belong to vimc. This device is not necessarily a platform_device, nor have a platform_data (which causes a NULL pointer dereference error) and if it does have a pdata, it is not necessarily type of struct vimc_platform_data. So casting to any of these types is wrong. Instead of expecting a given pdev with a given pdata, just expect for the device it self. vimc-core is the one who creates them, we know in advance exactly which object to expect in the match. Fixes: 4a29b7090749 ("[media] vimc: Subdevices as modules") Signed-off-by: Helen Koike Reviewed-by: Boris Brezillon Tested-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 3aa62d7e3d0e..23992affd01f 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -244,10 +244,7 @@ static void vimc_comp_unbind(struct device *master) static int vimc_comp_compare(struct device *comp, void *data) { - const struct platform_device *pdev = to_platform_device(comp); - const char *name = data; - - return !strcmp(pdev->dev.platform_data, name); + return comp == data; } static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) @@ -277,7 +274,7 @@ static struct component_match *vimc_add_subdevs(struct vimc_device *vimc) } component_match_add(&vimc->pdev.dev, &match, vimc_comp_compare, - (void *)vimc->pipe_cfg->ents[i].name); + &vimc->subdevs[i]->dev); } return match; -- cgit v1.2.3-59-g8ed1b From fe97d64d72586827f422a5aa49a4b7fb5cbb6932 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Fri, 17 May 2019 20:46:54 -0400 Subject: media: vimc: Remove unneeded return statement in vimc_sen_s_stream() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The other subdevice implementations in vimc (debayer and scaler) which share their code structure with the sensor do not have an explicit return statement at the end of the s_stream(0) code path. Align the sensor subdevice by dropping the return statement. Signed-off-by: Niklas Söderlund Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-sensor.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 081e54204c9f..baca9ca67ce0 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -221,7 +221,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) vfree(vsen->frame); vsen->frame = NULL; - return 0; } return 0; -- cgit v1.2.3-59-g8ed1b From 5d2e73a5f80a5b5aff3caf1ec6d39b5b3f54b26e Mon Sep 17 00:00:00 2001 From: Vandana BN Date: Wed, 22 May 2019 04:34:15 -0400 Subject: media: usb:zr364xx:Fix KASAN:null-ptr-deref Read in zr364xx_vidioc_querycap SyzKaller hit the null pointer deref while reading from uninitialized udev->product in zr364xx_vidioc_querycap(). ================================================================== BUG: KASAN: null-ptr-deref in read_word_at_a_time+0xe/0x20 include/linux/compiler.h:274 Read of size 1 at addr 0000000000000000 by task v4l_id/5287 CPU: 1 PID: 5287 Comm: v4l_id Not tainted 5.1.0-rc3-319004-g43151d6 #6 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0xe8/0x16e lib/dump_stack.c:113 kasan_report.cold+0x5/0x3c mm/kasan/report.c:321 read_word_at_a_time+0xe/0x20 include/linux/compiler.h:274 strscpy+0x8a/0x280 lib/string.c:207 zr364xx_vidioc_querycap+0xb5/0x210 drivers/media/usb/zr364xx/zr364xx.c:706 v4l_querycap+0x12b/0x340 drivers/media/v4l2-core/v4l2-ioctl.c:1062 __video_do_ioctl+0x5bb/0xb40 drivers/media/v4l2-core/v4l2-ioctl.c:2874 video_usercopy+0x44e/0xf00 drivers/media/v4l2-core/v4l2-ioctl.c:3056 v4l2_ioctl+0x14e/0x1a0 drivers/media/v4l2-core/v4l2-dev.c:364 vfs_ioctl fs/ioctl.c:46 [inline] file_ioctl fs/ioctl.c:509 [inline] do_vfs_ioctl+0xced/0x12f0 fs/ioctl.c:696 ksys_ioctl+0xa0/0xc0 fs/ioctl.c:713 __do_sys_ioctl fs/ioctl.c:720 [inline] __se_sys_ioctl fs/ioctl.c:718 [inline] __x64_sys_ioctl+0x74/0xb0 fs/ioctl.c:718 do_syscall_64+0xcf/0x4f0 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f3b56d8b347 Code: 90 90 90 48 8b 05 f1 fa 2a 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 90 90 90 90 90 90 90 90 90 90 b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d c1 fa 2a 00 31 d2 48 29 c2 64 RSP: 002b:00007ffe005d5d68 EFLAGS: 00000202 ORIG_RAX: 0000000000000010 RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007f3b56d8b347 RDX: 00007ffe005d5d70 RSI: 0000000080685600 RDI: 0000000000000003 RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000202 R12: 0000000000400884 R13: 00007ffe005d5ec0 R14: 0000000000000000 R15: 0000000000000000 ================================================================== For this device udev->product is not initialized and accessing it causes a NULL pointer deref. The fix is to check for NULL before strscpy() and copy empty string, if product is NULL Reported-by: syzbot+66010012fd4c531a1a96@syzkaller.appspotmail.com Signed-off-by: Vandana BN Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/zr364xx/zr364xx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 96fee8d5b865..cd2bc9ed0cd9 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -703,7 +703,8 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, struct zr364xx_camera *cam = video_drvdata(file); strscpy(cap->driver, DRIVER_DESC, sizeof(cap->driver)); - strscpy(cap->card, cam->udev->product, sizeof(cap->card)); + if (cam->udev->product) + strscpy(cap->card, cam->udev->product, sizeof(cap->card)); strscpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | -- cgit v1.2.3-59-g8ed1b From ccf7a31f1ed96ee211f660c488d49a85f586417c Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:52 -0400 Subject: media: cx25840: don't open-code cx25840_reset() inside cx25840_load_fw() cx25840_load_fw() does the same thing as cx25840_reset(), only keeps "is_initialized" flag so any further invocation of this function besides the first one is a NOP. Let's just call cx25840_reset() directly from cx25840_load_fw() instead of open coding it there. While we are at it, let's also improve comments about cx25840_load_fw() so they are current and in the proper style (one of them even referred to a non-existing cx25840 init operation). Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 70 ++++++++++++++++---------------- include/media/drv-intf/cx25840.h | 28 ++++++++----- 2 files changed, 51 insertions(+), 47 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 8b0b8b5aa531..0bf30222cf93 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1649,32 +1649,46 @@ static void log_audio_status(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -/* This load_fw operation must be called to load the driver's firmware. - Without this the audio standard detection will fail and you will - only get mono. - - Since loading the firmware is often problematic when the driver is - compiled into the kernel I recommend postponing calling this function - until the first open of the video device. Another reason for - postponing it is that loading this firmware takes a long time (seconds) - due to the slow i2c bus speed. So it will speed up the boot process if - you can avoid loading the fw as long as the video device isn't used. */ -static int cx25840_load_fw(struct v4l2_subdev *sd) +static int cx25840_reset(struct v4l2_subdev *sd, u32 val) { struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); + if (is_cx2583x(state)) + cx25836_initialize(client); + else if (is_cx2388x(state)) + cx23885_initialize(client); + else if (is_cx231xx(state)) + cx231xx_initialize(client); + else + cx25840_initialize(client); + + state->is_initialized = 1; + + return 0; +} + +/* + * This load_fw operation must be called to load the driver's firmware. + * This will load the firmware on the first invocation (further ones are NOP). + * Without this the audio standard detection will fail and you will + * only get mono. + * Alternatively, you can call the reset operation instead of this one. + * + * Since loading the firmware is often problematic when the driver is + * compiled into the kernel I recommend postponing calling this function + * until the first open of the video device. Another reason for + * postponing it is that loading this firmware takes a long time (seconds) + * due to the slow i2c bus speed. So it will speed up the boot process if + * you can avoid loading the fw as long as the video device isn't used. + */ +static int cx25840_load_fw(struct v4l2_subdev *sd) +{ + struct cx25840_state *state = to_state(sd); + if (!state->is_initialized) { /* initialize and load firmware */ - state->is_initialized = 1; - if (is_cx2583x(state)) - cx25836_initialize(client); - else if (is_cx2388x(state)) - cx23885_initialize(client); - else if (is_cx231xx(state)) - cx231xx_initialize(client); - else - cx25840_initialize(client); + cx25840_reset(sd, 0); } return 0; } @@ -1937,22 +1951,6 @@ static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) return 0; } -static int cx25840_reset(struct v4l2_subdev *sd, u32 val) -{ - struct cx25840_state *state = to_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (is_cx2583x(state)) - cx25836_initialize(client); - else if (is_cx2388x(state)) - cx23885_initialize(client); - else if (is_cx231xx(state)) - cx231xx_initialize(client); - else - cx25840_initialize(client); - return 0; -} - static int cx25840_log_status(struct v4l2_subdev *sd) { struct cx25840_state *state = to_state(sd); diff --git a/include/media/drv-intf/cx25840.h b/include/media/drv-intf/cx25840.h index 328ddb359fdf..4eae27c163ba 100644 --- a/include/media/drv-intf/cx25840.h +++ b/include/media/drv-intf/cx25840.h @@ -9,17 +9,23 @@ #ifndef _CX25840_H_ #define _CX25840_H_ -/* Note that the cx25840 driver requires that the bridge driver calls the - v4l2_subdev's init operation in order to load the driver's firmware. - Without this the audio standard detection will fail and you will - only get mono. - - Since loading the firmware is often problematic when the driver is - compiled into the kernel I recommend postponing calling this function - until the first open of the video device. Another reason for - postponing it is that loading this firmware takes a long time (seconds) - due to the slow i2c bus speed. So it will speed up the boot process if - you can avoid loading the fw as long as the video device isn't used. */ +/* + * Note that the cx25840 driver requires that the bridge driver calls the + * v4l2_subdev's load_fw operation in order to load the driver's firmware. + * This will load the firmware on the first invocation (further ones are NOP). + * Without this the audio standard detection will fail and you will + * only get mono. + * Alternatively, you can call the reset operation (this can be done + * multiple times if needed, each invocation will fully reinitialize + * the device). + * + * Since loading the firmware is often problematic when the driver is + * compiled into the kernel I recommend postponing calling this function + * until the first open of the video device. Another reason for + * postponing it is that loading this firmware takes a long time (seconds) + * due to the slow i2c bus speed. So it will speed up the boot process if + * you can avoid loading the fw as long as the video device isn't used. + */ enum cx25840_video_input { /* Composite video inputs In1-In8 */ -- cgit v1.2.3-59-g8ed1b From 60acc4ab1127a1bb3e4e33ca13b3ed82489c7ea4 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:53 -0400 Subject: media: cx25840: g_std operation really implements querystd operation cx25840 driver g_std operation queries the currently detected video signal, however this is what querystd operation should do, so let's rename the handler. None of the existing cx25840 driver users ever called the g_std operation, one of them calls querystd on each of its subdevs but then the result is only used to implement VIDIOC_QUERYSTD (as it should). Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 0bf30222cf93..2bcaf239b0d2 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1772,7 +1772,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) } /* Query the current detected video format */ -static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +static int cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -1800,8 +1800,9 @@ static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf; *std = stds[ fmt ]; - v4l_dbg(1, cx25840_debug, client, "g_std fmt = %x, v4l2_std_id = 0x%x\n", - fmt, (unsigned int)stds[ fmt ]); + v4l_dbg(1, cx25840_debug, client, + "querystd fmt = %x, v4l2_std_id = 0x%x\n", + fmt, (unsigned int)stds[fmt]); return 0; } @@ -5081,7 +5082,7 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { static const struct v4l2_subdev_video_ops cx25840_video_ops = { .s_std = cx25840_s_std, - .g_std = cx25840_g_std, + .querystd = cx25840_querystd, .s_routing = cx25840_s_video_routing, .s_stream = cx25840_s_stream, .g_input_status = cx25840_g_input_status, -- cgit v1.2.3-59-g8ed1b From 763549a3cf121d59d5e9ad078ae71d94be9be748 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:54 -0400 Subject: media: cx25840: implement g_std operation This commit implements g_std operation in cx25840 driver by returning the last set video standard. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 2bcaf239b0d2..8c1111ba051b 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1822,6 +1822,15 @@ static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status) return 0; } +static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std) +{ + struct cx25840_state *state = to_state(sd); + + *std = state->std; + + return 0; +} + static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std) { struct cx25840_state *state = to_state(sd); @@ -5081,6 +5090,7 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = { }; static const struct v4l2_subdev_video_ops cx25840_video_ops = { + .g_std = cx25840_g_std, .s_std = cx25840_s_std, .querystd = cx25840_querystd, .s_routing = cx25840_s_video_routing, -- cgit v1.2.3-59-g8ed1b From e81a9076b4d60351bd574bc1c353793301427635 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:55 -0400 Subject: media: cx25840: add pin to pad mapping and output format configuration This commit adds pin to pad mapping and output format configuration support in CX2584x-series chips to cx25840 driver. This functionality is then used to allow disabling ivtv-specific hacks and configuration values (called a "generic mode"), so cx25840 driver can be used for other devices not needing them without risking compatibility problems. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 414 ++++++++++++++++++++++++++++++- drivers/media/i2c/cx25840/cx25840-core.h | 15 ++ drivers/media/i2c/cx25840/cx25840-vbi.c | 4 + include/media/drv-intf/cx25840.h | 77 +++++- 4 files changed, 500 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 8c1111ba051b..f03bd637b795 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -21,6 +21,9 @@ * CX23888 DIF support for the HVR1850 * Copyright (C) 2011 Steven Toth * + * CX2584x pin to pad mapping and output format configuration support are + * Copyright (C) 2011 Maciej S. Szmigiero + * * 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 @@ -316,6 +319,217 @@ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, return 0; } +static u8 cx25840_function_to_pad(struct i2c_client *client, u8 function) +{ + if (function > CX25840_PAD_VRESET) { + v4l_err(client, "invalid function %u, assuming default\n", + (unsigned int)function); + return 0; + } + + return function; +} + +static void cx25840_set_invert(u8 *pinctrl3, u8 *voutctrl4, u8 function, + u8 pin, bool invert) +{ + switch (function) { + case CX25840_PAD_IRQ_N: + if (invert) + *pinctrl3 &= ~2; + else + *pinctrl3 |= 2; + break; + + case CX25840_PAD_ACTIVE: + if (invert) + *voutctrl4 |= BIT(2); + else + *voutctrl4 &= ~BIT(2); + break; + + case CX25840_PAD_VACTIVE: + if (invert) + *voutctrl4 |= BIT(5); + else + *voutctrl4 &= ~BIT(5); + break; + + case CX25840_PAD_CBFLAG: + if (invert) + *voutctrl4 |= BIT(4); + else + *voutctrl4 &= ~BIT(4); + break; + + case CX25840_PAD_VRESET: + if (invert) + *voutctrl4 |= BIT(0); + else + *voutctrl4 &= ~BIT(0); + break; + } + + if (function != CX25840_PAD_DEFAULT) + return; + + switch (pin) { + case CX25840_PIN_DVALID_PRGM0: + if (invert) + *voutctrl4 |= BIT(6); + else + *voutctrl4 &= ~BIT(6); + break; + + case CX25840_PIN_HRESET_PRGM2: + if (invert) + *voutctrl4 |= BIT(1); + else + *voutctrl4 &= ~BIT(1); + break; + } +} + +static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n, + struct v4l2_subdev_io_pin_config *p) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + unsigned int i; + u8 pinctrl[6], pinconf[10], voutctrl4; + + for (i = 0; i < 6; i++) + pinctrl[i] = cx25840_read(client, 0x114 + i); + + for (i = 0; i < 10; i++) + pinconf[i] = cx25840_read(client, 0x11c + i); + + voutctrl4 = cx25840_read(client, 0x407); + + for (i = 0; i < n; i++) { + u8 strength = p[i].strength; + + if (strength != CX25840_PIN_DRIVE_SLOW && + strength != CX25840_PIN_DRIVE_MEDIUM && + strength != CX25840_PIN_DRIVE_FAST) { + + v4l_err(client, + "invalid drive speed for pin %u (%u), assuming fast\n", + (unsigned int)p[i].pin, + (unsigned int)strength); + + strength = CX25840_PIN_DRIVE_FAST; + } + + switch (p[i].pin) { + case CX25840_PIN_DVALID_PRGM0: + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) + pinctrl[0] &= ~BIT(6); + else + pinctrl[0] |= BIT(6); + + pinconf[3] &= 0xf0; + pinconf[3] |= cx25840_function_to_pad(client, + p[i].function); + + cx25840_set_invert(&pinctrl[3], &voutctrl4, + p[i].function, + CX25840_PIN_DVALID_PRGM0, + p[i].flags & + BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)); + + pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */ + switch (strength) { + case CX25840_PIN_DRIVE_SLOW: + pinctrl[4] |= 1 << 2; + break; + + case CX25840_PIN_DRIVE_FAST: + pinctrl[4] |= 2 << 2; + break; + } + + break; + + case CX25840_PIN_HRESET_PRGM2: + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) + pinctrl[1] &= ~BIT(0); + else + pinctrl[1] |= BIT(0); + + pinconf[4] &= 0xf0; + pinconf[4] |= cx25840_function_to_pad(client, + p[i].function); + + cx25840_set_invert(&pinctrl[3], &voutctrl4, + p[i].function, + CX25840_PIN_HRESET_PRGM2, + p[i].flags & + BIT(V4L2_SUBDEV_IO_PIN_ACTIVE_LOW)); + + pinctrl[4] &= ~(3 << 2); /* CX25840_PIN_DRIVE_MEDIUM */ + switch (strength) { + case CX25840_PIN_DRIVE_SLOW: + pinctrl[4] |= 1 << 2; + break; + + case CX25840_PIN_DRIVE_FAST: + pinctrl[4] |= 2 << 2; + break; + } + + break; + + case CX25840_PIN_PLL_CLK_PRGM7: + if (p[i].flags & BIT(V4L2_SUBDEV_IO_PIN_DISABLE)) + pinctrl[2] &= ~BIT(2); + else + pinctrl[2] |= BIT(2); + + switch (p[i].function) { + case CX25840_PAD_XTI_X5_DLL: + pinconf[6] = 0; + break; + + case CX25840_PAD_AUX_PLL: + pinconf[6] = 1; + break; + + case CX25840_PAD_VID_PLL: + pinconf[6] = 5; + break; + + case CX25840_PAD_XTI: + pinconf[6] = 2; + break; + + default: + pinconf[6] = 3; + pinconf[6] |= + cx25840_function_to_pad(client, + p[i].function) + << 4; + } + + break; + + default: + v4l_err(client, "invalid or unsupported pin %u\n", + (unsigned int)p[i].pin); + break; + } + } + + cx25840_write(client, 0x407, voutctrl4); + + for (i = 0; i < 6; i++) + cx25840_write(client, 0x114 + i, pinctrl[i]); + + for (i = 0; i < 10; i++) + cx25840_write(client, 0x11c + i, pinconf[i]); + + return 0; +} + static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, struct v4l2_subdev_io_pin_config *pincfg) { @@ -323,6 +537,8 @@ static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, if (is_cx2388x(state)) return cx23885_s_io_pin_config(sd, n, pincfg); + else if (is_cx2584x(state)) + return cx25840_s_io_pin_config(sd, n, pincfg); return 0; } @@ -389,6 +605,91 @@ static void cx25840_work_handler(struct work_struct *work) wake_up(&state->fw_wait); } +#define CX25840_VCONFIG_SET_BIT(state, opt_msk, voc, idx, bit, oneval) \ + do { \ + if ((state)->vid_config & (opt_msk)) { \ + if (((state)->vid_config & (opt_msk)) == \ + (oneval)) \ + (voc)[idx] |= BIT(bit); \ + else \ + (voc)[idx] &= ~BIT(bit); \ + } \ + } while (0) + +/* apply current vconfig to hardware regs */ +static void cx25840_vconfig_apply(struct i2c_client *client) +{ + struct cx25840_state *state = to_state(i2c_get_clientdata(client)); + u8 voutctrl[3]; + unsigned int i; + + for (i = 0; i < 3; i++) + voutctrl[i] = cx25840_read(client, 0x404 + i); + + if (state->vid_config & CX25840_VCONFIG_FMT_MASK) + voutctrl[0] &= ~3; + switch (state->vid_config & CX25840_VCONFIG_FMT_MASK) { + case CX25840_VCONFIG_FMT_BT656: + voutctrl[0] |= 1; + break; + + case CX25840_VCONFIG_FMT_VIP11: + voutctrl[0] |= 2; + break; + + case CX25840_VCONFIG_FMT_VIP2: + voutctrl[0] |= 3; + break; + + case CX25840_VCONFIG_FMT_BT601: + /* zero */ + default: + break; + } + + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_RES_MASK, voutctrl, + 0, 2, CX25840_VCONFIG_RES_10BIT); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VBIRAW_MASK, voutctrl, + 0, 3, CX25840_VCONFIG_VBIRAW_ENABLED); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ANCDATA_MASK, voutctrl, + 0, 4, CX25840_VCONFIG_ANCDATA_ENABLED); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_TASKBIT_MASK, voutctrl, + 0, 5, CX25840_VCONFIG_TASKBIT_ONE); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_ACTIVE_MASK, voutctrl, + 1, 2, CX25840_VCONFIG_ACTIVE_HORIZONTAL); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VALID_MASK, voutctrl, + 1, 3, CX25840_VCONFIG_VALID_ANDACTIVE); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_HRESETW_MASK, voutctrl, + 1, 4, CX25840_VCONFIG_HRESETW_PIXCLK); + + if (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) + voutctrl[1] &= ~(3 << 6); + switch (state->vid_config & CX25840_VCONFIG_CLKGATE_MASK) { + case CX25840_VCONFIG_CLKGATE_VALID: + voutctrl[1] |= 2; + break; + + case CX25840_VCONFIG_CLKGATE_VALIDACTIVE: + voutctrl[1] |= 3; + break; + + case CX25840_VCONFIG_CLKGATE_NONE: + /* zero */ + default: + break; + } + + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_DCMODE_MASK, voutctrl, + 2, 0, CX25840_VCONFIG_DCMODE_BYTES); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_IDID0S_MASK, voutctrl, + 2, 1, CX25840_VCONFIG_IDID0S_LINECNT); + CX25840_VCONFIG_SET_BIT(state, CX25840_VCONFIG_VIPCLAMP_MASK, voutctrl, + 2, 4, CX25840_VCONFIG_VIPCLAMP_ENABLED); + + for (i = 0; i < 3; i++) + cx25840_write(client, 0x404 + i, voutctrl[i]); +} + static void cx25840_initialize(struct i2c_client *client) { DEFINE_WAIT(wait); @@ -455,6 +756,9 @@ static void cx25840_initialize(struct i2c_client *client) /* (re)set input */ set_input(client, state->vid_input, state->aud_input); + if (state->generic_mode) + cx25840_vconfig_apply(client); + /* start microcontroller */ cx25840_and_or(client, 0x803, ~0x10, 0x10); } @@ -809,13 +1113,20 @@ void cx25840_std_setup(struct i2c_client *client) else cx25840_write(client, 0x49f, 0x14); + /* generic mode uses the values that the chip autoconfig would set */ if (std & V4L2_STD_625_50) { hblank = 132; hactive = 720; burst = 93; - vblank = 36; - vactive = 580; - vblank656 = 40; + if (state->generic_mode) { + vblank = 34; + vactive = 576; + vblank656 = 38; + } else { + vblank = 36; + vactive = 580; + vblank656 = 40; + } src_decimation = 0x21f; luma_lpf = 2; @@ -824,6 +1135,10 @@ void cx25840_std_setup(struct i2c_client *client) comb = 0; sc = 0x0a425f; } else if (std == V4L2_STD_PAL_Nc) { + if (state->generic_mode) { + burst = 95; + luma_lpf = 1; + } uv_lpf = 1; comb = 0x20; sc = 556453; @@ -838,12 +1153,19 @@ void cx25840_std_setup(struct i2c_client *client) vactive = 487; luma_lpf = 1; uv_lpf = 1; + if (state->generic_mode) { + vblank = 20; + vblank656 = 24; + } src_decimation = 0x21f; if (std == V4L2_STD_PAL_60) { - vblank = 26; - vblank656 = 26; - burst = 0x5b; + if (!state->generic_mode) { + vblank = 26; + vblank656 = 26; + burst = 0x5b; + } else + burst = 0x59; luma_lpf = 2; comb = 0x20; sc = 688739; @@ -854,8 +1176,10 @@ void cx25840_std_setup(struct i2c_client *client) comb = 0x20; sc = 555452; } else { - vblank = 26; - vblank656 = 26; + if (!state->generic_mode) { + vblank = 26; + vblank656 = 26; + } burst = 0x5b; comb = 0x66; sc = 556063; @@ -1403,7 +1727,9 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; } - Vlines = fmt->height + (is_50Hz ? 4 : 7); + Vlines = fmt->height; + if (!state->generic_mode) + Vlines += is_50Hz ? 4 : 7; /* * We keep 1 margin for the Vsrc < Vlines check since the @@ -1647,8 +1973,71 @@ static void log_audio_status(struct i2c_client *client) } } +#define CX25840_VCONFIG_OPTION(state, cfg_in, opt_msk) \ + do { \ + if ((cfg_in) & (opt_msk)) { \ + (state)->vid_config &= ~(opt_msk); \ + (state)->vid_config |= (cfg_in) & (opt_msk); \ + } \ + } while (0) + +/* apply incoming options to the current vconfig */ +static void cx25840_vconfig_add(struct cx25840_state *state, u32 cfg_in) +{ + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_FMT_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_RES_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VBIRAW_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ANCDATA_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_TASKBIT_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_ACTIVE_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VALID_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_HRESETW_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_CLKGATE_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_DCMODE_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_IDID0S_MASK); + CX25840_VCONFIG_OPTION(state, cfg_in, CX25840_VCONFIG_VIPCLAMP_MASK); +} + /* ----------------------------------------------------------------------- */ +/* + * Initializes the device in the generic mode. + * For cx2584x chips also adds additional video output settings provided + * in @val parameter (CX25840_VCONFIG_*). + * + * The generic mode disables some of the ivtv-related hacks in this driver. + * For cx2584x chips it also enables setting video output configuration while + * setting it according to datasheet defaults by default. + */ +static int cx25840_init(struct v4l2_subdev *sd, u32 val) +{ + struct cx25840_state *state = to_state(sd); + + state->generic_mode = true; + + if (is_cx2584x(state)) { + /* set datasheet video output defaults */ + state->vid_config = CX25840_VCONFIG_FMT_BT656 | + CX25840_VCONFIG_RES_8BIT | + CX25840_VCONFIG_VBIRAW_DISABLED | + CX25840_VCONFIG_ANCDATA_ENABLED | + CX25840_VCONFIG_TASKBIT_ONE | + CX25840_VCONFIG_ACTIVE_HORIZONTAL | + CX25840_VCONFIG_VALID_NORMAL | + CX25840_VCONFIG_HRESETW_NORMAL | + CX25840_VCONFIG_CLKGATE_NONE | + CX25840_VCONFIG_DCMODE_DWORDS | + CX25840_VCONFIG_IDID0S_NORMAL | + CX25840_VCONFIG_VIPCLAMP_DISABLED; + + /* add additional settings */ + cx25840_vconfig_add(state, val); + } else /* TODO: generic mode needs to be developed for other chips */ + WARN_ON(1); + + return 0; +} + static int cx25840_reset(struct v4l2_subdev *sd, u32 val) { struct cx25840_state *state = to_state(sd); @@ -1860,6 +2249,11 @@ static int cx25840_s_video_routing(struct v4l2_subdev *sd, if (is_cx23888(state)) cx23888_std_setup(client); + if (is_cx2584x(state) && state->generic_mode && config) { + cx25840_vconfig_add(state, config); + cx25840_vconfig_apply(client); + } + return set_input(client, input, state->aud_input); } @@ -5067,6 +5461,8 @@ static const struct v4l2_ctrl_ops cx25840_ctrl_ops = { static const struct v4l2_subdev_core_ops cx25840_core_ops = { .log_status = cx25840_log_status, .reset = cx25840_reset, + /* calling the (optional) init op will turn on the generic mode */ + .init = cx25840_init, .load_fw = cx25840_load_fw, .s_io_pin_config = common_s_io_pin_config, #ifdef CONFIG_VIDEO_ADV_DEBUG diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index e3ff1d7ec770..2ff7191ad232 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -53,10 +53,15 @@ enum cx25840_media_pads { * @mute: audio mute V4L2 control (non-cx2583x devices only) * @pvr150_workaround: whether we enable workaround for Hauppauge PVR150 * hardware bug (audio dropping out) + * @generic_mode: whether we disable ivtv-specific hacks + * this mode gets turned on when the bridge driver calls + * cx25840 subdevice init core op * @radio: set if we are currently in the radio mode, otherwise * the current mode is non-radio (that is, video) * @std: currently set video standard * @vid_input: currently set video input + * @vid_config: currently set video output configuration + * only used in the generic mode * @aud_input: currently set audio input * @audclk_freq: currently set audio sample rate * @audmode: currently set audio mode (when in non-radio mode) @@ -83,9 +88,11 @@ struct cx25840_state { struct v4l2_ctrl *mute; }; int pvr150_workaround; + bool generic_mode; int radio; v4l2_std_id std; enum cx25840_video_input vid_input; + u32 vid_config; enum cx25840_audio_input aud_input; u32 audclk_freq; int audmode; @@ -118,6 +125,14 @@ static inline bool is_cx2583x(struct cx25840_state *state) state->id == CX25837; } +static inline bool is_cx2584x(struct cx25840_state *state) +{ + return state->id == CX25840 || + state->id == CX25841 || + state->id == CX25842 || + state->id == CX25843; +} + static inline bool is_cx231xx(struct cx25840_state *state) { return state->id == CX2310X_AV; diff --git a/drivers/media/i2c/cx25840/cx25840-vbi.c b/drivers/media/i2c/cx25840/cx25840-vbi.c index 8c99a79fb726..415d482365e0 100644 --- a/drivers/media/i2c/cx25840/cx25840-vbi.c +++ b/drivers/media/i2c/cx25840/cx25840-vbi.c @@ -95,6 +95,7 @@ int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * memset(svbi->service_lines, 0, sizeof(svbi->service_lines)); svbi->service_set = 0; /* we're done if raw VBI is active */ + /* TODO: this will have to be changed for generic_mode VBI */ if ((cx25840_read(client, 0x404) & 0x10) == 0) return 0; @@ -137,6 +138,7 @@ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) cx25840_write(client, 0x54f, vbi_offset); else cx25840_write(client, 0x47f, vbi_offset); + /* TODO: this will have to be changed for generic_mode VBI */ cx25840_write(client, 0x404, 0x2e); return 0; } @@ -157,6 +159,7 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * cx25840_std_setup(client); /* Sliced VBI */ + /* TODO: this will have to be changed for generic_mode VBI */ cx25840_write(client, 0x404, 0x32); /* Ancillary data */ cx25840_write(client, 0x406, 0x13); if (is_cx23888(state)) @@ -211,6 +214,7 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format * } cx25840_write(client, state->vbi_regs_offset + 0x43c, 0x16); + /* TODO: this will have to be changed for generic_mode VBI */ if (is_cx23888(state)) cx25840_write(client, 0x428, is_pal ? 0x2a : 0x22); else diff --git a/include/media/drv-intf/cx25840.h b/include/media/drv-intf/cx25840.h index 4eae27c163ba..ed8ee1c77a6c 100644 --- a/include/media/drv-intf/cx25840.h +++ b/include/media/drv-intf/cx25840.h @@ -82,6 +82,81 @@ enum cx25840_video_input { CX25840_DIF_ON = 0x80000400, }; +/* + * The defines below are used to set the chip video output settings + * in the generic mode that can be enabled by calling the subdevice + * init core op. + * + * The requested settings can be passed to the init core op as + * @val parameter and to the s_routing video op as @config parameter. + * + * For details please refer to the section 3.7 Video Output Formatting and + * to Video Out Control 1 to 4 registers in the section 5.6 Video Decoder Core + * of the chip datasheet. + */ +#define CX25840_VCONFIG_FMT_SHIFT 0 +#define CX25840_VCONFIG_FMT_MASK GENMASK(2, 0) +#define CX25840_VCONFIG_FMT_BT601 BIT(0) +#define CX25840_VCONFIG_FMT_BT656 BIT(1) +#define CX25840_VCONFIG_FMT_VIP11 GENMASK(1, 0) +#define CX25840_VCONFIG_FMT_VIP2 BIT(2) + +#define CX25840_VCONFIG_RES_SHIFT 3 +#define CX25840_VCONFIG_RES_MASK GENMASK(4, 3) +#define CX25840_VCONFIG_RES_8BIT BIT(3) +#define CX25840_VCONFIG_RES_10BIT BIT(4) + +#define CX25840_VCONFIG_VBIRAW_SHIFT 5 +#define CX25840_VCONFIG_VBIRAW_MASK GENMASK(6, 5) +#define CX25840_VCONFIG_VBIRAW_DISABLED BIT(5) +#define CX25840_VCONFIG_VBIRAW_ENABLED BIT(6) + +#define CX25840_VCONFIG_ANCDATA_SHIFT 7 +#define CX25840_VCONFIG_ANCDATA_MASK GENMASK(8, 7) +#define CX25840_VCONFIG_ANCDATA_DISABLED BIT(7) +#define CX25840_VCONFIG_ANCDATA_ENABLED BIT(8) + +#define CX25840_VCONFIG_TASKBIT_SHIFT 9 +#define CX25840_VCONFIG_TASKBIT_MASK GENMASK(10, 9) +#define CX25840_VCONFIG_TASKBIT_ZERO BIT(9) +#define CX25840_VCONFIG_TASKBIT_ONE BIT(10) + +#define CX25840_VCONFIG_ACTIVE_SHIFT 11 +#define CX25840_VCONFIG_ACTIVE_MASK GENMASK(12, 11) +#define CX25840_VCONFIG_ACTIVE_COMPOSITE BIT(11) +#define CX25840_VCONFIG_ACTIVE_HORIZONTAL BIT(12) + +#define CX25840_VCONFIG_VALID_SHIFT 13 +#define CX25840_VCONFIG_VALID_MASK GENMASK(14, 13) +#define CX25840_VCONFIG_VALID_NORMAL BIT(13) +#define CX25840_VCONFIG_VALID_ANDACTIVE BIT(14) + +#define CX25840_VCONFIG_HRESETW_SHIFT 15 +#define CX25840_VCONFIG_HRESETW_MASK GENMASK(16, 15) +#define CX25840_VCONFIG_HRESETW_NORMAL BIT(15) +#define CX25840_VCONFIG_HRESETW_PIXCLK BIT(16) + +#define CX25840_VCONFIG_CLKGATE_SHIFT 17 +#define CX25840_VCONFIG_CLKGATE_MASK GENMASK(18, 17) +#define CX25840_VCONFIG_CLKGATE_NONE BIT(17) +#define CX25840_VCONFIG_CLKGATE_VALID BIT(18) +#define CX25840_VCONFIG_CLKGATE_VALIDACTIVE GENMASK(18, 17) + +#define CX25840_VCONFIG_DCMODE_SHIFT 19 +#define CX25840_VCONFIG_DCMODE_MASK GENMASK(20, 19) +#define CX25840_VCONFIG_DCMODE_DWORDS BIT(19) +#define CX25840_VCONFIG_DCMODE_BYTES BIT(20) + +#define CX25840_VCONFIG_IDID0S_SHIFT 21 +#define CX25840_VCONFIG_IDID0S_MASK GENMASK(22, 21) +#define CX25840_VCONFIG_IDID0S_NORMAL BIT(21) +#define CX25840_VCONFIG_IDID0S_LINECNT BIT(22) + +#define CX25840_VCONFIG_VIPCLAMP_SHIFT 23 +#define CX25840_VCONFIG_VIPCLAMP_MASK GENMASK(24, 23) +#define CX25840_VCONFIG_VIPCLAMP_ENABLED BIT(23) +#define CX25840_VCONFIG_VIPCLAMP_DISABLED BIT(24) + enum cx25840_audio_input { /* Audio inputs: serial or In4-In8 */ CX25840_AUDIO_SERIAL, @@ -109,7 +184,7 @@ enum cx25840_io_pin { }; enum cx25840_io_pad { - /* Output pads */ + /* Output pads, these must match the actual chip register values */ CX25840_PAD_DEFAULT = 0, CX25840_PAD_ACTIVE, CX25840_PAD_VACTIVE, -- cgit v1.2.3-59-g8ed1b From 65efeca0a6411139fc1956805f6334f3decc3c1b Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:56 -0400 Subject: media: cx25840: set_fmt operation should clamp out-of-range picture sizes According to V4L2 API set_fmt subdev operation should not return an error on out-of-range picture sizes, the values should be clamped instead to the supported range. The cx25840 datasheet says that the chip is capable of scaling down the picture width and height, respectively, 16 and 8 times. These values agree with what the old implementation enforced. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 59 ++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index f03bd637b795..371ac6bb265a 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -1702,7 +1702,8 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt = &format->format; struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - int HSC, VSC, Vsrc, Hsrc, filter, Vlines; + u32 HSC, VSC, Vsrc, Hsrc, Vadd; + int filter; int is_50Hz = !(state->std & V4L2_STD_525_60); if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) @@ -1727,28 +1728,46 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; } - Vlines = fmt->height; - if (!state->generic_mode) - Vlines += is_50Hz ? 4 : 7; + if (!state->generic_mode) { + Vadd = is_50Hz ? 4 : 7; - /* - * We keep 1 margin for the Vsrc < Vlines check since the - * cx23888 reports a Vsrc of 486 instead of 487 for the NTSC - * height. Without that margin the cx23885 fails in this - * check. - */ - if ((fmt->width == 0) || (Vlines == 0) || - (fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc + 1 < Vlines)) { - v4l_err(client, "%dx%d is not a valid size!\n", - fmt->width, fmt->height); - return -ERANGE; + /* + * cx23888 in 525-line mode is programmed for 486 active lines + * while other chips use 487 active lines. + * + * See reg 0x428 bits [21:12] in cx23888_std_setup() vs + * vactive in cx25840_std_setup(). + */ + if (is_cx23888(state) && !is_50Hz) + Vadd--; + } else + Vadd = 0; + + if (Hsrc == 0 || + Vsrc <= Vadd) { + v4l_err(client, + "chip reported picture size (%u x %u) is far too small\n", + (unsigned int)Hsrc, (unsigned int)Vsrc); + /* + * that's the best we can do since the output picture + * size is completely unknown in this case + */ + return -EINVAL; } + + fmt->width = clamp(fmt->width, (Hsrc + 15) / 16, Hsrc); + + if (Vadd * 8 >= Vsrc) + fmt->height = clamp(fmt->height, (u32)1, Vsrc - Vadd); + else + fmt->height = clamp(fmt->height, (Vsrc - Vadd * 8 + 7) / 8, + Vsrc - Vadd); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); + VSC = (1 << 16) - (Vsrc * (1 << 9) / (fmt->height + Vadd) - (1 << 9)); VSC &= 0x1fff; if (fmt->width >= 385) @@ -1760,8 +1779,10 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, else filter = 3; - v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n", - fmt->width, fmt->height, HSC, VSC); + v4l_dbg(1, cx25840_debug, client, + "decoder set size %u x %u with scale %x x %x\n", + (unsigned int)fmt->width, (unsigned int)fmt->height, + (unsigned int)HSC, (unsigned int)VSC); /* HSCALE=HSC */ if (is_cx23888(state)) { -- cgit v1.2.3-59-g8ed1b From d525e5c2f1b7f3bf198aeb56b039a682de4b00df Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:57 -0400 Subject: media: cxusb: implement Medion MD95700 digital / analog coexistence This patch prepares cxusb driver for supporting the analog part of Medion 95700 (previously only the digital - DVB - mode was supported). Specifically, it adds support for: * switching the device between analog and digital modes of operation, * enforcing that only one mode is active at the same time due to hardware limitations. Actual implementation of the analog mode will be provided by the next commit. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 449 +++++++++++++++++++++++++++---- drivers/media/usb/dvb-usb/cxusb.h | 48 ++++ drivers/media/usb/dvb-usb/dvb-usb-dvb.c | 5 +- drivers/media/usb/dvb-usb/dvb-usb-init.c | 13 + drivers/media/usb/dvb-usb/dvb-usb.h | 10 + 5 files changed, 472 insertions(+), 53 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 9ddb2000249e..68b0543abbdc 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -16,6 +16,7 @@ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) * Copyright (C) 2006, 2007 Chris Pascoe (c.pascoe@itee.uq.edu.au) + * Copyright (C) 2011, 2017 Maciej S. Szmigiero (mail@maciej.szmigiero.name) * * 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 @@ -24,9 +25,12 @@ * see Documentation/media/dvb-drivers/dvb-usb.rst for more information */ #include -#include -#include +#include +#include #include +#include +#include +#include #include "cxusb.h" @@ -47,17 +51,45 @@ #include "si2157.h" /* debug */ -static int dvb_usb_cxusb_debug; +int dvb_usb_cxusb_debug; module_param_named(debug, dvb_usb_cxusb_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS); +MODULE_PARM_DESC(debug, "set debugging level (see cxusb.h)." + DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, 0x03, args) -#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, 0x02, args) +#define deb_info(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_MISC, args) +#define deb_i2c(args...) dprintk(dvb_usb_cxusb_debug, CXUSB_DBG_I2C, args) + +enum cxusb_table_index { + MEDION_MD95700, + DVICO_BLUEBIRD_LG064F_COLD, + DVICO_BLUEBIRD_LG064F_WARM, + DVICO_BLUEBIRD_DUAL_1_COLD, + DVICO_BLUEBIRD_DUAL_1_WARM, + DVICO_BLUEBIRD_LGZ201_COLD, + DVICO_BLUEBIRD_LGZ201_WARM, + DVICO_BLUEBIRD_TH7579_COLD, + DVICO_BLUEBIRD_TH7579_WARM, + DIGITALNOW_BLUEBIRD_DUAL_1_COLD, + DIGITALNOW_BLUEBIRD_DUAL_1_WARM, + DVICO_BLUEBIRD_DUAL_2_COLD, + DVICO_BLUEBIRD_DUAL_2_WARM, + DVICO_BLUEBIRD_DUAL_4, + DVICO_BLUEBIRD_DVB_T_NANO_2, + DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, + AVERMEDIA_VOLAR_A868R, + DVICO_BLUEBIRD_DUAL_4_REV_2, + CONEXANT_D680_DMB, + MYGICA_D689, + MYGICA_T230, + NR__cxusb_table_index +}; + +static struct usb_device_id cxusb_table[]; -static int cxusb_ctrl_msg(struct dvb_usb_device *d, - u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) +int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen) { struct cxusb_state *st = d->priv; int ret; @@ -89,7 +121,8 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) struct cxusb_state *st = d->priv; u8 o[2], i; - if (st->gpio_write_state[GPIO_TUNER] == onoff) + if (st->gpio_write_state[GPIO_TUNER] == onoff && + !st->gpio_write_refresh[GPIO_TUNER]) return; o[0] = GPIO_TUNER; @@ -100,6 +133,7 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) deb_info("gpio_write failed.\n"); st->gpio_write_state[GPIO_TUNER] = onoff; + st->gpio_write_refresh[GPIO_TUNER] = false; } static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, @@ -259,7 +293,7 @@ unlock: static u32 cxusb_i2c_func(struct i2c_adapter *adapter) { - return I2C_FUNC_I2C; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static struct i2c_algorithm cxusb_i2c_algo = { @@ -267,15 +301,48 @@ static struct i2c_algorithm cxusb_i2c_algo = { .functionality = cxusb_i2c_func, }; -static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +static int _cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 b = 0; + + deb_info("setting power %s\n", onoff ? "ON" : "OFF"); + if (onoff) return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); else return cxusb_ctrl_msg(d, CMD_POWER_OFF, &b, 1, NULL, 0); } +static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + bool is_medion = d->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; + int ret; + + if (is_medion && !onoff) { + struct cxusb_medion_dev *cxdev = d->priv; + + mutex_lock(&cxdev->open_lock); + + if (cxdev->open_type == CXUSB_OPEN_ANALOG) { + deb_info("preventing DVB core from setting power OFF while we are in analog mode\n"); + ret = -EBUSY; + goto ret_unlock; + } + } + + ret = _cxusb_power_ctrl(d, onoff); + +ret_unlock: + if (is_medion && !onoff) { + struct cxusb_medion_dev *cxdev = d->priv; + + mutex_unlock(&cxdev->open_lock); + } + + return ret; +} + static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; @@ -353,11 +420,26 @@ static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { + struct dvb_usb_device *dvbdev = adap->dev; + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; u8 buf[2] = { 0x03, 0x00 }; + + if (is_medion && onoff) { + int ret; + + ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL); + if (ret != 0) + return ret; + } + if (onoff) - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0); + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, buf, 2, NULL, 0); else - cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + + if (is_medion && !onoff) + cxusb_medion_put(dvbdev); return 0; } @@ -630,9 +712,21 @@ static struct max2165_config mygica_d689_max2165_cfg = { /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { + struct dvb_usb_device *dvbdev = adap->dev; + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; + dvb_attach(simple_tuner_attach, adap->fe_adap[0].fe, - &adap->dev->i2c_adap, 0x61, + &dvbdev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); + + if (is_medion && adap->fe_adap[0].fe != NULL) + /* + * make sure that DVB core won't put to sleep (reset, really) + * tuner when we might be open in analog mode + */ + adap->fe_adap[0].fe->ops.tuner_ops.sleep = NULL; + return 0; } @@ -736,20 +830,105 @@ static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) return (fe == NULL) ? -EIO : 0; } -static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) +static int cxusb_medion_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) { + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dvb_usb_device *dvbdev = adap->dev; + + if (acquire) + return cxusb_medion_get(dvbdev, CXUSB_OPEN_DIGITAL); + + cxusb_medion_put(dvbdev); + + return 0; +} + +static int cxusb_medion_set_mode(struct dvb_usb_device *dvbdev, bool digital) +{ + struct cxusb_state *st = dvbdev->priv; + int ret; u8 b; - if (usb_set_interface(adap->dev->udev, 0, 6) < 0) - err("set interface failed"); + unsigned int i; + + /* + * switching mode while doing an I2C transaction often causes + * the device to crash + */ + mutex_lock(&dvbdev->i2c_mutex); + + if (digital) { + ret = usb_set_interface(dvbdev->udev, 0, 6); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "digital interface selection failed (%d)\n", + ret); + goto ret_unlock; + } + } else { + ret = usb_set_interface(dvbdev->udev, 0, 1); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "analog interface selection failed (%d)\n", + ret); + goto ret_unlock; + } + } + + /* pipes need to be cleared after setting interface */ + ret = usb_clear_halt(dvbdev->udev, usb_rcvbulkpipe(dvbdev->udev, 1)); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "clear halt on IN pipe failed (%d)\n", + ret); + + ret = usb_clear_halt(dvbdev->udev, usb_sndbulkpipe(dvbdev->udev, 1)); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "clear halt on OUT pipe failed (%d)\n", + ret); + + ret = cxusb_ctrl_msg(dvbdev, digital ? CMD_DIGITAL : CMD_ANALOG, + NULL, 0, &b, 1); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, "mode switch failed (%d)\n", + ret); + goto ret_unlock; + } + + /* mode switch seems to reset GPIO states */ + for (i = 0; i < ARRAY_SIZE(st->gpio_write_refresh); i++) + st->gpio_write_refresh[i] = true; - cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1); +ret_unlock: + mutex_unlock(&dvbdev->i2c_mutex); + + return ret; +} + +static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *dvbdev = adap->dev; + bool is_medion = dvbdev->props.devices[0].warm_ids[0] == + &cxusb_table[MEDION_MD95700]; + + if (is_medion) { + int ret; + + ret = cxusb_medion_set_mode(dvbdev, true); + if (ret) + return ret; + } adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, - &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) - return 0; + &dvbdev->i2c_adap); + if (adap->fe_adap[0].fe == NULL) + return -EIO; - return -EIO; + if (is_medion) + adap->fe_adap[0].fe->ops.ts_bus_ctrl = + cxusb_medion_fe_ts_bus_ctrl; + + return 0; } static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) @@ -1312,6 +1491,101 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, return -EINVAL; } +int cxusb_medion_get(struct dvb_usb_device *dvbdev, + enum cxusb_open_type open_type) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret = 0; + + mutex_lock(&cxdev->open_lock); + + if (WARN_ON((cxdev->open_type == CXUSB_OPEN_INIT || + cxdev->open_type == CXUSB_OPEN_NONE) && + cxdev->open_ctr != 0)) { + ret = -EINVAL; + goto ret_unlock; + } + + if (cxdev->open_type == CXUSB_OPEN_INIT) { + ret = -EAGAIN; + goto ret_unlock; + } + + if (cxdev->open_ctr == 0) { + if (cxdev->open_type != open_type) { + deb_info("will acquire and switch to %s\n", + open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + + if (open_type == CXUSB_OPEN_ANALOG) { + ret = _cxusb_power_ctrl(dvbdev, 1); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "powerup for analog switch failed (%d)\n", + ret); + + ret = cxusb_medion_set_mode(dvbdev, false); + if (ret != 0) + goto ret_unlock; + + ret = cxusb_medion_analog_init(dvbdev); + if (ret != 0) + goto ret_unlock; + } else { /* digital */ + ret = _cxusb_power_ctrl(dvbdev, 1); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "powerup for digital switch failed (%d)\n", + ret); + + ret = cxusb_medion_set_mode(dvbdev, true); + if (ret != 0) + goto ret_unlock; + } + + cxdev->open_type = open_type; + } else + deb_info("reacquired idle %s\n", + open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + + cxdev->open_ctr = 1; + } else if (cxdev->open_type == open_type) { + cxdev->open_ctr++; + deb_info("acquired %s\n", open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); + } else + ret = -EBUSY; + +ret_unlock: + mutex_unlock(&cxdev->open_lock); + + return ret; +} + +void cxusb_medion_put(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + mutex_lock(&cxdev->open_lock); + + if (cxdev->open_type == CXUSB_OPEN_INIT) { + WARN_ON(cxdev->open_ctr != 0); + cxdev->open_type = CXUSB_OPEN_NONE; + goto unlock; + } + + if (!WARN_ON(cxdev->open_ctr < 1)) { + cxdev->open_ctr--; + + deb_info("release %s\n", cxdev->open_type == + CXUSB_OPEN_ANALOG ? "analog" : "digital"); + } + +unlock: + mutex_unlock(&cxdev->open_lock); +} + /* DVB USB Driver stuff */ static struct dvb_usb_device_properties cxusb_medion_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties; @@ -1327,12 +1601,101 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static struct dvb_usb_device_properties cxusb_mygica_d689_properties; static struct dvb_usb_device_properties cxusb_mygica_t230_properties; +static int cxusb_medion_priv_init(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + cxdev->dvbdev = dvbdev; + cxdev->open_type = CXUSB_OPEN_INIT; + mutex_init(&cxdev->open_lock); + + return 0; +} + +static void cxusb_medion_priv_destroy(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + mutex_destroy(&cxdev->open_lock); +} + +static bool cxusb_medion_check_altsetting(struct usb_host_interface *as) +{ + unsigned int ctr; + + for (ctr = 0; ctr < as->desc.bNumEndpoints; ctr++) { + if ((as->endpoint[ctr].desc.bEndpointAddress & + USB_ENDPOINT_NUMBER_MASK) != 2) + continue; + + if (as->endpoint[ctr].desc.bEndpointAddress & USB_DIR_IN && + ((as->endpoint[ctr].desc.bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_ISOC)) + return true; + + break; + } + + return false; +} + +static bool cxusb_medion_check_intf(struct usb_interface *intf) +{ + unsigned int ctr; + + if (intf->num_altsetting < 2) { + dev_err(intf->usb_dev, "no alternate interface"); + + return false; + } + + for (ctr = 0; ctr < intf->num_altsetting; ctr++) { + if (intf->altsetting[ctr].desc.bAlternateSetting != 1) + continue; + + if (cxusb_medion_check_altsetting(&intf->altsetting[ctr])) + return true; + + break; + } + + dev_err(intf->usb_dev, "no iso interface"); + + return false; +} + static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { + struct dvb_usb_device *dvbdev; + int ret; + + /* Medion 95700 */ if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, + THIS_MODULE, &dvbdev, adapter_nr)) { + if (!cxusb_medion_check_intf(intf)) { + ret = -ENODEV; + goto ret_uninit; + } + + _cxusb_power_ctrl(dvbdev, 1); + ret = cxusb_medion_set_mode(dvbdev, false); + if (ret) + goto ret_uninit; + + ret = cxusb_medion_register_analog(dvbdev); + + cxusb_medion_set_mode(dvbdev, true); + _cxusb_power_ctrl(dvbdev, 0); + + if (ret != 0) + goto ret_uninit; + + /* release device from INIT mode to normal operation */ + cxusb_medion_put(dvbdev); + + return 0; + } else if (0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, THIS_MODULE, NULL, adapter_nr) || @@ -1362,6 +1725,11 @@ static int cxusb_probe(struct usb_interface *intf, return 0; return -EINVAL; + +ret_uninit: + dvb_usb_device_exit(intf); + + return ret; } static void cxusb_disconnect(struct usb_interface *intf) @@ -1370,6 +1738,9 @@ static void cxusb_disconnect(struct usb_interface *intf) struct cxusb_state *st = d->priv; struct i2c_client *client; + if (d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700]) + cxusb_medion_unregister_analog(d); + /* remove I2C client for tuner */ client = st->i2c_client_tuner; if (client) { @@ -1387,31 +1758,6 @@ static void cxusb_disconnect(struct usb_interface *intf) dvb_usb_device_exit(intf); } -enum cxusb_table_index { - MEDION_MD95700, - DVICO_BLUEBIRD_LG064F_COLD, - DVICO_BLUEBIRD_LG064F_WARM, - DVICO_BLUEBIRD_DUAL_1_COLD, - DVICO_BLUEBIRD_DUAL_1_WARM, - DVICO_BLUEBIRD_LGZ201_COLD, - DVICO_BLUEBIRD_LGZ201_WARM, - DVICO_BLUEBIRD_TH7579_COLD, - DVICO_BLUEBIRD_TH7579_WARM, - DIGITALNOW_BLUEBIRD_DUAL_1_COLD, - DIGITALNOW_BLUEBIRD_DUAL_1_WARM, - DVICO_BLUEBIRD_DUAL_2_COLD, - DVICO_BLUEBIRD_DUAL_2_WARM, - DVICO_BLUEBIRD_DUAL_4, - DVICO_BLUEBIRD_DVB_T_NANO_2, - DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM, - AVERMEDIA_VOLAR_A868R, - DVICO_BLUEBIRD_DUAL_4_REV_2, - CONEXANT_D680_DMB, - MYGICA_D689, - MYGICA_T230, - NR__cxusb_table_index -}; - static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { [MEDION_MD95700] = { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) @@ -1485,7 +1831,9 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { .usb_ctrl = CYPRESS_FX2, - .size_of_priv = sizeof(struct cxusb_state), + .size_of_priv = sizeof(struct cxusb_medion_dev), + .priv_init = cxusb_medion_priv_init, + .priv_destroy = cxusb_medion_priv_destroy, .num_adapters = 1, .adapter = { @@ -2198,6 +2546,7 @@ module_usb_driver(cxusb_driver); MODULE_AUTHOR("Patrick Boettcher "); MODULE_AUTHOR("Michael Krufky "); MODULE_AUTHOR("Chris Pascoe "); +MODULE_AUTHOR("Maciej S. Szmigiero "); MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); MODULE_VERSION("1.0-alpha"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 88f9b9804b25..f586d61a7bf8 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -2,6 +2,9 @@ #ifndef _DVB_USB_CXUSB_H_ #define _DVB_USB_CXUSB_H_ +#include +#include + #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" @@ -34,6 +37,7 @@ struct cxusb_state { u8 gpio_write_state[3]; + bool gpio_write_refresh[3]; struct i2c_client *i2c_client_demod; struct i2c_client *i2c_client_tuner; @@ -45,4 +49,48 @@ struct cxusb_state { enum fe_status *status); }; +enum cxusb_open_type { + CXUSB_OPEN_INIT, CXUSB_OPEN_NONE, + CXUSB_OPEN_ANALOG, CXUSB_OPEN_DIGITAL +}; + +struct cxusb_medion_dev { + /* has to be the first one */ + struct cxusb_state state; + + struct dvb_usb_device *dvbdev; + + enum cxusb_open_type open_type; + unsigned int open_ctr; + struct mutex open_lock; +}; + +/* defines for "debug" module parameter */ +#define CXUSB_DBG_RC BIT(0) +#define CXUSB_DBG_I2C BIT(1) +#define CXUSB_DBG_MISC BIT(2) + +extern int dvb_usb_cxusb_debug; + +int cxusb_ctrl_msg(struct dvb_usb_device *d, + u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen); + +static inline int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) +{ + return -EINVAL; +} + +static inline int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) +{ + return 0; +} + +static inline void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) +{ +} + +int cxusb_medion_get(struct dvb_usb_device *dvbdev, + enum cxusb_open_type open_type); +void cxusb_medion_put(struct dvb_usb_device *dvbdev); + #endif diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c index 8056053c9ab0..0a7f8ba90992 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c @@ -56,9 +56,6 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) * for reception. */ if (adap->feedcount == onoff && adap->feedcount > 0) { - deb_ts("submitting all URBs\n"); - usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); - deb_ts("controlling pid parser\n"); if (adap->props.fe[adap->active_fe].caps & DVB_USB_ADAP_HAS_PID_FILTER && adap->props.fe[adap->active_fe].caps & @@ -80,6 +77,8 @@ static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff) } } + deb_ts("submitting all URBs\n"); + usb_urb_submit(&adap->fe_adap[adap->active_fe].stream); } return 0; } diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c index dd063a736df5..2ddfff713af1 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c @@ -133,6 +133,10 @@ static int dvb_usb_exit(struct dvb_usb_device *d) dvb_usb_i2c_exit(d); deb_info("state should be zero now: %x\n", d->state); d->state = DVB_USB_STATE_INIT; + + if (d->priv != NULL && d->props.priv_destroy != NULL) + d->props.priv_destroy(d); + kfree(d->priv); kfree(d); return 0; @@ -154,6 +158,15 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums) err("no memory for priv in 'struct dvb_usb_device'"); return -ENOMEM; } + + if (d->props.priv_init != NULL) { + ret = d->props.priv_init(d); + if (ret != 0) { + kfree(d->priv); + d->priv = NULL; + return ret; + } + } } /* check the capabilities and set appropriate variables */ diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 32829bdd5f22..2eb0e24e8943 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -129,6 +129,9 @@ struct usb_data_stream_properties { * @frontend_ctrl: called to power on/off active frontend. * @streaming_ctrl: called to start and stop the MPEG2-TS streaming of the * device (not URB submitting/killing). + * This callback will be called without data URBs being active - data URBs + * will be submitted only after streaming_ctrl(1) returns successfully and + * they will be killed before streaming_ctrl(0) gets called. * @pid_filter_ctrl: called to en/disable the PID filter, if any. * @pid_filter: called to set/unset a PID for filtering. * @frontend_attach: called to attach the possible frontends (fill fe-field @@ -234,6 +237,11 @@ enum dvb_usb_mode { * * @size_of_priv: how many bytes shall be allocated for the private field * of struct dvb_usb_device. + * @priv_init: optional callback to initialize the variable that private field + * of struct dvb_usb_device has pointer to just after it had been allocated and + * zeroed. + * @priv_destroy: just like priv_init, only called before deallocating + * the memory pointed by private field of struct dvb_usb_device. * * @power_ctrl: called to enable/disable power of the device. * @read_mac_address: called to read the MAC address of the device. @@ -275,6 +283,8 @@ struct dvb_usb_device_properties { int no_reconnect; int size_of_priv; + int (*priv_init)(struct dvb_usb_device *); + void (*priv_destroy)(struct dvb_usb_device *); int num_adapters; struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE]; -- cgit v1.2.3-59-g8ed1b From e478d40540544e229c843fe0c698ebc7d0ca07e6 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:58 -0400 Subject: media: cxusb: add analog mode support for Medion MD95700 This patch adds support for analog part of Medion 95700 in the cxusb driver. What works: * Video capture at various sizes with sequential fields, * Input switching (TV Tuner, Composite, S-Video), * TV and radio tuning, * Video standard switching and auto detection, * Radio mode switching (stereo / mono), * Unplugging while capturing, * DVB / analog coexistence. What does not work yet: * Audio, * VBI, * Picture controls. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: remove left-over commented-out debug message] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/Kconfig | 16 +- drivers/media/usb/dvb-usb/Makefile | 3 + drivers/media/usb/dvb-usb/cxusb-analog.c | 1845 ++++++++++++++++++++++++++++++ drivers/media/usb/dvb-usb/cxusb.c | 2 - drivers/media/usb/dvb-usb/cxusb.h | 106 ++ 5 files changed, 1968 insertions(+), 4 deletions(-) create mode 100644 drivers/media/usb/dvb-usb/cxusb-analog.c (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 87dbae875177..1a3e5f965ae4 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -139,12 +139,24 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Conexant USB2.0 hybrid reference design. - Currently, only DVB and ATSC modes are supported, analog mode - shall be added in the future. Devices that require this module: + DVB and ATSC modes are supported, for a basic analog mode support + see the next option ("Analog support for the Conexant USB2.0 hybrid + reference design"). + Devices that require this module: Medion MD95700 hybrid USB2.0 device. DViCO FusionHDTV (Bluebird) USB2.0 devices +config DVB_USB_CXUSB_ANALOG + bool "Analog support for the Conexant USB2.0 hybrid reference design" + depends on DVB_USB_CXUSB && VIDEO_V4L2 + select VIDEO_CX25840 + select VIDEOBUF2_VMALLOC + help + Say Y here to enable basic analog mode support for the Conexant + USB2.0 hybrid reference design. + Currently this mode is supported only on a Medion MD95700 device. + config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" depends on DVB_USB diff --git a/drivers/media/usb/dvb-usb/Makefile b/drivers/media/usb/dvb-usb/Makefile index 407d90ca8be0..28e4806a87cd 100644 --- a/drivers/media/usb/dvb-usb/Makefile +++ b/drivers/media/usb/dvb-usb/Makefile @@ -42,6 +42,9 @@ dvb-usb-digitv-objs := digitv.o obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o dvb-usb-cxusb-objs := cxusb.o +ifeq ($(CONFIG_DVB_USB_CXUSB_ANALOG),y) +dvb-usb-cxusb-objs += cxusb-analog.o +endif obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o dvb-usb-ttusb2-objs := ttusb2.o diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c new file mode 100644 index 000000000000..8df6c33bbbb1 --- /dev/null +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -0,0 +1,1845 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// DVB USB compliant linux driver for Conexant USB reference design - +// (analog part). +// +// Copyright (C) 2011, 2017, 2018 +// Maciej S. Szmigiero (mail@maciej.szmigiero.name) +// +// In case there are new analog / DVB-T hybrid devices released in the market +// using the same general design as Medion MD95700: a CX25840 video decoder +// outputting a BT.656 stream to a USB bridge chip which then forwards it to +// the host in isochronous USB packets this code should be made generic, with +// board specific bits implemented via separate card structures. +// +// This is, however, unlikely as the Medion model was released +// years ago (in 2005). +// +// TODO: +// * audio support, +// * finish radio support (requires audio of course), +// * VBI support, +// * controls support + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cxusb.h" + +static int cxusb_medion_v_queue_setup(struct vb2_queue *q, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + unsigned int size = cxdev->width * cxdev->height * 2; + + if (*num_planes > 0) { + if (*num_planes != 1) + return -EINVAL; + + if (sizes[0] < size) + return -EINVAL; + } else { + *num_planes = 1; + sizes[0] = size; + } + + return 0; +} + +static int cxusb_medion_v_buf_init(struct vb2_buffer *vb) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(vb->vb2_queue); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + cxusb_vprintk(dvbdev, OPS, "buffer init\n"); + + if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2) + return -ENOMEM; + + cxusb_vprintk(dvbdev, OPS, "buffer OK\n"); + + return 0; +} + +static void cxusb_auxbuf_init(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + u8 *buf, unsigned int len) +{ + cxusb_vprintk(dvbdev, AUXB, "initializing auxbuf of len %u\n", len); + + auxbuf->buf = buf; + auxbuf->len = len; + auxbuf->paylen = 0; +} + +static void cxusb_auxbuf_head_trim(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + unsigned int pos) +{ + if (pos == 0) + return; + + if (WARN_ON(pos > auxbuf->paylen)) + return; + + cxusb_vprintk(dvbdev, AUXB, + "trimming auxbuf len by %u to %u\n", + pos, auxbuf->paylen - pos); + + memmove(auxbuf->buf, auxbuf->buf + pos, auxbuf->paylen - pos); + auxbuf->paylen -= pos; +} + +static unsigned int cxusb_auxbuf_paylen(struct cxusb_medion_auxbuf *auxbuf) +{ + return auxbuf->paylen; +} + +static bool cxusb_auxbuf_make_space(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + unsigned int howmuch) +{ + unsigned int freespace; + + if (WARN_ON(howmuch >= auxbuf->len)) + howmuch = auxbuf->len - 1; + + freespace = auxbuf->len - cxusb_auxbuf_paylen(auxbuf); + + cxusb_vprintk(dvbdev, AUXB, "freespace is %u\n", freespace); + + if (freespace >= howmuch) + return true; + + howmuch -= freespace; + + cxusb_vprintk(dvbdev, AUXB, "will overwrite %u bytes of buffer\n", + howmuch); + + cxusb_auxbuf_head_trim(dvbdev, auxbuf, howmuch); + + return false; +} + +/* returns false if some data was overwritten */ +static bool cxusb_auxbuf_append_urb(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct urb *urb) +{ + unsigned long len; + int i; + bool ret; + + for (i = 0, len = 0; i < urb->number_of_packets; i++) + len += urb->iso_frame_desc[i].actual_length; + + ret = cxusb_auxbuf_make_space(dvbdev, auxbuf, len); + + for (i = 0; i < urb->number_of_packets; i++) { + unsigned int to_copy; + + to_copy = urb->iso_frame_desc[i].actual_length; + + memcpy(auxbuf->buf + auxbuf->paylen, urb->transfer_buffer + + urb->iso_frame_desc[i].offset, to_copy); + + auxbuf->paylen += to_copy; + } + + return ret; +} + +static bool cxusb_auxbuf_copy(struct cxusb_medion_auxbuf *auxbuf, + unsigned int pos, unsigned char *dest, + unsigned int len) +{ + if (pos + len > auxbuf->paylen) + return false; + + memcpy(dest, auxbuf->buf + pos, len); + + return true; +} + +static bool cxusb_medion_cf_refc_fld_chg(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlines, + unsigned int maxlinesamples, + unsigned char buf[4]) +{ + bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) == + CXUSB_BT656_FIELD_1; + unsigned int remlines; + + if (bt656->line == 0 || firstfield == firstfield_code) + return false; + + if (bt656->fmode == LINE_SAMPLES) { + unsigned int remsamples = maxlinesamples - + bt656->linesamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c after line %u field change\n", + firstfield ? '1' : '2', bt656->line); + + if (bt656->buf != NULL && remsamples > 0) { + memset(bt656->buf, 0, remsamples); + bt656->buf += remsamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c line %u %u samples still remaining (of %u)\n", + firstfield ? '1' : '2', + bt656->line, remsamples, + maxlinesamples); + } + + bt656->line++; + } + + remlines = maxlines - bt656->line; + if (bt656->buf != NULL && remlines > 0) { + memset(bt656->buf, 0, remlines * maxlinesamples); + bt656->buf += remlines * maxlinesamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c %u lines still remaining (of %u)\n", + firstfield ? '1' : '2', remlines, + maxlines); + } + + return true; +} + +static void cxusb_medion_cf_refc_start_sch(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned char buf[4]) +{ + bool firstfield_code = (buf[3] & CXUSB_BT656_FIELD_MASK) == + CXUSB_BT656_FIELD_1; + bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == + CXUSB_BT656_SEAV_SAV; + bool vbi_code = (buf[3] & CXUSB_BT656_VBI_MASK) == + CXUSB_BT656_VBI_ON; + + if (!sav_code || firstfield != firstfield_code) + return; + + if (!vbi_code) { + cxusb_vprintk(dvbdev, BT656, "line start @ pos %u\n", + bt656->pos); + + bt656->linesamples = 0; + bt656->fmode = LINE_SAMPLES; + } else { + cxusb_vprintk(dvbdev, BT656, "VBI start @ pos %u\n", + bt656->pos); + + bt656->fmode = VBI_SAMPLES; + } +} + +static void cxusb_medion_cf_refc_line_smpl(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlinesamples, + unsigned char buf[4]) +{ + bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == + CXUSB_BT656_SEAV_SAV; + unsigned int remsamples; + + if (sav_code) + cxusb_vprintk(dvbdev, BT656, + "SAV in line samples @ line %u, pos %u\n", + bt656->line, bt656->pos); + + remsamples = maxlinesamples - bt656->linesamples; + if (bt656->buf != NULL && remsamples > 0) { + memset(bt656->buf, 0, remsamples); + bt656->buf += remsamples; + + cxusb_vprintk(dvbdev, BT656, + "field %c line %u %u samples still remaining (of %u)\n", + firstfield ? '1' : '2', bt656->line, remsamples, + maxlinesamples); + } + + bt656->fmode = START_SEARCH; + bt656->line++; +} + +static void cxusb_medion_cf_refc_vbi_smpl(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + unsigned char buf[4]) +{ + bool sav_code = (buf[3] & CXUSB_BT656_SEAV_MASK) == + CXUSB_BT656_SEAV_SAV; + + if (sav_code) + cxusb_vprintk(dvbdev, BT656, "SAV in VBI samples @ pos %u\n", + bt656->pos); + + bt656->fmode = START_SEARCH; +} + +/* returns whether the whole 4-byte code should be skipped in the buffer */ +static bool cxusb_medion_cf_ref_code(struct dvb_usb_device *dvbdev, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlines, + unsigned int maxlinesamples, + unsigned char buf[4]) +{ + if (bt656->fmode == START_SEARCH) + cxusb_medion_cf_refc_start_sch(dvbdev, bt656, firstfield, buf); + else if (bt656->fmode == LINE_SAMPLES) { + cxusb_medion_cf_refc_line_smpl(dvbdev, bt656, firstfield, + maxlinesamples, buf); + return false; + } else if (bt656->fmode == VBI_SAMPLES) { + cxusb_medion_cf_refc_vbi_smpl(dvbdev, bt656, buf); + return false; + } + + return true; +} + +static bool cxusb_medion_cs_start_sch(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct cxusb_bt656_params *bt656, + unsigned int maxlinesamples) +{ + unsigned char buf[64]; + unsigned int idx; + unsigned int tocheck = clamp_t(size_t, maxlinesamples / 4, 3, + sizeof(buf)); + + if (!cxusb_auxbuf_copy(auxbuf, bt656->pos + 1, buf, tocheck)) + return false; + + for (idx = 0; idx <= tocheck - 3; idx++) + if (memcmp(buf + idx, CXUSB_BT656_PREAMBLE, 3) == 0) { + bt656->pos += (1 + idx); + return true; + } + + cxusb_vprintk(dvbdev, BT656, "line %u early start, pos %u\n", + bt656->line, bt656->pos); + + bt656->linesamples = 0; + bt656->fmode = LINE_SAMPLES; + + return true; +} + +static void cxusb_medion_cs_line_smpl(struct cxusb_bt656_params *bt656, + unsigned int maxlinesamples, + unsigned char val) +{ + if (bt656->buf != NULL) + *(bt656->buf++) = val; + + bt656->linesamples++; + bt656->pos++; + + if (bt656->linesamples >= maxlinesamples) { + bt656->fmode = START_SEARCH; + bt656->line++; + } +} + +static bool cxusb_medion_copy_samples(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct cxusb_bt656_params *bt656, + unsigned int maxlinesamples, + unsigned char val) +{ + if (bt656->fmode == START_SEARCH && bt656->line > 0) + return cxusb_medion_cs_start_sch(dvbdev, auxbuf, bt656, + maxlinesamples); + else if (bt656->fmode == LINE_SAMPLES) + cxusb_medion_cs_line_smpl(bt656, maxlinesamples, val); + else /* TODO: copy VBI samples */ + bt656->pos++; + + return true; +} + +static bool cxusb_medion_copy_field(struct dvb_usb_device *dvbdev, + struct cxusb_medion_auxbuf *auxbuf, + struct cxusb_bt656_params *bt656, + bool firstfield, + unsigned int maxlines, + unsigned int maxlinesmpls) +{ + while (bt656->line < maxlines) { + unsigned char val; + + if (!cxusb_auxbuf_copy(auxbuf, bt656->pos, &val, 1)) + break; + + if (val == CXUSB_BT656_PREAMBLE[0]) { + unsigned char buf[4]; + + buf[0] = val; + if (!cxusb_auxbuf_copy(auxbuf, bt656->pos + 1, + buf + 1, 3)) + break; + + if (buf[1] == CXUSB_BT656_PREAMBLE[1] && + buf[2] == CXUSB_BT656_PREAMBLE[2]) { + /* + * is this a field change? + * if so, terminate copying the current field + */ + if (cxusb_medion_cf_refc_fld_chg(dvbdev, + bt656, + firstfield, + maxlines, + maxlinesmpls, + buf)) + return true; + + if (cxusb_medion_cf_ref_code(dvbdev, bt656, + firstfield, + maxlines, + maxlinesmpls, + buf)) + bt656->pos += 4; + + continue; + } + } + + if (!cxusb_medion_copy_samples(dvbdev, auxbuf, bt656, + maxlinesmpls, val)) + break; + } + + if (bt656->line < maxlines) { + cxusb_vprintk(dvbdev, BT656, + "end of buffer pos = %u, line = %u\n", + bt656->pos, bt656->line); + return false; + } + + return true; +} + +static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, + bool reset) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + struct cxusb_bt656_params *bt656 = &cxdev->bt656; + + /* + * if this is a new frame + * fetch a buffer from list + */ + if (bt656->mode == NEW_FRAME) { + if (!list_empty(&cxdev->buflist)) { + cxdev->vbuf = + list_first_entry(&cxdev->buflist, + struct cxusb_medion_vbuffer, + list); + list_del(&cxdev->vbuf->list); + } else + dev_warn(&dvbdev->udev->dev, "no free buffers\n"); + } + + if (bt656->mode == NEW_FRAME || reset) { + cxusb_vprintk(dvbdev, URB, "will copy field 1\n"); + bt656->pos = 0; + bt656->mode = FIRST_FIELD; + bt656->fmode = START_SEARCH; + bt656->line = 0; + + if (cxdev->vbuf != NULL) { + cxdev->vbuf->vb2.vb2_buf.timestamp = ktime_get_ns(); + bt656->buf = vb2_plane_vaddr(&cxdev->vbuf->vb2.vb2_buf, + 0); + } + } + + if (bt656->mode == FIRST_FIELD) { + if (!cxusb_medion_copy_field(dvbdev, &cxdev->auxbuf, bt656, + true, cxdev->height / 2, + cxdev->width * 2)) + return false; + + /* + * do not trim buffer there in case + * we need to reset the search later + */ + + cxusb_vprintk(dvbdev, URB, "will copy field 2\n"); + bt656->mode = SECOND_FIELD; + bt656->fmode = START_SEARCH; + bt656->line = 0; + } + + if (bt656->mode == SECOND_FIELD) { + if (!cxusb_medion_copy_field(dvbdev, &cxdev->auxbuf, bt656, + false, cxdev->height / 2, + cxdev->width * 2)) + return false; + + cxusb_auxbuf_head_trim(dvbdev, &cxdev->auxbuf, bt656->pos); + + bt656->mode = NEW_FRAME; + + if (cxdev->vbuf != NULL) { + vb2_set_plane_payload(&cxdev->vbuf->vb2.vb2_buf, 0, + cxdev->width * cxdev->height * 2); + + cxdev->vbuf->vb2.field = cxdev->field_order; + cxdev->vbuf->vb2.sequence = cxdev->vbuf_sequence++; + + vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf, + VB2_BUF_STATE_DONE); + + cxdev->vbuf = NULL; + cxdev->bt656.buf = NULL; + + cxusb_vprintk(dvbdev, URB, "frame done\n"); + } else { + cxusb_vprintk(dvbdev, URB, "frame skipped\n"); + cxdev->vbuf_sequence++; + } + } + + return true; +} + +static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, + bool *auxbuf_reset) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + unsigned int urbn; + struct urb *urb; + int ret; + + *auxbuf_reset = false; + + urbn = cxdev->nexturb; + if (!test_bit(urbn, &cxdev->urbcomplete)) + return false; + + clear_bit(urbn, &cxdev->urbcomplete); + + do { + cxdev->nexturb++; + cxdev->nexturb %= CXUSB_VIDEO_URBS; + urb = cxdev->streamurbs[cxdev->nexturb]; + } while (urb == NULL); + + urb = cxdev->streamurbs[urbn]; + cxusb_vprintk(dvbdev, URB, "URB %u status = %d\n", urbn, urb->status); + + if (urb->status == 0 || urb->status == -EXDEV) { + int i; + unsigned long len; + + for (i = 0, len = 0; i < urb->number_of_packets; i++) + len += urb->iso_frame_desc[i].actual_length; + + cxusb_vprintk(dvbdev, URB, "URB %u data len = %lu\n", urbn, + len); + + if (len > 0) { + cxusb_vprintk(dvbdev, URB, "appending URB\n"); + + /* + * append new data to auxbuf while + * overwriting old data if necessary + * + * if any overwrite happens then we can no + * longer rely on consistency of the whole + * data so let's start again the current + * auxbuf frame assembling process from + * the beginning + */ + *auxbuf_reset = + !cxusb_auxbuf_append_urb(dvbdev, + &cxdev->auxbuf, + urb); + } + } + + cxusb_vprintk(dvbdev, URB, "URB %u resubmit\n", urbn); + + ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret != 0) + dev_err(&dvbdev->udev->dev, + "unable to resubmit URB %u (%d), you'll have to restart streaming\n", + urbn, ret); + + /* next URB is complete already? reschedule us then to handle it */ + return test_bit(cxdev->nexturb, &cxdev->urbcomplete); +} + +static void cxusb_medion_v_complete_work(struct work_struct *work) +{ + struct cxusb_medion_dev *cxdev = container_of(work, + struct cxusb_medion_dev, + urbwork); + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + bool auxbuf_reset; + bool reschedule; + + mutex_lock(cxdev->videodev->lock); + + cxusb_vprintk(dvbdev, URB, "worker called, stop_streaming = %d\n", + (int)cxdev->stop_streaming); + + if (cxdev->stop_streaming) + goto unlock; + + reschedule = cxusb_medion_v_complete_handle_urb(cxdev, &auxbuf_reset); + + if (cxusb_medion_v_process_auxbuf(cxdev, auxbuf_reset)) + /* reschedule us until auxbuf no longer can produce any frame */ + reschedule = true; + + if (reschedule) { + cxusb_vprintk(dvbdev, URB, "rescheduling worker\n"); + schedule_work(&cxdev->urbwork); + } + +unlock: + mutex_unlock(cxdev->videodev->lock); +} + +static void cxusb_medion_v_complete(struct urb *u) +{ + struct dvb_usb_device *dvbdev = u->context; + struct cxusb_medion_dev *cxdev = dvbdev->priv; + unsigned int i; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i] == u) + break; + + if (i >= CXUSB_VIDEO_URBS) { + dev_err(&dvbdev->udev->dev, + "complete on unknown URB\n"); + return; + } + + cxusb_vprintk(dvbdev, URB, "URB %u complete\n", i); + + set_bit(i, &cxdev->urbcomplete); + schedule_work(&cxdev->urbwork); +} + +static void cxusb_medion_urbs_free(struct cxusb_medion_dev *cxdev) +{ + unsigned int i; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i] != NULL) { + kfree(cxdev->streamurbs[i]->transfer_buffer); + usb_free_urb(cxdev->streamurbs[i]); + cxdev->streamurbs[i] = NULL; + } +} + +static void cxusb_medion_return_buffers(struct cxusb_medion_dev *cxdev, + bool requeue) +{ + struct cxusb_medion_vbuffer *vbuf, *vbuf_tmp; + + list_for_each_entry_safe(vbuf, vbuf_tmp, &cxdev->buflist, + list) { + list_del(&vbuf->list); + vb2_buffer_done(&vbuf->vb2.vb2_buf, + requeue ? VB2_BUF_STATE_QUEUED : + VB2_BUF_STATE_ERROR); + } + + if (cxdev->vbuf != NULL) { + vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf, + requeue ? VB2_BUF_STATE_QUEUED : + VB2_BUF_STATE_ERROR); + + cxdev->vbuf = NULL; + cxdev->bt656.buf = NULL; + } +} + +static int cxusb_medion_v_ss_auxbuf_alloc(struct cxusb_medion_dev *cxdev, + int *npackets) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + u8 *buf; + unsigned int framelen, urblen, auxbuflen; + + framelen = (cxdev->width * 2 + 4 + 4) * + (cxdev->height + 50 /* VBI lines */); + + /* + * try to fit a whole frame into each URB, as long as doing so + * does not require very high order memory allocations + */ + BUILD_BUG_ON(CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE > + CXUSB_VIDEO_MAX_FRAME_PKTS); + *npackets = min_t(int, (framelen + CXUSB_VIDEO_PKT_SIZE - 1) / + CXUSB_VIDEO_PKT_SIZE, + CXUSB_VIDEO_URB_MAX_SIZE / CXUSB_VIDEO_PKT_SIZE); + urblen = *npackets * CXUSB_VIDEO_PKT_SIZE; + + cxusb_vprintk(dvbdev, URB, + "each URB will have %d packets for total of %u bytes (%u x %u @ %u)\n", + *npackets, urblen, (unsigned int)cxdev->width, + (unsigned int)cxdev->height, framelen); + + auxbuflen = framelen + urblen; + + buf = vmalloc(auxbuflen); + if (buf == NULL) + return -ENOMEM; + + cxusb_auxbuf_init(dvbdev, &cxdev->auxbuf, buf, auxbuflen); + + return 0; +} + +static u32 cxusb_medion_norm2field_order(v4l2_std_id norm) +{ + bool is625 = norm & V4L2_STD_625_50; + bool is525 = norm & V4L2_STD_525_60; + + if (!is625 && !is525) + return V4L2_FIELD_NONE; + + if (is625 && is525) + return V4L2_FIELD_NONE; + + if (is625) + return V4L2_FIELD_SEQ_TB; + else /* is525 */ + return V4L2_FIELD_SEQ_BT; +} + +static u32 cxusb_medion_field_order(struct cxusb_medion_dev *cxdev) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + u32 field; + int ret; + v4l2_std_id norm; + + /* TV tuner is PAL-only so it is always TB */ + if (cxdev->input == 0) + return V4L2_FIELD_SEQ_TB; + + field = cxusb_medion_norm2field_order(cxdev->norm); + if (field != V4L2_FIELD_NONE) + return field; + + ret = v4l2_subdev_call(cxdev->cx25840, video, g_std, &norm); + if (ret != 0) + cxusb_vprintk(dvbdev, OPS, + "cannot get current standard for input %u\n", + (unsigned int)cxdev->input); + else { + field = cxusb_medion_norm2field_order(norm); + if (field != V4L2_FIELD_NONE) + return field; + } + + dev_warn(&dvbdev->udev->dev, + "cannot determine field order for the current standard setup and received signal, using TB\n"); + return V4L2_FIELD_SEQ_TB; +} + +static int cxusb_medion_v_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + u8 streamon_params[2] = { 0x03, 0x00 }; + int npackets, i; + int ret; + + cxusb_vprintk(dvbdev, OPS, "should start streaming\n"); + + if (cxdev->stop_streaming) { + /* stream is being stopped */ + ret = -EBUSY; + goto ret_retbufs; + } + + cxdev->field_order = cxusb_medion_field_order(cxdev); + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 1); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "unable to start stream (%d)\n", ret); + goto ret_retbufs; + } + + ret = cxusb_ctrl_msg(dvbdev, CMD_STREAMING_ON, streamon_params, 2, + NULL, 0); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "unable to start streaming (%d)\n", ret); + goto ret_unstream_cx; + } + + ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); + if (ret != 0) + goto ret_unstream_md; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) { + int framen; + u8 *streambuf; + struct urb *surb; + + /* + * TODO: change this to an array of single pages to avoid + * doing a large continuous allocation when (if) + * s-g isochronous USB transfers are supported + */ + streambuf = kmalloc(npackets * CXUSB_VIDEO_PKT_SIZE, + GFP_KERNEL); + if (streambuf == NULL) { + if (i < 2) { + ret = -ENOMEM; + goto ret_freeab; + } else + break; + } + + surb = usb_alloc_urb(npackets, GFP_KERNEL); + if (surb == NULL) { + kfree(streambuf); + ret = -ENOMEM; + goto ret_freeu; + } + + cxdev->streamurbs[i] = surb; + surb->dev = dvbdev->udev; + surb->context = dvbdev; + surb->pipe = usb_rcvisocpipe(dvbdev->udev, 2); + + surb->interval = 1; + surb->transfer_flags = URB_ISO_ASAP; + + surb->transfer_buffer = streambuf; + + surb->complete = cxusb_medion_v_complete; + surb->number_of_packets = npackets; + surb->transfer_buffer_length = npackets * CXUSB_VIDEO_PKT_SIZE; + + for (framen = 0; framen < npackets; framen++) { + surb->iso_frame_desc[framen].offset = + CXUSB_VIDEO_PKT_SIZE * framen; + + surb->iso_frame_desc[framen].length = + CXUSB_VIDEO_PKT_SIZE; + } + } + + cxdev->urbcomplete = 0; + cxdev->nexturb = 0; + cxdev->vbuf_sequence = 0; + + cxdev->vbuf = NULL; + cxdev->bt656.mode = NEW_FRAME; + cxdev->bt656.buf = NULL; + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i] != NULL) { + ret = usb_submit_urb(cxdev->streamurbs[i], + GFP_KERNEL); + if (ret != 0) + dev_err(&dvbdev->udev->dev, + "URB %d submission failed (%d)\n", i, + ret); + } + + return 0; + +ret_freeu: + cxusb_medion_urbs_free(cxdev); + +ret_freeab: + vfree(cxdev->auxbuf.buf); + +ret_unstream_md: + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + +ret_unstream_cx: + v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0); + +ret_retbufs: + cxusb_medion_return_buffers(cxdev, true); + + return ret; +} + +static void cxusb_medion_v_stop_streaming(struct vb2_queue *q) +{ + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + unsigned int i; + + cxusb_vprintk(dvbdev, OPS, "should stop streaming\n"); + + if (WARN_ON(cxdev->stop_streaming)) + return; + + cxdev->stop_streaming = true; + + cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_stream, 0); + if (ret != 0) + dev_err(&dvbdev->udev->dev, "unable to stop stream (%d)\n", + ret); + + /* let URB completion run */ + mutex_unlock(cxdev->videodev->lock); + + for (i = 0; i < CXUSB_VIDEO_URBS; i++) + if (cxdev->streamurbs[i] != NULL) + usb_kill_urb(cxdev->streamurbs[i]); + + flush_work(&cxdev->urbwork); + + mutex_lock(cxdev->videodev->lock); + + /* free transfer buffer and URB */ + vfree(cxdev->auxbuf.buf); + + cxusb_medion_urbs_free(cxdev); + + cxusb_medion_return_buffers(cxdev, false); + + cxdev->stop_streaming = false; +} + +static void cxusub_medion_v_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *v4l2buf = to_vb2_v4l2_buffer(vb); + struct cxusb_medion_vbuffer *vbuf = + container_of(v4l2buf, struct cxusb_medion_vbuffer, vb2); + struct dvb_usb_device *dvbdev = vb2_get_drv_priv(vb->vb2_queue); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + /* cxusb_vprintk(dvbdev, OPS, "mmmm.. a fresh buffer...\n"); */ + + list_add_tail(&vbuf->list, &cxdev->buflist); +} + +static const struct vb2_ops cxdev_video_qops = { + .queue_setup = cxusb_medion_v_queue_setup, + .buf_init = cxusb_medion_v_buf_init, + .start_streaming = cxusb_medion_v_start_streaming, + .stop_streaming = cxusb_medion_v_stop_streaming, + .buf_queue = cxusub_medion_v_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish +}; + +static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; +static const __u32 radiocaps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + +static int cxusb_medion_v_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + + strscpy(cap->driver, dvbdev->udev->dev.driver->name, + sizeof(cap->driver)); + strscpy(cap->card, "Medion 95700", sizeof(cap->card)); + usb_make_path(dvbdev->udev, cap->bus_info, sizeof(cap->bus_info)); + + cap->capabilities = videocaps | radiocaps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int cxusb_medion_v_enum_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + if (f->index != 0) + return -EINVAL; + + f->pixelformat = V4L2_PIX_FMT_UYVY; + + return 0; +} + +static int cxusb_medion_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + f->fmt.pix.width = cxdev->width; + f->fmt.pix.height = cxdev->height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + f->fmt.pix.field = vb2_start_streaming_called(&cxdev->videoqueue) ? + cxdev->field_order : cxusb_medion_field_order(cxdev); + f->fmt.pix.bytesperline = cxdev->width * 2; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + + return 0; +} + +static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, + struct v4l2_format *f, + bool isset) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct v4l2_subdev_format subfmt; + u32 field; + int ret; + + if (isset && vb2_is_busy(&cxdev->videoqueue)) + return -EBUSY; + + field = vb2_start_streaming_called(&cxdev->videoqueue) ? + cxdev->field_order : cxusb_medion_field_order(cxdev); + + memset(&subfmt, 0, sizeof(subfmt)); + subfmt.which = isset ? V4L2_SUBDEV_FORMAT_ACTIVE : + V4L2_SUBDEV_FORMAT_TRY; + subfmt.format.width = f->fmt.pix.width & ~1; + subfmt.format.height = f->fmt.pix.height & ~1; + subfmt.format.code = MEDIA_BUS_FMT_FIXED; + subfmt.format.field = field; + subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; + + ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt); + if (ret != 0) + return ret; + + f->fmt.pix.width = subfmt.format.width; + f->fmt.pix.height = subfmt.format.height; + f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; + f->fmt.pix.field = field; + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + + if (isset) { + cxdev->width = f->fmt.pix.width; + cxdev->height = f->fmt.pix.height; + } + + return 0; +} + +static int cxusb_medion_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + return cxusb_medion_try_s_fmt_vid_cap(file, f, false); +} + +static int cxusb_medion_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + return cxusb_medion_try_s_fmt_vid_cap(file, f, true); +} + +static const struct { + struct v4l2_input input; + u32 inputcfg; +} cxusb_medion_inputs[] = { + { .input = { .name = "TV tuner", .type = V4L2_INPUT_TYPE_TUNER, + .tuner = 0, .std = V4L2_STD_PAL }, + .inputcfg = CX25840_COMPOSITE2, }, + + { .input = { .name = "Composite", .type = V4L2_INPUT_TYPE_CAMERA, + .std = V4L2_STD_ALL }, + .inputcfg = CX25840_COMPOSITE1, }, + + { .input = { .name = "S-Video", .type = V4L2_INPUT_TYPE_CAMERA, + .std = V4L2_STD_ALL }, + .inputcfg = CX25840_SVIDEO_LUMA3 | CX25840_SVIDEO_CHROMA4 } +}; + +#define CXUSB_INPUT_CNT ARRAY_SIZE(cxusb_medion_inputs) + +static int cxusb_medion_enum_input(struct file *file, void *fh, + struct v4l2_input *inp) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + u32 index = inp->index; + + if (index >= CXUSB_INPUT_CNT) + return -EINVAL; + + *inp = cxusb_medion_inputs[index].input; + inp->index = index; + inp->capabilities |= V4L2_IN_CAP_STD; + + if (index == cxdev->input) { + int ret; + u32 status = 0; + + ret = v4l2_subdev_call(cxdev->cx25840, video, g_input_status, + &status); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 input status query failed (%d)\n", + ret); + else + inp->status = status; + } + + return 0; +} + +static int cxusb_medion_g_input(struct file *file, void *fh, + unsigned int *i) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + *i = cxdev->input; + + return 0; +} + +static int cxusb_medion_set_norm(struct cxusb_medion_dev *cxdev, + v4l2_std_id norm) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + int ret; + + cxusb_vprintk(dvbdev, OPS, + "trying to set standard for input %u to %lx\n", + (unsigned int)cxdev->input, + (unsigned long)norm); + + /* no autodetection support */ + if (norm == V4L2_STD_UNKNOWN) + return -EINVAL; + + /* on composite or S-Video any std is acceptable */ + if (cxdev->input != 0) { + ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm); + if (ret) + return ret; + + goto ret_savenorm; + } + + /* TV tuner is only able to demodulate PAL */ + if ((norm & ~V4L2_STD_PAL) != 0) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->tda9887, video, s_std, norm); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "tda9887 norm setup failed (%d)\n", + ret); + return ret; + } + + ret = v4l2_subdev_call(cxdev->tuner, video, s_std, norm); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "tuner norm setup failed (%d)\n", + ret); + return ret; + } + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_std, norm); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "cx25840 norm setup failed (%d)\n", + ret); + return ret; + } + +ret_savenorm: + cxdev->norm = norm; + + return 0; +} + +static int cxusb_medion_s_input(struct file *file, void *fh, + unsigned int i) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + v4l2_std_id norm; + + if (i >= CXUSB_INPUT_CNT) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing, + cxusb_medion_inputs[i].inputcfg, 0, 0); + if (ret != 0) + return ret; + + cxdev->input = i; + cxdev->videodev->tvnorms = cxusb_medion_inputs[i].input.std; + + norm = cxdev->norm & cxusb_medion_inputs[i].input.std; + if (norm == 0) + norm = cxusb_medion_inputs[i].input.std; + + cxusb_medion_set_norm(cxdev, norm); + + return 0; +} + +static int cxusb_medion_g_tuner(struct file *file, void *fh, + struct v4l2_tuner *tuner) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct video_device *vdev = video_devdata(file); + int ret; + + if (tuner->index != 0) + return -EINVAL; + + if (vdev->vfl_type == VFL_TYPE_GRABBER) + tuner->type = V4L2_TUNER_ANALOG_TV; + else + tuner->type = V4L2_TUNER_RADIO; + + tuner->capability = 0; + tuner->afc = 0; + + /* + * fills: + * always: capability (static), rangelow (static), rangehigh (static) + * radio mode: afc (may fail silently), rxsubchans (static), audmode + */ + ret = v4l2_subdev_call(cxdev->tda9887, tuner, g_tuner, tuner); + if (ret != 0) + return ret; + + /* + * fills: + * always: capability (static), rangelow (static), rangehigh (static) + * radio mode: rxsubchans (always stereo), audmode, + * signal (might be wrong) + */ + ret = v4l2_subdev_call(cxdev->tuner, tuner, g_tuner, tuner); + if (ret != 0) + return ret; + + tuner->signal = 0; + + /* + * fills: TV mode: capability, rxsubchans, audmode, signal + */ + ret = v4l2_subdev_call(cxdev->cx25840, tuner, g_tuner, tuner); + if (ret != 0) + return ret; + + if (vdev->vfl_type == VFL_TYPE_GRABBER) + strscpy(tuner->name, "TV tuner", sizeof(tuner->name)); + else + strscpy(tuner->name, "Radio tuner", sizeof(tuner->name)); + + memset(tuner->reserved, 0, sizeof(tuner->reserved)); + + return 0; +} + +static int cxusb_medion_s_tuner(struct file *file, void *fh, + const struct v4l2_tuner *tuner) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct video_device *vdev = video_devdata(file); + int ret; + + if (tuner->index != 0) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_tuner, tuner); + if (ret != 0) + return ret; + + ret = v4l2_subdev_call(cxdev->tuner, tuner, s_tuner, tuner); + if (ret != 0) + return ret; + + /* + * make sure that cx25840 is in a correct TV / radio mode, + * since calls above may have changed it for tuner / IF demod + */ + if (vdev->vfl_type == VFL_TYPE_GRABBER) + v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); + else + v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); + + return v4l2_subdev_call(cxdev->cx25840, tuner, s_tuner, tuner); +} + +static int cxusb_medion_g_frequency(struct file *file, void *fh, + struct v4l2_frequency *freq) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + if (freq->tuner != 0) + return -EINVAL; + + return v4l2_subdev_call(cxdev->tuner, tuner, g_frequency, freq); +} + +static int cxusb_medion_s_frequency(struct file *file, void *fh, + const struct v4l2_frequency *freq) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + struct video_device *vdev = video_devdata(file); + int ret; + + if (freq->tuner != 0) + return -EINVAL; + + ret = v4l2_subdev_call(cxdev->tda9887, tuner, s_frequency, freq); + if (ret != 0) + return ret; + + ret = v4l2_subdev_call(cxdev->tuner, tuner, s_frequency, freq); + if (ret != 0) + return ret; + + /* + * make sure that cx25840 is in a correct TV / radio mode, + * since calls above may have changed it for tuner / IF demod + */ + if (vdev->vfl_type == VFL_TYPE_GRABBER) + v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); + else + v4l2_subdev_call(cxdev->cx25840, tuner, s_radio); + + return v4l2_subdev_call(cxdev->cx25840, tuner, s_frequency, freq); +} + +static int cxusb_medion_g_std(struct file *file, void *fh, + v4l2_std_id *norm) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + *norm = cxdev->norm; + + if (*norm == V4L2_STD_UNKNOWN) + return -ENODATA; + + return 0; +} + +static int cxusb_medion_s_std(struct file *file, void *fh, + v4l2_std_id norm) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + return cxusb_medion_set_norm(cxdev, norm); +} + +static int cxusb_medion_querystd(struct file *file, void *fh, + v4l2_std_id *norm) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + v4l2_std_id norm_mask; + int ret; + + /* + * make sure we don't have improper std bits set for the TV tuner + * (could happen when no signal was present yet after reset) + */ + if (cxdev->input == 0) + norm_mask = V4L2_STD_PAL; + else + norm_mask = V4L2_STD_ALL; + + ret = v4l2_subdev_call(cxdev->cx25840, video, querystd, norm); + if (ret != 0) { + cxusb_vprintk(dvbdev, OPS, + "cannot get detected standard for input %u\n", + (unsigned int)cxdev->input); + return ret; + } + + cxusb_vprintk(dvbdev, OPS, "input %u detected standard is %lx\n", + (unsigned int)cxdev->input, (unsigned long)*norm); + *norm &= norm_mask; + + return 0; +} + +static int cxusb_medion_log_status(struct file *file, void *fh) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + v4l2_device_call_all(&cxdev->v4l2dev, 0, core, log_status); + + return 0; +} + +static const struct v4l2_ioctl_ops cxusb_video_ioctl = { + .vidioc_querycap = cxusb_medion_v_querycap, + .vidioc_enum_fmt_vid_cap = cxusb_medion_v_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = cxusb_medion_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = cxusb_medion_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = cxusb_medion_try_fmt_vid_cap, + .vidioc_enum_input = cxusb_medion_enum_input, + .vidioc_g_input = cxusb_medion_g_input, + .vidioc_s_input = cxusb_medion_s_input, + .vidioc_g_tuner = cxusb_medion_g_tuner, + .vidioc_s_tuner = cxusb_medion_s_tuner, + .vidioc_g_frequency = cxusb_medion_g_frequency, + .vidioc_s_frequency = cxusb_medion_s_frequency, + .vidioc_g_std = cxusb_medion_g_std, + .vidioc_s_std = cxusb_medion_s_std, + .vidioc_querystd = cxusb_medion_querystd, + .vidioc_log_status = cxusb_medion_log_status, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff +}; + +static const struct v4l2_ioctl_ops cxusb_radio_ioctl = { + .vidioc_querycap = cxusb_medion_v_querycap, + .vidioc_g_tuner = cxusb_medion_g_tuner, + .vidioc_s_tuner = cxusb_medion_s_tuner, + .vidioc_g_frequency = cxusb_medion_g_frequency, + .vidioc_s_frequency = cxusb_medion_s_frequency, + .vidioc_log_status = cxusb_medion_log_status +}; + +/* + * in principle, this should be const, but s_io_pin_config is declared + * to take non-const, and gcc complains + */ +static struct v4l2_subdev_io_pin_config cxusub_medion_pin_config[] = { + { .pin = CX25840_PIN_DVALID_PRGM0, .function = CX25840_PAD_DEFAULT, + .strength = CX25840_PIN_DRIVE_MEDIUM }, + { .pin = CX25840_PIN_PLL_CLK_PRGM7, .function = CX25840_PAD_AUX_PLL }, + { .pin = CX25840_PIN_HRESET_PRGM2, .function = CX25840_PAD_ACTIVE, + .strength = CX25840_PIN_DRIVE_MEDIUM } +}; + +int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + u8 tuner_analog_msg_data[] = { 0x9c, 0x60, 0x85, 0x54 }; + struct i2c_msg tuner_analog_msg = { .addr = 0x61, .flags = 0, + .buf = tuner_analog_msg_data, + .len = + sizeof(tuner_analog_msg_data) }; + struct v4l2_subdev_format subfmt; + int ret; + + /* switch tuner to analog mode so IF demod will become accessible */ + ret = i2c_transfer(&dvbdev->i2c_adap, &tuner_analog_msg, 1); + if (ret != 1) + dev_warn(&dvbdev->udev->dev, + "tuner analog switch failed (%d)\n", ret); + + /* + * cx25840 might have lost power during mode switching so we need + * to set it again + */ + ret = v4l2_subdev_call(cxdev->cx25840, core, reset, 0); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 reset failed (%d)\n", ret); + + ret = v4l2_subdev_call(cxdev->cx25840, video, s_routing, + CX25840_COMPOSITE1, 0, 0); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 initial input setting failed (%d)\n", ret); + + /* composite */ + cxdev->input = 1; + cxdev->videodev->tvnorms = V4L2_STD_ALL; + cxdev->norm = V4L2_STD_PAL; + + /* TODO: setup audio samples insertion */ + + ret = v4l2_subdev_call(cxdev->cx25840, core, s_io_pin_config, + sizeof(cxusub_medion_pin_config) / + sizeof(cxusub_medion_pin_config[0]), + cxusub_medion_pin_config); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 pin config failed (%d)\n", ret); + + /* make sure that we aren't in radio mode */ + v4l2_subdev_call(cxdev->tda9887, video, s_std, cxdev->norm); + v4l2_subdev_call(cxdev->tuner, video, s_std, cxdev->norm); + v4l2_subdev_call(cxdev->cx25840, video, s_std, cxdev->norm); + + memset(&subfmt, 0, sizeof(subfmt)); + subfmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + subfmt.format.width = cxdev->width; + subfmt.format.height = cxdev->height; + subfmt.format.code = MEDIA_BUS_FMT_FIXED; + subfmt.format.field = V4L2_FIELD_SEQ_TB; + subfmt.format.colorspace = V4L2_COLORSPACE_SMPTE170M; + + ret = v4l2_subdev_call(cxdev->cx25840, pad, set_fmt, NULL, &subfmt); + if (ret != 0) + dev_warn(&dvbdev->udev->dev, + "cx25840 format set failed (%d)\n", ret); + + if (ret == 0) { + cxdev->width = subfmt.format.width; + cxdev->height = subfmt.format.height; + } + + return 0; +} + +static int cxusb_videoradio_open(struct file *f) +{ + struct dvb_usb_device *dvbdev = video_drvdata(f); + int ret; + + /* + * no locking needed since this call only modifies analog + * state if there are no other analog handles currenly + * opened so ops done via them cannot create a conflict + */ + ret = cxusb_medion_get(dvbdev, CXUSB_OPEN_ANALOG); + if (ret != 0) + return ret; + + ret = v4l2_fh_open(f); + if (ret != 0) + goto ret_release; + + cxusb_vprintk(dvbdev, OPS, "got open\n"); + + return 0; + +ret_release: + cxusb_medion_put(dvbdev); + + return ret; +} + +static int cxusb_videoradio_release(struct file *f) +{ + struct video_device *vdev = video_devdata(f); + struct dvb_usb_device *dvbdev = video_drvdata(f); + int ret; + + cxusb_vprintk(dvbdev, OPS, "got release\n"); + + if (vdev->vfl_type == VFL_TYPE_GRABBER) + ret = vb2_fop_release(f); + else + ret = v4l2_fh_release(f); + + cxusb_medion_put(dvbdev); + + return ret; +} + +static const struct v4l2_file_operations cxusb_video_fops = { + .owner = THIS_MODULE, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, + .open = cxusb_videoradio_open, + .release = cxusb_videoradio_release +}; + +static const struct v4l2_file_operations cxusb_radio_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = cxusb_videoradio_open, + .release = cxusb_videoradio_release +}; + +static void cxusb_medion_v4l2_release(struct v4l2_device *v4l2_dev) +{ + struct cxusb_medion_dev *cxdev = + container_of(v4l2_dev, struct cxusb_medion_dev, v4l2dev); + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + + cxusb_vprintk(dvbdev, OPS, "v4l2 device release\n"); + + v4l2_device_unregister(&cxdev->v4l2dev); + + mutex_destroy(&cxdev->dev_lock); + + while (completion_done(&cxdev->v4l2_release)) + schedule(); + + complete(&cxdev->v4l2_release); +} + +static void cxusb_medion_videodev_release(struct video_device *vdev) +{ + struct dvb_usb_device *dvbdev = video_get_drvdata(vdev); + + cxusb_vprintk(dvbdev, OPS, "video device release\n"); + + vb2_queue_release(vdev->queue); + + video_device_release(vdev); +} + +static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + cxdev->videoqueue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + cxdev->videoqueue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | + VB2_DMABUF; + cxdev->videoqueue.ops = &cxdev_video_qops; + cxdev->videoqueue.mem_ops = &vb2_vmalloc_memops; + cxdev->videoqueue.drv_priv = dvbdev; + cxdev->videoqueue.buf_struct_size = + sizeof(struct cxusb_medion_vbuffer); + cxdev->videoqueue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + cxdev->videoqueue.min_buffers_needed = 6; + cxdev->videoqueue.lock = &cxdev->dev_lock; + + ret = vb2_queue_init(&cxdev->videoqueue); + if (ret) { + dev_err(&dvbdev->udev->dev, + "video queue init failed, ret = %d\n", ret); + return ret; + } + + cxdev->videodev = video_device_alloc(); + if (cxdev->videodev == NULL) { + dev_err(&dvbdev->udev->dev, "video device alloc failed\n"); + ret = -ENOMEM; + goto ret_qrelease; + } + + cxdev->videodev->device_caps = videocaps; + cxdev->videodev->fops = &cxusb_video_fops; + cxdev->videodev->v4l2_dev = &cxdev->v4l2dev; + cxdev->videodev->queue = &cxdev->videoqueue; + strscpy(cxdev->videodev->name, "cxusb", sizeof(cxdev->videodev->name)); + cxdev->videodev->vfl_dir = VFL_DIR_RX; + cxdev->videodev->ioctl_ops = &cxusb_video_ioctl; + cxdev->videodev->tvnorms = V4L2_STD_ALL; + cxdev->videodev->release = cxusb_medion_videodev_release; + cxdev->videodev->lock = &cxdev->dev_lock; + video_set_drvdata(cxdev->videodev, dvbdev); + + ret = video_register_device(cxdev->videodev, VFL_TYPE_GRABBER, -1); + if (ret) { + dev_err(&dvbdev->udev->dev, + "video device register failed, ret = %d\n", ret); + goto ret_vrelease; + } + + return 0; + +ret_vrelease: + video_device_release(cxdev->videodev); + +ret_qrelease: + vb2_queue_release(&cxdev->videoqueue); + + return ret; +} + +static int cxusb_medion_register_analog_radio(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + cxdev->radiodev = video_device_alloc(); + if (cxdev->radiodev == NULL) { + dev_err(&dvbdev->udev->dev, "radio device alloc failed\n"); + return -ENOMEM; + } + + cxdev->radiodev->device_caps = radiocaps; + cxdev->radiodev->fops = &cxusb_radio_fops; + cxdev->radiodev->v4l2_dev = &cxdev->v4l2dev; + strscpy(cxdev->radiodev->name, "cxusb", sizeof(cxdev->radiodev->name)); + cxdev->radiodev->vfl_dir = VFL_DIR_RX; + cxdev->radiodev->ioctl_ops = &cxusb_radio_ioctl; + cxdev->radiodev->release = video_device_release; + cxdev->radiodev->lock = &cxdev->dev_lock; + video_set_drvdata(cxdev->radiodev, dvbdev); + + ret = video_register_device(cxdev->radiodev, VFL_TYPE_RADIO, -1); + if (ret) { + dev_err(&dvbdev->udev->dev, + "radio device register failed, ret = %d\n", ret); + video_device_release(cxdev->radiodev); + return ret; + } + + return 0; +} + +static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + struct tuner_setup tun_setup; + + /* attach cx25840 capture chip */ + cxdev->cx25840 = v4l2_i2c_new_subdev(&cxdev->v4l2dev, + &dvbdev->i2c_adap, + "cx25840", 0x44, NULL); + if (cxdev->cx25840 == NULL) { + dev_err(&dvbdev->udev->dev, "cx25840 not found\n"); + return -ENODEV; + } + + /* + * Initialize cx25840 chip by calling its subdevice init core op. + * + * This switches it into the generic mode that disables some of + * ivtv-related hacks in the cx25840 driver while allowing setting + * of the chip video output configuration (passed in the call below + * as the last argument). + */ + ret = v4l2_subdev_call(cxdev->cx25840, core, init, + CX25840_VCONFIG_FMT_BT656 | + CX25840_VCONFIG_RES_8BIT | + CX25840_VCONFIG_VBIRAW_DISABLED | + CX25840_VCONFIG_ANCDATA_DISABLED | + CX25840_VCONFIG_ACTIVE_COMPOSITE | + CX25840_VCONFIG_VALID_ANDACTIVE | + CX25840_VCONFIG_HRESETW_NORMAL | + CX25840_VCONFIG_CLKGATE_NONE | + CX25840_VCONFIG_DCMODE_DWORDS); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "cx25840 init failed (%d)\n", ret); + return ret; + } + + /* attach analog tuner */ + cxdev->tuner = v4l2_i2c_new_subdev(&cxdev->v4l2dev, + &dvbdev->i2c_adap, + "tuner", 0x61, NULL); + if (cxdev->tuner == NULL) { + dev_err(&dvbdev->udev->dev, "tuner not found\n"); + return -ENODEV; + } + + /* configure it */ + memset(&tun_setup, 0, sizeof(tun_setup)); + tun_setup.addr = 0x61; + tun_setup.type = TUNER_PHILIPS_FMD1216ME_MK3; + tun_setup.mode_mask = T_RADIO | T_ANALOG_TV; + v4l2_subdev_call(cxdev->tuner, tuner, s_type_addr, &tun_setup); + + /* attach IF demod */ + cxdev->tda9887 = v4l2_i2c_new_subdev(&cxdev->v4l2dev, + &dvbdev->i2c_adap, + "tuner", 0x43, NULL); + if (cxdev->tda9887 == NULL) { + dev_err(&dvbdev->udev->dev, "tda9887 not found\n"); + return -ENODEV; + } + + return 0; +} + +int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + mutex_init(&cxdev->dev_lock); + + init_completion(&cxdev->v4l2_release); + + cxdev->v4l2dev.release = cxusb_medion_v4l2_release; + + ret = v4l2_device_register(&dvbdev->udev->dev, &cxdev->v4l2dev); + if (ret != 0) { + dev_err(&dvbdev->udev->dev, + "V4L2 device registration failed, ret = %d\n", ret); + mutex_destroy(&cxdev->dev_lock); + return ret; + } + + ret = cxusb_medion_register_analog_subdevs(dvbdev); + if (ret) + goto ret_unregister; + + INIT_WORK(&cxdev->urbwork, cxusb_medion_v_complete_work); + INIT_LIST_HEAD(&cxdev->buflist); + + cxdev->width = 320; + cxdev->height = 240; + + ret = cxusb_medion_register_analog_video(dvbdev); + if (ret) + goto ret_unregister; + + ret = cxusb_medion_register_analog_radio(dvbdev); + if (ret) + goto ret_vunreg; + + return 0; + +ret_vunreg: + video_unregister_device(cxdev->videodev); + +ret_unregister: + v4l2_device_put(&cxdev->v4l2dev); + wait_for_completion(&cxdev->v4l2_release); + + return ret; +} + +void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) +{ + struct cxusb_medion_dev *cxdev = dvbdev->priv; + + cxusb_vprintk(dvbdev, OPS, "unregistering analog\n"); + + video_unregister_device(cxdev->radiodev); + video_unregister_device(cxdev->videodev); + + v4l2_device_put(&cxdev->v4l2dev); + wait_for_completion(&cxdev->v4l2_release); + + cxusb_vprintk(dvbdev, OPS, "analog unregistered\n"); +} diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 68b0543abbdc..8b754ea069bc 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -11,7 +11,6 @@ * design, so it can be reused for the "analogue-only" device (if it will * appear at all). * - * TODO: Use the cx25840-driver for the analogue part * * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@posteo.de) * Copyright (C) 2006 Michael Krufky (mkrufky@linuxtv.org) @@ -2548,5 +2547,4 @@ MODULE_AUTHOR("Michael Krufky "); MODULE_AUTHOR("Chris Pascoe "); MODULE_AUTHOR("Maciej S. Szmigiero "); MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design"); -MODULE_VERSION("1.0-alpha"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index f586d61a7bf8..9636f9575e58 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -2,12 +2,29 @@ #ifndef _DVB_USB_CXUSB_H_ #define _DVB_USB_CXUSB_H_ +#include #include +#include #include +#include +#include +#include +#include +#include +#include +#include #define DVB_USB_LOG_PREFIX "cxusb" #include "dvb-usb.h" +#define CXUSB_VIDEO_URBS (5) +#define CXUSB_VIDEO_URB_MAX_SIZE (512 * 1024) + +#define CXUSB_VIDEO_PKT_SIZE 3030 +#define CXUSB_VIDEO_MAX_FRAME_PKTS 346 +#define CXUSB_VIDEO_MAX_FRAME_SIZE (CXUSB_VIDEO_MAX_FRAME_PKTS * \ + CXUSB_VIDEO_PKT_SIZE) + /* usb commands - some of it are guesses, don't have a reference yet */ #define CMD_BLUEBIRD_GPIO_RW 0x05 @@ -32,6 +49,20 @@ #define CMD_ANALOG 0x50 #define CMD_DIGITAL 0x51 +#define CXUSB_BT656_PREAMBLE ((const u8 *)"\xff\x00\x00") + +#define CXUSB_BT656_FIELD_MASK BIT(6) +#define CXUSB_BT656_FIELD_1 0 +#define CXUSB_BT656_FIELD_2 BIT(6) + +#define CXUSB_BT656_VBI_MASK BIT(5) +#define CXUSB_BT656_VBI_ON BIT(5) +#define CXUSB_BT656_VBI_OFF 0 + +#define CXUSB_BT656_SEAV_MASK BIT(4) +#define CXUSB_BT656_SEAV_EAV BIT(4) +#define CXUSB_BT656_SEAV_SAV 0 + /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 80 @@ -54,6 +85,29 @@ enum cxusb_open_type { CXUSB_OPEN_ANALOG, CXUSB_OPEN_DIGITAL }; +struct cxusb_medion_auxbuf { + u8 *buf; + unsigned int len; + unsigned int paylen; +}; + +enum cxusb_bt656_mode { + NEW_FRAME, FIRST_FIELD, SECOND_FIELD +}; + +enum cxusb_bt656_fmode { + START_SEARCH, LINE_SAMPLES, VBI_SAMPLES +}; + +struct cxusb_bt656_params { + enum cxusb_bt656_mode mode; + enum cxusb_bt656_fmode fmode; + unsigned int pos; + unsigned int line; + unsigned int linesamples; + u8 *buf; +}; + struct cxusb_medion_dev { /* has to be the first one */ struct cxusb_state state; @@ -63,18 +117,69 @@ struct cxusb_medion_dev { enum cxusb_open_type open_type; unsigned int open_ctr; struct mutex open_lock; + +#ifdef CONFIG_DVB_USB_CXUSB_ANALOG + struct v4l2_device v4l2dev; + struct v4l2_subdev *cx25840; + struct v4l2_subdev *tuner; + struct v4l2_subdev *tda9887; + struct video_device *videodev, *radiodev; + struct mutex dev_lock; + + struct vb2_queue videoqueue; + u32 input; + bool stop_streaming; + u32 width, height; + u32 field_order; + struct cxusb_medion_auxbuf auxbuf; + v4l2_std_id norm; + + struct urb *streamurbs[CXUSB_VIDEO_URBS]; + unsigned long urbcomplete; + struct work_struct urbwork; + unsigned int nexturb; + + struct cxusb_bt656_params bt656; + struct cxusb_medion_vbuffer *vbuf; + __u32 vbuf_sequence; + + struct list_head buflist; + + struct completion v4l2_release; +#endif +}; + +struct cxusb_medion_vbuffer { + struct vb2_v4l2_buffer vb2; + struct list_head list; }; /* defines for "debug" module parameter */ #define CXUSB_DBG_RC BIT(0) #define CXUSB_DBG_I2C BIT(1) #define CXUSB_DBG_MISC BIT(2) +#define CXUSB_DBG_BT656 BIT(3) +#define CXUSB_DBG_URB BIT(4) +#define CXUSB_DBG_OPS BIT(5) +#define CXUSB_DBG_AUXB BIT(6) extern int dvb_usb_cxusb_debug; +#define cxusb_vprintk(dvbdev, lvl, ...) do { \ + struct cxusb_medion_dev *_cxdev = (dvbdev)->priv; \ + if (dvb_usb_cxusb_debug & CXUSB_DBG_##lvl) \ + v4l2_printk(KERN_DEBUG, \ + &_cxdev->v4l2dev, __VA_ARGS__); \ + } while (0) + int cxusb_ctrl_msg(struct dvb_usb_device *d, u8 cmd, const u8 *wbuf, int wlen, u8 *rbuf, int rlen); +#ifdef CONFIG_DVB_USB_CXUSB_ANALOG +int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev); +int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev); +void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev); +#else static inline int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) { return -EINVAL; @@ -88,6 +193,7 @@ static inline int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev) static inline void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev) { } +#endif int cxusb_medion_get(struct dvb_usb_device *dvbdev, enum cxusb_open_type open_type); -- cgit v1.2.3-59-g8ed1b From ead14a70754f8d7f5dbcb0553c7f11eb0fc4a6ac Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Mon, 29 Apr 2019 12:16:59 -0400 Subject: media: cxusb: add raw mode support for Medion MD95700 This adds raw (unprocessed) BT.656 stream capturing support for the analog part of Medion 95700. It can be enabled by setting CXUSB_EXTENDEDMODE_CAPTURE_RAW flag in parm.capture.extendedmode passed to VIDIOC_S_PARM. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb-analog.c | 190 +++++++++++++++++++++++++------ drivers/media/usb/dvb-usb/cxusb.h | 4 + drivers/media/v4l2-core/v4l2-ioctl.c | 3 +- 3 files changed, 163 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index 8df6c33bbbb1..68e0973caed5 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -44,7 +44,9 @@ static int cxusb_medion_v_queue_setup(struct vb2_queue *q, { struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); struct cxusb_medion_dev *cxdev = dvbdev->priv; - unsigned int size = cxdev->width * cxdev->height * 2; + unsigned int size = cxdev->raw_mode ? + CXUSB_VIDEO_MAX_FRAME_SIZE : + cxdev->width * cxdev->height * 2; if (*num_planes > 0) { if (*num_planes != 1) @@ -67,8 +69,13 @@ static int cxusb_medion_v_buf_init(struct vb2_buffer *vb) cxusb_vprintk(dvbdev, OPS, "buffer init\n"); - if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2) - return -ENOMEM; + if (cxdev->raw_mode) { + if (vb2_plane_size(vb, 0) < CXUSB_VIDEO_MAX_FRAME_SIZE) + return -ENOMEM; + } else { + if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2) + return -ENOMEM; + } cxusb_vprintk(dvbdev, OPS, "buffer OK\n"); @@ -442,6 +449,45 @@ static bool cxusb_medion_copy_field(struct dvb_usb_device *dvbdev, return true; } +static void cxusb_medion_v_process_urb_raw(struct cxusb_medion_dev *cxdev, + struct urb *urb) +{ + struct dvb_usb_device *dvbdev = cxdev->dvbdev; + u8 *buf; + struct cxusb_medion_vbuffer *vbuf; + int i; + unsigned long len; + + if (list_empty(&cxdev->buflist)) { + dev_warn(&dvbdev->udev->dev, "no free buffers\n"); + cxdev->vbuf_sequence++; + return; + } + + vbuf = list_first_entry(&cxdev->buflist, struct cxusb_medion_vbuffer, + list); + list_del(&vbuf->list); + + vbuf->vb2.field = V4L2_FIELD_NONE; + vbuf->vb2.sequence = cxdev->vbuf_sequence++; + vbuf->vb2.vb2_buf.timestamp = ktime_get_ns(); + + buf = vb2_plane_vaddr(&vbuf->vb2.vb2_buf, 0); + + for (i = 0, len = 0; i < urb->number_of_packets; i++) { + memcpy(buf, urb->transfer_buffer + + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + + buf += urb->iso_frame_desc[i].actual_length; + len += urb->iso_frame_desc[i].actual_length; + } + + vb2_set_plane_payload(&vbuf->vb2.vb2_buf, 0, len); + + vb2_buffer_done(&vbuf->vb2.vb2_buf, VB2_BUF_STATE_DONE); +} + static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, bool reset) { @@ -563,22 +609,26 @@ static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, len); if (len > 0) { - cxusb_vprintk(dvbdev, URB, "appending URB\n"); - - /* - * append new data to auxbuf while - * overwriting old data if necessary - * - * if any overwrite happens then we can no - * longer rely on consistency of the whole - * data so let's start again the current - * auxbuf frame assembling process from - * the beginning - */ - *auxbuf_reset = - !cxusb_auxbuf_append_urb(dvbdev, - &cxdev->auxbuf, - urb); + if (cxdev->raw_mode) + cxusb_medion_v_process_urb_raw(cxdev, urb); + else { + cxusb_vprintk(dvbdev, URB, "appending URB\n"); + + /* + * append new data to auxbuf while + * overwriting old data if necessary + * + * if any overwrite happens then we can no + * longer rely on consistency of the whole + * data so let's start again the current + * auxbuf frame assembling process from + * the beginning + */ + *auxbuf_reset = + !cxusb_auxbuf_append_urb(dvbdev, + &cxdev->auxbuf, + urb); + } } } @@ -613,7 +663,8 @@ static void cxusb_medion_v_complete_work(struct work_struct *work) reschedule = cxusb_medion_v_complete_handle_urb(cxdev, &auxbuf_reset); - if (cxusb_medion_v_process_auxbuf(cxdev, auxbuf_reset)) + if (!cxdev->raw_mode && cxusb_medion_v_process_auxbuf(cxdev, + auxbuf_reset)) /* reschedule us until auxbuf no longer can produce any frame */ reschedule = true; @@ -802,9 +853,13 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, goto ret_unstream_cx; } - ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); - if (ret != 0) - goto ret_unstream_md; + if (cxdev->raw_mode) + npackets = CXUSB_VIDEO_MAX_FRAME_PKTS; + else { + ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); + if (ret != 0) + goto ret_unstream_md; + } for (i = 0; i < CXUSB_VIDEO_URBS; i++) { int framen; @@ -860,9 +915,11 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, cxdev->nexturb = 0; cxdev->vbuf_sequence = 0; - cxdev->vbuf = NULL; - cxdev->bt656.mode = NEW_FRAME; - cxdev->bt656.buf = NULL; + if (!cxdev->raw_mode) { + cxdev->vbuf = NULL; + cxdev->bt656.mode = NEW_FRAME; + cxdev->bt656.buf = NULL; + } for (i = 0; i < CXUSB_VIDEO_URBS; i++) if (cxdev->streamurbs[i] != NULL) { @@ -880,7 +937,8 @@ ret_freeu: cxusb_medion_urbs_free(cxdev); ret_freeab: - vfree(cxdev->auxbuf.buf); + if (!cxdev->raw_mode) + vfree(cxdev->auxbuf.buf); ret_unstream_md: cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); @@ -927,7 +985,8 @@ static void cxusb_medion_v_stop_streaming(struct vb2_queue *q) mutex_lock(cxdev->videodev->lock); /* free transfer buffer and URB */ - vfree(cxdev->auxbuf.buf); + if (!cxdev->raw_mode) + vfree(cxdev->auxbuf.buf); cxusb_medion_urbs_free(cxdev); @@ -1000,9 +1059,11 @@ static int cxusb_medion_g_fmt_vid_cap(struct file *file, void *fh, f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; f->fmt.pix.field = vb2_start_streaming_called(&cxdev->videoqueue) ? cxdev->field_order : cxusb_medion_field_order(cxdev); - f->fmt.pix.bytesperline = cxdev->width * 2; + f->fmt.pix.bytesperline = cxdev->raw_mode ? 0 : cxdev->width * 2; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + f->fmt.pix.sizeimage = + cxdev->raw_mode ? CXUSB_VIDEO_MAX_FRAME_SIZE : + f->fmt.pix.bytesperline * f->fmt.pix.height; return 0; } @@ -1040,8 +1101,10 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, f->fmt.pix.height = subfmt.format.height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; f->fmt.pix.field = field; - f->fmt.pix.bytesperline = f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; + f->fmt.pix.bytesperline = cxdev->raw_mode ? 0 : f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = + cxdev->raw_mode ? CXUSB_VIDEO_MAX_FRAME_SIZE : + f->fmt.pix.bytesperline * f->fmt.pix.height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; if (isset) { @@ -1397,6 +1460,67 @@ static int cxusb_medion_querystd(struct file *file, void *fh, return 0; } +static int cxusb_medion_g_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *param) +{ + v4l2_std_id std; + + if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + param->parm.capture.readbuffers = 2; + + if (cxusb_medion_g_std(file, fh, &std) == 0) + v4l2_video_std_frame_period(std, + ¶m->parm.capture.timeperframe); + + return 0; +} + +static int cxusb_medion_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *param) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + + ret = cxusb_medion_g_s_parm(file, fh, param); + if (ret != 0) + return ret; + + if (cxdev->raw_mode) + param->parm.capture.extendedmode |= + CXUSB_EXTENDEDMODE_CAPTURE_RAW; + + return 0; +} + +static int cxusb_medion_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *param) +{ + struct dvb_usb_device *dvbdev = video_drvdata(file); + struct cxusb_medion_dev *cxdev = dvbdev->priv; + int ret; + bool want_raw; + + ret = cxusb_medion_g_s_parm(file, fh, param); + if (ret != 0) + return ret; + + want_raw = param->parm.capture.extendedmode & + CXUSB_EXTENDEDMODE_CAPTURE_RAW; + + if (want_raw != cxdev->raw_mode) { + if (vb2_start_streaming_called(&cxdev->videoqueue) || + cxdev->stop_streaming) + return -EBUSY; + + cxdev->raw_mode = want_raw; + } + + return 0; +} + static int cxusb_medion_log_status(struct file *file, void *fh) { struct dvb_usb_device *dvbdev = video_drvdata(file); @@ -1416,6 +1540,8 @@ static const struct v4l2_ioctl_ops cxusb_video_ioctl = { .vidioc_enum_input = cxusb_medion_enum_input, .vidioc_g_input = cxusb_medion_g_input, .vidioc_s_input = cxusb_medion_s_input, + .vidioc_g_parm = cxusb_medion_g_parm, + .vidioc_s_parm = cxusb_medion_s_parm, .vidioc_g_tuner = cxusb_medion_g_tuner, .vidioc_s_tuner = cxusb_medion_s_tuner, .vidioc_g_frequency = cxusb_medion_g_frequency, diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 9636f9575e58..35e72f571a2c 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -131,6 +131,7 @@ struct cxusb_medion_dev { bool stop_streaming; u32 width, height; u32 field_order; + bool raw_mode; struct cxusb_medion_auxbuf auxbuf; v4l2_std_id norm; @@ -154,6 +155,9 @@ struct cxusb_medion_vbuffer { struct list_head list; }; +/* Capture streaming parameters extendedmode field flags */ +#define CXUSB_EXTENDEDMODE_CAPTURE_RAW 1 + /* defines for "debug" module parameter */ #define CXUSB_DBG_RC BIT(0) #define CXUSB_DBG_I2C BIT(1) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index ac87c3e37280..0b9ca5acdd35 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2023,7 +2023,7 @@ static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, if (ret) return ret; - /* Note: extendedmode is never used in drivers */ + /* Note: extendedmode is never used in output drivers */ if (V4L2_TYPE_IS_OUTPUT(p->type)) { memset(p->parm.output.reserved, 0, sizeof(p->parm.output.reserved)); @@ -2032,7 +2032,6 @@ static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, } else { memset(p->parm.capture.reserved, 0, sizeof(p->parm.capture.reserved)); - p->parm.capture.extendedmode = 0; p->parm.capture.capturemode &= V4L2_MODE_HIGHQUALITY; } return ops->vidioc_s_parm(file, fh, p); -- cgit v1.2.3-59-g8ed1b From 23e0b8c65e8e40b8b579084d80cc78130f661fe3 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 27 May 2019 08:19:22 -0400 Subject: media: coda: add decoder MPEG-4 profile and level controls The MPEG-4 decoder firmware reports profile and level indication values that can be used to update V4L2 MPEG-4 profile and level controls. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-common.c | 23 +++++++++++++++ drivers/media/platform/coda/coda-mpeg4.c | 49 +++++++++++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 5 ++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/coda/coda-mpeg4.c (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index e17875e4343c..69afa0ca3ddc 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o +coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg4.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index eb5f76d336fd..5f9aa49684f1 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1590,6 +1590,15 @@ void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, profile = coda_h264_profile(profile_idc); level = coda_h264_level(level_idc); break; + case V4L2_PIX_FMT_MPEG4: + codec_name = "MPEG-4"; + profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL; + profile_ctrl = ctx->mpeg4_profile_ctrl; + level_ctrl = ctx->mpeg4_level_ctrl; + profile = coda_mpeg4_profile(profile_idc); + level = coda_mpeg4_level(level_idc); + break; default: return; } @@ -2119,6 +2128,20 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); if (ctx->h264_level_ctrl) ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0, + V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY); + if (ctx->mpeg4_profile_ctrl) + ctx->mpeg4_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg4_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5, 0, + V4L2_MPEG_VIDEO_MPEG4_LEVEL_5); + if (ctx->mpeg4_level_ctrl) + ctx->mpeg4_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; } static int coda_ctrls_setup(struct coda_ctx *ctx) diff --git a/drivers/media/platform/coda/coda-mpeg4.c b/drivers/media/platform/coda/coda-mpeg4.c new file mode 100644 index 000000000000..c3aca763c320 --- /dev/null +++ b/drivers/media/platform/coda/coda-mpeg4.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - MPEG-4 helper functions + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + */ + +#include +#include + +#include "coda.h" + +int coda_mpeg4_profile(int profile_idc) +{ + switch (profile_idc) { + case 0: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE; + case 15: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE; + case 2: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_CORE; + case 1: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE_SCALABLE; + case 11: + return V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY; + default: + return -EINVAL; + } +} + +int coda_mpeg4_level(int level_idc) +{ + switch (level_idc) { + case 0: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_0; + case 1: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_1; + case 2: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_2; + case 3: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_3; + case 4: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_4; + case 5: + return V4L2_MPEG_VIDEO_MPEG4_LEVEL_5; + default: + return -EINVAL; + } +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 1c822dfdb3ce..d8c8b3777db8 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -217,6 +217,8 @@ struct coda_ctx { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *h264_profile_ctrl; struct v4l2_ctrl *h264_level_ctrl; + struct v4l2_ctrl *mpeg4_profile_ctrl; + struct v4l2_ctrl *mpeg4_level_ctrl; struct v4l2_fh fh; int gopcounter; int runcounter; @@ -328,6 +330,9 @@ int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, int *size, int max_size); +int coda_mpeg4_profile(int profile_idc); +int coda_mpeg4_level(int level_idc); + void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, u8 level_idc); -- cgit v1.2.3-59-g8ed1b From 5902bca94ae05316ec7feab9b84cb07ffa5c1175 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 24 Apr 2019 06:43:47 -0400 Subject: media: v4l2-ctrl: add MPEG-2 profile and level controls Add MPEG-2 CID definitions for profiles and levels defined in ITU-T Rec. H.262. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/v4l/ext-ctrls-codec.rst | 56 ++++++++++++++++++++++++ drivers/media/v4l2-core/v4l2-ctrls.c | 23 ++++++++++ include/uapi/linux/v4l2-controls.h | 18 ++++++++ 3 files changed, 97 insertions(+) (limited to 'drivers/media') diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst index 4a8446203085..843c93e8e7bc 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst @@ -759,6 +759,32 @@ enum v4l2_mpeg_video_h264_level - +.. _v4l2-mpeg-video-mpeg2-level: + +``V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL`` + (enum) + +enum v4l2_mpeg_video_mpeg2_level - + The level information for the MPEG2 elementary stream. Applicable to + MPEG2 codecs. Possible values are: + + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW`` + - Low Level (LL) + * - ``V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN`` + - Main Level (ML) + * - ``V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440`` + - High-1440 Level (H-14) + * - ``V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH`` + - High Level (HL) + + + .. _v4l2-mpeg-video-mpeg4-level: ``V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL`` @@ -845,6 +871,36 @@ enum v4l2_mpeg_video_h264_profile - +.. _v4l2-mpeg-video-mpeg2-profile: + +``V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE`` + (enum) + +enum v4l2_mpeg_video_mpeg2_profile - + The profile information for MPEG2. Applicable to MPEG2 codecs. + Possible values are: + + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE`` + - Simple profile (SP) + * - ``V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN`` + - Main profile (MP) + * - ``V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE`` + - SNR Scalable profile (SNR) + * - ``V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE`` + - Spatially Scalable profile (Spt) + * - ``V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH`` + - High profile (HP) + * - ``V4L2_MPEG_VIDEO_MPEG2_PROFILE_MULTIVIEW`` + - Multi-view profile (MVP) + + + .. _v4l2-mpeg-video-mpeg4-profile: ``V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE`` diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 2ffffd923265..38e80fb36d1a 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -406,6 +406,21 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Explicit", NULL, }; + static const char * const mpeg_mpeg2_level[] = { + "Low", + "Main", + "High 1440", + "High", + NULL, + }; + static const char * const mpeg2_profile[] = { + "Simple", + "Main", + "SNR Scalable", + "Spatially Scalable", + "High", + NULL, + }; static const char * const mpeg_mpeg4_level[] = { "0", "0b", @@ -622,6 +637,10 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return h264_fp_arrangement_type; case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: return h264_fmo_map_type; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + return mpeg_mpeg2_level; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + return mpeg2_profile; case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: return mpeg_mpeg4_level; case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: @@ -832,6 +851,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -1197,6 +1218,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_H264_VUI_SAR_IDC: case V4L2_CID_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE: case V4L2_CID_MPEG_VIDEO_H264_FMO_MAP_TYPE: + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_JPEG_CHROMA_SUBSAMPLING: diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 9cad9fd969e3..a2669b79b294 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -409,6 +409,24 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE (V4L2_CID_MPEG_BASE+228) #define V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME (V4L2_CID_MPEG_BASE+229) +/* CIDs for the MPEG-2 Part 2 (H.262) codec */ +#define V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL (V4L2_CID_MPEG_BASE+270) +enum v4l2_mpeg_video_mpeg2_level { + V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW = 0, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN = 1, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440 = 2, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH = 3, +}; +#define V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE (V4L2_CID_MPEG_BASE+271) +enum v4l2_mpeg_video_mpeg2_profile { + V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE = 0, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN = 1, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE = 2, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE = 3, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH = 4, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_MULTIVIEW = 5, +}; + /* CIDs for the FWHT codec as used by the vicodec driver. */ #define V4L2_CID_FWHT_I_FRAME_QP (V4L2_CID_MPEG_BASE + 290) #define V4L2_CID_FWHT_P_FRAME_QP (V4L2_CID_MPEG_BASE + 291) -- cgit v1.2.3-59-g8ed1b From 8a8621ba0135f47c7d65b413d1cb9141b9422c96 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 27 May 2019 08:20:11 -0400 Subject: media: coda: add decoder MPEG-2 profile and level controls The MPEG-2 decoder firmware reports profile and level indication that can be used to set V4L2 MPEG-2 profile and level controls Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-common.c | 25 ++++++++++++++++++ drivers/media/platform/coda/coda-mpeg2.c | 44 +++++++++++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 6 +++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/coda/coda-mpeg2.c (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 69afa0ca3ddc..54e9a73a92ab 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg4.o coda-jpeg.o +coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 5f9aa49684f1..8164512464a6 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1590,6 +1590,15 @@ void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, profile = coda_h264_profile(profile_idc); level = coda_h264_level(level_idc); break; + case V4L2_PIX_FMT_MPEG2: + codec_name = "MPEG-2"; + profile_cid = V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE; + level_cid = V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL; + profile_ctrl = ctx->mpeg2_profile_ctrl; + level_ctrl = ctx->mpeg2_level_ctrl; + profile = coda_mpeg2_profile(profile_idc); + level = coda_mpeg2_level(level_idc); + break; case V4L2_PIX_FMT_MPEG4: codec_name = "MPEG-4"; profile_cid = V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE; @@ -1949,6 +1958,8 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: ctx->params.mpeg4_inter_qp = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: + case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE: case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL: /* nothing to do, these are fixed */ @@ -2129,6 +2140,20 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) if (ctx->h264_level_ctrl) ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctx->mpeg2_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH, 0, + V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH); + if (ctx->mpeg2_profile_ctrl) + ctx->mpeg2_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctx->mpeg2_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH, 0, + V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH); + if (ctx->mpeg2_level_ctrl) + ctx->mpeg2_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + ctx->mpeg4_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_CODING_EFFICIENCY, 0, diff --git a/drivers/media/platform/coda/coda-mpeg2.c b/drivers/media/platform/coda/coda-mpeg2.c new file mode 100644 index 000000000000..73e50dabce19 --- /dev/null +++ b/drivers/media/platform/coda/coda-mpeg2.c @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Coda multi-standard codec IP - MPEG-2 helper functions + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + */ + +#include +#include +#include "coda.h" + +int coda_mpeg2_profile(int profile_idc) +{ + switch (profile_idc) { + case 5: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE; + case 4: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN; + case 3: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE; + case 2: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE; + case 1: + return V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH; + default: + return -EINVAL; + } +} + +int coda_mpeg2_level(int level_idc) +{ + switch (level_idc) { + case 10: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW; + case 8: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN; + case 6: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440; + case 4: + return V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH; + default: + return -EINVAL; + } +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index d8c8b3777db8..5c1a105ffdd2 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -122,6 +122,8 @@ struct coda_params { s8 h264_chroma_qp_index_offset; u8 h264_profile_idc; u8 h264_level_idc; + u8 mpeg2_profile_idc; + u8 mpeg2_level_idc; u8 mpeg4_intra_qp; u8 mpeg4_inter_qp; u8 gop_size; @@ -217,6 +219,8 @@ struct coda_ctx { struct v4l2_ctrl_handler ctrls; struct v4l2_ctrl *h264_profile_ctrl; struct v4l2_ctrl *h264_level_ctrl; + struct v4l2_ctrl *mpeg2_profile_ctrl; + struct v4l2_ctrl *mpeg2_level_ctrl; struct v4l2_ctrl *mpeg4_profile_ctrl; struct v4l2_ctrl *mpeg4_level_ctrl; struct v4l2_fh fh; @@ -330,6 +334,8 @@ int coda_sps_parse_profile(struct coda_ctx *ctx, struct vb2_buffer *vb); int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, int *size, int max_size); +int coda_mpeg2_profile(int profile_idc); +int coda_mpeg2_level(int level_idc); int coda_mpeg4_profile(int profile_idc); int coda_mpeg4_level(int level_idc); -- cgit v1.2.3-59-g8ed1b From 7edd18b64a16722a2059c2334657de01be810806 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:33 -0400 Subject: media: coda: add lockdep asserts coda_command_sync, coda_hw_reset, and __coda_start_decoding all expect to be called under the coda_mutex device lock. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index a5b2891392b8..fd8c66a62099 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -102,6 +102,8 @@ static int coda_command_sync(struct coda_ctx *ctx, int cmd) struct coda_dev *dev = ctx->dev; int ret; + lockdep_assert_held(&dev->coda_mutex); + coda_command_async(ctx, cmd); ret = coda_wait_timeout(dev); trace_coda_bit_done(ctx); @@ -116,6 +118,8 @@ int coda_hw_reset(struct coda_ctx *ctx) unsigned int idx; int ret; + lockdep_assert_held(&dev->coda_mutex); + if (!dev->rstc) return -ENOENT; @@ -1676,6 +1680,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) u32 val; int ret; + lockdep_assert_held(&dev->coda_mutex); + coda_dbg(1, ctx, "Video Data Order Adapter: %s\n", ctx->use_vdoa ? "Enabled" : "Disabled"); -- cgit v1.2.3-59-g8ed1b From b65f1e6546655569ac6c76b4d26c87470dc3f933 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Apr 2019 11:51:34 -0400 Subject: media: coda: use v4l2_m2m_buf_copy_metadata Use v4l2_m2m2_buf_copy_metadata to let BIT encoder contexts copy buffer field, timestamp, timestamp flags, and optionally timecode. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index fd8c66a62099..c2e43a680e83 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1506,12 +1506,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; } - dst_buf->vb2_buf.timestamp = src_buf->vb2_buf.timestamp; - dst_buf->field = src_buf->field; - dst_buf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->flags |= - src_buf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - dst_buf->timecode = src_buf->timecode; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); -- cgit v1.2.3-59-g8ed1b From 1f0545d3ed1df3a915546cee60b56f855962ed69 Mon Sep 17 00:00:00 2001 From: Pawel Osciak Date: Fri, 24 May 2019 05:20:28 -0400 Subject: media: uapi: Add H264 low-level decoder API compound controls. Stateless video codecs will require both the H264 metadata and slices in order to be able to decode frames. This introduces the definitions for the structures used to pass the metadata from the userspace to the kernel. [hverkuil-cisco@xs4all.nl: add space after . in ".For"] [hverkuil-cisco@xs4all.nl: sync v4l2_ctrl_h264_decode_params struct layout with header] Co-developed-by: Maxime Ripard Reviewed-by: Paul Kocialkowski Reviewed-by: Tomasz Figa Signed-off-by: Pawel Osciak Signed-off-by: Guenter Roeck Signed-off-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/v4l/biblio.rst | 9 + Documentation/media/uapi/v4l/ext-ctrls-codec.rst | 569 ++++++++++++++++++++++ Documentation/media/uapi/v4l/vidioc-queryctrl.rst | 30 ++ Documentation/media/videodev2.h.rst.exceptions | 5 + drivers/media/v4l2-core/v4l2-ctrls.c | 42 ++ include/media/v4l2-ctrls.h | 13 +- 6 files changed, 667 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/Documentation/media/uapi/v4l/biblio.rst b/Documentation/media/uapi/v4l/biblio.rst index ec33768c055e..8f4eb8823d82 100644 --- a/Documentation/media/uapi/v4l/biblio.rst +++ b/Documentation/media/uapi/v4l/biblio.rst @@ -122,6 +122,15 @@ ITU BT.1119 :author: International Telecommunication Union (http://www.itu.ch) +.. _h264: + +ITU-T Rec. H.264 Specification (04/2017 Edition) +================================================ + +:title: ITU-T Recommendation H.264 "Advanced Video Coding for Generic Audiovisual Services" + +:author: International Telecommunication Union (http://www.itu.ch) + .. _jfif: JFIF diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst index 843c93e8e7bc..d6ea2ffd65c5 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst @@ -1451,6 +1451,575 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - - Layer number +.. _v4l2-mpeg-h264: + +``V4L2_CID_MPEG_VIDEO_H264_SPS (struct)`` + Specifies the sequence parameter set (as extracted from the + bitstream) for the associated H264 slice data. This includes the + necessary parameters for configuring a stateless hardware decoding + pipeline for H264. The bitstream parameters are defined according + to :ref:`h264`, section 7.4.2.1.1 "Sequence Parameter Set Data + Semantics". For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_h264_sps + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_sps + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``profile_idc`` + - + * - __u8 + - ``constraint_set_flags`` + - See :ref:`Sequence Parameter Set Constraints Set Flags ` + * - __u8 + - ``level_idc`` + - + * - __u8 + - ``seq_parameter_set_id`` + - + * - __u8 + - ``chroma_format_idc`` + - + * - __u8 + - ``bit_depth_luma_minus8`` + - + * - __u8 + - ``bit_depth_chroma_minus8`` + - + * - __u8 + - ``log2_max_frame_num_minus4`` + - + * - __u8 + - ``pic_order_cnt_type`` + - + * - __u8 + - ``log2_max_pic_order_cnt_lsb_minus4`` + - + * - __u8 + - ``max_num_ref_frames`` + - + * - __u8 + - ``num_ref_frames_in_pic_order_cnt_cycle`` + - + * - __s32 + - ``offset_for_ref_frame[255]`` + - + * - __s32 + - ``offset_for_non_ref_pic`` + - + * - __s32 + - ``offset_for_top_to_bottom_field`` + - + * - __u16 + - ``pic_width_in_mbs_minus1`` + - + * - __u16 + - ``pic_height_in_map_units_minus1`` + - + * - __u32 + - ``flags`` + - See :ref:`Sequence Parameter Set Flags ` + +.. _h264_sps_constraints_set_flags: + +``Sequence Parameter Set Constraints Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_SPS_CONSTRAINT_SET0_FLAG`` + - 0x00000001 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET1_FLAG`` + - 0x00000002 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET2_FLAG`` + - 0x00000004 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET3_FLAG`` + - 0x00000008 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET4_FLAG`` + - 0x00000010 + - + * - ``V4L2_H264_SPS_CONSTRAINT_SET5_FLAG`` + - 0x00000020 + - + +.. _h264_sps_flags: + +``Sequence Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE`` + - 0x00000001 + - + * - ``V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS`` + - 0x00000002 + - + * - ``V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO`` + - 0x00000004 + - + * - ``V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED`` + - 0x00000008 + - + * - ``V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY`` + - 0x00000010 + - + * - ``V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD`` + - 0x00000020 + - + * - ``V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE`` + - 0x00000040 + - + +``V4L2_CID_MPEG_VIDEO_H264_PPS (struct)`` + Specifies the picture parameter set (as extracted from the + bitstream) for the associated H264 slice data. This includes the + necessary parameters for configuring a stateless hardware decoding + pipeline for H264. The bitstream parameters are defined according + to :ref:`h264`, section 7.4.2.2 "Picture Parameter Set RBSP + Semantics". For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_h264_pps + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_pps + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``pic_parameter_set_id`` + - + * - __u8 + - ``seq_parameter_set_id`` + - + * - __u8 + - ``num_slice_groups_minus1`` + - + * - __u8 + - ``num_ref_idx_l0_default_active_minus1`` + - + * - __u8 + - ``num_ref_idx_l1_default_active_minus1`` + - + * - __u8 + - ``weighted_bipred_idc`` + - + * - __s8 + - ``pic_init_qp_minus26`` + - + * - __s8 + - ``pic_init_qs_minus26`` + - + * - __s8 + - ``chroma_qp_index_offset`` + - + * - __s8 + - ``second_chroma_qp_index_offset`` + - + * - __u16 + - ``flags`` + - See :ref:`Picture Parameter Set Flags ` + +.. _h264_pps_flags: + +``Picture Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE`` + - 0x00000001 + - + * - ``V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT`` + - 0x00000002 + - + * - ``V4L2_H264_PPS_FLAG_WEIGHTED_PRED`` + - 0x00000004 + - + * - ``V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT`` + - 0x00000008 + - + * - ``V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED`` + - 0x00000010 + - + * - ``V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT`` + - 0x00000020 + - + * - ``V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE`` + - 0x00000040 + - + * - ``V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT`` + - 0x00000080 + - + +``V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (struct)`` + Specifies the scaling matrix (as extracted from the bitstream) for + the associated H264 slice data. The bitstream parameters are + defined according to :ref:`h264`, section 7.4.2.1.1.1 "Scaling + List Semantics". For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_h264_scaling_matrix + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_scaling_matrix + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u8 + - ``scaling_list_4x4[6][16]`` + - + * - __u8 + - ``scaling_list_8x8[6][64]`` + - + +``V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (struct)`` + Specifies the slice parameters (as extracted from the bitstream) + for the associated H264 slice data. This includes the necessary + parameters for configuring a stateless hardware decoding pipeline + for H264. The bitstream parameters are defined according to + :ref:`h264`, section 7.4.3 "Slice Header Semantics". For further + documentation, refer to the above specification, unless there is + an explicit comment stating otherwise. + + .. note:: + + This compound control is not yet part of the public kernel API + and it is expected to change. + + This structure is expected to be passed as an array, with one + entry for each slice included in the bitstream buffer. + +.. c:type:: v4l2_ctrl_h264_slice_params + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_slice_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u32 + - ``size`` + - + * - __u32 + - ``header_bit_size`` + - + * - __u16 + - ``first_mb_in_slice`` + - + * - __u8 + - ``slice_type`` + - + * - __u8 + - ``pic_parameter_set_id`` + - + * - __u8 + - ``colour_plane_id`` + - + * - __u8 + - ``redundant_pic_cnt`` + - + * - __u16 + - ``frame_num`` + - + * - __u16 + - ``idr_pic_id`` + - + * - __u16 + - ``pic_order_cnt_lsb`` + - + * - __s32 + - ``delta_pic_order_cnt_bottom`` + - + * - __s32 + - ``delta_pic_order_cnt0`` + - + * - __s32 + - ``delta_pic_order_cnt1`` + - + * - struct :c:type:`v4l2_h264_pred_weight_table` + - ``pred_weight_table`` + - + * - __u32 + - ``dec_ref_pic_marking_bit_size`` + - + * - __u32 + - ``pic_order_cnt_bit_size`` + - + * - __u8 + - ``cabac_init_idc`` + - + * - __s8 + - ``slice_qp_delta`` + - + * - __s8 + - ``slice_qs_delta`` + - + * - __u8 + - ``disable_deblocking_filter_idc`` + - + * - __s8 + - ``slice_alpha_c0_offset_div2`` + - + * - __s8 + - ``slice_beta_offset_div2`` + - + * - __u8 + - ``num_ref_idx_l0_active_minus1`` + - + * - __u8 + - ``num_ref_idx_l1_active_minus1`` + - + * - __u32 + - ``slice_group_change_cycle`` + - + * - __u8 + - ``ref_pic_list0[32]`` + - Reference picture list after applying the per-slice modifications + * - __u8 + - ``ref_pic_list1[32]`` + - Reference picture list after applying the per-slice modifications + * - __u32 + - ``flags`` + - See :ref:`Slice Parameter Flags ` + +.. _h264_slice_flags: + +``Slice Parameter Set Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_SLICE_FLAG_FIELD_PIC`` + - 0x00000001 + - + * - ``V4L2_H264_SLICE_FLAG_BOTTOM_FIELD`` + - 0x00000002 + - + * - ``V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED`` + - 0x00000004 + - + * - ``V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH`` + - 0x00000008 + - + +``Prediction Weight Table`` + + The bitstream parameters are defined according to :ref:`h264`, + section 7.4.3.2 "Prediction Weight Table Semantics". For further + documentation, refer to the above specification, unless there is + an explicit comment stating otherwise. + +.. c:type:: v4l2_h264_pred_weight_table + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_h264_pred_weight_table + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u16 + - ``luma_log2_weight_denom`` + - + * - __u16 + - ``chroma_log2_weight_denom`` + - + * - struct :c:type:`v4l2_h264_weight_factors` + - ``weight_factors[2]`` + - The weight factors at index 0 are the weight factors for the reference + list 0, the one at index 1 for the reference list 1. + +.. c:type:: v4l2_h264_weight_factors + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_h264_weight_factors + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __s16 + - ``luma_weight[32]`` + - + * - __s16 + - ``luma_offset[32]`` + - + * - __s16 + - ``chroma_weight[32][2]`` + - + * - __s16 + - ``chroma_offset[32][2]`` + - + +``V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (struct)`` + Specifies the decode parameters (as extracted from the bitstream) + for the associated H264 slice data. This includes the necessary + parameters for configuring a stateless hardware decoding pipeline + for H264. The bitstream parameters are defined according to + :ref:`h264`. For further documentation, refer to the above + specification, unless there is an explicit comment stating + otherwise. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_h264_decode_params + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_ctrl_h264_decode_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - struct :c:type:`v4l2_h264_dpb_entry` + - ``dpb[16]`` + - + * - __u16 + - ``num_slices`` + - Number of slices needed to decode the current frame + * - __u16 + - ``nal_ref_idc`` + - NAL reference ID value coming from the NAL Unit header + * - __u8 + - ``ref_pic_list_p0[32]`` + - Backward reference list used by P-frames in the original bitstream order + * - __u8 + - ``ref_pic_list_b0[32]`` + - Backward reference list used by B-frames in the original bitstream order + * - __u8 + - ``ref_pic_list_b1[32]`` + - Forward reference list used by B-frames in the original bitstream order + * - __s32 + - ``top_field_order_cnt`` + - Picture Order Count for the coded top field + * - __s32 + - ``bottom_field_order_cnt`` + - Picture Order Count for the coded bottom field + * - __u32 + - ``flags`` + - See :ref:`Decode Parameters Flags ` + +.. _h264_decode_params_flags: + +``Decode Parameters Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC`` + - 0x00000001 + - That picture is an IDR picture + +.. c:type:: v4l2_h264_dpb_entry + +.. cssclass:: longtable + +.. flat-table:: struct v4l2_h264_dpb_entry + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u64 + - ``reference_ts`` + - Timestamp of the V4L2 capture buffer to use as reference, used + with B-coded and P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u16 + - ``frame_num`` + - + * - __u16 + - ``pic_num`` + - + * - __s32 + - ``top_field_order_cnt`` + - + * - __s32 + - ``bottom_field_order_cnt`` + - + * - __u32 + - ``flags`` + - See :ref:`DPB Entry Flags ` + +.. _h264_dpb_flags: + +``DPB Entries Flags`` + +.. cssclass:: longtable + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - ``V4L2_H264_DPB_ENTRY_FLAG_VALID`` + - 0x00000001 + - The DPB entry is valid and should be considered + * - ``V4L2_H264_DPB_ENTRY_FLAG_ACTIVE`` + - 0x00000002 + - The DPB entry is currently being used as a reference frame + * - ``V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM`` + - 0x00000004 + - The DPB entry is a long term reference frame .. _v4l2-mpeg-mpeg2: diff --git a/Documentation/media/uapi/v4l/vidioc-queryctrl.rst b/Documentation/media/uapi/v4l/vidioc-queryctrl.rst index f824162d0ea9..dc500632095d 100644 --- a/Documentation/media/uapi/v4l/vidioc-queryctrl.rst +++ b/Documentation/media/uapi/v4l/vidioc-queryctrl.rst @@ -443,6 +443,36 @@ See also the examples in :ref:`control`. - n/a - A struct :c:type:`v4l2_ctrl_mpeg2_quantization`, containing MPEG-2 quantization matrices for stateless video decoders. + * - ``V4L2_CTRL_TYPE_H264_SPS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_h264_sps`, containing H264 + sequence parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_H264_PPS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_h264_pps`, containing H264 + picture parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_H264_SCALING_MATRIX`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_h264_scaling_matrix`, containing H264 + scaling matrices for stateless video decoders. + * - ``V4L2_CTRL_TYPE_H264_SLICE_PARAMS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_h264_slice_params`, containing H264 + slice parameters for stateless video decoders. + * - ``V4L2_CTRL_TYPE_H264_DECODE_PARAMS`` + - n/a + - n/a + - n/a + - A struct :c:type:`v4l2_ctrl_h264_decode_params`, containing H264 + decode parameters for stateless video decoders. .. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| diff --git a/Documentation/media/videodev2.h.rst.exceptions b/Documentation/media/videodev2.h.rst.exceptions index 64d348e67df9..55cbe324b9fc 100644 --- a/Documentation/media/videodev2.h.rst.exceptions +++ b/Documentation/media/videodev2.h.rst.exceptions @@ -136,6 +136,11 @@ replace symbol V4L2_CTRL_TYPE_U32 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_U8 :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS :c:type:`v4l2_ctrl_type` replace symbol V4L2_CTRL_TYPE_MPEG2_QUANTIZATION :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_H264_SPS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_H264_PPS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_H264_SCALING_MATRIX :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_H264_SLICE_PARAMS :c:type:`v4l2_ctrl_type` +replace symbol V4L2_CTRL_TYPE_H264_DECODE_PARAMS :c:type:`v4l2_ctrl_type` # V4L2 capability defines replace define V4L2_CAP_VIDEO_CAPTURE device-capabilities diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 38e80fb36d1a..1870cecad9ae 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -851,6 +851,11 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_SPS: return "H264 Sequence Parameter Set"; + case V4L2_CID_MPEG_VIDEO_H264_PPS: return "H264 Picture Parameter Set"; + case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: return "H264 Scaling Matrix"; + case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: return "H264 Slice Parameters"; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level"; case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; @@ -1337,6 +1342,21 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: *type = V4L2_CTRL_TYPE_FWHT_PARAMS; break; + case V4L2_CID_MPEG_VIDEO_H264_SPS: + *type = V4L2_CTRL_TYPE_H264_SPS; + break; + case V4L2_CID_MPEG_VIDEO_H264_PPS: + *type = V4L2_CTRL_TYPE_H264_PPS; + break; + case V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX: + *type = V4L2_CTRL_TYPE_H264_SCALING_MATRIX; + break; + case V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_SLICE_PARAMS; + break; + case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: + *type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1724,6 +1744,13 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_FWHT_PARAMS: return 0; + case V4L2_CTRL_TYPE_H264_SPS: + case V4L2_CTRL_TYPE_H264_PPS: + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + return 0; + default: return -EINVAL; } @@ -2307,6 +2334,21 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_FWHT_PARAMS: elem_size = sizeof(struct v4l2_ctrl_fwht_params); break; + case V4L2_CTRL_TYPE_H264_SPS: + elem_size = sizeof(struct v4l2_ctrl_h264_sps); + break; + case V4L2_CTRL_TYPE_H264_PPS: + elem_size = sizeof(struct v4l2_ctrl_h264_pps); + break; + case V4L2_CTRL_TYPE_H264_SCALING_MATRIX: + elem_size = sizeof(struct v4l2_ctrl_h264_scaling_matrix); + break; + case V4L2_CTRL_TYPE_H264_SLICE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_slice_params); + break; + case V4L2_CTRL_TYPE_H264_DECODE_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_h264_decode_params); + break; default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index ee026387f513..a8aede26491e 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -23,11 +23,12 @@ #include /* - * Include the mpeg2 and fwht stateless codec compound control definitions. + * Include the stateless codec compound control definitions. * This will move to the public headers once this API is fully stable. */ #include #include +#include /* forward references */ struct file; @@ -51,6 +52,11 @@ struct poll_table_struct; * @p_mpeg2_slice_params: Pointer to a MPEG2 slice parameters structure. * @p_mpeg2_quantization: Pointer to a MPEG2 quantization data structure. * @p_fwht_params: Pointer to a FWHT stateless parameters structure. + * @p_h264_sps: Pointer to a struct v4l2_ctrl_h264_sps. + * @p_h264_pps: Pointer to a struct v4l2_ctrl_h264_pps. + * @p_h264_scaling_matrix: Pointer to a struct v4l2_ctrl_h264_scaling_matrix. + * @p_h264_slice_params: Pointer to a struct v4l2_ctrl_h264_slice_params. + * @p_h264_decode_params: Pointer to a struct v4l2_ctrl_h264_decode_params. * @p: Pointer to a compound value. */ union v4l2_ctrl_ptr { @@ -63,6 +69,11 @@ union v4l2_ctrl_ptr { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_mpeg2_quantization *p_mpeg2_quantization; struct v4l2_ctrl_fwht_params *p_fwht_params; + struct v4l2_ctrl_h264_sps *p_h264_sps; + struct v4l2_ctrl_h264_pps *p_h264_pps; + struct v4l2_ctrl_h264_scaling_matrix *p_h264_scaling_matrix; + struct v4l2_ctrl_h264_slice_params *p_h264_slice_params; + struct v4l2_ctrl_h264_decode_params *p_h264_decode_params; void *p; }; -- cgit v1.2.3-59-g8ed1b From f183ec61cc2fcaab88d1ace56101224afb79d2b3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Fri, 24 May 2019 05:20:29 -0400 Subject: media: pixfmt: Add H264 Slice format The H264_SLICE_RAW format is meant to hold the parsed slice data without the start code. This will be needed by stateless decoders. Signed-off-by: Maxime Ripard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/media/h264-ctrls.h | 197 +++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 include/media/h264-ctrls.h (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 0b9ca5acdd35..0fbee3caef5d 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1325,6 +1325,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_H264: descr = "H.264"; break; case V4L2_PIX_FMT_H264_NO_SC: descr = "H.264 (No Start Codes)"; break; case V4L2_PIX_FMT_H264_MVC: descr = "H.264 MVC"; break; + case V4L2_PIX_FMT_H264_SLICE_RAW: descr = "H.264 Parsed Slice Data"; break; case V4L2_PIX_FMT_H263: descr = "H.263"; break; case V4L2_PIX_FMT_MPEG1: descr = "MPEG-1 ES"; break; case V4L2_PIX_FMT_MPEG2: descr = "MPEG-2 ES"; break; diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h new file mode 100644 index 000000000000..e1404d78d6ff --- /dev/null +++ b/include/media/h264-ctrls.h @@ -0,0 +1,197 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * These are the H.264 state controls for use with stateless H.264 + * codec drivers. + * + * It turns out that these structs are not stable yet and will undergo + * more changes. So keep them private until they are stable and ready to + * become part of the official public API. + */ + +#ifndef _H264_CTRLS_H_ +#define _H264_CTRLS_H_ + +#include + +/* Our pixel format isn't stable at the moment */ +#define V4L2_PIX_FMT_H264_SLICE_RAW v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ + +/* + * This is put insanely high to avoid conflicting with controls that + * would be added during the phase where those controls are not + * stable. It should be fixed eventually. + */ +#define V4L2_CID_MPEG_VIDEO_H264_SPS (V4L2_CID_MPEG_BASE+1000) +#define V4L2_CID_MPEG_VIDEO_H264_PPS (V4L2_CID_MPEG_BASE+1001) +#define V4L2_CID_MPEG_VIDEO_H264_SCALING_MATRIX (V4L2_CID_MPEG_BASE+1002) +#define V4L2_CID_MPEG_VIDEO_H264_SLICE_PARAMS (V4L2_CID_MPEG_BASE+1003) +#define V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS (V4L2_CID_MPEG_BASE+1004) + +/* enum v4l2_ctrl_type type values */ +#define V4L2_CTRL_TYPE_H264_SPS 0x0110 +#define V4L2_CTRL_TYPE_H264_PPS 0x0111 +#define V4L2_CTRL_TYPE_H264_SCALING_MATRIX 0x0112 +#define V4L2_CTRL_TYPE_H264_SLICE_PARAMS 0x0113 +#define V4L2_CTRL_TYPE_H264_DECODE_PARAMS 0x0114 + +#define V4L2_H264_SPS_CONSTRAINT_SET0_FLAG 0x01 +#define V4L2_H264_SPS_CONSTRAINT_SET1_FLAG 0x02 +#define V4L2_H264_SPS_CONSTRAINT_SET2_FLAG 0x04 +#define V4L2_H264_SPS_CONSTRAINT_SET3_FLAG 0x08 +#define V4L2_H264_SPS_CONSTRAINT_SET4_FLAG 0x10 +#define V4L2_H264_SPS_CONSTRAINT_SET5_FLAG 0x20 + +#define V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE 0x01 +#define V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS 0x02 +#define V4L2_H264_SPS_FLAG_DELTA_PIC_ORDER_ALWAYS_ZERO 0x04 +#define V4L2_H264_SPS_FLAG_GAPS_IN_FRAME_NUM_VALUE_ALLOWED 0x08 +#define V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY 0x10 +#define V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD 0x20 +#define V4L2_H264_SPS_FLAG_DIRECT_8X8_INFERENCE 0x40 + +struct v4l2_ctrl_h264_sps { + __u8 profile_idc; + __u8 constraint_set_flags; + __u8 level_idc; + __u8 seq_parameter_set_id; + __u8 chroma_format_idc; + __u8 bit_depth_luma_minus8; + __u8 bit_depth_chroma_minus8; + __u8 log2_max_frame_num_minus4; + __u8 pic_order_cnt_type; + __u8 log2_max_pic_order_cnt_lsb_minus4; + __u8 max_num_ref_frames; + __u8 num_ref_frames_in_pic_order_cnt_cycle; + __s32 offset_for_ref_frame[255]; + __s32 offset_for_non_ref_pic; + __s32 offset_for_top_to_bottom_field; + __u16 pic_width_in_mbs_minus1; + __u16 pic_height_in_map_units_minus1; + __u32 flags; +}; + +#define V4L2_H264_PPS_FLAG_ENTROPY_CODING_MODE 0x0001 +#define V4L2_H264_PPS_FLAG_BOTTOM_FIELD_PIC_ORDER_IN_FRAME_PRESENT 0x0002 +#define V4L2_H264_PPS_FLAG_WEIGHTED_PRED 0x0004 +#define V4L2_H264_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT 0x0008 +#define V4L2_H264_PPS_FLAG_CONSTRAINED_INTRA_PRED 0x0010 +#define V4L2_H264_PPS_FLAG_REDUNDANT_PIC_CNT_PRESENT 0x0020 +#define V4L2_H264_PPS_FLAG_TRANSFORM_8X8_MODE 0x0040 +#define V4L2_H264_PPS_FLAG_PIC_SCALING_MATRIX_PRESENT 0x0080 + +struct v4l2_ctrl_h264_pps { + __u8 pic_parameter_set_id; + __u8 seq_parameter_set_id; + __u8 num_slice_groups_minus1; + __u8 num_ref_idx_l0_default_active_minus1; + __u8 num_ref_idx_l1_default_active_minus1; + __u8 weighted_bipred_idc; + __s8 pic_init_qp_minus26; + __s8 pic_init_qs_minus26; + __s8 chroma_qp_index_offset; + __s8 second_chroma_qp_index_offset; + __u16 flags; +}; + +struct v4l2_ctrl_h264_scaling_matrix { + __u8 scaling_list_4x4[6][16]; + __u8 scaling_list_8x8[6][64]; +}; + +struct v4l2_h264_weight_factors { + __s16 luma_weight[32]; + __s16 luma_offset[32]; + __s16 chroma_weight[32][2]; + __s16 chroma_offset[32][2]; +}; + +struct v4l2_h264_pred_weight_table { + __u16 luma_log2_weight_denom; + __u16 chroma_log2_weight_denom; + struct v4l2_h264_weight_factors weight_factors[2]; +}; + +#define V4L2_H264_SLICE_TYPE_P 0 +#define V4L2_H264_SLICE_TYPE_B 1 +#define V4L2_H264_SLICE_TYPE_I 2 +#define V4L2_H264_SLICE_TYPE_SP 3 +#define V4L2_H264_SLICE_TYPE_SI 4 + +#define V4L2_H264_SLICE_FLAG_FIELD_PIC 0x01 +#define V4L2_H264_SLICE_FLAG_BOTTOM_FIELD 0x02 +#define V4L2_H264_SLICE_FLAG_DIRECT_SPATIAL_MV_PRED 0x04 +#define V4L2_H264_SLICE_FLAG_SP_FOR_SWITCH 0x08 + +struct v4l2_ctrl_h264_slice_params { + /* Size in bytes, including header */ + __u32 size; + /* Offset in bits to slice_data() from the beginning of this slice. */ + __u32 header_bit_size; + + __u16 first_mb_in_slice; + __u8 slice_type; + __u8 pic_parameter_set_id; + __u8 colour_plane_id; + __u8 redundant_pic_cnt; + __u16 frame_num; + __u16 idr_pic_id; + __u16 pic_order_cnt_lsb; + __s32 delta_pic_order_cnt_bottom; + __s32 delta_pic_order_cnt0; + __s32 delta_pic_order_cnt1; + + struct v4l2_h264_pred_weight_table pred_weight_table; + /* Size in bits of dec_ref_pic_marking() syntax element. */ + __u32 dec_ref_pic_marking_bit_size; + /* Size in bits of pic order count syntax. */ + __u32 pic_order_cnt_bit_size; + + __u8 cabac_init_idc; + __s8 slice_qp_delta; + __s8 slice_qs_delta; + __u8 disable_deblocking_filter_idc; + __s8 slice_alpha_c0_offset_div2; + __s8 slice_beta_offset_div2; + __u8 num_ref_idx_l0_active_minus1; + __u8 num_ref_idx_l1_active_minus1; + __u32 slice_group_change_cycle; + + /* + * Entries on each list are indices into + * v4l2_ctrl_h264_decode_params.dpb[]. + */ + __u8 ref_pic_list0[32]; + __u8 ref_pic_list1[32]; + + __u32 flags; +}; + +#define V4L2_H264_DPB_ENTRY_FLAG_VALID 0x01 +#define V4L2_H264_DPB_ENTRY_FLAG_ACTIVE 0x02 +#define V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM 0x04 + +struct v4l2_h264_dpb_entry { + __u64 reference_ts; + __u16 frame_num; + __u16 pic_num; + /* Note that field is indicated by v4l2_buffer.field */ + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; + __u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */ +}; + +#define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 + +struct v4l2_ctrl_h264_decode_params { + struct v4l2_h264_dpb_entry dpb[16]; + __u16 num_slices; + __u16 nal_ref_idc; + __u8 ref_pic_list_p0[32]; + __u8 ref_pic_list_b0[32]; + __u8 ref_pic_list_b1[32]; + __s32 top_field_order_cnt; + __s32 bottom_field_order_cnt; + __u32 flags; /* V4L2_H264_DECODE_PARAM_FLAG_* */ +}; + +#endif -- cgit v1.2.3-59-g8ed1b From 26989c2725a571ef74cb5ac8f9badb8de113147e Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 28 May 2019 13:11:16 -0400 Subject: media: videobuf2-v4l2: set last_buffer_dequeued in dqbuf last_buffer_dequeued was set to true in __fill_v4l2_buffer, but this is called for qbuf as well. Move it to vb2_dqbuf. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-v4l2.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index fb9ac7696fc6..40d76eb4c2fe 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -563,11 +563,6 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) b->flags |= V4L2_BUF_FLAG_REQUEST_FD; b->request_fd = vbuf->request_fd; } - - if (!q->is_output && - b->flags & V4L2_BUF_FLAG_DONE && - b->flags & V4L2_BUF_FLAG_LAST) - q->last_buffer_dequeued = true; } /* @@ -786,6 +781,11 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) ret = vb2_core_dqbuf(q, NULL, b, nonblocking); + if (!q->is_output && + b->flags & V4L2_BUF_FLAG_DONE && + b->flags & V4L2_BUF_FLAG_LAST) + q->last_buffer_dequeued = true; + /* * After calling the VIDIOC_DQBUF V4L2_BUF_FLAG_DONE must be * cleared. -- cgit v1.2.3-59-g8ed1b From 707947247e9517b94af5661b504467765edf16c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 4 Apr 2019 09:15:00 -0400 Subject: media: videobuf2-vmalloc: get_userptr: buffers are always writable In vb2_vmalloc_get_userptr() the framevector is created with the 'write' argument set to false when vb2_create_framevec() is called for OUTPUT buffers. So the pages are marked as read-only. However, userspace will write to these buffers since it will fill in the data to output. Since get_userptr is only called if the userptr of the queued buffer has changed since the last time that same buffer was queued, this will fail when the buffer contents is updated and the buffer is queued again. E.g., userspace fills buffer 1 with the output video and queues it. The first time get_userptr is called and the pages are grabbed and pinned in memory and marked read-only. The second time buffer 1 is filled with different video data and queued again. Since the userptr hasn't changed the get_userptr() callback isn't called again. Since the pages were marked as read-only the new contents isn't updated. Just always call vb2_create_framevec() with FOLL_WRITE to always allow writing to the buffers. Using USERPTR streaming with OUTPUT devices is almost never done. And when it is done it is via v4l2-compliance and a driver like vim2m. But since v4l2-compliance doesn't actually inspect the capture buffer and compare it to the original output buffer, this issue was never noticed. But the vicodec driver actually needs to parse the bitstream in the OUTPUT buffers and any errors there will be immediately noticed. So this time v4l2-compliance failed the USERPTR streaming test. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/videobuf2/videobuf2-dma-contig.c | 3 +-- drivers/media/common/videobuf2/videobuf2-dma-sg.c | 3 +-- drivers/media/common/videobuf2/videobuf2-memops.c | 9 ++------- drivers/media/common/videobuf2/videobuf2-vmalloc.c | 3 +-- include/media/videobuf2-memops.h | 3 +-- 5 files changed, 6 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c index ecbef266130b..7d77e4d30c8a 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c @@ -475,8 +475,7 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr, buf->dma_dir = dma_dir; offset = lower_32_bits(offset_in_page(vaddr)); - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || - dma_dir == DMA_BIDIRECTIONAL); + vec = vb2_create_framevec(vaddr, size); if (IS_ERR(vec)) { ret = PTR_ERR(vec); goto fail_buf; diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c index 0f06f08346ba..ed706b2a263c 100644 --- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c +++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c @@ -239,8 +239,7 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr, buf->offset = vaddr & ~PAGE_MASK; buf->size = size; buf->dma_sgt = &buf->sg_table; - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || - dma_dir == DMA_BIDIRECTIONAL); + vec = vb2_create_framevec(vaddr, size); if (IS_ERR(vec)) goto userptr_fail_pfnvec; buf->vec = vec; diff --git a/drivers/media/common/videobuf2/videobuf2-memops.c b/drivers/media/common/videobuf2/videobuf2-memops.c index c4a85be48ac2..6e9e05153f4e 100644 --- a/drivers/media/common/videobuf2/videobuf2-memops.c +++ b/drivers/media/common/videobuf2/videobuf2-memops.c @@ -26,7 +26,6 @@ * vb2_create_framevec() - map virtual addresses to pfns * @start: Virtual user address where we start mapping * @length: Length of a range to map - * @write: Should we map for writing into the area * * This function allocates and fills in a vector with pfns corresponding to * virtual address range passed in arguments. If pfns have corresponding pages, @@ -35,17 +34,13 @@ * failure. Returned vector needs to be freed via vb2_destroy_pfnvec(). */ struct frame_vector *vb2_create_framevec(unsigned long start, - unsigned long length, - bool write) + unsigned long length) { int ret; unsigned long first, last; unsigned long nr; struct frame_vector *vec; - unsigned int flags = FOLL_FORCE; - - if (write) - flags |= FOLL_WRITE; + unsigned int flags = FOLL_FORCE | FOLL_WRITE; first = start >> PAGE_SHIFT; last = (start + length - 1) >> PAGE_SHIFT; diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 1c6659f7c394..04d51ca63223 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -87,8 +87,7 @@ static void *vb2_vmalloc_get_userptr(struct device *dev, unsigned long vaddr, buf->dma_dir = dma_dir; offset = vaddr & ~PAGE_MASK; buf->size = size; - vec = vb2_create_framevec(vaddr, size, dma_dir == DMA_FROM_DEVICE || - dma_dir == DMA_BIDIRECTIONAL); + vec = vb2_create_framevec(vaddr, size); if (IS_ERR(vec)) { ret = PTR_ERR(vec); goto fail_pfnvec_create; diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h index 4b5b84f93538..cd4a46331531 100644 --- a/include/media/videobuf2-memops.h +++ b/include/media/videobuf2-memops.h @@ -34,8 +34,7 @@ struct vb2_vmarea_handler { extern const struct vm_operations_struct vb2_common_vm_ops; struct frame_vector *vb2_create_framevec(unsigned long start, - unsigned long length, - bool write); + unsigned long length); void vb2_destroy_framevec(struct frame_vector *vec); #endif -- cgit v1.2.3-59-g8ed1b From e9ad78bc0c548104bf612c20a7cfdea9b93a0059 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 May 2019 16:12:53 -0400 Subject: media: cxusb-analog: Fix some coding style issues This is a new file, so the best moment to make it to follow Kernel coding style is now. This patch was partially generated with: ./scripts/checkpatch.pl --fix-inplace --strict -f drivers/media/usb/dvb-usb/cxusb-analog.c And manually checked and adjusted to avoid any warnings. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb-analog.c | 67 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 33 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index 68e0973caed5..9b42ca71c177 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -204,7 +204,7 @@ static bool cxusb_medion_cf_refc_fld_chg(struct dvb_usb_device *dvbdev, "field %c after line %u field change\n", firstfield ? '1' : '2', bt656->line); - if (bt656->buf != NULL && remsamples > 0) { + if (bt656->buf && remsamples > 0) { memset(bt656->buf, 0, remsamples); bt656->buf += remsamples; @@ -219,7 +219,7 @@ static bool cxusb_medion_cf_refc_fld_chg(struct dvb_usb_device *dvbdev, } remlines = maxlines - bt656->line; - if (bt656->buf != NULL && remlines > 0) { + if (bt656->buf && remlines > 0) { memset(bt656->buf, 0, remlines * maxlinesamples); bt656->buf += remlines * maxlinesamples; @@ -277,7 +277,7 @@ static void cxusb_medion_cf_refc_line_smpl(struct dvb_usb_device *dvbdev, bt656->line, bt656->pos); remsamples = maxlinesamples - bt656->linesamples; - if (bt656->buf != NULL && remsamples > 0) { + if (bt656->buf && remsamples > 0) { memset(bt656->buf, 0, remsamples); bt656->buf += remsamples; @@ -313,9 +313,9 @@ static bool cxusb_medion_cf_ref_code(struct dvb_usb_device *dvbdev, unsigned int maxlinesamples, unsigned char buf[4]) { - if (bt656->fmode == START_SEARCH) + if (bt656->fmode == START_SEARCH) { cxusb_medion_cf_refc_start_sch(dvbdev, bt656, firstfield, buf); - else if (bt656->fmode == LINE_SAMPLES) { + } else if (bt656->fmode == LINE_SAMPLES) { cxusb_medion_cf_refc_line_smpl(dvbdev, bt656, firstfield, maxlinesamples, buf); return false; @@ -359,7 +359,7 @@ static void cxusb_medion_cs_line_smpl(struct cxusb_bt656_params *bt656, unsigned int maxlinesamples, unsigned char val) { - if (bt656->buf != NULL) + if (bt656->buf) *(bt656->buf++) = val; bt656->linesamples++; @@ -505,8 +505,9 @@ static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, struct cxusb_medion_vbuffer, list); list_del(&cxdev->vbuf->list); - } else + } else { dev_warn(&dvbdev->udev->dev, "no free buffers\n"); + } } if (bt656->mode == NEW_FRAME || reset) { @@ -516,7 +517,7 @@ static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, bt656->fmode = START_SEARCH; bt656->line = 0; - if (cxdev->vbuf != NULL) { + if (cxdev->vbuf) { cxdev->vbuf->vb2.vb2_buf.timestamp = ktime_get_ns(); bt656->buf = vb2_plane_vaddr(&cxdev->vbuf->vb2.vb2_buf, 0); @@ -550,7 +551,7 @@ static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, bt656->mode = NEW_FRAME; - if (cxdev->vbuf != NULL) { + if (cxdev->vbuf) { vb2_set_plane_payload(&cxdev->vbuf->vb2.vb2_buf, 0, cxdev->width * cxdev->height * 2); @@ -593,7 +594,7 @@ static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, cxdev->nexturb++; cxdev->nexturb %= CXUSB_VIDEO_URBS; urb = cxdev->streamurbs[cxdev->nexturb]; - } while (urb == NULL); + } while (!urb); urb = cxdev->streamurbs[urbn]; cxusb_vprintk(dvbdev, URB, "URB %u status = %d\n", urbn, urb->status); @@ -609,9 +610,9 @@ static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, len); if (len > 0) { - if (cxdev->raw_mode) + if (cxdev->raw_mode) { cxusb_medion_v_process_urb_raw(cxdev, urb); - else { + } else { cxusb_vprintk(dvbdev, URB, "appending URB\n"); /* @@ -704,7 +705,7 @@ static void cxusb_medion_urbs_free(struct cxusb_medion_dev *cxdev) unsigned int i; for (i = 0; i < CXUSB_VIDEO_URBS; i++) - if (cxdev->streamurbs[i] != NULL) { + if (cxdev->streamurbs[i]) { kfree(cxdev->streamurbs[i]->transfer_buffer); usb_free_urb(cxdev->streamurbs[i]); cxdev->streamurbs[i] = NULL; @@ -724,7 +725,7 @@ static void cxusb_medion_return_buffers(struct cxusb_medion_dev *cxdev, VB2_BUF_STATE_ERROR); } - if (cxdev->vbuf != NULL) { + if (cxdev->vbuf) { vb2_buffer_done(&cxdev->vbuf->vb2.vb2_buf, requeue ? VB2_BUF_STATE_QUEUED : VB2_BUF_STATE_ERROR); @@ -763,7 +764,7 @@ static int cxusb_medion_v_ss_auxbuf_alloc(struct cxusb_medion_dev *cxdev, auxbuflen = framelen + urblen; buf = vmalloc(auxbuflen); - if (buf == NULL) + if (!buf) return -ENOMEM; cxusb_auxbuf_init(dvbdev, &cxdev->auxbuf, buf, auxbuflen); @@ -804,11 +805,11 @@ static u32 cxusb_medion_field_order(struct cxusb_medion_dev *cxdev) return field; ret = v4l2_subdev_call(cxdev->cx25840, video, g_std, &norm); - if (ret != 0) + if (ret != 0) { cxusb_vprintk(dvbdev, OPS, "cannot get current standard for input %u\n", (unsigned int)cxdev->input); - else { + } else { field = cxusb_medion_norm2field_order(norm); if (field != V4L2_FIELD_NONE) return field; @@ -853,9 +854,9 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, goto ret_unstream_cx; } - if (cxdev->raw_mode) + if (cxdev->raw_mode) { npackets = CXUSB_VIDEO_MAX_FRAME_PKTS; - else { + } else { ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); if (ret != 0) goto ret_unstream_md; @@ -873,16 +874,16 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, */ streambuf = kmalloc(npackets * CXUSB_VIDEO_PKT_SIZE, GFP_KERNEL); - if (streambuf == NULL) { + if (!streambuf) { if (i < 2) { ret = -ENOMEM; goto ret_freeab; - } else - break; + } + break; } surb = usb_alloc_urb(npackets, GFP_KERNEL); - if (surb == NULL) { + if (!surb) { kfree(streambuf); ret = -ENOMEM; goto ret_freeu; @@ -922,9 +923,9 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, } for (i = 0; i < CXUSB_VIDEO_URBS; i++) - if (cxdev->streamurbs[i] != NULL) { + if (cxdev->streamurbs[i]) { ret = usb_submit_urb(cxdev->streamurbs[i], - GFP_KERNEL); + GFP_KERNEL); if (ret != 0) dev_err(&dvbdev->udev->dev, "URB %d submission failed (%d)\n", i, @@ -977,7 +978,7 @@ static void cxusb_medion_v_stop_streaming(struct vb2_queue *q) mutex_unlock(cxdev->videodev->lock); for (i = 0; i < CXUSB_VIDEO_URBS; i++) - if (cxdev->streamurbs[i] != NULL) + if (cxdev->streamurbs[i]) usb_kill_urb(cxdev->streamurbs[i]); flush_work(&cxdev->urbwork); @@ -1626,7 +1627,7 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) cxusub_medion_pin_config); if (ret != 0) dev_warn(&dvbdev->udev->dev, - "cx25840 pin config failed (%d)\n", ret); + "cx25840 pin config failed (%d)\n", ret); /* make sure that we aren't in radio mode */ v4l2_subdev_call(cxdev->tda9887, video, s_std, cxdev->norm); @@ -1771,7 +1772,7 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev) } cxdev->videodev = video_device_alloc(); - if (cxdev->videodev == NULL) { + if (!cxdev->videodev) { dev_err(&dvbdev->udev->dev, "video device alloc failed\n"); ret = -ENOMEM; goto ret_qrelease; @@ -1813,7 +1814,7 @@ static int cxusb_medion_register_analog_radio(struct dvb_usb_device *dvbdev) int ret; cxdev->radiodev = video_device_alloc(); - if (cxdev->radiodev == NULL) { + if (!cxdev->radiodev) { dev_err(&dvbdev->udev->dev, "radio device alloc failed\n"); return -ENOMEM; } @@ -1849,7 +1850,7 @@ static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) cxdev->cx25840 = v4l2_i2c_new_subdev(&cxdev->v4l2dev, &dvbdev->i2c_adap, "cx25840", 0x44, NULL); - if (cxdev->cx25840 == NULL) { + if (!cxdev->cx25840) { dev_err(&dvbdev->udev->dev, "cx25840 not found\n"); return -ENODEV; } @@ -1874,7 +1875,7 @@ static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) CX25840_VCONFIG_DCMODE_DWORDS); if (ret != 0) { dev_err(&dvbdev->udev->dev, - "cx25840 init failed (%d)\n", ret); + "cx25840 init failed (%d)\n", ret); return ret; } @@ -1882,7 +1883,7 @@ static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) cxdev->tuner = v4l2_i2c_new_subdev(&cxdev->v4l2dev, &dvbdev->i2c_adap, "tuner", 0x61, NULL); - if (cxdev->tuner == NULL) { + if (!cxdev->tuner) { dev_err(&dvbdev->udev->dev, "tuner not found\n"); return -ENODEV; } @@ -1898,7 +1899,7 @@ static int cxusb_medion_register_analog_subdevs(struct dvb_usb_device *dvbdev) cxdev->tda9887 = v4l2_i2c_new_subdev(&cxdev->v4l2dev, &dvbdev->i2c_adap, "tuner", 0x43, NULL); - if (cxdev->tda9887 == NULL) { + if (!cxdev->tda9887) { dev_err(&dvbdev->udev->dev, "tda9887 not found\n"); return -ENODEV; } -- cgit v1.2.3-59-g8ed1b From 63f9fa925e021a832d706a7781e7b9c750909368 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 May 2019 17:42:57 -0400 Subject: media: cxusb: fix several coding style issues As this driver had a major change, let's take the opportunity and do some coding style cleanup, in order to make it compliant with Kernel's style. This patch was partially done with the help of two tools: ./scripts/checkpatch.pl --fix-inplace --strict astyle --indent=tab=8 --style=linux But manually adjusted in order to fit our style. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 365 ++++++++++++++++++++++---------------- drivers/media/usb/dvb-usb/cxusb.h | 8 +- 2 files changed, 217 insertions(+), 156 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 8b754ea069bc..cc61315b675c 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -136,7 +136,7 @@ static void cxusb_gpio_tuner(struct dvb_usb_device *d, int onoff) } static int cxusb_bluebird_gpio_rw(struct dvb_usb_device *d, u8 changemask, - u8 newval) + u8 newval) { u8 o[2], gpio_state; int rc; @@ -164,7 +164,7 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) } static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, - u8 addr, int onoff) + u8 addr, int onoff) { u8 o[2] = {addr, onoff}; u8 i; @@ -174,12 +174,12 @@ static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, if (rc < 0) return rc; + if (i == 0x01) return 0; - else { - deb_info("gpio_write failed.\n"); - return -EIO; - } + + deb_info("gpio_write failed.\n"); + return -EIO; } /* I2C */ @@ -194,7 +194,6 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], return -EAGAIN; for (i = 0; i < num; i++) { - if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_MEDION) switch (msg[i].addr) { case 0x63: @@ -220,13 +219,13 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], obuf[2] = msg[i].addr; if (cxusb_ctrl_msg(d, CMD_I2C_READ, obuf, 3, - ibuf, 1+msg[i].len) < 0) { + ibuf, 1 + msg[i].len) < 0) { warn("i2c read failed"); break; } memcpy(msg[i].buf, &ibuf[1], msg[i].len); - } else if (i+1 < num && (msg[i+1].flags & I2C_M_RD) && - msg[i].addr == msg[i+1].addr) { + } else if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD) && + msg[i].addr == msg[i + 1].addr) { /* write to then read from same address */ u8 obuf[MAX_XFER_SIZE], ibuf[MAX_XFER_SIZE]; @@ -243,19 +242,19 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], goto unlock; } obuf[0] = msg[i].len; - obuf[1] = msg[i+1].len; + obuf[1] = msg[i + 1].len; obuf[2] = msg[i].addr; memcpy(&obuf[3], msg[i].buf, msg[i].len); if (cxusb_ctrl_msg(d, CMD_I2C_READ, - obuf, 3+msg[i].len, - ibuf, 1+msg[i+1].len) < 0) + obuf, 3 + msg[i].len, + ibuf, 1 + msg[i + 1].len) < 0) break; if (ibuf[0] != 0x08) deb_i2c("i2c read may have failed\n"); - memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len); + memcpy(msg[i + 1].buf, &ibuf[1], msg[i + 1].len); i++; } else { @@ -273,7 +272,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], memcpy(&obuf[2], msg[i].buf, msg[i].len); if (cxusb_ctrl_msg(d, CMD_I2C_WRITE, obuf, - 2+msg[i].len, &ibuf,1) < 0) + 2 + msg[i].len, &ibuf, 1) < 0) break; if (ibuf != 0x08) deb_i2c("i2c write may have failed\n"); @@ -314,8 +313,7 @@ static int _cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff) { - bool is_medion = d->props.devices[0].warm_ids[0] == - &cxusb_table[MEDION_MD95700]; + bool is_medion = d->props.devices[0].warm_ids[0] == &cxusb_table[MEDION_MD95700]; int ret; if (is_medion && !onoff) { @@ -345,17 +343,23 @@ ret_unlock: static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; + if (!onoff) return cxusb_ctrl_msg(d, CMD_POWER_OFF, NULL, 0, NULL, 0); if (d->state == DVB_USB_STATE_INIT && usb_set_interface(d->udev, 0, 0) < 0) err("set interface failed"); - do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && - !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + do { + /* Nothing */ + } while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && + !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); + if (!ret) { - /* FIXME: We don't know why, but we need to configure the - * lgdt3303 with the register settings below on resume */ + /* + * FIXME: We don't know why, but we need to configure the + * lgdt3303 with the register settings below on resume + */ int i; u8 buf; static const u8 bufs[] = { @@ -373,7 +377,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) msleep(20); for (i = 0; i < ARRAY_SIZE(bufs); i += 4 / sizeof(u8)) { ret = cxusb_ctrl_msg(d, CMD_I2C_WRITE, - bufs+i, 4, &buf, 1); + bufs + i, 4, &buf, 1); if (ret) break; if (buf != 0x8) @@ -386,6 +390,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff) { u8 b = 0; + if (onoff) return cxusb_ctrl_msg(d, CMD_POWER_ON, &b, 1, NULL, 0); else @@ -407,6 +412,7 @@ static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; u8 b; + ret = cxusb_power_ctrl(d, onoff); if (!onoff) return ret; @@ -454,7 +460,7 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) } static int cxusb_read_status(struct dvb_frontend *fe, - enum fe_status *status) + enum fe_status *status) { struct dvb_usb_adapter *adap = (struct dvb_usb_adapter *)fe->dvb->priv; struct cxusb_state *state = (struct cxusb_state *)adap->dev->priv; @@ -487,8 +493,8 @@ static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) return; while (1) { if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, ep), - junk, junk_len, &rd_count, timeout) < 0) + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) break; if (!rd_count) break; @@ -510,8 +516,8 @@ static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) return; while (1) { if (usb_bulk_msg(d->udev, - usb_rcvbulkpipe(d->udev, p->endpoint), - junk, junk_len, &rd_count, timeout) < 0) + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) break; if (!rd_count) break; @@ -519,17 +525,18 @@ static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) kfree(junk); } -static int cxusb_d680_dmb_streaming_ctrl( - struct dvb_usb_adapter *adap, int onoff) +static int cxusb_d680_dmb_streaming_ctrl(struct dvb_usb_adapter *adap, + int onoff) { if (onoff) { u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, - buf, sizeof(buf), NULL, 0); + buf, sizeof(buf), NULL, 0); } else { int ret = cxusb_ctrl_msg(adap->dev, - CMD_STREAMING_OFF, NULL, 0, NULL, 0); + CMD_STREAMING_OFF, NULL, 0, NULL, 0); return ret; } } @@ -549,8 +556,12 @@ static int cxusb_rc_query(struct dvb_usb_device *d) static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d) { u8 ircode[4]; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; + struct i2c_msg msg = { + .addr = 0x6b, + .flags = I2C_M_RD, + .buf = ircode, + .len = 4 + }; if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1) return 0; @@ -574,13 +585,13 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d) return 0; } -static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) +static int cxusb_dee1601_demod_init(struct dvb_frontend *fe) { - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x28 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; mt352_write(fe, clock_config, sizeof(clock_config)); @@ -595,13 +606,14 @@ static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) return 0; } -static int cxusb_mt352_demod_init(struct dvb_frontend* fe) -{ /* used in both lgz201 and th7579 */ - static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x29 }; - static u8 reset [] = { RESET, 0x80 }; - static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; +static int cxusb_mt352_demod_init(struct dvb_frontend *fe) +{ + /* used in both lgz201 and th7579 */ + static u8 clock_config[] = { CLOCK_CTL, 0x38, 0x29 }; + static u8 reset[] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg[] = { AGC_TARGET, 0x24, 0x20 }; + static u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; mt352_write(fe, clock_config, sizeof(clock_config)); @@ -719,7 +731,7 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) &dvbdev->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3); - if (is_medion && adap->fe_adap[0].fe != NULL) + if (is_medion && adap->fe_adap[0].fe) /* * make sure that DVB core won't put to sleep (reset, really) * tuner when we might be open in analog mode @@ -738,7 +750,8 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap) { - dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, NULL, DVB_PLL_LG_Z201); + dvb_attach(dvb_pll_attach, adap->fe_adap[0].fe, 0x61, + NULL, DVB_PLL_LG_Z201); return 0; } @@ -798,7 +811,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe->callback = dvico_bluebird_xc2028_callback; fe = dvb_attach(xc2028_attach, adap->fe_adap[0].fe, &cfg); - if (fe == NULL || fe->ops.tuner_ops.set_config == NULL) + if (!fe || !fe->ops.tuner_ops.set_config) return -EIO; fe->ops.tuner_ops.set_config(fe, &ctl); @@ -816,17 +829,19 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &d680_dmb_tuner); - return (fe == NULL) ? -EIO : 0; + return (!fe) ? -EIO : 0; } static int cxusb_mygica_d689_tuner_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe; + fe = dvb_attach(max2165_attach, adap->fe_adap[0].fe, &adap->dev->i2c_adap, &mygica_d689_max2165_cfg); - return (fe == NULL) ? -EIO : 0; + return (!fe) ? -EIO : 0; } static int cxusb_medion_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) @@ -920,7 +935,7 @@ static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &dvbdev->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + if (!adap->fe_adap[0].fe) return -EIO; if (is_medion) @@ -941,7 +956,7 @@ static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) &cxusb_lgdt3303_config, 0x0e, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -953,7 +968,7 @@ static int cxusb_aver_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap) &cxusb_aver_lgdt3303_config, 0x0e, &adap->dev->i2c_adap); - if (adap->fe_adap[0].fe != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -969,7 +984,7 @@ static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -984,13 +999,13 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -1000,8 +1015,12 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) { u8 ircode[4]; int i; - struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD, - .buf = ircode, .len = 4 }; + struct i2c_msg msg = { + .addr = 0x6b, + .flags = I2C_M_RD, + .buf = ircode, + .len = 4 + }; if (usb_set_interface(adap->dev->udev, 0, 1) < 0) err("set interface failed"); @@ -1017,7 +1036,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap) dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config_no_i2c_gate, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) == NULL) + if (!adap->fe_adap[0].fe) return -EIO; /* try to determine if there is no IR decoder on the I2C bus */ @@ -1115,7 +1134,7 @@ static struct dib7000p_config cxusb_dualdig4_rev2_config = { }; struct dib0700_adapter_state { - int (*set_param_save)(struct dvb_frontend *); + int (*set_param_save)(struct dvb_frontend *fe); struct dib7000p_ops dib7000p_ops; }; @@ -1134,14 +1153,15 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) return -ENODEV; if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) { - printk(KERN_WARNING "Unable to enumerate dib7000p\n"); + &cxusb_dualdig4_rev2_config) < 0) { + pr_warn("Unable to enumerate dib7000p\n"); return -ENODEV; } - adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config); - if (adap->fe_adap[0].fe == NULL) + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, + 0x80, + &cxusb_dualdig4_rev2_config); + if (!adap->fe_adap[0].fe) return -EIO; return 0; @@ -1174,11 +1194,16 @@ static int dib7070_set_param_override(struct dvb_frontend *fe) struct dib0700_adapter_state *state = adap->priv; u16 offset; - u8 band = BAND_OF_FREQUENCY(p->frequency/1000); + u8 band = BAND_OF_FREQUENCY(p->frequency / 1000); + switch (band) { - case BAND_VHF: offset = 950; break; + case BAND_VHF: + offset = 950; + break; default: - case BAND_UHF: offset = 550; break; + case BAND_UHF: + offset = 550; + break; } state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); @@ -1200,7 +1225,7 @@ static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7070p_dib0070_config) == NULL) + &dib7070p_dib0070_config) == NULL) return -ENODEV; st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; @@ -1223,13 +1248,13 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) adap->fe_adap[0].fe = dvb_attach(zl10353_attach, &cxusb_zl10353_xc3028_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; adap->fe_adap[0].fe = dvb_attach(mt352_attach, &cxusb_mt352_xc3028_config, &adap->dev->i2c_adap); - if ((adap->fe_adap[0].fe) != NULL) + if (adap->fe_adap[0].fe) return 0; return -EIO; @@ -1260,11 +1285,14 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) /* Unblock all USB pipes */ usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.adapter[0].fe[0].stream.endpoint)); /* Drain USB pipes to avoid hang after reboot */ for (n = 0; n < 5; n++) { @@ -1286,8 +1314,9 @@ static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, &d680_lgs8gl5_cfg, &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + adap->fe_adap[0].fe = dvb_attach(lgs8gxx_attach, + &d680_lgs8gl5_cfg, &d->i2c_adap); + if (!adap->fe_adap[0].fe) return -EIO; return 0; @@ -1317,12 +1346,14 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) /* Unblock all USB pipes */ usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); - + usb_rcvbulkpipe(d->udev, + d->props.adapter[0].fe[0].stream.endpoint)); /* Reset the tuner */ if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { @@ -1337,9 +1368,10 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) msleep(100); /* Attach frontend */ - adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, &mygica_d689_atbm8830_cfg, - &d->i2c_adap); - if (adap->fe_adap[0].fe == NULL) + adap->fe_adap[0].fe = dvb_attach(atbm8830_attach, + &mygica_d689_atbm8830_cfg, + &d->i2c_adap); + if (!adap->fe_adap[0].fe) return -EIO; return 0; @@ -1362,11 +1394,14 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) /* Unblock all USB pipes */ usb_clear_halt(d->udev, - usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_sndbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.generic_bulk_ctrl_endpoint)); usb_clear_halt(d->udev, - usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint)); + usb_rcvbulkpipe(d->udev, + d->props.adapter[0].fe[0].stream.endpoint)); /* attach frontend */ si2168_config.i2c_adapter = &adapter; @@ -1379,7 +1414,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) info.platform_data = &si2168_config; request_module(info.type); client_demod = i2c_new_device(&d->i2c_adap, &info); - if (client_demod == NULL || client_demod->dev.driver == NULL) + if (!client_demod || !client_demod->dev.driver) return -ENODEV; if (!try_module_get(client_demod->dev.driver->owner)) { @@ -1399,7 +1434,7 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) info.platform_data = &si2157_config; request_module(info.type); client_tuner = i2c_new_device(adapter, &info); - if (client_tuner == NULL || client_tuner->dev.driver == NULL) { + if (!client_tuner || !client_tuner->dev.driver) { module_put(client_demod->dev.driver->owner); i2c_unregister_device(client_demod); return -ENODEV; @@ -1543,18 +1578,20 @@ int cxusb_medion_get(struct dvb_usb_device *dvbdev, } cxdev->open_type = open_type; - } else + } else { deb_info("reacquired idle %s\n", open_type == CXUSB_OPEN_ANALOG ? "analog" : "digital"); + } cxdev->open_ctr = 1; } else if (cxdev->open_type == open_type) { cxdev->open_ctr++; deb_info("acquired %s\n", open_type == CXUSB_OPEN_ANALOG ? "analog" : "digital"); - } else + } else { ret = -EBUSY; + } ret_unlock: mutex_unlock(&cxdev->open_lock); @@ -1577,8 +1614,9 @@ void cxusb_medion_put(struct dvb_usb_device *dvbdev) if (!WARN_ON(cxdev->open_ctr < 1)) { cxdev->open_ctr--; - deb_info("release %s\n", cxdev->open_type == - CXUSB_OPEN_ANALOG ? "analog" : "digital"); + deb_info("release %s\n", + cxdev->open_type == CXUSB_OPEN_ANALOG ? + "analog" : "digital"); } unlock: @@ -1670,8 +1708,8 @@ static int cxusb_probe(struct usb_interface *intf, int ret; /* Medion 95700 */ - if (0 == dvb_usb_device_init(intf, &cxusb_medion_properties, - THIS_MODULE, &dvbdev, adapter_nr)) { + if (!dvb_usb_device_init(intf, &cxusb_medion_properties, + THIS_MODULE, &dvbdev, adapter_nr)) { if (!cxusb_medion_check_intf(intf)) { ret = -ENODEV; goto ret_uninit; @@ -1694,33 +1732,39 @@ static int cxusb_probe(struct usb_interface *intf, cxusb_medion_put(dvbdev); return 0; - } else if (0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgh064f_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dee1601_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_lgz201_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dtt7579_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_dualdig4_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_bluebird_nano2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_nano2_needsfirmware_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, - &cxusb_bluebird_dualdig4_rev2_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, - THIS_MODULE, NULL, adapter_nr) || - 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, - THIS_MODULE, NULL, adapter_nr) || - 0) + } else if (!dvb_usb_device_init(intf, + &cxusb_bluebird_lgh064f_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dee1601_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_lgz201_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dtt7579_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_nano2_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_nano2_needsfirmware_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, + THIS_MODULE, NULL, adapter_nr) || + !dvb_usb_device_init(intf, &cxusb_mygica_t230_properties, + THIS_MODULE, NULL, adapter_nr) || + 0) return 0; return -EINVAL; @@ -1786,10 +1830,12 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) }, [DIGITALNOW_BLUEBIRD_DUAL_1_COLD] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) + USB_DEVICE(USB_VID_DVICO, + USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) }, [DIGITALNOW_BLUEBIRD_DUAL_1_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) + USB_DEVICE(USB_VID_DVICO, + USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) }, [DVICO_BLUEBIRD_DUAL_2_COLD] = { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) @@ -1804,7 +1850,8 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, [DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM] = { - USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) + USB_DEVICE(USB_VID_DVICO, + USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, [AVERMEDIA_VOLAR_A868R] = { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) @@ -1823,7 +1870,7 @@ static struct usb_device_id cxusb_table[NR__cxusb_table_index + 1] = { }, {} /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, cxusb_table); +MODULE_DEVICE_TABLE(usb, cxusb_table); static struct dvb_usb_device_properties cxusb_medion_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, @@ -1853,7 +1900,7 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_power_ctrl, @@ -1864,7 +1911,8 @@ static struct dvb_usb_device_properties cxusb_medion_properties = { .num_device_descs = 1, .devices = { - { "Medion MD95700 (MDUSBTV-HYBRID)", + { + "Medion MD95700 (MDUSBTV-HYBRID)", { NULL }, { &cxusb_table[MEDION_MD95700], NULL }, }, @@ -1877,8 +1925,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -1902,7 +1952,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = { } } }, - }}, + } }, }, }, @@ -1935,8 +1985,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -1959,7 +2011,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { } } }, - }}, + } }, }, }, @@ -1984,7 +2036,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = { { &cxusb_table[DVICO_BLUEBIRD_DUAL_1_WARM], NULL }, }, { "DigitalNow DVB-T Dual USB", - { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL }, + { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_COLD], NULL }, { &cxusb_table[DIGITALNOW_BLUEBIRD_DUAL_1_WARM], NULL }, }, { "DViCO FusionHDTV DVB-T Dual Digital 2", @@ -2000,8 +2052,10 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -2025,7 +2079,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_bluebird_power_ctrl, @@ -2056,8 +2110,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { .usb_ctrl = DEVICE_SPECIFIC, .firmware = "dvb-usb-bluebird-01.fw", .download_firmware = bluebird_patch_dvico_firmware_download, - /* use usb alt setting 0 for EP4 transfer (dvb-t), - use usb alt setting 7 for EP2 transfer (atsc) */ + + /* + * use usb alt setting 0 for EP4 transfer (dvb-t), + * use usb alt setting 7 for EP2 transfer (atsc) + */ .size_of_priv = sizeof(struct cxusb_state), @@ -2081,7 +2138,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_bluebird_power_ctrl, @@ -2133,7 +2190,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = { } } }, - }}, + } }, }, }, @@ -2187,7 +2244,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { } } }, - }}, + } }, }, }, @@ -2214,7 +2271,8 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = { } }; -static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties = { +static struct dvb_usb_device_properties +cxusb_bluebird_nano2_needsfirmware_properties = { .caps = DVB_USB_IS_AN_I2C_ADAPTER, .usb_ctrl = DEVICE_SPECIFIC, @@ -2243,7 +2301,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope } } }, - }}, + } }, }, }, @@ -2262,10 +2320,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope }, .num_device_descs = 1, - .devices = { - { "DViCO FusionHDTV DVB-T NANO2 w/o firmware", + .devices = { { + "DViCO FusionHDTV DVB-T NANO2 w/o firmware", { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2], NULL }, - { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], NULL }, + { &cxusb_table[DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM], + NULL }, }, } }; @@ -2296,7 +2355,7 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } } }, - }}, + } }, }, }, .power_ctrl = cxusb_aver_power_ctrl, @@ -2342,7 +2401,7 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { } } }, - }}, + } }, }, }, @@ -2396,7 +2455,7 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { } } }, - }}, + } }, }, }, @@ -2451,7 +2510,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { } } }, - }}, + } }, }, }, diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 35e72f571a2c..eb70fbb02680 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -77,12 +77,14 @@ struct cxusb_state { struct mutex stream_mutex; u8 last_lock; int (*fe_read_status)(struct dvb_frontend *fe, - enum fe_status *status); + enum fe_status *status); }; enum cxusb_open_type { - CXUSB_OPEN_INIT, CXUSB_OPEN_NONE, - CXUSB_OPEN_ANALOG, CXUSB_OPEN_DIGITAL + CXUSB_OPEN_INIT, + CXUSB_OPEN_NONE, + CXUSB_OPEN_ANALOG, + CXUSB_OPEN_DIGITAL }; struct cxusb_medion_auxbuf { -- cgit v1.2.3-59-g8ed1b From 10a34367ce097d5cd62ea526f5bcc809f99b5eb3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 28 May 2019 17:42:56 -0400 Subject: media: cx25840: Address several coding style issues As we did a major change on this file, let's take the moment to cleanup several coding style issues on it. This patch was partially done with the help of two tools: ./scripts/checkpatch.pl --fix-inplace --strict astyle --indent=tab=8 --style=linux But manually adjusted in order to fit our style. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 915 ++++++++++++++++++++----------- drivers/media/i2c/cx25840/cx25840-core.h | 15 +- include/media/drv-intf/cx25840.h | 33 +- 3 files changed, 619 insertions(+), 344 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 371ac6bb265a..f071a9434fed 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -35,7 +35,6 @@ * GNU General Public License for more details. */ - #include #include #include @@ -76,17 +75,17 @@ MODULE_LICENSE("GPL"); static int cx25840_debug; -module_param_named(debug,cx25840_debug, int, 0644); +module_param_named(debug, cx25840_debug, int, 0644); MODULE_PARM_DESC(debug, "Debugging messages [0=Off (default) 1=On]"); - /* ----------------------------------------------------------------------- */ static void cx23888_std_setup(struct i2c_client *client); int cx25840_write(struct i2c_client *client, u16 addr, u8 value) { u8 buffer[3]; + buffer[0] = addr >> 8; buffer[1] = addr & 0xff; buffer[2] = value; @@ -96,6 +95,7 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value) int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) { u8 buffer[6]; + buffer[0] = addr >> 8; buffer[1] = addr & 0xff; buffer[2] = value & 0xff; @@ -105,7 +105,7 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) return i2c_master_send(client, buffer, 6); } -u8 cx25840_read(struct i2c_client * client, u16 addr) +u8 cx25840_read(struct i2c_client *client, u16 addr) { struct i2c_msg msgs[2]; u8 tx_buf[2], rx_buf[1]; @@ -116,13 +116,13 @@ u8 cx25840_read(struct i2c_client * client, u16 addr) msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 2; - msgs[0].buf = (char *) tx_buf; + msgs[0].buf = (char *)tx_buf; /* Read data from register */ msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 1; - msgs[1].buf = (char *) rx_buf; + msgs[1].buf = (char *)rx_buf; if (i2c_transfer(client->adapter, msgs, 2) < 2) return 0; @@ -130,7 +130,7 @@ u8 cx25840_read(struct i2c_client * client, u16 addr) return rx_buf[0]; } -u32 cx25840_read4(struct i2c_client * client, u16 addr) +u32 cx25840_read4(struct i2c_client *client, u16 addr) { struct i2c_msg msgs[2]; u8 tx_buf[2], rx_buf[4]; @@ -141,13 +141,13 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr) msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 2; - msgs[0].buf = (char *) tx_buf; + msgs[0].buf = (char *)tx_buf; /* Read data from registers */ msgs[1].addr = client->addr; msgs[1].flags = I2C_M_RD; msgs[1].len = 4; - msgs[1].buf = (char *) rx_buf; + msgs[1].buf = (char *)rx_buf; if (i2c_transfer(client->adapter, msgs, 2) < 2) return 0; @@ -156,7 +156,7 @@ u32 cx25840_read4(struct i2c_client * client, u16 addr) rx_buf[0]; } -int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask, +int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int and_mask, u8 or_value) { return cx25840_write(client, addr, @@ -174,13 +174,14 @@ int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, /* ----------------------------------------------------------------------- */ -static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, - enum cx25840_audio_input aud_input); +static int set_input(struct i2c_client *client, + enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input); /* ----------------------------------------------------------------------- */ static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *p) + struct v4l2_subdev_io_pin_config *p) { struct i2c_client *client = v4l2_get_subdevdata(sd); int i; @@ -411,7 +412,6 @@ static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n, if (strength != CX25840_PIN_DRIVE_SLOW && strength != CX25840_PIN_DRIVE_MEDIUM && strength != CX25840_PIN_DRIVE_FAST) { - v4l_err(client, "invalid drive speed for pin %u (%u), assuming fast\n", (unsigned int)p[i].pin, @@ -531,7 +531,7 @@ static int cx25840_s_io_pin_config(struct v4l2_subdev *sd, size_t n, } static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, - struct v4l2_subdev_io_pin_config *pincfg) + struct v4l2_subdev_io_pin_config *pincfg) { struct cx25840_state *state = to_state(sd); @@ -546,8 +546,10 @@ static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n, static void init_dll1(struct i2c_client *client) { - /* This is the Hauppauge sequence used to - * initialize the Delay Lock Loop 1 (ADC DLL). */ + /* + * This is the Hauppauge sequence used to + * initialize the Delay Lock Loop 1 (ADC DLL). + */ cx25840_write(client, 0x159, 0x23); cx25840_write(client, 0x15a, 0x87); cx25840_write(client, 0x15b, 0x06); @@ -562,8 +564,10 @@ static void init_dll1(struct i2c_client *client) static void init_dll2(struct i2c_client *client) { - /* This is the Hauppauge sequence used to - * initialize the Delay Lock Loop 2 (ADC DLL). */ + /* + * This is the Hauppauge sequence used to + * initialize the Delay Lock Loop 2 (ADC DLL). + */ cx25840_write(client, 0x15d, 0xe3); cx25840_write(client, 0x15e, 0x86); cx25840_write(client, 0x15f, 0x06); @@ -575,7 +579,11 @@ static void init_dll2(struct i2c_client *client) static void cx25836_initialize(struct i2c_client *client) { - /* reset configuration is described on page 3-77 of the CX25836 datasheet */ + /* + *reset configuration is described on page 3-77 + * of the CX25836 datasheet + */ + /* 2. */ cx25840_and_or(client, 0x000, ~0x01, 0x01); cx25840_and_or(client, 0x000, ~0x01, 0x00); @@ -601,6 +609,7 @@ static void cx25836_initialize(struct i2c_client *client) static void cx25840_work_handler(struct work_struct *work) { struct cx25840_state *state = container_of(work, struct cx25840_state, fw_work); + cx25840_loadfw(state->c); wake_up(&state->fw_wait); } @@ -699,8 +708,10 @@ static void cx25840_initialize(struct i2c_client *client) /* datasheet startup in numbered steps, refer to page 3-77 */ /* 2. */ cx25840_and_or(client, 0x803, ~0x10, 0x00); - /* The default of this register should be 4, but I get 0 instead. - * Set this register to 4 manually. */ + /* + * The default of this register should be 4, but I get 0 instead. + * Set this register to 4 manually. + */ cx25840_write(client, 0x000, 0x04); /* 3. */ init_dll1(client); @@ -710,10 +721,12 @@ static void cx25840_initialize(struct i2c_client *client) cx25840_write(client, 0x13c, 0x01); cx25840_write(client, 0x13c, 0x00); /* 5. */ - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ + /* + * Do the firmware load in a work handler to prevent. + * Otherwise the kernel is blocked waiting for the + * bit-banging i2c interface to finish uploading the + * firmware. + */ INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); @@ -945,10 +958,12 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write(client, 0x160, 0x1d); cx25840_write(client, 0x164, 0x00); - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ + /* + * Do the firmware load in a work handler to prevent. + * Otherwise the kernel is blocked waiting for the + * bit-banging i2c interface to finish uploading the + * firmware. + */ INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); @@ -960,7 +975,8 @@ static void cx23885_initialize(struct i2c_client *client) destroy_workqueue(q); } - /* Call the cx23888 specific std setup func, we no longer rely on + /* + * Call the cx23888 specific std setup func, we no longer rely on * the generic cx24840 func. */ if (is_cx23888(state)) @@ -982,7 +998,9 @@ static void cx23885_initialize(struct i2c_client *client) cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff); /* CC raw enable */ - /* - VIP 1.1 control codes - 10bit, blue field enable. + + /* + * - VIP 1.1 control codes - 10bit, blue field enable. * - enable raw data during vertical blanking. * - enable ancillary Data insertion for 656 or VIP. */ @@ -1065,10 +1083,12 @@ static void cx231xx_initialize(struct i2c_client *client) /* White crush, Chroma AGC & Chroma Killer enabled */ cx25840_write(client, 0x401, 0xe8); - /* Do the firmware load in a work handler to prevent. - Otherwise the kernel is blocked waiting for the - bit-banging i2c interface to finish uploading the - firmware. */ + /* + * Do the firmware load in a work handler to prevent. + * Otherwise the kernel is blocked waiting for the + * bit-banging i2c interface to finish uploading the + * firmware. + */ INIT_WORK(&state->fw_work, cx25840_work_handler); init_waitqueue_head(&state->fw_wait); q = create_singlethread_workqueue("cx25840_fw"); @@ -1164,8 +1184,9 @@ void cx25840_std_setup(struct i2c_client *client) vblank = 26; vblank656 = 26; burst = 0x5b; - } else + } else { burst = 0x59; + } luma_lpf = 2; comb = 0x20; sc = 688739; @@ -1200,24 +1221,28 @@ void cx25840_std_setup(struct i2c_client *client) int pll = (28636363L * ((((u64)pll_int) << 25L) + pll_frac)) >> 25L; pll /= pll_post; - v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n", - pll / 1000000, pll % 1000000); - v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n", - pll / 8000000, (pll / 8) % 1000000); + v4l_dbg(1, cx25840_debug, client, + "PLL = %d.%06d MHz\n", + pll / 1000000, pll % 1000000); + v4l_dbg(1, cx25840_debug, client, + "PLL/8 = %d.%06d MHz\n", + pll / 8000000, (pll / 8) % 1000000); fin = ((u64)src_decimation * pll) >> 12; v4l_dbg(1, cx25840_debug, client, - "ADC Sampling freq = %d.%06d MHz\n", - fin / 1000000, fin % 1000000); + "ADC Sampling freq = %d.%06d MHz\n", + fin / 1000000, fin % 1000000); fsc = (((u64)sc) * pll) >> 24L; v4l_dbg(1, cx25840_debug, client, - "Chroma sub-carrier freq = %d.%06d MHz\n", - fsc / 1000000, fsc % 1000000); + "Chroma sub-carrier freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); - v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n", + v4l_dbg(1, cx25840_debug, client, + "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, comb, sc); + src_decimation, burst, luma_lpf, uv_lpf, + comb, sc); } } @@ -1272,10 +1297,10 @@ static void input_change(struct i2c_client *client) /* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */ if (std & V4L2_STD_SECAM) { cx25840_write(client, 0x402, 0); - } - else { + } else { cx25840_write(client, 0x402, 0x04); - cx25840_write(client, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); + cx25840_write(client, 0x49f, + (std & V4L2_STD_NTSC) ? 0x14 : 0x11); } cx25840_and_or(client, 0x401, ~0x60, 0); cx25840_and_or(client, 0x401, ~0x60, 0x60); @@ -1289,13 +1314,14 @@ static void input_change(struct i2c_client *client) if (state->radio) { cx25840_write(client, 0x808, 0xf9); cx25840_write(client, 0x80b, 0x00); - } - else if (std & V4L2_STD_525_60) { - /* Certain Hauppauge PVR150 models have a hardware bug - that causes audio to drop out. For these models the - audio standard must be set explicitly. - To be precise: it affects cards with tuner models - 85, 99 and 112 (model numbers from tveeprom). */ + } else if (std & V4L2_STD_525_60) { + /* + * Certain Hauppauge PVR150 models have a hardware bug + * that causes audio to drop out. For these models the + * audio standard must be set explicitly. + * To be precise: it affects cards with tuner models + * 85, 99 and 112 (model numbers from tveeprom). + */ int hw_fix = state->pvr150_workaround; if (std == V4L2_STD_NTSC_M_JP) { @@ -1312,35 +1338,40 @@ static void input_change(struct i2c_client *client) } else if (std & V4L2_STD_PAL) { /* Autodetect audio standard and audio system */ cx25840_write(client, 0x808, 0xff); - /* Since system PAL-L is pretty much non-existent and - not used by any public broadcast network, force - 6.5 MHz carrier to be interpreted as System DK, - this avoids DK audio detection instability */ + /* + * Since system PAL-L is pretty much non-existent and + * not used by any public broadcast network, force + * 6.5 MHz carrier to be interpreted as System DK, + * this avoids DK audio detection instability + */ cx25840_write(client, 0x80b, 0x00); } else if (std & V4L2_STD_SECAM) { /* Autodetect audio standard and audio system */ cx25840_write(client, 0x808, 0xff); - /* If only one of SECAM-DK / SECAM-L is required, then force - 6.5MHz carrier, else autodetect it */ + /* + * If only one of SECAM-DK / SECAM-L is required, then force + * 6.5MHz carrier, else autodetect it + */ if ((std & V4L2_STD_SECAM_DK) && !(std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { /* 6.5 MHz carrier to be interpreted as System DK */ cx25840_write(client, 0x80b, 0x00); - } else if (!(std & V4L2_STD_SECAM_DK) && - (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { + } else if (!(std & V4L2_STD_SECAM_DK) && + (std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))) { /* 6.5 MHz carrier to be interpreted as System L */ cx25840_write(client, 0x80b, 0x08); - } else { + } else { /* 6.5 MHz carrier to be autodetected */ cx25840_write(client, 0x80b, 0x10); - } + } } cx25840_and_or(client, 0x810, ~0x01, 0); } -static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input, - enum cx25840_audio_input aud_input) +static int set_input(struct i2c_client *client, + enum cx25840_video_input vid_input, + enum cx25840_audio_input aud_input) { struct cx25840_state *state = to_state(i2c_get_clientdata(client)); u8 is_composite = (vid_input >= CX25840_COMPOSITE1 && @@ -1365,7 +1396,7 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp vid_input); reg = vid_input & 0xff; is_composite = !is_component && - ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); + ((vid_input & CX25840_SVIDEO_ON) != CX25840_SVIDEO_ON); v4l_dbg(1, cx25840_debug, client, "mux cfg 0x%x comp=%d\n", reg, is_composite); @@ -1373,8 +1404,10 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp reg = 0xf0 + (vid_input - CX25840_COMPOSITE1); } else { if ((vid_input & ~0xff0) || - luma < CX25840_SVIDEO_LUMA1 || luma > CX25840_SVIDEO_LUMA8 || - chroma < CX25840_SVIDEO_CHROMA4 || chroma > CX25840_SVIDEO_CHROMA8) { + luma < CX25840_SVIDEO_LUMA1 || + luma > CX25840_SVIDEO_LUMA8 || + chroma < CX25840_SVIDEO_CHROMA4 || + chroma > CX25840_SVIDEO_CHROMA8) { v4l_err(client, "0x%04x is not a valid video input!\n", vid_input); return -EINVAL; @@ -1398,12 +1431,24 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp case CX25840_AUDIO_SERIAL: /* do nothing, use serial audio input */ break; - case CX25840_AUDIO4: reg &= ~0x30; break; - case CX25840_AUDIO5: reg &= ~0x30; reg |= 0x10; break; - case CX25840_AUDIO6: reg &= ~0x30; reg |= 0x20; break; - case CX25840_AUDIO7: reg &= ~0xc0; break; - case CX25840_AUDIO8: reg &= ~0xc0; reg |= 0x40; break; - + case CX25840_AUDIO4: + reg &= ~0x30; + break; + case CX25840_AUDIO5: + reg &= ~0x30; + reg |= 0x10; + break; + case CX25840_AUDIO6: + reg &= ~0x30; + reg |= 0x20; + break; + case CX25840_AUDIO7: + reg &= ~0xc0; + break; + case CX25840_AUDIO8: + reg &= ~0xc0; + reg |= 0x40; + break; default: v4l_err(client, "0x%04x is not a valid audio input!\n", aud_input); @@ -1420,7 +1465,6 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_and_or(client, 0x401, ~0x6, is_composite ? 0 : 0x02); if (is_cx2388x(state)) { - /* Enable or disable the DIF for tuner use */ if (is_dif) { cx25840_and_or(client, 0x102, ~0x80, 0x80); @@ -1451,15 +1495,23 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write4(client, 0x410, 0xffff0dbf); cx25840_write4(client, 0x414, 0x00137d03); - cx25840_write4(client, state->vbi_regs_offset + 0x42c, 0x42600000); - cx25840_write4(client, state->vbi_regs_offset + 0x430, 0x0000039b); - cx25840_write4(client, state->vbi_regs_offset + 0x438, 0x00000000); - - cx25840_write4(client, state->vbi_regs_offset + 0x440, 0xF8E3E824); - cx25840_write4(client, state->vbi_regs_offset + 0x444, 0x401040dc); - cx25840_write4(client, state->vbi_regs_offset + 0x448, 0xcd3f02a0); - cx25840_write4(client, state->vbi_regs_offset + 0x44c, 0x161f1000); - cx25840_write4(client, state->vbi_regs_offset + 0x450, 0x00000802); + cx25840_write4(client, state->vbi_regs_offset + 0x42c, + 0x42600000); + cx25840_write4(client, state->vbi_regs_offset + 0x430, + 0x0000039b); + cx25840_write4(client, state->vbi_regs_offset + 0x438, + 0x00000000); + + cx25840_write4(client, state->vbi_regs_offset + 0x440, + 0xF8E3E824); + cx25840_write4(client, state->vbi_regs_offset + 0x444, + 0x401040dc); + cx25840_write4(client, state->vbi_regs_offset + 0x448, + 0xcd3f02a0); + cx25840_write4(client, state->vbi_regs_offset + 0x44c, + 0x161f1000); + cx25840_write4(client, state->vbi_regs_offset + 0x450, + 0x00000802); cx25840_write4(client, 0x91c, 0x01000000); cx25840_write4(client, 0x8e0, 0x03063870); @@ -1526,8 +1578,9 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp * Only one of the two will be in use. */ cx25840_write4(client, AFE_CTRL, val); - } else + } else { cx25840_and_or(client, 0x102, ~0x2, 0); + } } state->vid_input = vid_input; @@ -1566,29 +1619,32 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp cx25840_write(client, 0x919, 0x01); } - if (is_cx2388x(state) && ((aud_input == CX25840_AUDIO7) || - (aud_input == CX25840_AUDIO6))) { + if (is_cx2388x(state) && + ((aud_input == CX25840_AUDIO7) || (aud_input == CX25840_AUDIO6))) { /* Configure audio from LR1 or LR2 input */ cx25840_write4(client, 0x910, 0); cx25840_write4(client, 0x8d0, 0x63073); - } else - if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) { + } else if (is_cx2388x(state) && (aud_input == CX25840_AUDIO8)) { /* Configure audio from tuner/sif input */ cx25840_write4(client, 0x910, 0x12b000c9); cx25840_write4(client, 0x8d0, 0x1f063870); } if (is_cx23888(state)) { - /* HVR1850 */ - /* AUD_IO_CTRL - I2S Input, Parallel1*/ - /* - Channel 1 src - Parallel1 (Merlin out) */ - /* - Channel 2 src - Parallel2 (Merlin out) */ - /* - Channel 3 src - Parallel3 (Merlin AC97 out) */ - /* - I2S source and dir - Merlin, output */ + /* + * HVR1850 + * + * AUD_IO_CTRL - I2S Input, Parallel1 + * - Channel 1 src - Parallel1 (Merlin out) + * - Channel 2 src - Parallel2 (Merlin out) + * - Channel 3 src - Parallel3 (Merlin AC97 out) + * - I2S source and dir - Merlin, output + */ cx25840_write4(client, 0x124, 0x100); if (!is_dif) { - /* Stop microcontroller if we don't need it + /* + * Stop microcontroller if we don't need it * to avoid audio popping on svideo/composite use. */ cx25840_and_or(client, 0x803, ~0x10, 0x00); @@ -1630,11 +1686,14 @@ static int set_v4lstd(struct i2c_client *client) fmt = 0xc; } - v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt); + v4l_dbg(1, cx25840_debug, client, + "changing video std to fmt %i\n", fmt); - /* Follow step 9 of section 3.16 in the cx25840 datasheet. - Without this PAL may display a vertical ghosting effect. - This happens for example with the Yuan MPC622. */ + /* + * Follow step 9 of section 3.16 in the cx25840 datasheet. + * Without this PAL may display a vertical ghosting effect. + * This happens for example with the Yuan MPC622. + */ if (fmt >= 4 && fmt < 8) { /* Set format to NTSC-M */ cx25840_and_or(client, 0x400, ~0xf, 1); @@ -1696,15 +1755,15 @@ static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl) /* ----------------------------------------------------------------------- */ static int cx25840_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; struct cx25840_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - u32 HSC, VSC, Vsrc, Hsrc, Vadd; + u32 hsc, vsc, v_src, h_src, v_add; int filter; - int is_50Hz = !(state->std & V4L2_STD_525_60); + int is_50hz = !(state->std & V4L2_STD_525_60); if (format->pad || fmt->code != MEDIA_BUS_FMT_FIXED) return -EINVAL; @@ -1713,23 +1772,23 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; if (is_cx23888(state)) { - Vsrc = (cx25840_read(client, 0x42a) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x429) & 0xf0) >> 4; + v_src = (cx25840_read(client, 0x42a) & 0x3f) << 4; + v_src |= (cx25840_read(client, 0x429) & 0xf0) >> 4; } else { - Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; - Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; + v_src = (cx25840_read(client, 0x476) & 0x3f) << 4; + v_src |= (cx25840_read(client, 0x475) & 0xf0) >> 4; } if (is_cx23888(state)) { - Hsrc = (cx25840_read(client, 0x426) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x425) & 0xf0) >> 4; + h_src = (cx25840_read(client, 0x426) & 0x3f) << 4; + h_src |= (cx25840_read(client, 0x425) & 0xf0) >> 4; } else { - Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; - Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; + h_src = (cx25840_read(client, 0x472) & 0x3f) << 4; + h_src |= (cx25840_read(client, 0x471) & 0xf0) >> 4; } if (!state->generic_mode) { - Vadd = is_50Hz ? 4 : 7; + v_add = is_50hz ? 4 : 7; /* * cx23888 in 525-line mode is programmed for 486 active lines @@ -1738,16 +1797,17 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, * See reg 0x428 bits [21:12] in cx23888_std_setup() vs * vactive in cx25840_std_setup(). */ - if (is_cx23888(state) && !is_50Hz) - Vadd--; - } else - Vadd = 0; + if (is_cx23888(state) && !is_50hz) + v_add--; + } else { + v_add = 0; + } - if (Hsrc == 0 || - Vsrc <= Vadd) { + if (h_src == 0 || + v_src <= v_add) { v4l_err(client, "chip reported picture size (%u x %u) is far too small\n", - (unsigned int)Hsrc, (unsigned int)Vsrc); + (unsigned int)h_src, (unsigned int)v_src); /* * that's the best we can do since the output picture * size is completely unknown in this case @@ -1755,20 +1815,20 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, return -EINVAL; } - fmt->width = clamp(fmt->width, (Hsrc + 15) / 16, Hsrc); + fmt->width = clamp(fmt->width, (h_src + 15) / 16, h_src); - if (Vadd * 8 >= Vsrc) - fmt->height = clamp(fmt->height, (u32)1, Vsrc - Vadd); + if (v_add * 8 >= v_src) + fmt->height = clamp(fmt->height, (u32)1, v_src - v_add); else - fmt->height = clamp(fmt->height, (Vsrc - Vadd * 8 + 7) / 8, - Vsrc - Vadd); + fmt->height = clamp(fmt->height, (v_src - v_add * 8 + 7) / 8, + v_src - v_add); if (format->which == V4L2_SUBDEV_FORMAT_TRY) return 0; - HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / (fmt->height + Vadd) - (1 << 9)); - VSC &= 0x1fff; + hsc = (h_src * (1 << 20)) / fmt->width - (1 << 20); + vsc = (1 << 16) - (v_src * (1 << 9) / (fmt->height + v_add) - (1 << 9)); + vsc &= 0x1fff; if (fmt->width >= 385) filter = 0; @@ -1782,20 +1842,20 @@ static int cx25840_set_fmt(struct v4l2_subdev *sd, v4l_dbg(1, cx25840_debug, client, "decoder set size %u x %u with scale %x x %x\n", (unsigned int)fmt->width, (unsigned int)fmt->height, - (unsigned int)HSC, (unsigned int)VSC); + (unsigned int)hsc, (unsigned int)vsc); - /* HSCALE=HSC */ + /* HSCALE=hsc */ if (is_cx23888(state)) { - cx25840_write4(client, 0x434, HSC | (1 << 24)); - /* VSCALE=VSC VS_INTRLACE=1 VFILT=filter */ - cx25840_write4(client, 0x438, VSC | (1 << 19) | (filter << 16)); + cx25840_write4(client, 0x434, hsc | (1 << 24)); + /* VSCALE=vsc VS_INTRLACE=1 VFILT=filter */ + cx25840_write4(client, 0x438, vsc | (1 << 19) | (filter << 16)); } else { - cx25840_write(client, 0x418, HSC & 0xff); - cx25840_write(client, 0x419, (HSC >> 8) & 0xff); - cx25840_write(client, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx25840_write(client, 0x41c, VSC & 0xff); - cx25840_write(client, 0x41d, VSC >> 8); + cx25840_write(client, 0x418, hsc & 0xff); + cx25840_write(client, 0x419, (hsc >> 8) & 0xff); + cx25840_write(client, 0x41a, hsc >> 16); + /* VSCALE=vsc */ + cx25840_write(client, 0x41c, vsc & 0xff); + cx25840_write(client, 0x41d, vsc >> 8); /* VS_INTRLACE=1 VFILT=filter */ cx25840_write(client, 0x41e, 0x8 | filter); } @@ -1822,23 +1882,25 @@ static void log_video_status(struct i2c_client *client) int vid_input = state->vid_input; v4l_info(client, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); + (gen_stat2 & 0x20) ? "" : "not "); v4l_info(client, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); + fmt_strs[gen_stat1 & 0xf]); v4l_info(client, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); + vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); if (vid_input >= CX25840_COMPOSITE1 && vid_input <= CX25840_COMPOSITE8) { v4l_info(client, "Specified video input: Composite %d\n", - vid_input - CX25840_COMPOSITE1 + 1); + vid_input - CX25840_COMPOSITE1 + 1); } else { - v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); + v4l_info(client, + "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", + (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); } - v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq); + v4l_info(client, "Specified audioclock freq: %d Hz\n", + state->audclk_freq); } /* ----------------------------------------------------------------------- */ @@ -1857,138 +1919,315 @@ static void log_audio_status(struct i2c_client *client) char *p; switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; + case 0x00: + p = "mono"; + break; + case 0x01: + p = "stereo"; + break; + case 0x02: + p = "dual"; + break; + case 0x04: + p = "tri"; + break; + case 0x10: + p = "mono with SAP"; + break; + case 0x11: + p = "stereo with SAP"; + break; + case 0x12: + p = "dual with SAP"; + break; + case 0x14: + p = "tri with SAP"; + break; + case 0xfe: + p = "forced mode"; + break; + default: + p = "not defined"; } v4l_info(client, "Detected audio mode: %s\n", p); switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "high-deviation FM"; break; - case 0x11: p = "very high-deviation FM"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; + case 0x00: + p = "not defined"; + break; + case 0x01: + p = "EIAJ"; + break; + case 0x02: + p = "A2-M"; + break; + case 0x03: + p = "A2-BG"; + break; + case 0x04: + p = "A2-DK1"; + break; + case 0x05: + p = "A2-DK2"; + break; + case 0x06: + p = "A2-DK3"; + break; + case 0x07: + p = "A1 (6.0 MHz FM Mono)"; + break; + case 0x08: + p = "AM-L"; + break; + case 0x09: + p = "NICAM-BG"; + break; + case 0x0a: + p = "NICAM-DK"; + break; + case 0x0b: + p = "NICAM-I"; + break; + case 0x0c: + p = "NICAM-L"; + break; + case 0x0d: + p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; + break; + case 0x0e: + p = "IF FM Radio"; + break; + case 0x0f: + p = "BTSC"; + break; + case 0x10: + p = "high-deviation FM"; + break; + case 0x11: + p = "very high-deviation FM"; + break; + case 0xfd: + p = "unknown audio standard"; + break; + case 0xfe: + p = "forced audio standard"; + break; + case 0xff: + p = "no detected audio standard"; + break; + default: + p = "not defined"; } v4l_info(client, "Detected audio standard: %s\n", p); v4l_info(client, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? - ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); + (download_ctl & 0x10) ? + ((mute_ctl & 0x2) ? "detecting" : "running") : "stopped"); switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; + case 0x00: + p = "undefined"; + break; + case 0x01: + p = "BTSC"; + break; + case 0x02: + p = "EIAJ"; + break; + case 0x03: + p = "A2-M"; + break; + case 0x04: + p = "A2-BG"; + break; + case 0x05: + p = "A2-DK1"; + break; + case 0x06: + p = "A2-DK2"; + break; + case 0x07: + p = "A2-DK3"; + break; + case 0x08: + p = "A1 (6.0 MHz FM Mono)"; + break; + case 0x09: + p = "AM-L"; + break; + case 0x0a: + p = "NICAM-BG"; + break; + case 0x0b: + p = "NICAM-DK"; + break; + case 0x0c: + p = "NICAM-I"; + break; + case 0x0d: + p = "NICAM-L"; + break; + case 0x0e: + p = "FM radio"; + break; + case 0x0f: + p = "automatic detection"; + break; + default: + p = "undefined"; } v4l_info(client, "Configured audio standard: %s\n", p); if ((audio_config >> 4) < 0xF) { switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AB)"; break; - case 0x06: p = "DUAL2 (AC) (FM)"; break; - case 0x07: p = "DUAL3 (BC) (FM)"; break; - case 0x08: p = "DUAL4 (AC) (AM)"; break; - case 0x09: p = "DUAL5 (BC) (AM)"; break; - case 0x0a: p = "SAP"; break; - default: p = "undefined"; + case 0x00: + p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; + break; + case 0x01: + p = "MONO2 (LANGUAGE B)"; + break; + case 0x02: + p = "MONO3 (STEREO forced MONO)"; + break; + case 0x03: + p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; + break; + case 0x04: + p = "STEREO"; + break; + case 0x05: + p = "DUAL1 (AB)"; + break; + case 0x06: + p = "DUAL2 (AC) (FM)"; + break; + case 0x07: + p = "DUAL3 (BC) (FM)"; + break; + case 0x08: + p = "DUAL4 (AC) (AM)"; + break; + case 0x09: + p = "DUAL5 (BC) (AM)"; + break; + case 0x0a: + p = "SAP"; + break; + default: + p = "undefined"; } v4l_info(client, "Configured audio mode: %s\n", p); } else { switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; + case 0x00: + p = "BG"; + break; + case 0x01: + p = "DK1"; + break; + case 0x02: + p = "DK2"; + break; + case 0x03: + p = "DK3"; + break; + case 0x04: + p = "I"; + break; + case 0x05: + p = "L"; + break; + case 0x06: + p = "BTSC"; + break; + case 0x07: + p = "EIAJ"; + break; + case 0x08: + p = "A2-M"; + break; + case 0x09: + p = "FM Radio"; + break; + case 0x0f: + p = "automatic standard and mode detection"; + break; + default: + p = "undefined"; } v4l_info(client, "Configured audio system: %s\n", p); } if (aud_input) { - v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input); + v4l_info(client, "Specified audio input: Tuner (In%d)\n", + aud_input); } else { v4l_info(client, "Specified audio input: External\n"); } switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; + case 0: + p = "mono/language A"; + break; + case 1: + p = "language B"; + break; + case 2: + p = "language C"; + break; + case 3: + p = "analog fallback"; + break; + case 4: + p = "stereo"; + break; + case 5: + p = "language AC"; + break; + case 6: + p = "language BC"; + break; + case 7: + p = "language AB"; + break; + default: + p = "undefined"; } v4l_info(client, "Preferred audio mode: %s\n", p); if ((audio_config & 0xf) == 0xf) { switch ((afc0 >> 3) & 0x3) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - case 2: p = "autodetect"; break; - default: p = "undefined"; + case 0: + p = "system DK"; + break; + case 1: + p = "system L"; + break; + case 2: + p = "autodetect"; + break; + default: + p = "undefined"; } v4l_info(client, "Selected 65 MHz format: %s\n", p); switch (afc0 & 0x7) { - case 0: p = "chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; + case 0: + p = "chroma"; + break; + case 1: + p = "BTSC"; + break; + case 2: + p = "EIAJ"; + break; + case 3: + p = "A2-M"; + break; + case 4: + p = "autodetect"; + break; + default: + p = "undefined"; } v4l_info(client, "Selected 45 MHz format: %s\n", p); } @@ -2039,22 +2278,24 @@ static int cx25840_init(struct v4l2_subdev *sd, u32 val) if (is_cx2584x(state)) { /* set datasheet video output defaults */ state->vid_config = CX25840_VCONFIG_FMT_BT656 | - CX25840_VCONFIG_RES_8BIT | - CX25840_VCONFIG_VBIRAW_DISABLED | - CX25840_VCONFIG_ANCDATA_ENABLED | - CX25840_VCONFIG_TASKBIT_ONE | - CX25840_VCONFIG_ACTIVE_HORIZONTAL | - CX25840_VCONFIG_VALID_NORMAL | - CX25840_VCONFIG_HRESETW_NORMAL | - CX25840_VCONFIG_CLKGATE_NONE | - CX25840_VCONFIG_DCMODE_DWORDS | - CX25840_VCONFIG_IDID0S_NORMAL | - CX25840_VCONFIG_VIPCLAMP_DISABLED; + CX25840_VCONFIG_RES_8BIT | + CX25840_VCONFIG_VBIRAW_DISABLED | + CX25840_VCONFIG_ANCDATA_ENABLED | + CX25840_VCONFIG_TASKBIT_ONE | + CX25840_VCONFIG_ACTIVE_HORIZONTAL | + CX25840_VCONFIG_VALID_NORMAL | + CX25840_VCONFIG_HRESETW_NORMAL | + CX25840_VCONFIG_CLKGATE_NONE | + CX25840_VCONFIG_DCMODE_DWORDS | + CX25840_VCONFIG_IDID0S_NORMAL | + CX25840_VCONFIG_VIPCLAMP_DISABLED; /* add additional settings */ cx25840_vconfig_add(state, val); - } else /* TODO: generic mode needs to be developed for other chips */ + } else { + /* TODO: generic mode needs to be developed for other chips */ WARN_ON(1); + } return 0; } @@ -2104,7 +2345,8 @@ static int cx25840_load_fw(struct v4l2_subdev *sd) } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +static int cx25840_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -2113,7 +2355,8 @@ static int cx25840_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * return 0; } -static int cx25840_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) +static int cx25840_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -2132,7 +2375,7 @@ static int cx25840_s_audio_stream(struct v4l2_subdev *sd, int enable) return 0; v4l_dbg(1, cx25840_debug, client, "%s audio output\n", - enable ? "enable" : "disable"); + enable ? "enable" : "disable"); if (enable) { v = cx25840_read(client, 0x115) | 0x80; @@ -2155,7 +2398,7 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable) u8 v; v4l_dbg(1, cx25840_debug, client, "%s video output\n", - enable ? "enable" : "disable"); + enable ? "enable" : "disable"); /* * It's not clear what should be done for these devices. @@ -2208,7 +2451,7 @@ static int cx25840_querystd(struct v4l2_subdev *sd, v4l2_std_id *std) }; u32 fmt = (cx25840_read4(client, 0x40c) >> 8) & 0xf; - *std = stds[ fmt ]; + *std = stds[fmt]; v4l_dbg(1, cx25840_debug, client, "querystd fmt = %x, v4l2_std_id = 0x%x\n", @@ -2221,7 +2464,8 @@ static int cx25840_g_input_status(struct v4l2_subdev *sd, u32 *status) { struct i2c_client *client = v4l2_get_subdevdata(sd); - /* A limited function that checks for signal status and returns + /* + * A limited function that checks for signal status and returns * the state. */ @@ -2289,7 +2533,8 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd, return set_input(client, state->vid_input, input); } -static int cx25840_s_frequency(struct v4l2_subdev *sd, const struct v4l2_frequency *freq) +static int cx25840_s_frequency(struct v4l2_subdev *sd, + const struct v4l2_frequency *freq) { struct i2c_client *client = v4l2_get_subdevdata(sd); @@ -2312,9 +2557,8 @@ static int cx25840_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) if (is_cx2583x(state)) return 0; - vt->capability |= - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; + vt->capability |= V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | + V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; mode = cx25840_read(client, 0x804); @@ -2344,33 +2588,41 @@ static int cx25840_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner *vt) return 0; switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - /* mono -> mono - stereo -> mono - bilingual -> lang1 */ - cx25840_and_or(client, 0x809, ~0xf, 0x00); - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1: - /* mono -> mono - stereo -> stereo - bilingual -> lang1 */ - cx25840_and_or(client, 0x809, ~0xf, 0x04); - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang1/lang2 */ - cx25840_and_or(client, 0x809, ~0xf, 0x07); - break; - case V4L2_TUNER_MODE_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang2 */ - cx25840_and_or(client, 0x809, ~0xf, 0x01); - break; - default: - return -EINVAL; + case V4L2_TUNER_MODE_MONO: + /* + * mono -> mono + * stereo -> mono + * bilingual -> lang1 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x00); + break; + case V4L2_TUNER_MODE_STEREO: + case V4L2_TUNER_MODE_LANG1: + /* + * mono -> mono + * stereo -> stereo + * bilingual -> lang1 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x04); + break; + case V4L2_TUNER_MODE_LANG1_LANG2: + /* + * mono -> mono + * stereo -> stereo + * bilingual -> lang1/lang2 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x07); + break; + case V4L2_TUNER_MODE_LANG2: + /* + * mono -> mono + * stereo -> stereo + * bilingual -> lang2 + */ + cx25840_and_or(client, 0x809, ~0xf, 0x01); + break; + default: + return -EINVAL; } state->audmode = vt->audmode; return 0; @@ -5545,22 +5797,28 @@ static u32 get_cx2388x_ident(struct i2c_client *client) /* Come out of digital power down */ cx25840_write(client, 0x000, 0); - /* Detecting whether the part is cx23885/7/8 is more + /* + * Detecting whether the part is cx23885/7/8 is more * difficult than it needs to be. No ID register. Instead we * probe certain registers indicated in the datasheets to look - * for specific defaults that differ between the silicon designs. */ + * for specific defaults that differ between the silicon designs. + */ /* It's either 885/7 if the IR Tx Clk Divider register exists */ if (cx25840_read4(client, 0x204) & 0xffff) { - /* CX23885 returns bogus repetitive byte values for the DIF, - * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) */ + /* + * CX23885 returns bogus repetitive byte values for the DIF, + * which doesn't exist for it. (Ex. 8a8a8a8a or 31313131) + */ ret = cx25840_read4(client, 0x300); if (((ret & 0xffff0000) >> 16) == (ret & 0xffff)) { /* No DIF */ ret = CX23885_AV; } else { - /* CX23887 has a broken DIF, but the registers - * appear valid (but unused), good enough to detect. */ + /* + * CX23887 has a broken DIF, but the registers + * appear valid (but unused), good enough to detect. + */ ret = CX23887_AV; } } else if (cx25840_read4(client, 0x300) & 0x0fffffff) { @@ -5592,14 +5850,18 @@ static int cx25840_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) return -EIO; - v4l_dbg(1, cx25840_debug, client, "detecting cx25840 client on address 0x%x\n", client->addr << 1); + v4l_dbg(1, cx25840_debug, client, + "detecting cx25840 client on address 0x%x\n", + client->addr << 1); device_id = cx25840_read(client, 0x101) << 8; device_id |= cx25840_read(client, 0x100); v4l_dbg(1, cx25840_debug, client, "device_id = 0x%04x\n", device_id); - /* The high byte of the device ID should be - * 0x83 for the cx2583x and 0x84 for the cx2584x */ + /* + * The high byte of the device ID should be + * 0x83 for the cx2583x and 0x84 for the cx2584x + */ if ((device_id & 0xff00) == 0x8300) { id = CX25836 + ((device_id >> 4) & 0xf) - 6; } else if ((device_id & 0xff00) == 0x8400) { @@ -5613,7 +5875,8 @@ static int cx25840_probe(struct i2c_client *client, v4l_err(client, "likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - v4l_err(client, "A method to reset it from the cx25840 driver software is not known at this time\n"); + v4l_err(client, + "A method to reset it from the cx25840 driver software is not known at this time\n"); return -ENODEV; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); @@ -5621,7 +5884,7 @@ static int cx25840_probe(struct i2c_client *client, } state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); - if (state == NULL) + if (!state) return -ENOMEM; sd = &state->sd; @@ -5648,7 +5911,7 @@ static int cx25840_probe(struct i2c_client *client, sd->entity.function = MEDIA_ENT_F_ATV_DECODER; ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(state->pads), - state->pads); + state->pads); if (ret < 0) { v4l_info(client, "failed to initialize media entity!\n"); return ret; @@ -5676,8 +5939,10 @@ static int cx25840_probe(struct i2c_client *client, case CX25841: case CX25842: case CX25843: - /* Note: revision '(device_id & 0x0f) == 2' was never built. The - marking skips from 0x1 == 22 to 0x3 == 23. */ + /* + * Note: revision '(device_id & 0x0f) == 2' was never built. + * The marking skips from 0x1 == 22 to 0x3 == 23. + */ v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n", (device_id & 0xfff0) >> 4, (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 @@ -5705,13 +5970,13 @@ static int cx25840_probe(struct i2c_client *client, state->std = V4L2_STD_NTSC_M; v4l2_ctrl_handler_init(&state->hdl, 9); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); + V4L2_CID_CONTRAST, 0, 127, 1, 64); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); + V4L2_CID_SATURATION, 0, 127, 1, 64); v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); + V4L2_CID_HUE, -128, 127, 1, 0); if (!is_cx2583x(state)) { default_volume = cx25840_read(client, 0x8d4); /* @@ -5723,8 +5988,7 @@ static int cx25840_probe(struct i2c_client *client, /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ default_volume = 228; cx25840_write(client, 0x8d4, 228); - } - else if (default_volume < 20) { + } else if (default_volume < 20) { /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ default_volume = 20; cx25840_write(client, 0x8d4, 20); @@ -5732,20 +5996,23 @@ static int cx25840_probe(struct i2c_client *client, default_volume = (((228 - default_volume) >> 1) + 23) << 9; state->volume = v4l2_ctrl_new_std(&state->hdl, - &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, - 0, 65535, 65535 / 100, default_volume); + &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_VOLUME, + 0, 65535, 65535 / 100, + default_volume); state->mute = v4l2_ctrl_new_std(&state->hdl, - &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, - 0, 1, 1, 0); + &cx25840_audio_ctrl_ops, + V4L2_CID_AUDIO_MUTE, + 0, 1, 1, 0); v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, - 0, 65535, 65535 / 100, 32768); + V4L2_CID_AUDIO_BALANCE, + 0, 65535, 65535 / 100, 32768); v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_BASS, - 0, 65535, 65535 / 100, 32768); + V4L2_CID_AUDIO_BASS, + 0, 65535, 65535 / 100, 32768); v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, - 0, 65535, 65535 / 100, 32768); + V4L2_CID_AUDIO_TREBLE, + 0, 65535, 65535 / 100, 32768); } sd->ctrl_handler = &state->hdl; if (state->hdl.error) { diff --git a/drivers/media/i2c/cx25840/cx25840-core.h b/drivers/media/i2c/cx25840/cx25840-core.h index 2ff7191ad232..079ad503b507 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.h +++ b/drivers/media/i2c/cx25840/cx25840-core.h @@ -16,7 +16,6 @@ #ifndef _CX25840_CORE_H_ #define _CX25840_CORE_H_ - #include #include #include @@ -100,7 +99,7 @@ struct cx25840_state { enum cx25840_model id; u32 rev; int is_initialized; - unsigned vbi_regs_offset; + unsigned int vbi_regs_offset; wait_queue_head_t fw_wait; struct work_struct fw_work; struct cx25840_ir_state *ir_state; @@ -166,7 +165,8 @@ int cx25840_write(struct i2c_client *client, u16 addr, u8 value); int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); u8 cx25840_read(struct i2c_client *client, u16 addr); u32 cx25840_read4(struct i2c_client *client, u16 addr); -int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value); +int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned int mask, + u8 value); int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask, u32 or_value); void cx25840_std_setup(struct i2c_client *client); @@ -185,9 +185,12 @@ extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops; /* ----------------------------------------------------------------------- */ /* cx25850-vbi.c */ int cx25840_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); -int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi); +int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, + struct v4l2_sliced_vbi_format *fmt); +int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, + struct v4l2_sliced_vbi_format *fmt); +int cx25840_decode_vbi_line(struct v4l2_subdev *sd, + struct v4l2_decode_vbi_line *vbi); /* ----------------------------------------------------------------------- */ /* cx25850-ir.c */ diff --git a/include/media/drv-intf/cx25840.h b/include/media/drv-intf/cx25840.h index ed8ee1c77a6c..ba69bc525382 100644 --- a/include/media/drv-intf/cx25840.h +++ b/include/media/drv-intf/cx25840.h @@ -1,10 +1,10 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - cx25840.h - definition for cx25840/1/2/3 inputs - - Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) -*/ +/* + * cx25840.h - definition for cx25840/1/2/3 inputs + * + * Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl) + */ #ifndef _CX25840_H_ #define _CX25840_H_ @@ -38,8 +38,10 @@ enum cx25840_video_input { CX25840_COMPOSITE7, CX25840_COMPOSITE8, - /* S-Video inputs consist of one luma input (In1-In8) ORed with one - chroma input (In5-In8) */ + /* + * S-Video inputs consist of one luma input (In1-In8) ORed with one + * chroma input (In5-In8) + */ CX25840_SVIDEO_LUMA1 = 0x10, CX25840_SVIDEO_LUMA2 = 0x20, CX25840_SVIDEO_LUMA3 = 0x30, @@ -243,13 +245,16 @@ enum cx23885_io_pad { CX23885_PAD_GPIO16, }; -/* pvr150_workaround activates a workaround for a hardware bug that is - present in Hauppauge PVR-150 (and possibly PVR-500) cards that have - certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The - audio autodetect fails on some channels for these models and the workaround - is to select the audio standard explicitly. Many thanks to Hauppauge for - providing this information. - This platform data only needs to be supplied by the ivtv driver. */ +/* + * pvr150_workaround activates a workaround for a hardware bug that is + * present in Hauppauge PVR-150 (and possibly PVR-500) cards that have + * certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The + * audio autodetect fails on some channels for these models and the workaround + * is to select the audio standard explicitly. Many thanks to Hauppauge for + * providing this information. + * + * This platform data only needs to be supplied by the ivtv driver. + */ struct cx25840_platform_data { int pvr150_workaround; }; -- cgit v1.2.3-59-g8ed1b From c8d0ccfd73dab35f60cb4f27d9fb7eb07c104e77 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 6 May 2019 03:05:16 -0400 Subject: media: mtk-vpu: fix leaked of_node references The call to of_parse_phandle returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. Detected by coccinelle with the following warnings: drivers/media/platform/mtk-vpu/mtk_vpu.c:477:1-7: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 464, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index 46c45f93c977..97dcb4cc4c15 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -468,9 +468,9 @@ struct platform_device *vpu_get_plat_device(struct platform_device *pdev) } vpu_pdev = of_find_device_by_node(vpu_node); + of_node_put(vpu_node); if (WARN_ON(!vpu_pdev)) { dev_err(dev, "vpu pdev failed\n"); - of_node_put(vpu_node); return NULL; } -- cgit v1.2.3-59-g8ed1b From 15b5c5b1dce9bc19a0f00697ce64ecd819cfd109 Mon Sep 17 00:00:00 2001 From: Wen Yang Date: Mon, 6 May 2019 03:05:17 -0400 Subject: media: mtk-vcodec: fix leaked of_node references The call to of_find_device_by_node returns a node pointer with refcount incremented thus it must be explicitly decremented after the last usage. Detected by coccinelle with the following warnings: drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c:60:3-9: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 38, but without a corresponding object release within this function. drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c:63:2-8: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 38, but without a corresponding object release within this function. drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c:72:3-9: ERROR: missing of_node_put; acquired a node pointer with refcount incremented on line 38, but without a corresponding object release within this function. Signed-off-by: Wen Yang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 7884465afcd2..11c45c556e88 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -42,8 +42,8 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) } pdev = of_find_device_by_node(node); + of_node_put(node); if (WARN_ON(!pdev)) { - of_node_put(node); return -1; } pm->larbvdec = &pdev->dev; -- cgit v1.2.3-59-g8ed1b From 518fa4e0e0da97ea2e17c95ab57647ce748a96e2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 27 May 2019 05:31:13 -0400 Subject: media: mc-device.c: don't memset __user pointer contents You can't memset the contents of a __user pointer. Instead, call copy_to_user to copy links.reserved (which is zeroed) to the user memory. This fixes this sparse warning: SPARSE:drivers/media/mc/mc-device.c drivers/media/mc/mc-device.c:521:16: warning: incorrect type in argument 1 (different address spaces) Fixes: f49308878d720 ("media: media_device_enum_links32: clean a reserved field") Signed-off-by: Hans Verkuil Reviewed-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/mc-device.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c index 6893843edada..8e2a66493e62 100644 --- a/drivers/media/mc/mc-device.c +++ b/drivers/media/mc/mc-device.c @@ -518,8 +518,9 @@ static long media_device_enum_links32(struct media_device *mdev, if (ret) return ret; - memset(ulinks->reserved, 0, sizeof(ulinks->reserved)); - + if (copy_to_user(ulinks->reserved, links.reserved, + sizeof(ulinks->reserved))) + return -EFAULT; return 0; } -- cgit v1.2.3-59-g8ed1b From 50710eeefbc1ed25375942aad0c4d1eb4af0f330 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Mon, 27 May 2019 08:14:55 -0400 Subject: media: saa7164: fix remove_proc_entry warning if saa7164_proc_create() fails, saa7164_fini() will trigger a warning, name 'saa7164' WARNING: CPU: 1 PID: 6311 at fs/proc/generic.c:672 remove_proc_entry+0x1e8/0x3a0 ? remove_proc_entry+0x1e8/0x3a0 ? try_stop_module+0x7b/0x240 ? proc_readdir+0x70/0x70 ? rcu_read_lock_sched_held+0xd7/0x100 saa7164_fini+0x13/0x1f [saa7164] __x64_sys_delete_module+0x30c/0x480 ? __ia32_sys_delete_module+0x480/0x480 ? __x64_sys_clock_gettime+0x11e/0x1c0 ? __x64_sys_timer_create+0x1a0/0x1a0 ? trace_hardirqs_off_caller+0x40/0x180 ? do_syscall_64+0x18/0x450 do_syscall_64+0x9f/0x450 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fix it by checking the return of proc_create_single() before calling remove_proc_entry(). Signed-off-by: Kefeng Wang Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: use 0444 instead of S_IRUGO] [hverkuil-cisco@xs4all.nl: use pr_info instead of KERN_INFO] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-core.c | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 05f25c9bb308..f5ad3cf207d3 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -1122,16 +1122,25 @@ static int saa7164_proc_show(struct seq_file *m, void *v) return 0; } +static struct proc_dir_entry *saa7164_pe; + static int saa7164_proc_create(void) { - struct proc_dir_entry *pe; - - pe = proc_create_single("saa7164", S_IRUGO, NULL, saa7164_proc_show); - if (!pe) + saa7164_pe = proc_create_single("saa7164", 0444, NULL, saa7164_proc_show); + if (!saa7164_pe) return -ENOMEM; return 0; } + +static void saa7164_proc_destroy(void) +{ + if (saa7164_pe) + remove_proc_entry("saa7164", NULL); +} +#else +static int saa7164_proc_create(void) { return 0; } +static void saa7164_proc_destroy(void) {} #endif static int saa7164_thread_function(void *data) @@ -1503,19 +1512,21 @@ static struct pci_driver saa7164_pci_driver = { static int __init saa7164_init(void) { - printk(KERN_INFO "saa7164 driver loaded\n"); + int ret = pci_register_driver(&saa7164_pci_driver); + + if (ret) + return ret; -#ifdef CONFIG_PROC_FS saa7164_proc_create(); -#endif - return pci_register_driver(&saa7164_pci_driver); + + pr_info("saa7164 driver loaded\n"); + + return 0; } static void __exit saa7164_fini(void) { -#ifdef CONFIG_PROC_FS - remove_proc_entry("saa7164", NULL); -#endif + saa7164_proc_destroy(); pci_unregister_driver(&saa7164_pci_driver); } -- cgit v1.2.3-59-g8ed1b From 64b42d8eee9b57d1329eeb338c3c30171a14cdbd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 29 May 2019 04:22:15 -0400 Subject: media: cec-adap: fix regression in ping sanity check Commit b6c96e156825 inadvertently also dropped the 'msg->len > 1' test from the preceding sanity check. This caused compliance test failures. Fixes: b6c96e156825 ("media: cec: allow any initiator for Ping and Image/Text View On") Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 5827d8c3742a..ac3683a7b2ab 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -809,7 +809,7 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, __func__); return -EINVAL; } - if (adap->is_configured && + if (msg->len > 1 && adap->is_configured && !cec_has_log_addr(adap, cec_msg_initiator(msg))) { dprintk(1, "%s: initiator has unknown logical address %d\n", __func__, cec_msg_initiator(msg)); -- cgit v1.2.3-59-g8ed1b From ce57a82f8a8dfd9c6eef3b99bf9b3677933210c0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 28 May 2019 13:02:17 -0400 Subject: media: v4l2-common: Fix v4l2_fill_pixfmt[_mp]() prototypes Width/height and 4CC formats are expressed using u32 types everywhere, let's fix the v4l2_fill_pixfmt[_mp]() prototypes to do the same. Signed-off-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 5 +++-- include/media/v4l2-common.h | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index c9efb2de710d..6ee9fa3bdb18 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -532,7 +532,7 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf } int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, - int pixelformat, int width, int height) + u32 pixelformat, u32 width, u32 height) { const struct v4l2_format_info *info; struct v4l2_plane_pix_format *plane; @@ -586,7 +586,8 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, } EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); -int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, int width, int height) +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, + u32 width, u32 height) { const struct v4l2_format_info *info; int i; diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 0a41bbecf3d3..3226bc8107cc 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -420,9 +420,9 @@ struct v4l2_format_info { const struct v4l2_format_info *v4l2_format_info(u32 format); -int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, - int width, int height); -int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, int pixelformat, - int width, int height); +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, + u32 width, u32 height); +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat, + u32 width, u32 height); #endif /* V4L2_COMMON_H_ */ -- cgit v1.2.3-59-g8ed1b From 32cddf9c94d81c4cd3c63fd1fe8ea9b98feac7e5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 28 May 2019 13:02:18 -0400 Subject: media: v4l2-common: Add an helper to apply frmsize constraints The rockchip VPU driver is open-coding this logic which seems pretty generic. Let's provide an helper to apply the min/max and alignment constraints on width/height. Signed-off-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-common.c | 27 +++++++++++++++++++++++++++ include/media/v4l2-common.h | 2 ++ 2 files changed, 29 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 6ee9fa3bdb18..f8ad1c580a3e 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -321,6 +321,16 @@ static unsigned int clamp_align(unsigned int x, unsigned int min, return x; } +static unsigned int clamp_roundup(unsigned int x, unsigned int min, + unsigned int max, unsigned int alignment) +{ + x = clamp(x, min, max); + if (alignment) + x = round_up(x, alignment); + + return x; +} + void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax, unsigned int walign, u32 *h, unsigned int hmin, unsigned int hmax, @@ -531,6 +541,23 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf return info->block_h[plane]; } +void v4l2_apply_frmsize_constraints(u32 *width, u32 *height, + const struct v4l2_frmsize_stepwise *frmsize) +{ + if (!frmsize) + return; + + /* + * Clamp width/height to meet min/max constraints and round it up to + * macroblock alignment. + */ + *width = clamp_roundup(*width, frmsize->min_width, frmsize->max_width, + frmsize->step_width); + *height = clamp_roundup(*height, frmsize->min_height, frmsize->max_height, + frmsize->step_height); +} +EXPORT_SYMBOL_GPL(v4l2_apply_frmsize_constraints); + int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat, u32 width, u32 height) { diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 3226bc8107cc..e826b154bc35 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -420,6 +420,8 @@ struct v4l2_format_info { const struct v4l2_format_info *v4l2_format_info(u32 format); +void v4l2_apply_frmsize_constraints(u32 *width, u32 *height, + const struct v4l2_frmsize_stepwise *frmsize); int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat, u32 width, u32 height); int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat, -- cgit v1.2.3-59-g8ed1b From d3844b9df9cb5f7bff074d0ec7f40e41c5200f4a Mon Sep 17 00:00:00 2001 From: Shawn Tu Date: Sun, 26 May 2019 22:26:05 -0400 Subject: media: ov8856: modify register to fix test pattern modify registers to fix bayer order in test pattern mode Signed-off-by: Shawn Tu Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov8856.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index dbf1095b9440..cd347d6b7b9d 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -195,11 +195,11 @@ static const struct ov8856_reg mode_3280x2464_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, - {0x3803, 0x07}, + {0x3803, 0x06}, {0x3804, 0x0c}, {0x3805, 0xdf}, {0x3806, 0x09}, - {0x3807, 0xa6}, + {0x3807, 0xa7}, {0x3808, 0x0c}, {0x3809, 0xd0}, {0x380a, 0x09}, @@ -211,7 +211,7 @@ static const struct ov8856_reg mode_3280x2464_regs[] = { {0x3810, 0x00}, {0x3811, 0x00}, {0x3812, 0x00}, - {0x3813, 0x00}, + {0x3813, 0x01}, {0x3814, 0x01}, {0x3815, 0x01}, {0x3816, 0x00}, @@ -385,11 +385,11 @@ static const struct ov8856_reg mode_1640x1232_regs[] = { {0x3800, 0x00}, {0x3801, 0x00}, {0x3802, 0x00}, - {0x3803, 0x07}, + {0x3803, 0x06}, {0x3804, 0x0c}, {0x3805, 0xdf}, {0x3806, 0x09}, - {0x3807, 0xa6}, + {0x3807, 0xa7}, {0x3808, 0x06}, {0x3809, 0x68}, {0x380a, 0x04}, @@ -401,7 +401,7 @@ static const struct ov8856_reg mode_1640x1232_regs[] = { {0x3810, 0x00}, {0x3811, 0x00}, {0x3812, 0x00}, - {0x3813, 0x00}, + {0x3813, 0x01}, {0x3814, 0x03}, {0x3815, 0x01}, {0x3816, 0x00}, -- cgit v1.2.3-59-g8ed1b From 8c03d845b86c5fc916cac9027eb5109e771e884f Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Mon, 20 May 2019 11:06:36 -0400 Subject: media: sun6i: Support A83T variant The A83T SoC has a camera sensor interface (known as CSI in Allwinner lingo), which is similar to the one found on the A64 and H3. The only difference seems to be that support of MIPI CSI through a connected MIPI CSI-2 bridge. Add support for this variant. Signed-off-by: Chen-Yu Tsai Acked-by: Maxime Ripard Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c index 4c79eb64a7a7..6e0e894154f4 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c @@ -924,6 +924,7 @@ static int sun6i_csi_remove(struct platform_device *pdev) static const struct of_device_id sun6i_csi_of_match[] = { { .compatible = "allwinner,sun6i-a31-csi", }, + { .compatible = "allwinner,sun8i-a83t-csi", }, { .compatible = "allwinner,sun8i-h3-csi", }, { .compatible = "allwinner,sun8i-v3s-csi", }, { .compatible = "allwinner,sun50i-a64-csi", }, -- cgit v1.2.3-59-g8ed1b From 5c1c695307b61bc0a86ff3a188da669220c7c9df Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 23 May 2019 04:48:11 -0400 Subject: media: em28xx: give RC device proper name Give the RC device the name of the board rather than "1-2:1.0 IR". Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index d85ea1af6aa1..e757a71d247f 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -58,7 +58,6 @@ struct em28xx_ir_poll_result { struct em28xx_IR { struct em28xx *dev; struct rc_dev *rc; - char name[32]; char phys[32]; /* poll decoder */ @@ -832,14 +831,10 @@ static int em28xx_ir_init(struct em28xx *dev) /* This is how often we ask the chip for IR information */ ir->polling = 100; /* ms */ - /* init input device */ - snprintf(ir->name, sizeof(ir->name), "%s IR", - dev_name(&dev->intf->dev)); - usb_make_path(udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - rc->device_name = ir->name; + rc->device_name = em28xx_boards[dev->model].name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_USB; rc->input_id.version = 1; -- cgit v1.2.3-59-g8ed1b From 6bd914bc05f378071f9fa975ce91fbf9a4a5e224 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 23 May 2019 05:31:11 -0400 Subject: media: em28xx: use common code for decoding nec scancodes Tested on WinTV-HVR-930C. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index e757a71d247f..6e43da5f6c5a 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -276,21 +276,8 @@ static int em2874_polling_getkey(struct em28xx_IR *ir, break; case RC_PROTO_BIT_NEC: - poll_result->scancode = msg[1] << 8 | msg[2]; - if ((msg[3] ^ msg[4]) != 0xff) { /* 32 bits NEC */ - poll_result->protocol = RC_PROTO_NEC32; - poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) | - (msg[2] << 16) | - (msg[3] << 8) | - (msg[4])); - } else if ((msg[1] ^ msg[2]) != 0xff) { /* 24 bits NEC */ - poll_result->protocol = RC_PROTO_NECX; - poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 | - msg[2], msg[3]); - } else { /* Normal NEC */ - poll_result->protocol = RC_PROTO_NEC; - poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]); - } + poll_result->scancode = ir_nec_bytes_to_scancode(msg[1], msg[2], msg[3], msg[4], + &poll_result->protocol); break; case RC_PROTO_BIT_RC6_0: -- cgit v1.2.3-59-g8ed1b From 0547858b00bf2e895ee7c6ede7b376450e217171 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 23 May 2019 06:01:51 -0400 Subject: media: em28xx: use usb_to_input_id() rather than handrolling it This also populates the version member correctly. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-input.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 6e43da5f6c5a..5aa15a7a49de 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -603,10 +604,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); input_dev->keycodesize = 0; input_dev->keycodemax = 0; - input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct); - input_dev->id.version = 1; + usb_to_input_id(udev, &input_dev->id); input_dev->dev.parent = &dev->intf->dev; err = input_register_device(input_dev); @@ -823,10 +821,7 @@ static int em28xx_ir_init(struct em28xx *dev) rc->device_name = em28xx_boards[dev->model].name; rc->input_phys = ir->phys; - rc->input_id.bustype = BUS_USB; - rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(udev->descriptor.idProduct); + usb_to_input_id(udev, &rc->input_id); rc->dev.parent = &dev->intf->dev; rc->driver_name = MODULE_NAME; -- cgit v1.2.3-59-g8ed1b From 6211e44a4dfc2a12c5d40984ab876537bf0d0830 Mon Sep 17 00:00:00 2001 From: Young Xiao <92siuyang@gmail.com> Date: Tue, 28 May 2019 08:38:13 -0400 Subject: media: cx231xx-dvb: fix memory leak in dvb_fini() In dvb_init(), dev->dvb is allocated by kzalloc. Therefore, it must be freed being set to NULL. Signed-off-by: Young Xiao <92siuyang@gmail.com> Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-dvb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 8fbb9523c88d..e205f7f0a56a 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -1147,6 +1147,7 @@ static int dvb_fini(struct cx231xx *dev) if (dev->dvb) { unregister_dvb(dev->dvb); + kfree(dev->dvb); dev->dvb = NULL; } -- cgit v1.2.3-59-g8ed1b From 835706214875de6e6f8b9d01ceeed17b20622677 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 29 Mar 2019 13:34:27 -0400 Subject: media: videobuf-dma-contig: Use size of buffer in mmap not vma size The size of the vma can be larger than the size of the backing buffer. Use the buffer size over vma size to prevent exposing extra memory to userspace. Signed-off-by: Andrew F. Davis Reviewed-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf-dma-contig.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index e1bf50df4c70..65e2655d22b7 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -280,7 +280,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, struct videobuf_dma_contig_memory *mem; struct videobuf_mapping *map; int retval; - unsigned long size; dev_dbg(q->dev, "%s\n", __func__); @@ -303,7 +302,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, goto error; /* Try to remap memory */ - size = vma->vm_end - vma->vm_start; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* the "vm_pgoff" is just used in v4l2 to find the @@ -314,7 +312,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q, */ vma->vm_pgoff = 0; - retval = vm_iomap_memory(vma, mem->dma_handle, size); + retval = vm_iomap_memory(vma, mem->dma_handle, mem->size); if (retval) { dev_err(q->dev, "mmap: remap failed with error %d. ", retval); -- cgit v1.2.3-59-g8ed1b From f42292040d31922ee4e4ea68e2f287fbc3bb2053 Mon Sep 17 00:00:00 2001 From: Arushi Singhal Date: Wed, 29 Mar 2017 11:13:20 -0400 Subject: media: staging: media: davinci_vpfe: Replace a bit shift This patch replaces bit shifting on 1 with the BIT(x) macro. This was done with coccinelle: @@ constant c; @@ -1 << c +BIT(c) [mchehab+samsung@kernel.org: rebase on the top of upstream] Signed-off-by: Arushi Singhal Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispstat.c | 2 +- drivers/staging/media/davinci_vpfe/dm365_isif.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 47353fee26c3..953a812bfe5e 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1040,7 +1040,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name, 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->grp_id = BIT(16); /* group ID for isp subdevs */ subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE; v4l2_set_subdevdata(subdev, stat); diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index 46fd8184fc77..05a997f7aa5d 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -816,7 +816,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) /* Correct whole line or partial */ if (vdfc->corr_whole_line) - val |= 1 << ISIF_VDFC_CORR_WHOLE_LN_SHIFT; + val |= BIT(ISIF_VDFC_CORR_WHOLE_LN_SHIFT); /* level shift value */ val |= (vdfc->def_level_shift & ISIF_VDFC_LEVEL_SHFT_MASK) << @@ -844,7 +844,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); /* set DFCMARST and set DFCMWR */ - val |= 1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT; + val |= BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); val |= 1; isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); @@ -875,7 +875,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc) } val = isif_read(isif->isif_cfg.base_addr, DFCMEMCTL); /* clear DFCMARST and set DFCMWR */ - val &= ~(1 << ISIF_DFCMEMCTL_DFCMARST_SHIFT); + val &= ~BIT(ISIF_DFCMEMCTL_DFCMARST_SHIFT); val |= 1; isif_write(isif->isif_cfg.base_addr, val, DFCMEMCTL); @@ -1135,7 +1135,7 @@ static int isif_config_raw(struct v4l2_subdev *sd, int mode) isif_write(isif->isif_cfg.base_addr, val, CGAMMAWD); /* Configure DPCM compression settings */ if (params->v4l2_pix_fmt == V4L2_PIX_FMT_SGRBG10DPCM8) { - val = 1 << ISIF_DPCM_EN_SHIFT; + val = BIT(ISIF_DPCM_EN_SHIFT); val |= (params->dpcm_predictor & ISIF_DPCM_PREDICTOR_MASK) << ISIF_DPCM_PREDICTOR_SHIFT; } -- cgit v1.2.3-59-g8ed1b From 814434984a5d2063ac15d7ff9a46075600ff1805 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 13 Jul 2017 11:23:44 -0400 Subject: media: omap3isp: Don't rely on devm for memory resource management devm functions are fine for managing resources that are directly related to the device at hand and that have no other dependencies. However, a process holding a file handle to a device created by a driver for a device may result in the file handle left behind after the device is long gone. This will result in accessing released (and potentially reallocated) memory. Instead, manage the memory resources in the driver. Releasing the resources can be later on bound to e.g. by releasing a reference. Signed-off-by: Sakari Ailus Acked-by: Hans Verkuil Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 16 +++++++++++----- drivers/media/platform/omap3isp/isph3a_aewb.c | 24 +++++++++++++++++------- drivers/media/platform/omap3isp/isph3a_af.c | 24 +++++++++++++++++------- drivers/media/platform/omap3isp/isphist.c | 11 +++++++---- drivers/media/platform/omap3isp/ispstat.c | 2 ++ 5 files changed, 54 insertions(+), 23 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index bd57174d81a7..5f30b802d319 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2006,6 +2006,8 @@ static int isp_remove(struct platform_device *pdev) media_entity_enum_cleanup(&isp->crashed); v4l2_async_notifier_cleanup(&isp->notifier); + kfree(isp); + return 0; } @@ -2196,7 +2198,7 @@ static int isp_probe(struct platform_device *pdev) int ret; int i, m; - isp = devm_kzalloc(&pdev->dev, sizeof(*isp), GFP_KERNEL); + isp = kzalloc(sizeof(*isp), GFP_KERNEL); if (!isp) { dev_err(&pdev->dev, "could not allocate memory\n"); return -ENOMEM; @@ -2205,17 +2207,19 @@ static int isp_probe(struct platform_device *pdev) ret = fwnode_property_read_u32(of_fwnode_handle(pdev->dev.of_node), "ti,phy-type", &isp->phy_type); if (ret) - return ret; + goto error_release_isp; isp->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "syscon"); - if (IS_ERR(isp->syscon)) - return PTR_ERR(isp->syscon); + if (IS_ERR(isp->syscon)) { + ret = PTR_ERR(isp->syscon); + goto error_release_isp; + } ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &isp->syscon_offset); if (ret) - return ret; + goto error_release_isp; isp->autoidle = autoidle; @@ -2372,6 +2376,8 @@ error_isp: error: v4l2_async_notifier_cleanup(&isp->notifier); mutex_destroy(&isp->isp_mutex); +error_release_isp: + kfree(isp); return ret; } diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index 3c82dea4d375..2cefc30e7b18 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -291,9 +291,10 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) { struct ispstat *aewb = &isp->isp_aewb; struct omap3isp_h3a_aewb_config *aewb_cfg; - struct omap3isp_h3a_aewb_config *aewb_recover_cfg; + struct omap3isp_h3a_aewb_config *aewb_recover_cfg = NULL; + int ret; - aewb_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_cfg), GFP_KERNEL); + aewb_cfg = kzalloc(sizeof(*aewb_cfg), GFP_KERNEL); if (!aewb_cfg) return -ENOMEM; @@ -303,12 +304,12 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) aewb->isp = isp; /* Set recover state configuration */ - aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg), - GFP_KERNEL); + aewb_recover_cfg = kzalloc(sizeof(*aewb_recover_cfg), GFP_KERNEL); if (!aewb_recover_cfg) { dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for recover configuration.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } aewb_recover_cfg->saturation_limit = OMAP3ISP_AEWB_MAX_SATURATION_LIM; @@ -325,13 +326,22 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) { dev_err(aewb->isp->dev, "AEWB: recover configuration is invalid.\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } aewb_recover_cfg->buf_size = h3a_aewb_get_buf_size(aewb_recover_cfg); aewb->recover_priv = aewb_recover_cfg; - return omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); + ret = omap3isp_stat_init(aewb, "AEWB", &h3a_aewb_subdev_ops); + +err: + if (ret) { + kfree(aewb_cfg); + kfree(aewb_recover_cfg); + } + + return ret; } /* diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 4da25c84f0c6..843ec1dc5c9d 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -354,9 +354,10 @@ int omap3isp_h3a_af_init(struct isp_device *isp) { struct ispstat *af = &isp->isp_af; struct omap3isp_h3a_af_config *af_cfg; - struct omap3isp_h3a_af_config *af_recover_cfg; + struct omap3isp_h3a_af_config *af_recover_cfg = NULL; + int ret; - af_cfg = devm_kzalloc(isp->dev, sizeof(*af_cfg), GFP_KERNEL); + af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL); if (af_cfg == NULL) return -ENOMEM; @@ -366,12 +367,12 @@ int omap3isp_h3a_af_init(struct isp_device *isp) af->isp = isp; /* Set recover state configuration */ - af_recover_cfg = devm_kzalloc(isp->dev, sizeof(*af_recover_cfg), - GFP_KERNEL); + af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL); if (!af_recover_cfg) { dev_err(af->isp->dev, "AF: cannot allocate memory for recover configuration.\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN; @@ -383,13 +384,22 @@ int omap3isp_h3a_af_init(struct isp_device *isp) if (h3a_af_validate_params(af, af_recover_cfg)) { dev_err(af->isp->dev, "AF: recover configuration is invalid.\n"); - return -EINVAL; + ret = -EINVAL; + goto err; } af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg); af->recover_priv = af_recover_cfg; - return omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); + ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); + +err: + if (ret) { + kfree(af_cfg); + kfree(af_recover_cfg); + } + + return ret; } void omap3isp_h3a_af_cleanup(struct isp_device *isp) diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index d4be3d0e06f9..3b9ed8086387 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -478,9 +478,9 @@ int omap3isp_hist_init(struct isp_device *isp) { struct ispstat *hist = &isp->isp_hist; struct omap3isp_hist_config *hist_cfg; - int ret = -1; + int ret; - hist_cfg = devm_kzalloc(isp->dev, sizeof(*hist_cfg), GFP_KERNEL); + hist_cfg = kzalloc(sizeof(*hist_cfg), GFP_KERNEL); if (hist_cfg == NULL) return -ENOMEM; @@ -502,7 +502,7 @@ int omap3isp_hist_init(struct isp_device *isp) if (IS_ERR(hist->dma_ch)) { ret = PTR_ERR(hist->dma_ch); if (ret == -EPROBE_DEFER) - return ret; + goto err; hist->dma_ch = NULL; dev_warn(isp->dev, @@ -518,9 +518,12 @@ int omap3isp_hist_init(struct isp_device *isp) hist->event_type = V4L2_EVENT_OMAP3ISP_HIST; ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); + +err: if (ret) { - if (hist->dma_ch) + if (!IS_ERR_OR_NULL(hist->dma_ch)) dma_release_channel(hist->dma_ch); + kfree(hist_cfg); } return ret; diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 953a812bfe5e..46a42c5dc1cc 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -1078,4 +1078,6 @@ void omap3isp_stat_cleanup(struct ispstat *stat) mutex_destroy(&stat->ioctl_lock); isp_stat_bufs_free(stat); kfree(stat->buf); + kfree(stat->priv); + kfree(stat->recover_priv); } -- cgit v1.2.3-59-g8ed1b From dd9a00ab9c3e14effc3f34b43e04504d05676fc9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 20 Feb 2017 10:22:18 -0500 Subject: media: omap3isp: Call video_unregister_device() unconditionally video_unregister_device() can be called on a never or an already unregistered device. Drop the redundant check. Signed-off-by: Sakari Ailus Reviewed-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/ispvideo.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 078d64114b24..175bbed9a235 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -1495,6 +1495,5 @@ 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)) - video_unregister_device(&video->video); + video_unregister_device(&video->video); } -- cgit v1.2.3-59-g8ed1b From 05a7c22c2f681bf7458bec21eb76e91e6b8713ca Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Tue, 15 Aug 2017 07:23:42 -0400 Subject: media: omap3isp: constify platform_device_id platform_device_id are not supposed to change at runtime. All functions working with platform_device_id provided by work with const platform_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 5f30b802d319..008933beebe0 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2389,7 +2389,7 @@ static const struct dev_pm_ops omap3isp_pm_ops = { .complete = isp_pm_complete, }; -static struct platform_device_id omap3isp_id_table[] = { +static const struct platform_device_id omap3isp_id_table[] = { { "omap3isp", 0 }, { }, }; -- cgit v1.2.3-59-g8ed1b From 69fbb3f47327d959830c94bf31893972b8c8f700 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Thu, 30 May 2019 03:25:49 -0400 Subject: media: wl128x: Fix some error handling in fm_v4l2_init_video_device() X-Originating-IP: [10.175.113.25] X-CFilter-Loop: Reflected The fm_v4l2_init_video_device() forget to unregister v4l2/video device in the error path, it could lead to UAF issue, eg, BUG: KASAN: use-after-free in atomic64_read include/asm-generic/atomic-instrumented.h:836 [inline] BUG: KASAN: use-after-free in atomic_long_read include/asm-generic/atomic-long.h:28 [inline] BUG: KASAN: use-after-free in __mutex_unlock_slowpath+0x92/0x690 kernel/locking/mutex.c:1206 Read of size 8 at addr ffff8881e84a7c70 by task v4l_id/3659 CPU: 1 PID: 3659 Comm: v4l_id Not tainted 5.1.0 #8 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1ubuntu1 04/01/2014 Call Trace: __dump_stack lib/dump_stack.c:77 [inline] dump_stack+0xa9/0x10e lib/dump_stack.c:113 print_address_description+0x65/0x270 mm/kasan/report.c:187 kasan_report+0x149/0x18d mm/kasan/report.c:317 atomic64_read include/asm-generic/atomic-instrumented.h:836 [inline] atomic_long_read include/asm-generic/atomic-long.h:28 [inline] __mutex_unlock_slowpath+0x92/0x690 kernel/locking/mutex.c:1206 fm_v4l2_fops_open+0xac/0x120 [fm_drv] v4l2_open+0x191/0x390 [videodev] chrdev_open+0x20d/0x570 fs/char_dev.c:417 do_dentry_open+0x700/0xf30 fs/open.c:777 do_last fs/namei.c:3416 [inline] path_openat+0x7c4/0x2a90 fs/namei.c:3532 do_filp_open+0x1a5/0x2b0 fs/namei.c:3563 do_sys_open+0x302/0x490 fs/open.c:1069 do_syscall_64+0x9f/0x450 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe RIP: 0033:0x7f8180c17c8e ... Allocated by task 3642: set_track mm/kasan/common.c:87 [inline] __kasan_kmalloc.constprop.3+0xa0/0xd0 mm/kasan/common.c:497 fm_drv_init+0x13/0x1000 [fm_drv] do_one_initcall+0xbc/0x47d init/main.c:901 do_init_module+0x1b5/0x547 kernel/module.c:3456 load_module+0x6405/0x8c10 kernel/module.c:3804 __do_sys_finit_module+0x162/0x190 kernel/module.c:3898 do_syscall_64+0x9f/0x450 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe Freed by task 3642: set_track mm/kasan/common.c:87 [inline] __kasan_slab_free+0x130/0x180 mm/kasan/common.c:459 slab_free_hook mm/slub.c:1429 [inline] slab_free_freelist_hook mm/slub.c:1456 [inline] slab_free mm/slub.c:3003 [inline] kfree+0xe1/0x270 mm/slub.c:3958 fm_drv_init+0x1e6/0x1000 [fm_drv] do_one_initcall+0xbc/0x47d init/main.c:901 do_init_module+0x1b5/0x547 kernel/module.c:3456 load_module+0x6405/0x8c10 kernel/module.c:3804 __do_sys_finit_module+0x162/0x190 kernel/module.c:3898 do_syscall_64+0x9f/0x450 arch/x86/entry/common.c:290 entry_SYSCALL_64_after_hwframe+0x49/0xbe Add relevant unregister functions to fix it. Cc: Hans Verkuil Reported-by: Hulk Robot Signed-off-by: Kefeng Wang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_v4l2.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index e25fd4d4d280..a1eaea19a81c 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -550,6 +550,7 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) /* Register with V4L2 subsystem as RADIO device */ if (video_register_device(&gradio_dev, VFL_TYPE_RADIO, radio_nr)) { + v4l2_device_unregister(&fmdev->v4l2_dev); fmerr("Could not register video device\n"); return -ENOMEM; } @@ -563,6 +564,8 @@ int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) if (ret < 0) { fmerr("(fmdev): Can't init ctrl handler\n"); v4l2_ctrl_handler_free(&fmdev->ctrl_handler); + video_unregister_device(fmdev->radio_dev); + v4l2_device_unregister(&fmdev->v4l2_dev); return -EBUSY; } -- cgit v1.2.3-59-g8ed1b From e867110a9a3241196613816d5bfd4688ebac15bb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 30 May 2019 02:45:48 -0400 Subject: media: dvb-usb/cxusb-analog.c: fix coccinelle warning, use ktime.h This patch fixes a coccinelle warning and includes ktime.h instead of timekeeping.h. The first includes the latter, but the latter doesn't exist before 3.17, causing problems for our compat build. It's easier to just use ktime.h instead. coccinelle warnings: (new ones prefixed by >>) >> drivers/media/usb/dvb-usb/cxusb-analog.c:1498:41-42: WARNING: Use ARRAY_SIZE Signed-off-by: Hans Verkuil Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb-analog.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index 9b42ca71c177..9b4f17ec63d3 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -1622,8 +1622,7 @@ int cxusb_medion_analog_init(struct dvb_usb_device *dvbdev) /* TODO: setup audio samples insertion */ ret = v4l2_subdev_call(cxdev->cx25840, core, s_io_pin_config, - sizeof(cxusub_medion_pin_config) / - sizeof(cxusub_medion_pin_config[0]), + ARRAY_SIZE(cxusub_medion_pin_config), cxusub_medion_pin_config); if (ret != 0) dev_warn(&dvbdev->udev->dev, -- cgit v1.2.3-59-g8ed1b From 7f9d5ac8e1e5af43a899110ddaa0b0c9374d1909 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 30 May 2019 14:59:24 -0400 Subject: media: cx23885: remove redundant assignment to err The variable err is assigned with a value that is never read and it is re-assigned a new value later on. The assignment is redundant and can be removed. Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-dvb.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index e2e63f05645e..13595fcb6a40 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2657,8 +2657,6 @@ int cx23885_dvb_register(struct cx23885_tsport *port) dev->pci_bus, dev->pci_slot); - err = -ENODEV; - /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ pr_info("%s: cx23885 based dvb card\n", dev->name); -- cgit v1.2.3-59-g8ed1b From 9f7406d6b56b4b71a12480b68221755ea7b3e0ee Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Fri, 31 May 2019 06:33:15 -0400 Subject: media: platform: ao-cec-g12a: disable regmap fast_io for cec bus regmap With fast_io enabled, spinlock_irq is used for read/write operations, thus leading to : BUG: sleeping function called from invalid context at [snip]/ao-cec-g12a.c:379 in_atomic(): 1, irqs_disabled(): 128, pid: 1451, name: irq/14-ff800280 [snip] Call trace: dump_backtrace+0x0/0x180 show_stack+0x14/0x1c dump_stack+0xa8/0xe0 ___might_sleep+0xf4/0x104 __might_sleep+0x4c/0x80 meson_ao_cec_g12a_read+0x7c/0x164 regmap_read+0x16c/0x1b0 meson_ao_cec_g12a_irq_thread+0xcc/0x200 irq_thread_fn+0x2c/0x60 irq_thread+0x14c/0x1fc kthread+0x11c/0x12c ret_from_fork+0x10/0x18 Simply remove fast_io to use mutexes instead. Fixes: b7778c46683c ("media: platform: meson: Add Amlogic Meson G12A AO CEC Controller driver") Signed-off-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/meson/ao-cec-g12a.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c index 3620a1e310f5..ddfd060625da 100644 --- a/drivers/media/platform/meson/ao-cec-g12a.c +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -415,7 +415,6 @@ static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { .reg_read = meson_ao_cec_g12a_read, .reg_write = meson_ao_cec_g12a_write, .max_register = 0xffff, - .fast_io = true, }; static inline void -- cgit v1.2.3-59-g8ed1b From 1ddc8a9732fb869e01363fc7b71d6ec684264ed9 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 4 Jun 2019 03:06:24 -0400 Subject: media: v4l2: Make sure all drivers set _MPLANE caps in vdev->device_caps This is needed if we want the core to be able to check _MPLANE support without having to call the ->vidioc_querycap() hook. Signed-off-by: Boris Brezillon Reviewed-by: Laurent Pinchart Reviewed-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 ++-- drivers/media/platform/exynos4-is/common.c | 5 +---- drivers/media/platform/exynos4-is/common.h | 3 +-- drivers/media/platform/exynos4-is/fimc-capture.c | 4 ++-- drivers/media/platform/exynos4-is/fimc-isp-video.c | 3 ++- drivers/media/platform/exynos4-is/fimc-lite.c | 4 +--- drivers/media/platform/exynos4-is/fimc-m2m.c | 4 ++-- drivers/media/platform/rcar_jpu.c | 6 ++++-- drivers/media/platform/s5p-mfc/s5p_mfc.c | 2 ++ drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 7 ------- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 7 ------- drivers/media/platform/ti-vpe/vpe.c | 3 +-- 12 files changed, 18 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index c757f5d98bcc..cd02e3c233fc 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -298,8 +298,6 @@ static int gsc_m2m_querycap(struct file *file, void *fh, strscpy(cap->card, GSC_MODULE_NAME " gscaler", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&gsc->pdev->dev)); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -763,6 +761,8 @@ int gsc_register_m2m_device(struct gsc_dev *gsc) gsc->vdev.lock = &gsc->lock; gsc->vdev.vfl_dir = VFL_DIR_M2M; gsc->vdev.v4l2_dev = &gsc->v4l2_dev; + gsc->vdev.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; snprintf(gsc->vdev.name, sizeof(gsc->vdev.name), "%s.%d:m2m", GSC_MODULE_NAME, gsc->id); diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c index 76f557548dfc..d47a77c8d4d6 100644 --- a/drivers/media/platform/exynos4-is/common.c +++ b/drivers/media/platform/exynos4-is/common.c @@ -37,15 +37,12 @@ struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity) } EXPORT_SYMBOL(fimc_find_remote_sensor); -void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap, - unsigned int caps) +void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap) { strscpy(cap->driver, dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, dev->driver->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(dev)); - cap->device_caps = caps; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; } EXPORT_SYMBOL(__fimc_vidioc_querycap); diff --git a/drivers/media/platform/exynos4-is/common.h b/drivers/media/platform/exynos4-is/common.h index 75b9c71d9419..58da94e7910c 100644 --- a/drivers/media/platform/exynos4-is/common.h +++ b/drivers/media/platform/exynos4-is/common.h @@ -12,5 +12,4 @@ #include struct v4l2_subdev *fimc_find_remote_sensor(struct media_entity *entity); -void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap, - unsigned int caps); +void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap); diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index de4af0357a3c..ecfa6ab4a19d 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -728,8 +728,7 @@ static int fimc_cap_querycap(struct file *file, void *priv, { struct fimc_dev *fimc = video_drvdata(file); - __fimc_vidioc_querycap(&fimc->pdev->dev, cap, V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_CAPTURE_MPLANE); + __fimc_vidioc_querycap(&fimc->pdev->dev, cap); return 0; } @@ -1765,6 +1764,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, vfd->release = video_device_release_empty; vfd->queue = q; vfd->lock = &fimc->lock; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; video_set_drvdata(vfd, fimc); vid_cap = &fimc->vid_cap; diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index bb35a2017f21..ad8dd672d4a7 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -349,7 +349,7 @@ static int isp_video_querycap(struct file *file, void *priv, { struct fimc_isp *isp = video_drvdata(file); - __fimc_vidioc_querycap(&isp->pdev->dev, cap, V4L2_CAP_STREAMING); + __fimc_vidioc_querycap(&isp->pdev->dev, cap); return 0; } @@ -614,6 +614,7 @@ int fimc_isp_video_device_register(struct fimc_isp *isp, vdev->minor = -1; vdev->release = video_device_release_empty; vdev->lock = &isp->video_lock; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE_MPLANE; iv->pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&vdev->entity, 1, &iv->pad); diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index 96f0a8a0dcae..a16b5bed59bb 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -658,9 +658,6 @@ static int fimc_lite_querycap(struct file *file, void *priv, strscpy(cap->card, FIMC_LITE_DRV_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&fimc->pdev->dev)); - - cap->device_caps = V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1282,6 +1279,7 @@ static int fimc_lite_subdev_registered(struct v4l2_subdev *sd) vfd->minor = -1; vfd->release = video_device_release_empty; vfd->queue = q; + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING; fimc->reqbufs_count = 0; INIT_LIST_HEAD(&fimc->pending_buf_q); diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 1bea1ce4091e..17e5bf4810f4 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -236,9 +236,8 @@ static int fimc_m2m_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { struct fimc_dev *fimc = video_drvdata(file); - unsigned int caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - __fimc_vidioc_querycap(&fimc->pdev->dev, cap, caps); + __fimc_vidioc_querycap(&fimc->pdev->dev, cap); return 0; } @@ -736,6 +735,7 @@ int fimc_register_m2m_device(struct fimc_dev *fimc, vfd->release = video_device_release_empty; vfd->lock = &fimc->lock; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "fimc.%d.m2m", fimc->id); diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index 1dfd2eb65920..9b6eadef6858 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -671,8 +671,6 @@ static int jpu_querycap(struct file *file, void *priv, strscpy(cap->driver, DRV_NAME, sizeof(cap->driver)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(ctx->jpu->dev)); - cap->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M_MPLANE; - cap->capabilities = V4L2_CAP_DEVICE_CAPS | cap->device_caps; memset(cap->reserved, 0, sizeof(cap->reserved)); return 0; @@ -1662,6 +1660,8 @@ static int jpu_probe(struct platform_device *pdev) jpu->vfd_encoder.lock = &jpu->mutex; jpu->vfd_encoder.v4l2_dev = &jpu->v4l2_dev; jpu->vfd_encoder.vfl_dir = VFL_DIR_M2M; + jpu->vfd_encoder.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; ret = video_register_device(&jpu->vfd_encoder, VFL_TYPE_GRABBER, -1); if (ret) { @@ -1679,6 +1679,8 @@ static int jpu_probe(struct platform_device *pdev) jpu->vfd_decoder.lock = &jpu->mutex; jpu->vfd_decoder.v4l2_dev = &jpu->v4l2_dev; jpu->vfd_decoder.vfl_dir = VFL_DIR_M2M; + jpu->vfd_decoder.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_M2M_MPLANE; ret = video_register_device(&jpu->vfd_decoder, VFL_TYPE_GRABBER, -1); if (ret) { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 9a53d3908b52..6ff57018a353 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1348,6 +1348,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; set_bit(V4L2_FL_QUIRK_INVERTED_CROP, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_DEC_NAME); dev->vfd_dec = vfd; @@ -1366,6 +1367,7 @@ static int s5p_mfc_probe(struct platform_device *pdev) vfd->lock = &dev->mfc_mutex; vfd->v4l2_dev = &dev->v4l2_dev; vfd->vfl_dir = VFL_DIR_M2M; + vfd->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; snprintf(vfd->name, sizeof(vfd->name), "%s", S5P_MFC_ENC_NAME); dev->vfd_enc = vfd; video_set_drvdata(vfd, dev); diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index e111f9c47179..d29e5bc73651 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -275,13 +275,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, dev->vfd_dec->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&dev->plat_dev->dev)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 5505e4fc2090..5ab1231b4189 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1317,13 +1317,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, dev->vfd_enc->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", dev_name(&dev->plat_dev->dev)); - /* - * This is only a mem-to-mem video device. The capture and output - * device capability flags are left only for backward compatibility - * and are scheduled for removal. - */ - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1e40eafec284..a61ac426853a 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1495,8 +1495,6 @@ static int vpe_querycap(struct file *file, void *priv, strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", VPE_MODULE_NAME); - cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -2411,6 +2409,7 @@ static const struct video_device vpe_videodev = { .minor = -1, .release = video_device_release_empty, .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, }; static const struct v4l2_m2m_ops m2m_ops = { -- cgit v1.2.3-59-g8ed1b From 7e98b7b542a456582ea3029be857cc99a3b19bd5 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Tue, 4 Jun 2019 03:06:25 -0400 Subject: media: v4l2: Get rid of ->vidioc_enum_fmt_vid_{cap, out}_mplane Support for multiplanar and singleplanar formats is mutually exclusive, at least in practice. In our attempt to unify support for support for mplane and !mplane in v4l, let's get rid of the ->vidioc_enum_fmt_{vid,out}_cap_mplane() hooks and call ->vidioc_enum_fmt_{vid,out}_cap() instead. Signed-off-by: Boris Brezillon Reviewed-by: Sylwester Nawrocki [hverkuil-cisco@xs4all.nl: fix typos: pirv -> priv and prov -> priv] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/intel/ipu3/ipu3-cio2.c | 2 +- drivers/media/platform/exynos-gsc/gsc-core.c | 2 +- drivers/media/platform/exynos-gsc/gsc-core.h | 2 +- drivers/media/platform/exynos-gsc/gsc-m2m.c | 10 +++++----- drivers/media/platform/exynos4-is/fimc-capture.c | 6 +++--- drivers/media/platform/exynos4-is/fimc-isp-video.c | 6 +++--- drivers/media/platform/exynos4-is/fimc-lite.c | 6 +++--- drivers/media/platform/exynos4-is/fimc-m2m.c | 8 ++++---- drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 4 ++-- drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 18 +++++++++--------- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 12 ++++++------ drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 12 ++++++------ drivers/media/platform/qcom/camss/camss-video.c | 2 +- drivers/media/platform/qcom/venus/vdec.c | 4 ++-- drivers/media/platform/qcom/venus/venc.c | 4 ++-- drivers/media/platform/rcar_fdp1.c | 4 ++-- drivers/media/platform/rcar_jpu.c | 4 ++-- drivers/media/platform/renesas-ceu.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 12 ++++++------ drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 12 ++++++------ drivers/media/platform/ti-vpe/vpe.c | 4 ++-- drivers/media/platform/vicodec/vicodec-core.c | 2 -- drivers/media/platform/vivid/vivid-core.c | 6 ++---- drivers/media/platform/vivid/vivid-vid-common.c | 20 -------------------- drivers/media/platform/vivid/vivid-vid-common.h | 2 -- drivers/media/v4l2-core/v4l2-dev.c | 2 -- drivers/media/v4l2-core/v4l2-ioctl.c | 21 +++++++++++---------- drivers/staging/media/ipu3/ipu3-v4l2.c | 4 ++-- .../staging/media/rockchip/vpu/rockchip_vpu_v4l2.c | 12 ++++++------ include/media/v4l2-ioctl.h | 14 ++------------ 30 files changed, 91 insertions(+), 128 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index 2a52a393fe74..c1d133e17e4b 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1174,7 +1174,7 @@ static const struct v4l2_file_operations cio2_v4l2_fops = { static const struct v4l2_ioctl_ops cio2_v4l2_ioctl_ops = { .vidioc_querycap = cio2_v4l2_querycap, - .vidioc_enum_fmt_vid_cap_mplane = cio2_v4l2_enum_fmt, + .vidioc_enum_fmt_vid_cap = cio2_v4l2_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = cio2_v4l2_g_fmt, .vidioc_s_fmt_vid_cap_mplane = cio2_v4l2_s_fmt, .vidioc_try_fmt_vid_cap_mplane = cio2_v4l2_try_fmt, diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 0fa3ec04ab7b..f1d555f47ce3 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -331,7 +331,7 @@ void gsc_check_src_scale_info(struct gsc_variant *var, } } -int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f) +int gsc_enum_fmt(struct v4l2_fmtdesc *f) { const struct gsc_fmt *fmt; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index c81f0a17d286..8ea49ca004fd 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -387,7 +387,7 @@ void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state); u32 get_plane_size(struct gsc_frame *fr, unsigned int plane); const struct gsc_fmt *get_format(int index); const struct gsc_fmt *find_fmt(u32 *pixelformat, u32 *mbus_code, u32 index); -int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f); +int gsc_enum_fmt(struct v4l2_fmtdesc *f); int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f); void gsc_set_frame_size(struct gsc_frame *frame, int width, int height); int gsc_g_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f); diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index cd02e3c233fc..6346694f7de8 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -301,10 +301,10 @@ static int gsc_m2m_querycap(struct file *file, void *fh, return 0; } -static int gsc_m2m_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int gsc_m2m_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - return gsc_enum_fmt_mplane(f); + return gsc_enum_fmt(f); } static int gsc_m2m_g_fmt_mplane(struct file *file, void *fh, @@ -560,8 +560,8 @@ static int gsc_m2m_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops gsc_m2m_ioctl_ops = { .vidioc_querycap = gsc_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = gsc_m2m_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = gsc_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = gsc_m2m_enum_fmt, + .vidioc_enum_fmt_vid_out = gsc_m2m_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = gsc_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = gsc_m2m_g_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = gsc_m2m_try_fmt_mplane, diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index ecfa6ab4a19d..84b91e248c5a 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -732,8 +732,8 @@ static int fimc_cap_querycap(struct file *file, void *priv, return 0; } -static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_cap_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct fimc_fmt *fmt; @@ -1360,7 +1360,7 @@ static int fimc_cap_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_querycap = fimc_cap_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_cap_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = fimc_cap_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = fimc_cap_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_cap_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = fimc_cap_g_fmt_mplane, diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c index ad8dd672d4a7..2226a13ac89b 100644 --- a/drivers/media/platform/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c @@ -353,8 +353,8 @@ static int isp_video_querycap(struct file *file, void *priv, return 0; } -static int isp_video_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int isp_video_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { const struct fimc_fmt *fmt; @@ -551,7 +551,7 @@ static int isp_video_reqbufs(struct file *file, void *priv, static const struct v4l2_ioctl_ops isp_video_ioctl_ops = { .vidioc_querycap = isp_video_querycap, - .vidioc_enum_fmt_vid_cap_mplane = isp_video_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = isp_video_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = isp_video_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = isp_video_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = isp_video_g_fmt_mplane, diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c index a16b5bed59bb..e71342756d88 100644 --- a/drivers/media/platform/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/exynos4-is/fimc-lite.c @@ -661,8 +661,8 @@ static int fimc_lite_querycap(struct file *file, void *priv, return 0; } -static int fimc_lite_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_lite_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { const struct fimc_fmt *fmt; @@ -951,7 +951,7 @@ static int fimc_lite_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops fimc_lite_ioctl_ops = { .vidioc_querycap = fimc_lite_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_lite_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = fimc_lite_enum_fmt, .vidioc_try_fmt_vid_cap_mplane = fimc_lite_try_fmt_mplane, .vidioc_s_fmt_vid_cap_mplane = fimc_lite_s_fmt_mplane, .vidioc_g_fmt_vid_cap_mplane = fimc_lite_g_fmt_mplane, diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 17e5bf4810f4..0d1d8b717d9a 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -241,8 +241,8 @@ static int fimc_m2m_querycap(struct file *file, void *fh, return 0; } -static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int fimc_m2m_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { struct fimc_fmt *fmt; @@ -532,8 +532,8 @@ static int fimc_m2m_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_querycap = fimc_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fimc_m2m_enum_fmt_mplane, - .vidioc_enum_fmt_vid_out_mplane = fimc_m2m_enum_fmt_mplane, + .vidioc_enum_fmt_vid_cap = fimc_m2m_enum_fmt, + .vidioc_enum_fmt_vid_out = fimc_m2m_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = fimc_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = fimc_m2m_g_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = fimc_m2m_try_fmt_mplane, diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index f761e4d8bf2a..3b199662cb34 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -536,8 +536,8 @@ end: static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = { .vidioc_querycap = mtk_jpeg_querycap, - .vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out, .vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane, .vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane, .vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane, diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index 7d15c06e9db9..365d3f92fd9e 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -620,7 +620,7 @@ static int mtk_mdp_m2m_querycap(struct file *file, void *fh, return 0; } -static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type) +static int mtk_mdp_enum_fmt(struct v4l2_fmtdesc *f, u32 type) { const struct mtk_mdp_fmt *fmt; @@ -633,16 +633,16 @@ static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type) return 0; } -static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int mtk_mdp_m2m_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); } -static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int mtk_mdp_m2m_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { - return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + return mtk_mdp_enum_fmt(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); } static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, @@ -935,8 +935,8 @@ static int mtk_mdp_m2m_s_selection(struct file *file, void *fh, static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = { .vidioc_querycap = mtk_mdp_m2m_querycap, - .vidioc_enum_fmt_vid_cap_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_out, + .vidioc_enum_fmt_vid_cap = mtk_mdp_m2m_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = mtk_mdp_m2m_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = mtk_mdp_m2m_g_fmt_mplane, .vidioc_g_fmt_vid_out_mplane = mtk_mdp_m2m_g_fmt_mplane, .vidioc_try_fmt_vid_cap_mplane = mtk_mdp_m2m_try_fmt_mplane, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 851903867bc9..ebf919509e8c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -957,14 +957,14 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) return 0; } -static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_vdec_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, false); } -static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int vidioc_vdec_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, true); } @@ -1461,8 +1461,8 @@ const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = { .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_vdec_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_vdec_enum_fmt_vid_out, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_querycap = vidioc_vdec_querycap, diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 50351adafc47..2c92ee4f0c8c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -207,14 +207,14 @@ static int vidioc_enum_framesizes(struct file *file, void *fh, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, false); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(f, true); } @@ -725,8 +725,8 @@ const struct v4l2_ioctl_ops mtk_venc_ioctl_ops = { .vidioc_dqbuf = vidioc_venc_dqbuf, .vidioc_querycap = vidioc_venc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_enum_framesizes = vidioc_enum_framesizes, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c index 58aebe7114cd..1d50dfbbb762 100644 --- a/drivers/media/platform/qcom/camss/camss-video.c +++ b/drivers/media/platform/qcom/camss/camss-video.c @@ -703,7 +703,7 @@ static int video_s_input(struct file *file, void *fh, unsigned int input) static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = { .vidioc_querycap = video_querycap, - .vidioc_enum_fmt_vid_cap_mplane = video_enum_fmt, + .vidioc_enum_fmt_vid_cap = video_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = video_g_fmt, .vidioc_s_fmt_vid_cap_mplane = video_s_fmt, .vidioc_try_fmt_vid_cap_mplane = video_try_fmt, diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c index 282de21cf2e1..2a47b9b8c5bc 100644 --- a/drivers/media/platform/qcom/venus/vdec.c +++ b/drivers/media/platform/qcom/venus/vdec.c @@ -491,8 +491,8 @@ unlock: static const struct v4l2_ioctl_ops vdec_ioctl_ops = { .vidioc_querycap = vdec_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vdec_enum_fmt, - .vidioc_enum_fmt_vid_out_mplane = vdec_enum_fmt, + .vidioc_enum_fmt_vid_cap = vdec_enum_fmt, + .vidioc_enum_fmt_vid_out = vdec_enum_fmt, .vidioc_s_fmt_vid_cap_mplane = vdec_s_fmt, .vidioc_s_fmt_vid_out_mplane = vdec_s_fmt, .vidioc_g_fmt_vid_cap_mplane = vdec_g_fmt, diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c index 32cff294582f..406a47923996 100644 --- a/drivers/media/platform/qcom/venus/venc.c +++ b/drivers/media/platform/qcom/venus/venc.c @@ -616,8 +616,8 @@ static int venc_enum_frameintervals(struct file *file, void *fh, static const struct v4l2_ioctl_ops venc_ioctl_ops = { .vidioc_querycap = venc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = venc_enum_fmt, - .vidioc_enum_fmt_vid_out_mplane = venc_enum_fmt, + .vidioc_enum_fmt_vid_cap = venc_enum_fmt, + .vidioc_enum_fmt_vid_out = venc_enum_fmt, .vidioc_s_fmt_vid_cap_mplane = venc_s_fmt, .vidioc_s_fmt_vid_out_mplane = venc_s_fmt, .vidioc_g_fmt_vid_cap_mplane = venc_g_fmt, diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 6a90bc4c476e..6f9a4c69f620 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -1730,8 +1730,8 @@ static const char * const fdp1_ctrl_deint_menu[] = { static const struct v4l2_ioctl_ops fdp1_ioctl_ops = { .vidioc_querycap = fdp1_vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = fdp1_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out_mplane = fdp1_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = fdp1_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = fdp1_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = fdp1_g_fmt, .vidioc_g_fmt_vid_out_mplane = fdp1_g_fmt, .vidioc_try_fmt_vid_cap_mplane = fdp1_try_fmt, diff --git a/drivers/media/platform/rcar_jpu.c b/drivers/media/platform/rcar_jpu.c index 9b6eadef6858..1c3f507acfc9 100644 --- a/drivers/media/platform/rcar_jpu.c +++ b/drivers/media/platform/rcar_jpu.c @@ -946,8 +946,8 @@ static int jpu_streamon(struct file *file, void *priv, enum v4l2_buf_type type) static const struct v4l2_ioctl_ops jpu_ioctl_ops = { .vidioc_querycap = jpu_querycap, - .vidioc_enum_fmt_vid_cap_mplane = jpu_enum_fmt_cap, - .vidioc_enum_fmt_vid_out_mplane = jpu_enum_fmt_out, + .vidioc_enum_fmt_vid_cap = jpu_enum_fmt_cap, + .vidioc_enum_fmt_vid_out = jpu_enum_fmt_out, .vidioc_g_fmt_vid_cap_mplane = jpu_g_fmt, .vidioc_g_fmt_vid_out_mplane = jpu_g_fmt, .vidioc_try_fmt_vid_cap_mplane = jpu_try_fmt, diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c index 150196f7cf96..57d0c0f9fa4b 100644 --- a/drivers/media/platform/renesas-ceu.c +++ b/drivers/media/platform/renesas-ceu.c @@ -1339,7 +1339,7 @@ static int ceu_enum_frameintervals(struct file *file, void *fh, static const struct v4l2_ioctl_ops ceu_ioctl_ops = { .vidioc_querycap = ceu_querycap, - .vidioc_enum_fmt_vid_cap_mplane = ceu_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = ceu_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap_mplane = ceu_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap_mplane = ceu_s_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = ceu_g_fmt_vid_cap, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index d29e5bc73651..51ab2e38a270 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -306,14 +306,14 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return 0; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, true); } @@ -880,8 +880,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, /* v4l2_ioctl_ops */ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 5ab1231b4189..90622abe1aad 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1347,14 +1347,14 @@ static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, false); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, f, true); } @@ -2336,8 +2336,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh, static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt, diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index a61ac426853a..3f90f9413da1 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1971,12 +1971,12 @@ static const struct v4l2_ctrl_ops vpe_ctrl_ops = { static const struct v4l2_ioctl_ops vpe_ioctl_ops = { .vidioc_querycap = vpe_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt, + .vidioc_enum_fmt_vid_cap = vpe_enum_fmt, .vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt, .vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt, .vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt, - .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt, + .vidioc_enum_fmt_vid_out = vpe_enum_fmt, .vidioc_g_fmt_vid_out_mplane = vpe_g_fmt, .vidioc_try_fmt_vid_out_mplane = vpe_try_fmt, .vidioc_s_fmt_vid_out_mplane = vpe_s_fmt, diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 89961257f03f..03acdf86176e 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1297,7 +1297,6 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, @@ -1307,7 +1306,6 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 7047df6f0e0e..beb2e566a43c 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -500,20 +500,18 @@ static const struct v4l2_file_operations vivid_radio_fops = { static const struct v4l2_ioctl_ops vivid_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid, + .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_vid, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_mplane, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap_mplane, .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap_mplane, - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid, + .vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid, .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_mplane, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane, .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 74b83bcc6119..9307ce1cdd16 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -797,26 +797,6 @@ int vivid_enum_fmt_vid(struct file *file, void *priv, return 0; } -int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_enum_fmt_vid(file, priv, f); -} - -int vidioc_enum_fmt_vid(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return vivid_enum_fmt_vid(file, priv, f); -} - int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { struct vivid_dev *dev = video_drvdata(file); diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h index 29b6c0b40a1b..d908d9725283 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ b/drivers/media/platform/vivid/vivid-vid-common.h @@ -28,8 +28,6 @@ void vivid_send_source_change(struct vivid_dev *dev, unsigned type); int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_enum_fmt_vid_mplane(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index d7528f82a66a..29946a2b2752 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -593,11 +593,9 @@ static void determine_valid_ioctls(struct video_device *vdev) if (is_vid || is_tch) { /* video and metadata specific ioctls */ if ((is_rx && (ops->vidioc_enum_fmt_vid_cap || - ops->vidioc_enum_fmt_vid_cap_mplane || ops->vidioc_enum_fmt_vid_overlay || ops->vidioc_enum_fmt_meta_cap)) || (is_tx && (ops->vidioc_enum_fmt_vid_out || - ops->vidioc_enum_fmt_vid_out_mplane || ops->vidioc_enum_fmt_meta_out))) set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls); if ((is_rx && (ops->vidioc_g_fmt_vid_cap || diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 0fbee3caef5d..b4c73e8f23c5 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1382,6 +1382,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct file *file, void *fh, void *arg) { + struct video_device *vdev = video_devdata(file); struct v4l2_fmtdesc *p = arg; int ret = check_fmt(file, p->type); @@ -1391,30 +1392,30 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!!(vdev->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) != + (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) + break; + if (unlikely(!ops->vidioc_enum_fmt_vid_cap)) break; ret = ops->vidioc_enum_fmt_vid_cap(file, fh, arg); break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (unlikely(!ops->vidioc_enum_fmt_vid_cap_mplane)) - break; - ret = ops->vidioc_enum_fmt_vid_cap_mplane(file, fh, arg); - break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: if (unlikely(!ops->vidioc_enum_fmt_vid_overlay)) break; ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, arg); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (!!(vdev->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) != + (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) + break; + if (unlikely(!ops->vidioc_enum_fmt_vid_out)) break; ret = ops->vidioc_enum_fmt_vid_out(file, fh, arg); break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (unlikely(!ops->vidioc_enum_fmt_vid_out_mplane)) - break; - ret = ops->vidioc_enum_fmt_vid_out_mplane(file, fh, arg); - break; case V4L2_BUF_TYPE_SDR_CAPTURE: if (unlikely(!ops->vidioc_enum_fmt_sdr_cap)) break; diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index a7bc22040ed8..3c7ad1eed434 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -955,12 +955,12 @@ static const struct v4l2_file_operations imgu_v4l2_fops = { static const struct v4l2_ioctl_ops imgu_v4l2_ioctl_ops = { .vidioc_querycap = imgu_vidioc_querycap, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap_mplane = imgu_vidioc_g_fmt, .vidioc_s_fmt_vid_cap_mplane = imgu_vidioc_s_fmt, .vidioc_try_fmt_vid_cap_mplane = imgu_vidioc_try_fmt, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, .vidioc_g_fmt_vid_out_mplane = imgu_vidioc_g_fmt, .vidioc_s_fmt_vid_out_mplane = imgu_vidioc_s_fmt, .vidioc_try_fmt_vid_out_mplane = imgu_vidioc_try_fmt, diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c index 1b80a45df8fe..8bc709ab13be 100644 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c +++ b/drivers/staging/media/rockchip/vpu/rockchip_vpu_v4l2.c @@ -153,14 +153,14 @@ static int vidioc_enum_fmt(struct file *file, void *priv, return -EINVAL; } -static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, priv, f, true); } -static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f) +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) { return vidioc_enum_fmt(file, priv, f, false); } @@ -494,8 +494,8 @@ const struct v4l2_ioctl_ops rockchip_vpu_ioctl_ops = { .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_cap_mplane, .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_out_mplane, .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_cap_mplane, - .vidioc_enum_fmt_vid_out_mplane = vidioc_enum_fmt_vid_out_mplane, - .vidioc_enum_fmt_vid_cap_mplane = vidioc_enum_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index 8533ece5026e..400f2e46c108 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -26,19 +26,13 @@ struct v4l2_fh; * :ref:`VIDIOC_QUERYCAP ` ioctl * @vidioc_enum_fmt_vid_cap: pointer to the function that implements * :ref:`VIDIOC_ENUM_FMT ` ioctl logic - * for video capture in single plane mode + * for video capture in single and multi plane mode * @vidioc_enum_fmt_vid_overlay: pointer to the function that implements * :ref:`VIDIOC_ENUM_FMT ` ioctl logic * for video overlay * @vidioc_enum_fmt_vid_out: pointer to the function that implements * :ref:`VIDIOC_ENUM_FMT ` ioctl logic - * for video output in single plane mode - * @vidioc_enum_fmt_vid_cap_mplane: pointer to the function that implements - * :ref:`VIDIOC_ENUM_FMT ` ioctl logic - * for video capture in multiplane mode - * @vidioc_enum_fmt_vid_out_mplane: pointer to the function that implements - * :ref:`VIDIOC_ENUM_FMT ` ioctl logic - * for video output in multiplane mode + * for video output in single and multi plane mode * @vidioc_enum_fmt_sdr_cap: pointer to the function that implements * :ref:`VIDIOC_ENUM_FMT ` ioctl logic * for Software Defined Radio capture @@ -313,10 +307,6 @@ struct v4l2_ioctl_ops { struct v4l2_fmtdesc *f); int (*vidioc_enum_fmt_vid_out)(struct file *file, void *fh, struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_cap_mplane)(struct file *file, void *fh, - struct v4l2_fmtdesc *f); - int (*vidioc_enum_fmt_vid_out_mplane)(struct file *file, void *fh, - struct v4l2_fmtdesc *f); int (*vidioc_enum_fmt_sdr_cap)(struct file *file, void *fh, struct v4l2_fmtdesc *f); int (*vidioc_enum_fmt_sdr_out)(struct file *file, void *fh, -- cgit v1.2.3-59-g8ed1b From e83ce3005db16243e1085925251fd0776bb60d09 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Jun 2019 07:19:52 -0400 Subject: media: media/radio: set device_caps in struct video_device Instead of filling in the struct v4l2_capability device_caps field, fill in the struct video_device device_caps field. That way the V4L2 core knows what the capabilities of the video device are. But this only really works if all drivers use this, so convert all radio drivers in this patch. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/dsbr100.c | 3 +-- drivers/media/radio/radio-cadet.c | 5 ++--- drivers/media/radio/radio-isa.c | 4 +--- drivers/media/radio/radio-keene.c | 3 +-- drivers/media/radio/radio-ma901.c | 3 +-- drivers/media/radio/radio-miropcm20.c | 4 ++-- drivers/media/radio/radio-mr800.c | 5 ++--- drivers/media/radio/radio-raremono.c | 3 +-- drivers/media/radio/radio-sf16fmi.c | 3 +-- drivers/media/radio/radio-si476x.c | 21 ++++++++------------- drivers/media/radio/radio-tea5764.c | 3 +-- drivers/media/radio/radio-tea5777.c | 5 ++--- drivers/media/radio/radio-timb.c | 3 +-- drivers/media/radio/radio-wl1273.c | 12 ++++-------- drivers/media/radio/si470x/radio-si470x-i2c.c | 7 +++---- drivers/media/radio/si470x/radio-si470x-usb.c | 6 +++--- drivers/media/radio/si4713/radio-platform-si4713.c | 4 +--- drivers/media/radio/si4713/radio-usb-si4713.c | 4 +--- drivers/media/radio/tea575x.c | 7 +++---- drivers/media/radio/wl128x/fmdrv_v4l2.c | 10 +++------- 20 files changed, 42 insertions(+), 73 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index c9d51a5f2838..76a21b9d9ad6 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -177,8 +177,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "dsbr100", sizeof(v->driver)); strscpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -387,6 +385,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, radio->videodev.release = video_device_release_empty; radio->videodev.lock = &radio->v4l2_lock; radio->videodev.ctrl_handler = &radio->hdl; + radio->videodev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN * FREQ_MUL; diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 12160894839c..a5db9b4dc3de 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -357,9 +357,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "ADS Cadet", sizeof(v->driver)); strscpy(v->card, "ADS Cadet", sizeof(v->card)); strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | - V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -646,6 +643,8 @@ static int __init cadet_init(void) dev->vdev.ioctl_ops = &cadet_ioctl_ops; dev->vdev.release = video_device_release_empty; dev->vdev.lock = &dev->lock; + dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&dev->vdev, dev); res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 551de8a45b95..f9255ada9d87 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -45,9 +45,6 @@ static int radio_isa_querycap(struct file *file, void *priv, strscpy(v->driver, isa->drv->driver.driver.name, sizeof(v->driver)); strscpy(v->card, isa->drv->card, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", isa->v4l2_dev.name); - - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -248,6 +245,7 @@ static int radio_isa_common_probe(struct radio_isa_card *isa, isa->vdev.fops = &radio_isa_fops; isa->vdev.ioctl_ops = &radio_isa_ioctl_ops; isa->vdev.release = video_device_release_empty; + isa->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; video_set_drvdata(&isa->vdev, isa); isa->freq = FREQ_LOW; isa->stereo = drv->has_stereo; diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c index e9484b013073..40a051fcd761 100644 --- a/drivers/media/radio/radio-keene.c +++ b/drivers/media/radio/radio-keene.c @@ -177,8 +177,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-keene", sizeof(v->driver)); strscpy(v->card, "Keene FM Transmitter", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -370,6 +368,7 @@ static int usb_keene_probe(struct usb_interface *intf, radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; radio->vdev.vfl_dir = VFL_DIR_TX; + radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_MODULATOR; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c index 5cb153727841..33aa29748dbb 100644 --- a/drivers/media/radio/radio-ma901.c +++ b/drivers/media/radio/radio-ma901.c @@ -200,8 +200,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-ma901", sizeof(v->driver)); strscpy(v->card, "Masterkit MA901 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -407,6 +405,7 @@ static int usb_ma901radio_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops; radio->vdev.release = video_device_release_empty; radio->vdev.lock = &radio->lock; + radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c index 95d12cbff5c9..99788834c646 100644 --- a/drivers/media/radio/radio-miropcm20.c +++ b/drivers/media/radio/radio-miropcm20.c @@ -204,8 +204,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "Miro PCM20", sizeof(v->driver)); strscpy(v->card, "Miro PCM20", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -481,6 +479,8 @@ static int __init pcm20_init(void) dev->vdev.ioctl_ops = &pcm20_ioctl_ops; dev->vdev.release = video_device_release_empty; dev->vdev.lock = &dev->lock; + dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&dev->vdev, dev); snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO, dev->audmode == V4L2_TUNER_MODE_MONO, -1); diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index ab1324f68199..f090a3f56d86 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -269,9 +269,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-mr800", sizeof(v->driver)); strscpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER | - V4L2_CAP_HW_FREQ_SEEK; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -554,6 +551,8 @@ static int usb_amradio_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops; radio->vdev.release = video_device_release_empty; radio->vdev.lock = &radio->lock; + radio->vdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER | + V4L2_CAP_HW_FREQ_SEEK; radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 5e782b3c2fa9..606f588e1edf 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -184,8 +184,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-raremono", sizeof(v->driver)); strscpy(v->card, "Thanko's Raremono", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -345,6 +343,7 @@ static int usb_raremono_probe(struct usb_interface *intf, radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops; radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; + radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; usb_set_intfdata(intf, &radio->v4l2_dev); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 434c03338d7f..54a40d60e4fd 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -133,8 +133,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); strscpy(v->card, "SF16-FMI/FMP/FMD radio", sizeof(v->card)); strscpy(v->bus_info, "ISA:radio-sf16fmi", sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -345,6 +343,7 @@ static int __init fmi_init(void) fmi->vdev.fops = &fmi_fops; fmi->vdev.ioctl_ops = &fmi_ioctl_ops; fmi->vdev.release = video_device_release_empty; + fmi->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; video_set_drvdata(&fmi->vdev, fmi); mutex_init(&fmi->lock); diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c index 0261f4d28f16..0d5187410853 100644 --- a/drivers/media/radio/radio-si476x.c +++ b/drivers/media/radio/radio-si476x.c @@ -345,19 +345,6 @@ static int si476x_radio_querycap(struct file *file, void *priv, strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); snprintf(capability->bus_info, sizeof(capability->bus_info), "platform:%s", radio->v4l2dev.name); - - capability->device_caps = V4L2_CAP_TUNER - | V4L2_CAP_RADIO - | V4L2_CAP_HW_FREQ_SEEK; - - si476x_core_lock(radio->core); - if (!si476x_core_is_a_secondary_tuner(radio->core)) - capability->device_caps |= V4L2_CAP_RDS_CAPTURE - | V4L2_CAP_READWRITE; - si476x_core_unlock(radio->core); - - capability->capabilities = capability->device_caps - | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1468,6 +1455,14 @@ static int si476x_radio_probe(struct platform_device *pdev) radio->videodev.v4l2_dev = &radio->v4l2dev; radio->videodev.ioctl_ops = &si4761_ioctl_ops; + radio->videodev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_HW_FREQ_SEEK; + + si476x_core_lock(radio->core); + if (!si476x_core_is_a_secondary_tuner(radio->core)) + radio->videodev.device_caps |= V4L2_CAP_RDS_CAPTURE | + V4L2_CAP_READWRITE; + si476x_core_unlock(radio->core); video_set_drvdata(&radio->videodev, radio); platform_set_drvdata(pdev, radio); diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index 6632be648cea..fc8afbc0fb22 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -291,8 +291,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->card, dev->name, sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "I2C:%s", dev_name(&dev->dev)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -474,6 +472,7 @@ static int tea5764_i2c_probe(struct i2c_client *client, video_set_drvdata(&radio->vdev, radio); radio->vdev.lock = &radio->mutex; radio->vdev.v4l2_dev = v4l2_dev; + radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; /* initialize and power off the chip */ tea5764_i2c_read(radio); diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c index 61f751cf1aa4..17f9e21ff3c5 100644 --- a/drivers/media/radio/radio-tea5777.c +++ b/drivers/media/radio/radio-tea5777.c @@ -270,9 +270,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->card, tea->card, sizeof(v->card)); strlcat(v->card, " TEA5777", sizeof(v->card)); strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -563,6 +560,8 @@ int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner) strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); tea->vd.lock = &tea->mutex; tea->vd.v4l2_dev = tea->v4l2_dev; + tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_HW_FREQ_SEEK; tea->fops = tea575x_fops; tea->fops.owner = owner; tea->vd.fops = &tea->fops; diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c index 0eda863124e9..d92352005d3d 100644 --- a/drivers/media/radio/radio-timb.c +++ b/drivers/media/radio/radio-timb.c @@ -42,8 +42,6 @@ static int timbradio_vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, DRIVER_NAME, sizeof(v->driver)); strscpy(v->card, "Timberdale Radio", sizeof(v->card)); snprintf(v->bus_info, sizeof(v->bus_info), "platform:"DRIVER_NAME); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -122,6 +120,7 @@ static int timbradio_probe(struct platform_device *pdev) tr->video_dev.release = video_device_release_empty; tr->video_dev.minor = -1; tr->video_dev.lock = &tr->lock; + tr->video_dev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; strscpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name)); err = v4l2_device_register(NULL, &tr->v4l2_dev); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index b95704f3cb8b..a1a36ce396ee 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -1292,14 +1292,6 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv, sizeof(capability->card)); strscpy(capability->bus_info, radio->bus_type, sizeof(capability->bus_info)); - - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO | - V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | - V4L2_CAP_RDS_OUTPUT; - capability->capabilities = capability->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1988,6 +1980,10 @@ static const struct video_device wl1273_viddev_template = { .name = WL1273_FM_DRIVER_NAME, .release = wl1273_vdev_release, .vfl_dir = VFL_DIR_TX, + .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_AUDIO | + V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR | + V4L2_CAP_RDS_OUTPUT, }; static int wl1273_fm_radio_remove(struct platform_device *pdev) diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index 15eea2b2c90f..6b42a189b271 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -232,10 +232,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, { strscpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -391,6 +387,9 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->videodev.lock = &radio->lock; radio->videodev.v4l2_dev = &radio->v4l2_dev; radio->videodev.release = video_device_release_empty; + radio->videodev.device_caps = + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&radio->videodev, radio); radio->gpio_reset = devm_gpiod_get_optional(&client->dev, "reset", diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 91d6ef5579f7..398e4149f219 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -523,9 +523,6 @@ static int si470x_vidioc_querycap(struct file *file, void *priv, strscpy(capability->card, DRIVER_CARD, sizeof(capability->card)); usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info)); - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | - V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -679,6 +676,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->videodev.lock = &radio->lock; radio->videodev.v4l2_dev = &radio->v4l2_dev; radio->videodev.release = video_device_release_empty; + radio->videodev.device_caps = + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_READWRITE | V4L2_CAP_TUNER | + V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE; video_set_drvdata(&radio->videodev, radio); /* get device and chip versions */ diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c index 733fcf3933e4..9a012a2012c8 100644 --- a/drivers/media/radio/si4713/radio-platform-si4713.c +++ b/drivers/media/radio/si4713/radio-platform-si4713.c @@ -72,9 +72,6 @@ static int radio_si4713_querycap(struct file *file, void *priv, sizeof(capability->card)); strscpy(capability->bus_info, "platform:radio-si4713", sizeof(capability->bus_info)); - capability->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; - capability->capabilities = capability->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -184,6 +181,7 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev) rsdev->radio_dev.ctrl_handler = sd->ctrl_handler; /* Serialize all access to the si4713 */ rsdev->radio_dev.lock = &rsdev->lock; + rsdev->radio_dev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; video_set_drvdata(&rsdev->radio_dev, rsdev); if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) { dev_err(&pdev->dev, "Could not register video device.\n"); diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c index 23065ecce979..33274189c83c 100644 --- a/drivers/media/radio/si4713/radio-usb-si4713.c +++ b/drivers/media/radio/si4713/radio-usb-si4713.c @@ -70,9 +70,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->driver, "radio-usb-si4713", sizeof(v->driver)); strscpy(v->card, "Si4713 FM Transmitter", sizeof(v->card)); usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -475,6 +472,7 @@ static int usb_si4713_probe(struct usb_interface *intf, radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; radio->vdev.vfl_dir = VFL_DIR_TX; + radio->vdev.device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT; video_set_drvdata(&radio->vdev, radio); diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c index f89f83e04741..1cfae4646e45 100644 --- a/drivers/media/radio/tea575x.c +++ b/drivers/media/radio/tea575x.c @@ -237,10 +237,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(v->card, tea->card, sizeof(v->card)); strlcat(v->card, tea->tea5759 ? " TEA5759" : " TEA5757", sizeof(v->card)); strscpy(v->bus_info, tea->bus_info, sizeof(v->bus_info)); - v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; - if (!tea->cannot_read_data) - v->device_caps |= V4L2_CAP_HW_FREQ_SEEK; - v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -540,6 +536,9 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner) strscpy(tea->vd.name, tea->v4l2_dev->name, sizeof(tea->vd.name)); tea->vd.lock = &tea->mutex; tea->vd.v4l2_dev = tea->v4l2_dev; + tea->vd.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + if (!tea->cannot_read_data) + tea->vd.device_caps |= V4L2_CAP_HW_FREQ_SEEK; tea->fops = tea575x_fops; tea->fops.owner = owner; tea->vd.fops = &tea->fops; diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c index a1eaea19a81c..6ed48e498989 100644 --- a/drivers/media/radio/wl128x/fmdrv_v4l2.c +++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c @@ -194,13 +194,6 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv, strscpy(capability->card, FM_DRV_CARD_SHORT_NAME, sizeof(capability->card)); sprintf(capability->bus_info, "UART"); - capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | - V4L2_CAP_RADIO | V4L2_CAP_MODULATOR | - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_RDS_CAPTURE; - capability->capabilities = capability->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -524,6 +517,9 @@ static const struct video_device fm_viddev_template = { * but that would affect applications using this driver. */ .vfl_dir = VFL_DIR_M2M, + .device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO | + V4L2_CAP_MODULATOR | V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE, }; int fm_v4l2_init_video_device(struct fmdev *fmdev, int radio_nr) -- cgit v1.2.3-59-g8ed1b From 8c3854d03bd7b86e8f36e6d9b07b4a6bc20deccd Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Jun 2019 07:19:53 -0400 Subject: media: media/usb: set device_caps in struct video_device Instead of filling in the struct v4l2_capability device_caps field, fill in the struct video_device device_caps field. That way the V4L2 core knows what the capabilities of the video device are. But this only really works if all drivers use this, so convert all usb drivers in this patch. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/airspy/airspy.c | 6 ++--- drivers/media/usb/au0828/au0828-video.c | 21 +++++++++--------- drivers/media/usb/cpia2/cpia2_v4l.c | 9 ++------ drivers/media/usb/cx231xx/cx231xx-video.c | 28 +++++++++++------------ drivers/media/usb/em28xx/em28xx-video.c | 32 +++++++++++++-------------- drivers/media/usb/go7007/go7007-v4l2.c | 15 +++++-------- drivers/media/usb/gspca/gspca.c | 6 ++--- drivers/media/usb/hackrf/hackrf.c | 14 +++++------- drivers/media/usb/hdpvr/hdpvr-video.c | 5 ++--- drivers/media/usb/msi2500/msi2500.c | 5 ++--- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 17 +++++--------- drivers/media/usb/pwc/pwc-if.c | 2 ++ drivers/media/usb/pwc/pwc-v4l.c | 3 --- drivers/media/usb/s2255/s2255drv.c | 5 ++--- drivers/media/usb/stk1160/stk1160-v4l.c | 7 ++---- drivers/media/usb/stkwebcam/stk-webcam.c | 6 ++--- drivers/media/usb/tm6000/tm6000-video.c | 20 ++++++++--------- drivers/media/usb/usbtv/usbtv-video.c | 5 ++--- drivers/media/usb/usbvision/usbvision-video.c | 20 ++++++++--------- drivers/media/usb/zr364xx/zr364xx.c | 7 ++---- 20 files changed, 100 insertions(+), 133 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c index 41fa0f93143d..6a3e8be95697 100644 --- a/drivers/media/usb/airspy/airspy.c +++ b/drivers/media/usb/airspy/airspy.c @@ -622,10 +622,6 @@ static int airspy_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, s->vdev.name, sizeof(cap->card)); usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1066,6 +1062,8 @@ static int airspy_probe(struct usb_interface *intf, s->v4l2_dev.ctrl_handler = &s->hdl; s->vdev.v4l2_dev = &s->v4l2_dev; s->vdev.lock = &s->v4l2_lock; + s->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); if (ret) { diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 4bde3db83aa2..981ee08fb05f 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -1191,7 +1191,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct au0828_dev *dev = video_drvdata(file); dprintk(1, "%s called std_set %d dev_state %ld\n", __func__, @@ -1202,16 +1201,10 @@ static int vidioc_querycap(struct file *file, void *priv, usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info)); /* set the device capabilities */ - cap->device_caps = V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -2000,6 +1993,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vdev.lock = &dev->lock; dev->vdev.queue = &dev->vb_vidq; dev->vdev.queue->lock = &dev->vb_queue_lock; + dev->vdev.device_caps = + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_TUNER | V4L2_CAP_VIDEO_CAPTURE; strscpy(dev->vdev.name, "au0828a video", sizeof(dev->vdev.name)); /* Setup the VBI device */ @@ -2008,6 +2004,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->vbi_dev.lock = &dev->lock; dev->vbi_dev.queue = &dev->vb_vbiq; dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock; + dev->vbi_dev.device_caps = + V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE; strscpy(dev->vbi_dev.name, "au0828a vbi", sizeof(dev->vbi_dev.name)); /* Init entities at the Media Controller */ diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 45caf78119c4..d3533e9f32a3 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -259,13 +259,6 @@ static int cpia2_querycap(struct file *file, void *fh, struct v4l2_capability *v if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) memset(vc->bus_info,0, sizeof(vc->bus_info)); - - vc->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - vc->capabilities = vc->device_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1161,6 +1154,8 @@ int cpia2_register_camera(struct camera_data *cam) cam->vdev.lock = &cam->v4l2_lock; cam->vdev.ctrl_handler = hdl; cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; reset_camera_struct_v4l(cam); diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index f8820478d46b..b651ac7713ea 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1555,30 +1555,19 @@ static int vidioc_streamoff(struct file *file, void *priv, int cx231xx_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct cx231xx_fh *fh = priv; struct cx231xx *dev = fh->dev; strscpy(cap->driver, "cx231xx", sizeof(cap->driver)); strscpy(cap->card, cx231xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - cap->device_caps = V4L2_CAP_RADIO; - else { - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - } - if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_READWRITE | + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (video_is_registered(&dev->radio_dev)) cap->capabilities |= V4L2_CAP_RADIO; + if (dev->tuner_type != TUNER_ABSENT) + cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -2234,6 +2223,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev_err(dev->dev, "failed to initialize video media entity!\n"); #endif dev->vdev.ctrl_handler = &dev->ctrl_handler; + dev->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vdev.device_caps |= V4L2_CAP_TUNER; + /* register v4l2 video video_device */ ret = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); @@ -2262,6 +2256,11 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) dev_err(dev->dev, "failed to initialize vbi media entity!\n"); #endif dev->vbi_dev.ctrl_handler = &dev->ctrl_handler; + dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vbi_dev.device_caps |= V4L2_CAP_TUNER; + /* register v4l2 vbi video_device */ ret = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); @@ -2277,6 +2276,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev) cx231xx_vdev_init(dev, &dev->radio_dev, &cx231xx_radio_template, "radio"); dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; + dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f43717ea831d..0512e1959394 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -1984,7 +1984,6 @@ static int vidioc_s_register(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; struct usb_device *udev = interface_to_usbdev(dev->intf); @@ -1993,23 +1992,12 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info)); - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps = V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - else if (vdev->vfl_type == VFL_TYPE_RADIO) - cap->device_caps = V4L2_CAP_RADIO; - else - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; - + cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE) - cap->device_caps |= V4L2_CAP_AUDIO; - + cap->capabilities |= V4L2_CAP_AUDIO; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - - cap->capabilities = cap->device_caps | - V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + cap->capabilities |= V4L2_CAP_TUNER; if (video_is_registered(&v4l2->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; if (video_is_registered(&v4l2->radio_dev)) @@ -2782,6 +2770,13 @@ static int em28xx_v4l2_init(struct em28xx *dev) mutex_init(&v4l2->vb_vbi_queue_lock); v4l2->vdev.queue = &v4l2->vb_vidq; v4l2->vdev.queue->lock = &v4l2->vb_queue_lock; + v4l2->vdev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING; + if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE) + v4l2->vdev.device_caps |= V4L2_CAP_AUDIO; + if (dev->tuner_type != TUNER_ABSENT) + v4l2->vdev.device_caps |= V4L2_CAP_TUNER; + /* disable inapplicable ioctls */ if (dev->is_webcam) { @@ -2818,6 +2813,10 @@ static int em28xx_v4l2_init(struct em28xx *dev) v4l2->vbi_dev.queue = &v4l2->vb_vbiq; v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock; + v4l2->vbi_dev.device_caps = V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + v4l2->vbi_dev.device_caps |= V4L2_CAP_TUNER; /* disable inapplicable ioctls */ v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM); @@ -2845,6 +2844,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template, "radio"); + v4l2->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index bebdfcecf600..ffbbd393bc7e 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -287,15 +287,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "go7007", sizeof(cap->driver)); strscpy(cap->card, go->name, sizeof(cap->card)); strscpy(cap->bus_info, go->bus_info, sizeof(cap->bus_info)); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - if (go->board_info->num_aud_inputs) - cap->device_caps |= V4L2_CAP_AUDIO; - if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) - cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1122,6 +1113,12 @@ int go7007_v4l2_init(struct go7007 *go) *vdev = go7007_template; vdev->lock = &go->serialize_lock; vdev->queue = &go->vidq; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + if (go->board_info->num_aud_inputs) + vdev->device_caps |= V4L2_CAP_AUDIO; + if (go->board_info->flags & GO7007_BOARD_HAS_TUNER) + vdev->device_caps |= V4L2_CAP_TUNER; video_set_drvdata(vdev, go); vdev->v4l2_dev = &go->v4l2_dev; if (!v4l2_device_has_op(&go->v4l2_dev, 0, video, querystd)) diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index 4d7517411cc2..d389020b50f9 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1218,10 +1218,6 @@ static int vidioc_querycap(struct file *file, void *priv, } usb_make_path(gspca_dev->dev, (char *) cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING - | V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1517,6 +1513,8 @@ int gspca_dev_probe2(struct usb_interface *intf, gspca_dev->empty_packet = -1; /* don't check the empty packets */ gspca_dev->vdev = gspca_template; gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev; + gspca_dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; video_set_drvdata(&gspca_dev->vdev, gspca_dev); gspca_dev->module = module; diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c index d43785206622..d625263f4984 100644 --- a/drivers/media/usb/hackrf/hackrf.c +++ b/drivers/media/usb/hackrf/hackrf.c @@ -905,19 +905,13 @@ static int hackrf_querycap(struct file *file, void *fh, { struct hackrf_dev *dev = video_drvdata(file); struct usb_interface *intf = dev->intf; - struct video_device *vdev = video_devdata(file); dev_dbg(&intf->dev, "\n"); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (vdev->vfl_dir == VFL_DIR_RX) - cap->device_caps |= V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; - else - cap->device_caps |= V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR; - cap->capabilities = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR | - V4L2_CAP_DEVICE_CAPS | cap->device_caps; + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_DEVICE_CAPS; strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, dev->rx_vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); @@ -1496,6 +1490,8 @@ static int hackrf_probe(struct usb_interface *intf, dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler; dev->rx_vdev.lock = &dev->v4l2_lock; dev->rx_vdev.vfl_dir = VFL_DIR_RX; + dev->rx_vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; video_set_drvdata(&dev->rx_vdev, dev); ret = video_register_device(&dev->rx_vdev, VFL_TYPE_SDR, -1); if (ret) { @@ -1514,6 +1510,8 @@ static int hackrf_probe(struct usb_interface *intf, dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler; dev->tx_vdev.lock = &dev->v4l2_lock; dev->tx_vdev.vfl_dir = VFL_DIR_TX; + dev->tx_vdev.device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR; video_set_drvdata(&dev->tx_vdev, dev); ret = video_register_device(&dev->tx_vdev, VFL_TYPE_SDR, -1); if (ret) { diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 3804aa3fb50f..a675506e8939 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -581,9 +581,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "hdpvr", sizeof(cap->driver)); strscpy(cap->card, "Hauppauge HD PVR", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1154,6 +1151,8 @@ static const struct video_device hdpvr_video_template = { .release = hdpvr_device_release, .ioctl_ops = &hdpvr_ioctl_ops, .tvnorms = V4L2_STD_ALL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO | + V4L2_CAP_READWRITE, }; static const struct v4l2_ctrl_ops hdpvr_ctrl_ops = { diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c index 10b5b95bee34..384d9bbd6495 100644 --- a/drivers/media/usb/msi2500/msi2500.c +++ b/drivers/media/usb/msi2500/msi2500.c @@ -607,9 +607,6 @@ static int msi2500_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, dev->vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1283,6 +1280,8 @@ static int msi2500_probe(struct usb_interface *intf, dev->v4l2_dev.ctrl_handler = &dev->hdl; dev->vdev.v4l2_dev = &dev->v4l2_dev; dev->vdev.lock = &dev->v4l2_lock; + dev->vdev.device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1); if (ret) { diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index cb6668580d77..30701ecc84c5 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -128,17 +128,6 @@ static int pvr2_querycap(struct file *file, void *priv, struct v4l2_capability * cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | V4L2_CAP_READWRITE | V4L2_CAP_DEVICE_CAPS; - switch (fh->pdi->devbase.vfl_type) { - case VFL_TYPE_GRABBER: - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; - break; - case VFL_TYPE_RADIO: - cap->device_caps = V4L2_CAP_RADIO; - break; - default: - return -EINVAL; - } - cap->device_caps |= V4L2_CAP_TUNER | V4L2_CAP_READWRITE; return 0; } @@ -1205,6 +1194,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, int unit_number; struct pvr2_hdw *hdw; int *nr_ptr = NULL; + u32 caps = V4L2_CAP_TUNER | V4L2_CAP_READWRITE; + dip->v4lp = vp; hdw = vp->channel.mc_head->hdw; @@ -1215,6 +1206,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->config = pvr2_config_mpeg; dip->minor_type = pvr2_v4l_type_video; nr_ptr = video_nr; + caps |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_AUDIO; if (!dip->stream) { pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n"); @@ -1225,12 +1217,14 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->config = pvr2_config_vbi; dip->minor_type = pvr2_v4l_type_vbi; nr_ptr = vbi_nr; + caps |= V4L2_CAP_VBI_CAPTURE; break; case VFL_TYPE_RADIO: dip->stream = &vp->channel.mc_head->video_stream; dip->config = pvr2_config_mpeg; dip->minor_type = pvr2_v4l_type_radio; nr_ptr = radio_nr; + caps |= V4L2_CAP_RADIO; break; default: /* Bail out (this should be impossible) */ @@ -1241,6 +1235,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, dip->devbase = vdev_template; dip->devbase.release = pvr2_video_device_release; dip->devbase.ioctl_ops = &pvr2_ioctl_ops; + dip->devbase.device_caps = caps; { int val; pvr2_ctrl_get_value( diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 4e94197094ad..a1bd1cb5924b 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -1125,6 +1125,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->v4l2_dev.ctrl_handler = &pdev->ctrl_handler; pdev->vdev.v4l2_dev = &pdev->v4l2_dev; pdev->vdev.lock = &pdev->v4l2_lock; + pdev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, -1); if (rc < 0) { diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c index bef6e4ef8a7e..85efb433c004 100644 --- a/drivers/media/usb/pwc/pwc-v4l.c +++ b/drivers/media/usb/pwc/pwc-v4l.c @@ -495,9 +495,6 @@ static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap strscpy(cap->driver, PWC_NAME, sizeof(cap->driver)); strscpy(cap->card, pdev->vdev.name, sizeof(cap->card)); usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 5b3e54b76e9a..15c1cf18266a 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -733,9 +733,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, "s2255", sizeof(cap->driver)); strscpy(cap->card, "s2255", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1666,6 +1663,8 @@ static int s2255_probe_v4l(struct s2255_dev *dev) vc->vdev.ctrl_handler = &vc->hdl; vc->vdev.lock = &dev->lock; vc->vdev.v4l2_dev = &dev->v4l2_dev; + vc->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; video_set_drvdata(&vc->vdev, vc); if (video_nr == -1) ret = video_register_device(&vc->vdev, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 701ed3d4afe6..166e867b2001 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -347,11 +347,6 @@ static int vidioc_querycap(struct file *file, strscpy(cap->driver, "stk1160", sizeof(cap->driver)); strscpy(cap->card, "stk1160", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -831,6 +826,8 @@ int stk1160_video_register(struct stk1160 *dev) /* This will be used to set video_device parent */ dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; /* NTSC is default */ dev->norm = V4L2_STD_NTSC_M; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index cb7d6454bbe1..be8041e3e6b8 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -798,10 +798,6 @@ static int stk_vidioc_querycap(struct file *filp, strscpy(cap->driver, "stk", sizeof(cap->driver)); strscpy(cap->card, "stk", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1261,6 +1257,8 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.lock = &dev->lock; dev->vdev.v4l2_dev = &dev->v4l2_dev; + dev->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 072210f5f92f..85fcddfb0202 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -854,22 +854,17 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct tm6000_core *dev = ((struct tm6000_fh *)priv)->dev; - struct video_device *vdev = video_devdata(file); strscpy(cap->driver, "tm6000", sizeof(cap->driver)); strscpy(cap->card, "Trident TVMaster TM5600/6000/6010", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_DEVICE_CAPS; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - else - cap->device_caps |= V4L2_CAP_RADIO; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; + cap->capabilities |= V4L2_CAP_TUNER; + if (dev->caps.has_radio) + cap->capabilities |= V4L2_CAP_RADIO; return 0; } @@ -1639,6 +1634,10 @@ int tm6000_v4l2_register(struct tm6000_core *dev) vdev_init(dev, &dev->vfd, &tm6000_template, "video"); dev->vfd.ctrl_handler = &dev->ctrl_handler; + dev->vfd.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vfd.device_caps |= V4L2_CAP_TUNER; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); @@ -1659,6 +1658,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev) vdev_init(dev, &dev->radio_dev, &tm6000_radio_template, "radio"); dev->radio_dev.ctrl_handler = &dev->radio_ctrl_handler; + dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; ret = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr); if (ret < 0) { diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 4a1eab711bdc..51f784479e91 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -603,9 +603,6 @@ static int usbtv_querycap(struct file *file, void *priv, strscpy(cap->driver, "usbtv", sizeof(cap->driver)); strscpy(cap->card, "usbtv", sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE; - cap->device_caps |= V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -942,6 +939,8 @@ int usbtv_video_init(struct usbtv *usbtv) usbtv->vdev.tvnorms = USBTV_TV_STD; usbtv->vdev.queue = &usbtv->vb2q; usbtv->vdev.lock = &usbtv->v4l2_lock; + usbtv->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; video_set_drvdata(&usbtv->vdev, usbtv); ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index e611052ebf59..bd216c9ff3d1 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -465,24 +465,18 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *vc) { struct usb_usbvision *usbvision = video_drvdata(file); - struct video_device *vdev = video_devdata(file); strscpy(vc->driver, "USBVision", sizeof(vc->driver)); strscpy(vc->card, usbvision_device_data[usbvision->dev_model].model_string, sizeof(vc->card)); usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info)); - vc->device_caps = usbvision->have_tuner ? V4L2_CAP_TUNER : 0; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - vc->device_caps |= V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - else - vc->device_caps |= V4L2_CAP_RADIO; - - vc->capabilities = vc->device_caps | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (usbvision_device_data[usbvision->dev_model].radio) vc->capabilities |= V4L2_CAP_RADIO; + if (usbvision->have_tuner) + vc->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1280,6 +1274,11 @@ static int usbvision_register_video(struct usb_usbvision *usbvision) v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_G_FREQUENCY); v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_S_TUNER); } + usbvision->vdev.device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (usbvision->have_tuner) + usbvision->vdev.device_caps |= V4L2_CAP_TUNER; + if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", @@ -1290,6 +1289,7 @@ static int usbvision_register_video(struct usb_usbvision *usbvision) /* usbvision has radio */ usbvision_vdev_init(usbvision, &usbvision->rdev, &usbvision_radio_template, "USBVision Radio"); + usbvision->rdev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; if (video_register_device(&usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n", diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index cd2bc9ed0cd9..87c5663e28bb 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -707,11 +707,6 @@ static int zr364xx_vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, cam->udev->product, sizeof(cap->card)); strscpy(cap->bus_info, dev_name(&cam->udev->dev), sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1338,6 +1333,8 @@ static const struct video_device zr364xx_template = { .fops = &zr364xx_fops, .ioctl_ops = &zr364xx_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; -- cgit v1.2.3-59-g8ed1b From 372332b111b7cf5642d80ad927ef80dcb3a66a84 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 4 Jun 2019 07:19:54 -0400 Subject: media: rtl2832_sdr: set device_caps in struct video_device Instead of filling in the struct v4l2_capability device_caps field, fill in the struct video_device device_caps field. That way the V4L2 core knows what the capabilities of the video device are. But this only really works if all drivers use this, so convert this SDR driver in this patch. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/rtl2832_sdr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index cf1a8f77ee02..e05c21d35dc8 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -428,9 +428,6 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, strscpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strscpy(cap->card, dev->vdev.name, sizeof(cap->card)); usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE | V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1242,6 +1239,8 @@ static struct video_device rtl2832_sdr_template = { .release = video_device_release_empty, .fops = &rtl2832_sdr_fops, .ioctl_ops = &rtl2832_sdr_ioctl_ops, + .device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER, }; static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) -- cgit v1.2.3-59-g8ed1b From ef732d5e2813ff5ef30cdb280b2d133e74213555 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 29 May 2019 02:45:59 -0400 Subject: media: v4l2-mem2mem: add try_en/decoder_cmd ioctl helpers Most if not all codecs will need to implement these ioctls and it is expected to be the same for all codecs. So add this to the core v4l2-mem2mem framework so that this code can easily be reused. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 29 +++++++++++++++++++++++++++++ include/media/v4l2-mem2mem.h | 4 ++++ 2 files changed, 33 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 3392833d9541..498044a0cb4e 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -1122,6 +1122,35 @@ int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv, } EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff); +int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *ec) +{ + if (ec->cmd != V4L2_ENC_CMD_STOP && ec->cmd != V4L2_ENC_CMD_START) + return -EINVAL; + + ec->flags = 0; + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_encoder_cmd); + +int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + if (dc->cmd != V4L2_DEC_CMD_STOP && dc->cmd != V4L2_DEC_CMD_START) + return -EINVAL; + + dc->flags = 0; + + if (dc->cmd == V4L2_DEC_CMD_STOP) { + dc->stop.pts = 0; + } else if (dc->cmd == V4L2_DEC_CMD_START) { + dc->start.speed = 0; + dc->start.format = V4L2_DEC_START_FMT_NONE; + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_try_decoder_cmd); + /* * v4l2_file_operations helpers. It is assumed here same lock is used * for the output and the capture buffer queue. diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index bb3e63d6bd1a..2e0c989266a7 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -672,6 +672,10 @@ int v4l2_m2m_ioctl_streamon(struct file *file, void *fh, enum v4l2_buf_type type); int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh, enum v4l2_buf_type type); +int v4l2_m2m_ioctl_try_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *ec); +int v4l2_m2m_ioctl_try_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc); int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma); __poll_t v4l2_m2m_fop_poll(struct file *file, poll_table *wait); -- cgit v1.2.3-59-g8ed1b From 9b925365569eb4e845c006fdc254257e78fc12a4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 28 May 2019 04:34:37 -0400 Subject: media: vicodec: use new v4l2_m2m_ioctl_try_en/decoder_cmd funcs Use the new helper functions for the try_de/decoder_cmd ioctls. Signed-off-by: Hans Verkuil Reviewed-by: Tomasz Figa Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 35 +++------------------------ 1 file changed, 4 insertions(+), 31 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 03acdf86176e..72c56756e45b 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1188,25 +1188,13 @@ static void vicodec_mark_last_buf(struct vicodec_ctx *ctx) spin_unlock(ctx->lock); } -static int vicodec_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *ec) -{ - if (ec->cmd != V4L2_ENC_CMD_STOP) - return -EINVAL; - - if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END) - return -EINVAL; - - return 0; -} - static int vicodec_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { struct vicodec_ctx *ctx = file2ctx(file); int ret; - ret = vicodec_try_encoder_cmd(file, fh, ec); + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); if (ret < 0) return ret; @@ -1214,28 +1202,13 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, return 0; } -static int vicodec_try_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - if (dc->cmd != V4L2_DEC_CMD_STOP) - return -EINVAL; - - if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) - return -EINVAL; - - if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0)) - return -EINVAL; - - return 0; -} - static int vicodec_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { struct vicodec_ctx *ctx = file2ctx(file); int ret; - ret = vicodec_try_decoder_cmd(file, fh, dc); + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; @@ -1324,9 +1297,9 @@ static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { .vidioc_g_selection = vidioc_g_selection, .vidioc_s_selection = vidioc_s_selection, - .vidioc_try_encoder_cmd = vicodec_try_encoder_cmd, + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, .vidioc_encoder_cmd = vicodec_encoder_cmd, - .vidioc_try_decoder_cmd = vicodec_try_decoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, .vidioc_decoder_cmd = vicodec_decoder_cmd, .vidioc_enum_framesizes = vicodec_enum_framesizes, -- cgit v1.2.3-59-g8ed1b From 3c1b9ac753e99005d7ee0a883d6e5b577ba32aa9 Mon Sep 17 00:00:00 2001 From: André Almeida Date: Thu, 30 May 2019 09:19:56 -0400 Subject: media: vimc: Remove or modify stream checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change the way subdevices check if the stream is running. Verify the stream pointer instead of src_frame. This makes easier to get rid of the void* and u8* that points to frames in the subdevices structs. Remove checks that s_stream does on subdevices. They are redundant since the Media Controller Framework doesn't allow two streaming on the same media pipeline at the same time. Signed-off-by: André Almeida Acked-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-debayer.c | 5 +---- drivers/media/platform/vimc/vimc-scaler.c | 7 ++----- drivers/media/platform/vimc/vimc-sensor.c | 6 +----- 3 files changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 281f9c1a7249..b221f26e01cf 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -270,7 +270,7 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vdeb->src_frame) + if (vdeb->ved.stream) return -EBUSY; sink_fmt = &vdeb->sink_fmt; @@ -337,9 +337,6 @@ static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) const struct v4l2_format_info *pix_info; unsigned int frame_size; - if (vdeb->src_frame) - return 0; - /* We only support translating bayer to RGB24 */ if (src_pixelformat != V4L2_PIX_FMT_RGB24) { dev_err(vdeb->dev, diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index 8aecf8e92031..617f2920b86b 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -158,7 +158,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsca->src_frame) + if (vsca->ved.stream) return -EBUSY; sink_fmt = &vsca->sink_fmt; @@ -213,9 +213,6 @@ static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) const struct v4l2_format_info *pix_info; unsigned int frame_size; - if (vsca->src_frame) - return 0; - if (!vimc_sca_is_pixfmt_supported(pixelformat)) { dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n", pixelformat); @@ -337,7 +334,7 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved, ved); /* If the stream in this node is not active, just return */ - if (!vsca->src_frame) + if (!ved->stream) return ERR_PTR(-EINVAL); vimc_sca_fill_src_frame(vsca, sink_frame); diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index baca9ca67ce0..d70f1a1408f1 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -141,7 +141,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ - if (vsen->frame) + if (vsen->ved.stream) return -EBUSY; mf = &vsen->mbus_format; @@ -197,10 +197,6 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) const struct v4l2_format_info *pix_info; unsigned int frame_size; - if (vsen->kthread_sen) - /* tpg is already executing */ - return 0; - /* Calculate the frame size */ pix_info = v4l2_format_info(pixelformat); frame_size = vsen->mbus_format.width * pix_info->bpp[0] * -- cgit v1.2.3-59-g8ed1b From 9293e39c5d7ffc2f48bd96c12dc66d396016a084 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 4 Jun 2019 05:37:33 -0400 Subject: media: mtk-vcodec: replace GPLv2 with SPDX Replace the GPLv2 boilerplate with the corresponding SPDX reference. Signed-off-by: Alexandre Courbot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 14 +------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 14 +------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c | 14 +------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h | 14 +------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c | 14 +------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h | 14 +------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c | 15 +-------------- drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h | 15 +-------------- drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c | 14 +------------- drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c | 15 +-------------- drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c | 16 +--------------- drivers/media/platform/mtk-vcodec/vdec_drv_base.h | 14 +------------- drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 15 +-------------- drivers/media/platform/mtk-vcodec/vdec_drv_if.h | 15 +-------------- drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h | 15 +-------------- drivers/media/platform/mtk-vcodec/vdec_vpu_if.c | 14 +------------- drivers/media/platform/mtk-vcodec/vdec_vpu_if.h | 14 +------------- drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 17 +---------------- drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c | 16 +--------------- drivers/media/platform/mtk-vcodec/venc_drv_base.h | 17 +---------------- drivers/media/platform/mtk-vcodec/venc_drv_if.c | 17 +---------------- drivers/media/platform/mtk-vcodec/venc_drv_if.h | 17 +---------------- drivers/media/platform/mtk-vcodec/venc_ipi_msg.h | 17 +---------------- drivers/media/platform/mtk-vcodec/venc_vpu_if.c | 15 +-------------- drivers/media/platform/mtk-vcodec/venc_vpu_if.h | 15 +-------------- 32 files changed, 32 insertions(+), 450 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index ebf919509e8c..344c94b33b0d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index e4984edec4f8..a18268694646 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_DEC_H_ #define _MTK_VCODEC_DEC_H_ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 4334b7394861..dbe957aa138d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 11c45c556e88..b09242b1470d 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -1,16 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h index 86a7825353e3..b44621ad15d8 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h @@ -1,16 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_DEC_PM_H_ #define _MTK_VCODEC_DEC_PM_H_ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index 662a84b822af..d7b43caf7988 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -1,17 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: PC Chen -* Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_DRV_H_ #define _MTK_VCODEC_DRV_H_ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 2c92ee4f0c8c..c1d010723053 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -1,17 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: PC Chen -* Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h index d7a154a97510..e372e5ddff8a 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.h @@ -1,17 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: PC Chen -* Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_ENC_H_ #define _MTK_VCODEC_ENC_H_ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 83f859e8509c..b6d7c602c2ad 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -1,17 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: PC Chen -* Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c index 39375b8ea27c..90bdad5c71b0 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c @@ -1,16 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h index f32167138976..dddbbe02a109 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.h @@ -1,16 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_ENC_PM_H_ #define _MTK_VCODEC_ENC_PM_H_ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c index 113b2097f061..693888e4987f 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c @@ -1,16 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h index 12131855b46a..55f046cd93a5 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.h @@ -1,16 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_INTR_H_ #define _MTK_VCODEC_INTR_H_ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index 060c0ad6243a..e1a9ac9694e3 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -1,17 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: PC Chen -* Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +// SPDX-License-Identifier: GPL-2.0 #include diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h index 9bf6e8d1b9c9..daabb63548d0 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h @@ -1,17 +1,4 @@ -/* -* Copyright (c) 2016 MediaTek Inc. -* Author: PC Chen -* Tiffany Lin -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License version 2 as -* published by the Free Software Foundation. -* -* 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. -*/ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _MTK_VCODEC_UTIL_H_ #define _MTK_VCODEC_UTIL_H_ diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index cdbcd6909728..d725ea54b1c1 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -1,16 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index ba79136421ef..8de997875b6b 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Jungchang Tsao - * PC Chen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include "../vdec_drv_if.h" diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index 939ea14bf6c5..02b65298c87e 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -1,18 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Daniel Hsiao - * Kai-Sean Yang - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h index 7e4c1a92bbd8..014712b1312e 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h @@ -1,16 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VDEC_DRV_BASE_ #define _VDEC_DRV_BASE_ diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 5ffc468dd910..6835cb7d090a 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index 9a21591f3818..ceba7f55a526 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VDEC_DRV_IF_H_ #define _VDEC_DRV_IF_H_ diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h index 5a8a629f4ac9..6370f1285a63 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VDEC_IPI_MSG_H_ #define _VDEC_IPI_MSG_H_ diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c index 1abd14e79565..9b240d325a84 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -1,16 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include "mtk_vcodec_drv.h" #include "mtk_vcodec_util.h" diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h index 79d8eac7f5e2..3c417493ccca 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -1,16 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PC Chen - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VDEC_VPU_IF_H_ #define _VDEC_VPU_IF_H_ diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index 6cf31b366aad..0cf08dd7b6e3 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -1,19 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Jungchang Tsao - * Daniel Hsiao - * PoChun Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index 957420dd60de..3fb9e0c79b4f 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -1,18 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Daniel Hsiao - * PoChun Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_base.h b/drivers/media/platform/mtk-vcodec/venc_drv_base.h index 6308d44dedf6..2de37b47fe73 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_base.h @@ -1,19 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Daniel Hsiao - * Jungchang Tsao - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VENC_DRV_BASE_ #define _VENC_DRV_BASE_ diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c index d02d5f1df279..25c1e100f5a1 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c @@ -1,19 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Daniel Hsiao - * Jungchang Tsao - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include #include diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h index 55ecda844894..d6605812ebb0 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.h @@ -1,19 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Daniel Hsiao - * Jungchang Tsao - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VENC_DRV_IF_H_ #define _VENC_DRV_IF_H_ diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h index 4c869cb6fbf7..d5282f24f934 100644 --- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h +++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h @@ -1,19 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: Jungchang Tsao - * Daniel Hsiao - * Tiffany Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VENC_IPI_MSG_H_ #define _VENC_IPI_MSG_H_ diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c index 0d882acf8830..a6906db74718 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PoChun Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +// SPDX-License-Identifier: GPL-2.0 #include "mtk_vpu.h" #include "venc_ipi_msg.h" diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h index 215d1e01362e..fd4f85646aa5 100644 --- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h @@ -1,17 +1,4 @@ -/* - * Copyright (c) 2016 MediaTek Inc. - * Author: PoChun Lin - * - * This program is free software; you can redistribute it and/or - * modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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. - */ +/* SPDX-License-Identifier: GPL-2.0 */ #ifndef _VENC_VPU_IF_H_ #define _VENC_VPU_IF_H_ -- cgit v1.2.3-59-g8ed1b From 0a7ff71e223fbf8d22a6db156a67482c77d5121a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 4 Jun 2019 05:37:36 -0400 Subject: media: mtk-vcodec: constify formats Formats are read-only internal memory structures, so make them const. Signed-off-by: Alexandre Courbot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 19 ++++++++++--------- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 +- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 19 ++++++++++--------- 3 files changed, 21 insertions(+), 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 344c94b33b0d..6ac3fa439b41 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -19,7 +19,7 @@ #define DFT_CFG_WIDTH MTK_VDEC_MIN_W #define DFT_CFG_HEIGHT MTK_VDEC_MIN_H -static struct mtk_video_fmt mtk_video_formats[] = { +static const struct mtk_video_fmt mtk_video_formats[] = { { .fourcc = V4L2_PIX_FMT_H264, .type = MTK_FMT_DEC, @@ -63,9 +63,9 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) #define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) -static struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) +static const struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { @@ -266,7 +266,7 @@ static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, unsigned int pixelformat) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; struct mtk_q_data *dst_q_data; unsigned int k; @@ -639,7 +639,8 @@ static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, } } -static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) +static int vidioc_try_fmt(struct v4l2_format *f, + const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int i; @@ -712,7 +713,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; fmt = mtk_vdec_find_format(f); if (!fmt) { @@ -727,7 +728,7 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; fmt = mtk_vdec_find_format(f); if (!fmt) { @@ -821,7 +822,7 @@ static int vidioc_vdec_s_fmt(struct file *file, void *priv, struct v4l2_pix_format_mplane *pix_mp; struct mtk_q_data *q_data; int ret = 0; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; mtk_v4l2_debug(3, "[%d]", ctx->id); @@ -920,7 +921,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; int i, j = 0; for (i = 0; i < NUM_FORMATS; i++) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index d7b43caf7988..7306aeabe229 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -124,7 +124,7 @@ struct mtk_q_data { enum v4l2_field field; unsigned int bytesperline[MTK_VCODEC_MAX_PLANES]; unsigned int sizeimage[MTK_VCODEC_MAX_PLANES]; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; }; /** diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index c1d010723053..67e8a023ef41 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -24,7 +24,7 @@ static void mtk_venc_worker(struct work_struct *work); -static struct mtk_video_fmt mtk_video_formats[] = { +static const struct mtk_video_fmt mtk_video_formats[] = { { .fourcc = V4L2_PIX_FMT_NV12M, .type = MTK_FMT_FRAME, @@ -153,7 +153,7 @@ static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = { static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; int i, j = 0; for (i = 0; i < NUM_FORMATS; ++i) { @@ -261,9 +261,9 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx, return &ctx->q_data[MTK_Q_DATA_DST]; } -static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) +static const struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; unsigned int k; for (k = 0; k < NUM_FORMATS; k++) { @@ -278,7 +278,8 @@ static struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f) /* V4L2 specification suggests the driver corrects the format struct if any of * the dimensions is unsupported */ -static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) +static int vidioc_try_fmt(struct v4l2_format *f, + const struct mtk_video_fmt *fmt) { struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; int i; @@ -414,7 +415,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv, struct vb2_queue *vq; struct mtk_q_data *q_data; int i, ret; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); if (!vq) { @@ -476,7 +477,7 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv, struct vb2_queue *vq; struct mtk_q_data *q_data; int ret, i; - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); @@ -575,7 +576,7 @@ static int vidioc_venc_g_fmt(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); fmt = mtk_venc_find_format(f); @@ -594,7 +595,7 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct mtk_video_fmt *fmt; + const struct mtk_video_fmt *fmt; fmt = mtk_venc_find_format(f); if (!fmt) { -- cgit v1.2.3-59-g8ed1b From 0c6280b3c353868a1a40596585db43af756b0617 Mon Sep 17 00:00:00 2001 From: Yunfei Dong Date: Tue, 4 Jun 2019 05:37:37 -0400 Subject: media: mtk-vcodec: support single-buffer frames MT8183 will use a multi-planar format backed by a single buffer. Adapt the existing code to be able to handle such frames instead of assuming each frame is backed by two buffers. Co-developed-by: Alexandre Courbot [acourbot: refactor, cleanup and split] Signed-off-by: Yunfei Dong Signed-off-by: Alexandre Courbot Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: fix checkpatch alignment warning] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 6ac3fa439b41..aee1ddc35de4 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -117,8 +117,9 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) if (dstbuf->used) { vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, ctx->picinfo.fb_sz[0]); - vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, - ctx->picinfo.fb_sz[1]); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, + ctx->picinfo.fb_sz[1]); mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", @@ -389,7 +390,8 @@ static void mtk_vdec_worker(struct work_struct *work) vdec_if_decode(ctx, NULL, NULL, &res_chg); clean_display_buffer(ctx); vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0); - vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0); dst_buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE); clean_free_buffer(ctx); @@ -1320,7 +1322,8 @@ static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); - vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); + if (ctx->q_data[MTK_Q_DATA_DST].fmt->num_planes == 2) + vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } -- cgit v1.2.3-59-g8ed1b From d4ec9550e4b2d2e357a46fdc65d8ef3d4d15984c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 4 Jun 2019 10:55:15 -0400 Subject: media: vivid: fix incorrect assignment operation when setting video mode The assigment of FB_VMODE_NONINTERLACE to var->vmode should be a bit-wise or of FB_VMODE_NONINTERLACE instead of an assignment, otherwise the previous clearing of the FB_VMODE_MASK bits of var->vmode makes no sense and is redundant. Addresses-Coverity: ("Unused value") Fixes: ad4e02d5081d ("[media] vivid: add a simple framebuffer device for overlay testing") Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-osd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c index 1a89593b0c86..f2e789bdf4a6 100644 --- a/drivers/media/platform/vivid/vivid-osd.c +++ b/drivers/media/platform/vivid/vivid-osd.c @@ -155,7 +155,7 @@ static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev * var->nonstd = 0; var->vmode &= ~FB_VMODE_MASK; - var->vmode = FB_VMODE_NONINTERLACED; + var->vmode |= FB_VMODE_NONINTERLACED; /* Dummy values */ var->hsync_len = 24; -- cgit v1.2.3-59-g8ed1b From eb42ac1b411ccad9bfe65dbeb65acc243981bbdb Mon Sep 17 00:00:00 2001 From: Shobhit Kukreti Date: Tue, 4 Jun 2019 21:49:58 -0400 Subject: media: platform: Fix Warning of Unneeded Semicolon reported by coccicheck fixed the warning in the files below drivers/media/platform/pxa_camera.c:1391:2-3: Unneeded semicolon drivers/media/platform/qcom/venus/vdec_ctrls.c:78:2-3: Unneeded semicolon drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c:146:3-4: Unneeded semicolon Signed-off-by: Shobhit Kukreti Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/pxa_camera.c | 2 +- drivers/media/platform/qcom/venus/vdec_ctrls.c | 2 +- drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index a632f06d9fff..a7b2b89d6155 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -1392,7 +1392,7 @@ static int pxa_buffer_init(struct pxa_camera_dev *pcdev, break; default: return -EINVAL; - }; + } buf->nb_planes = nb_channels; ret = sg_split(sgt->sgl, sgt->nents, 0, nb_channels, diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c index f4604b0cd57e..90f7620c9671 100644 --- a/drivers/media/platform/qcom/venus/vdec_ctrls.c +++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c @@ -75,7 +75,7 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; default: return -EINVAL; - }; + } return 0; } diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c index 075d4695ee4d..a79250a7f812 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c @@ -143,7 +143,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe, "%s: stv0367ter_attach failed for NIM card %s\n" , __func__, dvb_card_str(tsin->dvb_card)); return -ENODEV; - }; + } /* * init the demod so that i2c gate_ctrl @@ -203,7 +203,7 @@ int c8sectpfe_frontend_attach(struct dvb_frontend **fe, "%s: stv6110x_attach failed for NIM card %s\n" , __func__, dvb_card_str(tsin->dvb_card)); return -ENODEV; - }; + } stv090x_config.tuner_init = fe2->tuner_init; stv090x_config.tuner_set_mode = fe2->tuner_set_mode; -- cgit v1.2.3-59-g8ed1b From 4f62e840f827a31d42db91f8ffb9a01420488589 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 5 Jun 2019 07:16:21 -0400 Subject: media: cxusb: Revert "media: cxusb: add raw mode support for, Medion MD95700" This patch shouldn't have been included in the pull request as it adds a non-standard raw mode that is for debugging only. So revert commit ead14a70754f8d7f5dbcb0553c7f11eb0fc4a6ac. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb-analog.c | 190 ++++++------------------------- drivers/media/usb/dvb-usb/cxusb.h | 4 - drivers/media/v4l2-core/v4l2-ioctl.c | 3 +- 3 files changed, 34 insertions(+), 163 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c index 9b4f17ec63d3..0699f718d052 100644 --- a/drivers/media/usb/dvb-usb/cxusb-analog.c +++ b/drivers/media/usb/dvb-usb/cxusb-analog.c @@ -44,9 +44,7 @@ static int cxusb_medion_v_queue_setup(struct vb2_queue *q, { struct dvb_usb_device *dvbdev = vb2_get_drv_priv(q); struct cxusb_medion_dev *cxdev = dvbdev->priv; - unsigned int size = cxdev->raw_mode ? - CXUSB_VIDEO_MAX_FRAME_SIZE : - cxdev->width * cxdev->height * 2; + unsigned int size = cxdev->width * cxdev->height * 2; if (*num_planes > 0) { if (*num_planes != 1) @@ -69,13 +67,8 @@ static int cxusb_medion_v_buf_init(struct vb2_buffer *vb) cxusb_vprintk(dvbdev, OPS, "buffer init\n"); - if (cxdev->raw_mode) { - if (vb2_plane_size(vb, 0) < CXUSB_VIDEO_MAX_FRAME_SIZE) - return -ENOMEM; - } else { - if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2) - return -ENOMEM; - } + if (vb2_plane_size(vb, 0) < cxdev->width * cxdev->height * 2) + return -ENOMEM; cxusb_vprintk(dvbdev, OPS, "buffer OK\n"); @@ -449,45 +442,6 @@ static bool cxusb_medion_copy_field(struct dvb_usb_device *dvbdev, return true; } -static void cxusb_medion_v_process_urb_raw(struct cxusb_medion_dev *cxdev, - struct urb *urb) -{ - struct dvb_usb_device *dvbdev = cxdev->dvbdev; - u8 *buf; - struct cxusb_medion_vbuffer *vbuf; - int i; - unsigned long len; - - if (list_empty(&cxdev->buflist)) { - dev_warn(&dvbdev->udev->dev, "no free buffers\n"); - cxdev->vbuf_sequence++; - return; - } - - vbuf = list_first_entry(&cxdev->buflist, struct cxusb_medion_vbuffer, - list); - list_del(&vbuf->list); - - vbuf->vb2.field = V4L2_FIELD_NONE; - vbuf->vb2.sequence = cxdev->vbuf_sequence++; - vbuf->vb2.vb2_buf.timestamp = ktime_get_ns(); - - buf = vb2_plane_vaddr(&vbuf->vb2.vb2_buf, 0); - - for (i = 0, len = 0; i < urb->number_of_packets; i++) { - memcpy(buf, urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - - buf += urb->iso_frame_desc[i].actual_length; - len += urb->iso_frame_desc[i].actual_length; - } - - vb2_set_plane_payload(&vbuf->vb2.vb2_buf, 0, len); - - vb2_buffer_done(&vbuf->vb2.vb2_buf, VB2_BUF_STATE_DONE); -} - static bool cxusb_medion_v_process_auxbuf(struct cxusb_medion_dev *cxdev, bool reset) { @@ -610,26 +564,22 @@ static bool cxusb_medion_v_complete_handle_urb(struct cxusb_medion_dev *cxdev, len); if (len > 0) { - if (cxdev->raw_mode) { - cxusb_medion_v_process_urb_raw(cxdev, urb); - } else { - cxusb_vprintk(dvbdev, URB, "appending URB\n"); - - /* - * append new data to auxbuf while - * overwriting old data if necessary - * - * if any overwrite happens then we can no - * longer rely on consistency of the whole - * data so let's start again the current - * auxbuf frame assembling process from - * the beginning - */ - *auxbuf_reset = - !cxusb_auxbuf_append_urb(dvbdev, - &cxdev->auxbuf, - urb); - } + cxusb_vprintk(dvbdev, URB, "appending URB\n"); + + /* + * append new data to auxbuf while + * overwriting old data if necessary + * + * if any overwrite happens then we can no + * longer rely on consistency of the whole + * data so let's start again the current + * auxbuf frame assembling process from + * the beginning + */ + *auxbuf_reset = + !cxusb_auxbuf_append_urb(dvbdev, + &cxdev->auxbuf, + urb); } } @@ -664,8 +614,7 @@ static void cxusb_medion_v_complete_work(struct work_struct *work) reschedule = cxusb_medion_v_complete_handle_urb(cxdev, &auxbuf_reset); - if (!cxdev->raw_mode && cxusb_medion_v_process_auxbuf(cxdev, - auxbuf_reset)) + if (cxusb_medion_v_process_auxbuf(cxdev, auxbuf_reset)) /* reschedule us until auxbuf no longer can produce any frame */ reschedule = true; @@ -854,13 +803,9 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, goto ret_unstream_cx; } - if (cxdev->raw_mode) { - npackets = CXUSB_VIDEO_MAX_FRAME_PKTS; - } else { - ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); - if (ret != 0) - goto ret_unstream_md; - } + ret = cxusb_medion_v_ss_auxbuf_alloc(cxdev, &npackets); + if (ret != 0) + goto ret_unstream_md; for (i = 0; i < CXUSB_VIDEO_URBS; i++) { int framen; @@ -916,11 +861,9 @@ static int cxusb_medion_v_start_streaming(struct vb2_queue *q, cxdev->nexturb = 0; cxdev->vbuf_sequence = 0; - if (!cxdev->raw_mode) { - cxdev->vbuf = NULL; - cxdev->bt656.mode = NEW_FRAME; - cxdev->bt656.buf = NULL; - } + cxdev->vbuf = NULL; + cxdev->bt656.mode = NEW_FRAME; + cxdev->bt656.buf = NULL; for (i = 0; i < CXUSB_VIDEO_URBS; i++) if (cxdev->streamurbs[i]) { @@ -938,8 +881,7 @@ ret_freeu: cxusb_medion_urbs_free(cxdev); ret_freeab: - if (!cxdev->raw_mode) - vfree(cxdev->auxbuf.buf); + vfree(cxdev->auxbuf.buf); ret_unstream_md: cxusb_ctrl_msg(dvbdev, CMD_STREAMING_OFF, NULL, 0, NULL, 0); @@ -986,8 +928,7 @@ static void cxusb_medion_v_stop_streaming(struct vb2_queue *q) mutex_lock(cxdev->videodev->lock); /* free transfer buffer and URB */ - if (!cxdev->raw_mode) - vfree(cxdev->auxbuf.buf); + vfree(cxdev->auxbuf.buf); cxusb_medion_urbs_free(cxdev); @@ -1060,11 +1001,9 @@ static int cxusb_medion_g_fmt_vid_cap(struct file *file, void *fh, f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; f->fmt.pix.field = vb2_start_streaming_called(&cxdev->videoqueue) ? cxdev->field_order : cxusb_medion_field_order(cxdev); - f->fmt.pix.bytesperline = cxdev->raw_mode ? 0 : cxdev->width * 2; + f->fmt.pix.bytesperline = cxdev->width * 2; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.sizeimage = - cxdev->raw_mode ? CXUSB_VIDEO_MAX_FRAME_SIZE : - f->fmt.pix.bytesperline * f->fmt.pix.height; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; return 0; } @@ -1102,10 +1041,8 @@ static int cxusb_medion_try_s_fmt_vid_cap(struct file *file, f->fmt.pix.height = subfmt.format.height; f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; f->fmt.pix.field = field; - f->fmt.pix.bytesperline = cxdev->raw_mode ? 0 : f->fmt.pix.width * 2; - f->fmt.pix.sizeimage = - cxdev->raw_mode ? CXUSB_VIDEO_MAX_FRAME_SIZE : - f->fmt.pix.bytesperline * f->fmt.pix.height; + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * f->fmt.pix.height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; if (isset) { @@ -1461,67 +1398,6 @@ static int cxusb_medion_querystd(struct file *file, void *fh, return 0; } -static int cxusb_medion_g_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *param) -{ - v4l2_std_id std; - - if (param->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - param->parm.capture.readbuffers = 2; - - if (cxusb_medion_g_std(file, fh, &std) == 0) - v4l2_video_std_frame_period(std, - ¶m->parm.capture.timeperframe); - - return 0; -} - -static int cxusb_medion_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *param) -{ - struct dvb_usb_device *dvbdev = video_drvdata(file); - struct cxusb_medion_dev *cxdev = dvbdev->priv; - int ret; - - ret = cxusb_medion_g_s_parm(file, fh, param); - if (ret != 0) - return ret; - - if (cxdev->raw_mode) - param->parm.capture.extendedmode |= - CXUSB_EXTENDEDMODE_CAPTURE_RAW; - - return 0; -} - -static int cxusb_medion_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *param) -{ - struct dvb_usb_device *dvbdev = video_drvdata(file); - struct cxusb_medion_dev *cxdev = dvbdev->priv; - int ret; - bool want_raw; - - ret = cxusb_medion_g_s_parm(file, fh, param); - if (ret != 0) - return ret; - - want_raw = param->parm.capture.extendedmode & - CXUSB_EXTENDEDMODE_CAPTURE_RAW; - - if (want_raw != cxdev->raw_mode) { - if (vb2_start_streaming_called(&cxdev->videoqueue) || - cxdev->stop_streaming) - return -EBUSY; - - cxdev->raw_mode = want_raw; - } - - return 0; -} - static int cxusb_medion_log_status(struct file *file, void *fh) { struct dvb_usb_device *dvbdev = video_drvdata(file); @@ -1541,8 +1417,6 @@ static const struct v4l2_ioctl_ops cxusb_video_ioctl = { .vidioc_enum_input = cxusb_medion_enum_input, .vidioc_g_input = cxusb_medion_g_input, .vidioc_s_input = cxusb_medion_s_input, - .vidioc_g_parm = cxusb_medion_g_parm, - .vidioc_s_parm = cxusb_medion_s_parm, .vidioc_g_tuner = cxusb_medion_g_tuner, .vidioc_s_tuner = cxusb_medion_s_tuner, .vidioc_g_frequency = cxusb_medion_g_frequency, diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index eb70fbb02680..9e374e53125b 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -133,7 +133,6 @@ struct cxusb_medion_dev { bool stop_streaming; u32 width, height; u32 field_order; - bool raw_mode; struct cxusb_medion_auxbuf auxbuf; v4l2_std_id norm; @@ -157,9 +156,6 @@ struct cxusb_medion_vbuffer { struct list_head list; }; -/* Capture streaming parameters extendedmode field flags */ -#define CXUSB_EXTENDEDMODE_CAPTURE_RAW 1 - /* defines for "debug" module parameter */ #define CXUSB_DBG_RC BIT(0) #define CXUSB_DBG_I2C BIT(1) diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b4c73e8f23c5..14596e8ad2c6 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2025,7 +2025,7 @@ static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, if (ret) return ret; - /* Note: extendedmode is never used in output drivers */ + /* Note: extendedmode is never used in drivers */ if (V4L2_TYPE_IS_OUTPUT(p->type)) { memset(p->parm.output.reserved, 0, sizeof(p->parm.output.reserved)); @@ -2034,6 +2034,7 @@ static int v4l_s_parm(const struct v4l2_ioctl_ops *ops, } else { memset(p->parm.capture.reserved, 0, sizeof(p->parm.capture.reserved)); + p->parm.capture.extendedmode = 0; p->parm.capture.capturemode &= V4L2_MODE_HIGHQUALITY; } return ops->vidioc_s_parm(file, fh, p); -- cgit v1.2.3-59-g8ed1b From dbb9fcc8c2d8d4ea1104f51d4947a8a8199a2cb5 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Fri, 31 May 2019 05:18:15 -0400 Subject: media: stm32-dcmi: fix irq = 0 case Manage the irq = 0 case, where we shall return an error. Fixes: b5b5a27bee58 ("media: stm32-dcmi: return appropriate error codes during probe") Signed-off-by: Fabien Dessenne Reported-by: Pavel Machek Acked-by: Pavel Machek Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/stm32/stm32-dcmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index b9dad0accd1b..d855e9c09c08 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -1702,7 +1702,7 @@ static int dcmi_probe(struct platform_device *pdev) if (irq <= 0) { if (irq != -EPROBE_DEFER) dev_err(&pdev->dev, "Could not get irq\n"); - return irq; + return irq ? irq : -ENXIO; } dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3-59-g8ed1b From 9698ed4d4a2993ce54b9f7d71a2891e972caa117 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:39 -0400 Subject: media: aspeed: fix a kernel warning on clk control Video engine clock control can be double disabled and eventually it causes a kernel warning with stack dump printing out like below: [ 515.540498] ------------[ cut here ]------------ [ 515.545174] WARNING: CPU: 0 PID: 1310 at drivers/clk/clk.c:684 clk_core_unprepare+0x13c/0x170 [ 515.553806] vclk-gate already unprepared [ 515.557841] CPU: 0 PID: 1310 Comm: obmc-ikvm Tainted: G W 5.0.6-df66fbc97853fbba90a0bfa44de32f3d5f7602b4 #1 [ 515.568973] Hardware name: Generic DT based system [ 515.573777] Backtrace: [ 515.576272] [<80107cdc>] (dump_backtrace) from [<80107f10>] (show_stack+0x20/0x24) [ 515.583930] r7:803a5614 r6:00000009 r5:00000000 r4:9d88fe1c [ 515.589712] [<80107ef0>] (show_stack) from [<80690184>] (dump_stack+0x20/0x28) [ 515.597053] [<80690164>] (dump_stack) from [<80116044>] (__warn.part.3+0xb4/0xdc) [ 515.604557] [<80115f90>] (__warn.part.3) from [<801160d8>] (warn_slowpath_fmt+0x6c/0x90) [ 515.612734] r6:000002ac r5:8080befc r4:80a07008 [ 515.617463] [<80116070>] (warn_slowpath_fmt) from [<803a5614>] (clk_core_unprepare+0x13c/0x170) [ 515.626167] r3:8080cdf4 r2:8080bfc0 [ 515.629834] r7:98d682a8 r6:9d8a9200 r5:9e5151a0 r4:97abd620 [ 515.635530] [<803a54d8>] (clk_core_unprepare) from [<803a76a4>] (clk_unprepare+0x34/0x3c) [ 515.643812] r5:9e5151a0 r4:97abd620 [ 515.647529] [<803a7670>] (clk_unprepare) from [<804f36ec>] (aspeed_video_off+0x38/0x50) [ 515.655539] r5:9e5151a0 r4:9e504000 [ 515.659242] [<804f36b4>] (aspeed_video_off) from [<804f4358>] (aspeed_video_release+0x90/0x114) [ 515.668036] r5:9e5044b0 r4:9e504000 [ 515.671643] [<804f42c8>] (aspeed_video_release) from [<804d302c>] (v4l2_release+0xd4/0xe8) [ 515.679999] r7:98d682a8 r6:9d087810 r5:9d8a9200 r4:9e504318 [ 515.685695] [<804d2f58>] (v4l2_release) from [<80236454>] (__fput+0x98/0x1c4) [ 515.692914] r5:9e51b608 r4:9d8a9200 [ 515.696597] [<802363bc>] (__fput) from [<802365e8>] (____fput+0x18/0x1c) [ 515.703315] r9:80a0700c r8:801011e4 r7:00000000 r6:80a64b9c r5:9d8e35a0 r4:9d8e38dc [ 515.711167] [<802365d0>] (____fput) from [<80131ca4>] (task_work_run+0x7c/0xa0) [ 515.718596] [<80131c28>] (task_work_run) from [<80106884>] (do_work_pending+0x4a8/0x578) [ 515.726777] r7:801011e4 r6:80a07008 r5:9d88ffb0 r4:ffffe000 [ 515.732466] [<801063dc>] (do_work_pending) from [<8010106c>] (slow_work_pending+0xc/0x20) [ 515.740727] Exception stack(0x9d88ffb0 to 0x9d88fff8) [ 515.745840] ffa0: 00000000 76f18094 00000000 00000000 [ 515.754122] ffc0: 00000007 00176778 7eda4c20 00000006 00000000 00000000 48e20fa4 00000000 [ 515.762386] ffe0: 00000002 7eda4b08 00000000 48f91efc 80000010 00000007 [ 515.769097] r10:00000000 r9:9d88e000 r8:801011e4 r7:00000006 r6:7eda4c20 r5:00176778 [ 515.777006] r4:00000007 [ 515.779558] ---[ end trace 12c04aadef8afbbb ]--- [ 515.784176] ------------[ cut here ]------------ [ 515.788817] WARNING: CPU: 0 PID: 1310 at drivers/clk/clk.c:825 clk_core_disable+0x18c/0x204 [ 515.797161] eclk-gate already disabled [ 515.800916] CPU: 0 PID: 1310 Comm: obmc-ikvm Tainted: G W 5.0.6-df66fbc97853fbba90a0bfa44de32f3d5f7602b4 #1 [ 515.811945] Hardware name: Generic DT based system [ 515.816730] Backtrace: [ 515.819210] [<80107cdc>] (dump_backtrace) from [<80107f10>] (show_stack+0x20/0x24) [ 515.826782] r7:803a5900 r6:00000009 r5:00000000 r4:9d88fe04 [ 515.832454] [<80107ef0>] (show_stack) from [<80690184>] (dump_stack+0x20/0x28) [ 515.839687] [<80690164>] (dump_stack) from [<80116044>] (__warn.part.3+0xb4/0xdc) [ 515.847170] [<80115f90>] (__warn.part.3) from [<801160d8>] (warn_slowpath_fmt+0x6c/0x90) [ 515.855247] r6:00000339 r5:8080befc r4:80a07008 [ 515.859868] [<80116070>] (warn_slowpath_fmt) from [<803a5900>] (clk_core_disable+0x18c/0x204) [ 515.868385] r3:8080cdd0 r2:8080c00c [ 515.871957] r7:98d682a8 r6:9d8a9200 r5:97abd560 r4:97abd560 [ 515.877615] [<803a5774>] (clk_core_disable) from [<803a59a0>] (clk_core_disable_lock+0x28/0x34) [ 515.886301] r7:98d682a8 r6:9d8a9200 r5:97abd560 r4:a0000013 [ 515.891960] [<803a5978>] (clk_core_disable_lock) from [<803a7714>] (clk_disable+0x2c/0x30) [ 515.900216] r5:9e5151a0 r4:9e515f60 [ 515.903816] [<803a76e8>] (clk_disable) from [<804f36f8>] (aspeed_video_off+0x44/0x50) [ 515.911656] [<804f36b4>] (aspeed_video_off) from [<804f4358>] (aspeed_video_release+0x90/0x114) [ 515.920341] r5:9e5044b0 r4:9e504000 [ 515.923921] [<804f42c8>] (aspeed_video_release) from [<804d302c>] (v4l2_release+0xd4/0xe8) [ 515.932184] r7:98d682a8 r6:9d087810 r5:9d8a9200 r4:9e504318 [ 515.937851] [<804d2f58>] (v4l2_release) from [<80236454>] (__fput+0x98/0x1c4) [ 515.944980] r5:9e51b608 r4:9d8a9200 [ 515.948559] [<802363bc>] (__fput) from [<802365e8>] (____fput+0x18/0x1c) [ 515.955257] r9:80a0700c r8:801011e4 r7:00000000 r6:80a64b9c r5:9d8e35a0 r4:9d8e38dc [ 515.963008] [<802365d0>] (____fput) from [<80131ca4>] (task_work_run+0x7c/0xa0) [ 515.970333] [<80131c28>] (task_work_run) from [<80106884>] (do_work_pending+0x4a8/0x578) [ 515.978421] r7:801011e4 r6:80a07008 r5:9d88ffb0 r4:ffffe000 [ 515.984086] [<801063dc>] (do_work_pending) from [<8010106c>] (slow_work_pending+0xc/0x20) [ 515.992247] Exception stack(0x9d88ffb0 to 0x9d88fff8) [ 515.997296] ffa0: 00000000 76f18094 00000000 00000000 [ 516.005473] ffc0: 00000007 00176778 7eda4c20 00000006 00000000 00000000 48e20fa4 00000000 [ 516.013642] ffe0: 00000002 7eda4b08 00000000 48f91efc 80000010 00000007 [ 516.020257] r10:00000000 r9:9d88e000 r8:801011e4 r7:00000006 r6:7eda4c20 r5:00176778 [ 516.028072] r4:00000007 [ 516.030606] ---[ end trace 12c04aadef8afbbc ]--- To prevent this issue, this commit adds clock status checking logic into the Aspeed video engine driver. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 8144fe36ad48..562d7c0adc78 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -187,6 +187,7 @@ enum { VIDEO_STREAMING, VIDEO_FRAME_INPRG, VIDEO_STOPPED, + VIDEO_CLOCKS_ON, }; struct aspeed_video_addr { @@ -483,19 +484,29 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video) static void aspeed_video_off(struct aspeed_video *video) { + if (!test_bit(VIDEO_CLOCKS_ON, &video->flags)) + return; + /* Disable interrupts */ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); /* Turn off the relevant clocks */ clk_disable_unprepare(video->vclk); clk_disable_unprepare(video->eclk); + + clear_bit(VIDEO_CLOCKS_ON, &video->flags); } static void aspeed_video_on(struct aspeed_video *video) { + if (test_bit(VIDEO_CLOCKS_ON, &video->flags)) + return; + /* Turn on the relevant clocks */ clk_prepare_enable(video->eclk); clk_prepare_enable(video->vclk); + + set_bit(VIDEO_CLOCKS_ON, &video->flags); } static void aspeed_video_bufs_done(struct aspeed_video *video, -- cgit v1.2.3-59-g8ed1b From 7b74dc0caa307a350e5710d51472af5b7858de05 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:40 -0400 Subject: media: aspeed: refine clock control logic Currently, this driver calls clk_prepare and clk_unprepare from interrupt context too but these should be called from sleepable context only. To fix this issue, this commit splits out clk_enable/disable and clk_prepare/unprepare, and it places clk_prepare/unprepare calls into the module probe/remove function. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 38 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 562d7c0adc78..7982ce634936 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -491,8 +491,8 @@ static void aspeed_video_off(struct aspeed_video *video) aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); /* Turn off the relevant clocks */ - clk_disable_unprepare(video->vclk); - clk_disable_unprepare(video->eclk); + clk_disable(video->vclk); + clk_disable(video->eclk); clear_bit(VIDEO_CLOCKS_ON, &video->flags); } @@ -503,8 +503,8 @@ static void aspeed_video_on(struct aspeed_video *video) return; /* Turn on the relevant clocks */ - clk_prepare_enable(video->eclk); - clk_prepare_enable(video->vclk); + clk_enable(video->eclk); + clk_enable(video->vclk); set_bit(VIDEO_CLOCKS_ON, &video->flags); } @@ -1613,31 +1613,46 @@ static int aspeed_video_init(struct aspeed_video *video) return PTR_ERR(video->eclk); } + rc = clk_prepare(video->eclk); + if (rc) + return rc; + video->vclk = devm_clk_get(dev, "vclk"); if (IS_ERR(video->vclk)) { dev_err(dev, "Unable to get VCLK\n"); - return PTR_ERR(video->vclk); + rc = PTR_ERR(video->vclk); + goto err_unprepare_eclk; } + rc = clk_prepare(video->vclk); + if (rc) + goto err_unprepare_eclk; + of_reserved_mem_device_init(dev); rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (rc) { dev_err(dev, "Failed to set DMA mask\n"); - of_reserved_mem_device_release(dev); - return rc; + goto err_release_reserved_mem; } if (!aspeed_video_alloc_buf(video, &video->jpeg, VE_JPEG_HEADER_SIZE)) { dev_err(dev, "Failed to allocate DMA for JPEG header\n"); - of_reserved_mem_device_release(dev); - return rc; + goto err_release_reserved_mem; } aspeed_video_init_jpeg_table(video->jpeg.virt, video->yuv420); return 0; + +err_release_reserved_mem: + of_reserved_mem_device_release(dev); + clk_unprepare(video->vclk); +err_unprepare_eclk: + clk_unprepare(video->eclk); + + return rc; } static int aspeed_video_probe(struct platform_device *pdev) @@ -1681,6 +1696,11 @@ static int aspeed_video_remove(struct platform_device *pdev) struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); struct aspeed_video *video = to_aspeed_video(v4l2_dev); + aspeed_video_off(video); + + clk_unprepare(video->vclk); + clk_unprepare(video->eclk); + video_unregister_device(&video->vdev); vb2_queue_release(&video->queue); -- cgit v1.2.3-59-g8ed1b From 12ae1c1bf5db2f33fcd9092a96f630291c4b181a Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:41 -0400 Subject: media: aspeed: change irq to threaded irq Differently from other Aspeed drivers, this driver calls clock control APIs in interrupt context. Since ECLK is coupled with a reset bit in clk-aspeed module, aspeed_clk_enable will make 10ms of busy waiting delay for triggering the reset and it will eventually disturb other drivers' interrupt handling. To fix this issue, this commit changes this driver's irq to threaded irq so that the delay can be happened in a thread context. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 7982ce634936..f7db8969c8f2 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -1600,8 +1600,9 @@ static int aspeed_video_init(struct aspeed_video *video) return -ENODEV; } - rc = devm_request_irq(dev, irq, aspeed_video_irq, IRQF_SHARED, - DEVICE_NAME, video); + rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq, + IRQF_ONESHOT | IRQF_SHARED, DEVICE_NAME, + video); if (rc < 0) { dev_err(dev, "Unable to request IRQ %d\n", irq); return rc; -- cgit v1.2.3-59-g8ed1b From c8b996ca28d0a8a5dfb423fef6d7ffce7279b19b Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:42 -0400 Subject: media: aspeed: remove IRQF_SHARED flag Video Engine has a dedicated interrupt line so this driver doesn't need to use IRQF_SHARED flag so remove it. Also, it'd be good for following what Thomas recommended in the IRQF_ONESHOT support patch like below: "Note that for now IRQF_ONESHOT cannot be used with IRQF_SHARED to avoid complex accounting mechanisms." Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index f7db8969c8f2..d1b541409544 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -1601,8 +1601,7 @@ static int aspeed_video_init(struct aspeed_video *video) } rc = devm_request_threaded_irq(dev, irq, NULL, aspeed_video_irq, - IRQF_ONESHOT | IRQF_SHARED, DEVICE_NAME, - video); + IRQF_ONESHOT, DEVICE_NAME, video); if (rc < 0) { dev_err(dev, "Unable to request IRQ %d\n", irq); return rc; -- cgit v1.2.3-59-g8ed1b From 084b6790cf356a662c473825cb945e829ee90e8a Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:43 -0400 Subject: media: aspeed: reduce noisy log printing outs Currently, this driver prints out too much log messages when a mode change happens, video turned off by screen saver and etc. Actually, all cases are reported to user space properly. Also, these are not critical errors but recoverable things, so this commit changes the log level of some noisy printing outs. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index d1b541409544..92abdfc79e76 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -441,7 +441,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video) if (!(seq_ctrl & VE_SEQ_CTRL_COMP_BUSY) || !(seq_ctrl & VE_SEQ_CTRL_CAP_BUSY)) { - dev_err(video->dev, "Engine busy; don't start frame\n"); + dev_dbg(video->dev, "Engine busy; don't start frame\n"); return -EBUSY; } @@ -769,7 +769,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) res_check(video), MODE_DETECT_TIMEOUT); if (!rc) { - dev_err(video->dev, "Timed out; first mode detect\n"); + dev_dbg(video->dev, "Timed out; first mode detect\n"); clear_bit(VIDEO_RES_DETECT, &video->flags); return; } @@ -787,7 +787,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) MODE_DETECT_TIMEOUT); clear_bit(VIDEO_RES_DETECT, &video->flags); if (!rc) { - dev_err(video->dev, "Timed out; second mode detect\n"); + dev_dbg(video->dev, "Timed out; second mode detect\n"); return; } @@ -821,7 +821,7 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) } while (invalid_resolution && (tries++ < INVALID_RESOLUTION_RETRIES)); if (invalid_resolution) { - dev_err(video->dev, "Invalid resolution detected\n"); + dev_dbg(video->dev, "Invalid resolution detected\n"); return; } @@ -1456,7 +1456,7 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q) !test_bit(VIDEO_FRAME_INPRG, &video->flags), STOP_TIMEOUT); if (!rc) { - dev_err(video->dev, "Timed out when stopping streaming\n"); + dev_dbg(video->dev, "Timed out when stopping streaming\n"); /* * Need to force stop any DMA and try and get HW into a good -- cgit v1.2.3-59-g8ed1b From f8a02b37e2188590bdc116ee0bcdf25907f5bfb8 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:44 -0400 Subject: media: aspeed: remove checking of VE_INTERRUPT_CAPTURE_COMPLETE VE_INTERRUPT_CAPTURE_COMPLETE and VE_INTERRUPT_COMP_COMPLETE are not set at the same time but the current interrupt handling mechanism of this driver doesn't clear the interrupt flag until both two are set, and this behavior causes unnecessary interrupt handler calls. In fact, this driver provides JPEG format only so taking care of the VE_INTERRUPT_COMP_COMPLETE is enough for getting compressed image frame so this commit gets rid of the VE_INTERRUPT_CAPTURE_COMPLETE checking logic to simplify the logic. Handling of VE_INTERRUPT_CAPTURE_COMPLETE could be added back later when it's actually needed. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Reviewed-by: Andrew Jeffery Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 92abdfc79e76..1cba582918cc 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -463,8 +463,7 @@ static int aspeed_video_start_frame(struct aspeed_video *video) aspeed_video_write(video, VE_COMP_ADDR, addr); aspeed_video_update(video, VE_INTERRUPT_CTRL, 0, - VE_INTERRUPT_COMP_COMPLETE | - VE_INTERRUPT_CAPTURE_COMPLETE); + VE_INTERRUPT_COMP_COMPLETE); aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_CAPTURE | VE_SEQ_CTRL_TRIG_COMP); @@ -568,8 +567,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) } } - if ((sts & VE_INTERRUPT_COMP_COMPLETE) && - (sts & VE_INTERRUPT_CAPTURE_COMPLETE)) { + if (sts & VE_INTERRUPT_COMP_COMPLETE) { struct aspeed_video_buffer *buf; u32 frame_size = aspeed_video_read(video, VE_OFFSET_COMP_STREAM); @@ -598,11 +596,9 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) VE_SEQ_CTRL_FORCE_IDLE | VE_SEQ_CTRL_TRIG_COMP, 0); aspeed_video_update(video, VE_INTERRUPT_CTRL, - VE_INTERRUPT_COMP_COMPLETE | - VE_INTERRUPT_CAPTURE_COMPLETE, 0); + VE_INTERRUPT_COMP_COMPLETE, 0); aspeed_video_write(video, VE_INTERRUPT_STATUS, - VE_INTERRUPT_COMP_COMPLETE | - VE_INTERRUPT_CAPTURE_COMPLETE); + VE_INTERRUPT_COMP_COMPLETE); if (test_bit(VIDEO_STREAMING, &video->flags) && buf) aspeed_video_start_frame(video); -- cgit v1.2.3-59-g8ed1b From 68b65879e81608b4fcb216e34ca083f048c84676 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:45 -0400 Subject: media: aspeed: refine interrupt handling logic There are cases that interrupt bits are cleared by a 500ms delayed work which causes unnecessary irq calls. Also, the current interrupt handler returns IRQ_HANDLED always but it should return IRQ_NONE if there is any unhandled interrupt. So this commit refines the interrupt handling logic to fix these issues. Signed-off-by: Jae Hyun Yoo Reviewed-by: Andrew Jeffery Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 1cba582918cc..c0b889141b8f 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -488,6 +488,7 @@ static void aspeed_video_off(struct aspeed_video *video) /* Disable interrupts */ aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); + aspeed_video_write(video, VE_INTERRUPT_STATUS, 0xffffffff); /* Turn off the relevant clocks */ clk_disable(video->vclk); @@ -554,7 +555,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) VE_INTERRUPT_MODE_DETECT, 0); aspeed_video_write(video, VE_INTERRUPT_STATUS, VE_INTERRUPT_MODE_DETECT); - + sts &= ~VE_INTERRUPT_MODE_DETECT; set_bit(VIDEO_MODE_DETECT_DONE, &video->flags); wake_up_interruptible_all(&video->wait); } else { @@ -599,12 +600,12 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) VE_INTERRUPT_COMP_COMPLETE, 0); aspeed_video_write(video, VE_INTERRUPT_STATUS, VE_INTERRUPT_COMP_COMPLETE); - + sts &= ~VE_INTERRUPT_COMP_COMPLETE; if (test_bit(VIDEO_STREAMING, &video->flags) && buf) aspeed_video_start_frame(video); } - return IRQ_HANDLED; + return sts ? IRQ_NONE : IRQ_HANDLED; } static void aspeed_video_check_and_set_polarity(struct aspeed_video *video) -- cgit v1.2.3-59-g8ed1b From 99914b61156041123a547da9a8132e7cc44e4e40 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:46 -0400 Subject: media: aspeed: remove source buffer allocation before mode detection Mode detection doesn't require source buffer allocation so this commit removes that. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 37 +++++------------------------------ 1 file changed, 5 insertions(+), 32 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index c0b889141b8f..d6708ddb0391 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -731,27 +731,6 @@ static void aspeed_video_get_resolution(struct aspeed_video *video) det->height = MIN_HEIGHT; video->v4l2_input_status = V4L2_IN_ST_NO_SIGNAL; - /* - * Since we need max buffer size for detection, free the second source - * buffer first. - */ - if (video->srcs[1].size) - aspeed_video_free_buf(video, &video->srcs[1]); - - if (video->srcs[0].size < VE_MAX_SRC_BUFFER_SIZE) { - if (video->srcs[0].size) - aspeed_video_free_buf(video, &video->srcs[0]); - - if (!aspeed_video_alloc_buf(video, &video->srcs[0], - VE_MAX_SRC_BUFFER_SIZE)) { - dev_err(video->dev, - "Failed to allocate source buffers\n"); - return; - } - } - - aspeed_video_write(video, VE_SRC0_ADDR, video->srcs[0].dma); - do { if (tries) { set_current_state(TASK_INTERRUPTIBLE); @@ -871,20 +850,14 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) size *= 4; - if (size == video->srcs[0].size / 2) { - aspeed_video_write(video, VE_SRC1_ADDR, - video->srcs[0].dma + size); - } else if (size == video->srcs[0].size) { - if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) - goto err_mem; - - aspeed_video_write(video, VE_SRC1_ADDR, video->srcs[1].dma); - } else { - aspeed_video_free_buf(video, &video->srcs[0]); + if (size != video->srcs[0].size) { + if (video->srcs[0].size) + aspeed_video_free_buf(video, &video->srcs[0]); + if (video->srcs[1].size) + aspeed_video_free_buf(video, &video->srcs[1]); if (!aspeed_video_alloc_buf(video, &video->srcs[0], size)) goto err_mem; - if (!aspeed_video_alloc_buf(video, &video->srcs[1], size)) goto err_mem; -- cgit v1.2.3-59-g8ed1b From 2b0287ef1d9e9a86517d481d270ac160a8c31651 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:47 -0400 Subject: media: aspeed: use different delays for triggering VE H/W reset In case of watchdog timeout detected while doing mode detection, it's better triggering video engine hardware reset immediately so this commit fixes code for the case. Other than the case, it will trigger video engine hardware reset after RESOLUTION_CHANGE_DELAY. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index d6708ddb0391..ba093096a5a7 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -522,7 +522,7 @@ static void aspeed_video_bufs_done(struct aspeed_video *video, spin_unlock_irqrestore(&video->lock, flags); } -static void aspeed_video_irq_res_change(struct aspeed_video *video) +static void aspeed_video_irq_res_change(struct aspeed_video *video, ulong delay) { dev_dbg(video->dev, "Resolution changed; resetting\n"); @@ -532,7 +532,7 @@ static void aspeed_video_irq_res_change(struct aspeed_video *video) aspeed_video_off(video); aspeed_video_bufs_done(video, VB2_BUF_STATE_ERROR); - schedule_delayed_work(&video->res_work, RESOLUTION_CHANGE_DELAY); + schedule_delayed_work(&video->res_work, delay); } static irqreturn_t aspeed_video_irq(int irq, void *arg) @@ -545,7 +545,7 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) * re-initialize */ if (sts & VE_INTERRUPT_MODE_DETECT_WD) { - aspeed_video_irq_res_change(video); + aspeed_video_irq_res_change(video, 0); return IRQ_HANDLED; } @@ -563,7 +563,8 @@ static irqreturn_t aspeed_video_irq(int irq, void *arg) * Signal acquired while NOT doing resolution * detection; reset the engine and re-initialize */ - aspeed_video_irq_res_change(video); + aspeed_video_irq_res_change(video, + RESOLUTION_CHANGE_DELAY); return IRQ_HANDLED; } } -- cgit v1.2.3-59-g8ed1b From 7aac98494d1d932cde053861ce0c12ca5ab3f762 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Jun 2019 08:20:15 -0400 Subject: media: platform: ao-cec-g12a: remove spin_lock_irqsave() locking in meson_ao_cec_g12a_read/write Since locking is handled by regmap, the spin_lock_irqsave() in the meson_ao_cec_g12a_read/write() regmap callbacks is not needed. Fixes: b7778c46683c ("media: platform: meson: Add Amlogic Meson G12A AO CEC Controller driver") Signed-off-by: Neil Armstrong Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/meson/ao-cec-g12a.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c index ddfd060625da..fb52e5dd044a 100644 --- a/drivers/media/platform/meson/ao-cec-g12a.c +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -365,28 +365,22 @@ static int meson_ao_cec_g12a_read(void *context, unsigned int addr, { struct meson_ao_cec_g12a_device *ao_cec = context; u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); - unsigned long flags; int ret = 0; - spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); - ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); if (ret) - goto read_out; + return ret; ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, !(reg & CECB_RW_BUS_BUSY), 5, 1000); if (ret) - goto read_out; + return ret; ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); *data = FIELD_GET(CECB_RW_RD_DATA, reg); -read_out: - spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); - return ret; } @@ -394,19 +388,11 @@ static int meson_ao_cec_g12a_write(void *context, unsigned int addr, unsigned int data) { struct meson_ao_cec_g12a_device *ao_cec = context; - unsigned long flags; u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | FIELD_PREP(CECB_RW_WR_DATA, data) | CECB_RW_WRITE_EN; - int ret = 0; - spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); - - ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); - - spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); - - return ret; + return regmap_write(ao_cec->regmap, CECB_RW_REG, reg); } static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { -- cgit v1.2.3-59-g8ed1b From 6e2980cc68d0dfac1c734fae887754c1cb9904a0 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 5 Jun 2019 09:08:20 -0400 Subject: media: pvrusb2: fix null-ptr-deref in class_unregister() The class_ptr will be NULL if pvr2_sysfs_class_create() fails in pvr_init(), when call pvr2_sysfs_class_destroy(), it will lead to null-ptr-deref, fix it. Reported-by: Hulk Robot Signed-off-by: Kefeng Wang Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-sysfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 7bc6d090358e..b6c6b314fadc 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -802,7 +802,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void) void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp) { pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp); - class_unregister(&clp->class); + if (clp) + class_unregister(&clp->class); } -- cgit v1.2.3-59-g8ed1b From f0d2b7a8915a00917207dd23aaf8554d7bf777b0 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 5 Jun 2019 12:46:25 -0400 Subject: media: v4l2: Fix the _MPLANE format check in v4l_enum_fmt() CAP_M2M_MPLANE means the device supports _MPLANE formats for both capture and output. Adjust the check to avoid EINVAL errors on such devices. Reported-by: Maxime Jourdan Signed-off-by: Boris Brezillon Reviewed-by: Tomasz Figa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 14596e8ad2c6..21e7ecf491c3 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1385,6 +1385,7 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, struct video_device *vdev = video_devdata(file); struct v4l2_fmtdesc *p = arg; int ret = check_fmt(file, p->type); + u32 cap_mask; if (ret) return ret; @@ -1393,7 +1394,9 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, switch (p->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (!!(vdev->device_caps & V4L2_CAP_VIDEO_CAPTURE_MPLANE) != + cap_mask = V4L2_CAP_VIDEO_CAPTURE_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (!!(vdev->device_caps & cap_mask) != (p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)) break; @@ -1408,7 +1411,9 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops, break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!!(vdev->device_caps & V4L2_CAP_VIDEO_OUTPUT_MPLANE) != + cap_mask = V4L2_CAP_VIDEO_OUTPUT_MPLANE | + V4L2_CAP_VIDEO_M2M_MPLANE; + if (!!(vdev->device_caps & cap_mask) != (p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)) break; -- cgit v1.2.3-59-g8ed1b From 3c8f4cd271c486844e8eccebaf6714d913180ecc Mon Sep 17 00:00:00 2001 From: Tobias Klausmann Date: Wed, 29 May 2019 12:56:33 -0400 Subject: media: stv6110x: Implement probe/remove for stv6110x Refactor out the common parts of stv6110x_probe() and stv6110x_attach() into separate functions. This provides the needed functionality to use dvb_module_probe() instead of dvb_attach()! Signed-off-by: Tobias Klausmann Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv6110x.c | 135 +++++++++++++++++++++++----- drivers/media/dvb-frontends/stv6110x.h | 3 + drivers/media/dvb-frontends/stv6110x_priv.h | 3 +- 3 files changed, 118 insertions(+), 23 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c index 0126cfae2e03..5012d0231652 100644 --- a/drivers/media/dvb-frontends/stv6110x.c +++ b/drivers/media/dvb-frontends/stv6110x.c @@ -333,6 +333,41 @@ static void stv6110x_release(struct dvb_frontend *fe) kfree(stv6110x); } +static void st6110x_init_regs(struct stv6110x_state *stv6110x) +{ + u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; + + memcpy(stv6110x->regs, default_regs, 8); +} + +static void stv6110x_setup_divider(struct stv6110x_state *stv6110x) +{ + switch (stv6110x->config->clk_div) { + default: + case 1: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 0); + break; + case 2: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 1); + break; + case 4: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 2); + break; + case 8: + case 0: + STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], + CTRL2_CO_DIV, + 3); + break; + } +} + static const struct dvb_tuner_ops stv6110x_ops = { .info = { .name = "STV6110(A) Silicon Tuner", @@ -342,7 +377,7 @@ static const struct dvb_tuner_ops stv6110x_ops = { .release = stv6110x_release }; -static const struct stv6110x_devctl stv6110x_ctl = { +static struct stv6110x_devctl stv6110x_ctl = { .tuner_init = stv6110x_init, .tuner_sleep = stv6110x_sleep, .tuner_set_mode = stv6110x_set_mode, @@ -356,48 +391,104 @@ static const struct stv6110x_devctl stv6110x_ctl = { .tuner_get_status = stv6110x_get_status, }; +static void stv6110x_set_frontend_opts(struct stv6110x_state *stv6110x) +{ + stv6110x->frontend->tuner_priv = stv6110x; + stv6110x->frontend->ops.tuner_ops = stv6110x_ops; +} + +static struct stv6110x_devctl *stv6110x_get_devctl(struct i2c_client *client) +{ + struct stv6110x_state *stv6110x = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + return stv6110x->devctl; +} + +static int stv6110x_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct stv6110x_config *config = client->dev.platform_data; + + struct stv6110x_state *stv6110x; + + stv6110x = kzalloc(sizeof(*stv6110x), GFP_KERNEL); + if (!stv6110x) + return -ENOMEM; + + stv6110x->frontend = config->frontend; + stv6110x->i2c = client->adapter; + stv6110x->config = config; + stv6110x->devctl = &stv6110x_ctl; + + st6110x_init_regs(stv6110x); + stv6110x_setup_divider(stv6110x); + stv6110x_set_frontend_opts(stv6110x); + + dev_info(&stv6110x->i2c->dev, "Probed STV6110x\n"); + + i2c_set_clientdata(client, stv6110x); + + /* setup callbacks */ + config->get_devctl = stv6110x_get_devctl; + + return 0; +} + +static int stv6110x_remove(struct i2c_client *client) +{ + struct stv6110x_state *stv6110x = i2c_get_clientdata(client); + + stv6110x_release(stv6110x->frontend); + return 0; +} + const struct stv6110x_devctl *stv6110x_attach(struct dvb_frontend *fe, const struct stv6110x_config *config, struct i2c_adapter *i2c) { struct stv6110x_state *stv6110x; - u8 default_regs[] = {0x07, 0x11, 0xdc, 0x85, 0x17, 0x01, 0xe6, 0x1e}; - stv6110x = kzalloc(sizeof (struct stv6110x_state), GFP_KERNEL); + stv6110x = kzalloc(sizeof(*stv6110x), GFP_KERNEL); if (!stv6110x) return NULL; + stv6110x->frontend = fe; stv6110x->i2c = i2c; stv6110x->config = config; stv6110x->devctl = &stv6110x_ctl; - memcpy(stv6110x->regs, default_regs, 8); - /* setup divider */ - switch (stv6110x->config->clk_div) { - default: - case 1: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 0); - break; - case 2: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 1); - break; - case 4: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 2); - break; - case 8: - case 0: - STV6110x_SETFIELD(stv6110x->regs[STV6110x_CTRL2], CTRL2_CO_DIV, 3); - break; - } + st6110x_init_regs(stv6110x); + stv6110x_setup_divider(stv6110x); + stv6110x_set_frontend_opts(stv6110x); fe->tuner_priv = stv6110x; fe->ops.tuner_ops = stv6110x_ops; - printk(KERN_INFO "%s: Attaching STV6110x\n", __func__); + dev_info(&stv6110x->i2c->dev, "Attaching STV6110x\n"); return stv6110x->devctl; } EXPORT_SYMBOL(stv6110x_attach); +static const struct i2c_device_id stv6110x_id_table[] = { + {"stv6110x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stv6110x_id_table); + +static struct i2c_driver stv6110x_driver = { + .driver = { + .name = "stv6110x", + .suppress_bind_attrs = true, + }, + .probe = stv6110x_probe, + .remove = stv6110x_remove, + .id_table = stv6110x_id_table, +}; + +module_i2c_driver(stv6110x_driver); + MODULE_AUTHOR("Manu Abraham"); MODULE_DESCRIPTION("STV6110x Silicon tuner"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/stv6110x.h b/drivers/media/dvb-frontends/stv6110x.h index 1630e55255fd..1feade3158c2 100644 --- a/drivers/media/dvb-frontends/stv6110x.h +++ b/drivers/media/dvb-frontends/stv6110x.h @@ -15,6 +15,9 @@ struct stv6110x_config { u8 addr; u32 refclk; u8 clk_div; /* divisor value for the output clock */ + struct dvb_frontend *frontend; + + struct stv6110x_devctl* (*get_devctl)(struct i2c_client *i2c); }; enum tuner_mode { diff --git a/drivers/media/dvb-frontends/stv6110x_priv.h b/drivers/media/dvb-frontends/stv6110x_priv.h index 909094df28df..b27769558f78 100644 --- a/drivers/media/dvb-frontends/stv6110x_priv.h +++ b/drivers/media/dvb-frontends/stv6110x_priv.h @@ -54,11 +54,12 @@ #define REFCLOCK_MHz (stv6110x->config->refclk / 1000000) struct stv6110x_state { + struct dvb_frontend *frontend; struct i2c_adapter *i2c; const struct stv6110x_config *config; u8 regs[8]; - const struct stv6110x_devctl *devctl; + struct stv6110x_devctl *devctl; }; #endif /* __STV6110x_PRIV_H */ -- cgit v1.2.3-59-g8ed1b From eb5005df886b3989dde5378064cc23315f769290 Mon Sep 17 00:00:00 2001 From: Tobias Klausmann Date: Wed, 29 May 2019 14:02:06 -0400 Subject: media: stv090x: Implement probe/remove for stv090x Move common code into a new function. This provides the needed functionality to use dvb_module_probe() instead of dvb_attach()! [mchehab+samsung@kernel.org: fix an out of order error return code] Signed-off-by: Tobias Klausmann Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv090x.c | 198 +++++++++++++++++++++-------- drivers/media/dvb-frontends/stv090x.h | 3 + drivers/media/dvb-frontends/stv090x_priv.h | 2 +- 3 files changed, 150 insertions(+), 53 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index d1261571dbe4..986e585e0103 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -4889,6 +4889,67 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); } +static int stv090x_setup_compound(struct stv090x_state *state) +{ + struct stv090x_dev *temp_int; + + temp_int = find_dev(state->i2c, + state->config->address); + + if (temp_int && state->demod_mode == STV090x_DUAL) { + state->internal = temp_int->internal; + state->internal->num_used++; + dprintk(FE_INFO, 1, "Found Internal Structure!"); + } else { + state->internal = kmalloc(sizeof(*state->internal), GFP_KERNEL); + if (!state->internal) + goto error; + temp_int = append_internal(state->internal); + if (!temp_int) { + kfree(state->internal); + goto error; + } + state->internal->num_used = 1; + state->internal->mclk = 0; + state->internal->dev_ver = 0; + state->internal->i2c_adap = state->i2c; + state->internal->i2c_addr = state->config->address; + dprintk(FE_INFO, 1, "Create New Internal Structure!"); + + mutex_init(&state->internal->demod_lock); + mutex_init(&state->internal->tuner_lock); + + if (stv090x_setup(&state->frontend) < 0) { + dprintk(FE_ERROR, 1, "Error setting up device"); + goto err_remove; + } + } + + if (state->internal->dev_ver >= 0x30) + state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM; + + /* workaround for stuck DiSEqC output */ + if (state->config->diseqc_envelope_mode) + stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); + + state->config->set_gpio = stv090x_set_gpio; + + dprintk(FE_ERROR, 1, "Probing %s demodulator(%d) Cut=0x%02x", + state->device == STV0900 ? "STV0900" : "STV0903", + state->config->demod, + state->internal->dev_ver); + + return 0; + +error: + kfree(state); + return -ENOMEM; +err_remove: + remove_dev(state->internal); + kfree(state->internal); + return -ENODEV; +} + static const struct dvb_frontend_ops stv090x_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { @@ -4921,85 +4982,118 @@ static const struct dvb_frontend_ops stv090x_ops = { .read_snr = stv090x_read_cnr, }; +static struct dvb_frontend *stv090x_get_dvb_frontend(struct i2c_client *client) +{ + struct stv090x_state *state = i2c_get_clientdata(client); -struct dvb_frontend *stv090x_attach(struct stv090x_config *config, - struct i2c_adapter *i2c, - enum stv090x_demodulator demod) + dev_dbg(&client->dev, "\n"); + + return &state->frontend; +} + +static int stv090x_probe(struct i2c_client *client, + const struct i2c_device_id *id) { + int ret = 0; + struct stv090x_config *config = client->dev.platform_data; + struct stv090x_state *state = NULL; - struct stv090x_dev *temp_int; - state = kzalloc(sizeof (struct stv090x_state), GFP_KERNEL); - if (state == NULL) + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) { + ret = -ENOMEM; goto error; + } state->verbose = &verbose; state->config = config; - state->i2c = i2c; + state->i2c = client->adapter; state->frontend.ops = stv090x_ops; state->frontend.demodulator_priv = state; - state->demod = demod; - state->demod_mode = config->demod_mode; /* Single or Dual mode */ + state->demod = config->demod; + /* Single or Dual mode */ + state->demod_mode = config->demod_mode; state->device = config->device; - state->rolloff = STV090x_RO_35; /* default */ + /* default */ + state->rolloff = STV090x_RO_35; - temp_int = find_dev(state->i2c, - state->config->address); + ret = stv090x_setup_compound(state); + if (ret) + goto error; - if ((temp_int != NULL) && (state->demod_mode == STV090x_DUAL)) { - state->internal = temp_int->internal; - state->internal->num_used++; - dprintk(FE_INFO, 1, "Found Internal Structure!"); - } else { - state->internal = kmalloc(sizeof(struct stv090x_internal), - GFP_KERNEL); - if (!state->internal) - goto error; - temp_int = append_internal(state->internal); - if (!temp_int) { - kfree(state->internal); - goto error; - } - state->internal->num_used = 1; - state->internal->mclk = 0; - state->internal->dev_ver = 0; - state->internal->i2c_adap = state->i2c; - state->internal->i2c_addr = state->config->address; - dprintk(FE_INFO, 1, "Create New Internal Structure!"); + i2c_set_clientdata(client, state); - mutex_init(&state->internal->demod_lock); - mutex_init(&state->internal->tuner_lock); + /* setup callbacks */ + config->get_dvb_frontend = stv090x_get_dvb_frontend; - if (stv090x_setup(&state->frontend) < 0) { - dprintk(FE_ERROR, 1, "Error setting up device"); - goto err_remove; - } - } + return 0; - if (state->internal->dev_ver >= 0x30) - state->frontend.ops.info.caps |= FE_CAN_MULTISTREAM; +error: + kfree(state); + return ret; +} - /* workaround for stuck DiSEqC output */ - if (config->diseqc_envelope_mode) - stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A); +static int stv090x_remove(struct i2c_client *client) +{ + struct stv090x_state *state = i2c_get_clientdata(client); + + stv090x_release(&state->frontend); + return 0; +} - config->set_gpio = stv090x_set_gpio; +struct dvb_frontend *stv090x_attach(struct stv090x_config *config, + struct i2c_adapter *i2c, + enum stv090x_demodulator demod) +{ + int ret = 0; + struct stv090x_state *state = NULL; - dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x", - state->device == STV0900 ? "STV0900" : "STV0903", - demod, - state->internal->dev_ver); + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + goto error; + + state->verbose = &verbose; + state->config = config; + state->i2c = i2c; + state->frontend.ops = stv090x_ops; + state->frontend.demodulator_priv = state; + state->demod = demod; + /* Single or Dual mode */ + state->demod_mode = config->demod_mode; + state->device = config->device; + /* default */ + state->rolloff = STV090x_RO_35; + + ret = stv090x_setup_compound(state); + if (ret) + goto error; return &state->frontend; -err_remove: - remove_dev(state->internal); - kfree(state->internal); error: kfree(state); return NULL; } EXPORT_SYMBOL(stv090x_attach); + +static const struct i2c_device_id stv090x_id_table[] = { + {"stv090x", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, stv090x_id_table); + +static struct i2c_driver stv090x_driver = { + .driver = { + .name = "stv090x", + .suppress_bind_attrs = true, + }, + .probe = stv090x_probe, + .remove = stv090x_remove, + .id_table = stv090x_id_table, +}; + +module_i2c_driver(stv090x_driver); + MODULE_PARM_DESC(verbose, "Set Verbosity level"); MODULE_AUTHOR("Manu Abraham"); MODULE_DESCRIPTION("STV090x Multi-Std Broadcast frontend"); diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h index 13f251a08abd..89f45d9fa427 100644 --- a/drivers/media/dvb-frontends/stv090x.h +++ b/drivers/media/dvb-frontends/stv090x.h @@ -57,6 +57,7 @@ struct stv090x_config { enum stv090x_device device; enum stv090x_mode demod_mode; enum stv090x_clkmode clk_mode; + enum stv090x_demodulator demod; u32 xtal; /* default: 8000000 */ u8 address; /* default: 0x68 */ @@ -93,6 +94,8 @@ struct stv090x_config { /* dir = 0 -> output, dir = 1 -> input/open-drain */ int (*set_gpio)(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value, u8 xor_value); + + struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *i2c); }; #if IS_REACHABLE(CONFIG_DVB_STV090x) diff --git a/drivers/media/dvb-frontends/stv090x_priv.h b/drivers/media/dvb-frontends/stv090x_priv.h index b22c58968c93..f8ece898c153 100644 --- a/drivers/media/dvb-frontends/stv090x_priv.h +++ b/drivers/media/dvb-frontends/stv090x_priv.h @@ -237,7 +237,7 @@ struct stv090x_state { struct stv090x_internal *internal; struct i2c_adapter *i2c; - const struct stv090x_config *config; + struct stv090x_config *config; struct dvb_frontend frontend; u32 *verbose; /* Cached module verbosity */ -- cgit v1.2.3-59-g8ed1b From 71f49a8bf5c592413edb5c8839ec0e6d754db3e1 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 4 Jun 2019 07:19:30 -0400 Subject: media: ttpci: use rc-core for the IR receiver The IR protocol can now only be set via the rc protocols sysfs file rather than via module parameters or a custom procfs file. So, it is no longer necessary to periodically check for protocol changes. The IR_RCMM protocol does not decode the Philips RC-MM protocol (12, 24 or 32 bit variants) or any protocol rc-core can encode, so this is marked RC_PROTO_UNKNOWN. Tested on Technotrend/Hauppauge WinTV Nexus-S rev2.1, which comes with a small black hauppauge remote. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/av7110.c | 14 +- drivers/media/pci/ttpci/av7110.h | 21 +- drivers/media/pci/ttpci/av7110_ir.c | 423 ++++++++------------------------ drivers/media/rc/keymaps/rc-hauppauge.c | 1 + 4 files changed, 112 insertions(+), 347 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index e6ee23544a6e..d0cdee1c6eb0 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -218,7 +218,7 @@ static void recover_arm(struct av7110 *av7110) restart_feeds(av7110); #if IS_ENABLED(CONFIG_DVB_AV7110_IR) - av7110_check_ir_config(av7110, true); + av7110_set_ir_config(av7110); #endif } @@ -250,10 +250,6 @@ static int arm_thread(void *data) if (!av7110->arm_ready) continue; -#if IS_ENABLED(CONFIG_DVB_AV7110_IR) - av7110_check_ir_config(av7110, false); -#endif - if (mutex_lock_interruptible(&av7110->dcomlock)) break; newloops = rdebi(av7110, DEBINOSWAP, STATUS_LOOPS, 0, 2); @@ -659,9 +655,11 @@ static void gpioirq(unsigned long cookie) return; case DATA_IRCOMMAND: - if (av7110->ir.ir_handler) - av7110->ir.ir_handler(av7110, - swahw32(irdebi(av7110, DEBINOSWAP, Reserved, 0, 4))); +#if IS_ENABLED(CONFIG_DVB_AV7110_IR) + av7110_ir_handler(av7110, + swahw32(irdebi(av7110, DEBINOSWAP, Reserved, + 0, 4))); +#endif iwdebi(av7110, DEBINOSWAP, RX_BUFF, 0, 2); break; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 8606ef5ebbe2..809d938ae166 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -81,23 +81,11 @@ struct av7110; /* infrared remote control */ struct infrared { - u16 key_map[256]; - struct input_dev *input_dev; + struct rc_dev *rcdev; char input_phys[32]; - struct timer_list keyup_timer; - struct tasklet_struct ir_tasklet; - void (*ir_handler)(struct av7110 *av7110, u32 ircom); - u32 ir_command; u32 ir_config; - u32 device_mask; - u8 protocol; - u8 inversion; - u16 last_key; - u16 last_toggle; - bool keypressed; }; - /* place to store all the necessary device information */ struct av7110 { @@ -304,9 +292,10 @@ struct av7110 { extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid, u16 subpid, u16 pcrpid); -extern int av7110_check_ir_config(struct av7110 *av7110, int force); -extern int av7110_ir_init(struct av7110 *av7110); -extern void av7110_ir_exit(struct av7110 *av7110); +void av7110_ir_handler(struct av7110 *av7110, u32 ircom); +int av7110_set_ir_config(struct av7110 *av7110); +int av7110_ir_init(struct av7110 *av7110); +void av7110_ir_exit(struct av7110 *av7110); /* msp3400 i2c subaddresses */ #define MSP_WR_DEM 0x10 diff --git a/drivers/media/pci/ttpci/av7110_ir.c b/drivers/media/pci/ttpci/av7110_ir.c index dfa18878e5f0..432789a3c312 100644 --- a/drivers/media/pci/ttpci/av7110_ir.c +++ b/drivers/media/pci/ttpci/av7110_ir.c @@ -4,379 +4,156 @@ * * Copyright (C) 1999-2003 Holger Waechtler * Copyright (C) 2003-2007 Oliver Endriss + * Copyright (C) 2019 Sean Young */ - -#include -#include -#include -#include #include -#include +#include #include "av7110.h" #include "av7110_hw.h" - -#define AV_CNT 4 - #define IR_RC5 0 #define IR_RCMM 1 #define IR_RC5_EXT 2 /* internal only */ -#define IR_ALL 0xffffffff - -#define UP_TIMEOUT (HZ*7/25) - - -/* Note: enable ir debugging by or'ing debug with 16 */ - -static int ir_protocol[AV_CNT] = { IR_RCMM, IR_RCMM, IR_RCMM, IR_RCMM}; -module_param_array(ir_protocol, int, NULL, 0644); -MODULE_PARM_DESC(ir_protocol, "Infrared protocol: 0 RC5, 1 RCMM (default)"); - -static int ir_inversion[AV_CNT]; -module_param_array(ir_inversion, int, NULL, 0644); -MODULE_PARM_DESC(ir_inversion, "Inversion of infrared signal: 0 not inverted (default), 1 inverted"); - -static uint ir_device_mask[AV_CNT] = { IR_ALL, IR_ALL, IR_ALL, IR_ALL }; -module_param_array(ir_device_mask, uint, NULL, 0644); -MODULE_PARM_DESC(ir_device_mask, "Bitmask of infrared devices: bit 0..31 = device 0..31 (default: all)"); - - -static int av_cnt; -static struct av7110 *av_list[AV_CNT]; - -static u16 default_key_map [256] = { - KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, - KEY_8, KEY_9, KEY_BACK, 0, KEY_POWER, KEY_MUTE, 0, KEY_INFO, - KEY_VOLUMEUP, KEY_VOLUMEDOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - KEY_CHANNELUP, KEY_CHANNELDOWN, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_TEXT, 0, 0, KEY_TV, 0, 0, 0, 0, 0, KEY_SETUP, 0, 0, - 0, 0, 0, KEY_SUBTITLE, 0, 0, KEY_LANGUAGE, 0, - KEY_RADIO, 0, 0, 0, 0, KEY_EXIT, 0, 0, - KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_OK, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RED, KEY_GREEN, KEY_YELLOW, - KEY_BLUE, 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_LIST, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, KEY_UP, KEY_UP, KEY_DOWN, KEY_DOWN, - 0, 0, 0, 0, KEY_EPG, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_VCR -}; - - -/* key-up timer */ -static void av7110_emit_keyup(struct timer_list *t) -{ - struct infrared *ir = from_timer(ir, t, keyup_timer); - - if (!ir || !ir->keypressed) - return; - - input_report_key(ir->input_dev, ir->last_key, 0); - input_sync(ir->input_dev); - ir->keypressed = false; -} - - -/* tasklet */ -static void av7110_emit_key(unsigned long parm) +/* interrupt handler */ +void av7110_ir_handler(struct av7110 *av7110, u32 ircom) { - struct infrared *ir = (struct infrared *) parm; - u32 ircom = ir->ir_command; - u8 data; - u8 addr; - u16 toggle; - u16 keycode; - - /* extract device address and data */ - switch (ir->protocol) { - case IR_RC5: /* RC5: 5 bits device address, 6 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - toggle = ircom & 0x0800; - break; + struct rc_dev *rcdev = av7110->ir.rcdev; + enum rc_proto proto; + u32 command, addr, scancode; + u32 toggle; - case IR_RCMM: /* RCMM: ? bits device address, ? bits data */ - data = ircom & 0xff; - addr = (ircom >> 8) & 0x1f; - toggle = ircom & 0x8000; - break; - - case IR_RC5_EXT: /* extended RC5: 5 bits device address, 7 bits data */ - data = ircom & 0x3f; - addr = (ircom >> 6) & 0x1f; - /* invert 7th data bit for backward compatibility with RC5 keymaps */ - if (!(ircom & 0x1000)) - data |= 0x40; - toggle = ircom & 0x0800; - break; - - default: - printk("%s invalid protocol %x\n", __func__, ir->protocol); - return; - } - - input_event(ir->input_dev, EV_MSC, MSC_RAW, (addr << 16) | data); - input_event(ir->input_dev, EV_MSC, MSC_SCAN, data); - - keycode = ir->key_map[data]; - - dprintk(16, "%s: code %08x -> addr %i data 0x%02x -> keycode %i\n", - __func__, ircom, addr, data, keycode); - - /* check device address */ - if (!(ir->device_mask & (1 << addr))) - return; - - if (!keycode) { - printk ("%s: code %08x -> addr %i data 0x%02x -> unknown key!\n", - __func__, ircom, addr, data); - return; - } - - if (ir->keypressed && - (ir->last_key != keycode || toggle != ir->last_toggle)) - input_event(ir->input_dev, EV_KEY, ir->last_key, 0); - - input_event(ir->input_dev, EV_KEY, keycode, 1); - input_sync(ir->input_dev); - - ir->keypressed = true; - ir->last_key = keycode; - ir->last_toggle = toggle; - - mod_timer(&ir->keyup_timer, jiffies + UP_TIMEOUT); -} - - -/* register with input layer */ -static void input_register_keys(struct infrared *ir) -{ - int i; + dprintk(4, "ir command = %08x\n", ircom); - set_bit(EV_KEY, ir->input_dev->evbit); - set_bit(EV_REP, ir->input_dev->evbit); - set_bit(EV_MSC, ir->input_dev->evbit); + if (rcdev) { + switch (av7110->ir.ir_config) { + case IR_RC5: /* RC5: 5 bits device address, 6 bits command */ + command = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + scancode = RC_SCANCODE_RC5(addr, command); + toggle = ircom & 0x0800; + proto = RC_PROTO_RC5; + break; - set_bit(MSC_RAW, ir->input_dev->mscbit); - set_bit(MSC_SCAN, ir->input_dev->mscbit); + case IR_RCMM: /* RCMM: ? bits device address, ? bits command */ + command = ircom & 0xff; + addr = (ircom >> 8) & 0x1f; + scancode = ircom; + toggle = ircom & 0x8000; + proto = RC_PROTO_UNKNOWN; + break; - memset(ir->input_dev->keybit, 0, sizeof(ir->input_dev->keybit)); + case IR_RC5_EXT: + /* + * extended RC5: 5 bits device address, 7 bits command + * + * Extended RC5 uses only one start bit. The second + * start bit is re-assigned bit 6 of the command bit. + */ + command = ircom & 0x3f; + addr = (ircom >> 6) & 0x1f; + if (!(ircom & 0x1000)) + command |= 0x40; + scancode = RC_SCANCODE_RC5(addr, command); + toggle = ircom & 0x0800; + proto = RC_PROTO_RC5; + break; + default: + dprintk(2, "unknown ir config %d\n", + av7110->ir.ir_config); + return; + } - for (i = 0; i < ARRAY_SIZE(ir->key_map); i++) { - if (ir->key_map[i] > KEY_MAX) - ir->key_map[i] = 0; - else if (ir->key_map[i] > KEY_RESERVED) - set_bit(ir->key_map[i], ir->input_dev->keybit); + rc_keydown(rcdev, proto, scancode, toggle != 0); } - - ir->input_dev->keycode = ir->key_map; - ir->input_dev->keycodesize = sizeof(ir->key_map[0]); - ir->input_dev->keycodemax = ARRAY_SIZE(ir->key_map); } -/* check for configuration changes */ -int av7110_check_ir_config(struct av7110 *av7110, int force) +int av7110_set_ir_config(struct av7110 *av7110) { - int i; - int modified = force; - int ret = -ENODEV; - - for (i = 0; i < av_cnt; i++) - if (av7110 == av_list[i]) - break; - - if (i < av_cnt && av7110) { - if ((av7110->ir.protocol & 1) != ir_protocol[i] || - av7110->ir.inversion != ir_inversion[i]) - modified = true; - - if (modified) { - /* protocol */ - if (ir_protocol[i]) { - ir_protocol[i] = 1; - av7110->ir.protocol = IR_RCMM; - av7110->ir.ir_config = 0x0001; - } else if (FW_VERSION(av7110->arm_app) >= 0x2620) { - av7110->ir.protocol = IR_RC5_EXT; - av7110->ir.ir_config = 0x0002; - } else { - av7110->ir.protocol = IR_RC5; - av7110->ir.ir_config = 0x0000; - } - /* inversion */ - if (ir_inversion[i]) { - ir_inversion[i] = 1; - av7110->ir.ir_config |= 0x8000; - } - av7110->ir.inversion = ir_inversion[i]; - /* update ARM */ - ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, - av7110->ir.ir_config); - } else - ret = 0; + dprintk(4, "ir config = %08x\n", av7110->ir.ir_config); - /* address */ - if (av7110->ir.device_mask != ir_device_mask[i]) - av7110->ir.device_mask = ir_device_mask[i]; - } - - return ret; + return av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, + av7110->ir.ir_config); } - -/* /proc/av7110_ir interface */ -static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer, - size_t count, loff_t *pos) +static int change_protocol(struct rc_dev *rcdev, u64 *rc_type) { - char *page; + struct av7110 *av7110 = rcdev->priv; u32 ir_config; - int size = sizeof ir_config + sizeof av_list[0]->ir.key_map; - int i; - if (count < size) + if (*rc_type & RC_PROTO_BIT_UNKNOWN) { + ir_config = IR_RCMM; + *rc_type = RC_PROTO_UNKNOWN; + } else if (*rc_type & RC_PROTO_BIT_RC5) { + if (FW_VERSION(av7110->arm_app) >= 0x2620) + ir_config = IR_RC5_EXT; + else + ir_config = IR_RC5; + *rc_type = RC_PROTO_BIT_RC5; + } else { return -EINVAL; - - page = vmalloc(size); - if (!page) - return -ENOMEM; - - if (copy_from_user(page, buffer, size)) { - vfree(page); - return -EFAULT; } - memcpy(&ir_config, page, sizeof ir_config); - - for (i = 0; i < av_cnt; i++) { - /* keymap */ - memcpy(av_list[i]->ir.key_map, page + sizeof ir_config, - sizeof(av_list[i]->ir.key_map)); - /* protocol, inversion, address */ - ir_protocol[i] = ir_config & 0x0001; - ir_inversion[i] = ir_config & 0x8000 ? 1 : 0; - if (ir_config & 0x4000) - ir_device_mask[i] = 1 << ((ir_config >> 16) & 0x1f); - else - ir_device_mask[i] = IR_ALL; - /* update configuration */ - av7110_check_ir_config(av_list[i], false); - input_register_keys(&av_list[i]->ir); - } - vfree(page); - return count; -} + if (ir_config == av7110->ir.ir_config) + return 0; -static const struct file_operations av7110_ir_proc_fops = { - .owner = THIS_MODULE, - .write = av7110_ir_proc_write, - .llseek = noop_llseek, -}; + av7110->ir.ir_config = ir_config; -/* interrupt handler */ -static void ir_handler(struct av7110 *av7110, u32 ircom) -{ - dprintk(4, "ir command = %08x\n", ircom); - av7110->ir.ir_command = ircom; - tasklet_schedule(&av7110->ir.ir_tasklet); + return av7110_set_ir_config(av7110); } - int av7110_ir_init(struct av7110 *av7110) { - struct input_dev *input_dev; - static struct proc_dir_entry *e; - int err; - - if (av_cnt >= ARRAY_SIZE(av_list)) - return -ENOSPC; + struct rc_dev *rcdev; + struct pci_dev *pci; + int ret; - av_list[av_cnt++] = av7110; - av7110_check_ir_config(av7110, true); - - timer_setup(&av7110->ir.keyup_timer, av7110_emit_keyup, 0); - - input_dev = input_allocate_device(); - if (!input_dev) + rcdev = rc_allocate_device(RC_DRIVER_SCANCODE); + if (!rcdev) return -ENOMEM; - av7110->ir.input_dev = input_dev; - snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), - "pci-%s/ir0", pci_name(av7110->dev->pci)); + pci = av7110->dev->pci; - input_dev->name = "DVB on-card IR receiver"; - - input_dev->phys = av7110->ir.input_phys; - input_dev->id.bustype = BUS_PCI; - input_dev->id.version = 2; - if (av7110->dev->pci->subsystem_vendor) { - input_dev->id.vendor = av7110->dev->pci->subsystem_vendor; - input_dev->id.product = av7110->dev->pci->subsystem_device; + snprintf(av7110->ir.input_phys, sizeof(av7110->ir.input_phys), + "pci-%s/ir0", pci_name(pci)); + + rcdev->device_name = av7110->card_name; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->input_phys = av7110->ir.input_phys; + rcdev->input_id.bustype = BUS_PCI; + rcdev->input_id.version = 2; + if (pci->subsystem_vendor) { + rcdev->input_id.vendor = pci->subsystem_vendor; + rcdev->input_id.product = pci->subsystem_device; } else { - input_dev->id.vendor = av7110->dev->pci->vendor; - input_dev->id.product = av7110->dev->pci->device; - } - input_dev->dev.parent = &av7110->dev->pci->dev; - /* initial keymap */ - memcpy(av7110->ir.key_map, default_key_map, sizeof av7110->ir.key_map); - input_register_keys(&av7110->ir); - err = input_register_device(input_dev); - if (err) { - input_free_device(input_dev); - return err; + rcdev->input_id.vendor = pci->vendor; + rcdev->input_id.product = pci->device; } - /* - * Input core's default autorepeat is 33 cps with 250 msec - * delay, let's adjust to numbers more suitable for remote - * control. - */ - input_enable_softrepeat(input_dev, 250, 125); + rcdev->dev.parent = &pci->dev; + rcdev->allowed_protocols = RC_PROTO_BIT_RC5 | RC_PROTO_BIT_UNKNOWN; + rcdev->change_protocol = change_protocol; + rcdev->map_name = RC_MAP_HAUPPAUGE; + rcdev->priv = av7110; - if (av_cnt == 1) { - e = proc_create("av7110_ir", S_IWUSR, NULL, &av7110_ir_proc_fops); - if (e) - proc_set_size(e, 4 + 256 * sizeof(u16)); - } + av7110->ir.rcdev = rcdev; + av7110->ir.ir_config = IR_RC5; + av7110_set_ir_config(av7110); - tasklet_init(&av7110->ir.ir_tasklet, av7110_emit_key, (unsigned long) &av7110->ir); - av7110->ir.ir_handler = ir_handler; + ret = rc_register_device(rcdev); + if (ret) { + av7110->ir.rcdev = NULL; + rc_free_device(rcdev); + } - return 0; + return ret; } - void av7110_ir_exit(struct av7110 *av7110) { - int i; - - if (av_cnt == 0) - return; - - del_timer_sync(&av7110->ir.keyup_timer); - av7110->ir.ir_handler = NULL; - tasklet_kill(&av7110->ir.ir_tasklet); - - for (i = 0; i < av_cnt; i++) - if (av_list[i] == av7110) { - av_list[i] = av_list[av_cnt-1]; - av_list[av_cnt-1] = NULL; - break; - } - - if (av_cnt == 1) - remove_proc_entry("av7110_ir", NULL); - - input_unregister_device(av7110->ir.input_dev); - - av_cnt--; + rc_unregister_device(av7110->ir.rcdev); } //MODULE_AUTHOR("Holger Waechtler , Oliver Endriss "); diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index 582aa9012443..c117e9fc2697 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -233,6 +233,7 @@ static struct rc_map_table rc5_hauppauge_new[] = { * This one also uses RC-5 protocol * Keycodes start with address = 0x00 */ + { 0x000f, KEY_TV }, { 0x001f, KEY_TV }, { 0x0020, KEY_CHANNELUP }, { 0x000c, KEY_RADIO }, -- cgit v1.2.3-59-g8ed1b From e5bc0e1ddd1cd3328297f255e215b3ca55f4fbc8 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 30 Mar 2019 10:27:36 -0400 Subject: media: vicodec: move v4l2_ctrl_request_complete after spin_unlock v4l2_ctrl_request_complete can sleep, so can't be called while a spinlock is held. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 72c56756e45b..358469f23191 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -442,14 +442,14 @@ static void device_run(void *priv) ctx->comp_has_next_frame = false; } v4l2_m2m_buf_done(dst_buf, state); - if (ctx->is_stateless && src_req) - v4l2_ctrl_request_complete(src_req, &ctx->hdl); ctx->comp_size = 0; ctx->header_size = 0; ctx->comp_magic_cnt = 0; ctx->comp_has_frame = false; spin_unlock(ctx->lock); + if (ctx->is_stateless && src_req) + v4l2_ctrl_request_complete(src_req, &ctx->hdl); if (ctx->is_enc) v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); -- cgit v1.2.3-59-g8ed1b From d421ba0c165f711a80f0ec29af4b2cff17f3a1c3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 13 Mar 2019 10:48:15 -0400 Subject: media: vicodec: always return a valid format. Rather than returning width/height values of 0, just default to a format. Formats in V4L2 are always supposed to be valid, there is no concept of an invalid format. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 358469f23191..b23d57f50c94 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1742,11 +1742,13 @@ static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { */ static int vicodec_open(struct file *file) { + const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0); struct video_device *vfd = video_devdata(file); struct vicodec_dev *dev = video_drvdata(file); struct vicodec_ctx *ctx = NULL; struct v4l2_ctrl_handler *hdl; - unsigned int size; + unsigned int raw_size; + unsigned int comp_size; int rc = 0; if (mutex_lock_interruptible(vfd->lock)) @@ -1785,7 +1787,7 @@ static int vicodec_open(struct file *file) v4l2_ctrl_handler_setup(hdl); if (ctx->is_enc) - ctx->q_data[V4L2_M2M_SRC].info = v4l2_fwht_get_pixfmt(0); + ctx->q_data[V4L2_M2M_SRC].info = info; else if (ctx->is_stateless) ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht; else @@ -1794,22 +1796,22 @@ static int vicodec_open(struct file *file) ctx->q_data[V4L2_M2M_SRC].coded_height = 720; ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; ctx->q_data[V4L2_M2M_SRC].visible_height = 720; - size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult / - ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div; + raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div; + comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult / + pixfmt_fwht.sizeimage_div; if (ctx->is_enc || ctx->is_stateless) - ctx->q_data[V4L2_M2M_SRC].sizeimage = size; + ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size; else ctx->q_data[V4L2_M2M_SRC].sizeimage = - size + sizeof(struct fwht_cframe_hdr); + comp_size + sizeof(struct fwht_cframe_hdr); + ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; if (ctx->is_enc) { - ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht; - ctx->q_data[V4L2_M2M_DST].sizeimage = 1280 * 720 * - ctx->q_data[V4L2_M2M_DST].info->sizeimage_mult / - ctx->q_data[V4L2_M2M_DST].info->sizeimage_div + - sizeof(struct fwht_cframe_hdr); + ctx->q_data[V4L2_M2M_DST].sizeimage = + comp_size + sizeof(struct fwht_cframe_hdr); } else { - ctx->q_data[V4L2_M2M_DST].info = NULL; + ctx->q_data[V4L2_M2M_DST].info = info; + ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size; } ctx->state.colorspace = V4L2_COLORSPACE_REC709; -- cgit v1.2.3-59-g8ed1b From 518f6b9a145a6994ce3838d8a917abd71ad98b70 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 6 Jun 2019 05:23:42 -0400 Subject: media: vicodec: fix initial stateless sizeimage value The initial sizeimage value was wrong for the stateless decoder. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index b23d57f50c94..7a7082808a23 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1799,8 +1799,10 @@ static int vicodec_open(struct file *file) raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div; comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult / pixfmt_fwht.sizeimage_div; - if (ctx->is_enc || ctx->is_stateless) + if (ctx->is_enc) ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size; + else if (ctx->is_stateless) + ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size; else ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size + sizeof(struct fwht_cframe_hdr); -- cgit v1.2.3-59-g8ed1b From efec9c815e5da15fe671fe7b3a0ea5575067b4b5 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 15 Mar 2019 11:04:24 -0400 Subject: media: vicodec: pass on enc output format to capture side Setting the encoder output format to e.g. 1920x1080 will set the crop rectangle to 1920x1088, the coded resolution to 1920x1088 and the capture coded resolution and sizeimage to 1920x1088 as well. Note that this might change, since the encoder spec is still in flux with respect to how this should behave. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 53 ++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 7a7082808a23..7a78d044072d 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1032,16 +1032,10 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) default: return -EINVAL; } - if (q_data->visible_width > q_data->coded_width) - q_data->visible_width = q_data->coded_width; - if (q_data->visible_height > q_data->coded_height) - q_data->visible_height = q_data->coded_height; - dprintk(ctx->dev, - "Setting format for type %d, coded wxh: %dx%d, visible wxh: %dx%d, fourcc: %08x\n", + "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n", f->type, q_data->coded_width, q_data->coded_height, - q_data->visible_width, q_data->visible_height, q_data->info->id); return 0; @@ -1063,18 +1057,58 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct vicodec_ctx *ctx = file2ctx(file); - struct v4l2_pix_format_mplane *pix_mp; + struct vicodec_q_data *q_data; + struct vicodec_q_data *q_data_cap; struct v4l2_pix_format *pix; + struct v4l2_pix_format_mplane *pix_mp; + u32 coded_w = 0, coded_h = 0; + unsigned int size = 0; int ret; + q_data = get_q_data(ctx, f->type); + q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + ret = vidioc_try_fmt_vid_out(file, priv, f); if (ret) return ret; + if (ctx->is_enc) { + struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? + &pixfmt_stateless_fwht : &pixfmt_fwht; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + coded_w = f->fmt.pix.width; + coded_h = f->fmt.pix.height; + } else { + coded_w = f->fmt.pix_mp.width; + coded_h = f->fmt.pix_mp.height; + } + if (vb2_is_busy(vq) && (coded_w != q_data->coded_width || + coded_h != q_data->coded_height)) + return -EBUSY; + size = coded_w * coded_h * + info->sizeimage_mult / info->sizeimage_div; + if (!ctx->is_stateless) + size += sizeof(struct fwht_cframe_hdr); + + if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage) + return -EBUSY; + } + ret = vidioc_s_fmt(file2ctx(file), f); if (!ret) { + if (ctx->is_enc) { + q_data->visible_width = coded_w; + q_data->visible_height = coded_h; + q_data_cap->coded_width = coded_w; + q_data_cap->coded_height = coded_h; + q_data_cap->sizeimage = size; + } + switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: pix = &f->fmt.pix; ctx->state.colorspace = pix->colorspace; @@ -1082,7 +1116,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv, ctx->state.ycbcr_enc = pix->ycbcr_enc; ctx->state.quantization = pix->quantization; break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: pix_mp = &f->fmt.pix_mp; ctx->state.colorspace = pix_mp->colorspace; -- cgit v1.2.3-59-g8ed1b From 358387d34bea5965f8330ebb71df649af587bf5f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 20 Mar 2019 07:31:39 -0400 Subject: media: vicodec: add V4L2_CID_MIN_BUFFERS_FOR_OUTPUT The stateful encoder requires the presence of this control. Since a single buffer is sufficient for vicodec, we just set this control to 1. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 7a78d044072d..4bea4a57386d 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1801,13 +1801,16 @@ static int vicodec_open(struct file *file) file->private_data = &ctx->fh; ctx->dev = dev; hdl = &ctx->hdl; - v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_handler_init(hdl, 5); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 16, 1, 10); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP, 1, 31, 1, 20); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, 1, 31, 1, 20); + if (ctx->is_enc) + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); if (ctx->is_stateless) v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); if (hdl->error) { -- cgit v1.2.3-59-g8ed1b From fbbbb2cd0b39acba0720354d4beb98f39b69a29f Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sat, 30 Mar 2019 10:11:38 -0400 Subject: media: vicodec: set KEY/PFRAME flag when decoding Set V4L2_BUF_FLAG_P/KEYFRAME after decoding a frame. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 4bea4a57386d..4b0062ac880c 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -329,6 +329,10 @@ static int device_process(struct vicodec_ctx *ctx, copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); + if (ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME) + dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + dst_vb->flags |= V4L2_BUF_FLAG_PFRAME; } return ret; } @@ -407,7 +411,6 @@ static void device_run(void *priv) u32 state; struct media_request *src_req; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); src_req = src_buf->vb2_buf.req_obj.req; @@ -421,7 +424,7 @@ static void device_run(void *priv) else dst_buf->sequence = q_dst->sequence++; dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); ctx->last_dst_buf = dst_buf; -- cgit v1.2.3-59-g8ed1b From 8307f0ab0331ad8b8bb8af85df372e6bfda688e7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 7 May 2019 05:30:24 -0400 Subject: media: vicodec: use correct sizeimage value when draining After a resolution change is detected, q_data->sizeimage is updated to the new format, but buf_prepare is still draining buffers that need to use the old pre-resolution-change value. So store the sizeimage value in q_data->vb2_sizeimage in queue_setup and use that in buf_prepare. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 4b0062ac880c..ce7f7bf1b998 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -84,6 +84,7 @@ struct vicodec_q_data { unsigned int visible_width; unsigned int visible_height; unsigned int sizeimage; + unsigned int vb2_sizeimage; unsigned int sequence; const struct v4l2_fwht_pixfmt_info *info; }; @@ -1361,6 +1362,7 @@ static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, *nplanes = 1; sizes[0] = size; + q_data->vb2_sizeimage = size; return 0; } @@ -1391,11 +1393,11 @@ static int vicodec_buf_prepare(struct vb2_buffer *vb) } } - if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) { dprintk(ctx->dev, "%s data will not fit into plane (%lu < %lu)\n", __func__, vb2_plane_size(vb, 0), - (long)q_data->sizeimage); + (long)q_data->vb2_sizeimage); return -EINVAL; } -- cgit v1.2.3-59-g8ed1b From 3b6813d6f52d18674e5bbfcf7ff4bcec15569144 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 6 Jun 2019 06:00:30 -0400 Subject: media: vicodec: stateless codecs do not have EOS and SOURCE_CHANGE events Return an error when attempting to subscribe to those events for a stateless codec. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index ce7f7bf1b998..91cd0c1dbede 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -1293,6 +1293,8 @@ static int vicodec_subscribe_event(struct v4l2_fh *fh, return -EINVAL; /* fall through */ case V4L2_EVENT_EOS: + if (ctx->is_stateless) + return -EINVAL; return v4l2_event_subscribe(fh, sub, 0, NULL); default: return v4l2_ctrl_subscribe_event(fh, sub); -- cgit v1.2.3-59-g8ed1b From d17589afa97061440c0a161775672a8a7bfa9d12 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 25 Mar 2019 07:27:45 -0400 Subject: media: vicodec: improve handling of ENC_CMD_STOP/START Correctly handle stopping and restarting the encoder, keeping track of the stop and drain states. In addition it adds correct handling of corner cases, allowing v4l2-compliance to pass. Unfortunately, the code is getting to be quite complicated, so we need to work on better codec support in v4l2-mem2mem.c to simplify drivers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vicodec/vicodec-core.c | 150 +++++++++++++++++++++----- 1 file changed, 122 insertions(+), 28 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index 91cd0c1dbede..7e7c1e80f29f 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -117,12 +117,14 @@ struct vicodec_ctx { struct vicodec_dev *dev; bool is_enc; bool is_stateless; + bool is_draining; + bool next_is_last; + bool has_stopped; spinlock_t *lock; struct v4l2_ctrl_handler hdl; struct vb2_v4l2_buffer *last_src_buf; - struct vb2_v4l2_buffer *last_dst_buf; /* Source and destination queue data */ struct vicodec_q_data q_data[2]; @@ -139,6 +141,10 @@ struct vicodec_ctx { bool source_changed; }; +static const struct v4l2_event vicodec_eos_event = { + .type = V4L2_EVENT_EOS +}; + static inline struct vicodec_ctx *file2ctx(struct file *file) { return container_of(file->private_data, struct vicodec_ctx, fh); @@ -402,9 +408,6 @@ static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, /* device_run() - prepares and starts the device */ static void device_run(void *priv) { - static const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; struct vicodec_ctx *ctx = priv; struct vicodec_dev *dev = ctx->dev; struct vb2_v4l2_buffer *src_buf, *dst_buf; @@ -427,12 +430,12 @@ static void device_run(void *priv) dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); - ctx->last_dst_buf = dst_buf; - spin_lock(ctx->lock); if (!ctx->comp_has_next_frame && src_buf == ctx->last_src_buf) { dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_event_queue_fh(&ctx->fh, &eos_event); + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + ctx->is_draining = false; + ctx->has_stopped = true; } if (ctx->is_enc || ctx->is_stateless) { src_buf->sequence = q_src->sequence++; @@ -583,6 +586,8 @@ static int job_ready(void *priv) unsigned int max_to_copy; unsigned int comp_frame_size; + if (ctx->has_stopped) + return 0; if (ctx->source_changed) return 0; if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) @@ -602,6 +607,8 @@ restart: if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { state = get_next_header(ctx, &p, p_src + sz - p); if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + if (ctx->is_draining && src_buf == ctx->last_src_buf) + return 1; job_remove_src_buf(ctx, state); goto restart; } @@ -629,6 +636,8 @@ restart: p += copy; ctx->comp_size += copy; if (ctx->comp_size < max_to_copy) { + if (ctx->is_draining && src_buf == ctx->last_src_buf) + return 1; job_remove_src_buf(ctx, state); goto restart; } @@ -670,7 +679,6 @@ restart: v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); update_capture_data_from_header(ctx); - ctx->first_source_change_sent = true; v4l2_event_queue_fh(&ctx->fh, &rs_event); set_last_buffer(dst_buf, src_buf, ctx); ctx->source_changed = true; @@ -717,7 +725,8 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, const struct v4l2_fwht_pixfmt_info *info = get_q_data(ctx, f->type)->info; - if (!info || ctx->is_enc) + if (ctx->is_enc || + !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) info = v4l2_fwht_get_pixfmt(f->index); else info = v4l2_fwht_find_nth_fmt(info->width_div, @@ -768,9 +777,6 @@ static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) q_data = get_q_data(ctx, f->type); info = q_data->info; - if (!info) - info = v4l2_fwht_get_pixfmt(0); - switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: @@ -1210,19 +1216,39 @@ static int vidioc_s_selection(struct file *file, void *priv, return 0; } -static void vicodec_mark_last_buf(struct vicodec_ctx *ctx) +static int vicodec_mark_last_buf(struct vicodec_ctx *ctx) { - static const struct v4l2_event eos_event = { - .type = V4L2_EVENT_EOS - }; + struct vb2_v4l2_buffer *next_dst_buf; + int ret = 0; spin_lock(ctx->lock); + if (ctx->is_draining) { + ret = -EBUSY; + goto unlock; + } + if (ctx->has_stopped) + goto unlock; + ctx->last_src_buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); - if (!ctx->last_src_buf && ctx->last_dst_buf) { - ctx->last_dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_event_queue_fh(&ctx->fh, &eos_event); + ctx->is_draining = true; + if (ctx->last_src_buf) + goto unlock; + + next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!next_dst_buf) { + ctx->next_is_last = true; + goto unlock; } + + next_dst_buf->flags |= V4L2_BUF_FLAG_LAST; + vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE); + ctx->is_draining = false; + ctx->has_stopped = true; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + +unlock: spin_unlock(ctx->lock); + return ret; } static int vicodec_encoder_cmd(struct file *file, void *fh, @@ -1235,8 +1261,22 @@ static int vicodec_encoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; - vicodec_mark_last_buf(ctx); - return 0; + if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || + !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) + return 0; + + if (ec->cmd == V4L2_ENC_CMD_STOP) + return vicodec_mark_last_buf(ctx); + ret = 0; + spin_lock(ctx->lock); + if (ctx->is_draining) { + ret = -EBUSY; + } else if (ctx->has_stopped) { + ctx->has_stopped = false; + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + } + spin_unlock(ctx->lock); + return ret; } static int vicodec_decoder_cmd(struct file *file, void *fh, @@ -1249,8 +1289,22 @@ static int vicodec_decoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; - vicodec_mark_last_buf(ctx); - return 0; + if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || + !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) + return 0; + + if (dc->cmd == V4L2_DEC_CMD_STOP) + return vicodec_mark_last_buf(ctx); + ret = 0; + spin_lock(ctx->lock); + if (ctx->is_draining) { + ret = -EBUSY; + } else if (ctx->has_stopped) { + ctx->has_stopped = false; + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + } + spin_unlock(ctx->lock); + return ret; } static int vicodec_enum_framesizes(struct file *file, void *fh, @@ -1423,6 +1477,25 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, }; + if (vb2_is_streaming(vq_cap)) { + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && + ctx->next_is_last) { + unsigned int i; + + for (i = 0; i < vb->num_planes; i++) + vb->planes[i].bytesused = 0; + vbuf->flags = V4L2_BUF_FLAG_LAST; + vbuf->field = V4L2_FIELD_NONE; + vbuf->sequence = get_q_data(ctx, vb->vb2_queue->type)->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + ctx->is_draining = false; + ctx->has_stopped = true; + ctx->next_is_last = false; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + return; + } + } + /* buf_queue handles only the first source change event */ if (ctx->first_source_change_sent) { v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); @@ -1530,16 +1603,11 @@ static int vicodec_start_streaming(struct vb2_queue *q, unsigned int total_planes_size; u8 *new_comp_frame = NULL; - if (!info) - return -EINVAL; - chroma_div = info->width_div * info->height_div; q_data->sequence = 0; if (V4L2_TYPE_IS_OUTPUT(q->type)) ctx->last_src_buf = NULL; - else - ctx->last_dst_buf = NULL; state->gop_cnt = 0; @@ -1615,6 +1683,32 @@ static void vicodec_stop_streaming(struct vb2_queue *q) vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + if (ctx->is_draining) { + struct vb2_v4l2_buffer *next_dst_buf; + + spin_lock(ctx->lock); + ctx->last_src_buf = NULL; + next_dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!next_dst_buf) { + ctx->next_is_last = true; + } else { + next_dst_buf->flags |= V4L2_BUF_FLAG_LAST; + vb2_buffer_done(&next_dst_buf->vb2_buf, VB2_BUF_STATE_DONE); + ctx->is_draining = false; + ctx->has_stopped = true; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + } + spin_unlock(ctx->lock); + } + } else { + ctx->is_draining = false; + ctx->has_stopped = false; + ctx->next_is_last = false; + } + if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->first_source_change_sent = false; + if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { if (!ctx->is_stateless) -- cgit v1.2.3-59-g8ed1b From 675e2f20b1139633876cdc8f621065fcbd582be9 Mon Sep 17 00:00:00 2001 From: Torleiv Sundre Date: Sun, 28 Apr 2019 01:21:13 -0400 Subject: media: uvcvideo: Include streaming interface number in debugfs dir name uvcvideo creates a debugfs directory based on the device bus number and device number. If a device contains more than one uvc function, the creation of the second and following debugfs directories will fail and print an info message like this: "uvcvideo: Unable to create debugfs 3-2 directory." This patch includes the uvc streaming interface number in the debugfs directory name, to make sure it is unique. The directory name format is changed from "-" to "--" Signed-off-by: Torleiv Sundre Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c index 8ba54139a087..d2b109959d82 100644 --- a/drivers/media/usb/uvc/uvc_debugfs.c +++ b/drivers/media/usb/uvc/uvc_debugfs.c @@ -74,12 +74,13 @@ void uvc_debugfs_init_stream(struct uvc_streaming *stream) { struct usb_device *udev = stream->dev->udev; struct dentry *dent; - char dir_name[32]; + char dir_name[33]; if (uvc_debugfs_root_dir == NULL) return; - sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum); + snprintf(dir_name, sizeof(dir_name), "%u-%u-%u", udev->bus->busnum, + udev->devnum, stream->intfnum); dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir); if (IS_ERR_OR_NULL(dent)) { -- cgit v1.2.3-59-g8ed1b From 11a087f484bf15ff65f0a9f277aa5a61fd07ed2a Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Tue, 30 Apr 2019 08:28:14 -0400 Subject: media: uvcvideo: Fix access to uninitialized fields on probe error We need to check whether this work we are canceling actually is initialized. Signed-off-by: Oliver Neukum Reported-by: syzbot+2e1ef9188251d9cc7944@syzkaller.appspotmail.com Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_ctrl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index 26163a5bde7d..e399b9fad757 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -2345,7 +2345,9 @@ void uvc_ctrl_cleanup_device(struct uvc_device *dev) struct uvc_entity *entity; unsigned int i; - cancel_work_sync(&dev->async_ctrl.work); + /* Can be uninitialized if we are aborting on probe error. */ + if (dev->async_ctrl.work.func) + cancel_work_sync(&dev->async_ctrl.work); /* Free controls and control mappings for all entities. */ list_for_each_entry(entity, &dev->entities, list) { -- cgit v1.2.3-59-g8ed1b From a8a3e813963c291de39206191a845cbe4b8fc4c7 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Jun 2019 06:55:48 -0400 Subject: media: i2c: mt9p031: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9p031.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 715be3632b01..5d824dd33edd 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -1034,7 +1034,7 @@ static int mt9p031_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client); - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct mt9p031 *mt9p031; unsigned int i; int ret; -- cgit v1.2.3-59-g8ed1b From 4e8c120de9268fc26f583268b9d22e7d37c4595f Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Wed, 15 May 2019 11:39:12 -0400 Subject: media: fdp1: Support M3N and E3 platforms New Gen3 R-Car platforms incorporate the FDP1 with an updated version register. No code change is required to support these targets, but they will currently report an error stating that the device can not be identified. Update the driver to match against the new device types. Signed-off-by: Kieran Bingham Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_fdp1.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 6f9a4c69f620..43aae9b6bb20 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -257,6 +257,8 @@ MODULE_PARM_DESC(debug, "activate debug info"); #define FD1_IP_H3_ES1 0x02010101 #define FD1_IP_M3W 0x02010202 #define FD1_IP_H3 0x02010203 +#define FD1_IP_M3N 0x02010204 +#define FD1_IP_E3 0x02010205 /* LUTs */ #define FD1_LUT_DIF_ADJ 0x1000 @@ -2365,6 +2367,12 @@ static int fdp1_probe(struct platform_device *pdev) case FD1_IP_H3: dprintk(fdp1, "FDP1 Version R-Car H3\n"); break; + case FD1_IP_M3N: + dprintk(fdp1, "FDP1 Version R-Car M3N\n"); + break; + case FD1_IP_E3: + dprintk(fdp1, "FDP1 Version R-Car E3\n"); + break; default: dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n", hw_version); -- cgit v1.2.3-59-g8ed1b From 4419617e0d0cc6f6526439e16f3a880e7d292eaa Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 12 Jun 2019 04:15:43 -0400 Subject: media: drivers: media: i2c: don't enable if CONFIG_DRM_I2C_ADV7511=n CONFIG_DRM_I2C_ADV7511 and CONFIG_VIDEO_ADV7511 bind to the same platform device, so whichever driver gets loaded first will be used on the device. So they shouldn't be enabled at the same time. Rework so that VIDEO_ADV7511 and VIDEO_COBALT depends on DRM_I2C_ADV7511=n or COMPILE_TEST. Suggested-by: Hans Verkuil Signed-off-by: Anders Roxell Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 1 + drivers/media/pci/cobalt/Kconfig | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 95d42730745c..79ce9ec6fc1b 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -511,6 +511,7 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on DRM_I2C_ADV7511=n || COMPILE_TEST select HDMI help Support for the Analog Devices ADV7511 video encoder. diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index 6c6c60abe9b1..e0e7df460a92 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -3,7 +3,7 @@ config VIDEO_COBALT tristate "Cisco Cobalt support" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on PCI_MSI && MTD_COMPLEX_MAPPINGS - depends on GPIOLIB || COMPILE_TEST + depends on (GPIOLIB && DRM_I2C_ADV7511=n) || COMPILE_TEST depends on SND depends on MTD select I2C_ALGOBIT -- cgit v1.2.3-59-g8ed1b From 1296987d2baf7f56748359b8dd42c425b9e7ee3a Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 12 Jun 2019 04:15:50 -0400 Subject: media: drivers: media: coda: fix warning same module names When building with CONFIG_VIDEO_CODA and CONFIG_CODA_FS enabled as loadable modules, we see the following warning: fs/coda/coda.ko drivers/media/platform/coda/coda.ko Rework so media/platform/coda is named coda-vpu. Leaving CODA_FS as is since that's a well known module. Signed-off-by: Anders Roxell Reviewed-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 54e9a73a92ab..bbb16425a875 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o +coda-vpu-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-mpeg2.o coda-mpeg4.o coda-jpeg.o -obj-$(CONFIG_VIDEO_CODA) += coda.o +obj-$(CONFIG_VIDEO_CODA) += coda-vpu.o obj-$(CONFIG_VIDEO_IMX_VDOA) += imx-vdoa.o -- cgit v1.2.3-59-g8ed1b From 64f883cd98c6d43013fb0cea788b63e50ebc068c Mon Sep 17 00:00:00 2001 From: Young Xiao <92siuyang@gmail.com> Date: Tue, 4 Jun 2019 08:26:33 -0400 Subject: media: davinci: vpif_capture: fix memory leak in vpif_probe() If vpif_probe() fails on v4l2_device_register() and vpif_probe_complete(), then memory allocated at initialize_vpif() for global vpif_obj.dev[i] become unreleased. The patch adds deallocation of vpif_obj.dev[i] on the error path. Signed-off-by: Young Xiao <92siuyang@gmail.com> Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 61809d2050fa..f0f7ef638c56 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1376,6 +1376,14 @@ vpif_init_free_channel_objects: return err; } +static inline void free_vpif_objs(void) +{ + int i; + + for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) + kfree(vpif_obj.dev[i]); +} + static int vpif_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1645,7 +1653,7 @@ static __init int vpif_probe(struct platform_device *pdev) err = v4l2_device_register(vpif_dev, &vpif_obj.v4l2_dev); if (err) { v4l2_err(vpif_dev->driver, "Error registering v4l2 device\n"); - goto cleanup; + goto vpif_free; } while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) { @@ -1692,7 +1700,9 @@ static __init int vpif_probe(struct platform_device *pdev) "registered sub device %s\n", subdevdata->name); } - vpif_probe_complete(); + err = vpif_probe_complete(); + if (err) + goto probe_subdev_out; } else { vpif_obj.notifier.ops = &vpif_async_ops; err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev, @@ -1711,6 +1721,8 @@ probe_subdev_out: kfree(vpif_obj.sd); vpif_unregister: v4l2_device_unregister(&vpif_obj.v4l2_dev); +vpif_free: + free_vpif_objs(); cleanup: v4l2_async_notifier_cleanup(&vpif_obj.notifier); -- cgit v1.2.3-59-g8ed1b From be22203aec440c1761ce8542c2636ac6c8951e3a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 12 Jun 2019 09:57:57 -0400 Subject: media: s5p-mfc: fix reading min scratch buffer size on MFC v6/v7 MFC v6 and v7 has no register to read min scratch buffer size, so it has to be read conditionally only if hardware supports it. This fixes following NULL pointer exception on SoCs with MFC v6/v7: 8<--- cut here --- Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = f25837f9 [00000000] *pgd=bd93d835 Internal error: Oops: 17 [#1] PREEMPT SMP ARM Modules linked in: btmrvl_sdio btmrvl bluetooth mwifiex_sdio mwifiex ecdh_generic ecc Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) PC is at s5p_mfc_get_min_scratch_buf_size+0x30/0x3c LR is at s5p_mfc_get_min_scratch_buf_size+0x28/0x3c ... [] (s5p_mfc_get_min_scratch_buf_size) from [] (s5p_mfc_irq+0x814/0xa5c) [] (s5p_mfc_irq) from [] (__handle_irq_event_percpu+0x64/0x3f8) [] (__handle_irq_event_percpu) from [] (handle_irq_event_percpu+0x2c/0x7c) [] (handle_irq_event_percpu) from [] (handle_irq_event+0x38/0x5c) [] (handle_irq_event) from [] (handle_fasteoi_irq+0xc4/0x180) [] (handle_fasteoi_irq) from [] (generic_handle_irq+0x24/0x34) [] (generic_handle_irq) from [] (__handle_domain_irq+0x7c/0xec) [] (__handle_domain_irq) from [] (gic_handle_irq+0x58/0x9c) [] (gic_handle_irq) from [] (__irq_svc+0x70/0xb0) Exception stack(0xe73ddc60 to 0xe73ddca8) ... [] (__irq_svc) from [] (console_unlock+0x5a8/0x6a8) [] (console_unlock) from [] (vprintk_emit+0x118/0x2d8) [] (vprintk_emit) from [] (vprintk_default+0x20/0x28) [] (vprintk_default) from [] (printk+0x30/0x54) [] (printk) from [] (s5p_mfc_init_decode_v6+0x1d4/0x284) [] (s5p_mfc_init_decode_v6) from [] (vb2_start_streaming+0x24/0x150) [] (vb2_start_streaming) from [] (vb2_core_streamon+0x11c/0x15c) [] (vb2_core_streamon) from [] (vidioc_streamon+0x64/0xa0) [] (vidioc_streamon) from [] (__video_do_ioctl+0x28c/0x45c) [] (__video_do_ioctl) from [] (video_usercopy+0x260/0x8a4) [] (video_usercopy) from [] (do_vfs_ioctl+0xb0/0x9fc) [] (do_vfs_ioctl) from [] (ksys_ioctl+0x34/0x58) [] (ksys_ioctl) from [] (ret_fast_syscall+0x0/0x28) Exception stack(0xe73ddfa8 to 0xe73ddff0) ... ---[ end trace 376cf5ba6e0bee93 ]--- Signed-off-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index c5dc1880a4c6..b776f83e395e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -523,7 +523,8 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, dev); ctx->mv_count = s5p_mfc_hw_call(dev->mfc_ops, get_mv_count, dev); - ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, + if (FW_HAS_E_MIN_SCRATCH_BUF(dev)) + ctx->scratch_buf_size = s5p_mfc_hw_call(dev->mfc_ops, get_min_scratch_buf_size, dev); if (ctx->img_width == 0 || ctx->img_height == 0) ctx->state = MFCINST_ERROR; -- cgit v1.2.3-59-g8ed1b From 3dad39e67cca68b321073cecabf2d7d1103d97d5 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 12 Jun 2019 08:05:10 -0400 Subject: media: imx214: Fix typo in module description of imx214 This patch fixes a spelling typo found in imx214.c Signed-off-by: Masanari Iida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/imx214.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 83e9961b0505..159a3a604f0e 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -1111,6 +1111,6 @@ static struct i2c_driver imx214_i2c_driver = { module_i2c_driver(imx214_i2c_driver); -MODULE_DESCRIPTION("Sony IMX214 Camera drier"); +MODULE_DESCRIPTION("Sony IMX214 Camera driver"); MODULE_AUTHOR("Ricardo Ribalda "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From 513dbd35b5d93c45fa7291147f21fc0227a9f999 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 5 Jun 2019 13:24:35 -0400 Subject: media: add SPDX headers to some files Add SPDX headers and fix MODULE_LICENSE() when needed on some files I co-authored. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda7432.c | 3 ++- drivers/media/pci/bt8xx/bttv-audio-hook.c | 2 +- drivers/media/pci/bt8xx/bttv-audio-hook.h | 2 ++ drivers/media/pci/cx88/cx88-alsa.c | 2 +- drivers/media/pci/cx88/cx88-blackbird.c | 2 +- drivers/media/pci/cx88/cx88-core.c | 2 +- drivers/media/pci/cx88/cx88-i2c.c | 1 - drivers/media/pci/cx88/cx88-video.c | 2 +- drivers/media/v4l2-core/videobuf-core.c | 5 +---- drivers/media/v4l2-core/videobuf-dma-contig.c | 5 +---- drivers/media/v4l2-core/videobuf-dma-sg.c | 5 +---- drivers/media/v4l2-core/videobuf-vmalloc.c | 7 ++----- 12 files changed, 14 insertions(+), 24 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index 06a78c2cdaab..cbdc9be0a597 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * For the STS-Thompson TDA7432 audio processor chip * @@ -9,7 +10,7 @@ * * Copyright (c) 2000 Eric Sandeen * Copyright (c) 2006 Mauro Carvalho Chehab - * This code is placed under the terms of the GNU General Public License + * * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu) * Which was based on tda8425.c by Greg Alexander (c) 1998 * diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.c b/drivers/media/pci/bt8xx/bttv-audio-hook.c index 8febe7358a8f..da1914a20b81 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.c +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.c @@ -1,8 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Handlers for board audio hooks, split from bttv-cards * * Copyright (c) 2006 Mauro Carvalho Chehab - * This code is placed under the terms of the GNU General Public License */ #include "bttv-audio-hook.h" diff --git a/drivers/media/pci/bt8xx/bttv-audio-hook.h b/drivers/media/pci/bt8xx/bttv-audio-hook.h index c61b9ac4f4e3..d6a1a5a60a56 100644 --- a/drivers/media/pci/bt8xx/bttv-audio-hook.h +++ b/drivers/media/pci/bt8xx/bttv-audio-hook.h @@ -1,4 +1,6 @@ /* + * SPDX-License-Identifier: GPL-2.0 + * * Handlers for board audio hooks, split from bttv-cards * * Copyright (c) 2006 Mauro Carvalho Chehab diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index b4ad5d12054e..e1e71ae293ed 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -95,7 +95,7 @@ MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s)."); MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); MODULE_AUTHOR("Ricardo Cerqueira"); MODULE_AUTHOR("Mauro Carvalho Chehab "); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(CX88_VERSION); MODULE_SUPPORTED_DEVICE("{{Conexant,23881},{{Conexant,23882},{{Conexant,23883}"); diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 0a10c9d192f3..64dd8b6cf808 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -28,7 +28,7 @@ MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(CX88_VERSION); static unsigned int debug; diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 8597cb8274ab..dcadf78657d6 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -31,7 +31,7 @@ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c index 50a9ae3fa596..7fc64aef1ef7 100644 --- a/drivers/media/pci/cx88/cx88-i2c.c +++ b/drivers/media/pci/cx88/cx88-i2c.c @@ -8,7 +8,6 @@ * & Marcus Metzler (mocm@thp.uni-koeln.de) * (c) 2002 Yurij Sysoev * (c) 1999-2003 Gerd Knorr - * * (c) 2005 Mauro Carvalho Chehab * - Multituner support and i2c address binding */ diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 3b49ebb21b13..5256ad7ead38 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -33,7 +33,7 @@ MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(CX88_VERSION); /* ------------------------------------------------------------------ */ diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index bf7dfb2a34af..d24b4c1d4158 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * generic helper functions for handling video4linux capture buffers * @@ -7,10 +8,6 @@ * (c) 2001,02 Gerd Knorr * (c) 2006 Mauro Carvalho Chehab, * (c) 2006 Ted Walther and John Sokol - * - * 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 */ #include diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c index 65e2655d22b7..b0ad5aba9046 100644 --- a/drivers/media/v4l2-core/videobuf-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf-dma-contig.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * helper functions for physically contiguous capture buffers * @@ -8,10 +9,6 @@ * * Based on videobuf-vmalloc.c, * (c) 2007 Mauro Carvalho Chehab, - * - * 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 */ #include diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 870a2a526e0b..a1dc49a0aaf9 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * helper functions for SG DMA video4linux capture buffers * @@ -12,10 +13,6 @@ * (c) 2001,02 Gerd Knorr * (c) 2006 Mauro Carvalho Chehab, * (c) 2006 Ted Walther and John Sokol - * - * 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 */ #include diff --git a/drivers/media/v4l2-core/videobuf-vmalloc.c b/drivers/media/v4l2-core/videobuf-vmalloc.c index cb50f1957828..136d5b99a1bd 100644 --- a/drivers/media/v4l2-core/videobuf-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf-vmalloc.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * helper functions for vmalloc video4linux capture buffers * @@ -6,11 +7,7 @@ * into PAGE_SIZE chunks). They also assume the driver does not need * to touch the video data. * - * (c) 2007 Mauro Carvalho Chehab, - * - * 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 + * (c) 2007 Mauro Carvalho Chehab */ #include -- cgit v1.2.3-59-g8ed1b From d5cb82b01a5ae6cf9a36a24be02ef28b84df28cc Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 20 Dec 2018 12:09:31 -0500 Subject: media: si2157: add detection of si2177 tuner Works in ATSC and QAM as is, DVB is completely untested. Firmware required. Signed-off-by: Brad Love Reviewed-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/si2157.c | 6 ++++++ drivers/media/tuners/si2157_priv.h | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c index 7be893def190..e87040d6eca7 100644 --- a/drivers/media/tuners/si2157.c +++ b/drivers/media/tuners/si2157.c @@ -129,6 +129,7 @@ static int si2157_init(struct dvb_frontend *fe) chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 | cmd.args[4] << 0; + #define SI2177_A30 ('A' << 24 | 77 << 16 | '3' << 8 | '0' << 0) #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0) #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0) #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0) @@ -144,6 +145,9 @@ static int si2157_init(struct dvb_frontend *fe) case SI2141_A10: fw_name = SI2141_A10_FIRMWARE; break; + case SI2177_A30: + fw_name = SI2157_A30_FIRMWARE; + break; case SI2157_A30: case SI2147_A30: case SI2146_A10: @@ -520,6 +524,7 @@ static const struct i2c_device_id si2157_id_table[] = { {"si2157", SI2157_CHIPTYPE_SI2157}, {"si2146", SI2157_CHIPTYPE_SI2146}, {"si2141", SI2157_CHIPTYPE_SI2141}, + {"si2177", SI2157_CHIPTYPE_SI2177}, {} }; MODULE_DEVICE_TABLE(i2c, si2157_id_table); @@ -541,3 +546,4 @@ MODULE_AUTHOR("Antti Palosaari "); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(SI2158_A20_FIRMWARE); MODULE_FIRMWARE(SI2141_A10_FIRMWARE); +MODULE_FIRMWARE(SI2157_A30_FIRMWARE); diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h index 7d16934c7708..2bda903358da 100644 --- a/drivers/media/tuners/si2157_priv.h +++ b/drivers/media/tuners/si2157_priv.h @@ -41,6 +41,7 @@ struct si2157_dev { #define SI2157_CHIPTYPE_SI2157 0 #define SI2157_CHIPTYPE_SI2146 1 #define SI2157_CHIPTYPE_SI2141 2 +#define SI2157_CHIPTYPE_SI2177 3 /* firmware command struct */ #define SI2157_ARGLEN 30 @@ -52,5 +53,5 @@ struct si2157_cmd { #define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw" #define SI2141_A10_FIRMWARE "dvb-tuner-si2141-a10-01.fw" - +#define SI2157_A30_FIRMWARE "dvb-tuner-si2157-a30-01.fw" #endif -- cgit v1.2.3-59-g8ed1b From cac821d2ea72fbefb16e8af1e192ec70aae29afe Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 30 May 2019 16:32:25 -0400 Subject: media: pvrusb2: Add multiple dvb frontend support All changes are equivalent and backwards compatible. All current devices have been changed to use fe[0] Code has been added to dvb init to support cleanup after failure. Multiple frontends are required by Hauppauge HVR-1975, which is in a later commit. Signed-off-by: Brad Love Reviewed-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-devattr.c | 46 ++++++++--------- drivers/media/usb/pvrusb2/pvrusb2-dvb.c | 77 ++++++++++++++++++++++------- drivers/media/usb/pvrusb2/pvrusb2-dvb.h | 2 +- 3 files changed, 82 insertions(+), 43 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c index 06de1c83f444..a4a27e071c6d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c @@ -188,10 +188,10 @@ static struct lgdt330x_config pvr2_lgdt3303_config = { static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, - 0x0e, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config, + 0x0e, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -199,7 +199,7 @@ static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap) static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF); @@ -248,10 +248,10 @@ static struct lgdt330x_config pvr2_lgdt3302_config = { static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, - 0x0e, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config, + 0x0e, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -259,7 +259,7 @@ static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap) static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(simple_tuner_attach, adap->fe, + dvb_attach(simple_tuner_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x61, TUNER_PHILIPS_FCV1236D); @@ -335,9 +335,9 @@ static struct tda18271_config hauppauge_tda18271_dvb_config = { static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(tda10048_attach, &hauppauge_tda10048_config, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -345,10 +345,10 @@ static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap) static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(tda829x_attach, adap->fe, + dvb_attach(tda829x_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x42, &tda829x_no_probe); - dvb_attach(tda18271_attach, adap->fe, 0x60, + dvb_attach(tda18271_attach, adap->fe[0], 0x60, &adap->channel.hdw->i2c_adap, &hauppauge_tda18271_dvb_config); @@ -433,9 +433,9 @@ static struct tda18271_config hauppauge_tda18271_config = { static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -443,9 +443,9 @@ static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap) static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) { - adap->fe = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, - &adap->channel.hdw->i2c_adap); - if (adap->fe) + adap->fe[0] = dvb_attach(s5h1411_attach, &pvr2_s5h1411_config, + &adap->channel.hdw->i2c_adap); + if (adap->fe[0]) return 0; return -EIO; @@ -453,10 +453,10 @@ static int pvr2_s5h1411_attach(struct pvr2_dvb_adapter *adap) static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap) { - dvb_attach(tda829x_attach, adap->fe, + dvb_attach(tda829x_attach, adap->fe[0], &adap->channel.hdw->i2c_adap, 0x42, &tda829x_no_probe); - dvb_attach(tda18271_attach, adap->fe, 0x60, + dvb_attach(tda18271_attach, adap->fe[0], 0x60, &adap->channel.hdw->i2c_adap, &hauppauge_tda18271_config); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c index 4b32b2141169..f302f1e7670a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c @@ -343,26 +343,19 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) goto done; } - if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { - - if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) { + if (dvb_props->frontend_attach(adap) == 0 && adap->fe[0]) { + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[0])) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "frontend registration failed!"); - dvb_frontend_detach(adap->fe); - adap->fe = NULL; ret = -ENODEV; - goto done; + goto fail_frontend0; } + if (adap->fe[0]->ops.analog_ops.standby) + adap->fe[0]->ops.analog_ops.standby(adap->fe[0]); - if (dvb_props->tuner_attach) - dvb_props->tuner_attach(adap); - - if (adap->fe->ops.analog_ops.standby) - adap->fe->ops.analog_ops.standby(adap->fe); - - /* Ensure all frontends negotiate bus access */ - adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; - + pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()", + adap->fe[0]->id); + adap->fe[0]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; } else { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "no frontend was attached!"); @@ -370,16 +363,62 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) return ret; } - done: + if (dvb_props->tuner_attach && dvb_props->tuner_attach(adap)) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, "tuner attach failed"); + ret = -ENODEV; + goto fail_tuner; + } + + if (adap->fe[1]) { + adap->fe[1]->id = 1; + adap->fe[1]->tuner_priv = adap->fe[0]->tuner_priv; + memcpy(&adap->fe[1]->ops.tuner_ops, + &adap->fe[0]->ops.tuner_ops, + sizeof(struct dvb_tuner_ops)); + + if (dvb_register_frontend(&adap->dvb_adap, adap->fe[1])) { + pvr2_trace(PVR2_TRACE_ERROR_LEGS, + "frontend registration failed!"); + ret = -ENODEV; + goto fail_frontend1; + } + /* MFE lock */ + adap->dvb_adap.mfe_shared = 1; + + if (adap->fe[1]->ops.analog_ops.standby) + adap->fe[1]->ops.analog_ops.standby(adap->fe[1]); + + pvr2_trace(PVR2_TRACE_INFO, "transferring fe[%d] ts_bus_ctrl() to pvr2_dvb_bus_ctrl()", + adap->fe[1]->id); + adap->fe[1]->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl; + } +done: pvr2_channel_limit_inputs(&adap->channel, 0); return ret; + +fail_frontend1: + dvb_frontend_detach(adap->fe[1]); + adap->fe[1] = NULL; +fail_tuner: + dvb_unregister_frontend(adap->fe[0]); +fail_frontend0: + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; + + return ret; } static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) { - if (adap->fe != NULL) { - dvb_unregister_frontend(adap->fe); - dvb_frontend_detach(adap->fe); + if (adap->fe[1]) { + dvb_unregister_frontend(adap->fe[1]); + dvb_frontend_detach(adap->fe[1]); + adap->fe[1] = NULL; + } + if (adap->fe[0]) { + dvb_unregister_frontend(adap->fe[0]); + dvb_frontend_detach(adap->fe[0]); + adap->fe[0] = NULL; } return 0; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h index e7f71fb94a6e..91bff573288d 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h @@ -18,7 +18,7 @@ struct pvr2_dvb_adapter { struct dmxdev dmxdev; struct dvb_demux demux; struct dvb_net dvb_net; - struct dvb_frontend *fe; + struct dvb_frontend *fe[2]; int feedcount; int max_feed_count; -- cgit v1.2.3-59-g8ed1b From 6f6be371608e88922970a3968f963720ba3871f0 Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 20 Dec 2018 15:14:25 -0500 Subject: media: pvrusb2: Add i2c client demod/tuner support i2c client device is the "new" method to attach to dvb modules, include support for this functionality. Cleanup code has been added to init in case of failure, as well as to frontend exit. Required by Hauppauge HVR-1975 Signed-off-by: Brad Love Reviewed-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-dvb.c | 11 +++++++++++ drivers/media/usb/pvrusb2/pvrusb2-dvb.h | 3 +++ 2 files changed, 14 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c index f302f1e7670a..7f5df5c47232 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.c @@ -404,6 +404,9 @@ fail_tuner: fail_frontend0: dvb_frontend_detach(adap->fe[0]); adap->fe[0] = NULL; + dvb_module_release(adap->i2c_client_tuner); + dvb_module_release(adap->i2c_client_demod[1]); + dvb_module_release(adap->i2c_client_demod[0]); return ret; } @@ -420,6 +423,14 @@ static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) dvb_frontend_detach(adap->fe[0]); adap->fe[0] = NULL; } + + dvb_module_release(adap->i2c_client_tuner); + adap->i2c_client_tuner = NULL; + dvb_module_release(adap->i2c_client_demod[1]); + adap->i2c_client_demod[1] = NULL; + dvb_module_release(adap->i2c_client_demod[0]); + adap->i2c_client_demod[0] = NULL; + return 0; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h index 91bff573288d..c0b27f5211bf 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-dvb.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-dvb.h @@ -20,6 +20,9 @@ struct pvr2_dvb_adapter { struct dvb_net dvb_net; struct dvb_frontend *fe[2]; + struct i2c_client *i2c_client_demod[2]; + struct i2c_client *i2c_client_tuner; + int feedcount; int max_feed_count; -- cgit v1.2.3-59-g8ed1b From dd60bf4360312559654a5efdac5108fee6fc9fdf Mon Sep 17 00:00:00 2001 From: Brad Love Date: Wed, 5 Jun 2019 16:22:11 -0400 Subject: media: pvrusb2: Add Hauppauge HVR1955/1975 devices Includes support to identify and use two Hauppauge device. - LGDT3306a ATSC/QAM demod - si2177 tuner - cx25840 decoder for analog tv/composite/s-video/audio HVR-1975 dual-frontend: - LGDT3306a ATSC/QAM demod - si2168 DVB-C/T/T2 demod - si2177 tuner - cx25840 decoder for analog tv/composite/s-video/audio Signed-off-by: Brad Love Reviewed-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/Kconfig | 2 + drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c | 25 ++++ drivers/media/usb/pvrusb2/pvrusb2-devattr.c | 166 ++++++++++++++++++++++++ drivers/media/usb/pvrusb2/pvrusb2-devattr.h | 1 + drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h | 4 + drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 36 ++++- 6 files changed, 233 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 64f9df067269..e6a4f730591b 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -41,6 +41,8 @@ config VIDEO_PVRUSB2_DVB select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT + select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c index d5bec0f69bec..36016ab3aef0 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -111,10 +111,35 @@ static const struct routing_scheme routing_defav400 = { .cnt = ARRAY_SIZE(routing_schemeav400), }; +static const struct routing_scheme_item routing_scheme160xxx[] = { + [PVR2_CVAL_INPUT_TV] = { + .vid = CX25840_COMPOSITE7, + .aud = CX25840_AUDIO8, + }, + [PVR2_CVAL_INPUT_RADIO] = { + .vid = CX25840_COMPOSITE4, + .aud = CX25840_AUDIO6, + }, + [PVR2_CVAL_INPUT_COMPOSITE] = { + .vid = CX25840_COMPOSITE3, + .aud = CX25840_AUDIO_SERIAL, + }, + [PVR2_CVAL_INPUT_SVIDEO] = { + .vid = CX25840_SVIDEO1, + .aud = CX25840_AUDIO_SERIAL, + }, +}; + +static const struct routing_scheme routing_def160xxx = { + .def = routing_scheme160xxx, + .cnt = ARRAY_SIZE(routing_scheme160xxx), +}; + static const struct routing_scheme *routing_schemes[] = { [PVR2_ROUTING_SCHEME_HAUPPAUGE] = &routing_def0, [PVR2_ROUTING_SCHEME_GOTVIEW] = &routing_defgv, [PVR2_ROUTING_SCHEME_AV400] = &routing_defav400, + [PVR2_ROUTING_SCHEME_HAUP160XXX] = &routing_def160xxx, }; void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c index a4a27e071c6d..ef57a6329863 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c @@ -37,6 +37,9 @@ pvr2_device_desc structures. #include "tda18271.h" #include "tda8290.h" #include "tuner-simple.h" +#include "si2157.h" +#include "lgdt3306a.h" +#include "si2168.h" #endif @@ -525,7 +528,166 @@ static const struct pvr2_device_desc pvr2_device_751xx = { #endif }; +/*------------------------------------------------------------------------*/ +/* Hauppauge PVR-USB2 Model 160000 / 160111 -- HVR-1955 / HVR-1975 */ + +#ifdef CONFIG_VIDEO_PVRUSB2_DVB +static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap); +static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap); +static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap); +static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap); + +static const struct pvr2_dvb_props pvr2_160000_dvb_props = { + .frontend_attach = pvr2_dual_fe_attach, + .tuner_attach = pvr2_si2157_attach, +}; + +static const struct pvr2_dvb_props pvr2_160111_dvb_props = { + .frontend_attach = pvr2_lgdt3306a_attach, + .tuner_attach = pvr2_si2157_attach, +}; + +static int pvr2_si2157_attach(struct pvr2_dvb_adapter *adap) +{ + struct si2157_config si2157_config = {}; + + si2157_config.inversion = 1; + si2157_config.fe = adap->fe[0]; + + adap->i2c_client_tuner = dvb_module_probe("si2157", "si2177", + &adap->channel.hdw->i2c_adap, + 0x60, &si2157_config); + + if (!adap->i2c_client_tuner) + return -ENODEV; + + return 0; +} + +static int pvr2_si2168_attach(struct pvr2_dvb_adapter *adap) +{ + struct si2168_config si2168_config = {}; + struct i2c_adapter *adapter; + + pr_debug("%s()\n", __func__); + + si2168_config.fe = &adap->fe[1]; + si2168_config.i2c_adapter = &adapter; + si2168_config.ts_mode = SI2168_TS_PARALLEL; /*2, 1-serial, 2-parallel.*/ + si2168_config.ts_clock_gapped = 1; /*0-disabled, 1-enabled.*/ + si2168_config.ts_clock_inv = 0; /*0-not-invert, 1-invert*/ + si2168_config.spectral_inversion = 1; /*0-not-invert, 1-invert*/ + + adap->i2c_client_demod[1] = dvb_module_probe("si2168", NULL, + &adap->channel.hdw->i2c_adap, + 0x64, &si2168_config); + + if (!adap->i2c_client_demod[1]) + return -ENODEV; + + return 0; +} +static int pvr2_lgdt3306a_attach(struct pvr2_dvb_adapter *adap) +{ + struct lgdt3306a_config lgdt3306a_config; + struct i2c_adapter *adapter; + + pr_debug("%s()\n", __func__); + + lgdt3306a_config.fe = &adap->fe[0]; + lgdt3306a_config.i2c_adapter = &adapter; + lgdt3306a_config.deny_i2c_rptr = 1; + lgdt3306a_config.spectral_inversion = 1; + lgdt3306a_config.qam_if_khz = 4000; + lgdt3306a_config.vsb_if_khz = 3250; + lgdt3306a_config.mpeg_mode = LGDT3306A_MPEG_PARALLEL; + lgdt3306a_config.tpclk_edge = LGDT3306A_TPCLK_FALLING_EDGE; + lgdt3306a_config.tpvalid_polarity = LGDT3306A_TP_VALID_LOW; + lgdt3306a_config.xtalMHz = 25, /* demod clock MHz; 24/25 supported */ + + adap->i2c_client_demod[0] = dvb_module_probe("lgdt3306a", NULL, + &adap->channel.hdw->i2c_adap, + 0x59, &lgdt3306a_config); + + if (!adap->i2c_client_demod[0]) + return -ENODEV; + + return 0; +} + +static int pvr2_dual_fe_attach(struct pvr2_dvb_adapter *adap) +{ + pr_debug("%s()\n", __func__); + + if (pvr2_lgdt3306a_attach(adap) != 0) + return -ENODEV; + + if (pvr2_si2168_attach(adap) != 0) { + dvb_module_release(adap->i2c_client_demod[0]); + return -ENODEV; + } + + return 0; +} +#endif + +#define PVR2_FIRMWARE_160xxx "v4l-pvrusb2-160xxx-01.fw" +static const char *pvr2_fw1_names_160xxx[] = { + PVR2_FIRMWARE_160xxx, +}; + +static const struct pvr2_device_client_desc pvr2_cli_160xxx[] = { + { .module_id = PVR2_CLIENT_ID_CX25840 }, +}; + +static const struct pvr2_device_desc pvr2_device_160000 = { + .description = "WinTV HVR-1975 Model 160000", + .shortname = "160000", + .client_table.lst = pvr2_cli_160xxx, + .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx), + .fx2_firmware.lst = pvr2_fw1_names_160xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx), + .default_tuner_type = TUNER_ABSENT, + .flag_has_cx25840 = 1, + .flag_has_hauppauge_rom = 1, + .flag_has_analogtuner = 1, + .flag_has_composite = 1, + .flag_has_svideo = 1, + .flag_fx2_16kb = 1, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, + .default_std_mask = V4L2_STD_NTSC_M, + .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, +#ifdef CONFIG_VIDEO_PVRUSB2_DVB + .dvb_props = &pvr2_160000_dvb_props, +#endif +}; + +static const struct pvr2_device_desc pvr2_device_160111 = { + .description = "WinTV HVR-1955 Model 160111", + .shortname = "160111", + .client_table.lst = pvr2_cli_160xxx, + .client_table.cnt = ARRAY_SIZE(pvr2_cli_160xxx), + .fx2_firmware.lst = pvr2_fw1_names_160xxx, + .fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_160xxx), + .default_tuner_type = TUNER_ABSENT, + .flag_has_cx25840 = 1, + .flag_has_hauppauge_rom = 1, + .flag_has_analogtuner = 1, + .flag_has_composite = 1, + .flag_has_svideo = 1, + .flag_fx2_16kb = 1, + .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, + .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, + .default_std_mask = V4L2_STD_NTSC_M, + .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, +#ifdef CONFIG_VIDEO_PVRUSB2_DVB + .dvb_props = &pvr2_160111_dvb_props, +#endif +}; /*------------------------------------------------------------------------*/ @@ -552,6 +714,10 @@ struct usb_device_id pvr2_device_table[] = { .driver_info = (kernel_ulong_t)&pvr2_device_751xx}, { USB_DEVICE(0x0ccd, 0x0039), .driver_info = (kernel_ulong_t)&pvr2_device_av400}, + { USB_DEVICE(0x2040, 0x7502), + .driver_info = (kernel_ulong_t)&pvr2_device_160111}, + { USB_DEVICE(0x2040, 0x7510), + .driver_info = (kernel_ulong_t)&pvr2_device_160000}, { } }; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h index c1e7d4822cd1..ea0b2bf429e9 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h @@ -66,6 +66,7 @@ struct pvr2_string_table { #define PVR2_ROUTING_SCHEME_GOTVIEW 1 #define PVR2_ROUTING_SCHEME_ONAIR 2 #define PVR2_ROUTING_SCHEME_AV400 3 +#define PVR2_ROUTING_SCHEME_HAUP160XXX 4 #define PVR2_DIGITAL_SCHEME_NONE 0 #define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1 diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h index 0a01de4e54db..640b033815ec 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h @@ -38,6 +38,10 @@ #define FX2CMD_FWPOST1 0x52u +/* These 2 only exist on Model 160xxx */ +#define FX2CMD_HCW_DEMOD_RESET_PIN 0xd4u +#define FX2CMD_HCW_MAKO_SLEEP_PIN 0xd5u + #define FX2CMD_POWER_OFF 0xdcu #define FX2CMD_POWER_ON 0xdeu diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 191439109788..957913146e88 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -316,6 +316,8 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"}, {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"}, {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"}, + {FX2CMD_HCW_DEMOD_RESET_PIN, "hcw demod reset pin"}, + {FX2CMD_HCW_MAKO_SLEEP_PIN, "hcw mako sleep pin"}, }; @@ -2139,10 +2141,28 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) ((0) << 16)); } - // This step MUST happen after the earlier powerup step. + /* This step MUST happen after the earlier powerup step */ pvr2_i2c_core_init(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; + /* Reset demod only on Hauppauge 160xxx platform */ + if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && + (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || + le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { + pr_info("%s(): resetting 160xxx demod\n", __func__); + /* TODO: not sure this is proper place to reset once only */ + pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_DEMOD_RESET_PIN | + (1 << 8) | + ((0) << 16)); + usleep_range(10000, 10500); + pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_DEMOD_RESET_PIN | + (1 << 8) | + ((1) << 16)); + usleep_range(10000, 10500); + } + pvr2_hdw_load_modules(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; @@ -4012,6 +4032,20 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw) static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff) { hdw->flag_ok = !0; + + /* Use this for Hauppauge 160xxx only */ + if (le16_to_cpu(hdw->usb_dev->descriptor.idVendor) == 0x2040 && + (le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7502 || + le16_to_cpu(hdw->usb_dev->descriptor.idProduct) == 0x7510)) { + pr_debug("%s(): resetting demod on Hauppauge 160xxx platform skipped\n", + __func__); + /* Can't reset 160xxx or it will trash Demod tristate */ + return pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_MAKO_SLEEP_PIN | + (1 << 8) | + ((onoff ? 1 : 0) << 16)); + } + return pvr2_issue_simple_cmd(hdw, FX2CMD_HCW_DEMOD_RESETIN | (1 << 8) | -- cgit v1.2.3-59-g8ed1b From 575f60312b3c5036385e95f61737da5a9e72f0ad Mon Sep 17 00:00:00 2001 From: Brad Love Date: Thu, 6 Jun 2019 12:57:54 -0400 Subject: media: cx231xx-cards: Add Hauppauge 955Q variant cx231xx/lgdt3306a/si2157/cx25840 Signed-off-by: Brad Love Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-cards.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index 26b05df698f0..e0d98ba8fdbf 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -1023,6 +1023,8 @@ struct usb_device_id cx231xx_id_table[] = { .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER}, {USB_DEVICE(0x2040, 0xb123), .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, + {USB_DEVICE(0x2040, 0xb124), + .driver_info = CX231XX_BOARD_HAUPPAUGE_955Q}, {USB_DEVICE(0x2040, 0xb151), .driver_info = CX231XX_BOARD_HAUPPAUGE_935C}, {USB_DEVICE(0x2040, 0xb150), -- cgit v1.2.3-59-g8ed1b From efe8b031d8eb92ef8c68efd05ca5c11a1050619a Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 11 Jun 2019 11:38:12 -0400 Subject: media: stv090x: fix double free on state object There two callers of stv090x_setup_compound manage the allocation and freeing if state there is an error condition from stv090x_setup_compound. Currently function stv090x_setup_compound also frees the state object too, leading to a double free in the callers of this function. Fix this by removing the extraneous free in stv090x_setup_compound and just leave the callers handle the allocation/free'ing. Signed-off-by: Colin Ian King Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv090x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index 986e585e0103..90d24131d335 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -4942,7 +4942,6 @@ static int stv090x_setup_compound(struct stv090x_state *state) return 0; error: - kfree(state); return -ENOMEM; err_remove: remove_dev(state->internal); -- cgit v1.2.3-59-g8ed1b From 12e23ebb396e6ffea88b8c5e483059a297326afb Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Thu, 13 Jun 2019 11:23:19 -0400 Subject: media: ttpci: Fix build error without RC_CORE If RC_CORE is not set, building fails: Reported-by: Hulk Robot Suggested-by: Sean Young Signed-off-by: YueHaibing Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ttpci/Kconfig b/drivers/media/pci/ttpci/Kconfig index d96d4fa20457..8a362ee9105f 100644 --- a/drivers/media/pci/ttpci/Kconfig +++ b/drivers/media/pci/ttpci/Kconfig @@ -1,13 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only config DVB_AV7110_IR bool + depends on RC_CORE=y || RC_CORE = DVB_AV7110 + default DVB_AV7110 config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C select TTPCI_EEPROM select VIDEO_SAA7146_VV - select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110 depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT -- cgit v1.2.3-59-g8ed1b From 5c4c8b4a999019f19e770cb55cbacb89c95897bd Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 13 Jun 2019 04:49:26 -0400 Subject: media: rc: IR signal for Panasonic air conditioner too long The IR signal to control the Panasonic ACXA75C00600 air conditioner has 439 pulse/spaces. Increase limit to make it possible to transmit signal. Reported-by: Takashi Kanamaru Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 10830605c734..f078f8a3aec8 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -19,7 +19,7 @@ #include "rc-core-priv.h" #include -#define LIRCBUF_SIZE 256 +#define LIRCBUF_SIZE 1024 static dev_t lirc_base_dev; -- cgit v1.2.3-59-g8ed1b From 4b1f67dc8edcb4a1e8a1d141609d89fa7d430d46 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 6 Jun 2019 12:12:53 -0400 Subject: media: v4l2-ctrl: Initialize _BUTTON and _CTRL_CLASS These two control types don't really need a default value, as they are not expected to carry any value. However, it's slightly clearer to initialize them explicitly instead of falling back to the switch default. Signed-off-by: Ezequiel Garcia Reviewed-by: Boris Brezillon Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index f2b9bdedbf8c..2d7525e2d9eb 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1520,6 +1520,10 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_BOOLEAN: ptr.p_s32[idx] = ctrl->default_value; break; + case V4L2_CTRL_TYPE_BUTTON: + case V4L2_CTRL_TYPE_CTRL_CLASS: + ptr.p_s32[idx] = 0; + break; case V4L2_CTRL_TYPE_U8: ptr.p_u8[idx] = ctrl->default_value; break; -- cgit v1.2.3-59-g8ed1b From 8eebd6150aa5232d4b47b9f0cc33c76b2bf3b06a Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 10 Jun 2019 16:55:23 -0400 Subject: media: mtk-jpeg: Use vb2_get_buffer Use the newly introduced vb2_get_buffer API and avoid accessing buffers in the queue directly. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c index 723a233e2b5f..ee802fc3bcdf 100644 --- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c +++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c @@ -518,7 +518,7 @@ static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return -EINVAL; } - vb = vq->bufs[buf->index]; + vb = vb2_get_buffer(vq, buf->index); jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb); jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ? MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT; -- cgit v1.2.3-59-g8ed1b From 9e393300167be4d0c6a6d17330de1fba9a675212 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 10 Jun 2019 16:55:24 -0400 Subject: media: mtk-vcodec: Use vb2_get_buffer Use the newly introduced vb2_get_buffer API and avoid accessing buffers in the queue directly. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: fixed checkpatch alignment warning] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index 480cc8fe281a..fd8de027e83e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -865,12 +865,18 @@ static int vb2ops_venc_start_streaming(struct vb2_queue *q, unsigned int count) err_set_param: for (i = 0; i < q->num_buffers; ++i) { - if (q->bufs[i]->state == VB2_BUF_STATE_ACTIVE) { + struct vb2_buffer *buf = vb2_get_buffer(q, i); + + /* + * FIXME: This check is not needed as only active buffers + * can be marked as done. + */ + if (buf->state == VB2_BUF_STATE_ACTIVE) { mtk_v4l2_debug(0, "[%d] id=%d, type=%d, %d -> VB2_BUF_STATE_QUEUED", ctx->id, i, q->type, - (int)q->bufs[i]->state); - v4l2_m2m_buf_done(to_vb2_v4l2_buffer(q->bufs[i]), - VB2_BUF_STATE_QUEUED); + (int)buf->state); + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(buf), + VB2_BUF_STATE_QUEUED); } } -- cgit v1.2.3-59-g8ed1b From ababd7612321bbe89abc87c607ca8d70702d9e56 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 10 Jun 2019 16:55:25 -0400 Subject: media: sti: Use vb2_get_buffer Use the newly introduced vb2_get_buffer API and avoid accessing buffers in the queue directly. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/hva/hva-v4l2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/sti/hva/hva-v4l2.c b/drivers/media/platform/sti/hva/hva-v4l2.c index c42623dccfd6..64004d15a9c9 100644 --- a/drivers/media/platform/sti/hva/hva-v4l2.c +++ b/drivers/media/platform/sti/hva/hva-v4l2.c @@ -566,6 +566,7 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) */ struct vb2_queue *vq; struct hva_stream *stream; + struct vb2_buffer *vb2_buf; vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, buf->type); @@ -575,7 +576,8 @@ static int hva_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return -EINVAL; } - stream = (struct hva_stream *)vq->bufs[buf->index]; + vb2_buf = vb2_get_buffer(vq, buf->index); + stream = to_hva_stream(to_vb2_v4l2_buffer(vb2_buf)); stream->bytesused = buf->bytesused; } -- cgit v1.2.3-59-g8ed1b From 0a0e265515db7619d0da9331d74245d02c741f07 Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 12 Jun 2019 08:00:31 -0400 Subject: media: atmel: atmel-isc: split driver into driver base and isc This splits the Atmel ISC driver into a common base: atmel-isc-base.c and the driver probe/dt part , atmel-sama5d2-isc.c This is needed to keep a common ground for the sensor controller which will be reused. The atmel-isc will use the common symbols inside the atmel-isc-base Future driver will also use the same symbols and redefine different aspects, for a different version of the ISC. This is done to avoid complete code duplication by creating a totally different driver for the new variant of the ISC. Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: folded 'atmel: atmel-sama5d2-isc: fixed checkpatch warnings' into this patch] Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 4 +- drivers/media/platform/atmel/Makefile | 4 +- drivers/media/platform/atmel/atmel-isc-base.c | 2153 ++++++++++++++++++ drivers/media/platform/atmel/atmel-isc.c | 2631 ---------------------- drivers/media/platform/atmel/atmel-isc.h | 249 ++ drivers/media/platform/atmel/atmel-sama5d2-isc.c | 344 +++ 6 files changed, 2752 insertions(+), 2633 deletions(-) create mode 100644 drivers/media/platform/atmel/atmel-isc-base.c delete mode 100644 drivers/media/platform/atmel/atmel-isc.c create mode 100644 drivers/media/platform/atmel/atmel-isc.h create mode 100644 drivers/media/platform/atmel/atmel-sama5d2-isc.c (limited to 'drivers/media') diff --git a/MAINTAINERS b/MAINTAINERS index ad2bf808b02c..bf32079578fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10296,7 +10296,9 @@ MICROCHIP ISC DRIVER M: Eugen Hristev L: linux-media@vger.kernel.org S: Supported -F: drivers/media/platform/atmel/atmel-isc.c +F: drivers/media/platform/atmel/atmel-sama5d2-isc.c +F: drivers/media/platform/atmel/atmel-isc.h +F: drivers/media/platform/atmel/atmel-isc-base.c F: drivers/media/platform/atmel/atmel-isc-regs.h F: Documentation/devicetree/bindings/media/atmel-isc.txt diff --git a/drivers/media/platform/atmel/Makefile b/drivers/media/platform/atmel/Makefile index 484936604ccb..2dba38994a70 100644 --- a/drivers/media/platform/atmel/Makefile +++ b/drivers/media/platform/atmel/Makefile @@ -1,3 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o +atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o + obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o +obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c new file mode 100644 index 000000000000..edfd7e00a565 --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -0,0 +1,2153 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Microchip Image Sensor Controller (ISC) common driver base + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atmel-isc-regs.h" +#include "atmel-isc.h" + +unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + +unsigned int sensor_preferred = 1; +module_param(sensor_preferred, uint, 0644); +MODULE_PARM_DESC(sensor_preferred, + "Sensor is preferred to output the specified format (1-on 0-off), default 1"); + +/* This is a list of the formats that the ISC can *output* */ +struct isc_format controller_formats[] = { + { + .fourcc = V4L2_PIX_FMT_ARGB444, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR32, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR32, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + }, +}; + +/* This is a list of formats that the ISC can receive as *input* */ +struct isc_format formats_list[] = { + { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_BGBG, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GBGB, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_GRGR, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, + .cfa_baycfg = ISC_BAY_CFG_RGRG, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, + }, +}; + +/* Gamma table with gamma 1/2.2 */ +const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { + /* 0 --> gamma 1/1.8 */ + { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, + 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, + 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F, + 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E, + 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C, + 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B, + 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A, + 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A, + 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A, + 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009, + 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 }, + + /* 1 --> gamma 1/2 */ + { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B, + 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013, + 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F, + 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D, + 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B, + 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A, + 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A, + 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009, + 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009, + 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009, + 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 }, + + /* 2 --> gamma 1/2.2 */ + { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B, + 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012, + 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F, + 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C, + 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B, + 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A, + 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009, + 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009, + 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008, + 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007, + 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, +}; + +#define ISC_IS_FORMAT_RAW(mbus_code) \ + (((mbus_code) & 0xf000) == 0x3000) + +static inline void isc_update_awb_ctrls(struct isc_device *isc) +{ + struct isc_ctrls *ctrls = &isc->ctrls; + + regmap_write(isc->regmap, ISC_WB_O_RGR, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); + regmap_write(isc->regmap, ISC_WB_O_BGB, + (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | + ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); + regmap_write(isc->regmap, ISC_WB_G_RGR, + ctrls->gain[ISC_HIS_CFG_MODE_R] | + (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); + regmap_write(isc->regmap, ISC_WB_G_BGB, + ctrls->gain[ISC_HIS_CFG_MODE_B] | + (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); +} + +static inline void isc_reset_awb_ctrls(struct isc_device *isc) +{ + int c; + + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* gains have a fixed point at 9 decimals */ + isc->ctrls.gain[c] = 1 << 9; + /* offsets are in 2's complements, the value + * will be substracted from ISC_WB_O_ZERO_VAL to obtain + * 2's complement of a value between 0 and + * ISC_WB_O_ZERO_VAL >> 1 + */ + isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; + } +} + +static int isc_wait_clk_stable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + struct regmap *regmap = isc_clk->regmap; + unsigned long timeout = jiffies + usecs_to_jiffies(1000); + unsigned int status; + + while (time_before(jiffies, timeout)) { + regmap_read(regmap, ISC_CLKSR, &status); + if (!(status & ISC_CLKSR_SIP)) + return 0; + + usleep_range(10, 250); + } + + return -ETIMEDOUT; +} + +static int isc_clk_prepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_get_sync(isc_clk->dev); + + return isc_wait_clk_stable(hw); +} + +static void isc_clk_unprepare(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + isc_wait_clk_stable(hw); + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_put_sync(isc_clk->dev); +} + +static int isc_clk_enable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 id = isc_clk->id; + struct regmap *regmap = isc_clk->regmap; + unsigned long flags; + unsigned int status; + + dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", + __func__, isc_clk->div, isc_clk->parent_id); + + spin_lock_irqsave(&isc_clk->lock, flags); + regmap_update_bits(regmap, ISC_CLKCFG, + ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), + (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | + (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); + + regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); + + regmap_read(regmap, ISC_CLKSR, &status); + if (status & ISC_CLK(id)) + return 0; + else + return -EINVAL; +} + +static void isc_clk_disable(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 id = isc_clk->id; + unsigned long flags; + + spin_lock_irqsave(&isc_clk->lock, flags); + regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); + spin_unlock_irqrestore(&isc_clk->lock, flags); +} + +static int isc_clk_is_enabled(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 status; + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_get_sync(isc_clk->dev); + + regmap_read(isc_clk->regmap, ISC_CLKSR, &status); + + if (isc_clk->id == ISC_ISPCK) + pm_runtime_put_sync(isc_clk->dev); + + return status & ISC_CLK(isc_clk->id) ? 1 : 0; +} + +static unsigned long +isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1); +} + +static int isc_clk_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + long best_rate = -EINVAL; + int best_diff = -1; + unsigned int i, div; + + for (i = 0; i < clk_hw_get_num_parents(hw); i++) { + struct clk_hw *parent; + unsigned long parent_rate; + + parent = clk_hw_get_parent_by_index(hw, i); + if (!parent) + continue; + + parent_rate = clk_hw_get_rate(parent); + if (!parent_rate) + continue; + + for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) { + unsigned long rate; + int diff; + + rate = DIV_ROUND_CLOSEST(parent_rate, div); + diff = abs(req->rate - rate); + + if (best_diff < 0 || best_diff > diff) { + best_rate = rate; + best_diff = diff; + req->best_parent_rate = parent_rate; + req->best_parent_hw = parent; + } + + if (!best_diff || rate < req->rate) + break; + } + + if (!best_diff) + break; + } + + dev_dbg(isc_clk->dev, + "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", + __func__, best_rate, + __clk_get_name((req->best_parent_hw)->clk), + req->best_parent_rate); + + if (best_rate < 0) + return best_rate; + + req->rate = best_rate; + + return 0; +} + +static int isc_clk_set_parent(struct clk_hw *hw, u8 index) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + if (index >= clk_hw_get_num_parents(hw)) + return -EINVAL; + + isc_clk->parent_id = index; + + return 0; +} + +static u8 isc_clk_get_parent(struct clk_hw *hw) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + + return isc_clk->parent_id; +} + +static int isc_clk_set_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long parent_rate) +{ + struct isc_clk *isc_clk = to_isc_clk(hw); + u32 div; + + if (!rate) + return -EINVAL; + + div = DIV_ROUND_CLOSEST(parent_rate, rate); + if (div > (ISC_CLK_MAX_DIV + 1) || !div) + return -EINVAL; + + isc_clk->div = div - 1; + + return 0; +} + +static const struct clk_ops isc_clk_ops = { + .prepare = isc_clk_prepare, + .unprepare = isc_clk_unprepare, + .enable = isc_clk_enable, + .disable = isc_clk_disable, + .is_enabled = isc_clk_is_enabled, + .recalc_rate = isc_clk_recalc_rate, + .determine_rate = isc_clk_determine_rate, + .set_parent = isc_clk_set_parent, + .get_parent = isc_clk_get_parent, + .set_rate = isc_clk_set_rate, +}; + +static int isc_clk_register(struct isc_device *isc, unsigned int id) +{ + struct regmap *regmap = isc->regmap; + struct device_node *np = isc->dev->of_node; + struct isc_clk *isc_clk; + struct clk_init_data init; + const char *clk_name = np->name; + const char *parent_names[3]; + int num_parents; + + num_parents = of_clk_get_parent_count(np); + if (num_parents < 1 || num_parents > 3) + return -EINVAL; + + if (num_parents > 2 && id == ISC_ISPCK) + num_parents = 2; + + of_clk_parent_fill(np, parent_names, num_parents); + + if (id == ISC_MCK) + of_property_read_string(np, "clock-output-names", &clk_name); + else + clk_name = "isc-ispck"; + + init.parent_names = parent_names; + init.num_parents = num_parents; + init.name = clk_name; + init.ops = &isc_clk_ops; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + + isc_clk = &isc->isc_clks[id]; + isc_clk->hw.init = &init; + isc_clk->regmap = regmap; + isc_clk->id = id; + isc_clk->dev = isc->dev; + spin_lock_init(&isc_clk->lock); + + isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); + if (IS_ERR(isc_clk->clk)) { + dev_err(isc->dev, "%s: clock register fail\n", clk_name); + return PTR_ERR(isc_clk->clk); + } else if (id == ISC_MCK) + of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk); + + return 0; +} + +int isc_clk_init(struct isc_device *isc) +{ + unsigned int i; + int ret; + + for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) + isc->isc_clks[i].clk = ERR_PTR(-EINVAL); + + for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { + ret = isc_clk_register(isc, i); + if (ret) + return ret; + } + + return 0; +} + +void isc_clk_cleanup(struct isc_device *isc) +{ + unsigned int i; + + of_clk_del_provider(isc->dev->of_node); + + for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { + struct isc_clk *isc_clk = &isc->isc_clks[i]; + + if (!IS_ERR(isc_clk->clk)) + clk_unregister(isc_clk->clk); + } +} + +static int isc_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct isc_device *isc = vb2_get_drv_priv(vq); + unsigned int size = isc->fmt.fmt.pix.sizeimage; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = size; + + return 0; +} + +static int isc_buffer_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = isc->fmt.fmt.pix.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", + vb2_plane_size(vb, 0), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, size); + + vbuf->field = isc->fmt.fmt.pix.field; + + return 0; +} + +static void isc_start_dma(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sizeimage = isc->fmt.fmt.pix.sizeimage; + u32 dctrl_dview; + dma_addr_t addr0; + u32 h, w; + + h = isc->fmt.fmt.pix.height; + w = isc->fmt.fmt.pix.width; + + /* + * In case the sensor is not RAW, it will output a pixel (12-16 bits) + * with two samples on the ISC Data bus (which is 8-12) + * ISC will count each sample, so, we need to multiply these values + * by two, to get the real number of samples for the required pixels. + */ + if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) { + h <<= 1; + w <<= 1; + } + + /* + * We limit the column/row count that the ISC will output according + * to the configured resolution that we want. + * This will avoid the situation where the sensor is misconfigured, + * sending more data, and the ISC will just take it and DMA to memory, + * causing corruption. + */ + regmap_write(regmap, ISC_PFE_CFG1, + (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) | + (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK)); + + regmap_write(regmap, ISC_PFE_CFG2, + (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) | + (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK)); + + regmap_update_bits(regmap, ISC_PFE_CFG0, + ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, + ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); + + addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); + regmap_write(regmap, ISC_DAD0, addr0); + + switch (isc->config.fourcc) { + case V4L2_PIX_FMT_YUV420: + regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); + regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); + break; + case V4L2_PIX_FMT_YUV422P: + regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2); + regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4); + break; + default: + break; + } + + dctrl_dview = isc->config.dctrl_dview; + + regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); + spin_lock(&isc->awb_lock); + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); + spin_unlock(&isc->awb_lock); +} + +static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 val, bay_cfg; + const u32 *gamma; + unsigned int i; + + /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ + for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { + val = pipeline & BIT(i) ? 1 : 0; + regmap_field_write(isc->pipeline[i], val); + } + + if (!pipeline) + return; + + bay_cfg = isc->config.sd_format->cfa_baycfg; + + if (ctrls->awb == ISC_WB_NONE) + isc_reset_awb_ctrls(isc); + + regmap_write(regmap, ISC_WB_CFG, bay_cfg); + isc_update_awb_ctrls(isc); + + regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); + + gamma = &isc_gamma_table[ctrls->gamma_index][0]; + regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES); + regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES); + regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES); + + /* Convert RGB to YUV */ + regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16)); + regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16)); + regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16)); + regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16)); + regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16)); + regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16)); + + regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness); + regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast); +} + +static int isc_update_profile(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 sr; + int counter = 100; + + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); + + regmap_read(regmap, ISC_CTRLSR, &sr); + while ((sr & ISC_CTRL_UPPRO) && counter--) { + usleep_range(1000, 2000); + regmap_read(regmap, ISC_CTRLSR, &sr); + } + + if (counter < 0) { + v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void isc_set_histogram(struct isc_device *isc, bool enable) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + + if (enable) { + regmap_write(regmap, ISC_HIS_CFG, + ISC_HIS_CFG_MODE_GR | + (isc->config.sd_format->cfa_baycfg + << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); + regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); + regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); + ctrls->hist_id = ISC_HIS_CFG_MODE_GR; + isc_update_profile(isc); + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + + ctrls->hist_stat = HIST_ENABLED; + } else { + regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); + regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); + + ctrls->hist_stat = HIST_DISABLED; + } +} + +static int isc_configure(struct isc_device *isc) +{ + struct regmap *regmap = isc->regmap; + u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; + struct isc_subdev_entity *subdev = isc->current_subdev; + + pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; + rlp_mode = isc->config.rlp_cfg_mode; + pipeline = isc->config.bits_pipeline; + + dcfg = isc->config.dcfg_imode | + ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; + + pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; + mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | + ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | + ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + + regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); + + regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, + rlp_mode); + + regmap_write(regmap, ISC_DCFG, dcfg); + + /* Set the pipeline */ + isc_set_pipeline(isc, pipeline); + + /* + * The current implemented histogram is available for RAW R, B, GB, GR + * channels. We need to check if sensor is outputting RAW BAYER + */ + if (isc->ctrls.awb && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + else + isc_set_histogram(isc, false); + + /* Update profile */ + return isc_update_profile(isc); +} + +static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct isc_device *isc = vb2_get_drv_priv(vq); + struct regmap *regmap = isc->regmap; + struct isc_buffer *buf; + unsigned long flags; + int ret; + + /* Enable stream on the sub device */ + ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", + ret); + goto err_start_stream; + } + + pm_runtime_get_sync(isc->dev); + + ret = isc_configure(isc); + if (unlikely(ret)) + goto err_configure; + + /* Enable DMA interrupt */ + regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE); + + spin_lock_irqsave(&isc->dma_queue_lock, flags); + + isc->sequence = 0; + isc->stop = false; + reinit_completion(&isc->comp); + + isc->cur_frm = list_first_entry(&isc->dma_queue, + struct isc_buffer, list); + list_del(&isc->cur_frm->list); + + isc_start_dma(isc); + + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); + + /* if we streaming from RAW, we can do one-shot white balance adj */ + if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + v4l2_ctrl_activate(isc->do_wb_ctrl, true); + + return 0; + +err_configure: + pm_runtime_put_sync(isc->dev); + + v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); + +err_start_stream: + spin_lock_irqsave(&isc->dma_queue_lock, flags); + list_for_each_entry(buf, &isc->dma_queue, list) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + INIT_LIST_HEAD(&isc->dma_queue); + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); + + return ret; +} + +static void isc_stop_streaming(struct vb2_queue *vq) +{ + struct isc_device *isc = vb2_get_drv_priv(vq); + unsigned long flags; + struct isc_buffer *buf; + int ret; + + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + + isc->stop = true; + + /* Wait until the end of the current frame */ + if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) + v4l2_err(&isc->v4l2_dev, + "Timeout waiting for end of the capture\n"); + + /* Disable DMA interrupt */ + regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); + + pm_runtime_put_sync(isc->dev); + + /* Disable stream on the sub device */ + ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); + if (ret && ret != -ENOIOCTLCMD) + v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); + + /* Release all active buffers */ + spin_lock_irqsave(&isc->dma_queue_lock, flags); + if (unlikely(isc->cur_frm)) { + vb2_buffer_done(&isc->cur_frm->vb.vb2_buf, + VB2_BUF_STATE_ERROR); + isc->cur_frm = NULL; + } + list_for_each_entry(buf, &isc->dma_queue, list) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + INIT_LIST_HEAD(&isc->dma_queue); + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); +} + +static void isc_buffer_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb); + struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); + unsigned long flags; + + spin_lock_irqsave(&isc->dma_queue_lock, flags); + if (!isc->cur_frm && list_empty(&isc->dma_queue) && + vb2_is_streaming(vb->vb2_queue)) { + isc->cur_frm = buf; + isc_start_dma(isc); + } else + list_add_tail(&buf->list, &isc->dma_queue); + spin_unlock_irqrestore(&isc->dma_queue_lock, flags); +} + +static struct isc_format *find_format_by_fourcc(struct isc_device *isc, + unsigned int fourcc) +{ + unsigned int num_formats = isc->num_user_formats; + struct isc_format *fmt; + unsigned int i; + + for (i = 0; i < num_formats; i++) { + fmt = isc->user_formats[i]; + if (fmt->fourcc == fourcc) + return fmt; + } + + return NULL; +} + +static const struct vb2_ops isc_vb2_ops = { + .queue_setup = isc_queue_setup, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_prepare = isc_buffer_prepare, + .start_streaming = isc_start_streaming, + .stop_streaming = isc_stop_streaming, + .buf_queue = isc_buffer_queue, +}; + +static int isc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct isc_device *isc = video_drvdata(file); + + strscpy(cap->driver, ATMEL_ISC_NAME, sizeof(cap->driver)); + strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", isc->v4l2_dev.name); + + return 0; +} + +static int isc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + u32 index = f->index; + u32 i, supported_index; + + if (index < ARRAY_SIZE(controller_formats)) { + f->pixelformat = controller_formats[index].fourcc; + return 0; + } + + index -= ARRAY_SIZE(controller_formats); + + i = 0; + supported_index = 0; + + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { + if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) || + !formats_list[i].sd_support) + continue; + if (supported_index == index) { + f->pixelformat = formats_list[i].fourcc; + return 0; + } + supported_index++; + } + + return -EINVAL; +} + +static int isc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct isc_device *isc = video_drvdata(file); + + *fmt = isc->fmt; + + return 0; +} + +/* + * Checks the current configured format, if ISC can output it, + * considering which type of format the ISC receives from the sensor + */ +static int isc_try_validate_formats(struct isc_device *isc) +{ + int ret; + bool bayer = false, yuv = false, rgb = false, grey = false; + + /* all formats supported by the RLP module are OK */ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + ret = 0; + bayer = true; + break; + + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + ret = 0; + yuv = true; + break; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ARGB555: + ret = 0; + rgb = true; + break; + case V4L2_PIX_FMT_GREY: + ret = 0; + grey = true; + break; + default: + /* any other different formats are not supported */ + ret = -EINVAL; + } + + /* we cannot output RAW/Grey if we do not receive RAW */ + if ((bayer || grey) && + !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) + return -EINVAL; + + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", + rgb, yuv, grey, bayer); + + return ret; +} + +/* + * Configures the RLP and DMA modules, depending on the output format + * configured for the ISC. + * If direct_dump == true, just dump raw data 8 bits. + */ +static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) +{ + if (direct_dump) { + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + return 0; + } + + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_RGB565: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB444: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB555: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 32; + break; + case V4L2_PIX_FMT_YUV420: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 12; + break; + case V4L2_PIX_FMT_YUV422P: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_YUYV: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_GREY: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Configuring pipeline modules, depending on which format the ISC outputs + * and considering which format it has as input from the sensor. + */ +static int isc_try_configure_pipeline(struct isc_device *isc) +{ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + WB_ENABLE | GAM_ENABLES; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV420: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV422P: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUYV: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_GREY: + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + /* if sensor format is RAW, we convert inside ISC */ + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + default: + isc->try_config.bits_pipeline = 0x0; + } + return 0; +} + +static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, + u32 *code) +{ + int i; + struct isc_format *sd_fmt = NULL, *direct_fmt = NULL; + struct v4l2_pix_format *pixfmt = &f->fmt.pix; + struct v4l2_subdev_pad_config pad_cfg; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_TRY, + }; + u32 mbus_code; + int ret; + bool rlp_dma_direct_dump = false; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* Step 1: find a RAW format that is supported */ + for (i = 0; i < isc->num_user_formats; i++) { + if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) { + sd_fmt = isc->user_formats[i]; + break; + } + } + /* Step 2: We can continue with this RAW format, or we can look + * for better: maybe sensor supports directly what we need. + */ + direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); + + /* Step 3: We have both. We decide given the module parameter which + * one to use. + */ + if (direct_fmt && sd_fmt && sensor_preferred) + sd_fmt = direct_fmt; + + /* Step 4: we do not have RAW but we have a direct format. Use it. */ + if (direct_fmt && !sd_fmt) + sd_fmt = direct_fmt; + + /* Step 5: if we are using a direct format, we need to package + * everything as 8 bit data and just dump it + */ + if (sd_fmt == direct_fmt) + rlp_dma_direct_dump = true; + + /* Step 6: We have no format. This can happen if the userspace + * requests some weird/invalid format. + * In this case, default to whatever we have + */ + if (!sd_fmt && !direct_fmt) { + sd_fmt = isc->user_formats[isc->num_user_formats - 1]; + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Sensor not supporting %.4s, using %.4s\n", + (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc); + } + + if (!sd_fmt) { + ret = -EINVAL; + goto isc_try_fmt_err; + } + + /* Step 7: Print out what we decided for debugging */ + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Preferring to have sensor using format %.4s\n", + (char *)&sd_fmt->fourcc); + + /* Step 8: at this moment we decided which format the subdev will use */ + isc->try_config.sd_format = sd_fmt; + + /* Limit to Atmel ISC hardware capabilities */ + if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) + pixfmt->width = ISC_MAX_SUPPORT_WIDTH; + if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) + pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; + + /* + * The mbus format is the one the subdev outputs. + * The pixels will be transferred in this format Sensor -> ISC + */ + mbus_code = sd_fmt->mbus_code; + + /* + * Validate formats. If the required format is not OK, default to raw. + */ + + isc->try_config.fourcc = pixfmt->pixelformat; + + if (isc_try_validate_formats(isc)) { + pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc; + /* Re-try to validate the new format */ + ret = isc_try_validate_formats(isc); + if (ret) + goto isc_try_fmt_err; + } + + ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump); + if (ret) + goto isc_try_fmt_err; + + ret = isc_try_configure_pipeline(isc); + if (ret) + goto isc_try_fmt_err; + + v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, + &pad_cfg, &format); + if (ret < 0) + goto isc_try_fmt_subdev_err; + + v4l2_fill_pix_format(pixfmt, &format.format); + + pixfmt->field = V4L2_FIELD_NONE; + pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3; + pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; + + if (code) + *code = mbus_code; + + return 0; + +isc_try_fmt_err: + v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); +isc_try_fmt_subdev_err: + memset(&isc->try_config, 0, sizeof(isc->try_config)); + + return ret; +} + +static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) +{ + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + u32 mbus_code = 0; + int ret; + + ret = isc_try_fmt(isc, f, &mbus_code); + if (ret) + return ret; + + v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code); + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, + set_fmt, NULL, &format); + if (ret < 0) + return ret; + + isc->fmt = *f; + + if (isc->try_config.sd_format && isc->config.sd_format && + isc->try_config.sd_format != isc->config.sd_format) { + isc->ctrls.hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); + } + /* make the try configuration active */ + isc->config = isc->try_config; + + v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); + + return 0; +} + +static int isc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct isc_device *isc = video_drvdata(file); + + if (vb2_is_streaming(&isc->vb2_vidq)) + return -EBUSY; + + return isc_set_fmt(isc, f); +} + +static int isc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct isc_device *isc = video_drvdata(file); + + return isc_try_fmt(isc, f, NULL); +} + +static int isc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + if (inp->index != 0) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + inp->std = 0; + strscpy(inp->name, "Camera", sizeof(inp->name)); + + return 0; +} + +static int isc_g_input(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + + return 0; +} + +static int isc_s_input(struct file *file, void *priv, unsigned int i) +{ + if (i > 0) + return -EINVAL; + + return 0; +} + +static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct isc_device *isc = video_drvdata(file); + + return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); +} + +static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct isc_device *isc = video_drvdata(file); + + return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); +} + +static int isc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev_frame_size_enum fse = { + .index = fsize->index, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret = -EINVAL; + int i; + + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fsize->pixel_format) + ret = 0; + + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fsize->pixel_format) + ret = 0; + + if (ret) + return ret; + + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, + NULL, &fse); + if (ret) + return ret; + + fse.code = isc->config.sd_format->mbus_code; + + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete.width = fse.max_width; + fsize->discrete.height = fse.max_height; + + return 0; +} + +static int isc_enum_frameintervals(struct file *file, void *fh, + struct v4l2_frmivalenum *fival) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev_frame_interval_enum fie = { + .index = fival->index, + .width = fival->width, + .height = fival->height, + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + int ret = -EINVAL; + int i; + + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fival->pixel_format) + ret = 0; + + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fival->pixel_format) + ret = 0; + + if (ret) + return ret; + + ret = v4l2_subdev_call(isc->current_subdev->sd, pad, + enum_frame_interval, NULL, &fie); + if (ret) + return ret; + + fie.code = isc->config.sd_format->mbus_code; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = fie.interval; + + return 0; +} + +static const struct v4l2_ioctl_ops isc_ioctl_ops = { + .vidioc_querycap = isc_querycap, + .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap, + + .vidioc_enum_input = isc_enum_input, + .vidioc_g_input = isc_g_input, + .vidioc_s_input = isc_s_input, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_parm = isc_g_parm, + .vidioc_s_parm = isc_s_parm, + .vidioc_enum_framesizes = isc_enum_framesizes, + .vidioc_enum_frameintervals = isc_enum_frameintervals, + + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static int isc_open(struct file *file) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev *sd = isc->current_subdev->sd; + int ret; + + if (mutex_lock_interruptible(&isc->lock)) + return -ERESTARTSYS; + + ret = v4l2_fh_open(file); + if (ret < 0) + goto unlock; + + if (!v4l2_fh_is_singular_file(file)) + goto unlock; + + ret = v4l2_subdev_call(sd, core, s_power, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + v4l2_fh_release(file); + goto unlock; + } + + ret = isc_set_fmt(isc, &isc->fmt); + if (ret) { + v4l2_subdev_call(sd, core, s_power, 0); + v4l2_fh_release(file); + } + +unlock: + mutex_unlock(&isc->lock); + return ret; +} + +static int isc_release(struct file *file) +{ + struct isc_device *isc = video_drvdata(file); + struct v4l2_subdev *sd = isc->current_subdev->sd; + bool fh_singular; + int ret; + + mutex_lock(&isc->lock); + + fh_singular = v4l2_fh_is_singular_file(file); + + ret = _vb2_fop_release(file, NULL); + + if (fh_singular) + v4l2_subdev_call(sd, core, s_power, 0); + + mutex_unlock(&isc->lock); + + return ret; +} + +static const struct v4l2_file_operations isc_fops = { + .owner = THIS_MODULE, + .open = isc_open, + .release = isc_release, + .unlocked_ioctl = video_ioctl2, + .read = vb2_fop_read, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, +}; + +irqreturn_t isc_interrupt(int irq, void *dev_id) +{ + struct isc_device *isc = (struct isc_device *)dev_id; + struct regmap *regmap = isc->regmap; + u32 isc_intsr, isc_intmask, pending; + irqreturn_t ret = IRQ_NONE; + + regmap_read(regmap, ISC_INTSR, &isc_intsr); + regmap_read(regmap, ISC_INTMASK, &isc_intmask); + + pending = isc_intsr & isc_intmask; + + if (likely(pending & ISC_INT_DDONE)) { + spin_lock(&isc->dma_queue_lock); + if (isc->cur_frm) { + struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; + struct vb2_buffer *vb = &vbuf->vb2_buf; + + vb->timestamp = ktime_get_ns(); + vbuf->sequence = isc->sequence++; + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + isc->cur_frm = NULL; + } + + if (!list_empty(&isc->dma_queue) && !isc->stop) { + isc->cur_frm = list_first_entry(&isc->dma_queue, + struct isc_buffer, list); + list_del(&isc->cur_frm->list); + + isc_start_dma(isc); + } + + if (isc->stop) + complete(&isc->comp); + + ret = IRQ_HANDLED; + spin_unlock(&isc->dma_queue_lock); + } + + if (pending & ISC_INT_HISDONE) { + schedule_work(&isc->awb_work); + ret = IRQ_HANDLED; + } + + return ret; +} + +static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) +{ + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; + u32 *hist_entry = &ctrls->hist_entry[0]; + u32 i; + + *min = 0; + *max = HIST_ENTRIES; + + regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); + + *hist_count = 0; + /* + * we deliberately ignore the end of the histogram, + * the most white pixels + */ + for (i = 1; i < HIST_ENTRIES; i++) { + if (*hist_entry && !*min) + *min = i; + if (*hist_entry) + *max = i; + *hist_count += i * (*hist_entry++); + } + + if (!*min) + *min = 1; +} + +static void isc_wb_update(struct isc_ctrls *ctrls) +{ + u32 *hist_count = &ctrls->hist_count[0]; + u32 c, offset[4]; + u64 avg = 0; + /* We compute two gains, stretch gain and grey world gain */ + u32 s_gain[4], gw_gain[4]; + + /* + * According to Grey World, we need to set gains for R/B to normalize + * them towards the green channel. + * Thus we want to keep Green as fixed and adjust only Red/Blue + * Compute the average of the both green channels first + */ + avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + + (u64)hist_count[ISC_HIS_CFG_MODE_GB]; + avg >>= 1; + + /* Green histogram is null, nothing to do */ + if (!avg) + return; + + for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { + /* + * the color offset is the minimum value of the histogram. + * we stretch this color to the full range by substracting + * this value from the color component. + */ + offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; + /* + * The offset is always at least 1. If the offset is 1, we do + * not need to adjust it, so our result must be zero. + * the offset is computed in a histogram on 9 bits (0..512) + * but the offset in register is based on + * 12 bits pipeline (0..4096). + * we need to shift with the 3 bits that the histogram is + * ignoring + */ + ctrls->offset[c] = (offset[c] - 1) << 3; + + /* the offset is then taken and converted to 2's complements */ + if (!ctrls->offset[c]) + ctrls->offset[c] = ISC_WB_O_ZERO_VAL; + + /* + * the stretch gain is the total number of histogram bins + * divided by the actual range of color component (Max - Min) + * If we compute gain like this, the actual color component + * will be stretched to the full histogram. + * We need to shift 9 bits for precision, we have 9 bits for + * decimals + */ + s_gain[c] = (HIST_ENTRIES << 9) / + (ctrls->hist_minmax[c][HIST_MAX_INDEX] - + ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); + + /* + * Now we have to compute the gain w.r.t. the average. + * Add/lose gain to the component towards the average. + * If it happens that the component is zero, use the + * fixed point value : 1.0 gain. + */ + if (hist_count[c]) + gw_gain[c] = div_u64(avg << 9, hist_count[c]); + else + gw_gain[c] = 1 << 9; + + /* multiply both gains and adjust for decimals */ + ctrls->gain[c] = s_gain[c] * gw_gain[c]; + ctrls->gain[c] >>= 9; + } +} + +static void isc_awb_work(struct work_struct *w) +{ + struct isc_device *isc = + container_of(w, struct isc_device, awb_work); + struct regmap *regmap = isc->regmap; + struct isc_ctrls *ctrls = &isc->ctrls; + u32 hist_id = ctrls->hist_id; + u32 baysel; + unsigned long flags; + u32 min, max; + + /* streaming is not active anymore */ + if (isc->stop) + return; + + if (ctrls->hist_stat != HIST_ENABLED) + return; + + isc_hist_count(isc, &min, &max); + ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; + ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; + + if (hist_id != ISC_HIS_CFG_MODE_B) { + hist_id++; + } else { + isc_wb_update(ctrls); + hist_id = ISC_HIS_CFG_MODE_GR; + } + + ctrls->hist_id = hist_id; + baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; + + /* if no more auto white balance, reset controls. */ + if (ctrls->awb == ISC_WB_NONE) + isc_reset_awb_ctrls(isc); + + pm_runtime_get_sync(isc->dev); + + /* + * only update if we have all the required histograms and controls + * if awb has been disabled, we need to reset registers as well. + */ + if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { + /* + * It may happen that DMA Done IRQ will trigger while we are + * updating white balance registers here. + * In that case, only parts of the controls have been updated. + * We can avoid that by locking the section. + */ + spin_lock_irqsave(&isc->awb_lock, flags); + isc_update_awb_ctrls(isc); + spin_unlock_irqrestore(&isc->awb_lock, flags); + + /* + * if we are doing just the one time white balance adjustment, + * we are basically done. + */ + if (ctrls->awb == ISC_WB_ONETIME) { + v4l2_info(&isc->v4l2_dev, + "Completed one time white-balance adjustment.\n"); + ctrls->awb = ISC_WB_NONE; + } + } + regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); + isc_update_profile(isc); + /* if awb has been disabled, we don't need to start another histogram */ + if (ctrls->awb) + regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); + + pm_runtime_put_sync(isc->dev); +} + +static int isc_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct isc_device *isc = container_of(ctrl->handler, + struct isc_device, ctrls.handler); + struct isc_ctrls *ctrls = &isc->ctrls; + + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; + break; + case V4L2_CID_CONTRAST: + ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; + break; + case V4L2_CID_GAMMA: + ctrls->gamma_index = ctrl->val; + break; + case V4L2_CID_AUTO_WHITE_BALANCE: + if (ctrl->val == 1) + ctrls->awb = ISC_WB_AUTO; + else + ctrls->awb = ISC_WB_NONE; + + /* we did not configure ISC yet */ + if (!isc->config.sd_format) + break; + + if (ctrls->hist_stat != HIST_ENABLED) + isc_reset_awb_ctrls(isc); + + if (isc->ctrls.awb == ISC_WB_AUTO && + vb2_is_streaming(&isc->vb2_vidq) && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + + break; + case V4L2_CID_DO_WHITE_BALANCE: + /* if AWB is enabled, do nothing */ + if (ctrls->awb == ISC_WB_AUTO) + return 0; + + ctrls->awb = ISC_WB_ONETIME; + isc_set_histogram(isc, true); + v4l2_dbg(1, debug, &isc->v4l2_dev, + "One time white-balance started.\n"); + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops isc_ctrl_ops = { + .s_ctrl = isc_s_ctrl, +}; + +static int isc_ctrl_init(struct isc_device *isc) +{ + const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; + struct isc_ctrls *ctrls = &isc->ctrls; + struct v4l2_ctrl_handler *hdl = &ctrls->handler; + int ret; + + ctrls->hist_stat = HIST_INIT; + isc_reset_awb_ctrls(isc); + + ret = v4l2_ctrl_handler_init(hdl, 5); + if (ret < 0) + return ret; + + ctrls->brightness = 0; + ctrls->contrast = 256; + + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); + + /* do_white_balance is a button, so min,max,step,default are ignored */ + isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, + 0, 0, 0, 0); + + v4l2_ctrl_activate(isc->do_wb_ctrl, false); + + v4l2_ctrl_handler_setup(hdl); + + return 0; +} + +static int isc_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct isc_device *isc = container_of(notifier->v4l2_dev, + struct isc_device, v4l2_dev); + struct isc_subdev_entity *subdev_entity = + container_of(notifier, struct isc_subdev_entity, notifier); + + if (video_is_registered(&isc->video_dev)) { + v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); + return -EBUSY; + } + + subdev_entity->sd = subdev; + + return 0; +} + +static void isc_async_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_subdev *asd) +{ + struct isc_device *isc = container_of(notifier->v4l2_dev, + struct isc_device, v4l2_dev); + cancel_work_sync(&isc->awb_work); + video_unregister_device(&isc->video_dev); + v4l2_ctrl_handler_free(&isc->ctrls.handler); +} + +static struct isc_format *find_format_by_code(unsigned int code, int *index) +{ + struct isc_format *fmt = &formats_list[0]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { + if (fmt->mbus_code == code) { + *index = i; + return fmt; + } + + fmt++; + } + + return NULL; +} + +static int isc_formats_init(struct isc_device *isc) +{ + struct isc_format *fmt; + struct v4l2_subdev *subdev = isc->current_subdev->sd; + unsigned int num_fmts, i, j; + u32 list_size = ARRAY_SIZE(formats_list); + struct v4l2_subdev_mbus_code_enum mbus_code = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + + num_fmts = 0; + while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, + NULL, &mbus_code)) { + mbus_code.index++; + + fmt = find_format_by_code(mbus_code.code, &i); + if (!fmt) { + v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", + mbus_code.code); + continue; + } + + fmt->sd_support = true; + num_fmts++; + } + + if (!num_fmts) + return -ENXIO; + + isc->num_user_formats = num_fmts; + isc->user_formats = devm_kcalloc(isc->dev, + num_fmts, sizeof(*isc->user_formats), + GFP_KERNEL); + if (!isc->user_formats) + return -ENOMEM; + + fmt = &formats_list[0]; + for (i = 0, j = 0; i < list_size; i++) { + if (fmt->sd_support) + isc->user_formats[j++] = fmt; + fmt++; + } + + return 0; +} + +static int isc_set_default_fmt(struct isc_device *isc) +{ + struct v4l2_format f = { + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .fmt.pix = { + .width = VGA_WIDTH, + .height = VGA_HEIGHT, + .field = V4L2_FIELD_NONE, + .pixelformat = isc->user_formats[0]->fourcc, + }, + }; + int ret; + + ret = isc_try_fmt(isc, &f, NULL); + if (ret) + return ret; + + isc->fmt = f; + return 0; +} + +static int isc_async_complete(struct v4l2_async_notifier *notifier) +{ + struct isc_device *isc = container_of(notifier->v4l2_dev, + struct isc_device, v4l2_dev); + struct video_device *vdev = &isc->video_dev; + struct vb2_queue *q = &isc->vb2_vidq; + int ret; + + INIT_WORK(&isc->awb_work, isc_awb_work); + + ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); + return ret; + } + + isc->current_subdev = container_of(notifier, + struct isc_subdev_entity, notifier); + mutex_init(&isc->lock); + init_completion(&isc->comp); + + /* Initialize videobuf2 queue */ + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; + q->drv_priv = isc; + q->buf_struct_size = sizeof(struct isc_buffer); + q->ops = &isc_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &isc->lock; + q->min_buffers_needed = 1; + q->dev = isc->dev; + + ret = vb2_queue_init(q); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, + "vb2_queue_init() failed: %d\n", ret); + return ret; + } + + /* Init video dma queues */ + INIT_LIST_HEAD(&isc->dma_queue); + spin_lock_init(&isc->dma_queue_lock); + spin_lock_init(&isc->awb_lock); + + ret = isc_formats_init(isc); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, + "Init format failed: %d\n", ret); + return ret; + } + + ret = isc_set_default_fmt(isc); + if (ret) { + v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); + return ret; + } + + ret = isc_ctrl_init(isc); + if (ret) { + v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); + return ret; + } + + /* Register video device */ + strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); + vdev->release = video_device_release_empty; + vdev->fops = &isc_fops; + vdev->ioctl_ops = &isc_ioctl_ops; + vdev->v4l2_dev = &isc->v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + vdev->queue = q; + vdev->lock = &isc->lock; + vdev->ctrl_handler = &isc->ctrls.handler; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; + video_set_drvdata(vdev, isc); + + ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); + if (ret < 0) { + v4l2_err(&isc->v4l2_dev, + "video_register_device failed: %d\n", ret); + return ret; + } + + return 0; +} + +const struct v4l2_async_notifier_operations isc_async_ops = { + .bound = isc_async_bound, + .unbind = isc_async_unbind, + .complete = isc_async_complete, +}; + +void isc_subdev_cleanup(struct isc_device *isc) +{ + struct isc_subdev_entity *subdev_entity; + + list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { + v4l2_async_notifier_unregister(&subdev_entity->notifier); + v4l2_async_notifier_cleanup(&subdev_entity->notifier); + } + + INIT_LIST_HEAD(&isc->subdev_entities); +} + +int isc_pipeline_init(struct isc_device *isc) +{ + struct device *dev = isc->dev; + struct regmap *regmap = isc->regmap; + struct regmap_field *regs; + unsigned int i; + + /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ + const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = { + REG_FIELD(ISC_WB_CTRL, 0, 0), + REG_FIELD(ISC_CFA_CTRL, 0, 0), + REG_FIELD(ISC_CC_CTRL, 0, 0), + REG_FIELD(ISC_GAM_CTRL, 0, 0), + REG_FIELD(ISC_GAM_CTRL, 1, 1), + REG_FIELD(ISC_GAM_CTRL, 2, 2), + REG_FIELD(ISC_GAM_CTRL, 3, 3), + REG_FIELD(ISC_CSC_CTRL, 0, 0), + REG_FIELD(ISC_CBC_CTRL, 0, 0), + REG_FIELD(ISC_SUB422_CTRL, 0, 0), + REG_FIELD(ISC_SUB420_CTRL, 0, 0), + }; + + for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { + regs = devm_regmap_field_alloc(dev, regmap, regfields[i]); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + isc->pipeline[i] = regs; + } + + return 0; +} + +/* regmap configuration */ +#define ATMEL_ISC_REG_MAX 0xbfc +const struct regmap_config isc_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .max_register = ATMEL_ISC_REG_MAX, +}; + diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c deleted file mode 100644 index 6f80980214ac..000000000000 --- a/drivers/media/platform/atmel/atmel-isc.c +++ /dev/null @@ -1,2631 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Atmel Image Sensor Controller (ISC) driver - * - * Copyright (C) 2016 Atmel - * - * Author: Songjun Wu - * - * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA - * - * ISC video pipeline integrates the following submodules: - * PFE: Parallel Front End to sample the camera sensor input stream - * WB: Programmable white balance in the Bayer domain - * CFA: Color filter array interpolation module - * CC: Programmable color correction - * GAM: Gamma correction - * CSC: Programmable color space conversion - * CBC: Contrast and Brightness control - * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling - * RLP: This module performs rounding, range limiting - * and packing of the incoming data - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "atmel-isc-regs.h" - -#define ATMEL_ISC_NAME "atmel_isc" - -#define ISC_MAX_SUPPORT_WIDTH 2592 -#define ISC_MAX_SUPPORT_HEIGHT 1944 - -#define ISC_CLK_MAX_DIV 255 - -enum isc_clk_id { - ISC_ISPCK = 0, - ISC_MCK = 1, -}; - -struct isc_clk { - struct clk_hw hw; - struct clk *clk; - struct regmap *regmap; - spinlock_t lock; - u8 id; - u8 parent_id; - u32 div; - struct device *dev; -}; - -#define to_isc_clk(hw) container_of(hw, struct isc_clk, hw) - -struct isc_buffer { - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -struct isc_subdev_entity { - struct v4l2_subdev *sd; - struct v4l2_async_subdev *asd; - struct v4l2_async_notifier notifier; - - u32 pfe_cfg0; - - struct list_head list; -}; - -/* - * struct isc_format - ISC media bus format information - This structure represents the interface between the ISC - and the sensor. It's the input format received by - the ISC. - * @fourcc: Fourcc code for this format - * @mbus_code: V4L2 media bus format code. - * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. - this is either BGBG, RGRG, etc. - * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC - */ - -struct isc_format { - u32 fourcc; - u32 mbus_code; - u32 cfa_baycfg; - - bool sd_support; - u32 pfe_cfg0_bps; -}; - -/* Pipeline bitmap */ -#define WB_ENABLE BIT(0) -#define CFA_ENABLE BIT(1) -#define CC_ENABLE BIT(2) -#define GAM_ENABLE BIT(3) -#define GAM_BENABLE BIT(4) -#define GAM_GENABLE BIT(5) -#define GAM_RENABLE BIT(6) -#define CSC_ENABLE BIT(7) -#define CBC_ENABLE BIT(8) -#define SUB422_ENABLE BIT(9) -#define SUB420_ENABLE BIT(10) - -#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) - -/* - * struct fmt_config - ISC format configuration and internal pipeline - This structure represents the internal configuration - of the ISC. - It also holds the format that ISC will present to v4l2. - * @sd_format: Pointer to an isc_format struct that holds the sensor - configuration. - * @fourcc: Fourcc code for this format. - * @bpp: Bytes per pixel in the current format. - * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) - * @dcfg_imode: Configuration of the input of the DMA module - * @dctrl_dview: Configuration of the output of the DMA module - * @bits_pipeline: Configuration of the pipeline, which modules are enabled - */ -struct fmt_config { - struct isc_format *sd_format; - - u32 fourcc; - u8 bpp; - - u32 rlp_cfg_mode; - u32 dcfg_imode; - u32 dctrl_dview; - - u32 bits_pipeline; -}; - -#define HIST_ENTRIES 512 -#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) - -enum{ - HIST_INIT = 0, - HIST_ENABLED, - HIST_DISABLED, -}; - -struct isc_ctrls { - struct v4l2_ctrl_handler handler; - - u32 brightness; - u32 contrast; - u8 gamma_index; -#define ISC_WB_NONE 0 -#define ISC_WB_AUTO 1 -#define ISC_WB_ONETIME 2 - u8 awb; - - /* one for each component : GR, R, GB, B */ - u32 gain[HIST_BAYER]; - u32 offset[HIST_BAYER]; - - u32 hist_entry[HIST_ENTRIES]; - u32 hist_count[HIST_BAYER]; - u8 hist_id; - u8 hist_stat; -#define HIST_MIN_INDEX 0 -#define HIST_MAX_INDEX 1 - u32 hist_minmax[HIST_BAYER][2]; -}; - -#define ISC_PIPE_LINE_NODE_NUM 11 - -struct isc_device { - struct regmap *regmap; - struct clk *hclock; - struct clk *ispck; - struct isc_clk isc_clks[2]; - - struct device *dev; - struct v4l2_device v4l2_dev; - struct video_device video_dev; - - struct vb2_queue vb2_vidq; - spinlock_t dma_queue_lock; - struct list_head dma_queue; - struct isc_buffer *cur_frm; - unsigned int sequence; - bool stop; - struct completion comp; - - struct v4l2_format fmt; - struct isc_format **user_formats; - unsigned int num_user_formats; - - struct fmt_config config; - struct fmt_config try_config; - - struct isc_ctrls ctrls; - struct v4l2_ctrl *do_wb_ctrl; - struct work_struct awb_work; - - struct mutex lock; - spinlock_t awb_lock; - - struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; - - struct isc_subdev_entity *current_subdev; - struct list_head subdev_entities; -}; - -/* This is a list of the formats that the ISC can *output* */ -static struct isc_format controller_formats[] = { - { - .fourcc = V4L2_PIX_FMT_ARGB444, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - }, - { - .fourcc = V4L2_PIX_FMT_ABGR32, - }, - { - .fourcc = V4L2_PIX_FMT_XBGR32, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - }, - { - .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { - .fourcc = V4L2_PIX_FMT_GREY, - }, -}; - -/* This is a list of formats that the ISC can receive as *input* */ -static struct isc_format formats_list[] = { - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_GBGB, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_GRGR, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_GBGB, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_GRGR, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_GBGB, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_GRGR, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, - .cfa_baycfg = ISC_BAY_CFG_RGRG, - }, - { - .fourcc = V4L2_PIX_FMT_GREY, - .mbus_code = MEDIA_BUS_FMT_Y8_1X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - }, -}; - -#define GAMMA_MAX 2 -#define GAMMA_ENTRIES 64 - -/* Gamma table with gamma 1/2.2 */ -static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { - /* 0 --> gamma 1/1.8 */ - { 0x65, 0x66002F, 0x950025, 0xBB0020, 0xDB001D, 0xF8001A, - 0x1130018, 0x12B0017, 0x1420016, 0x1580014, 0x16D0013, 0x1810012, - 0x1940012, 0x1A60012, 0x1B80011, 0x1C90010, 0x1DA0010, 0x1EA000F, - 0x1FA000F, 0x209000F, 0x218000F, 0x227000E, 0x235000E, 0x243000E, - 0x251000E, 0x25F000D, 0x26C000D, 0x279000D, 0x286000D, 0x293000C, - 0x2A0000C, 0x2AC000C, 0x2B8000C, 0x2C4000C, 0x2D0000B, 0x2DC000B, - 0x2E7000B, 0x2F3000B, 0x2FE000B, 0x309000B, 0x314000B, 0x31F000A, - 0x32A000A, 0x334000B, 0x33F000A, 0x349000A, 0x354000A, 0x35E000A, - 0x368000A, 0x372000A, 0x37C000A, 0x386000A, 0x3900009, 0x399000A, - 0x3A30009, 0x3AD0009, 0x3B60009, 0x3BF000A, 0x3C90009, 0x3D20009, - 0x3DB0009, 0x3E40009, 0x3ED0009, 0x3F60009 }, - - /* 1 --> gamma 1/2 */ - { 0x7F, 0x800034, 0xB50028, 0xDE0021, 0x100001E, 0x11E001B, - 0x1390019, 0x1520017, 0x16A0015, 0x1800014, 0x1940014, 0x1A80013, - 0x1BB0012, 0x1CD0011, 0x1DF0010, 0x1EF0010, 0x200000F, 0x20F000F, - 0x21F000E, 0x22D000F, 0x23C000E, 0x24A000E, 0x258000D, 0x265000D, - 0x273000C, 0x27F000D, 0x28C000C, 0x299000C, 0x2A5000C, 0x2B1000B, - 0x2BC000C, 0x2C8000B, 0x2D3000C, 0x2DF000B, 0x2EA000A, 0x2F5000A, - 0x2FF000B, 0x30A000A, 0x314000B, 0x31F000A, 0x329000A, 0x333000A, - 0x33D0009, 0x3470009, 0x350000A, 0x35A0009, 0x363000A, 0x36D0009, - 0x3760009, 0x37F0009, 0x3880009, 0x3910009, 0x39A0009, 0x3A30009, - 0x3AC0008, 0x3B40009, 0x3BD0008, 0x3C60008, 0x3CE0008, 0x3D60009, - 0x3DF0008, 0x3E70008, 0x3EF0008, 0x3F70008 }, - - /* 2 --> gamma 1/2.2 */ - { 0x99, 0x9B0038, 0xD4002A, 0xFF0023, 0x122001F, 0x141001B, - 0x15D0019, 0x1760017, 0x18E0015, 0x1A30015, 0x1B80013, 0x1CC0012, - 0x1DE0011, 0x1F00010, 0x2010010, 0x2110010, 0x221000F, 0x230000F, - 0x23F000E, 0x24D000E, 0x25B000D, 0x269000C, 0x276000C, 0x283000C, - 0x28F000C, 0x29B000C, 0x2A7000C, 0x2B3000B, 0x2BF000B, 0x2CA000B, - 0x2D5000B, 0x2E0000A, 0x2EB000A, 0x2F5000A, 0x2FF000A, 0x30A000A, - 0x3140009, 0x31E0009, 0x327000A, 0x3310009, 0x33A0009, 0x3440009, - 0x34D0009, 0x3560009, 0x35F0009, 0x3680008, 0x3710008, 0x3790009, - 0x3820008, 0x38A0008, 0x3930008, 0x39B0008, 0x3A30008, 0x3AB0008, - 0x3B30008, 0x3BB0008, 0x3C30008, 0x3CB0007, 0x3D20008, 0x3DA0007, - 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, -}; - -#define ISC_IS_FORMAT_RAW(mbus_code) \ - (((mbus_code) & 0xf000) == 0x3000) - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); - -static unsigned int sensor_preferred = 1; -module_param(sensor_preferred, uint, 0644); -MODULE_PARM_DESC(sensor_preferred, - "Sensor is preferred to output the specified format (1-on 0-off), default 1"); - -static inline void isc_update_awb_ctrls(struct isc_device *isc) -{ - struct isc_ctrls *ctrls = &isc->ctrls; - - regmap_write(isc->regmap, ISC_WB_O_RGR, - (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_R])) | - ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GR]) << 16)); - regmap_write(isc->regmap, ISC_WB_O_BGB, - (ISC_WB_O_ZERO_VAL - (ctrls->offset[ISC_HIS_CFG_MODE_B])) | - ((ISC_WB_O_ZERO_VAL - ctrls->offset[ISC_HIS_CFG_MODE_GB]) << 16)); - regmap_write(isc->regmap, ISC_WB_G_RGR, - ctrls->gain[ISC_HIS_CFG_MODE_R] | - (ctrls->gain[ISC_HIS_CFG_MODE_GR] << 16)); - regmap_write(isc->regmap, ISC_WB_G_BGB, - ctrls->gain[ISC_HIS_CFG_MODE_B] | - (ctrls->gain[ISC_HIS_CFG_MODE_GB] << 16)); -} - -static inline void isc_reset_awb_ctrls(struct isc_device *isc) -{ - int c; - - for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { - /* gains have a fixed point at 9 decimals */ - isc->ctrls.gain[c] = 1 << 9; - /* offsets are in 2's complements, the value - * will be substracted from ISC_WB_O_ZERO_VAL to obtain - * 2's complement of a value between 0 and - * ISC_WB_O_ZERO_VAL >> 1 - */ - isc->ctrls.offset[c] = ISC_WB_O_ZERO_VAL; - } -} - -static int isc_wait_clk_stable(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - struct regmap *regmap = isc_clk->regmap; - unsigned long timeout = jiffies + usecs_to_jiffies(1000); - unsigned int status; - - while (time_before(jiffies, timeout)) { - regmap_read(regmap, ISC_CLKSR, &status); - if (!(status & ISC_CLKSR_SIP)) - return 0; - - usleep_range(10, 250); - } - - return -ETIMEDOUT; -} - -static int isc_clk_prepare(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_get_sync(isc_clk->dev); - - return isc_wait_clk_stable(hw); -} - -static void isc_clk_unprepare(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - isc_wait_clk_stable(hw); - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_put_sync(isc_clk->dev); -} - -static int isc_clk_enable(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 id = isc_clk->id; - struct regmap *regmap = isc_clk->regmap; - unsigned long flags; - unsigned int status; - - dev_dbg(isc_clk->dev, "ISC CLK: %s, div = %d, parent id = %d\n", - __func__, isc_clk->div, isc_clk->parent_id); - - spin_lock_irqsave(&isc_clk->lock, flags); - regmap_update_bits(regmap, ISC_CLKCFG, - ISC_CLKCFG_DIV_MASK(id) | ISC_CLKCFG_SEL_MASK(id), - (isc_clk->div << ISC_CLKCFG_DIV_SHIFT(id)) | - (isc_clk->parent_id << ISC_CLKCFG_SEL_SHIFT(id))); - - regmap_write(regmap, ISC_CLKEN, ISC_CLK(id)); - spin_unlock_irqrestore(&isc_clk->lock, flags); - - regmap_read(regmap, ISC_CLKSR, &status); - if (status & ISC_CLK(id)) - return 0; - else - return -EINVAL; -} - -static void isc_clk_disable(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 id = isc_clk->id; - unsigned long flags; - - spin_lock_irqsave(&isc_clk->lock, flags); - regmap_write(isc_clk->regmap, ISC_CLKDIS, ISC_CLK(id)); - spin_unlock_irqrestore(&isc_clk->lock, flags); -} - -static int isc_clk_is_enabled(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 status; - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_get_sync(isc_clk->dev); - - regmap_read(isc_clk->regmap, ISC_CLKSR, &status); - - if (isc_clk->id == ISC_ISPCK) - pm_runtime_put_sync(isc_clk->dev); - - return status & ISC_CLK(isc_clk->id) ? 1 : 0; -} - -static unsigned long -isc_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - return DIV_ROUND_CLOSEST(parent_rate, isc_clk->div + 1); -} - -static int isc_clk_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - long best_rate = -EINVAL; - int best_diff = -1; - unsigned int i, div; - - for (i = 0; i < clk_hw_get_num_parents(hw); i++) { - struct clk_hw *parent; - unsigned long parent_rate; - - parent = clk_hw_get_parent_by_index(hw, i); - if (!parent) - continue; - - parent_rate = clk_hw_get_rate(parent); - if (!parent_rate) - continue; - - for (div = 1; div < ISC_CLK_MAX_DIV + 2; div++) { - unsigned long rate; - int diff; - - rate = DIV_ROUND_CLOSEST(parent_rate, div); - diff = abs(req->rate - rate); - - if (best_diff < 0 || best_diff > diff) { - best_rate = rate; - best_diff = diff; - req->best_parent_rate = parent_rate; - req->best_parent_hw = parent; - } - - if (!best_diff || rate < req->rate) - break; - } - - if (!best_diff) - break; - } - - dev_dbg(isc_clk->dev, - "ISC CLK: %s, best_rate = %ld, parent clk: %s @ %ld\n", - __func__, best_rate, - __clk_get_name((req->best_parent_hw)->clk), - req->best_parent_rate); - - if (best_rate < 0) - return best_rate; - - req->rate = best_rate; - - return 0; -} - -static int isc_clk_set_parent(struct clk_hw *hw, u8 index) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - if (index >= clk_hw_get_num_parents(hw)) - return -EINVAL; - - isc_clk->parent_id = index; - - return 0; -} - -static u8 isc_clk_get_parent(struct clk_hw *hw) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - - return isc_clk->parent_id; -} - -static int isc_clk_set_rate(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate) -{ - struct isc_clk *isc_clk = to_isc_clk(hw); - u32 div; - - if (!rate) - return -EINVAL; - - div = DIV_ROUND_CLOSEST(parent_rate, rate); - if (div > (ISC_CLK_MAX_DIV + 1) || !div) - return -EINVAL; - - isc_clk->div = div - 1; - - return 0; -} - -static const struct clk_ops isc_clk_ops = { - .prepare = isc_clk_prepare, - .unprepare = isc_clk_unprepare, - .enable = isc_clk_enable, - .disable = isc_clk_disable, - .is_enabled = isc_clk_is_enabled, - .recalc_rate = isc_clk_recalc_rate, - .determine_rate = isc_clk_determine_rate, - .set_parent = isc_clk_set_parent, - .get_parent = isc_clk_get_parent, - .set_rate = isc_clk_set_rate, -}; - -static int isc_clk_register(struct isc_device *isc, unsigned int id) -{ - struct regmap *regmap = isc->regmap; - struct device_node *np = isc->dev->of_node; - struct isc_clk *isc_clk; - struct clk_init_data init; - const char *clk_name = np->name; - const char *parent_names[3]; - int num_parents; - - num_parents = of_clk_get_parent_count(np); - if (num_parents < 1 || num_parents > 3) - return -EINVAL; - - if (num_parents > 2 && id == ISC_ISPCK) - num_parents = 2; - - of_clk_parent_fill(np, parent_names, num_parents); - - if (id == ISC_MCK) - of_property_read_string(np, "clock-output-names", &clk_name); - else - clk_name = "isc-ispck"; - - init.parent_names = parent_names; - init.num_parents = num_parents; - init.name = clk_name; - init.ops = &isc_clk_ops; - init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; - - isc_clk = &isc->isc_clks[id]; - isc_clk->hw.init = &init; - isc_clk->regmap = regmap; - isc_clk->id = id; - isc_clk->dev = isc->dev; - spin_lock_init(&isc_clk->lock); - - isc_clk->clk = clk_register(isc->dev, &isc_clk->hw); - if (IS_ERR(isc_clk->clk)) { - dev_err(isc->dev, "%s: clock register fail\n", clk_name); - return PTR_ERR(isc_clk->clk); - } else if (id == ISC_MCK) - of_clk_add_provider(np, of_clk_src_simple_get, isc_clk->clk); - - return 0; -} - -static int isc_clk_init(struct isc_device *isc) -{ - unsigned int i; - int ret; - - for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) - isc->isc_clks[i].clk = ERR_PTR(-EINVAL); - - for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { - ret = isc_clk_register(isc, i); - if (ret) - return ret; - } - - return 0; -} - -static void isc_clk_cleanup(struct isc_device *isc) -{ - unsigned int i; - - of_clk_del_provider(isc->dev->of_node); - - for (i = 0; i < ARRAY_SIZE(isc->isc_clks); i++) { - struct isc_clk *isc_clk = &isc->isc_clks[i]; - - if (!IS_ERR(isc_clk->clk)) - clk_unregister(isc_clk->clk); - } -} - -static int isc_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, unsigned int *nplanes, - unsigned int sizes[], struct device *alloc_devs[]) -{ - struct isc_device *isc = vb2_get_drv_priv(vq); - unsigned int size = isc->fmt.fmt.pix.sizeimage; - - if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = size; - - return 0; -} - -static int isc_buffer_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = isc->fmt.fmt.pix.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - v4l2_err(&isc->v4l2_dev, "buffer too small (%lu < %lu)\n", - vb2_plane_size(vb, 0), size); - return -EINVAL; - } - - vb2_set_plane_payload(vb, 0, size); - - vbuf->field = isc->fmt.fmt.pix.field; - - return 0; -} - -static void isc_start_dma(struct isc_device *isc) -{ - struct regmap *regmap = isc->regmap; - u32 sizeimage = isc->fmt.fmt.pix.sizeimage; - u32 dctrl_dview; - dma_addr_t addr0; - u32 h, w; - - h = isc->fmt.fmt.pix.height; - w = isc->fmt.fmt.pix.width; - - /* - * In case the sensor is not RAW, it will output a pixel (12-16 bits) - * with two samples on the ISC Data bus (which is 8-12) - * ISC will count each sample, so, we need to multiply these values - * by two, to get the real number of samples for the required pixels. - */ - if (!ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) { - h <<= 1; - w <<= 1; - } - - /* - * We limit the column/row count that the ISC will output according - * to the configured resolution that we want. - * This will avoid the situation where the sensor is misconfigured, - * sending more data, and the ISC will just take it and DMA to memory, - * causing corruption. - */ - regmap_write(regmap, ISC_PFE_CFG1, - (ISC_PFE_CFG1_COLMIN(0) & ISC_PFE_CFG1_COLMIN_MASK) | - (ISC_PFE_CFG1_COLMAX(w - 1) & ISC_PFE_CFG1_COLMAX_MASK)); - - regmap_write(regmap, ISC_PFE_CFG2, - (ISC_PFE_CFG2_ROWMIN(0) & ISC_PFE_CFG2_ROWMIN_MASK) | - (ISC_PFE_CFG2_ROWMAX(h - 1) & ISC_PFE_CFG2_ROWMAX_MASK)); - - regmap_update_bits(regmap, ISC_PFE_CFG0, - ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN, - ISC_PFE_CFG0_COLEN | ISC_PFE_CFG0_ROWEN); - - addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); - regmap_write(regmap, ISC_DAD0, addr0); - - switch (isc->config.fourcc) { - case V4L2_PIX_FMT_YUV420: - regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); - regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); - break; - case V4L2_PIX_FMT_YUV422P: - regmap_write(regmap, ISC_DAD1, addr0 + sizeimage / 2); - regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 3) / 4); - break; - default: - break; - } - - dctrl_dview = isc->config.dctrl_dview; - - regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); - spin_lock(&isc->awb_lock); - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); - spin_unlock(&isc->awb_lock); -} - -static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) -{ - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - u32 val, bay_cfg; - const u32 *gamma; - unsigned int i; - - /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ - for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { - val = pipeline & BIT(i) ? 1 : 0; - regmap_field_write(isc->pipeline[i], val); - } - - if (!pipeline) - return; - - bay_cfg = isc->config.sd_format->cfa_baycfg; - - if (ctrls->awb == ISC_WB_NONE) - isc_reset_awb_ctrls(isc); - - regmap_write(regmap, ISC_WB_CFG, bay_cfg); - isc_update_awb_ctrls(isc); - - regmap_write(regmap, ISC_CFA_CFG, bay_cfg | ISC_CFA_CFG_EITPOL); - - gamma = &isc_gamma_table[ctrls->gamma_index][0]; - regmap_bulk_write(regmap, ISC_GAM_BENTRY, gamma, GAMMA_ENTRIES); - regmap_bulk_write(regmap, ISC_GAM_GENTRY, gamma, GAMMA_ENTRIES); - regmap_bulk_write(regmap, ISC_GAM_RENTRY, gamma, GAMMA_ENTRIES); - - /* Convert RGB to YUV */ - regmap_write(regmap, ISC_CSC_YR_YG, 0x42 | (0x81 << 16)); - regmap_write(regmap, ISC_CSC_YB_OY, 0x19 | (0x10 << 16)); - regmap_write(regmap, ISC_CSC_CBR_CBG, 0xFDA | (0xFB6 << 16)); - regmap_write(regmap, ISC_CSC_CBB_OCB, 0x70 | (0x80 << 16)); - regmap_write(regmap, ISC_CSC_CRR_CRG, 0x70 | (0xFA2 << 16)); - regmap_write(regmap, ISC_CSC_CRB_OCR, 0xFEE | (0x80 << 16)); - - regmap_write(regmap, ISC_CBC_BRIGHT, ctrls->brightness); - regmap_write(regmap, ISC_CBC_CONTRAST, ctrls->contrast); -} - -static int isc_update_profile(struct isc_device *isc) -{ - struct regmap *regmap = isc->regmap; - u32 sr; - int counter = 100; - - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_UPPRO); - - regmap_read(regmap, ISC_CTRLSR, &sr); - while ((sr & ISC_CTRL_UPPRO) && counter--) { - usleep_range(1000, 2000); - regmap_read(regmap, ISC_CTRLSR, &sr); - } - - if (counter < 0) { - v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n"); - return -ETIMEDOUT; - } - - return 0; -} - -static void isc_set_histogram(struct isc_device *isc, bool enable) -{ - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - - if (enable) { - regmap_write(regmap, ISC_HIS_CFG, - ISC_HIS_CFG_MODE_GR | - (isc->config.sd_format->cfa_baycfg - << ISC_HIS_CFG_BAYSEL_SHIFT) | - ISC_HIS_CFG_RAR); - regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); - regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); - ctrls->hist_id = ISC_HIS_CFG_MODE_GR; - isc_update_profile(isc); - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); - - ctrls->hist_stat = HIST_ENABLED; - } else { - regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); - regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); - - ctrls->hist_stat = HIST_DISABLED; - } -} - -static int isc_configure(struct isc_device *isc) -{ - struct regmap *regmap = isc->regmap; - u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; - struct isc_subdev_entity *subdev = isc->current_subdev; - - pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; - rlp_mode = isc->config.rlp_cfg_mode; - pipeline = isc->config.bits_pipeline; - - dcfg = isc->config.dcfg_imode | - ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; - - pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; - mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | - ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | - ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | - ISC_PFE_CFG0_CCIR656; - - regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); - - regmap_update_bits(regmap, ISC_RLP_CFG, ISC_RLP_CFG_MODE_MASK, - rlp_mode); - - regmap_write(regmap, ISC_DCFG, dcfg); - - /* Set the pipeline */ - isc_set_pipeline(isc, pipeline); - - /* - * The current implemented histogram is available for RAW R, B, GB, GR - * channels. We need to check if sensor is outputting RAW BAYER - */ - if (isc->ctrls.awb && - ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) - isc_set_histogram(isc, true); - else - isc_set_histogram(isc, false); - - /* Update profile */ - return isc_update_profile(isc); -} - -static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct isc_device *isc = vb2_get_drv_priv(vq); - struct regmap *regmap = isc->regmap; - struct isc_buffer *buf; - unsigned long flags; - int ret; - - /* Enable stream on the sub device */ - ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", - ret); - goto err_start_stream; - } - - pm_runtime_get_sync(isc->dev); - - ret = isc_configure(isc); - if (unlikely(ret)) - goto err_configure; - - /* Enable DMA interrupt */ - regmap_write(regmap, ISC_INTEN, ISC_INT_DDONE); - - spin_lock_irqsave(&isc->dma_queue_lock, flags); - - isc->sequence = 0; - isc->stop = false; - reinit_completion(&isc->comp); - - isc->cur_frm = list_first_entry(&isc->dma_queue, - struct isc_buffer, list); - list_del(&isc->cur_frm->list); - - isc_start_dma(isc); - - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); - - /* if we streaming from RAW, we can do one-shot white balance adj */ - if (ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) - v4l2_ctrl_activate(isc->do_wb_ctrl, true); - - return 0; - -err_configure: - pm_runtime_put_sync(isc->dev); - - v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); - -err_start_stream: - spin_lock_irqsave(&isc->dma_queue_lock, flags); - list_for_each_entry(buf, &isc->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); - INIT_LIST_HEAD(&isc->dma_queue); - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); - - return ret; -} - -static void isc_stop_streaming(struct vb2_queue *vq) -{ - struct isc_device *isc = vb2_get_drv_priv(vq); - unsigned long flags; - struct isc_buffer *buf; - int ret; - - v4l2_ctrl_activate(isc->do_wb_ctrl, false); - - isc->stop = true; - - /* Wait until the end of the current frame */ - if (isc->cur_frm && !wait_for_completion_timeout(&isc->comp, 5 * HZ)) - v4l2_err(&isc->v4l2_dev, - "Timeout waiting for end of the capture\n"); - - /* Disable DMA interrupt */ - regmap_write(isc->regmap, ISC_INTDIS, ISC_INT_DDONE); - - pm_runtime_put_sync(isc->dev); - - /* Disable stream on the sub device */ - ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 0); - if (ret && ret != -ENOIOCTLCMD) - v4l2_err(&isc->v4l2_dev, "stream off failed in subdev\n"); - - /* Release all active buffers */ - spin_lock_irqsave(&isc->dma_queue_lock, flags); - if (unlikely(isc->cur_frm)) { - vb2_buffer_done(&isc->cur_frm->vb.vb2_buf, - VB2_BUF_STATE_ERROR); - isc->cur_frm = NULL; - } - list_for_each_entry(buf, &isc->dma_queue, list) - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - INIT_LIST_HEAD(&isc->dma_queue); - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); -} - -static void isc_buffer_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct isc_buffer *buf = container_of(vbuf, struct isc_buffer, vb); - struct isc_device *isc = vb2_get_drv_priv(vb->vb2_queue); - unsigned long flags; - - spin_lock_irqsave(&isc->dma_queue_lock, flags); - if (!isc->cur_frm && list_empty(&isc->dma_queue) && - vb2_is_streaming(vb->vb2_queue)) { - isc->cur_frm = buf; - isc_start_dma(isc); - } else - list_add_tail(&buf->list, &isc->dma_queue); - spin_unlock_irqrestore(&isc->dma_queue_lock, flags); -} - -static struct isc_format *find_format_by_fourcc(struct isc_device *isc, - unsigned int fourcc) -{ - unsigned int num_formats = isc->num_user_formats; - struct isc_format *fmt; - unsigned int i; - - for (i = 0; i < num_formats; i++) { - fmt = isc->user_formats[i]; - if (fmt->fourcc == fourcc) - return fmt; - } - - return NULL; -} - -static const struct vb2_ops isc_vb2_ops = { - .queue_setup = isc_queue_setup, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_prepare = isc_buffer_prepare, - .start_streaming = isc_start_streaming, - .stop_streaming = isc_stop_streaming, - .buf_queue = isc_buffer_queue, -}; - -static int isc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct isc_device *isc = video_drvdata(file); - - strscpy(cap->driver, ATMEL_ISC_NAME, sizeof(cap->driver)); - strscpy(cap->card, "Atmel Image Sensor Controller", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", isc->v4l2_dev.name); - - return 0; -} - -static int isc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - u32 index = f->index; - u32 i, supported_index; - - if (index < ARRAY_SIZE(controller_formats)) { - f->pixelformat = controller_formats[index].fourcc; - return 0; - } - - index -= ARRAY_SIZE(controller_formats); - - i = 0; - supported_index = 0; - - for (i = 0; i < ARRAY_SIZE(formats_list); i++) { - if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) || - !formats_list[i].sd_support) - continue; - if (supported_index == index) { - f->pixelformat = formats_list[i].fourcc; - return 0; - } - supported_index++; - } - - return -EINVAL; -} - -static int isc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct isc_device *isc = video_drvdata(file); - - *fmt = isc->fmt; - - return 0; -} - -/* - * Checks the current configured format, if ISC can output it, - * considering which type of format the ISC receives from the sensor - */ -static int isc_try_validate_formats(struct isc_device *isc) -{ - int ret; - bool bayer = false, yuv = false, rgb = false, grey = false; - - /* all formats supported by the RLP module are OK */ - switch (isc->try_config.fourcc) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - ret = 0; - bayer = true; - break; - - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YUV422P: - case V4L2_PIX_FMT_YUYV: - ret = 0; - yuv = true; - break; - - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_ABGR32: - case V4L2_PIX_FMT_XBGR32: - case V4L2_PIX_FMT_ARGB444: - case V4L2_PIX_FMT_ARGB555: - ret = 0; - rgb = true; - break; - case V4L2_PIX_FMT_GREY: - ret = 0; - grey = true; - break; - default: - /* any other different formats are not supported */ - ret = -EINVAL; - } - - /* we cannot output RAW/Grey if we do not receive RAW */ - if ((bayer || grey) && - !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) - return -EINVAL; - - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", - rgb, yuv, grey, bayer); - - return ret; -} - -/* - * Configures the RLP and DMA modules, depending on the output format - * configured for the ISC. - * If direct_dump == true, just dump raw data 8 bits. - */ -static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) -{ - if (direct_dump) { - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - return 0; - } - - switch (isc->try_config.fourcc) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 8; - break; - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_RGB565: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_ARGB444: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_ARGB555: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_ABGR32: - case V4L2_PIX_FMT_XBGR32: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 32; - break; - case V4L2_PIX_FMT_YUV420: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; - isc->try_config.bpp = 12; - break; - case V4L2_PIX_FMT_YUV422P: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_YUYV: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 16; - break; - case V4L2_PIX_FMT_GREY: - isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; - isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; - isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - isc->try_config.bpp = 8; - break; - default: - return -EINVAL; - } - return 0; -} - -/* - * Configuring pipeline modules, depending on which format the ISC outputs - * and considering which format it has as input from the sensor. - */ -static int isc_try_configure_pipeline(struct isc_device *isc) -{ - switch (isc->try_config.fourcc) { - case V4L2_PIX_FMT_RGB565: - case V4L2_PIX_FMT_ARGB555: - case V4L2_PIX_FMT_ARGB444: - case V4L2_PIX_FMT_ABGR32: - case V4L2_PIX_FMT_XBGR32: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - WB_ENABLE | GAM_ENABLES; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_YUV420: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_YUV422P: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - SUB422_ENABLE | CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_YUYV: - /* if sensor format is RAW, we convert inside ISC */ - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - SUB422_ENABLE | CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - case V4L2_PIX_FMT_GREY: - if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { - /* if sensor format is RAW, we convert inside ISC */ - isc->try_config.bits_pipeline = CFA_ENABLE | - CSC_ENABLE | WB_ENABLE | GAM_ENABLES | - CBC_ENABLE; - } else { - isc->try_config.bits_pipeline = 0x0; - } - break; - default: - isc->try_config.bits_pipeline = 0x0; - } - return 0; -} - -static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, - u32 *code) -{ - int i; - struct isc_format *sd_fmt = NULL, *direct_fmt = NULL; - struct v4l2_pix_format *pixfmt = &f->fmt.pix; - struct v4l2_subdev_pad_config pad_cfg; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_TRY, - }; - u32 mbus_code; - int ret; - bool rlp_dma_direct_dump = false; - - if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - /* Step 1: find a RAW format that is supported */ - for (i = 0; i < isc->num_user_formats; i++) { - if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) { - sd_fmt = isc->user_formats[i]; - break; - } - } - /* Step 2: We can continue with this RAW format, or we can look - * for better: maybe sensor supports directly what we need. - */ - direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); - - /* Step 3: We have both. We decide given the module parameter which - * one to use. - */ - if (direct_fmt && sd_fmt && sensor_preferred) - sd_fmt = direct_fmt; - - /* Step 4: we do not have RAW but we have a direct format. Use it. */ - if (direct_fmt && !sd_fmt) - sd_fmt = direct_fmt; - - /* Step 5: if we are using a direct format, we need to package - * everything as 8 bit data and just dump it - */ - if (sd_fmt == direct_fmt) - rlp_dma_direct_dump = true; - - /* Step 6: We have no format. This can happen if the userspace - * requests some weird/invalid format. - * In this case, default to whatever we have - */ - if (!sd_fmt && !direct_fmt) { - sd_fmt = isc->user_formats[isc->num_user_formats - 1]; - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Sensor not supporting %.4s, using %.4s\n", - (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc); - } - - if (!sd_fmt) { - ret = -EINVAL; - goto isc_try_fmt_err; - } - - /* Step 7: Print out what we decided for debugging */ - v4l2_dbg(1, debug, &isc->v4l2_dev, - "Preferring to have sensor using format %.4s\n", - (char *)&sd_fmt->fourcc); - - /* Step 8: at this moment we decided which format the subdev will use */ - isc->try_config.sd_format = sd_fmt; - - /* Limit to Atmel ISC hardware capabilities */ - if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) - pixfmt->width = ISC_MAX_SUPPORT_WIDTH; - if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) - pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; - - /* - * The mbus format is the one the subdev outputs. - * The pixels will be transferred in this format Sensor -> ISC - */ - mbus_code = sd_fmt->mbus_code; - - /* - * Validate formats. If the required format is not OK, default to raw. - */ - - isc->try_config.fourcc = pixfmt->pixelformat; - - if (isc_try_validate_formats(isc)) { - pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc; - /* Re-try to validate the new format */ - ret = isc_try_validate_formats(isc); - if (ret) - goto isc_try_fmt_err; - } - - ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump); - if (ret) - goto isc_try_fmt_err; - - ret = isc_try_configure_pipeline(isc); - if (ret) - goto isc_try_fmt_err; - - v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, - &pad_cfg, &format); - if (ret < 0) - goto isc_try_fmt_subdev_err; - - v4l2_fill_pix_format(pixfmt, &format.format); - - pixfmt->field = V4L2_FIELD_NONE; - pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3; - pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - - if (code) - *code = mbus_code; - - return 0; - -isc_try_fmt_err: - v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); -isc_try_fmt_subdev_err: - memset(&isc->try_config, 0, sizeof(isc->try_config)); - - return ret; -} - -static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) -{ - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - u32 mbus_code = 0; - int ret; - - ret = isc_try_fmt(isc, f, &mbus_code); - if (ret) - return ret; - - v4l2_fill_mbus_format(&format.format, &f->fmt.pix, mbus_code); - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, - set_fmt, NULL, &format); - if (ret < 0) - return ret; - - isc->fmt = *f; - - if (isc->try_config.sd_format && isc->config.sd_format && - isc->try_config.sd_format != isc->config.sd_format) { - isc->ctrls.hist_stat = HIST_INIT; - isc_reset_awb_ctrls(isc); - } - /* make the try configuration active */ - isc->config = isc->try_config; - - v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); - - return 0; -} - -static int isc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct isc_device *isc = video_drvdata(file); - - if (vb2_is_streaming(&isc->vb2_vidq)) - return -EBUSY; - - return isc_set_fmt(isc, f); -} - -static int isc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct isc_device *isc = video_drvdata(file); - - return isc_try_fmt(isc, f, NULL); -} - -static int isc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - if (inp->index != 0) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = 0; - strscpy(inp->name, "Camera", sizeof(inp->name)); - - return 0; -} - -static int isc_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - - return 0; -} - -static int isc_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i > 0) - return -EINVAL; - - return 0; -} - -static int isc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct isc_device *isc = video_drvdata(file); - - return v4l2_g_parm_cap(video_devdata(file), isc->current_subdev->sd, a); -} - -static int isc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) -{ - struct isc_device *isc = video_drvdata(file); - - return v4l2_s_parm_cap(video_devdata(file), isc->current_subdev->sd, a); -} - -static int isc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev_frame_size_enum fse = { - .index = fsize->index, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - int ret = -EINVAL; - int i; - - for (i = 0; i < isc->num_user_formats; i++) - if (isc->user_formats[i]->fourcc == fsize->pixel_format) - ret = 0; - - for (i = 0; i < ARRAY_SIZE(controller_formats); i++) - if (controller_formats[i].fourcc == fsize->pixel_format) - ret = 0; - - if (ret) - return ret; - - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, - NULL, &fse); - if (ret) - return ret; - - fse.code = isc->config.sd_format->mbus_code; - - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = fse.max_width; - fsize->discrete.height = fse.max_height; - - return 0; -} - -static int isc_enum_frameintervals(struct file *file, void *fh, - struct v4l2_frmivalenum *fival) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev_frame_interval_enum fie = { - .index = fival->index, - .width = fival->width, - .height = fival->height, - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - int ret = -EINVAL; - int i; - - for (i = 0; i < isc->num_user_formats; i++) - if (isc->user_formats[i]->fourcc == fival->pixel_format) - ret = 0; - - for (i = 0; i < ARRAY_SIZE(controller_formats); i++) - if (controller_formats[i].fourcc == fival->pixel_format) - ret = 0; - - if (ret) - return ret; - - ret = v4l2_subdev_call(isc->current_subdev->sd, pad, - enum_frame_interval, NULL, &fie); - if (ret) - return ret; - - fie.code = isc->config.sd_format->mbus_code; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = fie.interval; - - return 0; -} - -static const struct v4l2_ioctl_ops isc_ioctl_ops = { - .vidioc_querycap = isc_querycap, - .vidioc_enum_fmt_vid_cap = isc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = isc_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = isc_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = isc_try_fmt_vid_cap, - - .vidioc_enum_input = isc_enum_input, - .vidioc_g_input = isc_g_input, - .vidioc_s_input = isc_s_input, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - - .vidioc_g_parm = isc_g_parm, - .vidioc_s_parm = isc_s_parm, - .vidioc_enum_framesizes = isc_enum_framesizes, - .vidioc_enum_frameintervals = isc_enum_frameintervals, - - .vidioc_log_status = v4l2_ctrl_log_status, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static int isc_open(struct file *file) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev *sd = isc->current_subdev->sd; - int ret; - - if (mutex_lock_interruptible(&isc->lock)) - return -ERESTARTSYS; - - ret = v4l2_fh_open(file); - if (ret < 0) - goto unlock; - - if (!v4l2_fh_is_singular_file(file)) - goto unlock; - - ret = v4l2_subdev_call(sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) { - v4l2_fh_release(file); - goto unlock; - } - - ret = isc_set_fmt(isc, &isc->fmt); - if (ret) { - v4l2_subdev_call(sd, core, s_power, 0); - v4l2_fh_release(file); - } - -unlock: - mutex_unlock(&isc->lock); - return ret; -} - -static int isc_release(struct file *file) -{ - struct isc_device *isc = video_drvdata(file); - struct v4l2_subdev *sd = isc->current_subdev->sd; - bool fh_singular; - int ret; - - mutex_lock(&isc->lock); - - fh_singular = v4l2_fh_is_singular_file(file); - - ret = _vb2_fop_release(file, NULL); - - if (fh_singular) - v4l2_subdev_call(sd, core, s_power, 0); - - mutex_unlock(&isc->lock); - - return ret; -} - -static const struct v4l2_file_operations isc_fops = { - .owner = THIS_MODULE, - .open = isc_open, - .release = isc_release, - .unlocked_ioctl = video_ioctl2, - .read = vb2_fop_read, - .mmap = vb2_fop_mmap, - .poll = vb2_fop_poll, -}; - -static irqreturn_t isc_interrupt(int irq, void *dev_id) -{ - struct isc_device *isc = (struct isc_device *)dev_id; - struct regmap *regmap = isc->regmap; - u32 isc_intsr, isc_intmask, pending; - irqreturn_t ret = IRQ_NONE; - - regmap_read(regmap, ISC_INTSR, &isc_intsr); - regmap_read(regmap, ISC_INTMASK, &isc_intmask); - - pending = isc_intsr & isc_intmask; - - if (likely(pending & ISC_INT_DDONE)) { - spin_lock(&isc->dma_queue_lock); - if (isc->cur_frm) { - struct vb2_v4l2_buffer *vbuf = &isc->cur_frm->vb; - struct vb2_buffer *vb = &vbuf->vb2_buf; - - vb->timestamp = ktime_get_ns(); - vbuf->sequence = isc->sequence++; - vb2_buffer_done(vb, VB2_BUF_STATE_DONE); - isc->cur_frm = NULL; - } - - if (!list_empty(&isc->dma_queue) && !isc->stop) { - isc->cur_frm = list_first_entry(&isc->dma_queue, - struct isc_buffer, list); - list_del(&isc->cur_frm->list); - - isc_start_dma(isc); - } - - if (isc->stop) - complete(&isc->comp); - - ret = IRQ_HANDLED; - spin_unlock(&isc->dma_queue_lock); - } - - if (pending & ISC_INT_HISDONE) { - schedule_work(&isc->awb_work); - ret = IRQ_HANDLED; - } - - return ret; -} - -static void isc_hist_count(struct isc_device *isc, u32 *min, u32 *max) -{ - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - u32 *hist_count = &ctrls->hist_count[ctrls->hist_id]; - u32 *hist_entry = &ctrls->hist_entry[0]; - u32 i; - - *min = 0; - *max = HIST_ENTRIES; - - regmap_bulk_read(regmap, ISC_HIS_ENTRY, hist_entry, HIST_ENTRIES); - - *hist_count = 0; - /* - * we deliberately ignore the end of the histogram, - * the most white pixels - */ - for (i = 1; i < HIST_ENTRIES; i++) { - if (*hist_entry && !*min) - *min = i; - if (*hist_entry) - *max = i; - *hist_count += i * (*hist_entry++); - } - - if (!*min) - *min = 1; -} - -static void isc_wb_update(struct isc_ctrls *ctrls) -{ - u32 *hist_count = &ctrls->hist_count[0]; - u32 c, offset[4]; - u64 avg = 0; - /* We compute two gains, stretch gain and grey world gain */ - u32 s_gain[4], gw_gain[4]; - - /* - * According to Grey World, we need to set gains for R/B to normalize - * them towards the green channel. - * Thus we want to keep Green as fixed and adjust only Red/Blue - * Compute the average of the both green channels first - */ - avg = (u64)hist_count[ISC_HIS_CFG_MODE_GR] + - (u64)hist_count[ISC_HIS_CFG_MODE_GB]; - avg >>= 1; - - /* Green histogram is null, nothing to do */ - if (!avg) - return; - - for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { - /* - * the color offset is the minimum value of the histogram. - * we stretch this color to the full range by substracting - * this value from the color component. - */ - offset[c] = ctrls->hist_minmax[c][HIST_MIN_INDEX]; - /* - * The offset is always at least 1. If the offset is 1, we do - * not need to adjust it, so our result must be zero. - * the offset is computed in a histogram on 9 bits (0..512) - * but the offset in register is based on - * 12 bits pipeline (0..4096). - * we need to shift with the 3 bits that the histogram is - * ignoring - */ - ctrls->offset[c] = (offset[c] - 1) << 3; - - /* the offset is then taken and converted to 2's complements */ - if (!ctrls->offset[c]) - ctrls->offset[c] = ISC_WB_O_ZERO_VAL; - - /* - * the stretch gain is the total number of histogram bins - * divided by the actual range of color component (Max - Min) - * If we compute gain like this, the actual color component - * will be stretched to the full histogram. - * We need to shift 9 bits for precision, we have 9 bits for - * decimals - */ - s_gain[c] = (HIST_ENTRIES << 9) / - (ctrls->hist_minmax[c][HIST_MAX_INDEX] - - ctrls->hist_minmax[c][HIST_MIN_INDEX] + 1); - - /* - * Now we have to compute the gain w.r.t. the average. - * Add/lose gain to the component towards the average. - * If it happens that the component is zero, use the - * fixed point value : 1.0 gain. - */ - if (hist_count[c]) - gw_gain[c] = div_u64(avg << 9, hist_count[c]); - else - gw_gain[c] = 1 << 9; - - /* multiply both gains and adjust for decimals */ - ctrls->gain[c] = s_gain[c] * gw_gain[c]; - ctrls->gain[c] >>= 9; - } -} - -static void isc_awb_work(struct work_struct *w) -{ - struct isc_device *isc = - container_of(w, struct isc_device, awb_work); - struct regmap *regmap = isc->regmap; - struct isc_ctrls *ctrls = &isc->ctrls; - u32 hist_id = ctrls->hist_id; - u32 baysel; - unsigned long flags; - u32 min, max; - - /* streaming is not active anymore */ - if (isc->stop) - return; - - if (ctrls->hist_stat != HIST_ENABLED) - return; - - isc_hist_count(isc, &min, &max); - ctrls->hist_minmax[hist_id][HIST_MIN_INDEX] = min; - ctrls->hist_minmax[hist_id][HIST_MAX_INDEX] = max; - - if (hist_id != ISC_HIS_CFG_MODE_B) { - hist_id++; - } else { - isc_wb_update(ctrls); - hist_id = ISC_HIS_CFG_MODE_GR; - } - - ctrls->hist_id = hist_id; - baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; - - /* if no more auto white balance, reset controls. */ - if (ctrls->awb == ISC_WB_NONE) - isc_reset_awb_ctrls(isc); - - pm_runtime_get_sync(isc->dev); - - /* - * only update if we have all the required histograms and controls - * if awb has been disabled, we need to reset registers as well. - */ - if (hist_id == ISC_HIS_CFG_MODE_GR || ctrls->awb == ISC_WB_NONE) { - /* - * It may happen that DMA Done IRQ will trigger while we are - * updating white balance registers here. - * In that case, only parts of the controls have been updated. - * We can avoid that by locking the section. - */ - spin_lock_irqsave(&isc->awb_lock, flags); - isc_update_awb_ctrls(isc); - spin_unlock_irqrestore(&isc->awb_lock, flags); - - /* - * if we are doing just the one time white balance adjustment, - * we are basically done. - */ - if (ctrls->awb == ISC_WB_ONETIME) { - v4l2_info(&isc->v4l2_dev, - "Completed one time white-balance adjustment.\n"); - ctrls->awb = ISC_WB_NONE; - } - } - regmap_write(regmap, ISC_HIS_CFG, hist_id | baysel | ISC_HIS_CFG_RAR); - isc_update_profile(isc); - /* if awb has been disabled, we don't need to start another histogram */ - if (ctrls->awb) - regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); - - pm_runtime_put_sync(isc->dev); -} - -static int isc_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct isc_device *isc = container_of(ctrl->handler, - struct isc_device, ctrls.handler); - struct isc_ctrls *ctrls = &isc->ctrls; - - if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) - return 0; - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - ctrls->brightness = ctrl->val & ISC_CBC_BRIGHT_MASK; - break; - case V4L2_CID_CONTRAST: - ctrls->contrast = ctrl->val & ISC_CBC_CONTRAST_MASK; - break; - case V4L2_CID_GAMMA: - ctrls->gamma_index = ctrl->val; - break; - case V4L2_CID_AUTO_WHITE_BALANCE: - if (ctrl->val == 1) - ctrls->awb = ISC_WB_AUTO; - else - ctrls->awb = ISC_WB_NONE; - - /* we did not configure ISC yet */ - if (!isc->config.sd_format) - break; - - if (ctrls->hist_stat != HIST_ENABLED) - isc_reset_awb_ctrls(isc); - - if (isc->ctrls.awb == ISC_WB_AUTO && - vb2_is_streaming(&isc->vb2_vidq) && - ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) - isc_set_histogram(isc, true); - - break; - case V4L2_CID_DO_WHITE_BALANCE: - /* if AWB is enabled, do nothing */ - if (ctrls->awb == ISC_WB_AUTO) - return 0; - - ctrls->awb = ISC_WB_ONETIME; - isc_set_histogram(isc, true); - v4l2_dbg(1, debug, &isc->v4l2_dev, - "One time white-balance started.\n"); - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops isc_ctrl_ops = { - .s_ctrl = isc_s_ctrl, -}; - -static int isc_ctrl_init(struct isc_device *isc) -{ - const struct v4l2_ctrl_ops *ops = &isc_ctrl_ops; - struct isc_ctrls *ctrls = &isc->ctrls; - struct v4l2_ctrl_handler *hdl = &ctrls->handler; - int ret; - - ctrls->hist_stat = HIST_INIT; - isc_reset_awb_ctrls(isc); - - ret = v4l2_ctrl_handler_init(hdl, 5); - if (ret < 0) - return ret; - - ctrls->brightness = 0; - ctrls->contrast = 256; - - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -1024, 1023, 1, 0); - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 256); - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 2); - v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - - /* do_white_balance is a button, so min,max,step,default are ignored */ - isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, - 0, 0, 0, 0); - - v4l2_ctrl_activate(isc->do_wb_ctrl, false); - - v4l2_ctrl_handler_setup(hdl); - - return 0; -} - -static int isc_async_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct isc_device *isc = container_of(notifier->v4l2_dev, - struct isc_device, v4l2_dev); - struct isc_subdev_entity *subdev_entity = - container_of(notifier, struct isc_subdev_entity, notifier); - - if (video_is_registered(&isc->video_dev)) { - v4l2_err(&isc->v4l2_dev, "only supports one sub-device.\n"); - return -EBUSY; - } - - subdev_entity->sd = subdev; - - return 0; -} - -static void isc_async_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_subdev *asd) -{ - struct isc_device *isc = container_of(notifier->v4l2_dev, - struct isc_device, v4l2_dev); - cancel_work_sync(&isc->awb_work); - video_unregister_device(&isc->video_dev); - v4l2_ctrl_handler_free(&isc->ctrls.handler); -} - -static struct isc_format *find_format_by_code(unsigned int code, int *index) -{ - struct isc_format *fmt = &formats_list[0]; - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(formats_list); i++) { - if (fmt->mbus_code == code) { - *index = i; - return fmt; - } - - fmt++; - } - - return NULL; -} - -static int isc_formats_init(struct isc_device *isc) -{ - struct isc_format *fmt; - struct v4l2_subdev *subdev = isc->current_subdev->sd; - unsigned int num_fmts, i, j; - u32 list_size = ARRAY_SIZE(formats_list); - struct v4l2_subdev_mbus_code_enum mbus_code = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - - num_fmts = 0; - while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, - NULL, &mbus_code)) { - mbus_code.index++; - - fmt = find_format_by_code(mbus_code.code, &i); - if (!fmt) { - v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", - mbus_code.code); - continue; - } - - fmt->sd_support = true; - num_fmts++; - } - - if (!num_fmts) - return -ENXIO; - - isc->num_user_formats = num_fmts; - isc->user_formats = devm_kcalloc(isc->dev, - num_fmts, sizeof(*isc->user_formats), - GFP_KERNEL); - if (!isc->user_formats) - return -ENOMEM; - - fmt = &formats_list[0]; - for (i = 0, j = 0; i < list_size; i++) { - if (fmt->sd_support) - isc->user_formats[j++] = fmt; - fmt++; - } - - return 0; -} - -static int isc_set_default_fmt(struct isc_device *isc) -{ - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = VGA_WIDTH, - .height = VGA_HEIGHT, - .field = V4L2_FIELD_NONE, - .pixelformat = isc->user_formats[0]->fourcc, - }, - }; - int ret; - - ret = isc_try_fmt(isc, &f, NULL); - if (ret) - return ret; - - isc->fmt = f; - return 0; -} - -static int isc_async_complete(struct v4l2_async_notifier *notifier) -{ - struct isc_device *isc = container_of(notifier->v4l2_dev, - struct isc_device, v4l2_dev); - struct video_device *vdev = &isc->video_dev; - struct vb2_queue *q = &isc->vb2_vidq; - int ret; - - INIT_WORK(&isc->awb_work, isc_awb_work); - - ret = v4l2_device_register_subdev_nodes(&isc->v4l2_dev); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, "Failed to register subdev nodes\n"); - return ret; - } - - isc->current_subdev = container_of(notifier, - struct isc_subdev_entity, notifier); - mutex_init(&isc->lock); - init_completion(&isc->comp); - - /* Initialize videobuf2 queue */ - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ; - q->drv_priv = isc; - q->buf_struct_size = sizeof(struct isc_buffer); - q->ops = &isc_vb2_ops; - q->mem_ops = &vb2_dma_contig_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->lock = &isc->lock; - q->min_buffers_needed = 1; - q->dev = isc->dev; - - ret = vb2_queue_init(q); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "vb2_queue_init() failed: %d\n", ret); - return ret; - } - - /* Init video dma queues */ - INIT_LIST_HEAD(&isc->dma_queue); - spin_lock_init(&isc->dma_queue_lock); - spin_lock_init(&isc->awb_lock); - - ret = isc_formats_init(isc); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "Init format failed: %d\n", ret); - return ret; - } - - ret = isc_set_default_fmt(isc); - if (ret) { - v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); - return ret; - } - - ret = isc_ctrl_init(isc); - if (ret) { - v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); - return ret; - } - - /* Register video device */ - strscpy(vdev->name, ATMEL_ISC_NAME, sizeof(vdev->name)); - vdev->release = video_device_release_empty; - vdev->fops = &isc_fops; - vdev->ioctl_ops = &isc_ioctl_ops; - vdev->v4l2_dev = &isc->v4l2_dev; - vdev->vfl_dir = VFL_DIR_RX; - vdev->queue = q; - vdev->lock = &isc->lock; - vdev->ctrl_handler = &isc->ctrls.handler; - vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; - video_set_drvdata(vdev, isc); - - ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1); - if (ret < 0) { - v4l2_err(&isc->v4l2_dev, - "video_register_device failed: %d\n", ret); - return ret; - } - - return 0; -} - -static const struct v4l2_async_notifier_operations isc_async_ops = { - .bound = isc_async_bound, - .unbind = isc_async_unbind, - .complete = isc_async_complete, -}; - -static void isc_subdev_cleanup(struct isc_device *isc) -{ - struct isc_subdev_entity *subdev_entity; - - list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { - v4l2_async_notifier_unregister(&subdev_entity->notifier); - v4l2_async_notifier_cleanup(&subdev_entity->notifier); - } - - INIT_LIST_HEAD(&isc->subdev_entities); -} - -static int isc_pipeline_init(struct isc_device *isc) -{ - struct device *dev = isc->dev; - struct regmap *regmap = isc->regmap; - struct regmap_field *regs; - unsigned int i; - - /* WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB422-->SUB420 */ - const struct reg_field regfields[ISC_PIPE_LINE_NODE_NUM] = { - REG_FIELD(ISC_WB_CTRL, 0, 0), - REG_FIELD(ISC_CFA_CTRL, 0, 0), - REG_FIELD(ISC_CC_CTRL, 0, 0), - REG_FIELD(ISC_GAM_CTRL, 0, 0), - REG_FIELD(ISC_GAM_CTRL, 1, 1), - REG_FIELD(ISC_GAM_CTRL, 2, 2), - REG_FIELD(ISC_GAM_CTRL, 3, 3), - REG_FIELD(ISC_CSC_CTRL, 0, 0), - REG_FIELD(ISC_CBC_CTRL, 0, 0), - REG_FIELD(ISC_SUB422_CTRL, 0, 0), - REG_FIELD(ISC_SUB420_CTRL, 0, 0), - }; - - for (i = 0; i < ISC_PIPE_LINE_NODE_NUM; i++) { - regs = devm_regmap_field_alloc(dev, regmap, regfields[i]); - if (IS_ERR(regs)) - return PTR_ERR(regs); - - isc->pipeline[i] = regs; - } - - return 0; -} - -static int isc_parse_dt(struct device *dev, struct isc_device *isc) -{ - struct device_node *np = dev->of_node; - struct device_node *epn = NULL, *rem; - struct isc_subdev_entity *subdev_entity; - unsigned int flags; - int ret; - - INIT_LIST_HEAD(&isc->subdev_entities); - - while (1) { - struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; - - epn = of_graph_get_next_endpoint(np, epn); - if (!epn) - return 0; - - rem = of_graph_get_remote_port_parent(epn); - if (!rem) { - dev_notice(dev, "Remote device at %pOF not found\n", - epn); - continue; - } - - ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), - &v4l2_epn); - if (ret) { - of_node_put(rem); - ret = -EINVAL; - dev_err(dev, "Could not parse the endpoint\n"); - break; - } - - subdev_entity = devm_kzalloc(dev, - sizeof(*subdev_entity), GFP_KERNEL); - if (!subdev_entity) { - of_node_put(rem); - ret = -ENOMEM; - break; - } - - /* asd will be freed by the subsystem once it's added to the - * notifier list - */ - subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd), - GFP_KERNEL); - if (!subdev_entity->asd) { - of_node_put(rem); - ret = -ENOMEM; - break; - } - - flags = v4l2_epn.bus.parallel.flags; - - if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) - subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; - - if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; - - if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; - - if (v4l2_epn.bus_type == V4L2_MBUS_BT656) - subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | - ISC_PFE_CFG0_CCIR656; - - subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - subdev_entity->asd->match.fwnode = - of_fwnode_handle(rem); - list_add_tail(&subdev_entity->list, &isc->subdev_entities); - } - - of_node_put(epn); - return ret; -} - -/* regmap configuration */ -#define ATMEL_ISC_REG_MAX 0xbfc -static const struct regmap_config isc_regmap_config = { - .reg_bits = 32, - .reg_stride = 4, - .val_bits = 32, - .max_register = ATMEL_ISC_REG_MAX, -}; - -static int atmel_isc_probe(struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct isc_device *isc; - struct resource *res; - void __iomem *io_base; - struct isc_subdev_entity *subdev_entity; - int irq; - int ret; - - isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); - if (!isc) - return -ENOMEM; - - platform_set_drvdata(pdev, isc); - isc->dev = dev; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - io_base = devm_ioremap_resource(dev, res); - if (IS_ERR(io_base)) - return PTR_ERR(io_base); - - isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); - if (IS_ERR(isc->regmap)) { - ret = PTR_ERR(isc->regmap); - dev_err(dev, "failed to init register map: %d\n", ret); - return ret; - } - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - ret = irq; - dev_err(dev, "failed to get irq: %d\n", ret); - return ret; - } - - ret = devm_request_irq(dev, irq, isc_interrupt, 0, - ATMEL_ISC_NAME, isc); - if (ret < 0) { - dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", - irq, ret); - return ret; - } - - ret = isc_pipeline_init(isc); - if (ret) - return ret; - - isc->hclock = devm_clk_get(dev, "hclock"); - if (IS_ERR(isc->hclock)) { - ret = PTR_ERR(isc->hclock); - dev_err(dev, "failed to get hclock: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(isc->hclock); - if (ret) { - dev_err(dev, "failed to enable hclock: %d\n", ret); - return ret; - } - - ret = isc_clk_init(isc); - if (ret) { - dev_err(dev, "failed to init isc clock: %d\n", ret); - goto unprepare_hclk; - } - - isc->ispck = isc->isc_clks[ISC_ISPCK].clk; - - ret = clk_prepare_enable(isc->ispck); - if (ret) { - dev_err(dev, "failed to enable ispck: %d\n", ret); - goto unprepare_hclk; - } - - /* ispck should be greater or equal to hclock */ - ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); - if (ret) { - dev_err(dev, "failed to set ispck rate: %d\n", ret); - goto unprepare_clk; - } - - ret = v4l2_device_register(dev, &isc->v4l2_dev); - if (ret) { - dev_err(dev, "unable to register v4l2 device.\n"); - goto unprepare_clk; - } - - ret = isc_parse_dt(dev, isc); - if (ret) { - dev_err(dev, "fail to parse device tree\n"); - goto unregister_v4l2_device; - } - - if (list_empty(&isc->subdev_entities)) { - dev_err(dev, "no subdev found\n"); - ret = -ENODEV; - goto unregister_v4l2_device; - } - - list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { - v4l2_async_notifier_init(&subdev_entity->notifier); - - ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier, - subdev_entity->asd); - if (ret) { - fwnode_handle_put(subdev_entity->asd->match.fwnode); - kfree(subdev_entity->asd); - goto cleanup_subdev; - } - - subdev_entity->notifier.ops = &isc_async_ops; - - ret = v4l2_async_notifier_register(&isc->v4l2_dev, - &subdev_entity->notifier); - if (ret) { - dev_err(dev, "fail to register async notifier\n"); - goto cleanup_subdev; - } - - if (video_is_registered(&isc->video_dev)) - break; - } - - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - pm_request_idle(dev); - - return 0; - -cleanup_subdev: - isc_subdev_cleanup(isc); - -unregister_v4l2_device: - v4l2_device_unregister(&isc->v4l2_dev); - -unprepare_clk: - clk_disable_unprepare(isc->ispck); -unprepare_hclk: - clk_disable_unprepare(isc->hclock); - - isc_clk_cleanup(isc); - - return ret; -} - -static int atmel_isc_remove(struct platform_device *pdev) -{ - struct isc_device *isc = platform_get_drvdata(pdev); - - pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); - - isc_subdev_cleanup(isc); - - v4l2_device_unregister(&isc->v4l2_dev); - - isc_clk_cleanup(isc); - - return 0; -} - -static int __maybe_unused isc_runtime_suspend(struct device *dev) -{ - struct isc_device *isc = dev_get_drvdata(dev); - - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); - - return 0; -} - -static int __maybe_unused isc_runtime_resume(struct device *dev) -{ - struct isc_device *isc = dev_get_drvdata(dev); - int ret; - - ret = clk_prepare_enable(isc->hclock); - if (ret) - return ret; - - return clk_prepare_enable(isc->ispck); -} - -static const struct dev_pm_ops atmel_isc_dev_pm_ops = { - SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) -}; - -static const struct of_device_id atmel_isc_of_match[] = { - { .compatible = "atmel,sama5d2-isc" }, - { } -}; -MODULE_DEVICE_TABLE(of, atmel_isc_of_match); - -static struct platform_driver atmel_isc_driver = { - .probe = atmel_isc_probe, - .remove = atmel_isc_remove, - .driver = { - .name = ATMEL_ISC_NAME, - .pm = &atmel_isc_dev_pm_ops, - .of_match_table = of_match_ptr(atmel_isc_of_match), - }, -}; - -module_platform_driver(atmel_isc_driver); - -MODULE_AUTHOR("Songjun Wu "); -MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); -MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("video"); diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h new file mode 100644 index 000000000000..5be5b093aefb --- /dev/null +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -0,0 +1,249 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Microchip Image Sensor Controller (ISC) driver header file + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev + * + */ +#ifndef _ATMEL_ISC_H_ + +#define ISC_MAX_SUPPORT_WIDTH 2592 +#define ISC_MAX_SUPPORT_HEIGHT 1944 + +#define ISC_CLK_MAX_DIV 255 + +enum isc_clk_id { + ISC_ISPCK = 0, + ISC_MCK = 1, +}; + +struct isc_clk { + struct clk_hw hw; + struct clk *clk; + struct regmap *regmap; + spinlock_t lock; /* serialize access to clock registers */ + u8 id; + u8 parent_id; + u32 div; + struct device *dev; +}; + +#define to_isc_clk(v) container_of(v, struct isc_clk, hw) + +struct isc_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +struct isc_subdev_entity { + struct v4l2_subdev *sd; + struct v4l2_async_subdev *asd; + struct v4l2_async_notifier notifier; + + u32 pfe_cfg0; + + struct list_head list; +}; + +/* + * struct isc_format - ISC media bus format information + This structure represents the interface between the ISC + and the sensor. It's the input format received by + the ISC. + * @fourcc: Fourcc code for this format + * @mbus_code: V4L2 media bus format code. + * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. + this is either BGBG, RGRG, etc. + * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC + */ + +struct isc_format { + u32 fourcc; + u32 mbus_code; + u32 cfa_baycfg; + + bool sd_support; + u32 pfe_cfg0_bps; +}; + +/* Pipeline bitmap */ +#define WB_ENABLE BIT(0) +#define CFA_ENABLE BIT(1) +#define CC_ENABLE BIT(2) +#define GAM_ENABLE BIT(3) +#define GAM_BENABLE BIT(4) +#define GAM_GENABLE BIT(5) +#define GAM_RENABLE BIT(6) +#define CSC_ENABLE BIT(7) +#define CBC_ENABLE BIT(8) +#define SUB422_ENABLE BIT(9) +#define SUB420_ENABLE BIT(10) + +#define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) + +/* + * struct fmt_config - ISC format configuration and internal pipeline + This structure represents the internal configuration + of the ISC. + It also holds the format that ISC will present to v4l2. + * @sd_format: Pointer to an isc_format struct that holds the sensor + configuration. + * @fourcc: Fourcc code for this format. + * @bpp: Bytes per pixel in the current format. + * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) + * @dcfg_imode: Configuration of the input of the DMA module + * @dctrl_dview: Configuration of the output of the DMA module + * @bits_pipeline: Configuration of the pipeline, which modules are enabled + */ +struct fmt_config { + struct isc_format *sd_format; + + u32 fourcc; + u8 bpp; + + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; +}; + +#define HIST_ENTRIES 512 +#define HIST_BAYER (ISC_HIS_CFG_MODE_B + 1) + +enum{ + HIST_INIT = 0, + HIST_ENABLED, + HIST_DISABLED, +}; + +struct isc_ctrls { + struct v4l2_ctrl_handler handler; + + u32 brightness; + u32 contrast; + u8 gamma_index; +#define ISC_WB_NONE 0 +#define ISC_WB_AUTO 1 +#define ISC_WB_ONETIME 2 + u8 awb; + + /* one for each component : GR, R, GB, B */ + u32 gain[HIST_BAYER]; + u32 offset[HIST_BAYER]; + + u32 hist_entry[HIST_ENTRIES]; + u32 hist_count[HIST_BAYER]; + u8 hist_id; + u8 hist_stat; +#define HIST_MIN_INDEX 0 +#define HIST_MAX_INDEX 1 + u32 hist_minmax[HIST_BAYER][2]; +}; + +#define ISC_PIPE_LINE_NODE_NUM 11 + +/* + * struct isc_device - ISC device driver data/config struct + * @regmap: Register map + * @hclock: Hclock clock input (refer datasheet) + * @ispck: iscpck clock (refer datasheet) + * @isc_clks: ISC clocks + * + * @dev: Registered device driver + * @v4l2_dev: v4l2 registered device + * @video_dev: registered video device + * + * @vb2_vidq: video buffer 2 video queue + * @dma_queue_lock: lock to serialize the dma buffer queue + * @dma_queue: the queue for dma buffers + * @cur_frm: current isc frame/buffer + * @sequence: current frame number + * @stop: true if isc is not streaming, false if streaming + * @comp: completion reference that signals frame completion + * + * @fmt: current v42l format + * @user_formats: list of formats that are supported and agreed with sd + * @num_user_formats: how many formats are in user_formats + * + * @config: current ISC format configuration + * @try_config: the current ISC try format , not yet activated + * + * @ctrls: holds information about ISC controls + * @do_wb_ctrl: control regarding the DO_WHITE_BALANCE button + * @awb_work: workqueue reference for autowhitebalance histogram + * analysis + * + * @lock: lock for serializing userspace file operations + * with ISC operations + * @awb_lock: lock for serializing awb work queue operations + * with DMA/buffer operations + * + * @pipeline: configuration of the ISC pipeline + * + * @current_subdev: current subdevice: the sensor + * @subdev_entities: list of subdevice entitites + */ +struct isc_device { + struct regmap *regmap; + struct clk *hclock; + struct clk *ispck; + struct isc_clk isc_clks[2]; + + struct device *dev; + struct v4l2_device v4l2_dev; + struct video_device video_dev; + + struct vb2_queue vb2_vidq; + spinlock_t dma_queue_lock; /* serialize access to dma queue */ + struct list_head dma_queue; + struct isc_buffer *cur_frm; + unsigned int sequence; + bool stop; + struct completion comp; + + struct v4l2_format fmt; + struct isc_format **user_formats; + unsigned int num_user_formats; + + struct fmt_config config; + struct fmt_config try_config; + + struct isc_ctrls ctrls; + struct v4l2_ctrl *do_wb_ctrl; + struct work_struct awb_work; + + struct mutex lock; /* serialize access to file operations */ + spinlock_t awb_lock; /* serialize access to DMA buffers from awb work queue */ + + struct regmap_field *pipeline[ISC_PIPE_LINE_NODE_NUM]; + + struct isc_subdev_entity *current_subdev; + struct list_head subdev_entities; +}; + +#define GAMMA_MAX 2 +#define GAMMA_ENTRIES 64 + +#define ATMEL_ISC_NAME "atmel-isc" + +/* module parameters */ +extern unsigned int debug; +extern unsigned int sensor_preferred; + +extern struct isc_format formats_list[]; +extern struct isc_format controller_formats[]; +extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES]; +extern const struct regmap_config isc_regmap_config; +extern const struct v4l2_async_notifier_operations isc_async_ops; + +irqreturn_t isc_interrupt(int irq, void *dev_id); +int isc_pipeline_init(struct isc_device *isc); +int isc_clk_init(struct isc_device *isc); +void isc_subdev_cleanup(struct isc_device *isc); +void isc_clk_cleanup(struct isc_device *isc); + +#endif diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c new file mode 100644 index 000000000000..127e79c8f84a --- /dev/null +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -0,0 +1,344 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip Image Sensor Controller (ISC) driver + * + * Copyright (C) 2016-2019 Microchip Technology, Inc. + * + * Author: Songjun Wu + * Author: Eugen Hristev + * + * + * Sensor-->PFE-->WB-->CFA-->CC-->GAM-->CSC-->CBC-->SUB-->RLP-->DMA + * + * ISC video pipeline integrates the following submodules: + * PFE: Parallel Front End to sample the camera sensor input stream + * WB: Programmable white balance in the Bayer domain + * CFA: Color filter array interpolation module + * CC: Programmable color correction + * GAM: Gamma correction + * CSC: Programmable color space conversion + * CBC: Contrast and Brightness control + * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling + * RLP: This module performs rounding, range limiting + * and packing of the incoming data + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "atmel-isc-regs.h" +#include "atmel-isc.h" + +#define ISC_MAX_SUPPORT_WIDTH 2592 +#define ISC_MAX_SUPPORT_HEIGHT 1944 + +#define ISC_CLK_MAX_DIV 255 + +static int isc_parse_dt(struct device *dev, struct isc_device *isc) +{ + struct device_node *np = dev->of_node; + struct device_node *epn = NULL, *rem; + struct isc_subdev_entity *subdev_entity; + unsigned int flags; + int ret; + + INIT_LIST_HEAD(&isc->subdev_entities); + + while (1) { + struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 }; + + epn = of_graph_get_next_endpoint(np, epn); + if (!epn) + return 0; + + rem = of_graph_get_remote_port_parent(epn); + if (!rem) { + dev_notice(dev, "Remote device at %pOF not found\n", + epn); + continue; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn), + &v4l2_epn); + if (ret) { + of_node_put(rem); + ret = -EINVAL; + dev_err(dev, "Could not parse the endpoint\n"); + break; + } + + subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity), + GFP_KERNEL); + if (!subdev_entity) { + of_node_put(rem); + ret = -ENOMEM; + break; + } + + /* asd will be freed by the subsystem once it's added to the + * notifier list + */ + subdev_entity->asd = kzalloc(sizeof(*subdev_entity->asd), + GFP_KERNEL); + if (!subdev_entity->asd) { + of_node_put(rem); + ret = -ENOMEM; + break; + } + + flags = v4l2_epn.bus.parallel.flags; + + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW) + subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW; + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; + + if (v4l2_epn.bus_type == V4L2_MBUS_BT656) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + + subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; + subdev_entity->asd->match.fwnode = + of_fwnode_handle(rem); + list_add_tail(&subdev_entity->list, &isc->subdev_entities); + } + + of_node_put(epn); + return ret; +} + +static int atmel_isc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct isc_device *isc; + struct resource *res; + void __iomem *io_base; + struct isc_subdev_entity *subdev_entity; + int irq; + int ret; + + isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL); + if (!isc) + return -ENOMEM; + + platform_set_drvdata(pdev, isc); + isc->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + io_base = devm_ioremap_resource(dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); + + isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config); + if (IS_ERR(isc->regmap)) { + ret = PTR_ERR(isc->regmap); + dev_err(dev, "failed to init register map: %d\n", ret); + return ret; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + ret = irq; + dev_err(dev, "failed to get irq: %d\n", ret); + return ret; + } + + ret = devm_request_irq(dev, irq, isc_interrupt, 0, + ATMEL_ISC_NAME, isc); + if (ret < 0) { + dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n", + irq, ret); + return ret; + } + + ret = isc_pipeline_init(isc); + if (ret) + return ret; + + isc->hclock = devm_clk_get(dev, "hclock"); + if (IS_ERR(isc->hclock)) { + ret = PTR_ERR(isc->hclock); + dev_err(dev, "failed to get hclock: %d\n", ret); + return ret; + } + + ret = clk_prepare_enable(isc->hclock); + if (ret) { + dev_err(dev, "failed to enable hclock: %d\n", ret); + return ret; + } + + ret = isc_clk_init(isc); + if (ret) { + dev_err(dev, "failed to init isc clock: %d\n", ret); + goto unprepare_hclk; + } + + isc->ispck = isc->isc_clks[ISC_ISPCK].clk; + + ret = clk_prepare_enable(isc->ispck); + if (ret) { + dev_err(dev, "failed to enable ispck: %d\n", ret); + goto unprepare_hclk; + } + + /* ispck should be greater or equal to hclock */ + ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock)); + if (ret) { + dev_err(dev, "failed to set ispck rate: %d\n", ret); + goto unprepare_clk; + } + + ret = v4l2_device_register(dev, &isc->v4l2_dev); + if (ret) { + dev_err(dev, "unable to register v4l2 device.\n"); + goto unprepare_clk; + } + + ret = isc_parse_dt(dev, isc); + if (ret) { + dev_err(dev, "fail to parse device tree\n"); + goto unregister_v4l2_device; + } + + if (list_empty(&isc->subdev_entities)) { + dev_err(dev, "no subdev found\n"); + ret = -ENODEV; + goto unregister_v4l2_device; + } + + list_for_each_entry(subdev_entity, &isc->subdev_entities, list) { + v4l2_async_notifier_init(&subdev_entity->notifier); + + ret = v4l2_async_notifier_add_subdev(&subdev_entity->notifier, + subdev_entity->asd); + if (ret) { + fwnode_handle_put(subdev_entity->asd->match.fwnode); + kfree(subdev_entity->asd); + goto cleanup_subdev; + } + + subdev_entity->notifier.ops = &isc_async_ops; + + ret = v4l2_async_notifier_register(&isc->v4l2_dev, + &subdev_entity->notifier); + if (ret) { + dev_err(dev, "fail to register async notifier\n"); + goto cleanup_subdev; + } + + if (video_is_registered(&isc->video_dev)) + break; + } + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_request_idle(dev); + + return 0; + +cleanup_subdev: + isc_subdev_cleanup(isc); + +unregister_v4l2_device: + v4l2_device_unregister(&isc->v4l2_dev); + +unprepare_clk: + clk_disable_unprepare(isc->ispck); +unprepare_hclk: + clk_disable_unprepare(isc->hclock); + + isc_clk_cleanup(isc); + + return ret; +} + +static int atmel_isc_remove(struct platform_device *pdev) +{ + struct isc_device *isc = platform_get_drvdata(pdev); + + pm_runtime_disable(&pdev->dev); + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + + isc_subdev_cleanup(isc); + + v4l2_device_unregister(&isc->v4l2_dev); + + isc_clk_cleanup(isc); + + return 0; +} + +static int __maybe_unused isc_runtime_suspend(struct device *dev) +{ + struct isc_device *isc = dev_get_drvdata(dev); + + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + + return 0; +} + +static int __maybe_unused isc_runtime_resume(struct device *dev) +{ + struct isc_device *isc = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(isc->hclock); + if (ret) + return ret; + + return clk_prepare_enable(isc->ispck); +} + +static const struct dev_pm_ops atmel_isc_dev_pm_ops = { + SET_RUNTIME_PM_OPS(isc_runtime_suspend, isc_runtime_resume, NULL) +}; + +static const struct of_device_id atmel_isc_of_match[] = { + { .compatible = "atmel,sama5d2-isc" }, + { } +}; +MODULE_DEVICE_TABLE(of, atmel_isc_of_match); + +static struct platform_driver atmel_isc_driver = { + .probe = atmel_isc_probe, + .remove = atmel_isc_remove, + .driver = { + .name = ATMEL_ISC_NAME, + .pm = &atmel_isc_dev_pm_ops, + .of_match_table = of_match_ptr(atmel_isc_of_match), + }, +}; + +module_platform_driver(atmel_isc_driver); + +MODULE_AUTHOR("Songjun Wu"); +MODULE_DESCRIPTION("The V4L2 driver for Atmel-ISC"); +MODULE_LICENSE("GPL v2"); +MODULE_SUPPORTED_DEVICE("video"); -- cgit v1.2.3-59-g8ed1b From b046ec51f9bb53a63a61dbc11733879aa4c7004c Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 12 Jun 2019 08:00:35 -0400 Subject: media: atmel: atmel-isc: fix and cleanup potential bugs Fixed issues that can lead to potential bugs. Cleanup order in the driver Taking into consideration std control creation can fail mutex_destroy call changing controller_formats with const specifier some cosmetic cleanups Signed-off-by: Eugen Hristev Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-base.c | 28 ++++++++++++++++-------- drivers/media/platform/atmel/atmel-isc.h | 2 +- drivers/media/platform/atmel/atmel-sama5d2-isc.c | 14 +++++++----- 3 files changed, 29 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index edfd7e00a565..eb1f5d4c207e 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -45,7 +45,7 @@ MODULE_PARM_DESC(sensor_preferred, "Sensor is preferred to output the specified format (1-on 0-off), default 1"); /* This is a list of the formats that the ISC can *output* */ -struct isc_format controller_formats[] = { +const struct isc_format controller_formats[] = { { .fourcc = V4L2_PIX_FMT_ARGB444, }, @@ -231,7 +231,7 @@ static inline void isc_update_awb_ctrls(struct isc_device *isc) static inline void isc_reset_awb_ctrls(struct isc_device *isc) { - int c; + unsigned int c; for (c = ISC_HIS_CFG_MODE_GR; c <= ISC_HIS_CFG_MODE_B; c++) { /* gains have a fixed point at 9 decimals */ @@ -1456,7 +1456,7 @@ static int isc_enum_frameintervals(struct file *file, void *fh, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; int ret = -EINVAL; - int i; + unsigned int i; for (i = 0; i < isc->num_user_formats; i++) if (isc->user_formats[i]->fourcc == fival->pixel_format) @@ -1883,6 +1883,12 @@ static int isc_ctrl_init(struct isc_device *isc) isc->do_wb_ctrl = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_DO_WHITE_BALANCE, 0, 0, 0, 0); + if (!isc->do_wb_ctrl) { + ret = hdl->error; + v4l2_ctrl_handler_free(hdl); + return ret; + } + v4l2_ctrl_activate(isc->do_wb_ctrl, false); v4l2_ctrl_handler_setup(hdl); @@ -2010,7 +2016,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) struct isc_device, v4l2_dev); struct video_device *vdev = &isc->video_dev; struct vb2_queue *q = &isc->vb2_vidq; - int ret; + int ret = 0; INIT_WORK(&isc->awb_work, isc_awb_work); @@ -2041,7 +2047,7 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) if (ret < 0) { v4l2_err(&isc->v4l2_dev, "vb2_queue_init() failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } /* Init video dma queues */ @@ -2053,19 +2059,19 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) if (ret < 0) { v4l2_err(&isc->v4l2_dev, "Init format failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } ret = isc_set_default_fmt(isc); if (ret) { v4l2_err(&isc->v4l2_dev, "Could not set default format\n"); - return ret; + goto isc_async_complete_err; } ret = isc_ctrl_init(isc); if (ret) { v4l2_err(&isc->v4l2_dev, "Init isc ctrols failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } /* Register video device */ @@ -2085,10 +2091,14 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier) if (ret < 0) { v4l2_err(&isc->v4l2_dev, "video_register_device failed: %d\n", ret); - return ret; + goto isc_async_complete_err; } return 0; + +isc_async_complete_err: + mutex_destroy(&isc->lock); + return ret; } const struct v4l2_async_notifier_operations isc_async_ops = { diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h index 5be5b093aefb..f5f5932ac1e2 100644 --- a/drivers/media/platform/atmel/atmel-isc.h +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -235,7 +235,7 @@ extern unsigned int debug; extern unsigned int sensor_preferred; extern struct isc_format formats_list[]; -extern struct isc_format controller_formats[]; +extern const struct isc_format controller_formats[]; extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES]; extern const struct regmap_config isc_regmap_config; extern const struct v4l2_async_notifier_operations isc_async_ops; diff --git a/drivers/media/platform/atmel/atmel-sama5d2-isc.c b/drivers/media/platform/atmel/atmel-sama5d2-isc.c index 127e79c8f84a..266df14da2d5 100644 --- a/drivers/media/platform/atmel/atmel-sama5d2-isc.c +++ b/drivers/media/platform/atmel/atmel-sama5d2-isc.c @@ -122,8 +122,7 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) ISC_PFE_CFG0_CCIR656; subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - subdev_entity->asd->match.fwnode = - of_fwnode_handle(rem); + subdev_entity->asd->match.fwnode = of_fwnode_handle(rem); list_add_tail(&subdev_entity->list, &isc->subdev_entities); } @@ -282,13 +281,14 @@ static int atmel_isc_remove(struct platform_device *pdev) struct isc_device *isc = platform_get_drvdata(pdev); pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(isc->ispck); - clk_disable_unprepare(isc->hclock); isc_subdev_cleanup(isc); v4l2_device_unregister(&isc->v4l2_dev); + clk_disable_unprepare(isc->ispck); + clk_disable_unprepare(isc->hclock); + isc_clk_cleanup(isc); return 0; @@ -313,7 +313,11 @@ static int __maybe_unused isc_runtime_resume(struct device *dev) if (ret) return ret; - return clk_prepare_enable(isc->ispck); + ret = clk_prepare_enable(isc->ispck); + if (ret) + clk_disable_unprepare(isc->hclock); + + return ret; } static const struct dev_pm_ops atmel_isc_dev_pm_ops = { -- cgit v1.2.3-59-g8ed1b From b2ce5617dad254230551feda3599f2cc68e53ad8 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Wed, 12 Jun 2019 12:19:35 -0400 Subject: media: i2c: fix warning same module names When building with CONFIG_VIDEO_ADV7511 and CONFIG_DRM_I2C_ADV7511 enabled as loadable modules, we see the following warning: drivers/gpu/drm/bridge/adv7511/adv7511.ko drivers/media/i2c/adv7511.ko Rework so that the file is named adv7511-v4l2.c. Signed-off-by: Anders Roxell Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Makefile | 2 +- drivers/media/i2c/adv7511-v4l2.c | 1997 ++++++++++++++++++++++++++++++++++++++ drivers/media/i2c/adv7511.c | 1992 ------------------------------------- 3 files changed, 1998 insertions(+), 1993 deletions(-) create mode 100644 drivers/media/i2c/adv7511-v4l2.c delete mode 100644 drivers/media/i2c/adv7511.c (limited to 'drivers/media') diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index d8ad9dad495d..fd4ea86dedd5 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_VIDEO_ADV748X) += adv748x/ obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o -obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o +obj-$(CONFIG_VIDEO_ADV7511) += adv7511-v4l2.o obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o obj-$(CONFIG_VIDEO_VS6624) += vs6624.o obj-$(CONFIG_VIDEO_BT819) += bt819.o diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c new file mode 100644 index 000000000000..2ad6bdf1a9fc --- /dev/null +++ b/drivers/media/i2c/adv7511-v4l2.c @@ -0,0 +1,1997 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Analog Devices ADV7511 HDMI Transmitter Device Driver + * + * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +/* + * This file is named adv7511-v4l2.c so it doesn't conflict with the Analog + * Device ADV7511 (config fragment CONFIG_DRM_I2C_ADV7511). + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + +MODULE_DESCRIPTION("Analog Devices ADV7511 HDMI Transmitter Device Driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL v2"); + +#define MASK_ADV7511_EDID_RDY_INT 0x04 +#define MASK_ADV7511_MSEN_INT 0x40 +#define MASK_ADV7511_HPD_INT 0x80 + +#define MASK_ADV7511_HPD_DETECT 0x40 +#define MASK_ADV7511_MSEN_DETECT 0x20 +#define MASK_ADV7511_EDID_RDY 0x10 + +#define EDID_MAX_RETRIES (8) +#define EDID_DELAY 250 +#define EDID_MAX_SEGM 8 + +#define ADV7511_MAX_WIDTH 1920 +#define ADV7511_MAX_HEIGHT 1200 +#define ADV7511_MIN_PIXELCLOCK 20000000 +#define ADV7511_MAX_PIXELCLOCK 225000000 + +#define ADV7511_MAX_ADDRS (3) + +/* +********************************************************************** +* +* Arrays with configuration parameters for the ADV7511 +* +********************************************************************** +*/ + +struct i2c_reg_value { + unsigned char reg; + unsigned char value; +}; + +struct adv7511_state_edid { + /* total number of blocks */ + u32 blocks; + /* Number of segments read */ + u32 segments; + u8 data[EDID_MAX_SEGM * 256]; + /* Number of EDID read retries left */ + unsigned read_retries; + bool complete; +}; + +struct adv7511_state { + struct adv7511_platform_data pdata; + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler hdl; + int chip_revision; + u8 i2c_edid_addr; + u8 i2c_pktmem_addr; + u8 i2c_cec_addr; + + struct i2c_client *i2c_cec; + struct cec_adapter *cec_adap; + u8 cec_addr[ADV7511_MAX_ADDRS]; + u8 cec_valid_addrs; + bool cec_enabled_adap; + + /* Is the adv7511 powered on? */ + bool power_on; + /* Did we receive hotplug and rx-sense signals? */ + bool have_monitor; + bool enabled_irq; + /* timings from s_dv_timings */ + struct v4l2_dv_timings dv_timings; + u32 fmt_code; + u32 colorspace; + u32 ycbcr_enc; + u32 quantization; + u32 xfer_func; + u32 content_type; + /* controls */ + struct v4l2_ctrl *hdmi_mode_ctrl; + struct v4l2_ctrl *hotplug_ctrl; + struct v4l2_ctrl *rx_sense_ctrl; + struct v4l2_ctrl *have_edid0_ctrl; + struct v4l2_ctrl *rgb_quantization_range_ctrl; + struct v4l2_ctrl *content_type_ctrl; + struct i2c_client *i2c_edid; + struct i2c_client *i2c_pktmem; + struct adv7511_state_edid edid; + /* Running counter of the number of detected EDIDs (for debugging) */ + unsigned edid_detect_counter; + struct workqueue_struct *work_queue; + struct delayed_work edid_handler; /* work entry */ +}; + +static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd); +static bool adv7511_check_edid_status(struct v4l2_subdev *sd); +static void adv7511_setup(struct v4l2_subdev *sd); +static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq); +static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq); + + +static const struct v4l2_dv_timings_cap adv7511_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + V4L2_INIT_BT_TIMINGS(640, ADV7511_MAX_WIDTH, 350, ADV7511_MAX_HEIGHT, + ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, + V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM) +}; + +static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct adv7511_state, sd); +} + +static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) +{ + return &container_of(ctrl->handler, struct adv7511_state, hdl)->sd; +} + +/* ------------------------ I2C ----------------------------------------------- */ + +static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, + u8 command, bool check) +{ + union i2c_smbus_data data; + + if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_BYTE_DATA, &data)) + return data.byte; + if (check) + v4l_err(client, "error reading %02x, %02x\n", + client->addr, command); + return -1; +} + +static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command) +{ + int i; + for (i = 0; i < 3; i++) { + int ret = adv_smbus_read_byte_data_check(client, command, true); + if (ret >= 0) { + if (i) + v4l_err(client, "read ok after %d retries\n", i); + return ret; + } + } + v4l_err(client, "read failed\n"); + return -1; +} + +static int adv7511_rd(struct v4l2_subdev *sd, u8 reg) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + + return adv_smbus_read_byte_data(client, reg); +} + +static int adv7511_wr(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(client, reg, val); + if (ret == 0) + return 0; + } + v4l2_err(sd, "%s: i2c write error\n", __func__); + return ret; +} + +/* To set specific bits in the register, a clear-mask is given (to be AND-ed), + and then the value-mask (to be OR-ed). */ +static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) +{ + adv7511_wr(sd, reg, (adv7511_rd(sd, reg) & clr_mask) | val_mask); +} + +static int adv_smbus_read_i2c_block_data(struct i2c_client *client, + u8 command, unsigned length, u8 *values) +{ + union i2c_smbus_data data; + int ret; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + data.block[0] = length; + + ret = i2c_smbus_xfer(client->adapter, client->addr, client->flags, + I2C_SMBUS_READ, command, + I2C_SMBUS_I2C_BLOCK_DATA, &data); + memcpy(values, data.block + 1, length); + return ret; +} + +static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) +{ + struct adv7511_state *state = get_adv7511_state(sd); + int i; + int err = 0; + + v4l2_dbg(1, debug, sd, "%s:\n", __func__); + + for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) + err = adv_smbus_read_i2c_block_data(state->i2c_edid, i, + I2C_SMBUS_BLOCK_MAX, buf + i); + if (err) + v4l2_err(sd, "%s: i2c read error\n", __func__); +} + +static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + return i2c_smbus_read_byte_data(state->i2c_cec, reg); +} + +static int adv7511_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct adv7511_state *state = get_adv7511_state(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val); + if (ret == 0) + return 0; + } + v4l2_err(sd, "%s: I2C Write Problem\n", __func__); + return ret; +} + +static inline int adv7511_cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, + u8 val) +{ + return adv7511_cec_write(sd, reg, (adv7511_cec_read(sd, reg) & mask) | val); +} + +static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + return adv_smbus_read_byte_data(state->i2c_pktmem, reg); +} + +static int adv7511_pktmem_wr(struct v4l2_subdev *sd, u8 reg, u8 val) +{ + struct adv7511_state *state = get_adv7511_state(sd); + int ret; + int i; + + for (i = 0; i < 3; i++) { + ret = i2c_smbus_write_byte_data(state->i2c_pktmem, reg, val); + if (ret == 0) + return 0; + } + v4l2_err(sd, "%s: i2c write error\n", __func__); + return ret; +} + +/* To set specific bits in the register, a clear-mask is given (to be AND-ed), + and then the value-mask (to be OR-ed). */ +static inline void adv7511_pktmem_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) +{ + adv7511_pktmem_wr(sd, reg, (adv7511_pktmem_rd(sd, reg) & clr_mask) | val_mask); +} + +static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd) +{ + return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT; +} + +static inline bool adv7511_have_rx_sense(struct v4l2_subdev *sd) +{ + return adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT; +} + +static void adv7511_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode) +{ + adv7511_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5); +} + +static void adv7511_csc_coeff(struct v4l2_subdev *sd, + u16 A1, u16 A2, u16 A3, u16 A4, + u16 B1, u16 B2, u16 B3, u16 B4, + u16 C1, u16 C2, u16 C3, u16 C4) +{ + /* A */ + adv7511_wr_and_or(sd, 0x18, 0xe0, A1>>8); + adv7511_wr(sd, 0x19, A1); + adv7511_wr_and_or(sd, 0x1A, 0xe0, A2>>8); + adv7511_wr(sd, 0x1B, A2); + adv7511_wr_and_or(sd, 0x1c, 0xe0, A3>>8); + adv7511_wr(sd, 0x1d, A3); + adv7511_wr_and_or(sd, 0x1e, 0xe0, A4>>8); + adv7511_wr(sd, 0x1f, A4); + + /* B */ + adv7511_wr_and_or(sd, 0x20, 0xe0, B1>>8); + adv7511_wr(sd, 0x21, B1); + adv7511_wr_and_or(sd, 0x22, 0xe0, B2>>8); + adv7511_wr(sd, 0x23, B2); + adv7511_wr_and_or(sd, 0x24, 0xe0, B3>>8); + adv7511_wr(sd, 0x25, B3); + adv7511_wr_and_or(sd, 0x26, 0xe0, B4>>8); + adv7511_wr(sd, 0x27, B4); + + /* C */ + adv7511_wr_and_or(sd, 0x28, 0xe0, C1>>8); + adv7511_wr(sd, 0x29, C1); + adv7511_wr_and_or(sd, 0x2A, 0xe0, C2>>8); + adv7511_wr(sd, 0x2B, C2); + adv7511_wr_and_or(sd, 0x2C, 0xe0, C3>>8); + adv7511_wr(sd, 0x2D, C3); + adv7511_wr_and_or(sd, 0x2E, 0xe0, C4>>8); + adv7511_wr(sd, 0x2F, C4); +} + +static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable) +{ + if (enable) { + u8 csc_mode = 0; + adv7511_csc_conversion_mode(sd, csc_mode); + adv7511_csc_coeff(sd, + 4096-564, 0, 0, 256, + 0, 4096-564, 0, 256, + 0, 0, 4096-564, 256); + /* enable CSC */ + adv7511_wr_and_or(sd, 0x18, 0x7f, 0x80); + /* AVI infoframe: Limited range RGB (16-235) */ + adv7511_wr_and_or(sd, 0x57, 0xf3, 0x04); + } else { + /* disable CSC */ + adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0); + /* AVI infoframe: Full range RGB (0-255) */ + adv7511_wr_and_or(sd, 0x57, 0xf3, 0x08); + } +} + +static void adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + /* Only makes sense for RGB formats */ + if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) { + /* so just keep quantization */ + adv7511_csc_rgb_full2limit(sd, false); + return; + } + + switch (ctrl->val) { + case V4L2_DV_RGB_RANGE_AUTO: + /* automatic */ + if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { + /* CE format, RGB limited range (16-235) */ + adv7511_csc_rgb_full2limit(sd, true); + } else { + /* not CE format, RGB full range (0-255) */ + adv7511_csc_rgb_full2limit(sd, false); + } + break; + case V4L2_DV_RGB_RANGE_LIMITED: + /* RGB limited range (16-235) */ + adv7511_csc_rgb_full2limit(sd, true); + break; + case V4L2_DV_RGB_RANGE_FULL: + /* RGB full range (0-255) */ + adv7511_csc_rgb_full2limit(sd, false); + break; + } +} + +/* ------------------------------ CTRL OPS ------------------------------ */ + +static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct v4l2_subdev *sd = to_sd(ctrl); + struct adv7511_state *state = get_adv7511_state(sd); + + v4l2_dbg(1, debug, sd, "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val); + + if (state->hdmi_mode_ctrl == ctrl) { + /* Set HDMI or DVI-D */ + adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); + return 0; + } + if (state->rgb_quantization_range_ctrl == ctrl) { + adv7511_set_rgb_quantization_mode(sd, ctrl); + return 0; + } + if (state->content_type_ctrl == ctrl) { + u8 itc, cn; + + state->content_type = ctrl->val; + itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC; + cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS; + adv7511_wr_and_or(sd, 0x57, 0x7f, itc << 7); + adv7511_wr_and_or(sd, 0x59, 0xcf, cn << 4); + return 0; + } + + return -EINVAL; +} + +static const struct v4l2_ctrl_ops adv7511_ctrl_ops = { + .s_ctrl = adv7511_s_ctrl, +}; + +/* ---------------------------- CORE OPS ------------------------------------------- */ + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static void adv7511_inv_register(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + v4l2_info(sd, "0x000-0x0ff: Main Map\n"); + if (state->i2c_cec) + v4l2_info(sd, "0x100-0x1ff: CEC Map\n"); +} + +static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + reg->size = 1; + switch (reg->reg >> 8) { + case 0: + reg->val = adv7511_rd(sd, reg->reg & 0xff); + break; + case 1: + if (state->i2c_cec) { + reg->val = adv7511_cec_read(sd, reg->reg & 0xff); + break; + } + /* fall through */ + default: + v4l2_info(sd, "Register %03llx not supported\n", reg->reg); + adv7511_inv_register(sd); + break; + } + return 0; +} + +static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + switch (reg->reg >> 8) { + case 0: + adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff); + break; + case 1: + if (state->i2c_cec) { + adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff); + break; + } + /* fall through */ + default: + v4l2_info(sd, "Register %03llx not supported\n", reg->reg); + adv7511_inv_register(sd); + break; + } + return 0; +} +#endif + +struct adv7511_cfg_read_infoframe { + const char *desc; + u8 present_reg; + u8 present_mask; + u8 header[3]; + u16 payload_addr; +}; + +static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size) +{ + u8 csum = 0; + size_t i; + + /* compute checksum */ + for (i = 0; i < size; i++) + csum += ptr[i]; + + return 256 - csum; +} + +static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + union hdmi_infoframe frame; + u8 buffer[32]; + u8 len; + int i; + + if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) { + v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc); + return; + } + + memcpy(buffer, cri->header, sizeof(cri->header)); + + len = buffer[2]; + + if (len + 4 > sizeof(buffer)) { + v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); + return; + } + + if (cri->payload_addr >= 0x100) { + for (i = 0; i < len; i++) + buffer[i + 4] = adv7511_pktmem_rd(sd, cri->payload_addr + i - 0x100); + } else { + for (i = 0; i < len; i++) + buffer[i + 4] = adv7511_rd(sd, cri->payload_addr + i); + } + buffer[3] = 0; + buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); + + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { + v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); + return; + } + + hdmi_infoframe_log(KERN_INFO, dev, &frame); +} + +static void adv7511_log_infoframes(struct v4l2_subdev *sd) +{ + static const struct adv7511_cfg_read_infoframe cri[] = { + { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, + { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, + { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, + }; + int i; + + for (i = 0; i < ARRAY_SIZE(cri); i++) + log_infoframe(sd, &cri[i]); +} + +static int adv7511_log_status(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + struct adv7511_state_edid *edid = &state->edid; + int i; + + static const char * const states[] = { + "in reset", + "reading EDID", + "idle", + "initializing HDCP", + "HDCP enabled", + "initializing HDCP repeater", + "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" + }; + static const char * const errors[] = { + "no error", + "bad receiver BKSV", + "Ri mismatch", + "Pj mismatch", + "i2c error", + "timed out", + "max repeater cascade exceeded", + "hash check failed", + "too many devices", + "9", "A", "B", "C", "D", "E", "F" + }; + + v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off"); + v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n", + (adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT) ? "detected" : "no", + (adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT) ? "detected" : "no", + edid->segments ? "found" : "no", + edid->blocks); + v4l2_info(sd, "%s output %s\n", + (adv7511_rd(sd, 0xaf) & 0x02) ? + "HDMI" : "DVI-D", + (adv7511_rd(sd, 0xa1) & 0x3c) ? + "disabled" : "enabled"); + v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n", + states[adv7511_rd(sd, 0xc8) & 0xf], + errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter, + adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96)); + v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full"); + if (adv7511_rd(sd, 0xaf) & 0x02) { + /* HDMI only */ + u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80; + u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 | + adv7511_rd(sd, 0x02) << 8 | + adv7511_rd(sd, 0x03); + u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2; + u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f; + u32 CTS; + + if (manual_cts) + CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 | + adv7511_rd(sd, 0x08) << 8 | + adv7511_rd(sd, 0x09); + else + CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 | + adv7511_rd(sd, 0x05) << 8 | + adv7511_rd(sd, 0x06); + v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n", + manual_cts ? "manual" : "automatic", N, CTS); + v4l2_info(sd, "VIC: detected %d, sent %d\n", + vic_detect, vic_sent); + adv7511_log_infoframes(sd); + } + if (state->dv_timings.type == V4L2_DV_BT_656_1120) + v4l2_print_dv_timings(sd->name, "timings: ", + &state->dv_timings, false); + else + v4l2_info(sd, "no timings set\n"); + v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); + + if (state->i2c_cec == NULL) + return 0; + + v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); + + v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? + "enabled" : "disabled"); + if (state->cec_enabled_adap) { + for (i = 0; i < ADV7511_MAX_ADDRS; i++) { + bool is_valid = state->cec_valid_addrs & (1 << i); + + if (is_valid) + v4l2_info(sd, "CEC Logical Address: 0x%x\n", + state->cec_addr[i]); + } + } + v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); + return 0; +} + +/* Power up/down adv7511 */ +static int adv7511_s_power(struct v4l2_subdev *sd, int on) +{ + struct adv7511_state *state = get_adv7511_state(sd); + const int retries = 20; + int i; + + v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off"); + + state->power_on = on; + + if (!on) { + /* Power down */ + adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40); + return true; + } + + /* Power up */ + /* The adv7511 does not always come up immediately. + Retry multiple times. */ + for (i = 0; i < retries; i++) { + adv7511_wr_and_or(sd, 0x41, 0xbf, 0x0); + if ((adv7511_rd(sd, 0x41) & 0x40) == 0) + break; + adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40); + msleep(10); + } + if (i == retries) { + v4l2_dbg(1, debug, sd, "%s: failed to powerup the adv7511!\n", __func__); + adv7511_s_power(sd, 0); + return false; + } + if (i > 1) + v4l2_dbg(1, debug, sd, "%s: needed %d retries to powerup the adv7511\n", __func__, i); + + /* Reserved registers that must be set */ + adv7511_wr(sd, 0x98, 0x03); + adv7511_wr_and_or(sd, 0x9a, 0xfe, 0x70); + adv7511_wr(sd, 0x9c, 0x30); + adv7511_wr_and_or(sd, 0x9d, 0xfc, 0x01); + adv7511_wr(sd, 0xa2, 0xa4); + adv7511_wr(sd, 0xa3, 0xa4); + adv7511_wr(sd, 0xe0, 0xd0); + adv7511_wr(sd, 0xf9, 0x00); + + adv7511_wr(sd, 0x43, state->i2c_edid_addr); + adv7511_wr(sd, 0x45, state->i2c_pktmem_addr); + + /* Set number of attempts to read the EDID */ + adv7511_wr(sd, 0xc9, 0xf); + return true; +} + +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) +static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct adv7511_state *state = cec_get_drvdata(adap); + struct v4l2_subdev *sd = &state->sd; + + if (state->i2c_cec == NULL) + return -EIO; + + if (!state->cec_enabled_adap && enable) { + /* power up cec section */ + adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01); + /* legacy mode and clear all rx buffers */ + adv7511_cec_write(sd, 0x4a, 0x00); + adv7511_cec_write(sd, 0x4a, 0x07); + adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */ + /* enabled irqs: */ + /* tx: ready */ + /* tx: arbitration lost */ + /* tx: retry timeout */ + /* rx: ready 1 */ + if (state->enabled_irq) + adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39); + } else if (state->cec_enabled_adap && !enable) { + if (state->enabled_irq) + adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00); + /* disable address mask 1-3 */ + adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0x00); + /* power down cec section */ + adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x00); + state->cec_valid_addrs = 0; + } + state->cec_enabled_adap = enable; + return 0; +} + +static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) +{ + struct adv7511_state *state = cec_get_drvdata(adap); + struct v4l2_subdev *sd = &state->sd; + unsigned int i, free_idx = ADV7511_MAX_ADDRS; + + if (!state->cec_enabled_adap) + return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; + + if (addr == CEC_LOG_ADDR_INVALID) { + adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0); + state->cec_valid_addrs = 0; + return 0; + } + + for (i = 0; i < ADV7511_MAX_ADDRS; i++) { + bool is_valid = state->cec_valid_addrs & (1 << i); + + if (free_idx == ADV7511_MAX_ADDRS && !is_valid) + free_idx = i; + if (is_valid && state->cec_addr[i] == addr) + return 0; + } + if (i == ADV7511_MAX_ADDRS) { + i = free_idx; + if (i == ADV7511_MAX_ADDRS) + return -ENXIO; + } + state->cec_addr[i] = addr; + state->cec_valid_addrs |= 1 << i; + + switch (i) { + case 0: + /* enable address mask 0 */ + adv7511_cec_write_and_or(sd, 0x4b, 0xef, 0x10); + /* set address for mask 0 */ + adv7511_cec_write_and_or(sd, 0x4c, 0xf0, addr); + break; + case 1: + /* enable address mask 1 */ + adv7511_cec_write_and_or(sd, 0x4b, 0xdf, 0x20); + /* set address for mask 1 */ + adv7511_cec_write_and_or(sd, 0x4c, 0x0f, addr << 4); + break; + case 2: + /* enable address mask 2 */ + adv7511_cec_write_and_or(sd, 0x4b, 0xbf, 0x40); + /* set address for mask 1 */ + adv7511_cec_write_and_or(sd, 0x4d, 0xf0, addr); + break; + } + return 0; +} + +static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct adv7511_state *state = cec_get_drvdata(adap); + struct v4l2_subdev *sd = &state->sd; + u8 len = msg->len; + unsigned int i; + + v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len); + + if (len > 16) { + v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); + return -EINVAL; + } + + /* + * The number of retries is the number of attempts - 1, but retry + * at least once. It's not clear if a value of 0 is allowed, so + * let's do at least one retry. + */ + adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4); + + /* clear cec tx irq status */ + adv7511_wr(sd, 0x97, 0x38); + + /* write data */ + for (i = 0; i < len; i++) + adv7511_cec_write(sd, i, msg->msg[i]); + + /* set length (data + header) */ + adv7511_cec_write(sd, 0x10, len); + /* start transmit, enable tx */ + adv7511_cec_write(sd, 0x11, 0x01); + return 0; +} + +static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + if ((adv7511_cec_read(sd, 0x11) & 0x01) == 0) { + v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); + return; + } + + if (tx_raw_status & 0x10) { + v4l2_dbg(1, debug, sd, + "%s: tx raw: arbitration lost\n", __func__); + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, + 1, 0, 0, 0); + return; + } + if (tx_raw_status & 0x08) { + u8 status; + u8 nack_cnt; + u8 low_drive_cnt; + + v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); + /* + * We set this status bit since this hardware performs + * retransmissions. + */ + status = CEC_TX_STATUS_MAX_RETRIES; + nack_cnt = adv7511_cec_read(sd, 0x14) & 0xf; + if (nack_cnt) + status |= CEC_TX_STATUS_NACK; + low_drive_cnt = adv7511_cec_read(sd, 0x14) >> 4; + if (low_drive_cnt) + status |= CEC_TX_STATUS_LOW_DRIVE; + cec_transmit_done(state->cec_adap, status, + 0, nack_cnt, low_drive_cnt, 0); + return; + } + if (tx_raw_status & 0x20) { + v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); + cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); + return; + } +} + +static const struct cec_adap_ops adv7511_cec_adap_ops = { + .adap_enable = adv7511_cec_adap_enable, + .adap_log_addr = adv7511_cec_adap_log_addr, + .adap_transmit = adv7511_cec_adap_transmit, +}; +#endif + +/* Enable interrupts */ +static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) +{ + struct adv7511_state *state = get_adv7511_state(sd); + u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; + u8 irqs_rd; + int retries = 100; + + v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); + + if (state->enabled_irq == enable) + return; + state->enabled_irq = enable; + + /* The datasheet says that the EDID ready interrupt should be + disabled if there is no hotplug. */ + if (!enable) + irqs = 0; + else if (adv7511_have_hotplug(sd)) + irqs |= MASK_ADV7511_EDID_RDY_INT; + + /* + * This i2c write can fail (approx. 1 in 1000 writes). But it + * is essential that this register is correct, so retry it + * multiple times. + * + * Note that the i2c write does not report an error, but the readback + * clearly shows the wrong value. + */ + do { + adv7511_wr(sd, 0x94, irqs); + irqs_rd = adv7511_rd(sd, 0x94); + } while (retries-- && irqs_rd != irqs); + + if (irqs_rd != irqs) + v4l2_err(sd, "Could not set interrupts: hw failure?\n"); + + adv7511_wr_and_or(sd, 0x95, 0xc0, + (state->cec_enabled_adap && enable) ? 0x39 : 0x00); +} + +/* Interrupt handler */ +static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + u8 irq_status; + u8 cec_irq; + + /* disable interrupts to prevent a race condition */ + adv7511_set_isr(sd, false); + irq_status = adv7511_rd(sd, 0x96); + cec_irq = adv7511_rd(sd, 0x97); + /* clear detected interrupts */ + adv7511_wr(sd, 0x96, irq_status); + adv7511_wr(sd, 0x97, cec_irq); + + v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__, + irq_status, cec_irq); + + if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT)) + adv7511_check_monitor_present_status(sd); + if (irq_status & MASK_ADV7511_EDID_RDY_INT) + adv7511_check_edid_status(sd); + +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) + if (cec_irq & 0x38) + adv_cec_tx_raw_status(sd, cec_irq); + + if (cec_irq & 1) { + struct adv7511_state *state = get_adv7511_state(sd); + struct cec_msg msg; + + msg.len = adv7511_cec_read(sd, 0x25) & 0x1f; + + v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__, + msg.len); + + if (msg.len > 16) + msg.len = 16; + + if (msg.len) { + u8 i; + + for (i = 0; i < msg.len; i++) + msg.msg[i] = adv7511_cec_read(sd, i + 0x15); + + adv7511_cec_write(sd, 0x4a, 0); /* toggle to re-enable rx 1 */ + adv7511_cec_write(sd, 0x4a, 1); + cec_received_msg(state->cec_adap, &msg); + } + } +#endif + + /* enable interrupts */ + adv7511_set_isr(sd, true); + + if (handled) + *handled = true; + return 0; +} + +static const struct v4l2_subdev_core_ops adv7511_core_ops = { + .log_status = adv7511_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = adv7511_g_register, + .s_register = adv7511_s_register, +#endif + .s_power = adv7511_s_power, + .interrupt_service_routine = adv7511_isr, +}; + +/* ------------------------------ VIDEO OPS ------------------------------ */ + +/* Enable/disable adv7511 output */ +static int adv7511_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); + adv7511_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c)); + if (enable) { + adv7511_check_monitor_present_status(sd); + } else { + adv7511_s_power(sd, 0); + state->have_monitor = false; + } + return 0; +} + +static int adv7511_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct adv7511_state *state = get_adv7511_state(sd); + struct v4l2_bt_timings *bt = &timings->bt; + u32 fps; + + v4l2_dbg(1, debug, sd, "%s:\n", __func__); + + /* quick sanity check */ + if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL)) + return -EINVAL; + + /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings + if the format is one of the CEA or DMT timings. */ + v4l2_find_dv_timings_cap(timings, &adv7511_timings_cap, 0, NULL, NULL); + + /* save timings */ + state->dv_timings = *timings; + + /* set h/vsync polarities */ + adv7511_wr_and_or(sd, 0x17, 0x9f, + ((bt->polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) | + ((bt->polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20)); + + fps = (u32)bt->pixelclock / (V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt)); + switch (fps) { + case 24: + adv7511_wr_and_or(sd, 0xfb, 0xf9, 1 << 1); + break; + case 25: + adv7511_wr_and_or(sd, 0xfb, 0xf9, 2 << 1); + break; + case 30: + adv7511_wr_and_or(sd, 0xfb, 0xf9, 3 << 1); + break; + default: + adv7511_wr_and_or(sd, 0xfb, 0xf9, 0); + break; + } + + /* update quantization range based on new dv_timings */ + adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); + + return 0; +} + +static int adv7511_g_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + v4l2_dbg(1, debug, sd, "%s:\n", __func__); + + if (!timings) + return -EINVAL; + + *timings = state->dv_timings; + + return 0; +} + +static int adv7511_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings) +{ + if (timings->pad != 0) + return -EINVAL; + + return v4l2_enum_dv_timings_cap(timings, &adv7511_timings_cap, NULL, NULL); +} + +static int adv7511_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + if (cap->pad != 0) + return -EINVAL; + + *cap = adv7511_timings_cap; + return 0; +} + +static const struct v4l2_subdev_video_ops adv7511_video_ops = { + .s_stream = adv7511_s_stream, + .s_dv_timings = adv7511_s_dv_timings, + .g_dv_timings = adv7511_g_dv_timings, +}; + +/* ------------------------------ AUDIO OPS ------------------------------ */ +static int adv7511_s_audio_stream(struct v4l2_subdev *sd, int enable) +{ + v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); + + if (enable) + adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x80); + else + adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x40); + + return 0; +} + +static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + u32 N; + + switch (freq) { + case 32000: N = 4096; break; + case 44100: N = 6272; break; + case 48000: N = 6144; break; + case 88200: N = 12544; break; + case 96000: N = 12288; break; + case 176400: N = 25088; break; + case 192000: N = 24576; break; + default: + return -EINVAL; + } + + /* Set N (used with CTS to regenerate the audio clock) */ + adv7511_wr(sd, 0x01, (N >> 16) & 0xf); + adv7511_wr(sd, 0x02, (N >> 8) & 0xff); + adv7511_wr(sd, 0x03, N & 0xff); + + return 0; +} + +static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) +{ + u32 i2s_sf; + + switch (freq) { + case 32000: i2s_sf = 0x30; break; + case 44100: i2s_sf = 0x00; break; + case 48000: i2s_sf = 0x20; break; + case 88200: i2s_sf = 0x80; break; + case 96000: i2s_sf = 0xa0; break; + case 176400: i2s_sf = 0xc0; break; + case 192000: i2s_sf = 0xe0; break; + default: + return -EINVAL; + } + + /* Set sampling frequency for I2S audio to 48 kHz */ + adv7511_wr_and_or(sd, 0x15, 0xf, i2s_sf); + + return 0; +} + +static int adv7511_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) +{ + /* Only 2 channels in use for application */ + adv7511_wr_and_or(sd, 0x73, 0xf8, 0x1); + /* Speaker mapping */ + adv7511_wr(sd, 0x76, 0x00); + + /* 16 bit audio word length */ + adv7511_wr_and_or(sd, 0x14, 0xf0, 0x02); + + return 0; +} + +static const struct v4l2_subdev_audio_ops adv7511_audio_ops = { + .s_stream = adv7511_s_audio_stream, + .s_clock_freq = adv7511_s_clock_freq, + .s_i2s_clock_freq = adv7511_s_i2s_clock_freq, + .s_routing = adv7511_s_routing, +}; + +/* ---------------------------- PAD OPS ------------------------------------- */ + +static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + memset(edid->reserved, 0, sizeof(edid->reserved)); + + if (edid->pad != 0) + return -EINVAL; + + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = state->edid.segments * 2; + return 0; + } + + if (state->edid.segments == 0) + return -ENODATA; + + if (edid->start_block >= state->edid.segments * 2) + return -EINVAL; + + if (edid->start_block + edid->blocks > state->edid.segments * 2) + edid->blocks = state->edid.segments * 2 - edid->start_block; + + memcpy(edid->edid, &state->edid.data[edid->start_block * 128], + 128 * edid->blocks); + + return 0; +} + +static int adv7511_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->pad != 0) + return -EINVAL; + + switch (code->index) { + case 0: + code->code = MEDIA_BUS_FMT_RGB888_1X24; + break; + case 1: + code->code = MEDIA_BUS_FMT_YUYV8_1X16; + break; + case 2: + code->code = MEDIA_BUS_FMT_UYVY8_1X16; + break; + default: + return -EINVAL; + } + return 0; +} + +static void adv7511_fill_format(struct adv7511_state *state, + struct v4l2_mbus_framefmt *format) +{ + format->width = state->dv_timings.bt.width; + format->height = state->dv_timings.bt.height; + format->field = V4L2_FIELD_NONE; +} + +static int adv7511_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + if (format->pad != 0) + return -EINVAL; + + memset(&format->format, 0, sizeof(format->format)); + adv7511_fill_format(state, &format->format); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + format->format.code = fmt->code; + format->format.colorspace = fmt->colorspace; + format->format.ycbcr_enc = fmt->ycbcr_enc; + format->format.quantization = fmt->quantization; + format->format.xfer_func = fmt->xfer_func; + } else { + format->format.code = state->fmt_code; + format->format.colorspace = state->colorspace; + format->format.ycbcr_enc = state->ycbcr_enc; + format->format.quantization = state->quantization; + format->format.xfer_func = state->xfer_func; + } + + return 0; +} + +static int adv7511_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct adv7511_state *state = get_adv7511_state(sd); + /* + * Bitfield namings come the CEA-861-F standard, table 8 "Auxiliary + * Video Information (AVI) InfoFrame Format" + * + * c = Colorimetry + * ec = Extended Colorimetry + * y = RGB or YCbCr + * q = RGB Quantization Range + * yq = YCC Quantization Range + */ + u8 c = HDMI_COLORIMETRY_NONE; + u8 ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + u8 y = HDMI_COLORSPACE_RGB; + u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT; + u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + u8 itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC; + u8 cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS; + + if (format->pad != 0) + return -EINVAL; + switch (format->format.code) { + case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_1X16: + case MEDIA_BUS_FMT_RGB888_1X24: + break; + default: + return -EINVAL; + } + + adv7511_fill_format(state, &format->format); + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *fmt; + + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + fmt->code = format->format.code; + fmt->colorspace = format->format.colorspace; + fmt->ycbcr_enc = format->format.ycbcr_enc; + fmt->quantization = format->format.quantization; + fmt->xfer_func = format->format.xfer_func; + return 0; + } + + switch (format->format.code) { + case MEDIA_BUS_FMT_UYVY8_1X16: + adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01); + adv7511_wr_and_or(sd, 0x16, 0x03, 0xb8); + y = HDMI_COLORSPACE_YUV422; + break; + case MEDIA_BUS_FMT_YUYV8_1X16: + adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01); + adv7511_wr_and_or(sd, 0x16, 0x03, 0xbc); + y = HDMI_COLORSPACE_YUV422; + break; + case MEDIA_BUS_FMT_RGB888_1X24: + default: + adv7511_wr_and_or(sd, 0x15, 0xf0, 0x00); + adv7511_wr_and_or(sd, 0x16, 0x03, 0x00); + break; + } + state->fmt_code = format->format.code; + state->colorspace = format->format.colorspace; + state->ycbcr_enc = format->format.ycbcr_enc; + state->quantization = format->format.quantization; + state->xfer_func = format->format.xfer_func; + + switch (format->format.colorspace) { + case V4L2_COLORSPACE_OPRGB: + c = HDMI_COLORIMETRY_EXTENDED; + ec = y ? HDMI_EXTENDED_COLORIMETRY_OPYCC_601 : + HDMI_EXTENDED_COLORIMETRY_OPRGB; + break; + case V4L2_COLORSPACE_SMPTE170M: + c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE; + if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV601) { + c = HDMI_COLORIMETRY_EXTENDED; + ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + } + break; + case V4L2_COLORSPACE_REC709: + c = y ? HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_NONE; + if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV709) { + c = HDMI_COLORIMETRY_EXTENDED; + ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; + } + break; + case V4L2_COLORSPACE_SRGB: + c = y ? HDMI_COLORIMETRY_EXTENDED : HDMI_COLORIMETRY_NONE; + ec = y ? HDMI_EXTENDED_COLORIMETRY_S_YCC_601 : + HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; + break; + case V4L2_COLORSPACE_BT2020: + c = HDMI_COLORIMETRY_EXTENDED; + if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM) + ec = 5; /* Not yet available in hdmi.h */ + else + ec = 6; /* Not yet available in hdmi.h */ + break; + default: + break; + } + + /* + * CEA-861-F says that for RGB formats the YCC range must match the + * RGB range, although sources should ignore the YCC range. + * + * The RGB quantization range shouldn't be non-zero if the EDID doesn't + * have the Q bit set in the Video Capabilities Data Block, however this + * isn't checked at the moment. The assumption is that the application + * knows the EDID and can detect this. + * + * The same is true for the YCC quantization range: non-standard YCC + * quantization ranges should only be sent if the EDID has the YQ bit + * set in the Video Capabilities Data Block. + */ + switch (format->format.quantization) { + case V4L2_QUANTIZATION_FULL_RANGE: + q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT : + HDMI_QUANTIZATION_RANGE_FULL; + yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_FULL; + break; + case V4L2_QUANTIZATION_LIM_RANGE: + q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT : + HDMI_QUANTIZATION_RANGE_LIMITED; + yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_LIMITED; + break; + } + + adv7511_wr_and_or(sd, 0x4a, 0xbf, 0); + adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5); + adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6); + adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7)); + adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4)); + adv7511_wr_and_or(sd, 0x4a, 0xff, 1); + adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); + + return 0; +} + +static const struct v4l2_subdev_pad_ops adv7511_pad_ops = { + .get_edid = adv7511_get_edid, + .enum_mbus_code = adv7511_enum_mbus_code, + .get_fmt = adv7511_get_fmt, + .set_fmt = adv7511_set_fmt, + .enum_dv_timings = adv7511_enum_dv_timings, + .dv_timings_cap = adv7511_dv_timings_cap, +}; + +/* --------------------- SUBDEV OPS --------------------------------------- */ + +static const struct v4l2_subdev_ops adv7511_ops = { + .core = &adv7511_core_ops, + .pad = &adv7511_pad_ops, + .video = &adv7511_video_ops, + .audio = &adv7511_audio_ops, +}; + +/* ----------------------------------------------------------------------- */ +static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, int segment, u8 *buf) +{ + if (debug >= lvl) { + int i, j; + v4l2_dbg(lvl, debug, sd, "edid segment %d\n", segment); + for (i = 0; i < 256; i += 16) { + u8 b[128]; + u8 *bp = b; + if (i == 128) + v4l2_dbg(lvl, debug, sd, "\n"); + for (j = i; j < i + 16; j++) { + sprintf(bp, "0x%02x, ", buf[j]); + bp += 6; + } + bp[0] = '\0'; + v4l2_dbg(lvl, debug, sd, "%s\n", b); + } + } +} + +static void adv7511_notify_no_edid(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + struct adv7511_edid_detect ed; + + /* We failed to read the EDID, so send an event for this. */ + ed.present = false; + ed.segment = adv7511_rd(sd, 0xc4); + ed.phys_addr = CEC_PHYS_ADDR_INVALID; + cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); + v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); + v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0); +} + +static void adv7511_edid_handler(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct adv7511_state *state = container_of(dwork, struct adv7511_state, edid_handler); + struct v4l2_subdev *sd = &state->sd; + + v4l2_dbg(1, debug, sd, "%s:\n", __func__); + + if (adv7511_check_edid_status(sd)) { + /* Return if we received the EDID. */ + return; + } + + if (adv7511_have_hotplug(sd)) { + /* We must retry reading the EDID several times, it is possible + * that initially the EDID couldn't be read due to i2c errors + * (DVI connectors are particularly prone to this problem). */ + if (state->edid.read_retries) { + state->edid.read_retries--; + v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); + state->have_monitor = false; + adv7511_s_power(sd, false); + adv7511_s_power(sd, true); + queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); + return; + } + } + + /* We failed to read the EDID, so send an event for this. */ + adv7511_notify_no_edid(sd); + v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__); +} + +static void adv7511_audio_setup(struct v4l2_subdev *sd) +{ + v4l2_dbg(1, debug, sd, "%s\n", __func__); + + adv7511_s_i2s_clock_freq(sd, 48000); + adv7511_s_clock_freq(sd, 48000); + adv7511_s_routing(sd, 0, 0, 0); +} + +/* Configure hdmi transmitter. */ +static void adv7511_setup(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + v4l2_dbg(1, debug, sd, "%s\n", __func__); + + /* Input format: RGB 4:4:4 */ + adv7511_wr_and_or(sd, 0x15, 0xf0, 0x0); + /* Output format: RGB 4:4:4 */ + adv7511_wr_and_or(sd, 0x16, 0x7f, 0x0); + /* 1st order interpolation 4:2:2 -> 4:4:4 up conversion, Aspect ratio: 16:9 */ + adv7511_wr_and_or(sd, 0x17, 0xf9, 0x06); + /* Disable pixel repetition */ + adv7511_wr_and_or(sd, 0x3b, 0x9f, 0x0); + /* Disable CSC */ + adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0); + /* Output format: RGB 4:4:4, Active Format Information is valid, + * underscanned */ + adv7511_wr_and_or(sd, 0x55, 0x9c, 0x12); + /* AVI Info frame packet enable, Audio Info frame disable */ + adv7511_wr_and_or(sd, 0x44, 0xe7, 0x10); + /* Colorimetry, Active format aspect ratio: same as picure. */ + adv7511_wr(sd, 0x56, 0xa8); + /* No encryption */ + adv7511_wr_and_or(sd, 0xaf, 0xed, 0x0); + + /* Positive clk edge capture for input video clock */ + adv7511_wr_and_or(sd, 0xba, 0x1f, 0x60); + + adv7511_audio_setup(sd); + + v4l2_ctrl_handler_setup(&state->hdl); +} + +static void adv7511_notify_monitor_detect(struct v4l2_subdev *sd) +{ + struct adv7511_monitor_detect mdt; + struct adv7511_state *state = get_adv7511_state(sd); + + mdt.present = state->have_monitor; + v4l2_subdev_notify(sd, ADV7511_MONITOR_DETECT, (void *)&mdt); +} + +static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + /* read hotplug and rx-sense state */ + u8 status = adv7511_rd(sd, 0x42); + + v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n", + __func__, + status, + status & MASK_ADV7511_HPD_DETECT ? ", hotplug" : "", + status & MASK_ADV7511_MSEN_DETECT ? ", rx-sense" : ""); + + /* update read only ctrls */ + v4l2_ctrl_s_ctrl(state->hotplug_ctrl, adv7511_have_hotplug(sd) ? 0x1 : 0x0); + v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, adv7511_have_rx_sense(sd) ? 0x1 : 0x0); + + if ((status & MASK_ADV7511_HPD_DETECT) && ((status & MASK_ADV7511_MSEN_DETECT) || state->edid.segments)) { + v4l2_dbg(1, debug, sd, "%s: hotplug and (rx-sense or edid)\n", __func__); + if (!state->have_monitor) { + v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__); + state->have_monitor = true; + adv7511_set_isr(sd, true); + if (!adv7511_s_power(sd, true)) { + v4l2_dbg(1, debug, sd, "%s: monitor detected, powerup failed\n", __func__); + return; + } + adv7511_setup(sd); + adv7511_notify_monitor_detect(sd); + state->edid.read_retries = EDID_MAX_RETRIES; + queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); + } + } else if (status & MASK_ADV7511_HPD_DETECT) { + v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__); + state->edid.read_retries = EDID_MAX_RETRIES; + queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); + } else if (!(status & MASK_ADV7511_HPD_DETECT)) { + v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); + if (state->have_monitor) { + v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__); + state->have_monitor = false; + adv7511_notify_monitor_detect(sd); + } + adv7511_s_power(sd, false); + memset(&state->edid, 0, sizeof(struct adv7511_state_edid)); + adv7511_notify_no_edid(sd); + } +} + +static bool edid_block_verify_crc(u8 *edid_block) +{ + u8 sum = 0; + int i; + + for (i = 0; i < 128; i++) + sum += edid_block[i]; + return sum == 0; +} + +static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment) +{ + struct adv7511_state *state = get_adv7511_state(sd); + u32 blocks = state->edid.blocks; + u8 *data = state->edid.data; + + if (!edid_block_verify_crc(&data[segment * 256])) + return false; + if ((segment + 1) * 2 <= blocks) + return edid_block_verify_crc(&data[segment * 256 + 128]); + return true; +} + +static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment) +{ + static const u8 hdmi_header[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 + }; + struct adv7511_state *state = get_adv7511_state(sd); + u8 *data = state->edid.data; + + if (segment != 0) + return true; + return !memcmp(data, hdmi_header, sizeof(hdmi_header)); +} + +static bool adv7511_check_edid_status(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + u8 edidRdy = adv7511_rd(sd, 0xc5); + + v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n", + __func__, EDID_MAX_RETRIES - state->edid.read_retries); + + if (state->edid.complete) + return true; + + if (edidRdy & MASK_ADV7511_EDID_RDY) { + int segment = adv7511_rd(sd, 0xc4); + struct adv7511_edid_detect ed; + + if (segment >= EDID_MAX_SEGM) { + v4l2_err(sd, "edid segment number too big\n"); + return false; + } + v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment); + adv7511_edid_rd(sd, 256, &state->edid.data[segment * 256]); + adv7511_dbg_dump_edid(2, debug, sd, segment, &state->edid.data[segment * 256]); + if (segment == 0) { + state->edid.blocks = state->edid.data[0x7e] + 1; + v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks); + } + if (!edid_verify_crc(sd, segment) || + !edid_verify_header(sd, segment)) { + /* edid crc error, force reread of edid segment */ + v4l2_err(sd, "%s: edid crc or header error\n", __func__); + state->have_monitor = false; + adv7511_s_power(sd, false); + adv7511_s_power(sd, true); + return false; + } + /* one more segment read ok */ + state->edid.segments = segment + 1; + v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x1); + if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) { + /* Request next EDID segment */ + v4l2_dbg(1, debug, sd, "%s: request segment %d\n", __func__, state->edid.segments); + adv7511_wr(sd, 0xc9, 0xf); + adv7511_wr(sd, 0xc4, state->edid.segments); + state->edid.read_retries = EDID_MAX_RETRIES; + queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); + return false; + } + + v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments); + state->edid.complete = true; + ed.phys_addr = cec_get_edid_phys_addr(state->edid.data, + state->edid.segments * 256, + NULL); + /* report when we have all segments + but report only for segment 0 + */ + ed.present = true; + ed.segment = 0; + state->edid_detect_counter++; + cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); + v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); + return ed.present; + } + + return false; +} + +static int adv7511_registered(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int err; + + err = cec_register_adapter(state->cec_adap, &client->dev); + if (err) + cec_delete_adapter(state->cec_adap); + return err; +} + +static void adv7511_unregistered(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + + cec_unregister_adapter(state->cec_adap); +} + +static const struct v4l2_subdev_internal_ops adv7511_int_ops = { + .registered = adv7511_registered, + .unregistered = adv7511_unregistered, +}; + +/* ----------------------------------------------------------------------- */ +/* Setup ADV7511 */ +static void adv7511_init_setup(struct v4l2_subdev *sd) +{ + struct adv7511_state *state = get_adv7511_state(sd); + struct adv7511_state_edid *edid = &state->edid; + u32 cec_clk = state->pdata.cec_clk; + u8 ratio; + + v4l2_dbg(1, debug, sd, "%s\n", __func__); + + /* clear all interrupts */ + adv7511_wr(sd, 0x96, 0xff); + adv7511_wr(sd, 0x97, 0xff); + /* + * Stop HPD from resetting a lot of registers. + * It might leave the chip in a partly un-initialized state, + * in particular with regards to hotplug bounces. + */ + adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0); + memset(edid, 0, sizeof(struct adv7511_state_edid)); + state->have_monitor = false; + adv7511_set_isr(sd, false); + adv7511_s_stream(sd, false); + adv7511_s_audio_stream(sd, false); + + if (state->i2c_cec == NULL) + return; + + v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk); + + /* cec soft reset */ + adv7511_cec_write(sd, 0x50, 0x01); + adv7511_cec_write(sd, 0x50, 0x00); + + /* legacy mode */ + adv7511_cec_write(sd, 0x4a, 0x00); + adv7511_cec_write(sd, 0x4a, 0x07); + + if (cec_clk % 750000 != 0) + v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n", + __func__, cec_clk); + + ratio = (cec_clk / 750000) - 1; + adv7511_cec_write(sd, 0x4e, ratio << 2); +} + +static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) +{ + struct adv7511_state *state; + struct adv7511_platform_data *pdata = client->dev.platform_data; + struct v4l2_ctrl_handler *hdl; + struct v4l2_subdev *sd; + u8 chip_id[2]; + int err = -EIO; + + /* Check if the adapter supports the needed features */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + + state = devm_kzalloc(&client->dev, sizeof(struct adv7511_state), GFP_KERNEL); + if (!state) + return -ENOMEM; + + /* Platform data */ + if (!pdata) { + v4l_err(client, "No platform data!\n"); + return -ENODEV; + } + memcpy(&state->pdata, pdata, sizeof(state->pdata)); + state->fmt_code = MEDIA_BUS_FMT_RGB888_1X24; + state->colorspace = V4L2_COLORSPACE_SRGB; + + sd = &state->sd; + + v4l2_dbg(1, debug, sd, "detecting adv7511 client on address 0x%x\n", + client->addr << 1); + + v4l2_i2c_subdev_init(sd, client, &adv7511_ops); + sd->internal_ops = &adv7511_int_ops; + + hdl = &state->hdl; + v4l2_ctrl_handler_init(hdl, 10); + /* add in ascending ID order */ + state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops, + V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, + 0, V4L2_DV_TX_MODE_DVI_D); + state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0); + state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0); + state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL, + V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0); + state->rgb_quantization_range_ctrl = + v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops, + V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, + 0, V4L2_DV_RGB_RANGE_AUTO); + state->content_type_ctrl = + v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops, + V4L2_CID_DV_TX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC, + 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); + sd->ctrl_handler = hdl; + if (hdl->error) { + err = hdl->error; + goto err_hdl; + } + state->pad.flags = MEDIA_PAD_FL_SINK; + sd->entity.function = MEDIA_ENT_F_DV_ENCODER; + err = media_entity_pads_init(&sd->entity, 1, &state->pad); + if (err) + goto err_hdl; + + /* EDID and CEC i2c addr */ + state->i2c_edid_addr = state->pdata.i2c_edid << 1; + state->i2c_cec_addr = state->pdata.i2c_cec << 1; + state->i2c_pktmem_addr = state->pdata.i2c_pktmem << 1; + + state->chip_revision = adv7511_rd(sd, 0x0); + chip_id[0] = adv7511_rd(sd, 0xf5); + chip_id[1] = adv7511_rd(sd, 0xf6); + if (chip_id[0] != 0x75 || chip_id[1] != 0x11) { + v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], + chip_id[1]); + err = -EIO; + goto err_entity; + } + + state->i2c_edid = i2c_new_dummy(client->adapter, + state->i2c_edid_addr >> 1); + if (state->i2c_edid == NULL) { + v4l2_err(sd, "failed to register edid i2c client\n"); + err = -ENOMEM; + goto err_entity; + } + + adv7511_wr(sd, 0xe1, state->i2c_cec_addr); + if (state->pdata.cec_clk < 3000000 || + state->pdata.cec_clk > 100000000) { + v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n", + __func__, state->pdata.cec_clk); + state->pdata.cec_clk = 0; + } + + if (state->pdata.cec_clk) { + state->i2c_cec = i2c_new_dummy(client->adapter, + state->i2c_cec_addr >> 1); + if (state->i2c_cec == NULL) { + v4l2_err(sd, "failed to register cec i2c client\n"); + err = -ENOMEM; + goto err_unreg_edid; + } + adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ + } else { + adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ + } + + state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); + if (state->i2c_pktmem == NULL) { + v4l2_err(sd, "failed to register pktmem i2c client\n"); + err = -ENOMEM; + goto err_unreg_cec; + } + + state->work_queue = create_singlethread_workqueue(sd->name); + if (state->work_queue == NULL) { + v4l2_err(sd, "could not create workqueue\n"); + err = -ENOMEM; + goto err_unreg_pktmem; + } + + INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); + + adv7511_init_setup(sd); + +#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) + state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, + state, dev_name(&client->dev), CEC_CAP_DEFAULTS, + ADV7511_MAX_ADDRS); + err = PTR_ERR_OR_ZERO(state->cec_adap); + if (err) { + destroy_workqueue(state->work_queue); + goto err_unreg_pktmem; + } +#endif + + adv7511_set_isr(sd, true); + adv7511_check_monitor_present_status(sd); + + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); + return 0; + +err_unreg_pktmem: + i2c_unregister_device(state->i2c_pktmem); +err_unreg_cec: + if (state->i2c_cec) + i2c_unregister_device(state->i2c_cec); +err_unreg_edid: + i2c_unregister_device(state->i2c_edid); +err_entity: + media_entity_cleanup(&sd->entity); +err_hdl: + v4l2_ctrl_handler_free(&state->hdl); + return err; +} + +/* ----------------------------------------------------------------------- */ + +static int adv7511_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct adv7511_state *state = get_adv7511_state(sd); + + state->chip_revision = -1; + + v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); + + adv7511_set_isr(sd, false); + adv7511_init_setup(sd); + cancel_delayed_work(&state->edid_handler); + i2c_unregister_device(state->i2c_edid); + if (state->i2c_cec) + i2c_unregister_device(state->i2c_cec); + i2c_unregister_device(state->i2c_pktmem); + destroy_workqueue(state->work_queue); + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + return 0; +} + +/* ----------------------------------------------------------------------- */ + +static const struct i2c_device_id adv7511_id[] = { + { "adv7511", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, adv7511_id); + +static struct i2c_driver adv7511_driver = { + .driver = { + .name = "adv7511", + }, + .probe = adv7511_probe, + .remove = adv7511_remove, + .id_table = adv7511_id, +}; + +module_i2c_driver(adv7511_driver); diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c deleted file mode 100644 index cec5ebb1c9e6..000000000000 --- a/drivers/media/i2c/adv7511.c +++ /dev/null @@ -1,1992 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * Analog Devices ADV7511 HDMI Transmitter Device Driver - * - * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); - -MODULE_DESCRIPTION("Analog Devices ADV7511 HDMI Transmitter Device Driver"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL v2"); - -#define MASK_ADV7511_EDID_RDY_INT 0x04 -#define MASK_ADV7511_MSEN_INT 0x40 -#define MASK_ADV7511_HPD_INT 0x80 - -#define MASK_ADV7511_HPD_DETECT 0x40 -#define MASK_ADV7511_MSEN_DETECT 0x20 -#define MASK_ADV7511_EDID_RDY 0x10 - -#define EDID_MAX_RETRIES (8) -#define EDID_DELAY 250 -#define EDID_MAX_SEGM 8 - -#define ADV7511_MAX_WIDTH 1920 -#define ADV7511_MAX_HEIGHT 1200 -#define ADV7511_MIN_PIXELCLOCK 20000000 -#define ADV7511_MAX_PIXELCLOCK 225000000 - -#define ADV7511_MAX_ADDRS (3) - -/* -********************************************************************** -* -* Arrays with configuration parameters for the ADV7511 -* -********************************************************************** -*/ - -struct i2c_reg_value { - unsigned char reg; - unsigned char value; -}; - -struct adv7511_state_edid { - /* total number of blocks */ - u32 blocks; - /* Number of segments read */ - u32 segments; - u8 data[EDID_MAX_SEGM * 256]; - /* Number of EDID read retries left */ - unsigned read_retries; - bool complete; -}; - -struct adv7511_state { - struct adv7511_platform_data pdata; - struct v4l2_subdev sd; - struct media_pad pad; - struct v4l2_ctrl_handler hdl; - int chip_revision; - u8 i2c_edid_addr; - u8 i2c_pktmem_addr; - u8 i2c_cec_addr; - - struct i2c_client *i2c_cec; - struct cec_adapter *cec_adap; - u8 cec_addr[ADV7511_MAX_ADDRS]; - u8 cec_valid_addrs; - bool cec_enabled_adap; - - /* Is the adv7511 powered on? */ - bool power_on; - /* Did we receive hotplug and rx-sense signals? */ - bool have_monitor; - bool enabled_irq; - /* timings from s_dv_timings */ - struct v4l2_dv_timings dv_timings; - u32 fmt_code; - u32 colorspace; - u32 ycbcr_enc; - u32 quantization; - u32 xfer_func; - u32 content_type; - /* controls */ - struct v4l2_ctrl *hdmi_mode_ctrl; - struct v4l2_ctrl *hotplug_ctrl; - struct v4l2_ctrl *rx_sense_ctrl; - struct v4l2_ctrl *have_edid0_ctrl; - struct v4l2_ctrl *rgb_quantization_range_ctrl; - struct v4l2_ctrl *content_type_ctrl; - struct i2c_client *i2c_edid; - struct i2c_client *i2c_pktmem; - struct adv7511_state_edid edid; - /* Running counter of the number of detected EDIDs (for debugging) */ - unsigned edid_detect_counter; - struct workqueue_struct *work_queue; - struct delayed_work edid_handler; /* work entry */ -}; - -static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd); -static bool adv7511_check_edid_status(struct v4l2_subdev *sd); -static void adv7511_setup(struct v4l2_subdev *sd); -static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq); -static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq); - - -static const struct v4l2_dv_timings_cap adv7511_timings_cap = { - .type = V4L2_DV_BT_656_1120, - /* keep this initialization for compatibility with GCC < 4.4.6 */ - .reserved = { 0 }, - V4L2_INIT_BT_TIMINGS(640, ADV7511_MAX_WIDTH, 350, ADV7511_MAX_HEIGHT, - ADV7511_MIN_PIXELCLOCK, ADV7511_MAX_PIXELCLOCK, - V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | - V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, - V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_REDUCED_BLANKING | - V4L2_DV_BT_CAP_CUSTOM) -}; - -static inline struct adv7511_state *get_adv7511_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct adv7511_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct adv7511_state, hdl)->sd; -} - -/* ------------------------ I2C ----------------------------------------------- */ - -static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, - u8 command, bool check) -{ - union i2c_smbus_data data; - - if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_BYTE_DATA, &data)) - return data.byte; - if (check) - v4l_err(client, "error reading %02x, %02x\n", - client->addr, command); - return -1; -} - -static s32 adv_smbus_read_byte_data(struct i2c_client *client, u8 command) -{ - int i; - for (i = 0; i < 3; i++) { - int ret = adv_smbus_read_byte_data_check(client, command, true); - if (ret >= 0) { - if (i) - v4l_err(client, "read ok after %d retries\n", i); - return ret; - } - } - v4l_err(client, "read failed\n"); - return -1; -} - -static int adv7511_rd(struct v4l2_subdev *sd, u8 reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - return adv_smbus_read_byte_data(client, reg); -} - -static int adv7511_wr(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - int i; - - for (i = 0; i < 3; i++) { - ret = i2c_smbus_write_byte_data(client, reg, val); - if (ret == 0) - return 0; - } - v4l2_err(sd, "%s: i2c write error\n", __func__); - return ret; -} - -/* To set specific bits in the register, a clear-mask is given (to be AND-ed), - and then the value-mask (to be OR-ed). */ -static inline void adv7511_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) -{ - adv7511_wr(sd, reg, (adv7511_rd(sd, reg) & clr_mask) | val_mask); -} - -static int adv_smbus_read_i2c_block_data(struct i2c_client *client, - u8 command, unsigned length, u8 *values) -{ - union i2c_smbus_data data; - int ret; - - if (length > I2C_SMBUS_BLOCK_MAX) - length = I2C_SMBUS_BLOCK_MAX; - data.block[0] = length; - - ret = i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); - memcpy(values, data.block + 1, length); - return ret; -} - -static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf) -{ - struct adv7511_state *state = get_adv7511_state(sd); - int i; - int err = 0; - - v4l2_dbg(1, debug, sd, "%s:\n", __func__); - - for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_read_i2c_block_data(state->i2c_edid, i, - I2C_SMBUS_BLOCK_MAX, buf + i); - if (err) - v4l2_err(sd, "%s: i2c read error\n", __func__); -} - -static inline int adv7511_cec_read(struct v4l2_subdev *sd, u8 reg) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - return i2c_smbus_read_byte_data(state->i2c_cec, reg); -} - -static int adv7511_cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct adv7511_state *state = get_adv7511_state(sd); - int ret; - int i; - - for (i = 0; i < 3; i++) { - ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val); - if (ret == 0) - return 0; - } - v4l2_err(sd, "%s: I2C Write Problem\n", __func__); - return ret; -} - -static inline int adv7511_cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, - u8 val) -{ - return adv7511_cec_write(sd, reg, (adv7511_cec_read(sd, reg) & mask) | val); -} - -static int adv7511_pktmem_rd(struct v4l2_subdev *sd, u8 reg) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - return adv_smbus_read_byte_data(state->i2c_pktmem, reg); -} - -static int adv7511_pktmem_wr(struct v4l2_subdev *sd, u8 reg, u8 val) -{ - struct adv7511_state *state = get_adv7511_state(sd); - int ret; - int i; - - for (i = 0; i < 3; i++) { - ret = i2c_smbus_write_byte_data(state->i2c_pktmem, reg, val); - if (ret == 0) - return 0; - } - v4l2_err(sd, "%s: i2c write error\n", __func__); - return ret; -} - -/* To set specific bits in the register, a clear-mask is given (to be AND-ed), - and then the value-mask (to be OR-ed). */ -static inline void adv7511_pktmem_wr_and_or(struct v4l2_subdev *sd, u8 reg, u8 clr_mask, u8 val_mask) -{ - adv7511_pktmem_wr(sd, reg, (adv7511_pktmem_rd(sd, reg) & clr_mask) | val_mask); -} - -static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd) -{ - return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT; -} - -static inline bool adv7511_have_rx_sense(struct v4l2_subdev *sd) -{ - return adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT; -} - -static void adv7511_csc_conversion_mode(struct v4l2_subdev *sd, u8 mode) -{ - adv7511_wr_and_or(sd, 0x18, 0x9f, (mode & 0x3)<<5); -} - -static void adv7511_csc_coeff(struct v4l2_subdev *sd, - u16 A1, u16 A2, u16 A3, u16 A4, - u16 B1, u16 B2, u16 B3, u16 B4, - u16 C1, u16 C2, u16 C3, u16 C4) -{ - /* A */ - adv7511_wr_and_or(sd, 0x18, 0xe0, A1>>8); - adv7511_wr(sd, 0x19, A1); - adv7511_wr_and_or(sd, 0x1A, 0xe0, A2>>8); - adv7511_wr(sd, 0x1B, A2); - adv7511_wr_and_or(sd, 0x1c, 0xe0, A3>>8); - adv7511_wr(sd, 0x1d, A3); - adv7511_wr_and_or(sd, 0x1e, 0xe0, A4>>8); - adv7511_wr(sd, 0x1f, A4); - - /* B */ - adv7511_wr_and_or(sd, 0x20, 0xe0, B1>>8); - adv7511_wr(sd, 0x21, B1); - adv7511_wr_and_or(sd, 0x22, 0xe0, B2>>8); - adv7511_wr(sd, 0x23, B2); - adv7511_wr_and_or(sd, 0x24, 0xe0, B3>>8); - adv7511_wr(sd, 0x25, B3); - adv7511_wr_and_or(sd, 0x26, 0xe0, B4>>8); - adv7511_wr(sd, 0x27, B4); - - /* C */ - adv7511_wr_and_or(sd, 0x28, 0xe0, C1>>8); - adv7511_wr(sd, 0x29, C1); - adv7511_wr_and_or(sd, 0x2A, 0xe0, C2>>8); - adv7511_wr(sd, 0x2B, C2); - adv7511_wr_and_or(sd, 0x2C, 0xe0, C3>>8); - adv7511_wr(sd, 0x2D, C3); - adv7511_wr_and_or(sd, 0x2E, 0xe0, C4>>8); - adv7511_wr(sd, 0x2F, C4); -} - -static void adv7511_csc_rgb_full2limit(struct v4l2_subdev *sd, bool enable) -{ - if (enable) { - u8 csc_mode = 0; - adv7511_csc_conversion_mode(sd, csc_mode); - adv7511_csc_coeff(sd, - 4096-564, 0, 0, 256, - 0, 4096-564, 0, 256, - 0, 0, 4096-564, 256); - /* enable CSC */ - adv7511_wr_and_or(sd, 0x18, 0x7f, 0x80); - /* AVI infoframe: Limited range RGB (16-235) */ - adv7511_wr_and_or(sd, 0x57, 0xf3, 0x04); - } else { - /* disable CSC */ - adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0); - /* AVI infoframe: Full range RGB (0-255) */ - adv7511_wr_and_or(sd, 0x57, 0xf3, 0x08); - } -} - -static void adv7511_set_rgb_quantization_mode(struct v4l2_subdev *sd, struct v4l2_ctrl *ctrl) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - /* Only makes sense for RGB formats */ - if (state->fmt_code != MEDIA_BUS_FMT_RGB888_1X24) { - /* so just keep quantization */ - adv7511_csc_rgb_full2limit(sd, false); - return; - } - - switch (ctrl->val) { - case V4L2_DV_RGB_RANGE_AUTO: - /* automatic */ - if (state->dv_timings.bt.flags & V4L2_DV_FL_IS_CE_VIDEO) { - /* CE format, RGB limited range (16-235) */ - adv7511_csc_rgb_full2limit(sd, true); - } else { - /* not CE format, RGB full range (0-255) */ - adv7511_csc_rgb_full2limit(sd, false); - } - break; - case V4L2_DV_RGB_RANGE_LIMITED: - /* RGB limited range (16-235) */ - adv7511_csc_rgb_full2limit(sd, true); - break; - case V4L2_DV_RGB_RANGE_FULL: - /* RGB full range (0-255) */ - adv7511_csc_rgb_full2limit(sd, false); - break; - } -} - -/* ------------------------------ CTRL OPS ------------------------------ */ - -static int adv7511_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct adv7511_state *state = get_adv7511_state(sd); - - v4l2_dbg(1, debug, sd, "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val); - - if (state->hdmi_mode_ctrl == ctrl) { - /* Set HDMI or DVI-D */ - adv7511_wr_and_or(sd, 0xaf, 0xfd, ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00); - return 0; - } - if (state->rgb_quantization_range_ctrl == ctrl) { - adv7511_set_rgb_quantization_mode(sd, ctrl); - return 0; - } - if (state->content_type_ctrl == ctrl) { - u8 itc, cn; - - state->content_type = ctrl->val; - itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC; - cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS; - adv7511_wr_and_or(sd, 0x57, 0x7f, itc << 7); - adv7511_wr_and_or(sd, 0x59, 0xcf, cn << 4); - return 0; - } - - return -EINVAL; -} - -static const struct v4l2_ctrl_ops adv7511_ctrl_ops = { - .s_ctrl = adv7511_s_ctrl, -}; - -/* ---------------------------- CORE OPS ------------------------------------------- */ - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static void adv7511_inv_register(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - v4l2_info(sd, "0x000-0x0ff: Main Map\n"); - if (state->i2c_cec) - v4l2_info(sd, "0x100-0x1ff: CEC Map\n"); -} - -static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - reg->size = 1; - switch (reg->reg >> 8) { - case 0: - reg->val = adv7511_rd(sd, reg->reg & 0xff); - break; - case 1: - if (state->i2c_cec) { - reg->val = adv7511_cec_read(sd, reg->reg & 0xff); - break; - } - /* fall through */ - default: - v4l2_info(sd, "Register %03llx not supported\n", reg->reg); - adv7511_inv_register(sd); - break; - } - return 0; -} - -static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - switch (reg->reg >> 8) { - case 0: - adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff); - break; - case 1: - if (state->i2c_cec) { - adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff); - break; - } - /* fall through */ - default: - v4l2_info(sd, "Register %03llx not supported\n", reg->reg); - adv7511_inv_register(sd); - break; - } - return 0; -} -#endif - -struct adv7511_cfg_read_infoframe { - const char *desc; - u8 present_reg; - u8 present_mask; - u8 header[3]; - u16 payload_addr; -}; - -static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size) -{ - u8 csum = 0; - size_t i; - - /* compute checksum */ - for (i = 0; i < size; i++) - csum += ptr[i]; - - return 256 - csum; -} - -static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct device *dev = &client->dev; - union hdmi_infoframe frame; - u8 buffer[32]; - u8 len; - int i; - - if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) { - v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc); - return; - } - - memcpy(buffer, cri->header, sizeof(cri->header)); - - len = buffer[2]; - - if (len + 4 > sizeof(buffer)) { - v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len); - return; - } - - if (cri->payload_addr >= 0x100) { - for (i = 0; i < len; i++) - buffer[i + 4] = adv7511_pktmem_rd(sd, cri->payload_addr + i - 0x100); - } else { - for (i = 0; i < len; i++) - buffer[i + 4] = adv7511_rd(sd, cri->payload_addr + i); - } - buffer[3] = 0; - buffer[3] = hdmi_infoframe_checksum(buffer, len + 4); - - if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { - v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc); - return; - } - - hdmi_infoframe_log(KERN_INFO, dev, &frame); -} - -static void adv7511_log_infoframes(struct v4l2_subdev *sd) -{ - static const struct adv7511_cfg_read_infoframe cri[] = { - { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 }, - { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 }, - { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 }, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(cri); i++) - log_infoframe(sd, &cri[i]); -} - -static int adv7511_log_status(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - struct adv7511_state_edid *edid = &state->edid; - int i; - - static const char * const states[] = { - "in reset", - "reading EDID", - "idle", - "initializing HDCP", - "HDCP enabled", - "initializing HDCP repeater", - "6", "7", "8", "9", "A", "B", "C", "D", "E", "F" - }; - static const char * const errors[] = { - "no error", - "bad receiver BKSV", - "Ri mismatch", - "Pj mismatch", - "i2c error", - "timed out", - "max repeater cascade exceeded", - "hash check failed", - "too many devices", - "9", "A", "B", "C", "D", "E", "F" - }; - - v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off"); - v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n", - (adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT) ? "detected" : "no", - (adv7511_rd(sd, 0x42) & MASK_ADV7511_MSEN_DETECT) ? "detected" : "no", - edid->segments ? "found" : "no", - edid->blocks); - v4l2_info(sd, "%s output %s\n", - (adv7511_rd(sd, 0xaf) & 0x02) ? - "HDMI" : "DVI-D", - (adv7511_rd(sd, 0xa1) & 0x3c) ? - "disabled" : "enabled"); - v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n", - states[adv7511_rd(sd, 0xc8) & 0xf], - errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter, - adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96)); - v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full"); - if (adv7511_rd(sd, 0xaf) & 0x02) { - /* HDMI only */ - u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80; - u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 | - adv7511_rd(sd, 0x02) << 8 | - adv7511_rd(sd, 0x03); - u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2; - u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f; - u32 CTS; - - if (manual_cts) - CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 | - adv7511_rd(sd, 0x08) << 8 | - adv7511_rd(sd, 0x09); - else - CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 | - adv7511_rd(sd, 0x05) << 8 | - adv7511_rd(sd, 0x06); - v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n", - manual_cts ? "manual" : "automatic", N, CTS); - v4l2_info(sd, "VIC: detected %d, sent %d\n", - vic_detect, vic_sent); - adv7511_log_infoframes(sd); - } - if (state->dv_timings.type == V4L2_DV_BT_656_1120) - v4l2_print_dv_timings(sd->name, "timings: ", - &state->dv_timings, false); - else - v4l2_info(sd, "no timings set\n"); - v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr); - - if (state->i2c_cec == NULL) - return 0; - - v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr); - - v4l2_info(sd, "CEC: %s\n", state->cec_enabled_adap ? - "enabled" : "disabled"); - if (state->cec_enabled_adap) { - for (i = 0; i < ADV7511_MAX_ADDRS; i++) { - bool is_valid = state->cec_valid_addrs & (1 << i); - - if (is_valid) - v4l2_info(sd, "CEC Logical Address: 0x%x\n", - state->cec_addr[i]); - } - } - v4l2_info(sd, "i2c pktmem addr: 0x%x\n", state->i2c_pktmem_addr); - return 0; -} - -/* Power up/down adv7511 */ -static int adv7511_s_power(struct v4l2_subdev *sd, int on) -{ - struct adv7511_state *state = get_adv7511_state(sd); - const int retries = 20; - int i; - - v4l2_dbg(1, debug, sd, "%s: power %s\n", __func__, on ? "on" : "off"); - - state->power_on = on; - - if (!on) { - /* Power down */ - adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40); - return true; - } - - /* Power up */ - /* The adv7511 does not always come up immediately. - Retry multiple times. */ - for (i = 0; i < retries; i++) { - adv7511_wr_and_or(sd, 0x41, 0xbf, 0x0); - if ((adv7511_rd(sd, 0x41) & 0x40) == 0) - break; - adv7511_wr_and_or(sd, 0x41, 0xbf, 0x40); - msleep(10); - } - if (i == retries) { - v4l2_dbg(1, debug, sd, "%s: failed to powerup the adv7511!\n", __func__); - adv7511_s_power(sd, 0); - return false; - } - if (i > 1) - v4l2_dbg(1, debug, sd, "%s: needed %d retries to powerup the adv7511\n", __func__, i); - - /* Reserved registers that must be set */ - adv7511_wr(sd, 0x98, 0x03); - adv7511_wr_and_or(sd, 0x9a, 0xfe, 0x70); - adv7511_wr(sd, 0x9c, 0x30); - adv7511_wr_and_or(sd, 0x9d, 0xfc, 0x01); - adv7511_wr(sd, 0xa2, 0xa4); - adv7511_wr(sd, 0xa3, 0xa4); - adv7511_wr(sd, 0xe0, 0xd0); - adv7511_wr(sd, 0xf9, 0x00); - - adv7511_wr(sd, 0x43, state->i2c_edid_addr); - adv7511_wr(sd, 0x45, state->i2c_pktmem_addr); - - /* Set number of attempts to read the EDID */ - adv7511_wr(sd, 0xc9, 0xf); - return true; -} - -#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) -static int adv7511_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct adv7511_state *state = cec_get_drvdata(adap); - struct v4l2_subdev *sd = &state->sd; - - if (state->i2c_cec == NULL) - return -EIO; - - if (!state->cec_enabled_adap && enable) { - /* power up cec section */ - adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x01); - /* legacy mode and clear all rx buffers */ - adv7511_cec_write(sd, 0x4a, 0x00); - adv7511_cec_write(sd, 0x4a, 0x07); - adv7511_cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */ - /* enabled irqs: */ - /* tx: ready */ - /* tx: arbitration lost */ - /* tx: retry timeout */ - /* rx: ready 1 */ - if (state->enabled_irq) - adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39); - } else if (state->cec_enabled_adap && !enable) { - if (state->enabled_irq) - adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00); - /* disable address mask 1-3 */ - adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0x00); - /* power down cec section */ - adv7511_cec_write_and_or(sd, 0x4e, 0xfc, 0x00); - state->cec_valid_addrs = 0; - } - state->cec_enabled_adap = enable; - return 0; -} - -static int adv7511_cec_adap_log_addr(struct cec_adapter *adap, u8 addr) -{ - struct adv7511_state *state = cec_get_drvdata(adap); - struct v4l2_subdev *sd = &state->sd; - unsigned int i, free_idx = ADV7511_MAX_ADDRS; - - if (!state->cec_enabled_adap) - return addr == CEC_LOG_ADDR_INVALID ? 0 : -EIO; - - if (addr == CEC_LOG_ADDR_INVALID) { - adv7511_cec_write_and_or(sd, 0x4b, 0x8f, 0); - state->cec_valid_addrs = 0; - return 0; - } - - for (i = 0; i < ADV7511_MAX_ADDRS; i++) { - bool is_valid = state->cec_valid_addrs & (1 << i); - - if (free_idx == ADV7511_MAX_ADDRS && !is_valid) - free_idx = i; - if (is_valid && state->cec_addr[i] == addr) - return 0; - } - if (i == ADV7511_MAX_ADDRS) { - i = free_idx; - if (i == ADV7511_MAX_ADDRS) - return -ENXIO; - } - state->cec_addr[i] = addr; - state->cec_valid_addrs |= 1 << i; - - switch (i) { - case 0: - /* enable address mask 0 */ - adv7511_cec_write_and_or(sd, 0x4b, 0xef, 0x10); - /* set address for mask 0 */ - adv7511_cec_write_and_or(sd, 0x4c, 0xf0, addr); - break; - case 1: - /* enable address mask 1 */ - adv7511_cec_write_and_or(sd, 0x4b, 0xdf, 0x20); - /* set address for mask 1 */ - adv7511_cec_write_and_or(sd, 0x4c, 0x0f, addr << 4); - break; - case 2: - /* enable address mask 2 */ - adv7511_cec_write_and_or(sd, 0x4b, 0xbf, 0x40); - /* set address for mask 1 */ - adv7511_cec_write_and_or(sd, 0x4d, 0xf0, addr); - break; - } - return 0; -} - -static int adv7511_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct adv7511_state *state = cec_get_drvdata(adap); - struct v4l2_subdev *sd = &state->sd; - u8 len = msg->len; - unsigned int i; - - v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len); - - if (len > 16) { - v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len); - return -EINVAL; - } - - /* - * The number of retries is the number of attempts - 1, but retry - * at least once. It's not clear if a value of 0 is allowed, so - * let's do at least one retry. - */ - adv7511_cec_write_and_or(sd, 0x12, ~0x70, max(1, attempts - 1) << 4); - - /* clear cec tx irq status */ - adv7511_wr(sd, 0x97, 0x38); - - /* write data */ - for (i = 0; i < len; i++) - adv7511_cec_write(sd, i, msg->msg[i]); - - /* set length (data + header) */ - adv7511_cec_write(sd, 0x10, len); - /* start transmit, enable tx */ - adv7511_cec_write(sd, 0x11, 0x01); - return 0; -} - -static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - if ((adv7511_cec_read(sd, 0x11) & 0x01) == 0) { - v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__); - return; - } - - if (tx_raw_status & 0x10) { - v4l2_dbg(1, debug, sd, - "%s: tx raw: arbitration lost\n", __func__); - cec_transmit_done(state->cec_adap, CEC_TX_STATUS_ARB_LOST, - 1, 0, 0, 0); - return; - } - if (tx_raw_status & 0x08) { - u8 status; - u8 nack_cnt; - u8 low_drive_cnt; - - v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__); - /* - * We set this status bit since this hardware performs - * retransmissions. - */ - status = CEC_TX_STATUS_MAX_RETRIES; - nack_cnt = adv7511_cec_read(sd, 0x14) & 0xf; - if (nack_cnt) - status |= CEC_TX_STATUS_NACK; - low_drive_cnt = adv7511_cec_read(sd, 0x14) >> 4; - if (low_drive_cnt) - status |= CEC_TX_STATUS_LOW_DRIVE; - cec_transmit_done(state->cec_adap, status, - 0, nack_cnt, low_drive_cnt, 0); - return; - } - if (tx_raw_status & 0x20) { - v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__); - cec_transmit_done(state->cec_adap, CEC_TX_STATUS_OK, 0, 0, 0, 0); - return; - } -} - -static const struct cec_adap_ops adv7511_cec_adap_ops = { - .adap_enable = adv7511_cec_adap_enable, - .adap_log_addr = adv7511_cec_adap_log_addr, - .adap_transmit = adv7511_cec_adap_transmit, -}; -#endif - -/* Enable interrupts */ -static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable) -{ - struct adv7511_state *state = get_adv7511_state(sd); - u8 irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT; - u8 irqs_rd; - int retries = 100; - - v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable"); - - if (state->enabled_irq == enable) - return; - state->enabled_irq = enable; - - /* The datasheet says that the EDID ready interrupt should be - disabled if there is no hotplug. */ - if (!enable) - irqs = 0; - else if (adv7511_have_hotplug(sd)) - irqs |= MASK_ADV7511_EDID_RDY_INT; - - /* - * This i2c write can fail (approx. 1 in 1000 writes). But it - * is essential that this register is correct, so retry it - * multiple times. - * - * Note that the i2c write does not report an error, but the readback - * clearly shows the wrong value. - */ - do { - adv7511_wr(sd, 0x94, irqs); - irqs_rd = adv7511_rd(sd, 0x94); - } while (retries-- && irqs_rd != irqs); - - if (irqs_rd != irqs) - v4l2_err(sd, "Could not set interrupts: hw failure?\n"); - - adv7511_wr_and_or(sd, 0x95, 0xc0, - (state->cec_enabled_adap && enable) ? 0x39 : 0x00); -} - -/* Interrupt handler */ -static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled) -{ - u8 irq_status; - u8 cec_irq; - - /* disable interrupts to prevent a race condition */ - adv7511_set_isr(sd, false); - irq_status = adv7511_rd(sd, 0x96); - cec_irq = adv7511_rd(sd, 0x97); - /* clear detected interrupts */ - adv7511_wr(sd, 0x96, irq_status); - adv7511_wr(sd, 0x97, cec_irq); - - v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__, - irq_status, cec_irq); - - if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT)) - adv7511_check_monitor_present_status(sd); - if (irq_status & MASK_ADV7511_EDID_RDY_INT) - adv7511_check_edid_status(sd); - -#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) - if (cec_irq & 0x38) - adv_cec_tx_raw_status(sd, cec_irq); - - if (cec_irq & 1) { - struct adv7511_state *state = get_adv7511_state(sd); - struct cec_msg msg; - - msg.len = adv7511_cec_read(sd, 0x25) & 0x1f; - - v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__, - msg.len); - - if (msg.len > 16) - msg.len = 16; - - if (msg.len) { - u8 i; - - for (i = 0; i < msg.len; i++) - msg.msg[i] = adv7511_cec_read(sd, i + 0x15); - - adv7511_cec_write(sd, 0x4a, 0); /* toggle to re-enable rx 1 */ - adv7511_cec_write(sd, 0x4a, 1); - cec_received_msg(state->cec_adap, &msg); - } - } -#endif - - /* enable interrupts */ - adv7511_set_isr(sd, true); - - if (handled) - *handled = true; - return 0; -} - -static const struct v4l2_subdev_core_ops adv7511_core_ops = { - .log_status = adv7511_log_status, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = adv7511_g_register, - .s_register = adv7511_s_register, -#endif - .s_power = adv7511_s_power, - .interrupt_service_routine = adv7511_isr, -}; - -/* ------------------------------ VIDEO OPS ------------------------------ */ - -/* Enable/disable adv7511 output */ -static int adv7511_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); - adv7511_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c)); - if (enable) { - adv7511_check_monitor_present_status(sd); - } else { - adv7511_s_power(sd, 0); - state->have_monitor = false; - } - return 0; -} - -static int adv7511_s_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) -{ - struct adv7511_state *state = get_adv7511_state(sd); - struct v4l2_bt_timings *bt = &timings->bt; - u32 fps; - - v4l2_dbg(1, debug, sd, "%s:\n", __func__); - - /* quick sanity check */ - if (!v4l2_valid_dv_timings(timings, &adv7511_timings_cap, NULL, NULL)) - return -EINVAL; - - /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings - if the format is one of the CEA or DMT timings. */ - v4l2_find_dv_timings_cap(timings, &adv7511_timings_cap, 0, NULL, NULL); - - /* save timings */ - state->dv_timings = *timings; - - /* set h/vsync polarities */ - adv7511_wr_and_or(sd, 0x17, 0x9f, - ((bt->polarities & V4L2_DV_VSYNC_POS_POL) ? 0 : 0x40) | - ((bt->polarities & V4L2_DV_HSYNC_POS_POL) ? 0 : 0x20)); - - fps = (u32)bt->pixelclock / (V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt)); - switch (fps) { - case 24: - adv7511_wr_and_or(sd, 0xfb, 0xf9, 1 << 1); - break; - case 25: - adv7511_wr_and_or(sd, 0xfb, 0xf9, 2 << 1); - break; - case 30: - adv7511_wr_and_or(sd, 0xfb, 0xf9, 3 << 1); - break; - default: - adv7511_wr_and_or(sd, 0xfb, 0xf9, 0); - break; - } - - /* update quantization range based on new dv_timings */ - adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); - - return 0; -} - -static int adv7511_g_dv_timings(struct v4l2_subdev *sd, - struct v4l2_dv_timings *timings) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - v4l2_dbg(1, debug, sd, "%s:\n", __func__); - - if (!timings) - return -EINVAL; - - *timings = state->dv_timings; - - return 0; -} - -static int adv7511_enum_dv_timings(struct v4l2_subdev *sd, - struct v4l2_enum_dv_timings *timings) -{ - if (timings->pad != 0) - return -EINVAL; - - return v4l2_enum_dv_timings_cap(timings, &adv7511_timings_cap, NULL, NULL); -} - -static int adv7511_dv_timings_cap(struct v4l2_subdev *sd, - struct v4l2_dv_timings_cap *cap) -{ - if (cap->pad != 0) - return -EINVAL; - - *cap = adv7511_timings_cap; - return 0; -} - -static const struct v4l2_subdev_video_ops adv7511_video_ops = { - .s_stream = adv7511_s_stream, - .s_dv_timings = adv7511_s_dv_timings, - .g_dv_timings = adv7511_g_dv_timings, -}; - -/* ------------------------------ AUDIO OPS ------------------------------ */ -static int adv7511_s_audio_stream(struct v4l2_subdev *sd, int enable) -{ - v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis")); - - if (enable) - adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x80); - else - adv7511_wr_and_or(sd, 0x4b, 0x3f, 0x40); - - return 0; -} - -static int adv7511_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - u32 N; - - switch (freq) { - case 32000: N = 4096; break; - case 44100: N = 6272; break; - case 48000: N = 6144; break; - case 88200: N = 12544; break; - case 96000: N = 12288; break; - case 176400: N = 25088; break; - case 192000: N = 24576; break; - default: - return -EINVAL; - } - - /* Set N (used with CTS to regenerate the audio clock) */ - adv7511_wr(sd, 0x01, (N >> 16) & 0xf); - adv7511_wr(sd, 0x02, (N >> 8) & 0xff); - adv7511_wr(sd, 0x03, N & 0xff); - - return 0; -} - -static int adv7511_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - u32 i2s_sf; - - switch (freq) { - case 32000: i2s_sf = 0x30; break; - case 44100: i2s_sf = 0x00; break; - case 48000: i2s_sf = 0x20; break; - case 88200: i2s_sf = 0x80; break; - case 96000: i2s_sf = 0xa0; break; - case 176400: i2s_sf = 0xc0; break; - case 192000: i2s_sf = 0xe0; break; - default: - return -EINVAL; - } - - /* Set sampling frequency for I2S audio to 48 kHz */ - adv7511_wr_and_or(sd, 0x15, 0xf, i2s_sf); - - return 0; -} - -static int adv7511_s_routing(struct v4l2_subdev *sd, u32 input, u32 output, u32 config) -{ - /* Only 2 channels in use for application */ - adv7511_wr_and_or(sd, 0x73, 0xf8, 0x1); - /* Speaker mapping */ - adv7511_wr(sd, 0x76, 0x00); - - /* 16 bit audio word length */ - adv7511_wr_and_or(sd, 0x14, 0xf0, 0x02); - - return 0; -} - -static const struct v4l2_subdev_audio_ops adv7511_audio_ops = { - .s_stream = adv7511_s_audio_stream, - .s_clock_freq = adv7511_s_clock_freq, - .s_i2s_clock_freq = adv7511_s_i2s_clock_freq, - .s_routing = adv7511_s_routing, -}; - -/* ---------------------------- PAD OPS ------------------------------------- */ - -static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - memset(edid->reserved, 0, sizeof(edid->reserved)); - - if (edid->pad != 0) - return -EINVAL; - - if (edid->start_block == 0 && edid->blocks == 0) { - edid->blocks = state->edid.segments * 2; - return 0; - } - - if (state->edid.segments == 0) - return -ENODATA; - - if (edid->start_block >= state->edid.segments * 2) - return -EINVAL; - - if (edid->start_block + edid->blocks > state->edid.segments * 2) - edid->blocks = state->edid.segments * 2 - edid->start_block; - - memcpy(edid->edid, &state->edid.data[edid->start_block * 128], - 128 * edid->blocks); - - return 0; -} - -static int adv7511_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad != 0) - return -EINVAL; - - switch (code->index) { - case 0: - code->code = MEDIA_BUS_FMT_RGB888_1X24; - break; - case 1: - code->code = MEDIA_BUS_FMT_YUYV8_1X16; - break; - case 2: - code->code = MEDIA_BUS_FMT_UYVY8_1X16; - break; - default: - return -EINVAL; - } - return 0; -} - -static void adv7511_fill_format(struct adv7511_state *state, - struct v4l2_mbus_framefmt *format) -{ - format->width = state->dv_timings.bt.width; - format->height = state->dv_timings.bt.height; - format->field = V4L2_FIELD_NONE; -} - -static int adv7511_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - if (format->pad != 0) - return -EINVAL; - - memset(&format->format, 0, sizeof(format->format)); - adv7511_fill_format(state, &format->format); - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *fmt; - - fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); - format->format.code = fmt->code; - format->format.colorspace = fmt->colorspace; - format->format.ycbcr_enc = fmt->ycbcr_enc; - format->format.quantization = fmt->quantization; - format->format.xfer_func = fmt->xfer_func; - } else { - format->format.code = state->fmt_code; - format->format.colorspace = state->colorspace; - format->format.ycbcr_enc = state->ycbcr_enc; - format->format.quantization = state->quantization; - format->format.xfer_func = state->xfer_func; - } - - return 0; -} - -static int adv7511_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct adv7511_state *state = get_adv7511_state(sd); - /* - * Bitfield namings come the CEA-861-F standard, table 8 "Auxiliary - * Video Information (AVI) InfoFrame Format" - * - * c = Colorimetry - * ec = Extended Colorimetry - * y = RGB or YCbCr - * q = RGB Quantization Range - * yq = YCC Quantization Range - */ - u8 c = HDMI_COLORIMETRY_NONE; - u8 ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - u8 y = HDMI_COLORSPACE_RGB; - u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT; - u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED; - u8 itc = state->content_type != V4L2_DV_IT_CONTENT_TYPE_NO_ITC; - u8 cn = itc ? state->content_type : V4L2_DV_IT_CONTENT_TYPE_GRAPHICS; - - if (format->pad != 0) - return -EINVAL; - switch (format->format.code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - case MEDIA_BUS_FMT_YUYV8_1X16: - case MEDIA_BUS_FMT_RGB888_1X24: - break; - default: - return -EINVAL; - } - - adv7511_fill_format(state, &format->format); - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *fmt; - - fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); - fmt->code = format->format.code; - fmt->colorspace = format->format.colorspace; - fmt->ycbcr_enc = format->format.ycbcr_enc; - fmt->quantization = format->format.quantization; - fmt->xfer_func = format->format.xfer_func; - return 0; - } - - switch (format->format.code) { - case MEDIA_BUS_FMT_UYVY8_1X16: - adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01); - adv7511_wr_and_or(sd, 0x16, 0x03, 0xb8); - y = HDMI_COLORSPACE_YUV422; - break; - case MEDIA_BUS_FMT_YUYV8_1X16: - adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01); - adv7511_wr_and_or(sd, 0x16, 0x03, 0xbc); - y = HDMI_COLORSPACE_YUV422; - break; - case MEDIA_BUS_FMT_RGB888_1X24: - default: - adv7511_wr_and_or(sd, 0x15, 0xf0, 0x00); - adv7511_wr_and_or(sd, 0x16, 0x03, 0x00); - break; - } - state->fmt_code = format->format.code; - state->colorspace = format->format.colorspace; - state->ycbcr_enc = format->format.ycbcr_enc; - state->quantization = format->format.quantization; - state->xfer_func = format->format.xfer_func; - - switch (format->format.colorspace) { - case V4L2_COLORSPACE_OPRGB: - c = HDMI_COLORIMETRY_EXTENDED; - ec = y ? HDMI_EXTENDED_COLORIMETRY_OPYCC_601 : - HDMI_EXTENDED_COLORIMETRY_OPRGB; - break; - case V4L2_COLORSPACE_SMPTE170M: - c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE; - if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV601) { - c = HDMI_COLORIMETRY_EXTENDED; - ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - } - break; - case V4L2_COLORSPACE_REC709: - c = y ? HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_NONE; - if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV709) { - c = HDMI_COLORIMETRY_EXTENDED; - ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709; - } - break; - case V4L2_COLORSPACE_SRGB: - c = y ? HDMI_COLORIMETRY_EXTENDED : HDMI_COLORIMETRY_NONE; - ec = y ? HDMI_EXTENDED_COLORIMETRY_S_YCC_601 : - HDMI_EXTENDED_COLORIMETRY_XV_YCC_601; - break; - case V4L2_COLORSPACE_BT2020: - c = HDMI_COLORIMETRY_EXTENDED; - if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM) - ec = 5; /* Not yet available in hdmi.h */ - else - ec = 6; /* Not yet available in hdmi.h */ - break; - default: - break; - } - - /* - * CEA-861-F says that for RGB formats the YCC range must match the - * RGB range, although sources should ignore the YCC range. - * - * The RGB quantization range shouldn't be non-zero if the EDID doesn't - * have the Q bit set in the Video Capabilities Data Block, however this - * isn't checked at the moment. The assumption is that the application - * knows the EDID and can detect this. - * - * The same is true for the YCC quantization range: non-standard YCC - * quantization ranges should only be sent if the EDID has the YQ bit - * set in the Video Capabilities Data Block. - */ - switch (format->format.quantization) { - case V4L2_QUANTIZATION_FULL_RANGE: - q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT : - HDMI_QUANTIZATION_RANGE_FULL; - yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_FULL; - break; - case V4L2_QUANTIZATION_LIM_RANGE: - q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT : - HDMI_QUANTIZATION_RANGE_LIMITED; - yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_LIMITED; - break; - } - - adv7511_wr_and_or(sd, 0x4a, 0xbf, 0); - adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5); - adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6); - adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2) | (itc << 7)); - adv7511_wr_and_or(sd, 0x59, 0x0f, (yq << 6) | (cn << 4)); - adv7511_wr_and_or(sd, 0x4a, 0xff, 1); - adv7511_set_rgb_quantization_mode(sd, state->rgb_quantization_range_ctrl); - - return 0; -} - -static const struct v4l2_subdev_pad_ops adv7511_pad_ops = { - .get_edid = adv7511_get_edid, - .enum_mbus_code = adv7511_enum_mbus_code, - .get_fmt = adv7511_get_fmt, - .set_fmt = adv7511_set_fmt, - .enum_dv_timings = adv7511_enum_dv_timings, - .dv_timings_cap = adv7511_dv_timings_cap, -}; - -/* --------------------- SUBDEV OPS --------------------------------------- */ - -static const struct v4l2_subdev_ops adv7511_ops = { - .core = &adv7511_core_ops, - .pad = &adv7511_pad_ops, - .video = &adv7511_video_ops, - .audio = &adv7511_audio_ops, -}; - -/* ----------------------------------------------------------------------- */ -static void adv7511_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd, int segment, u8 *buf) -{ - if (debug >= lvl) { - int i, j; - v4l2_dbg(lvl, debug, sd, "edid segment %d\n", segment); - for (i = 0; i < 256; i += 16) { - u8 b[128]; - u8 *bp = b; - if (i == 128) - v4l2_dbg(lvl, debug, sd, "\n"); - for (j = i; j < i + 16; j++) { - sprintf(bp, "0x%02x, ", buf[j]); - bp += 6; - } - bp[0] = '\0'; - v4l2_dbg(lvl, debug, sd, "%s\n", b); - } - } -} - -static void adv7511_notify_no_edid(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - struct adv7511_edid_detect ed; - - /* We failed to read the EDID, so send an event for this. */ - ed.present = false; - ed.segment = adv7511_rd(sd, 0xc4); - ed.phys_addr = CEC_PHYS_ADDR_INVALID; - cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); - v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); - v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x0); -} - -static void adv7511_edid_handler(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct adv7511_state *state = container_of(dwork, struct adv7511_state, edid_handler); - struct v4l2_subdev *sd = &state->sd; - - v4l2_dbg(1, debug, sd, "%s:\n", __func__); - - if (adv7511_check_edid_status(sd)) { - /* Return if we received the EDID. */ - return; - } - - if (adv7511_have_hotplug(sd)) { - /* We must retry reading the EDID several times, it is possible - * that initially the EDID couldn't be read due to i2c errors - * (DVI connectors are particularly prone to this problem). */ - if (state->edid.read_retries) { - state->edid.read_retries--; - v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__); - state->have_monitor = false; - adv7511_s_power(sd, false); - adv7511_s_power(sd, true); - queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); - return; - } - } - - /* We failed to read the EDID, so send an event for this. */ - adv7511_notify_no_edid(sd); - v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__); -} - -static void adv7511_audio_setup(struct v4l2_subdev *sd) -{ - v4l2_dbg(1, debug, sd, "%s\n", __func__); - - adv7511_s_i2s_clock_freq(sd, 48000); - adv7511_s_clock_freq(sd, 48000); - adv7511_s_routing(sd, 0, 0, 0); -} - -/* Configure hdmi transmitter. */ -static void adv7511_setup(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - v4l2_dbg(1, debug, sd, "%s\n", __func__); - - /* Input format: RGB 4:4:4 */ - adv7511_wr_and_or(sd, 0x15, 0xf0, 0x0); - /* Output format: RGB 4:4:4 */ - adv7511_wr_and_or(sd, 0x16, 0x7f, 0x0); - /* 1st order interpolation 4:2:2 -> 4:4:4 up conversion, Aspect ratio: 16:9 */ - adv7511_wr_and_or(sd, 0x17, 0xf9, 0x06); - /* Disable pixel repetition */ - adv7511_wr_and_or(sd, 0x3b, 0x9f, 0x0); - /* Disable CSC */ - adv7511_wr_and_or(sd, 0x18, 0x7f, 0x0); - /* Output format: RGB 4:4:4, Active Format Information is valid, - * underscanned */ - adv7511_wr_and_or(sd, 0x55, 0x9c, 0x12); - /* AVI Info frame packet enable, Audio Info frame disable */ - adv7511_wr_and_or(sd, 0x44, 0xe7, 0x10); - /* Colorimetry, Active format aspect ratio: same as picure. */ - adv7511_wr(sd, 0x56, 0xa8); - /* No encryption */ - adv7511_wr_and_or(sd, 0xaf, 0xed, 0x0); - - /* Positive clk edge capture for input video clock */ - adv7511_wr_and_or(sd, 0xba, 0x1f, 0x60); - - adv7511_audio_setup(sd); - - v4l2_ctrl_handler_setup(&state->hdl); -} - -static void adv7511_notify_monitor_detect(struct v4l2_subdev *sd) -{ - struct adv7511_monitor_detect mdt; - struct adv7511_state *state = get_adv7511_state(sd); - - mdt.present = state->have_monitor; - v4l2_subdev_notify(sd, ADV7511_MONITOR_DETECT, (void *)&mdt); -} - -static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - /* read hotplug and rx-sense state */ - u8 status = adv7511_rd(sd, 0x42); - - v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n", - __func__, - status, - status & MASK_ADV7511_HPD_DETECT ? ", hotplug" : "", - status & MASK_ADV7511_MSEN_DETECT ? ", rx-sense" : ""); - - /* update read only ctrls */ - v4l2_ctrl_s_ctrl(state->hotplug_ctrl, adv7511_have_hotplug(sd) ? 0x1 : 0x0); - v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, adv7511_have_rx_sense(sd) ? 0x1 : 0x0); - - if ((status & MASK_ADV7511_HPD_DETECT) && ((status & MASK_ADV7511_MSEN_DETECT) || state->edid.segments)) { - v4l2_dbg(1, debug, sd, "%s: hotplug and (rx-sense or edid)\n", __func__); - if (!state->have_monitor) { - v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__); - state->have_monitor = true; - adv7511_set_isr(sd, true); - if (!adv7511_s_power(sd, true)) { - v4l2_dbg(1, debug, sd, "%s: monitor detected, powerup failed\n", __func__); - return; - } - adv7511_setup(sd); - adv7511_notify_monitor_detect(sd); - state->edid.read_retries = EDID_MAX_RETRIES; - queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); - } - } else if (status & MASK_ADV7511_HPD_DETECT) { - v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__); - state->edid.read_retries = EDID_MAX_RETRIES; - queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); - } else if (!(status & MASK_ADV7511_HPD_DETECT)) { - v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__); - if (state->have_monitor) { - v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__); - state->have_monitor = false; - adv7511_notify_monitor_detect(sd); - } - adv7511_s_power(sd, false); - memset(&state->edid, 0, sizeof(struct adv7511_state_edid)); - adv7511_notify_no_edid(sd); - } -} - -static bool edid_block_verify_crc(u8 *edid_block) -{ - u8 sum = 0; - int i; - - for (i = 0; i < 128; i++) - sum += edid_block[i]; - return sum == 0; -} - -static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment) -{ - struct adv7511_state *state = get_adv7511_state(sd); - u32 blocks = state->edid.blocks; - u8 *data = state->edid.data; - - if (!edid_block_verify_crc(&data[segment * 256])) - return false; - if ((segment + 1) * 2 <= blocks) - return edid_block_verify_crc(&data[segment * 256 + 128]); - return true; -} - -static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment) -{ - static const u8 hdmi_header[] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 - }; - struct adv7511_state *state = get_adv7511_state(sd); - u8 *data = state->edid.data; - - if (segment != 0) - return true; - return !memcmp(data, hdmi_header, sizeof(hdmi_header)); -} - -static bool adv7511_check_edid_status(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - u8 edidRdy = adv7511_rd(sd, 0xc5); - - v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n", - __func__, EDID_MAX_RETRIES - state->edid.read_retries); - - if (state->edid.complete) - return true; - - if (edidRdy & MASK_ADV7511_EDID_RDY) { - int segment = adv7511_rd(sd, 0xc4); - struct adv7511_edid_detect ed; - - if (segment >= EDID_MAX_SEGM) { - v4l2_err(sd, "edid segment number too big\n"); - return false; - } - v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment); - adv7511_edid_rd(sd, 256, &state->edid.data[segment * 256]); - adv7511_dbg_dump_edid(2, debug, sd, segment, &state->edid.data[segment * 256]); - if (segment == 0) { - state->edid.blocks = state->edid.data[0x7e] + 1; - v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks); - } - if (!edid_verify_crc(sd, segment) || - !edid_verify_header(sd, segment)) { - /* edid crc error, force reread of edid segment */ - v4l2_err(sd, "%s: edid crc or header error\n", __func__); - state->have_monitor = false; - adv7511_s_power(sd, false); - adv7511_s_power(sd, true); - return false; - } - /* one more segment read ok */ - state->edid.segments = segment + 1; - v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, 0x1); - if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) { - /* Request next EDID segment */ - v4l2_dbg(1, debug, sd, "%s: request segment %d\n", __func__, state->edid.segments); - adv7511_wr(sd, 0xc9, 0xf); - adv7511_wr(sd, 0xc4, state->edid.segments); - state->edid.read_retries = EDID_MAX_RETRIES; - queue_delayed_work(state->work_queue, &state->edid_handler, EDID_DELAY); - return false; - } - - v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments); - state->edid.complete = true; - ed.phys_addr = cec_get_edid_phys_addr(state->edid.data, - state->edid.segments * 256, - NULL); - /* report when we have all segments - but report only for segment 0 - */ - ed.present = true; - ed.segment = 0; - state->edid_detect_counter++; - cec_s_phys_addr(state->cec_adap, ed.phys_addr, false); - v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed); - return ed.present; - } - - return false; -} - -static int adv7511_registered(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); - int err; - - err = cec_register_adapter(state->cec_adap, &client->dev); - if (err) - cec_delete_adapter(state->cec_adap); - return err; -} - -static void adv7511_unregistered(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - - cec_unregister_adapter(state->cec_adap); -} - -static const struct v4l2_subdev_internal_ops adv7511_int_ops = { - .registered = adv7511_registered, - .unregistered = adv7511_unregistered, -}; - -/* ----------------------------------------------------------------------- */ -/* Setup ADV7511 */ -static void adv7511_init_setup(struct v4l2_subdev *sd) -{ - struct adv7511_state *state = get_adv7511_state(sd); - struct adv7511_state_edid *edid = &state->edid; - u32 cec_clk = state->pdata.cec_clk; - u8 ratio; - - v4l2_dbg(1, debug, sd, "%s\n", __func__); - - /* clear all interrupts */ - adv7511_wr(sd, 0x96, 0xff); - adv7511_wr(sd, 0x97, 0xff); - /* - * Stop HPD from resetting a lot of registers. - * It might leave the chip in a partly un-initialized state, - * in particular with regards to hotplug bounces. - */ - adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0); - memset(edid, 0, sizeof(struct adv7511_state_edid)); - state->have_monitor = false; - adv7511_set_isr(sd, false); - adv7511_s_stream(sd, false); - adv7511_s_audio_stream(sd, false); - - if (state->i2c_cec == NULL) - return; - - v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk); - - /* cec soft reset */ - adv7511_cec_write(sd, 0x50, 0x01); - adv7511_cec_write(sd, 0x50, 0x00); - - /* legacy mode */ - adv7511_cec_write(sd, 0x4a, 0x00); - adv7511_cec_write(sd, 0x4a, 0x07); - - if (cec_clk % 750000 != 0) - v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n", - __func__, cec_clk); - - ratio = (cec_clk / 750000) - 1; - adv7511_cec_write(sd, 0x4e, ratio << 2); -} - -static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id) -{ - struct adv7511_state *state; - struct adv7511_platform_data *pdata = client->dev.platform_data; - struct v4l2_ctrl_handler *hdl; - struct v4l2_subdev *sd; - u8 chip_id[2]; - int err = -EIO; - - /* Check if the adapter supports the needed features */ - if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EIO; - - state = devm_kzalloc(&client->dev, sizeof(struct adv7511_state), GFP_KERNEL); - if (!state) - return -ENOMEM; - - /* Platform data */ - if (!pdata) { - v4l_err(client, "No platform data!\n"); - return -ENODEV; - } - memcpy(&state->pdata, pdata, sizeof(state->pdata)); - state->fmt_code = MEDIA_BUS_FMT_RGB888_1X24; - state->colorspace = V4L2_COLORSPACE_SRGB; - - sd = &state->sd; - - v4l2_dbg(1, debug, sd, "detecting adv7511 client on address 0x%x\n", - client->addr << 1); - - v4l2_i2c_subdev_init(sd, client, &adv7511_ops); - sd->internal_ops = &adv7511_int_ops; - - hdl = &state->hdl; - v4l2_ctrl_handler_init(hdl, 10); - /* add in ascending ID order */ - state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops, - V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, - 0, V4L2_DV_TX_MODE_DVI_D); - state->hotplug_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_TX_HOTPLUG, 0, 1, 0, 0); - state->rx_sense_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_TX_RXSENSE, 0, 1, 0, 0); - state->have_edid0_ctrl = v4l2_ctrl_new_std(hdl, NULL, - V4L2_CID_DV_TX_EDID_PRESENT, 0, 1, 0, 0); - state->rgb_quantization_range_ctrl = - v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops, - V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, - 0, V4L2_DV_RGB_RANGE_AUTO); - state->content_type_ctrl = - v4l2_ctrl_new_std_menu(hdl, &adv7511_ctrl_ops, - V4L2_CID_DV_TX_IT_CONTENT_TYPE, V4L2_DV_IT_CONTENT_TYPE_NO_ITC, - 0, V4L2_DV_IT_CONTENT_TYPE_NO_ITC); - sd->ctrl_handler = hdl; - if (hdl->error) { - err = hdl->error; - goto err_hdl; - } - state->pad.flags = MEDIA_PAD_FL_SINK; - sd->entity.function = MEDIA_ENT_F_DV_ENCODER; - err = media_entity_pads_init(&sd->entity, 1, &state->pad); - if (err) - goto err_hdl; - - /* EDID and CEC i2c addr */ - state->i2c_edid_addr = state->pdata.i2c_edid << 1; - state->i2c_cec_addr = state->pdata.i2c_cec << 1; - state->i2c_pktmem_addr = state->pdata.i2c_pktmem << 1; - - state->chip_revision = adv7511_rd(sd, 0x0); - chip_id[0] = adv7511_rd(sd, 0xf5); - chip_id[1] = adv7511_rd(sd, 0xf6); - if (chip_id[0] != 0x75 || chip_id[1] != 0x11) { - v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], - chip_id[1]); - err = -EIO; - goto err_entity; - } - - state->i2c_edid = i2c_new_dummy(client->adapter, - state->i2c_edid_addr >> 1); - if (state->i2c_edid == NULL) { - v4l2_err(sd, "failed to register edid i2c client\n"); - err = -ENOMEM; - goto err_entity; - } - - adv7511_wr(sd, 0xe1, state->i2c_cec_addr); - if (state->pdata.cec_clk < 3000000 || - state->pdata.cec_clk > 100000000) { - v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n", - __func__, state->pdata.cec_clk); - state->pdata.cec_clk = 0; - } - - if (state->pdata.cec_clk) { - state->i2c_cec = i2c_new_dummy(client->adapter, - state->i2c_cec_addr >> 1); - if (state->i2c_cec == NULL) { - v4l2_err(sd, "failed to register cec i2c client\n"); - err = -ENOMEM; - goto err_unreg_edid; - } - adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */ - } else { - adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */ - } - - state->i2c_pktmem = i2c_new_dummy(client->adapter, state->i2c_pktmem_addr >> 1); - if (state->i2c_pktmem == NULL) { - v4l2_err(sd, "failed to register pktmem i2c client\n"); - err = -ENOMEM; - goto err_unreg_cec; - } - - state->work_queue = create_singlethread_workqueue(sd->name); - if (state->work_queue == NULL) { - v4l2_err(sd, "could not create workqueue\n"); - err = -ENOMEM; - goto err_unreg_pktmem; - } - - INIT_DELAYED_WORK(&state->edid_handler, adv7511_edid_handler); - - adv7511_init_setup(sd); - -#if IS_ENABLED(CONFIG_VIDEO_ADV7511_CEC) - state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, - state, dev_name(&client->dev), CEC_CAP_DEFAULTS, - ADV7511_MAX_ADDRS); - err = PTR_ERR_OR_ZERO(state->cec_adap); - if (err) { - destroy_workqueue(state->work_queue); - goto err_unreg_pktmem; - } -#endif - - adv7511_set_isr(sd, true); - adv7511_check_monitor_present_status(sd); - - v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, - client->addr << 1, client->adapter->name); - return 0; - -err_unreg_pktmem: - i2c_unregister_device(state->i2c_pktmem); -err_unreg_cec: - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); -err_unreg_edid: - i2c_unregister_device(state->i2c_edid); -err_entity: - media_entity_cleanup(&sd->entity); -err_hdl: - v4l2_ctrl_handler_free(&state->hdl); - return err; -} - -/* ----------------------------------------------------------------------- */ - -static int adv7511_remove(struct i2c_client *client) -{ - struct v4l2_subdev *sd = i2c_get_clientdata(client); - struct adv7511_state *state = get_adv7511_state(sd); - - state->chip_revision = -1; - - v4l2_dbg(1, debug, sd, "%s removed @ 0x%x (%s)\n", client->name, - client->addr << 1, client->adapter->name); - - adv7511_set_isr(sd, false); - adv7511_init_setup(sd); - cancel_delayed_work(&state->edid_handler); - i2c_unregister_device(state->i2c_edid); - if (state->i2c_cec) - i2c_unregister_device(state->i2c_cec); - i2c_unregister_device(state->i2c_pktmem); - destroy_workqueue(state->work_queue); - v4l2_device_unregister_subdev(sd); - media_entity_cleanup(&sd->entity); - v4l2_ctrl_handler_free(sd->ctrl_handler); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static const struct i2c_device_id adv7511_id[] = { - { "adv7511", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, adv7511_id); - -static struct i2c_driver adv7511_driver = { - .driver = { - .name = "adv7511", - }, - .probe = adv7511_probe, - .remove = adv7511_remove, - .id_table = adv7511_id, -}; - -module_i2c_driver(adv7511_driver); -- cgit v1.2.3-59-g8ed1b From a244fabc15ffba245f80fd49ab486b9881e9e6de Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:40 -0400 Subject: media: rcar-vin: Do not call pm_runtime_{resume,suspend}() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver does not implement runtime resume and suspend function so there is little point in trying to call them. This is a leftover from the drivers soc_camera beginnings. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 7cbdcbf9b090..b821ea01786e 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -798,9 +798,6 @@ static int rvin_initialize_device(struct file *file) return ret; pm_runtime_enable(&vin->vdev.dev); - ret = pm_runtime_resume(&vin->vdev.dev); - if (ret < 0 && ret != -ENOSYS) - goto eresume; /* * Try to configure with default parameters. Notice: this is the @@ -817,7 +814,6 @@ static int rvin_initialize_device(struct file *file) return 0; esfmt: pm_runtime_disable(&vin->vdev.dev); -eresume: rvin_power_off(vin); return ret; @@ -868,7 +864,6 @@ static int rvin_release(struct file *file) * Then de-initialize hw module. */ if (fh_singular) { - pm_runtime_suspend(&vin->vdev.dev); pm_runtime_disable(&vin->vdev.dev); rvin_power_off(vin); } -- cgit v1.2.3-59-g8ed1b From b2ef816c3db01f365448e8623c4f1d51cc2ba610 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:41 -0400 Subject: media: rcar-vin: Remove unneeded calls to pm_runtime_{enable, disable} MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Runtime PM is already enabled unconditionally when the driver is probed and disabled when it's removed. There is no point in doing it again for Gen2 when opening and closing the video device. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index b821ea01786e..0841f1a0bfd7 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -797,8 +797,6 @@ static int rvin_initialize_device(struct file *file) if (ret < 0) return ret; - pm_runtime_enable(&vin->vdev.dev); - /* * Try to configure with default parameters. Notice: this is the * very first open, so, we cannot race against other calls, @@ -813,7 +811,6 @@ static int rvin_initialize_device(struct file *file) return 0; esfmt: - pm_runtime_disable(&vin->vdev.dev); rvin_power_off(vin); return ret; @@ -863,10 +860,8 @@ static int rvin_release(struct file *file) * If this was the last open file. * Then de-initialize hw module. */ - if (fh_singular) { - pm_runtime_disable(&vin->vdev.dev); + if (fh_singular) rvin_power_off(vin); - } mutex_unlock(&vin->lock); -- cgit v1.2.3-59-g8ed1b From 11492ee7cbfec989caf319bc299f0004b8a23e01 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:42 -0400 Subject: media: rcar-vin: Allow interrupting lock when trying to open the video device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The user should be allowed to break waiting for the lock when opening the video device. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 0841f1a0bfd7..f67cef97b89a 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -821,7 +821,9 @@ static int rvin_open(struct file *file) struct rvin_dev *vin = video_drvdata(file); int ret; - mutex_lock(&vin->lock); + ret = mutex_lock_interruptible(&vin->lock); + if (ret) + return ret; file->private_data = vin; -- cgit v1.2.3-59-g8ed1b From 4e4ef86f522d36771396e96e2a6b7ac22cb2dae2 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:43 -0400 Subject: media: rcar-vin: Do not sync subdevice format when opening the video device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The format is already synced when the subdevice is bound, there is no need to do do it every time the video device is opened. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 25 ------------------------- 1 file changed, 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index f67cef97b89a..71651c5a6948 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -782,38 +782,13 @@ static int rvin_initialize_device(struct file *file) struct rvin_dev *vin = video_drvdata(file); int ret; - struct v4l2_format f = { - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .fmt.pix = { - .width = vin->format.width, - .height = vin->format.height, - .field = vin->format.field, - .colorspace = vin->format.colorspace, - .pixelformat = vin->format.pixelformat, - }, - }; - ret = rvin_power_on(vin); if (ret < 0) return ret; - /* - * Try to configure with default parameters. Notice: this is the - * very first open, so, we cannot race against other calls, - * apart from someone else calling open() simultaneously, but - * .host_lock is protecting us against it. - */ - ret = rvin_s_fmt_vid_cap(file, NULL, &f); - if (ret < 0) - goto esfmt; - v4l2_ctrl_handler_setup(&vin->ctrl_handler); return 0; -esfmt: - rvin_power_off(vin); - - return ret; } static int rvin_open(struct file *file) -- cgit v1.2.3-59-g8ed1b From 2a18fbec1dabf053f97365e7aa1ef64c69112618 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:44 -0400 Subject: media: rcar-vin: Move pm_runtime_{get,put} out of helpers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The helpers rvin_power_{on,off} deal with both VIN and the parallel subdevice power. This makes it hard to merge the Gen2 and Gen3 open/release functions. Move the VIN power handling directly to the open/release functions to prepare for the merge. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 35 +++++++++++++++++------------ 1 file changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 71651c5a6948..c84962073cf6 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -754,8 +754,6 @@ static int rvin_power_on(struct rvin_dev *vin) int ret; struct v4l2_subdev *sd = vin_to_source(vin); - pm_runtime_get_sync(vin->v4l2_dev.dev); - ret = v4l2_subdev_call(sd, core, s_power, 1); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; @@ -768,9 +766,6 @@ static int rvin_power_off(struct rvin_dev *vin) struct v4l2_subdev *sd = vin_to_source(vin); ret = v4l2_subdev_call(sd, core, s_power, 0); - - pm_runtime_put(vin->v4l2_dev.dev); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; @@ -796,26 +791,36 @@ static int rvin_open(struct file *file) struct rvin_dev *vin = video_drvdata(file); int ret; + ret = pm_runtime_get_sync(vin->dev); + if (ret < 0) + return ret; + ret = mutex_lock_interruptible(&vin->lock); if (ret) - return ret; + goto err_pm; file->private_data = vin; ret = v4l2_fh_open(file); if (ret) - goto unlock; - - if (!v4l2_fh_is_singular_file(file)) - goto unlock; + goto err_unlock; - if (rvin_initialize_device(file)) { - v4l2_fh_release(file); - ret = -ENODEV; + if (v4l2_fh_is_singular_file(file)) { + ret = rvin_initialize_device(file); + if (ret) + goto err_open; } -unlock: mutex_unlock(&vin->lock); + + return 0; +err_open: + v4l2_fh_release(file); +err_unlock: + mutex_unlock(&vin->lock); +err_pm: + pm_runtime_put(vin->dev); + return ret; } @@ -842,6 +847,8 @@ static int rvin_release(struct file *file) mutex_unlock(&vin->lock); + pm_runtime_put(vin->dev); + return ret; } -- cgit v1.2.3-59-g8ed1b From e378faaa66f18a7a26b181574d5f4a7c25598a3f Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:45 -0400 Subject: media: rcar-vin: Merge helpers dealing with powering the parallel subdevice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The two power helpers are now only dealing with the parallel subdevice, merge them into a single rvin_power_parallel() helper to reduce code duplication. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index c84962073cf6..5a01b617c87d 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -749,23 +749,13 @@ static const struct v4l2_ioctl_ops rvin_mc_ioctl_ops = { * File Operations */ -static int rvin_power_on(struct rvin_dev *vin) +static int rvin_power_parallel(struct rvin_dev *vin, bool on) { - int ret; struct v4l2_subdev *sd = vin_to_source(vin); - - ret = v4l2_subdev_call(sd, core, s_power, 1); - if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) - return ret; - return 0; -} - -static int rvin_power_off(struct rvin_dev *vin) -{ + int power = on ? 1 : 0; int ret; - struct v4l2_subdev *sd = vin_to_source(vin); - ret = v4l2_subdev_call(sd, core, s_power, 0); + ret = v4l2_subdev_call(sd, core, s_power, power); if (ret < 0 && ret != -ENOIOCTLCMD && ret != -ENODEV) return ret; @@ -777,7 +767,7 @@ static int rvin_initialize_device(struct file *file) struct rvin_dev *vin = video_drvdata(file); int ret; - ret = rvin_power_on(vin); + ret = rvin_power_parallel(vin, true); if (ret < 0) return ret; @@ -843,7 +833,7 @@ static int rvin_release(struct file *file) * Then de-initialize hw module. */ if (fh_singular) - rvin_power_off(vin); + rvin_power_parallel(vin, false); mutex_unlock(&vin->lock); -- cgit v1.2.3-59-g8ed1b From a59846ce4f26530a457b5a25e7ea5647946ccd71 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:46 -0400 Subject: media: rcar-vin: Fold rvin_initialize_device() into rvin_open() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function no longer serve a purpose as most tasks it performed have been refactored, fold what remains of it into the only caller. While at it add error checking for v4l2_ctrl_handler_setup(). Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index 5a01b617c87d..a84a07f1588c 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -762,20 +762,6 @@ static int rvin_power_parallel(struct rvin_dev *vin, bool on) return 0; } -static int rvin_initialize_device(struct file *file) -{ - struct rvin_dev *vin = video_drvdata(file); - int ret; - - ret = rvin_power_parallel(vin, true); - if (ret < 0) - return ret; - - v4l2_ctrl_handler_setup(&vin->ctrl_handler); - - return 0; -} - static int rvin_open(struct file *file) { struct rvin_dev *vin = video_drvdata(file); @@ -796,14 +782,20 @@ static int rvin_open(struct file *file) goto err_unlock; if (v4l2_fh_is_singular_file(file)) { - ret = rvin_initialize_device(file); - if (ret) + ret = rvin_power_parallel(vin, true); + if (ret < 0) goto err_open; + + ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); + if (ret) + goto err_parallel; } mutex_unlock(&vin->lock); return 0; +err_parallel: + rvin_power_parallel(vin, false); err_open: v4l2_fh_release(file); err_unlock: -- cgit v1.2.3-59-g8ed1b From a60b42c9218b3fdd33974c94e4c023d99191a114 Mon Sep 17 00:00:00 2001 From: Niklas Söderlund Date: Wed, 12 Jun 2019 19:45:47 -0400 Subject: media: rcar-vin: Merge Gen2 and Gen3 file operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the rework of the Gen2 file operations it's now trivial to merge the Gen2 and Gen3 versions. Signed-off-by: Niklas Söderlund Reviewed-by: Ulrich Hecht Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-vin/rcar-v4l2.c | 102 ++++++---------------------- 1 file changed, 19 insertions(+), 83 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c index a84a07f1588c..0936bcd98df1 100644 --- a/drivers/media/platform/rcar-vin/rcar-v4l2.c +++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c @@ -781,16 +781,21 @@ static int rvin_open(struct file *file) if (ret) goto err_unlock; - if (v4l2_fh_is_singular_file(file)) { - ret = rvin_power_parallel(vin, true); + if (vin->info->use_mc) { + ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1); if (ret < 0) goto err_open; - - ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); - if (ret) - goto err_parallel; + } else { + if (v4l2_fh_is_singular_file(file)) { + ret = rvin_power_parallel(vin, true); + if (ret < 0) + goto err_open; + + ret = v4l2_ctrl_handler_setup(&vin->ctrl_handler); + if (ret) + goto err_parallel; + } } - mutex_unlock(&vin->lock); return 0; @@ -820,12 +825,12 @@ static int rvin_release(struct file *file) /* the release helper will cleanup any on-going streaming */ ret = _vb2_fop_release(file, NULL); - /* - * If this was the last open file. - * Then de-initialize hw module. - */ - if (fh_singular) - rvin_power_parallel(vin, false); + if (vin->info->use_mc) { + v4l2_pipeline_pm_use(&vin->vdev.entity, 0); + } else { + if (fh_singular) + rvin_power_parallel(vin, false); + } mutex_unlock(&vin->lock); @@ -844,74 +849,6 @@ static const struct v4l2_file_operations rvin_fops = { .read = vb2_fop_read, }; -/* ----------------------------------------------------------------------------- - * Media controller file operations - */ - -static int rvin_mc_open(struct file *file) -{ - struct rvin_dev *vin = video_drvdata(file); - int ret; - - ret = mutex_lock_interruptible(&vin->lock); - if (ret) - return ret; - - ret = pm_runtime_get_sync(vin->dev); - if (ret < 0) - goto err_unlock; - - ret = v4l2_pipeline_pm_use(&vin->vdev.entity, 1); - if (ret < 0) - goto err_pm; - - file->private_data = vin; - - ret = v4l2_fh_open(file); - if (ret) - goto err_v4l2pm; - - mutex_unlock(&vin->lock); - - return 0; -err_v4l2pm: - v4l2_pipeline_pm_use(&vin->vdev.entity, 0); -err_pm: - pm_runtime_put(vin->dev); -err_unlock: - mutex_unlock(&vin->lock); - - return ret; -} - -static int rvin_mc_release(struct file *file) -{ - struct rvin_dev *vin = video_drvdata(file); - int ret; - - mutex_lock(&vin->lock); - - /* the release helper will cleanup any on-going streaming. */ - ret = _vb2_fop_release(file, NULL); - - v4l2_pipeline_pm_use(&vin->vdev.entity, 0); - pm_runtime_put(vin->dev); - - mutex_unlock(&vin->lock); - - return ret; -} - -static const struct v4l2_file_operations rvin_mc_fops = { - .owner = THIS_MODULE, - .unlocked_ioctl = video_ioctl2, - .open = rvin_mc_open, - .release = rvin_mc_release, - .poll = vb2_fop_poll, - .mmap = vb2_fop_mmap, - .read = vb2_fop_read, -}; - void rvin_v4l2_unregister(struct rvin_dev *vin) { if (!video_is_registered(&vin->vdev)) @@ -952,6 +889,7 @@ int rvin_v4l2_register(struct rvin_dev *vin) snprintf(vdev->name, sizeof(vdev->name), "VIN%u output", vin->id); vdev->release = video_device_release_empty; vdev->lock = &vin->lock; + vdev->fops = &rvin_fops; vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; @@ -963,10 +901,8 @@ int rvin_v4l2_register(struct rvin_dev *vin) vin->format.colorspace = RVIN_DEFAULT_COLORSPACE; if (vin->info->use_mc) { - vdev->fops = &rvin_mc_fops; vdev->ioctl_ops = &rvin_mc_ioctl_ops; } else { - vdev->fops = &rvin_fops; vdev->ioctl_ops = &rvin_ioctl_ops; rvin_reset_format(vin); } -- cgit v1.2.3-59-g8ed1b From e08efef8fe7db87206314c19b341612c719f891a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 13 Jun 2019 06:48:34 -0400 Subject: media: s5p-mfc: Make additional clocks optional Since the beginning the second clock ('special', 'sclk') was optional and it is not available on some variants of Exynos SoCs (i.e. Exynos5420 with v7 of MFC hardware). However commit 1bce6fb3edf1 ("[media] s5p-mfc: Rework clock handling") made handling of all specified clocks mandatory. This patch restores original behavior of the driver and fixes its operation on Exynos5420 SoCs. Fixes: 1bce6fb3edf1 ("[media] s5p-mfc: Rework clock handling") Signed-off-by: Marek Szyprowski Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 2e62f8721fa5..7d52431c2c83 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -34,6 +34,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) for (i = 0; i < pm->num_clocks; i++) { pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); if (IS_ERR(pm->clocks[i])) { + /* additional clocks are optional */ + if (i && PTR_ERR(pm->clocks[i]) == -ENOENT) { + pm->clocks[i] = NULL; + continue; + } mfc_err("Failed to get clock: %s\n", pm->clk_names[i]); return PTR_ERR(pm->clocks[i]); -- cgit v1.2.3-59-g8ed1b From 9aa36e61dc6bf11d8ff46d6f177fb2e3a8fc5e91 Mon Sep 17 00:00:00 2001 From: André Almeida Date: Thu, 13 Jun 2019 11:06:13 -0400 Subject: media: vimc: debayer: Fix typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix typo on "tranforming". Add a line break so it keeps under 80 columns. Fix typo on "[it] need". Signed-off-by: André Almeida Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-debayer.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 310c0d0eefa2..00598fbf3cba 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -16,14 +16,16 @@ #include "vimc-common.h" #define VIMC_DEB_DRV_NAME "vimc-debayer" -/* This module only supports tranforming a bayer format to V4L2_PIX_FMT_RGB24 */ +/* This module only supports transforming a bayer format + * to V4L2_PIX_FMT_RGB24 + */ #define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24 #define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24 static unsigned int deb_mean_win_size = 3; module_param(deb_mean_win_size, uint, 0000); MODULE_PARM_DESC(deb_mean_win_size, " the window size to calculate the mean.\n" - "NOTE: the window size need to be an odd number, as the main pixel " + "NOTE: the window size needs to be an odd number, as the main pixel " "stays in the center of the window, otherwise the next odd number " "is considered"); -- cgit v1.2.3-59-g8ed1b From d13b3cdcbacbeb31c0a4b5b3a63e855b4511fd85 Mon Sep 17 00:00:00 2001 From: André Almeida Date: Thu, 13 Jun 2019 11:06:14 -0400 Subject: media: vimc: Makefile: file cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove redundant Makefile rules (vimc_capture-objs, ...). Stop exposing vimc-{common, streamer} as modules, since there's no use case where they would be individually added/removed from Vimc. As consequence, remove MODULE_ macros from vimc-{common, streamer}. `-objs` is fitted for building host programs, change to `-y`, more straightforward for device drivers. Signed-off-by: André Almeida Suggested-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/Makefile | 12 +++--------- drivers/media/platform/vimc/vimc-common.c | 4 ---- drivers/media/platform/vimc/vimc-streamer.c | 4 ---- 3 files changed, 3 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile index c4fc8e7d365a..96d06f030c31 100644 --- a/drivers/media/platform/vimc/Makefile +++ b/drivers/media/platform/vimc/Makefile @@ -1,11 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -vimc-objs := vimc-core.o -vimc_capture-objs := vimc-capture.o -vimc_common-objs := vimc-common.o -vimc_debayer-objs := vimc-debayer.o -vimc_scaler-objs := vimc-scaler.o -vimc_sensor-objs := vimc-sensor.o -vimc_streamer-objs := vimc-streamer.o +vimc-y := vimc-core.o vimc-common.o vimc-streamer.o -obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc_capture.o vimc_common.o vimc-debayer.o \ - vimc_scaler.o vimc_sensor.o vimc_streamer.o +obj-$(CONFIG_VIDEO_VIMC) += vimc.o vimc-capture.o vimc-debayer.o \ + vimc-scaler.o vimc-sensor.o diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index f4d2073076ed..03016f204d05 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -377,7 +377,3 @@ void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) v4l2_device_unregister_subdev(sd); } EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Common"); -MODULE_AUTHOR("Helen Koike "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index 26b674259489..236ade38f1da 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -188,7 +188,3 @@ int vimc_streamer_s_stream(struct vimc_stream *stream, return 0; } EXPORT_SYMBOL_GPL(vimc_streamer_s_stream); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC) Streamer"); -MODULE_AUTHOR("Lucas A. M. Magalhães "); -MODULE_LICENSE("GPL"); -- cgit v1.2.3-59-g8ed1b From 86aed3f519312ee86bf6c618687aa1be08dd9ca4 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 14 Jun 2019 03:56:21 -0400 Subject: media: mtk-vcodec: avoid unneeded pointer-to-long conversions The interface used to communicate with the firmware casts pointers into unsigned longs and back again in order to store private references, all of this for pointers that remain purely in the kernel. Replace these unsigned longs with void pointers to make the code a bit sturdier and easier to follow. Also simplify some interfaces by removing arguments that could be infered from others. Signed-off-by: Alexandre Courbot Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: fix checkpatch alignment warning] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 2 +- drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c | 12 ++++++------ drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c | 12 ++++++------ drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c | 14 +++++++------- drivers/media/platform/mtk-vcodec/vdec_drv_base.h | 8 ++++---- drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 10 +++++----- drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 10 +++++----- drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c | 10 +++++----- drivers/media/platform/mtk-vcodec/venc_drv_base.h | 8 ++++---- drivers/media/platform/mtk-vcodec/venc_drv_if.c | 6 +++--- 10 files changed, 46 insertions(+), 46 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index c1422739dab4..c95de5d08dda 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -273,7 +273,7 @@ struct mtk_vcodec_ctx { const struct vdec_common_if *dec_if; const struct venc_common_if *enc_if; - unsigned long drv_handle; + void *drv_handle; struct vdec_pic_info picinfo; int dpb_size; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index c035f744b1f1..67a7d4f813d5 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -266,7 +266,7 @@ static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz) mtk_vcodec_debug(inst, "sz=%d", *dpb_sz); } -static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +static int vdec_h264_init(struct mtk_vcodec_ctx *ctx) { struct vdec_h264_inst *inst = NULL; int err; @@ -295,7 +295,7 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) mtk_vcodec_debug(inst, "H264 Instance >> %p", inst); - *h_vdec = (unsigned long)inst; + ctx->drv_handle = inst; return 0; error_deinit: @@ -306,7 +306,7 @@ error_free_inst: return err; } -static void vdec_h264_deinit(unsigned long h_vdec) +static void vdec_h264_deinit(void *h_vdec) { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; @@ -331,7 +331,7 @@ static int find_start_code(unsigned char *data, unsigned int data_sz) return -1; } -static int vdec_h264_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, +static int vdec_h264_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; @@ -451,8 +451,8 @@ static void vdec_h264_get_fb(struct vdec_h264_inst *inst, list->count--; } -static int vdec_h264_get_param(unsigned long h_vdec, - enum vdec_get_param_type type, void *out) +static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) { struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index 24f976f0d477..42e302650e69 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -388,7 +388,7 @@ static void free_working_buf(struct vdec_vp8_inst *inst) inst->vsi->dec.working_buf_dma = 0; } -static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx) { struct vdec_vp8_inst *inst; int err; @@ -419,7 +419,7 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) get_hw_reg_base(inst); mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst); - *h_vdec = (unsigned long)inst; + ctx->drv_handle = inst; return 0; error_deinit: @@ -429,7 +429,7 @@ error_free_inst: return err; } -static int vdec_vp8_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, +static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg) { struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; @@ -565,8 +565,8 @@ static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr) cr->left, cr->top, cr->width, cr->height); } -static int vdec_vp8_get_param(unsigned long h_vdec, - enum vdec_get_param_type type, void *out) +static int vdec_vp8_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) { struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; @@ -599,7 +599,7 @@ static int vdec_vp8_get_param(unsigned long h_vdec, return 0; } -static void vdec_vp8_deinit(unsigned long h_vdec) +static void vdec_vp8_deinit(void *h_vdec) { struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index 9e6b630d7f5b..7935f97989b0 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -757,7 +757,7 @@ static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst, return 0; } -static void vdec_vp9_deinit(unsigned long h_vdec) +static void vdec_vp9_deinit(void *h_vdec) { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; struct mtk_vcodec_mem *mem; @@ -779,7 +779,7 @@ static void vdec_vp9_deinit(unsigned long h_vdec) vp9_free_inst(inst); } -static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx) { struct vdec_vp9_inst *inst; @@ -803,7 +803,7 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi; init_all_fb_lists(inst); - (*h_vdec) = (unsigned long)inst; + ctx->drv_handle = inst; return 0; err_deinit_inst: @@ -812,8 +812,8 @@ err_deinit_inst: return -EINVAL; } -static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, - struct vdec_fb *fb, bool *res_chg) +static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) { int ret = 0; struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; @@ -969,8 +969,8 @@ static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr) cr->left, cr->top, cr->width, cr->height); } -static int vdec_vp9_get_param(unsigned long h_vdec, - enum vdec_get_param_type type, void *out) +static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type, + void *out) { struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; int ret = 0; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h index 2019aec71ddb..ceb4db4cb3be 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h @@ -17,7 +17,7 @@ struct vdec_common_if { * @ctx : [in] mtk v4l2 context * @h_vdec : [out] driver handle */ - int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec); + int (*init)(struct mtk_vcodec_ctx *ctx); /** * (*decode)() - trigger decode @@ -26,7 +26,7 @@ struct vdec_common_if { * @fb : [in] frame buffer to store decoded frame * @res_chg : [out] resolution change happen */ - int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs, + int (*decode)(void *h_vdec, struct mtk_vcodec_mem *bs, struct vdec_fb *fb, bool *res_chg); /** @@ -35,14 +35,14 @@ struct vdec_common_if { * @type : [in] input parameter type * @out : [out] buffer to store query result */ - int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type, + int (*get_param)(void *h_vdec, enum vdec_get_param_type type, void *out); /** * (*deinit)() - deinitialize driver. * @h_vdec : [in] driver handle to be deinit */ - void (*deinit)(unsigned long h_vdec); + void (*deinit)(void *h_vdec); }; #endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index bd42d9028c42..8354404a7fc9 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -39,7 +39,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) mtk_vdec_lock(ctx); mtk_vcodec_dec_clock_on(&ctx->dev->pm); - ret = ctx->dec_if->init(ctx, &ctx->drv_handle); + ret = ctx->dec_if->init(ctx); mtk_vcodec_dec_clock_off(&ctx->dev->pm); mtk_vdec_unlock(ctx); @@ -66,7 +66,7 @@ int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, } } - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return -EIO; mtk_vdec_lock(ctx); @@ -89,7 +89,7 @@ int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type, { int ret = 0; - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return -EIO; mtk_vdec_lock(ctx); @@ -101,7 +101,7 @@ int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type, void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) { - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return; mtk_vdec_lock(ctx); @@ -110,5 +110,5 @@ void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) mtk_vcodec_dec_clock_off(&ctx->dev->pm); mtk_vdec_unlock(ctx); - ctx->drv_handle = 0; + ctx->drv_handle = NULL; } diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index 21f2eaea207b..0183dd395d44 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -458,7 +458,7 @@ static void h264_encode_filler(struct venc_h264_inst *inst, void *buf, memset(p, 0xff, size); } -static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) +static int h264_enc_init(struct mtk_vcodec_ctx *ctx) { int ret = 0; struct venc_h264_inst *inst; @@ -484,12 +484,12 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) if (ret) kfree(inst); else - (*handle) = (unsigned long)inst; + ctx->drv_handle = inst; return ret; } -static int h264_enc_encode(unsigned long handle, +static int h264_enc_encode(void *handle, enum venc_start_opt opt, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, @@ -584,7 +584,7 @@ encode_err: return ret; } -static int h264_enc_set_param(unsigned long handle, +static int h264_enc_set_param(void *handle, enum venc_set_param_type type, struct venc_enc_param *enc_prm) { @@ -637,7 +637,7 @@ static int h264_enc_set_param(unsigned long handle, return ret; } -static int h264_enc_deinit(unsigned long handle) +static int h264_enc_deinit(void *handle) { int ret = 0; struct venc_h264_inst *inst = (struct venc_h264_inst *)handle; diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index 81f87f6ec435..3787e75ca902 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -323,7 +323,7 @@ static int vp8_enc_encode_frame(struct venc_vp8_inst *inst, return ret; } -static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) +static int vp8_enc_init(struct mtk_vcodec_ctx *ctx) { int ret = 0; struct venc_vp8_inst *inst; @@ -349,12 +349,12 @@ static int vp8_enc_init(struct mtk_vcodec_ctx *ctx, unsigned long *handle) if (ret) kfree(inst); else - (*handle) = (unsigned long)inst; + ctx->drv_handle = inst; return ret; } -static int vp8_enc_encode(unsigned long handle, +static int vp8_enc_encode(void *handle, enum venc_start_opt opt, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, @@ -391,7 +391,7 @@ encode_err: return ret; } -static int vp8_enc_set_param(unsigned long handle, +static int vp8_enc_set_param(void *handle, enum venc_set_param_type type, struct venc_enc_param *enc_prm) { @@ -442,7 +442,7 @@ static int vp8_enc_set_param(unsigned long handle, return ret; } -static int vp8_enc_deinit(unsigned long handle) +static int vp8_enc_deinit(void *handle) { int ret = 0; struct venc_vp8_inst *inst = (struct venc_vp8_inst *)handle; diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_base.h b/drivers/media/platform/mtk-vcodec/venc_drv_base.h index 09968a68db42..3d718411dc73 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_base.h @@ -19,7 +19,7 @@ struct venc_common_if { * @ctx: [in] mtk v4l2 context * @handle: [out] driver handle */ - int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *handle); + int (*init)(struct mtk_vcodec_ctx *ctx); /** * (*encode)() - trigger encode @@ -29,7 +29,7 @@ struct venc_common_if { * @bs_buf: [in] bitstream buffer to store output bitstream * @result: [out] encode result */ - int (*encode)(unsigned long handle, enum venc_start_opt opt, + int (*encode)(void *handle, enum venc_start_opt opt, struct venc_frm_buf *frm_buf, struct mtk_vcodec_mem *bs_buf, struct venc_done_result *result); @@ -40,14 +40,14 @@ struct venc_common_if { * @type: [in] parameter type * @in: [in] buffer to store the parameter */ - int (*set_param)(unsigned long handle, enum venc_set_param_type type, + int (*set_param)(void *handle, enum venc_set_param_type type, struct venc_enc_param *in); /** * (*deinit)() - deinitialize driver. * @handle: [in] driver handle */ - int (*deinit)(unsigned long handle); + int (*deinit)(void *handle); }; #endif diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c index 600c43c17e48..b5cc645f7c68 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c @@ -37,7 +37,7 @@ int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) mtk_venc_lock(ctx); mtk_vcodec_enc_clock_on(&ctx->dev->pm); - ret = ctx->enc_if->init(ctx, (unsigned long *)&ctx->drv_handle); + ret = ctx->enc_if->init(ctx); mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); @@ -89,7 +89,7 @@ int venc_if_deinit(struct mtk_vcodec_ctx *ctx) { int ret = 0; - if (ctx->drv_handle == 0) + if (!ctx->drv_handle) return 0; mtk_venc_lock(ctx); @@ -98,7 +98,7 @@ int venc_if_deinit(struct mtk_vcodec_ctx *ctx) mtk_vcodec_enc_clock_off(&ctx->dev->pm); mtk_venc_unlock(ctx); - ctx->drv_handle = 0; + ctx->drv_handle = NULL; return ret; } -- cgit v1.2.3-59-g8ed1b From 9fcb242be63db7c43c65401b615012225c648515 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Fri, 14 Jun 2019 03:56:40 -0400 Subject: media: mtk-vcodec: remove unneeded proxy functions We were getting the codec interface through a proxy function that does not bring anything compared to just accessing the interface definition directly, so just do that. Also make the decoder interfaces const. Signed-off-by: Alexandre Courbot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c | 9 +-------- drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c | 9 +-------- drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c | 9 +-------- drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 10 +++------- drivers/media/platform/mtk-vcodec/vdec_drv_if.h | 4 ++++ drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c | 9 +-------- drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c | 9 +-------- drivers/media/platform/mtk-vcodec/venc_drv_if.c | 7 ++----- drivers/media/platform/mtk-vcodec/venc_drv_if.h | 3 +++ 9 files changed, 17 insertions(+), 52 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index 67a7d4f813d5..c5f8f1fca44c 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -485,16 +485,9 @@ static int vdec_h264_get_param(void *h_vdec, enum vdec_get_param_type type, return 0; } -static struct vdec_common_if vdec_h264_if = { +const struct vdec_common_if vdec_h264_if = { .init = vdec_h264_init, .decode = vdec_h264_decode, .get_param = vdec_h264_get_param, .deinit = vdec_h264_deinit, }; - -struct vdec_common_if *get_h264_dec_comm_if(void); - -struct vdec_common_if *get_h264_dec_comm_if(void) -{ - return &vdec_h264_if; -} diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index 42e302650e69..63a8708ce682 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -610,16 +610,9 @@ static void vdec_vp8_deinit(void *h_vdec) kfree(inst); } -static struct vdec_common_if vdec_vp8_if = { +const struct vdec_common_if vdec_vp8_if = { .init = vdec_vp8_init, .decode = vdec_vp8_decode, .get_param = vdec_vp8_get_param, .deinit = vdec_vp8_deinit, }; - -struct vdec_common_if *get_vp8_dec_comm_if(void); - -struct vdec_common_if *get_vp8_dec_comm_if(void) -{ - return &vdec_vp8_if; -} diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index 7935f97989b0..5066c283d86d 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -1000,16 +1000,9 @@ static int vdec_vp9_get_param(void *h_vdec, enum vdec_get_param_type type, return ret; } -static struct vdec_common_if vdec_vp9_if = { +const struct vdec_common_if vdec_vp9_if = { .init = vdec_vp9_init, .decode = vdec_vp9_decode, .get_param = vdec_vp9_get_param, .deinit = vdec_vp9_deinit, }; - -struct vdec_common_if *get_vp9_dec_comm_if(void); - -struct vdec_common_if *get_vp9_dec_comm_if(void) -{ - return &vdec_vp9_if; -} diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 8354404a7fc9..2e43dd4486e0 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -15,23 +15,19 @@ #include "mtk_vcodec_dec_pm.h" #include "mtk_vpu.h" -const struct vdec_common_if *get_h264_dec_comm_if(void); -const struct vdec_common_if *get_vp8_dec_comm_if(void); -const struct vdec_common_if *get_vp9_dec_comm_if(void); - int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { int ret = 0; switch (fourcc) { case V4L2_PIX_FMT_H264: - ctx->dec_if = get_h264_dec_comm_if(); + ctx->dec_if = &vdec_h264_if; break; case V4L2_PIX_FMT_VP8: - ctx->dec_if = get_vp8_dec_comm_if(); + ctx->dec_if = &vdec_vp8_if; break; case V4L2_PIX_FMT_VP9: - ctx->dec_if = get_vp9_dec_comm_if(); + ctx->dec_if = &vdec_vp9_if; break; default: return -EINVAL; diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h index c5bd8b0dbe13..270d8dc9984b 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -54,6 +54,10 @@ struct vdec_fb_node { struct vdec_fb *fb; }; +extern const struct vdec_common_if vdec_h264_if; +extern const struct vdec_common_if vdec_vp8_if; +extern const struct vdec_common_if vdec_vp9_if; + /** * vdec_if_init() - initialize decode driver * @ctx : [in] v4l2 context diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c index 0183dd395d44..b9624f8df0e9 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c @@ -655,16 +655,9 @@ static int h264_enc_deinit(void *handle) return ret; } -static const struct venc_common_if venc_h264_if = { +const struct venc_common_if venc_h264_if = { .init = h264_enc_init, .encode = h264_enc_encode, .set_param = h264_enc_set_param, .deinit = h264_enc_deinit, }; - -const struct venc_common_if *get_h264_enc_comm_if(void); - -const struct venc_common_if *get_h264_enc_comm_if(void) -{ - return &venc_h264_if; -} diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c index 3787e75ca902..8d36f0362efe 100644 --- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c @@ -460,16 +460,9 @@ static int vp8_enc_deinit(void *handle) return ret; } -static const struct venc_common_if venc_vp8_if = { +const struct venc_common_if venc_vp8_if = { .init = vp8_enc_init, .encode = vp8_enc_encode, .set_param = vp8_enc_set_param, .deinit = vp8_enc_deinit, }; - -const struct venc_common_if *get_vp8_enc_comm_if(void); - -const struct venc_common_if *get_vp8_enc_comm_if(void) -{ - return &venc_vp8_if; -} diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c index b5cc645f7c68..c6bb82ac2dcd 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c @@ -17,19 +17,16 @@ #include "mtk_vcodec_enc_pm.h" #include "mtk_vpu.h" -const struct venc_common_if *get_h264_enc_comm_if(void); -const struct venc_common_if *get_vp8_enc_comm_if(void); - int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { int ret = 0; switch (fourcc) { case V4L2_PIX_FMT_VP8: - ctx->enc_if = get_vp8_enc_comm_if(); + ctx->enc_if = &venc_vp8_if; break; case V4L2_PIX_FMT_H264: - ctx->enc_if = get_h264_enc_comm_if(); + ctx->enc_if = &venc_h264_if; break; default: return -EINVAL; diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h index cc5bb36c2735..52fc9cc812fc 100644 --- a/drivers/media/platform/mtk-vcodec/venc_drv_if.h +++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.h @@ -110,6 +110,9 @@ struct venc_done_result { bool is_key_frm; }; +extern const struct venc_common_if venc_h264_if; +extern const struct venc_common_if venc_vp8_if; + /* * venc_if_init - Create the driver handle * @ctx: device context -- cgit v1.2.3-59-g8ed1b From 3fcedae346029561f4d033412371c857fa9ebf0f Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 14 Jun 2019 10:09:06 -0400 Subject: media: vivid: remove unnecessary min and max timeperframe constants The tpf_min (1/100) and tpf_max (100/1) are used as the lowest and the highest allowable value for the desired frame period in vivid_vid_cap_s_parm(). But the comparison between these values is unnecessary because the compared value is already chosen from webcam_intervals[] (from 1/60 to 1/1). Cc: Hans Verkuil Signed-off-by: Akinobu Mita Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.h | 12 ------------ drivers/media/platform/vivid/vivid-vid-cap.c | 7 ------- 2 files changed, 19 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 6697c7009629..18a9ba9d76e8 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -22,18 +22,6 @@ #define dprintk(dev, level, fmt, arg...) \ v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg) -/* Maximum allowed frame rate - * - * vivid will allow setting timeperframe in [1/FPS_MAX - FPS_MAX/1] range. - * - * Ideally FPS_MAX should be infinity, i.e. practically UINT_MAX, but that - * might hit application errors when they manipulate these values. - * - * Besides, for tpf < 10ms image-generation logic should be changed, to avoid - * producing frames with equal content. - */ -#define FPS_MAX 100 - /* The maximum number of clip rectangles */ #define MAX_CLIPS 16 /* The maximum number of inputs */ diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 530ac8decb25..6e8c6de1465d 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -21,11 +21,6 @@ #include "vivid-kthread-cap.h" #include "vivid-vid-cap.h" -/* timeperframe: min/max and default */ -static const struct v4l2_fract - tpf_min = {.numerator = 1, .denominator = FPS_MAX}, - tpf_max = {.numerator = FPS_MAX, .denominator = 1}; - static const struct vivid_fmt formats_ovl[] = { { .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ @@ -1865,8 +1860,6 @@ int vivid_vid_cap_s_parm(struct file *file, void *priv, i = ival_sz - 1; dev->webcam_ival_idx = i; tpf = webcam_intervals[dev->webcam_ival_idx]; - tpf = V4L2_FRACT_COMPARE(tpf, <, tpf_min) ? tpf_min : tpf; - tpf = V4L2_FRACT_COMPARE(tpf, >, tpf_max) ? tpf_max : tpf; /* resync the thread's timings */ dev->cap_seq_resync = true; -- cgit v1.2.3-59-g8ed1b From eef4d8e9f06dd06496ea82400f26379c4de8797c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 15 Jun 2019 03:45:53 -0400 Subject: media: meye: Fix build COMPILE_TEST error If COMPILE_TEST is y and SONY_LAPTOP is m, building fails as below: Reported-by: Hulk Robot Fixes: 6159e12e1177 ("media: meye: allow building it with COMPILE_TEST on non-x86") Signed-off-by: YueHaibing Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/meye/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig index b0ba78abbdbb..b37da612dd0c 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/media/pci/meye/Kconfig @@ -2,7 +2,8 @@ config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" depends on PCI && VIDEO_V4L2 - depends on SONY_LAPTOP || COMPILE_TEST + depends on SONY_LAPTOP + depends on X86 || COMPILE_TEST help This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in -- cgit v1.2.3-59-g8ed1b From 94954bb709c998aeda73be42bb18a7911b6413b4 Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sat, 15 Jun 2019 11:00:57 -0400 Subject: media: video-i2c: use V4L2_FRACT_COMPARE Use V4L2_FRACT_COMPARE to check whether two v4l2_fract structs are equal. Cc: Matt Ranostay Cc: Sakari Ailus Cc: Hans Verkuil Signed-off-by: Akinobu Mita Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/video-i2c.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index abd3152df7d0..078141712c88 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -190,12 +190,8 @@ static int mlx90640_setup(struct video_i2c_data *data) unsigned int n, idx; for (n = 0; n < data->chip->num_frame_intervals - 1; n++) { - if (data->frame_interval.numerator - != data->chip->frame_intervals[n].numerator) - continue; - - if (data->frame_interval.denominator - == data->chip->frame_intervals[n].denominator) + if (V4L2_FRACT_COMPARE(data->frame_interval, ==, + data->chip->frame_intervals[n])) break; } -- cgit v1.2.3-59-g8ed1b From bfa69bdf342b723a065528acdb217d13a40e40b6 Mon Sep 17 00:00:00 2001 From: André Almeida Date: Sat, 15 Jun 2019 22:09:58 -0400 Subject: media: vimc: stream: add missing function documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comments at vimc_streamer_s_stream and vimc_streamer_thread, making the vimc-stream totally documented. Signed-off-by: André Almeida [hverkuil-cisco@xs4all.nl: fix typo: in a fixed framerate -> at a fixed framerate] [hverkuil-cisco@xs4all.nl: fix typo: stops the thread -> stop the thread] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-streamer.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index 236ade38f1da..3b3f36357a0e 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -122,6 +122,14 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, return -EINVAL; } +/* + * vimc_streamer_thread - process frames through the pipeline + * + * @data: vimc_stream struct of the current stream + * + * From the source to the sink, gets a frame from each subdevice and send to + * the next one of the pipeline at a fixed framerate. + */ static int vimc_streamer_thread(void *data) { struct vimc_stream *stream = data; @@ -149,6 +157,20 @@ static int vimc_streamer_thread(void *data) return 0; } +/* + * vimc_streamer_s_stream - start/stop the streaming on the media pipeline + * + * @stream: the pointer to the stream structure of the current stream + * @ved: pointer to the vimc entity of the entity of the stream + * @enable: flag to determine if stream should start/stop + * + * When starting, check if there is no stream->kthread allocated. This should + * indicate that a stream is already running. Then, it initializes + * the pipeline, creates and runs a kthread to consume buffers through the + * pipeline. + * When stopping, analogously check if there is a stream running, stop + * the thread and terminates the pipeline. + */ int vimc_streamer_s_stream(struct vimc_stream *stream, struct vimc_ent_device *ved, int enable) -- cgit v1.2.3-59-g8ed1b From 1a9ade50b82fd941d23473015752a56aa9812e37 Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Fri, 31 May 2019 18:15:48 -0400 Subject: media: aspeed: add a workaround to fix a silicon bug AST2500 silicon revision A1 and A2 have a silicon bug which causes extremly long capturing time on specific resolutions (1680 width). To fix the bug, this commit adjusts the capturing window register setting to 1728 if detected width is 1680. The compression window register setting will be kept as the original width so output result will be the same. Signed-off-by: Jae Hyun Yoo Reviewed-by: Eddie James Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/aspeed-video.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index ba093096a5a7..f899ac3b4a61 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -824,8 +824,29 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) struct v4l2_bt_timings *act = &video->active_timings; unsigned int size = act->width * act->height; + /* Set capture/compression frame sizes */ aspeed_video_calc_compressed_size(video, size); + if (video->active_timings.width == 1680) { + /* + * This is a workaround to fix a silicon bug on A1 and A2 + * revisions. Since it doesn't break capturing operation of + * other revisions, use it for all revisions without checking + * the revision ID. It picked 1728 which is a very next + * 64-pixels aligned value to 1680 to minimize memory bandwidth + * and to get better access speed from video engine. + */ + aspeed_video_write(video, VE_CAP_WINDOW, + 1728 << 16 | act->height); + size += (1728 - 1680) * video->active_timings.height; + } else { + aspeed_video_write(video, VE_CAP_WINDOW, + act->width << 16 | act->height); + } + aspeed_video_write(video, VE_COMP_WINDOW, + act->width << 16 | act->height); + aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); + /* Don't use direct mode below 1024 x 768 (irqs don't fire) */ if (size < DIRECT_FETCH_THRESHOLD) { aspeed_video_write(video, VE_TGS_0, @@ -842,13 +863,6 @@ static void aspeed_video_set_resolution(struct aspeed_video *video) aspeed_video_update(video, VE_CTRL, 0, VE_CTRL_DIRECT_FETCH); } - /* Set capture/compression frame sizes */ - aspeed_video_write(video, VE_CAP_WINDOW, - act->width << 16 | act->height); - aspeed_video_write(video, VE_COMP_WINDOW, - act->width << 16 | act->height); - aspeed_video_write(video, VE_SRC_SCANLINE_OFFSET, act->width * 4); - size *= 4; if (size != video->srcs[0].size) { -- cgit v1.2.3-59-g8ed1b From 56202c0cbe4fdeaeced6f5d2785b8a7ef4332905 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 5 Jun 2019 14:05:43 -0400 Subject: media: coda: Use devm_platform_ioremap_resource() Use devm_platform_ioremap_resource() to simplify the code a bit. Signed-off-by: Fabio Estevam Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 751b0be1c2ea..de64040dad8a 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2814,7 +2814,6 @@ static int coda_probe(struct platform_device *pdev) struct device_node *np = pdev->dev.of_node; struct gen_pool *pool; struct coda_dev *dev; - struct resource *res; int ret, irq; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -2846,8 +2845,7 @@ static int coda_probe(struct platform_device *pdev) } /* Get memory for physical registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->regs_base = devm_ioremap_resource(&pdev->dev, res); + dev->regs_base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->regs_base)) return PTR_ERR(dev->regs_base); -- cgit v1.2.3-59-g8ed1b From 448e11538f71933ba0ebd156bb176cf66827d6fd Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:18 -0400 Subject: media: vivid: make input dv_timings per-input Make the following properties per-input -DV Timings Signal Mode -DV Timings These properties need to be per-input in order to implement proper HDMI (dis)connect-behavior, where the signal mode will be used to signify whether or not there is an input device connected. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 12 ++++- drivers/media/platform/vivid/vivid-core.h | 11 +++-- drivers/media/platform/vivid/vivid-ctrls.c | 13 +++-- drivers/media/platform/vivid/vivid-kthread-cap.c | 2 +- drivers/media/platform/vivid/vivid-vid-cap.c | 63 ++++++++++++++++-------- drivers/media/platform/vivid/vivid-vid-common.c | 2 +- 6 files changed, 69 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index beb2e566a43c..f481f1768184 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1005,7 +1005,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) tvnorms_cap = V4L2_STD_ALL; if (dev->output_type[0] == SVID) tvnorms_out = V4L2_STD_ALL; - dev->dv_timings_cap = def_dv_timings; + for (i = 0; i < MAX_INPUTS; i++) + dev->dv_timings_cap[i] = def_dv_timings; dev->dv_timings_out = def_dv_timings; dev->tv_freq = 2804 /* 175.25 * 16 */; dev->tv_audmode = V4L2_TUNER_MODE_STEREO; @@ -1035,6 +1036,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (ret) goto unreg_dev; + /* enable/disable interface specific controls */ + if (dev->num_inputs && dev->input_type[0] != HDMI) { + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_dv_timings, false); + } else if (dev->num_inputs && dev->input_type[0] == HDMI) { + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_standard, false); + } + /* * update the capture and output formats to do a proper initial * configuration. diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 18a9ba9d76e8..713ed7e87f76 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -292,18 +292,19 @@ struct vivid_dev { v4l2_std_id query_std; enum tpg_video_aspect std_aspect_ratio; - enum vivid_signal_mode dv_timings_signal_mode; + enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS]; char **query_dv_timings_qmenu; char *query_dv_timings_qmenu_strings; unsigned query_dv_timings_size; - unsigned query_dv_timings_last; - unsigned query_dv_timings; - enum tpg_video_aspect dv_timings_aspect_ratio; + unsigned int query_dv_timings_last[MAX_INPUTS]; + unsigned int query_dv_timings[MAX_INPUTS]; + enum tpg_video_aspect dv_timings_aspect_ratio[MAX_INPUTS]; /* Input */ unsigned input; v4l2_std_id std_cap; - struct v4l2_dv_timings dv_timings_cap; + struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS]; + int dv_timings_cap_sel[MAX_INPUTS]; u32 service_set_cap; struct vivid_vbi_gen_data vbi_gen; u8 *edid; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 4cd526ff248b..a3c9661caf95 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -467,16 +467,19 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); break; case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: - dev->dv_timings_signal_mode = dev->ctrl_dv_timings_signal_mode->val; - if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) - dev->query_dv_timings = dev->ctrl_dv_timings->val; + dev->dv_timings_signal_mode[dev->input] = + dev->ctrl_dv_timings_signal_mode->val; + dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val; + v4l2_ctrl_activate(dev->ctrl_dv_timings, - dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS); + dev->dv_timings_signal_mode[dev->input] == + SELECTED_DV_TIMINGS); + vivid_update_quality(dev); vivid_send_source_change(dev, HDMI); break; case VIVID_CID_DV_TIMINGS_ASPECT_RATIO: - dev->dv_timings_aspect_ratio = ctrl->val; + dev->dv_timings_aspect_ratio[dev->input] = ctrl->val; tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); break; case VIVID_CID_TSTAMP_SRC: diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index f8006a30c12f..b4eee952e1c9 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -421,7 +421,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) ((vivid_is_svid_cap(dev) && !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) || (vivid_is_hdmi_cap(dev) && - !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)))) + !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) is_loop = true; buf->vb.sequence = dev->vid_cap_seq_count; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 6e8c6de1465d..2f8db64e3e65 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -294,7 +294,8 @@ void vivid_update_quality(struct vivid_dev *dev) tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } - if (vivid_is_hdmi_cap(dev) && VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode)) { + if (vivid_is_hdmi_cap(dev) && + VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) { tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } @@ -356,7 +357,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) return dev->std_aspect_ratio; if (vivid_is_hdmi_cap(dev)) - return dev->dv_timings_aspect_ratio; + return dev->dv_timings_aspect_ratio[dev->input]; return TPG_VIDEO_ASPECT_IMAGE; } @@ -381,7 +382,7 @@ static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) */ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) { - struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; unsigned size; u64 pixelclock; @@ -481,8 +482,8 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi } } if (vivid_is_hdmi_cap(dev)) - return dev->dv_timings_cap.bt.interlaced ? V4L2_FIELD_ALTERNATE : - V4L2_FIELD_NONE; + return dev->dv_timings_cap[dev->input].bt.interlaced ? + V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE; return V4L2_FIELD_NONE; } @@ -1305,10 +1306,10 @@ int vidioc_enum_input(struct file *file, void *priv, dev->input_name_counter[inp->index]); inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; if (dev->edid_blocks == 0 || - dev->dv_timings_signal_mode == NO_SIGNAL) + dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL) inp->status |= V4L2_IN_ST_NO_SIGNAL; - else if (dev->dv_timings_signal_mode == NO_LOCK || - dev->dv_timings_signal_mode == OUT_OF_RANGE) + else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK || + dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE) inp->status |= V4L2_IN_ST_NO_H_LOCK; break; } @@ -1348,7 +1349,7 @@ int vidioc_g_input(struct file *file, void *priv, unsigned *i) int vidioc_s_input(struct file *file, void *priv, unsigned i) { struct vivid_dev *dev = video_drvdata(file); - struct v4l2_bt_timings *bt = &dev->dv_timings_cap.bt; + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; unsigned brightness; if (i >= dev->num_inputs) @@ -1402,6 +1403,20 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) v4l2_ctrl_modify_range(dev->brightness, 128 * i, 255 + 128 * i, 1, 128 + 128 * i); v4l2_ctrl_s_ctrl(dev->brightness, brightness); + + /* Restore per-input states. */ + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, + vivid_is_hdmi_cap(dev)); + v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) && + dev->dv_timings_signal_mode[dev->input] == + SELECTED_DV_TIMINGS); + if (vivid_is_hdmi_cap(dev)) { + v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode, + dev->dv_timings_signal_mode[dev->input]); + v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings, + dev->query_dv_timings[dev->input]); + } + return 0; } @@ -1671,12 +1686,13 @@ int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, !valid_cvt_gtf_timings(timings)) return -EINVAL; - if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap, 0, false)) + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap[dev->input], + 0, false)) return 0; if (vb2_is_busy(&dev->vb_vid_cap_q)) return -EBUSY; - dev->dv_timings_cap = *timings; + dev->dv_timings_cap[dev->input] = *timings; vivid_update_format_cap(dev, false); return 0; } @@ -1685,26 +1701,31 @@ int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings) { struct vivid_dev *dev = video_drvdata(file); + unsigned int input = dev->input; + unsigned int last = dev->query_dv_timings_last[input]; if (!vivid_is_hdmi_cap(dev)) return -ENODATA; - if (dev->dv_timings_signal_mode == NO_SIGNAL || + if (dev->dv_timings_signal_mode[input] == NO_SIGNAL || dev->edid_blocks == 0) return -ENOLINK; - if (dev->dv_timings_signal_mode == NO_LOCK) + if (dev->dv_timings_signal_mode[input] == NO_LOCK) return -ENOLCK; - if (dev->dv_timings_signal_mode == OUT_OF_RANGE) { + if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) { timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; return -ERANGE; } - if (dev->dv_timings_signal_mode == CURRENT_DV_TIMINGS) { - *timings = dev->dv_timings_cap; - } else if (dev->dv_timings_signal_mode == SELECTED_DV_TIMINGS) { - *timings = v4l2_dv_timings_presets[dev->query_dv_timings]; + if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) { + *timings = dev->dv_timings_cap[input]; + } else if (dev->dv_timings_signal_mode[input] == + SELECTED_DV_TIMINGS) { + *timings = + v4l2_dv_timings_presets[dev->query_dv_timings[input]]; } else { - *timings = v4l2_dv_timings_presets[dev->query_dv_timings_last]; - dev->query_dv_timings_last = (dev->query_dv_timings_last + 1) % - dev->query_dv_timings_size; + *timings = + v4l2_dv_timings_presets[last]; + dev->query_dv_timings_last[input] = + (last + 1) % dev->query_dv_timings_size; } return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 9307ce1cdd16..98c0e5b4d391 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -823,7 +823,7 @@ int vidioc_g_dv_timings(struct file *file, void *_fh, if (vdev->vfl_dir == VFL_DIR_RX) { if (!vivid_is_hdmi_cap(dev)) return -ENODATA; - *timings = dev->dv_timings_cap; + *timings = dev->dv_timings_cap[dev->input]; } else { if (!vivid_is_hdmi_out(dev)) return -ENODATA; -- cgit v1.2.3-59-g8ed1b From 6c396c28dce0709b105eb59ecf4e44fd2f2e54dc Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:19 -0400 Subject: media: vivid: make input std_signal per-input Make the following properties per-input: -Standard Signal Mode -Standard These properties need to be per-input in order to implement proper HDMI (dis)connect-behavior, where the signal mode will be used to signify whether or not there is an inpute device connected. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 5 ++- drivers/media/platform/vivid/vivid-core.h | 10 ++--- drivers/media/platform/vivid/vivid-ctrls.c | 14 +++--- drivers/media/platform/vivid/vivid-kthread-cap.c | 6 +-- drivers/media/platform/vivid/vivid-vbi-cap.c | 16 +++---- drivers/media/platform/vivid/vivid-vid-cap.c | 55 +++++++++++++++--------- drivers/media/platform/vivid/vivid-vid-common.c | 4 +- 7 files changed, 64 insertions(+), 46 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index f481f1768184..85e6aaf7bf0d 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -999,14 +999,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->webcam_size_idx = 1; dev->webcam_ival_idx = 3; tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); - dev->std_cap = V4L2_STD_PAL; dev->std_out = V4L2_STD_PAL; if (dev->input_type[0] == TV || dev->input_type[0] == SVID) tvnorms_cap = V4L2_STD_ALL; if (dev->output_type[0] == SVID) tvnorms_out = V4L2_STD_ALL; - for (i = 0; i < MAX_INPUTS; i++) + for (i = 0; i < MAX_INPUTS; i++) { dev->dv_timings_cap[i] = def_dv_timings; + dev->std_cap[i] = V4L2_STD_PAL; + } dev->dv_timings_out = def_dv_timings; dev->tv_freq = 2804 /* 175.25 * 16 */; dev->tv_audmode = V4L2_TUNER_MODE_STEREO; diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 713ed7e87f76..f9d26a42b370 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -287,10 +287,10 @@ struct vivid_dev { bool time_wrap; u64 time_wrap_offset; unsigned perc_dropped_buffers; - enum vivid_signal_mode std_signal_mode; - unsigned query_std_last; - v4l2_std_id query_std; - enum tpg_video_aspect std_aspect_ratio; + enum vivid_signal_mode std_signal_mode[MAX_INPUTS]; + unsigned int query_std_last[MAX_INPUTS]; + v4l2_std_id query_std[MAX_INPUTS]; + enum tpg_video_aspect std_aspect_ratio[MAX_INPUTS]; enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS]; char **query_dv_timings_qmenu; @@ -302,7 +302,7 @@ struct vivid_dev { /* Input */ unsigned input; - v4l2_std_id std_cap; + v4l2_std_id std_cap[MAX_INPUTS]; struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS]; int dv_timings_cap_sel[MAX_INPUTS]; u32 service_set_cap; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index a3c9661caf95..e27103f694c5 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -463,7 +463,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) tpg_s_show_square(&dev->tpg, ctrl->val); break; case VIVID_CID_STD_ASPECT_RATIO: - dev->std_aspect_ratio = ctrl->val; + dev->std_aspect_ratio[dev->input] = ctrl->val; tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); break; case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: @@ -1130,10 +1130,14 @@ static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl) switch (ctrl->id) { case VIVID_CID_STD_SIGNAL_MODE: - dev->std_signal_mode = dev->ctrl_std_signal_mode->val; - if (dev->std_signal_mode == SELECTED_STD) - dev->query_std = vivid_standard[dev->ctrl_standard->val]; - v4l2_ctrl_activate(dev->ctrl_standard, dev->std_signal_mode == SELECTED_STD); + dev->std_signal_mode[dev->input] = + dev->ctrl_std_signal_mode->val; + if (dev->std_signal_mode[dev->input] == SELECTED_STD) + dev->query_std[dev->input] = + vivid_standard[dev->ctrl_standard->val]; + v4l2_ctrl_activate(dev->ctrl_standard, + dev->std_signal_mode[dev->input] == + SELECTED_STD); vivid_update_quality(dev); vivid_send_source_change(dev, TV); vivid_send_source_change(dev, SVID); diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c index b4eee952e1c9..6cf495a7d5cc 100644 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ b/drivers/media/platform/vivid/vivid-kthread-cap.c @@ -43,7 +43,7 @@ static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) { if (vivid_is_sdtv_cap(dev)) - return dev->std_cap; + return dev->std_cap[dev->input]; return 0; } @@ -408,7 +408,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; unsigned line_height = 16 / factor; bool is_tv = vivid_is_sdtv_cap(dev); - bool is_60hz = is_tv && (dev->std_cap & V4L2_STD_525_60); + bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60); unsigned p; int line = 1; u8 *basep[TPG_MAX_PLANES][2]; @@ -419,7 +419,7 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) if (dev->loop_video && dev->can_loop_video && ((vivid_is_svid_cap(dev) && - !VIVID_INVALID_SIGNAL(dev->std_signal_mode)) || + !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) || (vivid_is_hdmi_cap(dev) && !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) is_loop = true; diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c index 40ecd7902b56..1a9348eea781 100644 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ b/drivers/media/platform/vivid/vivid-vbi-cap.c @@ -18,7 +18,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) { struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); @@ -65,7 +65,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) { - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; vbi->sampling_rate = 27000000; vbi->offset = 24; @@ -93,7 +93,7 @@ void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0)); - if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); } @@ -111,7 +111,7 @@ void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0)); - if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { unsigned i; for (i = 0; i < 25; i++) @@ -124,7 +124,7 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq, unsigned sizes[], struct device *alloc_devs[]) { struct vivid_dev *dev = vb2_get_drv_priv(vq); - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 36 * sizeof(struct v4l2_sliced_vbi_data) : 1440 * 2 * (is_60hz ? 12 : 18); @@ -144,7 +144,7 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq, static int vbi_cap_buf_prepare(struct vb2_buffer *vb) { struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? 36 * sizeof(struct v4l2_sliced_vbi_data) : 1440 * 2 * (is_60hz ? 12 : 18); @@ -302,7 +302,7 @@ int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_forma { struct vivid_dev *dev = video_drvdata(file); struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - bool is_60hz = dev->std_cap & V4L2_STD_525_60; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; u32 service_set = vbi->service_set; if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) @@ -337,7 +337,7 @@ int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_ bool is_60hz; if (vdev->vfl_dir == VFL_DIR_RX) { - is_60hz = dev->std_cap & V4L2_STD_525_60; + is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) return -EINVAL; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 2f8db64e3e65..6edb0325f25f 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -191,7 +191,7 @@ static void vid_cap_buf_finish(struct vb2_buffer *vb) * test this. */ vbuf->flags |= V4L2_BUF_FLAG_TIMECODE; - if (dev->std_cap & V4L2_STD_525_60) + if (dev->std_cap[dev->input] & V4L2_STD_525_60) fps = 30; tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS; tc->flags = 0; @@ -299,7 +299,8 @@ void vivid_update_quality(struct vivid_dev *dev) tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } - if (vivid_is_sdtv_cap(dev) && VIVID_INVALID_SIGNAL(dev->std_signal_mode)) { + if (vivid_is_sdtv_cap(dev) && + VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); return; } @@ -354,7 +355,7 @@ static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc) enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) { if (vivid_is_sdtv_cap(dev)) - return dev->std_aspect_ratio; + return dev->std_aspect_ratio[dev->input]; if (vivid_is_hdmi_cap(dev)) return dev->dv_timings_aspect_ratio[dev->input]; @@ -365,7 +366,7 @@ enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) { if (vivid_is_sdtv_cap(dev)) - return (dev->std_cap & V4L2_STD_525_60) ? + return (dev->std_cap[dev->input] & V4L2_STD_525_60) ? TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; if (vivid_is_hdmi_cap(dev) && @@ -399,7 +400,7 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) case SVID: dev->field_cap = dev->tv_field_cap; dev->src_rect.width = 720; - if (dev->std_cap & V4L2_STD_525_60) { + if (dev->std_cap[dev->input] & V4L2_STD_525_60) { dev->src_rect.height = 480; dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 }; dev->service_set_cap = V4L2_SLICED_CAPTION_525; @@ -582,7 +583,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, h = sz->height; } else if (vivid_is_sdtv_cap(dev)) { w = 720; - h = (dev->std_cap & V4L2_STD_525_60) ? 480 : 576; + h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576; } else { w = dev->src_rect.width; h = dev->src_rect.height; @@ -1318,9 +1319,9 @@ int vidioc_enum_input(struct file *file, void *priv, if (dev->sensor_vflip) inp->status |= V4L2_IN_ST_VFLIP; if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) { - if (dev->std_signal_mode == NO_SIGNAL) { + if (dev->std_signal_mode[dev->input] == NO_SIGNAL) { inp->status |= V4L2_IN_ST_NO_SIGNAL; - } else if (dev->std_signal_mode == NO_LOCK) { + } else if (dev->std_signal_mode[dev->input] == NO_LOCK) { inp->status |= V4L2_IN_ST_NO_H_LOCK; } else if (vivid_is_tv_cap(dev)) { switch (tpg_g_quality(&dev->tpg)) { @@ -1410,11 +1411,20 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i) v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) && dev->dv_timings_signal_mode[dev->input] == SELECTED_DV_TIMINGS); + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, vivid_is_sdtv_cap(dev)); + v4l2_ctrl_activate(dev->ctrl_standard, vivid_is_sdtv_cap(dev) && + dev->std_signal_mode[dev->input]); + if (vivid_is_hdmi_cap(dev)) { v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode, dev->dv_timings_signal_mode[dev->input]); v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings, dev->query_dv_timings[dev->input]); + } else if (vivid_is_sdtv_cap(dev)) { + v4l2_ctrl_s_ctrl(dev->ctrl_std_signal_mode, + dev->std_signal_mode[dev->input]); + v4l2_ctrl_s_ctrl(dev->ctrl_standard, + dev->std_signal_mode[dev->input]); } return 0; @@ -1509,8 +1519,9 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) } else if (qual == TPG_QUAL_GRAY) { vt->rxsubchans = V4L2_TUNER_SUB_MONO; } else { - unsigned channel_nr = dev->tv_freq / (6 * 16); - unsigned options = (dev->std_cap & V4L2_STD_NTSC_M) ? 4 : 3; + unsigned int channel_nr = dev->tv_freq / (6 * 16); + unsigned int options = + (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3; switch (channel_nr % options) { case 0: @@ -1520,7 +1531,7 @@ int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) vt->rxsubchans = V4L2_TUNER_SUB_STEREO; break; case 2: - if (dev->std_cap & V4L2_STD_NTSC_M) + if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; else vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; @@ -1577,23 +1588,25 @@ const char * const vivid_ctrl_standard_strings[] = { int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id) { struct vivid_dev *dev = video_drvdata(file); + unsigned int last = dev->query_std_last[dev->input]; if (!vivid_is_sdtv_cap(dev)) return -ENODATA; - if (dev->std_signal_mode == NO_SIGNAL || - dev->std_signal_mode == NO_LOCK) { + if (dev->std_signal_mode[dev->input] == NO_SIGNAL || + dev->std_signal_mode[dev->input] == NO_LOCK) { *id = V4L2_STD_UNKNOWN; return 0; } if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) { *id = V4L2_STD_UNKNOWN; - } else if (dev->std_signal_mode == CURRENT_STD) { - *id = dev->std_cap; - } else if (dev->std_signal_mode == SELECTED_STD) { - *id = dev->query_std; + } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) { + *id = dev->std_cap[dev->input]; + } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) { + *id = dev->query_std[dev->input]; } else { - *id = vivid_standard[dev->query_std_last]; - dev->query_std_last = (dev->query_std_last + 1) % ARRAY_SIZE(vivid_standard); + *id = vivid_standard[last]; + dev->query_std_last[dev->input] = + (last + 1) % ARRAY_SIZE(vivid_standard); } return 0; @@ -1605,11 +1618,11 @@ int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) if (!vivid_is_sdtv_cap(dev)) return -ENODATA; - if (dev->std_cap == id) + if (dev->std_cap[dev->input] == id) return 0; if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) return -EBUSY; - dev->std_cap = id; + dev->std_cap[dev->input] = id; vivid_update_format_cap(dev, false); return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 98c0e5b4d391..10a344c29a1a 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -645,7 +645,7 @@ bool vivid_vid_can_loop(struct vivid_dev *dev) dev->field_cap == V4L2_FIELD_SEQ_BT) return false; if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { - if (!(dev->std_cap & V4L2_STD_525_60) != + if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) != !(dev->std_out & V4L2_STD_525_60)) return false; return true; @@ -805,7 +805,7 @@ int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) if (vdev->vfl_dir == VFL_DIR_RX) { if (!vivid_is_sdtv_cap(dev)) return -ENODATA; - *id = dev->std_cap; + *id = dev->std_cap[dev->input]; } else { if (!vivid_is_svid_out(dev)) return -ENODATA; -- cgit v1.2.3-59-g8ed1b From c533435ffb91ff52a407fae24b2fe560870aea10 Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:20 -0400 Subject: media: vivid: add display present control Add a custom control for selecting the presence of a display connected to the active output. This control is part of an effort to implement proper HDMI (dis)connect behavior for vivid. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 3 +++ drivers/media/platform/vivid/vivid-core.h | 2 ++ drivers/media/platform/vivid/vivid-ctrls.c | 18 ++++++++++++++++++ drivers/media/platform/vivid/vivid-vid-out.c | 6 ++++++ 4 files changed, 29 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 85e6aaf7bf0d..b1d5332b363f 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -730,6 +730,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) for (i = 0; i < dev->num_outputs; i++) { dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID; dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++; + dev->display_present[i] = true; } dev->has_audio_outputs = out_type_counter[SVID]; if (out_type_counter[HDMI] == 16) { @@ -1038,6 +1039,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) goto unreg_dev; /* enable/disable interface specific controls */ + if (dev->num_outputs && dev->output_type[0] != HDMI) + v4l2_ctrl_activate(dev->ctrl_display_present, false); if (dev->num_inputs && dev->input_type[0] != HDMI) { v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); v4l2_ctrl_activate(dev->ctrl_dv_timings, false); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index f9d26a42b370..3b89e930eb0d 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -225,6 +225,7 @@ struct vivid_dev { struct v4l2_ctrl *ctrl_dv_timings_signal_mode; struct v4l2_ctrl *ctrl_dv_timings; }; + struct v4l2_ctrl *ctrl_display_present; struct v4l2_ctrl *ctrl_has_crop_cap; struct v4l2_ctrl *ctrl_has_compose_cap; struct v4l2_ctrl *ctrl_has_scaler_cap; @@ -349,6 +350,7 @@ struct vivid_dev { u8 *scaled_line; u8 *blended_line; unsigned cur_scaled_line; + bool display_present[MAX_OUTPUTS]; /* Output Overlay */ void *fb_vbase_out; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index e27103f694c5..6e6e8e0fb4bd 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -68,6 +68,7 @@ #define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) #define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42) #define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43) +#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44) #define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) #define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) @@ -944,6 +945,12 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) if (dev->loop_video) vivid_send_source_change(dev, HDMI); break; + case VIVID_CID_DISPLAY_PRESENT: + if (dev->output_type[dev->output] != HDMI) + break; + + dev->display_present[dev->output] = ctrl->val; + break; } return 0; } @@ -982,6 +989,15 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = { .step = 1, }; +static const struct v4l2_ctrl_config vivid_ctrl_display_present = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_DISPLAY_PRESENT, + .name = "Display Present", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; /* Streaming Controls */ @@ -1588,6 +1604,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, 0, V4L2_DV_TX_MODE_HDMI); + dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_display_present, NULL); } if ((dev->has_vid_cap && dev->has_vid_out) || (dev->has_vbi_cap && dev->has_vbi_out)) diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index 9350ca65dd91..148b663a6075 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -1094,6 +1094,12 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o) dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; vivid_update_format_out(dev); + + v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev)); + if (vivid_is_hdmi_out(dev)) + v4l2_ctrl_s_ctrl(dev->ctrl_display_present, + dev->display_present[dev->output]); + return 0; } -- cgit v1.2.3-59-g8ed1b From 389e21b312a4bbe4ae72de5412dd3db6ea0818fa Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:21 -0400 Subject: media: vivid: add number of HDMI ports to device state This will be used for HDMI-specific controls such as hotplug detection and power present. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 2 ++ drivers/media/platform/vivid/vivid-core.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index b1d5332b363f..8c211fba3c66 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -720,6 +720,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) in_type_counter[HDMI]--; dev->num_inputs--; } + dev->num_hdmi_inputs = in_type_counter[HDMI]; /* how many outputs do we have and of what type? */ dev->num_outputs = num_outputs[inst]; @@ -742,6 +743,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) out_type_counter[HDMI]--; dev->num_outputs--; } + dev->num_hdmi_outputs = out_type_counter[HDMI]; /* do we create a video capture device? */ dev->has_vid_cap = node_type & 0x0001; diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 3b89e930eb0d..3b2c346ed53d 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -168,9 +168,11 @@ struct vivid_dev { /* supported features */ bool multiplanar; unsigned num_inputs; + unsigned int num_hdmi_inputs; u8 input_type[MAX_INPUTS]; u8 input_name_counter[MAX_INPUTS]; unsigned num_outputs; + unsigned int num_hdmi_outputs; u8 output_type[MAX_OUTPUTS]; u8 output_name_counter[MAX_OUTPUTS]; bool has_audio_inputs; -- cgit v1.2.3-59-g8ed1b From 79a792dafac60b8bd7397e0bf15b3e9ce8a6278c Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:22 -0400 Subject: media: vivid: add HDMI (dis)connect TX emulation Adds the following bitmask controls: -V4L2_CID_DV_TX_EDID_PRESENT -V4L2_CID_DV_TX_HOTPLUG -V4L2_CID_DV_TX_RXSENSE The bitmasks are all set based on the custom vivid DISPLAY_PRESENT control. This also removes 2/2 v4l2-compliance warnings for vivid output device. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.h | 3 +++ drivers/media/platform/vivid/vivid-ctrls.c | 25 ++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index 3b2c346ed53d..a5f0177da2d3 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -236,6 +236,9 @@ struct vivid_dev { struct v4l2_ctrl *ctrl_has_scaler_out; struct v4l2_ctrl *ctrl_tx_mode; struct v4l2_ctrl *ctrl_tx_rgb_range; + struct v4l2_ctrl *ctrl_tx_edid_present; + struct v4l2_ctrl *ctrl_tx_hotplug; + struct v4l2_ctrl *ctrl_tx_rxsense; struct v4l2_ctrl *radio_tx_rds_pi; struct v4l2_ctrl *radio_tx_rds_pty; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index 6e6e8e0fb4bd..ab25973894b4 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -912,6 +912,8 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) { struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out); struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + u32 display_present = 0; + unsigned int i, j; switch (ctrl->id) { case VIVID_CID_HAS_CROP_OUT: @@ -950,6 +952,15 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) break; dev->display_present[dev->output] = ctrl->val; + + for (i = 0, j = 0; i < dev->num_outputs; i++) + if (dev->output_type[i] == HDMI) + display_present |= + dev->display_present[i] << j++; + + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present); + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present); + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present); break; } return 0; @@ -1593,7 +1604,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); } - if (has_hdmi && dev->has_vid_out) { + if (dev->num_hdmi_outputs) { /* * We aren't doing anything with this at the moment, but * HDMI outputs typically have this controls. @@ -1606,6 +1617,18 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, 0, V4L2_DV_TX_MODE_HDMI); dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_display_present, NULL); + dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_HOTPLUG, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1); + dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_RXSENSE, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1); + dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_outputs - 1)) - 1); } if ((dev->has_vid_cap && dev->has_vid_out) || (dev->has_vbi_cap && dev->has_vbi_out)) -- cgit v1.2.3-59-g8ed1b From 8a99e9faa131b2cfedf9764c646b85ad6217f2e8 Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:23 -0400 Subject: media: vivid: add HDMI (dis)connect RX emulation Adds the following bitmask control: -V4L2_CID_DV_RX_POWER_PRESENT The RX_POWER_PRESENT bitmask is set based on the digital video timings signal mode. This also removes 1/1 warnings for v4l2-compliance test on vivid instance with HDMI input. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.h | 4 ++++ drivers/media/platform/vivid/vivid-ctrls.c | 21 +++++++++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index a5f0177da2d3..7ebb14673c75 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -240,6 +240,8 @@ struct vivid_dev { struct v4l2_ctrl *ctrl_tx_hotplug; struct v4l2_ctrl *ctrl_tx_rxsense; + struct v4l2_ctrl *ctrl_rx_power_present; + struct v4l2_ctrl *radio_tx_rds_pi; struct v4l2_ctrl *radio_tx_rds_pty; struct v4l2_ctrl *radio_tx_rds_mono_stereo; @@ -323,6 +325,8 @@ struct vivid_dev { unsigned tv_field_cap; unsigned tv_audio_input; + u32 power_present; + /* Capture Overlay */ struct v4l2_framebuffer fb_cap; struct v4l2_fh *overlay_cap_owner; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index ab25973894b4..ed80ba51441e 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -358,7 +358,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) V4L2_COLORSPACE_470_SYSTEM_BG, }; struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap); - unsigned i; + unsigned int i, j; switch (ctrl->id) { case VIVID_CID_TEST_PATTERN: @@ -472,6 +472,18 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) dev->ctrl_dv_timings_signal_mode->val; dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val; + dev->power_present = 0; + for (i = 0, j = 0; + i < ARRAY_SIZE(dev->dv_timings_signal_mode); + i++) + if (dev->input_type[i] == HDMI) { + if (dev->dv_timings_signal_mode[i] != NO_SIGNAL) + dev->power_present |= (1 << j); + j++; + } + __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present, + dev->power_present); + v4l2_ctrl_activate(dev->ctrl_dv_timings, dev->dv_timings_signal_mode[dev->input] == SELECTED_DV_TIMINGS); @@ -1583,7 +1595,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL); } - if (has_hdmi && dev->has_vid_cap) { + if (dev->num_hdmi_inputs) { dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_signal_mode, NULL); @@ -1603,6 +1615,11 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, &vivid_vid_cap_ctrl_ops, V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, 0, V4L2_DV_RGB_RANGE_AUTO); + dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap, + NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, + (2 << (dev->num_hdmi_inputs - 1)) - 1, 0, + (2 << (dev->num_hdmi_inputs - 1)) - 1); + } if (dev->num_hdmi_outputs) { /* -- cgit v1.2.3-59-g8ed1b From 4ee895e71abb51de61f8ea4b7cdba68e474ccf16 Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:24 -0400 Subject: media: vivid: reorder CEC allocation and control set-up CEC adapters and controllers (handlers) are now set up as follows: 1. Allocate CEC adapters: setup of control handlers in next step requires these adapters to be allocated. 2. Setup of control handlers: This must be done prior to registering and exposing the adapters to user space to avoid a race condition. 3. Register CEC adapters: make them available to user space. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: PTR_ERR -> PTR_ERR_OR_ZERO] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 100 +++++++++++++++++------------- 1 file changed, 58 insertions(+), 42 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 8c211fba3c66..bc2a176937a4 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -667,6 +667,9 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; int ret; int i; +#ifdef CONFIG_VIDEO_VIVID_CEC + unsigned int cec_tx_bus_cnt = 0; +#endif /* allocate main vivid state structure */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -1058,14 +1061,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) vivid_update_format_cap(dev, false); vivid_update_format_out(dev); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); - /* initialize overlay */ dev->fb_cap.fmt.width = dev->src_rect.width; dev->fb_cap.fmt.height = dev->src_rect.height; @@ -1226,6 +1221,47 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->fb_info.node); } +#ifdef CONFIG_VIDEO_VIVID_CEC + if (dev->has_vid_cap && in_type_counter[HDMI]) { + struct cec_adapter *adap; + + adap = vivid_cec_alloc_adap(dev, 0, false); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) + goto unreg_dev; + dev->cec_rx_adap = adap; + } + + if (dev->has_vid_out) { + for (i = 0; i < dev->num_outputs; i++) { + struct cec_adapter *adap; + + if (dev->output_type[i] != HDMI) + continue; + + dev->cec_output2bus_map[i] = cec_tx_bus_cnt; + adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) { + for (i = 0; i < dev->num_outputs; i++) + cec_delete_adapter(dev->cec_tx_adap[i]); + goto unreg_dev; + } + + dev->cec_tx_adap[cec_tx_bus_cnt] = adap; + cec_tx_bus_cnt++; + } + } +#endif + + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); + /* finally start creating the device nodes */ if (dev->has_vid_cap) { vfd = &dev->vid_cap_dev; @@ -1255,22 +1291,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) #ifdef CONFIG_VIDEO_VIVID_CEC if (in_type_counter[HDMI]) { - struct cec_adapter *adap; - - adap = vivid_cec_alloc_adap(dev, 0, false); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) - goto unreg_dev; - dev->cec_rx_adap = adap; - ret = cec_register_adapter(adap, &pdev->dev); + ret = cec_register_adapter(dev->cec_rx_adap, &pdev->dev); if (ret < 0) { - cec_delete_adapter(adap); + cec_delete_adapter(dev->cec_rx_adap); dev->cec_rx_adap = NULL; goto unreg_dev; } - cec_s_phys_addr(adap, 0, false); + cec_s_phys_addr(dev->cec_rx_adap, 0, false); v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n", - dev_name(&adap->devnode.dev)); + dev_name(&dev->cec_rx_adap->devnode.dev)); } #endif @@ -1282,10 +1311,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) } if (dev->has_vid_out) { -#ifdef CONFIG_VIDEO_VIVID_CEC - unsigned int bus_cnt = 0; -#endif - vfd = &dev->vid_out_dev; snprintf(vfd->name, sizeof(vfd->name), "vivid-%03d-vid-out", inst); @@ -1313,30 +1338,21 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) #endif #ifdef CONFIG_VIDEO_VIVID_CEC - for (i = 0; i < dev->num_outputs; i++) { - struct cec_adapter *adap; - - if (dev->output_type[i] != HDMI) - continue; - dev->cec_output2bus_map[i] = bus_cnt; - adap = vivid_cec_alloc_adap(dev, bus_cnt, true); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) - goto unreg_dev; - dev->cec_tx_adap[bus_cnt] = adap; - ret = cec_register_adapter(adap, &pdev->dev); + for (i = 0; i < cec_tx_bus_cnt; i++) { + ret = cec_register_adapter(dev->cec_tx_adap[i], &pdev->dev); if (ret < 0) { - cec_delete_adapter(adap); - dev->cec_tx_adap[bus_cnt] = NULL; + for (; i < cec_tx_bus_cnt; i++) { + cec_delete_adapter(dev->cec_tx_adap[i]); + dev->cec_tx_adap[i] = NULL; + } goto unreg_dev; } v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", - dev_name(&adap->devnode.dev), bus_cnt); - bus_cnt++; - if (bus_cnt <= out_type_counter[HDMI]) - cec_s_phys_addr(adap, bus_cnt << 12, false); + dev_name(&dev->cec_tx_adap[i]->devnode.dev), i); + if (i <= out_type_counter[HDMI]) + cec_s_phys_addr(dev->cec_tx_adap[i], i << 12, false); else - cec_s_phys_addr(adap, 0x1000, false); + cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false); } #endif -- cgit v1.2.3-59-g8ed1b From 4938958f5374962e54cfdb04a7b041808af3d4c8 Mon Sep 17 00:00:00 2001 From: Johan Korsnes Date: Tue, 18 Jun 2019 03:37:25 -0400 Subject: media: vivid: add CEC support to display present ctrl Set/invalidate physical addresses based on the configuration of the display present control. This is relevant not only when the display present control is modified, but also when the Vivid instance EDID is set/cleared. Signed-off-by: Johan Korsnes Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-ctrls.c | 25 +++++++++++++++++++++---- drivers/media/platform/vivid/vivid-vid-cap.c | 17 +++++++++++++++-- drivers/media/platform/vivid/vivid-vid-common.c | 2 ++ 3 files changed, 38 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index ed80ba51441e..3e916c8befb7 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -18,6 +18,7 @@ #include "vivid-radio-common.h" #include "vivid-osd.h" #include "vivid-ctrls.h" +#include "vivid-cec.h" #define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) #define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0) @@ -925,7 +926,7 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out); struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; u32 display_present = 0; - unsigned int i, j; + unsigned int i, j, bus_idx; switch (ctrl->id) { case VIVID_CID_HAS_CROP_OUT: @@ -964,15 +965,31 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) break; dev->display_present[dev->output] = ctrl->val; - for (i = 0, j = 0; i < dev->num_outputs; i++) if (dev->output_type[i] == HDMI) display_present |= dev->display_present[i] << j++; - __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present); __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present); - __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present); + + if (dev->edid_blocks) { + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, + display_present); + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, + display_present); + } + + bus_idx = dev->cec_output2bus_map[dev->output]; + if (!dev->cec_tx_adap[bus_idx]) + break; + + if (ctrl->val && dev->edid_blocks) + cec_s_phys_addr(dev->cec_tx_adap[bus_idx], + dev->cec_tx_adap[bus_idx]->phys_addr, + false); + else + cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]); + break; } return 0; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 6edb0325f25f..8cbaa0c998ed 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1748,7 +1748,8 @@ int vidioc_s_edid(struct file *file, void *_fh, { struct vivid_dev *dev = video_drvdata(file); u16 phys_addr; - unsigned int i; + u32 display_present = 0; + unsigned int i, j; int ret; memset(edid->reserved, 0, sizeof(edid->reserved)); @@ -1758,6 +1759,8 @@ int vidioc_s_edid(struct file *file, void *_fh, return -EINVAL; if (edid->blocks == 0) { dev->edid_blocks = 0; + v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0); + v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0); phys_addr = CEC_PHYS_ADDR_INVALID; goto set_phys_addr; } @@ -1776,13 +1779,23 @@ int vidioc_s_edid(struct file *file, void *_fh, dev->edid_blocks = edid->blocks; memcpy(dev->edid, edid->edid, edid->blocks * 128); + for (i = 0, j = 0; i < dev->num_outputs; i++) + if (dev->output_type[i] == HDMI) + display_present |= + dev->display_present[i] << j++; + + v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present); + v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present); + set_phys_addr: /* TODO: a proper hotplug detect cycle should be emulated here */ cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false); for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) cec_s_phys_addr(dev->cec_tx_adap[i], - v4l2_phys_addr_for_input(phys_addr, i + 1), + dev->display_present[i] ? + v4l2_phys_addr_for_input(phys_addr, i + 1) : + CEC_PHYS_ADDR_INVALID, false); return 0; } diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 10a344c29a1a..1f33eb1a76b6 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -887,6 +887,8 @@ int vidioc_g_edid(struct file *file, void *_fh, return -EINVAL; if (dev->output_type[edid->pad] != HDMI) return -EINVAL; + if (!dev->display_present[edid->pad]) + return -ENODATA; bus_idx = dev->cec_output2bus_map[edid->pad]; adap = dev->cec_tx_adap[bus_idx]; } -- cgit v1.2.3-59-g8ed1b From 26092e7eec3d1a5f2dd4fc9cb691bfdcdc558a51 Mon Sep 17 00:00:00 2001 From: Shobhit Kukreti Date: Sat, 1 Jun 2019 11:27:34 -0400 Subject: media: i2c: Fix Unnecessary Semicolon Warning Reported by coccicheck Removed the warning from the following files: drivers/media/i2c/ov13858.c drivers/media/i2c/ov2685.c drivers/media/i2c/ov5695.c Signed-off-by: Shobhit Kukreti Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov13858.c | 4 ++-- drivers/media/i2c/ov2685.c | 2 +- drivers/media/i2c/ov5695.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 45bb872db3c5..aac6f77afa0f 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -1224,7 +1224,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) ov13858->exposure->minimum, max, ov13858->exposure->step, max); break; - }; + } /* * Applying V4L2 control value only happens @@ -1262,7 +1262,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; - }; + } pm_runtime_put(&client->dev); diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 98a1f2e312b5..6814583d9606 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -576,7 +576,7 @@ static int ov2685_set_ctrl(struct v4l2_ctrl *ctrl) __func__, ctrl->id, ctrl->val); ret = -EINVAL; break; - }; + } pm_runtime_put(&client->dev); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 5d107c53364d..e65a94353175 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1143,7 +1143,7 @@ static int ov5695_set_ctrl(struct v4l2_ctrl *ctrl) dev_warn(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); break; - }; + } pm_runtime_put(&client->dev); -- cgit v1.2.3-59-g8ed1b From 5c49ac3ac6562a39baa2aece050a14b661197036 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Sun, 2 Jun 2019 17:22:15 -0400 Subject: media: ov6650: Fix device node exposed without proper locking Commit c62b96050bee ("media: ov6650: Register with asynchronous subdevice framework") carelessly requested creation of a video device node by setting a V4L2_SUBDEV_FL_HAS_DEVNODE flag. The driver is not ready for that as it doesn't implement proper locking required for serialization of IOCTLs. Fix it by dropping the flag assignment. Fixes: c62b96050bee ("media: ov6650: Register with asynchronous subdevice framework") Signed-off-by: Janusz Krzysztofik Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov6650.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index 1b972e591b48..ace95ba7dd19 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -1009,7 +1009,6 @@ static int ov6650_probe(struct i2c_client *client, priv->colorspace = V4L2_COLORSPACE_JPEG; priv->subdev.internal_ops = &ov6650_internal_ops; - priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ret = v4l2_async_register_subdev(&priv->subdev); if (ret) -- cgit v1.2.3-59-g8ed1b From 4ace2d28aba594e234923f55f476e97c56f6689a Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 6 Jun 2019 10:18:42 -0400 Subject: media: v4l2-fwnode: Avoid using PTR_ERR(NULL) PTR_ERR(NULL) yields 0 which is commonly used to denote success. This is the case here, and PTR_ERR(NULL) is apparently shunned upon. Fix this by explicitly returning 0 if fwnode == NULL. Reported-by: Hans Verkuil Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 44e9bcb67935..7e740d332a54 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1095,7 +1095,7 @@ v4l2_fwnode_reference_parse_int_props(struct device *dev, } } - return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); + return !fwnode || PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode); error: fwnode_handle_put(fwnode); -- cgit v1.2.3-59-g8ed1b From e14b77c3db5c97c5ef67f508cc302571163dbbca Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 6 Jun 2019 10:21:25 -0400 Subject: media: ov9640: Don't check for NULL on devm_gpiod_get return values devm_gpiod_get never returns NULL; therefore it's not necessary to check for that. PTR_ERR(NULL) also yields zero, which is confusing to smatch. Reported-by: Hans Verkuil Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov9640.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index d6831f28378b..482609665305 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -691,14 +691,14 @@ static int ov9640_probe(struct i2c_client *client, priv->gpio_power = devm_gpiod_get(&client->dev, "Camera power", GPIOD_OUT_LOW); - if (IS_ERR_OR_NULL(priv->gpio_power)) { + if (IS_ERR(priv->gpio_power)) { ret = PTR_ERR(priv->gpio_power); return ret; } priv->gpio_reset = devm_gpiod_get(&client->dev, "Camera reset", GPIOD_OUT_HIGH); - if (IS_ERR_OR_NULL(priv->gpio_reset)) { + if (IS_ERR(priv->gpio_reset)) { ret = PTR_ERR(priv->gpio_reset); return ret; } -- cgit v1.2.3-59-g8ed1b From 3a959dcd11a4b1f55bbb4a37d3bac685c4e106b1 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 29 May 2019 15:25:18 -0400 Subject: media: mt9m111: add regulator support In the soc_camera removal, the board specific power callback was dropped. This at least will remove the power optimization from ezx and em-x270 pxa based boards. As to recreate the same level of functionality, make the mt9m111 have a regulator providing it its power, so that board designers can plug in a gpio based or ldo regulator, mimicking their former soc_camera power hook. [sakari.ailus@linux.intel.com: fix a build warning] Fixes: 5c10113cc668 ("media: mt9m111: make a standalone v4l2 subdevice") Signed-off-by: Robert Jarzmik Signed-off-by: Mauro Carvalho Chehab Tested-by: Akinobu Mita Tested-by: Robert Jarzmik Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m111.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 5168bb5880c4..746d1345b505 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -243,6 +244,7 @@ struct mt9m111 { int power_count; const struct mt9m111_datafmt *fmt; int lastpage; /* PageMap cache value */ + struct regulator *regulator; bool is_streaming; /* user point of view - 0: falling 1: rising edge */ unsigned int pclk_sample:1; @@ -982,6 +984,12 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) if (ret < 0) return ret; + if (mt9m111->regulator) { + ret = regulator_enable(mt9m111->regulator); + if (ret < 0) + return ret; + } + ret = mt9m111_resume(mt9m111); if (ret < 0) { dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); @@ -994,6 +1002,8 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) static void mt9m111_power_off(struct mt9m111 *mt9m111) { mt9m111_suspend(mt9m111); + if (mt9m111->regulator) + regulator_disable(mt9m111->regulator); v4l2_clk_disable(mt9m111->clk); } @@ -1256,6 +1266,13 @@ static int mt9m111_probe(struct i2c_client *client, if (IS_ERR(mt9m111->clk)) return PTR_ERR(mt9m111->clk); + mt9m111->regulator = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(mt9m111->regulator)) { + dev_err(&client->dev, "regulator not found: %ld\n", + PTR_ERR(mt9m111->regulator)); + return PTR_ERR(mt9m111->regulator); + } + /* Default HIGHPOWER context */ mt9m111->ctx = &context_b; -- cgit v1.2.3-59-g8ed1b From 9a57d72b94869ceb29f932e95cb39f0cc156ea1f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 31 May 2019 16:11:35 -0400 Subject: media: mt9m111: No need to check for the regulator The regulator_get() function returns a regulator when it succeeds. There's no need to check whether the regulator is NULL later on. Signed-off-by: Sakari Ailus Reviewed-by: Marco Felsch Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m111.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 746d1345b505..bb19f8c346cb 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -984,11 +984,9 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) if (ret < 0) return ret; - if (mt9m111->regulator) { - ret = regulator_enable(mt9m111->regulator); - if (ret < 0) - return ret; - } + ret = regulator_enable(mt9m111->regulator); + if (ret < 0) + return ret; ret = mt9m111_resume(mt9m111); if (ret < 0) { @@ -1002,8 +1000,7 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) static void mt9m111_power_off(struct mt9m111 *mt9m111) { mt9m111_suspend(mt9m111); - if (mt9m111->regulator) - regulator_disable(mt9m111->regulator); + regulator_disable(mt9m111->regulator); v4l2_clk_disable(mt9m111->clk); } -- cgit v1.2.3-59-g8ed1b From 04bc4f6631f7e47a9fe47ea6c0794ed56d9b3cf8 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 31 May 2019 16:12:49 -0400 Subject: media: mt9m111: Fix error handling in mt9m111_power_on The mt9m111_power_on function did not properly clean up whenever it encountered an error. Do that now. Signed-off-by: Sakari Ailus Reviewed-by: Marco Felsch Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m111.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index bb19f8c346cb..593ebe5e2cb6 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -986,13 +986,21 @@ static int mt9m111_power_on(struct mt9m111 *mt9m111) ret = regulator_enable(mt9m111->regulator); if (ret < 0) - return ret; + goto out_clk_disable; ret = mt9m111_resume(mt9m111); - if (ret < 0) { - dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); - v4l2_clk_disable(mt9m111->clk); - } + if (ret < 0) + goto out_regulator_disable; + + return 0; + +out_regulator_disable: + regulator_disable(mt9m111->regulator); + +out_clk_disable: + v4l2_clk_disable(mt9m111->clk); + + dev_err(&client->dev, "Failed to resume the sensor: %d\n", ret); return ret; } -- cgit v1.2.3-59-g8ed1b From 5197051fdf4da4962837c4ec6d90d27dab8f2fa6 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Jun 2019 06:55:45 -0400 Subject: media: i2c: ak881x: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ak881x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c index 30f9db1351b9..09860603da64 100644 --- a/drivers/media/i2c/ak881x.c +++ b/drivers/media/i2c/ak881x.c @@ -232,7 +232,7 @@ static const struct v4l2_subdev_ops ak881x_subdev_ops = { static int ak881x_probe(struct i2c_client *client, const struct i2c_device_id *did) { - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; struct ak881x *ak881x; u8 ifmode, data; -- cgit v1.2.3-59-g8ed1b From 41341dd9c389ea96bc9ea57dc34ac443635513c0 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Jun 2019 06:55:46 -0400 Subject: media: i2c: mt9m001: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m001.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 4b23fde937b3..2df743cbe09d 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -730,7 +730,7 @@ static int mt9m001_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m001 *mt9m001; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { -- cgit v1.2.3-59-g8ed1b From 54ed1c182ed28b09683240fe7ebff3000107d956 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Jun 2019 06:55:47 -0400 Subject: media: i2c: mt9m111: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m111.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 593ebe5e2cb6..bd3a51c3b081 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1250,7 +1250,7 @@ static int mt9m111_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct mt9m111 *mt9m111; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { -- cgit v1.2.3-59-g8ed1b From e64de2082dab5e0ca51f7dbe83029f0d7b5b3d34 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Jun 2019 06:55:49 -0400 Subject: media: i2c: ov2640: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ov2640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/ov2640.c b/drivers/media/i2c/ov2640.c index 83031cfc7914..30e7e6b2b293 100644 --- a/drivers/media/i2c/ov2640.c +++ b/drivers/media/i2c/ov2640.c @@ -1197,7 +1197,7 @@ static int ov2640_probe(struct i2c_client *client, const struct i2c_device_id *did) { struct ov2640_priv *priv; - struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { -- cgit v1.2.3-59-g8ed1b From 2a50c83bbd724e8583602ac76fc04c369bd35493 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Jun 2019 06:55:50 -0400 Subject: media: i2c: tw9910: simplify getting the adapter of a client We have a dedicated pointer for that, so use it. Much easier to read and less computation involved. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tw9910.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c index 4d7cd736b930..a25a350b0ddc 100644 --- a/drivers/media/i2c/tw9910.c +++ b/drivers/media/i2c/tw9910.c @@ -934,8 +934,7 @@ static int tw9910_probe(struct i2c_client *client, { struct tw9910_priv *priv; struct tw9910_video_info *info; - struct i2c_adapter *adapter = - to_i2c_adapter(client->dev.parent); + struct i2c_adapter *adapter = client->adapter; int ret; if (!client->dev.platform_data) { -- cgit v1.2.3-59-g8ed1b From 8d4e29a51a954b43e06d916772fa4f50b7e5bbd6 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 3 Jun 2019 16:01:55 -0400 Subject: media: mt9m111: fix fw-node refactoring In the patch refactoring the fw-node, the mt9m111 was broken for all platform_data based platforms, which were the first aim of this driver. Only the devicetree platform are still functional, probably because the testing was done on these. The result is that -EINVAL is systematically return for such platforms, what this patch fixes. [Sakari Ailus: Rework this to resolve a merge conflict and use dev_fwnode] Fixes: 98480d65c48c ("media: mt9m111: allow to setup pixclk polarity") Signed-off-by: Robert Jarzmik Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/mt9m111.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index bd3a51c3b081..d10fe3712036 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1263,9 +1263,11 @@ static int mt9m111_probe(struct i2c_client *client, if (!mt9m111) return -ENOMEM; - ret = mt9m111_probe_fw(client, mt9m111); - if (ret) - return ret; + if (dev_fwnode(&client->dev)) { + ret = mt9m111_probe_fw(client, mt9m111); + if (ret) + return ret; + } mt9m111->clk = v4l2_clk_get(&client->dev, "mclk"); if (IS_ERR(mt9m111->clk)) -- cgit v1.2.3-59-g8ed1b From 415cd3ac4ea04ba916a5b02f7853a504e0994757 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:25 -0400 Subject: media: Revert "[media] marvell-ccic: reset ccic phy when stop streaming for stability" This accesses the clock registers directly and thus is going to stay in the way of making the driver devicetree friendly. No boards seems to actually use this. If it's somehow actually needed it needs to be done differently. This reverts commit 7c269f454e7a51b151d94f99344120efa1cd0acb. Signed-off-by: Lubomir Rintel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 6 ------ drivers/media/platform/marvell-ccic/mcam-core.h | 2 -- drivers/media/platform/marvell-ccic/mmp-driver.c | 25 ------------------------ 3 files changed, 33 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 040fe9501415..2494a31de01b 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1154,12 +1154,6 @@ static void mcam_vb_stop_streaming(struct vb2_queue *vq) if (cam->state != S_STREAMING) return; mcam_ctlr_stop_dma(cam); - /* - * Reset the CCIC PHY after stopping streaming, - * otherwise, the CCIC may be unstable. - */ - if (cam->ctlr_reset) - cam->ctlr_reset(cam); /* * VB2 reclaims the buffers, so we need to forget * about them. diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index ad8955f9f0a1..a3a097a45e78 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -116,7 +116,6 @@ struct mcam_camera { int mclk_src; /* which clock source the mclk derives from */ int mclk_div; /* Clock Divider Value for MCLK */ - int ccic_id; enum v4l2_mbus_type bus_type; /* MIPI support */ /* The dphy config value, allocated in board file @@ -137,7 +136,6 @@ struct mcam_camera { int (*plat_power_up) (struct mcam_camera *cam); void (*plat_power_down) (struct mcam_camera *cam); void (*calc_dphy) (struct mcam_camera *cam); - void (*ctlr_reset) (struct mcam_camera *cam); /* * Everything below here is private to the mcam core and diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index bf4d4a47f1db..9c4c7d37d0df 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -103,7 +103,6 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) #define CPU_SUBSYS_PMU_BASE 0xd4282800 #define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */ #define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */ -#define REG_CCIC2_CRCR 0xf4 /* CCIC2 clk reset ctrl reg */ static void mcam_clk_enable(struct mcam_camera *mcam) { @@ -181,28 +180,6 @@ static void mmpcam_power_down(struct mcam_camera *mcam) mcam_clk_disable(mcam); } -static void mcam_ctlr_reset(struct mcam_camera *mcam) -{ - unsigned long val; - struct mmp_camera *cam = mcam_to_cam(mcam); - - if (mcam->ccic_id) { - /* - * Using CCIC2 - */ - val = ioread32(cam->power_regs + REG_CCIC2_CRCR); - iowrite32(val & ~0x2, cam->power_regs + REG_CCIC2_CRCR); - iowrite32(val | 0x2, cam->power_regs + REG_CCIC2_CRCR); - } else { - /* - * Using CCIC1 - */ - val = ioread32(cam->power_regs + REG_CCIC_CRCR); - iowrite32(val & ~0x2, cam->power_regs + REG_CCIC_CRCR); - iowrite32(val | 0x2, cam->power_regs + REG_CCIC_CRCR); - } -} - /* * calc the dphy register values * There are three dphy registers being used. @@ -350,11 +327,9 @@ static int mmpcam_probe(struct platform_device *pdev) mcam = &cam->mcam; mcam->plat_power_up = mmpcam_power_up; mcam->plat_power_down = mmpcam_power_down; - mcam->ctlr_reset = mcam_ctlr_reset; mcam->calc_dphy = mmpcam_calc_dphy; mcam->dev = &pdev->dev; mcam->use_smbus = 0; - mcam->ccic_id = pdev->id; mcam->mclk_min = pdata->mclk_min; mcam->mclk_src = pdata->mclk_src; mcam->mclk_div = pdata->mclk_div; -- cgit v1.2.3-59-g8ed1b From fa49e1d37bbd6d25a11379891ece1e4d5d313036 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:26 -0400 Subject: media: marvell-ccic: drop unused stuff Remove structure members and headers that are not actually used. Saves us from some noise in subsequent cleanup commits. Signed-off-by: Lubomir Rintel Acked-by: Pavel Machek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 1 - drivers/media/platform/marvell-ccic/mcam-core.h | 2 -- drivers/media/platform/marvell-ccic/mmp-driver.c | 2 -- include/linux/platform_data/media/mmp-camera.h | 1 - 4 files changed, 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 2494a31de01b..76641d5211ab 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -1776,7 +1776,6 @@ int mccic_register(struct mcam_camera *cam) */ sensor_cfg.clock_speed = cam->clock_speed; sensor_cfg.use_smbus = cam->use_smbus; - cam->sensor_addr = ov7670_info.addr; cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, cam->i2c_adapter, &ov7670_info, NULL); if (cam->sensor == NULL) { diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index a3a097a45e78..b828b1bb59d3 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -112,7 +112,6 @@ struct mcam_camera { short int use_smbus; /* SMBUS or straight I2c? */ enum mcam_buffer_mode buffer_mode; - int mclk_min; /* The minimal value of mclk */ int mclk_src; /* which clock source the mclk derives from */ int mclk_div; /* Clock Divider Value for MCLK */ @@ -152,7 +151,6 @@ struct mcam_camera { */ struct video_device vdev; struct v4l2_subdev *sensor; - unsigned short sensor_addr; /* Videobuf2 stuff */ struct vb2_queue vb_queue; diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 9c4c7d37d0df..25a4e2b580f4 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -330,7 +329,6 @@ static int mmpcam_probe(struct platform_device *pdev) mcam->calc_dphy = mmpcam_calc_dphy; mcam->dev = &pdev->dev; mcam->use_smbus = 0; - mcam->mclk_min = pdata->mclk_min; mcam->mclk_src = pdata->mclk_src; mcam->mclk_div = pdata->mclk_div; mcam->bus_type = pdata->bus_type; diff --git a/include/linux/platform_data/media/mmp-camera.h b/include/linux/platform_data/media/mmp-camera.h index d2d3a443eedf..4c3a80a45883 100644 --- a/include/linux/platform_data/media/mmp-camera.h +++ b/include/linux/platform_data/media/mmp-camera.h @@ -16,7 +16,6 @@ struct mmp_camera_platform_data { int sensor_power_gpio; int sensor_reset_gpio; enum v4l2_mbus_type bus_type; - int mclk_min; /* The minimal value of MCLK */ int mclk_src; /* which clock source the MCLK derives from */ int mclk_div; /* Clock Divider Value for MCLK */ /* -- cgit v1.2.3-59-g8ed1b From f12fb2849b11b4c571a32d31ec51eabd70ab8193 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:27 -0400 Subject: media: marvell-ccic/mmp: enable clock before accessing registers The access to REG_CLKCTRL or REG_CTRL1 without the clock enabled hangs the machine. Enable the clock first. Signed-off-by: Lubomir Rintel Acked-by: Pavel Machek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mmp-driver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 25a4e2b580f4..bd2934a4d7ce 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -142,6 +142,7 @@ static int mmpcam_power_up(struct mcam_camera *mcam) * Turn on power and clocks to the controller. */ mmpcam_power_up_ctlr(cam); + mcam_clk_enable(mcam); /* * Provide power to the sensor. */ @@ -155,8 +156,6 @@ static int mmpcam_power_up(struct mcam_camera *mcam) gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */ mdelay(5); - mcam_clk_enable(mcam); - return 0; } -- cgit v1.2.3-59-g8ed1b From 4d5da53d327ccfa2fe3b8a6bf776df8ba3985456 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:28 -0400 Subject: media: marvell-ccic: rename the clocks Use the names more suitable for devicetree bindings. There are no board files utilizing this, thus we seem to be at liberty at renaming this without consequences. Signed-off-by: Lubomir Rintel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mmp-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index bd2934a4d7ce..0634aeca40f2 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -31,7 +31,7 @@ MODULE_ALIAS("platform:mmp-camera"); MODULE_AUTHOR("Jonathan Corbet "); MODULE_LICENSE("GPL"); -static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"}; +static char *mcam_clks[] = {"axi", "func", "phy"}; struct mmp_camera { void __iomem *power_regs; -- cgit v1.2.3-59-g8ed1b From 83c40e6611ec1e548ece34f6940f516333abc16a Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:29 -0400 Subject: media: marvell-ccic/mmp: add devicetree support The platform data is actually not used anywhere (along with the CSI support) and should be safe to remove. Signed-off-by: Lubomir Rintel Acked-by: Pavel Machek Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mmp-driver.c | 36 ++++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 0634aeca40f2..492663a8a29d 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -194,6 +196,9 @@ static void mmpcam_calc_dphy(struct mcam_camera *mcam) struct device *dev = &cam->pdev->dev; unsigned long tx_clk_esc; + if (!pdata) + return; + /* * If CSI2_DPHY3 is calculated dynamically, * pdata->lane_clk should be already set @@ -312,10 +317,6 @@ static int mmpcam_probe(struct platform_device *pdev) struct mmp_camera_platform_data *pdata; int ret; - pdata = pdev->dev.platform_data; - if (!pdata) - return -ENODEV; - cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL); if (cam == NULL) return -ENOMEM; @@ -328,17 +329,29 @@ static int mmpcam_probe(struct platform_device *pdev) mcam->calc_dphy = mmpcam_calc_dphy; mcam->dev = &pdev->dev; mcam->use_smbus = 0; - mcam->mclk_src = pdata->mclk_src; - mcam->mclk_div = pdata->mclk_div; - mcam->bus_type = pdata->bus_type; - mcam->dphy = pdata->dphy; + pdata = pdev->dev.platform_data; + if (pdata) { + mcam->mclk_src = pdata->mclk_src; + mcam->mclk_div = pdata->mclk_div; + mcam->bus_type = pdata->bus_type; + mcam->dphy = pdata->dphy; + mcam->lane = pdata->lane; + } else { + /* + * These are values that used to be hardcoded in mcam-core and + * work well on a OLPC XO 1.75 with a parallel bus sensor. + * If it turns out other setups make sense, the values should + * be obtained from the device tree. + */ + mcam->mclk_src = 3; + mcam->mclk_div = 2; + } if (mcam->bus_type == V4L2_MBUS_CSI2_DPHY) { cam->mipi_clk = devm_clk_get(mcam->dev, "mipi"); if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0)) return PTR_ERR(cam->mipi_clk); } mcam->mipi_enabled = false; - mcam->lane = pdata->lane; mcam->chip_id = MCAM_ARMADA610; mcam->buffer_mode = B_DMA_sg; strscpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info)); @@ -473,6 +486,10 @@ static int mmpcam_resume(struct platform_device *pdev) #endif +static const struct of_device_id mmpcam_of_match[] = { + { .compatible = "marvell,mmp2-ccic", }, + {}, +}; static struct platform_driver mmpcam_driver = { .probe = mmpcam_probe, @@ -483,6 +500,7 @@ static struct platform_driver mmpcam_driver = { #endif .driver = { .name = "mmp-camera", + .of_match_table = of_match_ptr(mmpcam_of_match), } }; -- cgit v1.2.3-59-g8ed1b From 3eefe36cc00c5391b1ca2a68c5f01e9aa127c2a6 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:30 -0400 Subject: media: marvell-ccic: use async notifier to get the sensor An instance of a sensor on DT-based MMP2 platform is always going to be created asynchronously. Let's move the manual device creation away from the core to the Cafe driver (used on OLPC XO-1, not present in DT) and set up appropriate async matches: I2C on Cafe, FWNODE on MMP (OLPC XO-1.75). Signed-off-by: Lubomir Rintel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/cafe-driver.c | 49 +++++-- drivers/media/platform/marvell-ccic/mcam-core.c | 157 +++++++++++++++------- drivers/media/platform/marvell-ccic/mcam-core.h | 5 +- drivers/media/platform/marvell-ccic/mmp-driver.c | 27 ++-- include/linux/platform_data/media/mmp-camera.h | 1 - 5 files changed, 162 insertions(+), 77 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index cd108b14b715..fe85368675cb 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -9,6 +9,7 @@ * * Copyright 2006-11 One Laptop Per Child Association, Inc. * Copyright 2006-11 Jonathan Corbet + * Copyright 2018 Lubomir Rintel * * Written by Jonathan Corbet, corbet@lwn.net. * @@ -25,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +52,7 @@ struct cafe_camera { int registered; /* Fully initialized? */ struct mcam_camera mcam; struct pci_dev *pdev; + struct i2c_adapter *i2c_adapter; wait_queue_head_t smbus_wait; /* Waiting on i2c events */ }; @@ -349,15 +352,15 @@ static int cafe_smbus_setup(struct cafe_camera *cam) return ret; } - cam->mcam.i2c_adapter = adap; + cam->i2c_adapter = adap; cafe_smbus_enable_irq(cam); return 0; } static void cafe_smbus_shutdown(struct cafe_camera *cam) { - i2c_del_adapter(cam->mcam.i2c_adapter); - kfree(cam->mcam.i2c_adapter); + i2c_del_adapter(cam->i2c_adapter); + kfree(cam->i2c_adapter); } @@ -450,6 +453,29 @@ static irqreturn_t cafe_irq(int irq, void *data) return IRQ_RETVAL(handled); } +/* -------------------------------------------------------------------------- */ + +static struct ov7670_config sensor_cfg = { + /* + * Exclude QCIF mode, because it only captures a tiny portion + * of the sensor FOV + */ + .min_width = 320, + .min_height = 240, + + /* + * Set the clock speed for the XO 1; I don't believe this + * driver has ever run anywhere else. + */ + .clock_speed = 45, + .use_smbus = 1, +}; + +struct i2c_board_info ov7670_info = { + .type = "ov7670", + .addr = 0x42 >> 1, + .platform_data = &sensor_cfg, +}; /* -------------------------------------------------------------------------- */ /* @@ -479,12 +505,6 @@ static int cafe_pci_probe(struct pci_dev *pdev, mcam->plat_power_down = cafe_ctlr_power_down; mcam->dev = &pdev->dev; snprintf(mcam->bus_info, sizeof(mcam->bus_info), "PCI:%s", pci_name(pdev)); - /* - * Set the clock speed for the XO 1; I don't believe this - * driver has ever run anywhere else. - */ - mcam->clock_speed = 45; - mcam->use_smbus = 1; /* * Vmalloc mode for buffers is traditional with this driver. * We *might* be able to run DMA_contig, especially on a system @@ -525,12 +545,21 @@ static int cafe_pci_probe(struct pci_dev *pdev, if (ret) goto out_pdown; + mcam->asd.match_type = V4L2_ASYNC_MATCH_I2C; + mcam->asd.match.i2c.adapter_id = i2c_adapter_id(cam->i2c_adapter); + mcam->asd.match.i2c.address = ov7670_info.addr; + ret = mccic_register(mcam); - if (ret == 0) { + if (ret) + goto out_smbus_shutdown; + + if (i2c_new_device(cam->i2c_adapter, &ov7670_info)) { cam->registered = 1; return 0; } + mccic_shutdown(mcam); +out_smbus_shutdown: cafe_smbus_shutdown(cam); out_pdown: cafe_ctlr_power_down(mcam); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 76641d5211ab..7dc7d9d91782 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -4,6 +4,7 @@ * so it needs platform-specific support outside of the core. * * Copyright 2011 Jonathan Corbet corbet@lwn.net + * Copyright 2018 Lubomir Rintel */ #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -93,6 +93,9 @@ MODULE_PARM_DESC(buffer_mode, #define sensor_call(cam, o, f, args...) \ v4l2_subdev_call(cam->sensor, o, f, ##args) +#define notifier_to_mcam(notifier) \ + container_of(notifier, struct mcam_camera, notifier) + static struct mcam_format_struct { __u8 *desc; __u32 pixelformat; @@ -1715,23 +1718,94 @@ EXPORT_SYMBOL_GPL(mccic_irq); /* * Registration and such. */ -static struct ov7670_config sensor_cfg = { + +static int mccic_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) +{ + struct mcam_camera *cam = notifier_to_mcam(notifier); + int ret; + + mutex_lock(&cam->s_mutex); + if (cam->sensor) { + cam_err(cam, "sensor already bound\n"); + ret = -EBUSY; + goto out; + } + + v4l2_set_subdev_hostdata(subdev, cam); + cam->sensor = subdev; + + ret = mcam_cam_init(cam); + if (ret) { + cam->sensor = NULL; + goto out; + } + + ret = mcam_setup_vb2(cam); + if (ret) { + cam->sensor = NULL; + goto out; + } + + cam->vdev = mcam_v4l_template; + cam->vdev.v4l2_dev = &cam->v4l2_dev; + cam->vdev.lock = &cam->s_mutex; + cam->vdev.queue = &cam->vb_queue; + video_set_drvdata(&cam->vdev, cam); + ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); + if (ret) { + cam->sensor = NULL; + goto out; + } + + cam_dbg(cam, "sensor %s bound\n", subdev->name); +out: + mutex_unlock(&cam->s_mutex); + return ret; +} + +static void mccic_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) +{ + struct mcam_camera *cam = notifier_to_mcam(notifier); + + mutex_lock(&cam->s_mutex); + if (cam->sensor != subdev) { + cam_err(cam, "sensor %s not bound\n", subdev->name); + goto out; + } + + video_unregister_device(&cam->vdev); + cam->sensor = NULL; + cam_dbg(cam, "sensor %s unbound\n", subdev->name); + +out: + mutex_unlock(&cam->s_mutex); +} + +static int mccic_notify_complete(struct v4l2_async_notifier *notifier) +{ + struct mcam_camera *cam = notifier_to_mcam(notifier); + int ret; + /* - * Exclude QCIF mode, because it only captures a tiny portion - * of the sensor FOV + * Get the v4l2 setup done. */ - .min_width = 320, - .min_height = 240, -}; + ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); + if (!ret) + cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; + + return ret; +} +static const struct v4l2_async_notifier_operations mccic_notify_ops = { + .bound = mccic_notify_bound, + .unbind = mccic_notify_unbind, + .complete = mccic_notify_complete, +}; int mccic_register(struct mcam_camera *cam) { - struct i2c_board_info ov7670_info = { - .type = "ov7670", - .addr = 0x42 >> 1, - .platform_data = &sensor_cfg, - }; int ret; /* @@ -1744,17 +1818,20 @@ int mccic_register(struct mcam_camera *cam) printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, attempting vmalloc mode instead\n"); cam->buffer_mode = B_vmalloc; } + if (!mcam_buffer_mode_supported(cam->buffer_mode)) { printk(KERN_ERR "marvell-cam: buffer mode %d unsupported\n", cam->buffer_mode); - return -EINVAL; + ret = -EINVAL; + goto out; } + /* * Register with V4L */ ret = v4l2_device_register(cam->dev, &cam->v4l2_dev); if (ret) - return ret; + goto out; mutex_init(&cam->s_mutex); cam->state = S_NOTREADY; @@ -1764,43 +1841,20 @@ int mccic_register(struct mcam_camera *cam) mcam_ctlr_init(cam); /* - * Get the v4l2 setup done. + * Register sensor notifier. */ - ret = v4l2_ctrl_handler_init(&cam->ctrl_handler, 10); - if (ret) - goto out_unregister; - cam->v4l2_dev.ctrl_handler = &cam->ctrl_handler; - - /* - * Try to find the sensor. - */ - sensor_cfg.clock_speed = cam->clock_speed; - sensor_cfg.use_smbus = cam->use_smbus; - cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, - cam->i2c_adapter, &ov7670_info, NULL); - if (cam->sensor == NULL) { - ret = -ENODEV; - goto out_unregister; + v4l2_async_notifier_init(&cam->notifier); + ret = v4l2_async_notifier_add_subdev(&cam->notifier, &cam->asd); + if (ret) { + cam_warn(cam, "failed to add subdev to a notifier"); + goto out; } - ret = mcam_cam_init(cam); - if (ret) - goto out_unregister; - - ret = mcam_setup_vb2(cam); - if (ret) - goto out_unregister; - - mutex_lock(&cam->s_mutex); - cam->vdev = mcam_v4l_template; - cam->vdev.v4l2_dev = &cam->v4l2_dev; - cam->vdev.lock = &cam->s_mutex; - cam->vdev.queue = &cam->vb_queue; - video_set_drvdata(&cam->vdev, cam); - ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1); - if (ret) { - mutex_unlock(&cam->s_mutex); - goto out_unregister; + cam->notifier.ops = &mccic_notify_ops; + ret = v4l2_async_notifier_register(&cam->v4l2_dev, &cam->notifier); + if (ret < 0) { + cam_warn(cam, "failed to register a sensor notifier"); + goto out; } /* @@ -1811,11 +1865,10 @@ int mccic_register(struct mcam_camera *cam) cam_warn(cam, "Unable to alloc DMA buffers at load will try again later."); } - mutex_unlock(&cam->s_mutex); return 0; -out_unregister: - v4l2_ctrl_handler_free(&cam->ctrl_handler); +out: + v4l2_async_notifier_unregister(&cam->notifier); v4l2_device_unregister(&cam->v4l2_dev); return ret; } @@ -1835,8 +1888,8 @@ void mccic_shutdown(struct mcam_camera *cam) } if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); - video_unregister_device(&cam->vdev); v4l2_ctrl_handler_free(&cam->ctrl_handler); + v4l2_async_notifier_unregister(&cam->notifier); v4l2_device_unregister(&cam->v4l2_dev); } EXPORT_SYMBOL_GPL(mccic_shutdown); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index b828b1bb59d3..4a72213aca1a 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -102,14 +102,11 @@ struct mcam_camera { * These fields should be set by the platform code prior to * calling mcam_register(). */ - struct i2c_adapter *i2c_adapter; unsigned char __iomem *regs; unsigned regs_size; /* size in bytes of the register space */ spinlock_t dev_lock; struct device *dev; /* For messages, dma alloc */ enum mcam_chip_id chip_id; - short int clock_speed; /* Sensor clock speed, default 30 */ - short int use_smbus; /* SMBUS or straight I2c? */ enum mcam_buffer_mode buffer_mode; int mclk_src; /* which clock source the mclk derives from */ @@ -150,6 +147,8 @@ struct mcam_camera { * Subsystem structures. */ struct video_device vdev; + struct v4l2_async_notifier notifier; + struct v4l2_async_subdev asd; struct v4l2_subdev *sensor; /* Videobuf2 stuff */ diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 492663a8a29d..92061e4adbfd 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -4,12 +4,12 @@ * to work with the Armada 610 as used in the OLPC 1.75 system. * * Copyright 2011 Jonathan Corbet + * Copyright 2018 Lubomir Rintel */ #include #include #include -#include #include #include #include @@ -314,6 +314,7 @@ static int mmpcam_probe(struct platform_device *pdev) struct mmp_camera *cam; struct mcam_camera *mcam; struct resource *res; + struct fwnode_handle *ep; struct mmp_camera_platform_data *pdata; int ret; @@ -328,7 +329,6 @@ static int mmpcam_probe(struct platform_device *pdev) mcam->plat_power_down = mmpcam_power_down; mcam->calc_dphy = mmpcam_calc_dphy; mcam->dev = &pdev->dev; - mcam->use_smbus = 0; pdata = pdev->dev.platform_data; if (pdata) { mcam->mclk_src = pdata->mclk_src; @@ -372,15 +372,6 @@ static int mmpcam_probe(struct platform_device *pdev) cam->power_regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(cam->power_regs)) return PTR_ERR(cam->power_regs); - /* - * Find the i2c adapter. This assumes, of course, that the - * i2c bus is already up and functioning. - */ - mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device); - if (mcam->i2c_adapter == NULL) { - dev_err(&pdev->dev, "No i2c adapter\n"); - return -ENODEV; - } /* * Sensor GPIO pins. */ @@ -403,6 +394,19 @@ static int mmpcam_probe(struct platform_device *pdev) mcam_init_clk(mcam); + /* + * Create a match of the sensor against its OF node. + */ + ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(pdev->dev.of_node), + NULL); + if (!ep) + return -ENODEV; + + mcam->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + mcam->asd.match.fwnode = fwnode_graph_get_remote_port_parent(ep); + + fwnode_handle_put(ep); + /* * Power the device up and hand it off to the core. */ @@ -412,6 +416,7 @@ static int mmpcam_probe(struct platform_device *pdev) ret = mccic_register(mcam); if (ret) goto out_power_down; + /* * Finally, set up our IRQ now that the core is ready to * deal with it. diff --git a/include/linux/platform_data/media/mmp-camera.h b/include/linux/platform_data/media/mmp-camera.h index 4c3a80a45883..c573ebc40035 100644 --- a/include/linux/platform_data/media/mmp-camera.h +++ b/include/linux/platform_data/media/mmp-camera.h @@ -12,7 +12,6 @@ enum dphy3_algo { }; struct mmp_camera_platform_data { - struct platform_device *i2c_device; int sensor_power_gpio; int sensor_reset_gpio; enum v4l2_mbus_type bus_type; -- cgit v1.2.3-59-g8ed1b From 81a409bfd5517d537097d3cfdfed7f8bf8ac469c Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Tue, 28 May 2019 05:07:31 -0400 Subject: media: marvell-ccic: provide a clock for the sensor The sensor needs the MCLK clock running when it's being probed. On platforms where the sensor is instantiated from a DT (MMP2) it is going to happen asynchronously. Therefore, the current modus operandi, where the bridge driver fiddles with the sensor power and clock itself is not going to fly. As the comments wisely note, this doesn't even belong there. Luckily, the ov7670 driver is already able to control its power and reset lines, we can just drop the MMP platform glue altogether. It also requests the clock via the standard clock subsystem. Good -- let's set up a clock instance so that the sensor can ask us to enable the clock. Note that this is pretty dumb at the moment: the clock is hardwired to a particular frequency and parent. It was always the case. Signed-off-by: Lubomir Rintel Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/Kconfig | 2 + drivers/media/platform/marvell-ccic/cafe-driver.c | 9 +- drivers/media/platform/marvell-ccic/mcam-core.c | 172 ++++++++++++++++------ drivers/media/platform/marvell-ccic/mcam-core.h | 3 + drivers/media/platform/marvell-ccic/mmp-driver.c | 152 ++----------------- include/linux/platform_data/media/mmp-camera.h | 2 - 6 files changed, 157 insertions(+), 183 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index 86b84474dd8c..3e3f86264762 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -2,6 +2,7 @@ config VIDEO_CAFE_CCIC tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" depends on PCI && I2C && VIDEO_V4L2 + depends on COMMON_CLK select VIDEO_OV7670 select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG @@ -15,6 +16,7 @@ config VIDEO_MMP_CAMERA tristate "Marvell Armada 610 integrated camera controller support" depends on I2C && VIDEO_V4L2 depends on ARCH_MMP || COMPILE_TEST + depends on COMMON_CLK select VIDEO_OV7670 select I2C_GPIO select VIDEOBUF2_VMALLOC diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index fe85368675cb..16602628f895 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "mcam-core.h" @@ -531,11 +532,10 @@ static int cafe_pci_probe(struct pci_dev *pdev, goto out_iounmap; /* - * Initialize the controller and leave it powered up. It will - * stay that way until the sensor driver shows up. + * Initialize the controller. */ cafe_ctlr_init(mcam); - cafe_ctlr_power_up(mcam); + /* * Set up I2C/SMBUS communications. We have to drop the mutex here * because the sensor could attach in this call chain, leading to @@ -553,6 +553,9 @@ static int cafe_pci_probe(struct pci_dev *pdev, if (ret) goto out_smbus_shutdown; + clkdev_create(mcam->mclk, "xclk", "%d-%04x", + i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr); + if (i2c_new_device(cam->i2c_adapter, &ov7670_info)) { cam->registered = 1; return 0; diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index 7dc7d9d91782..f9ac1547d093 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -303,9 +304,6 @@ static void mcam_enable_mipi(struct mcam_camera *mcam) */ mcam_reg_write(mcam, REG_CSI2_CTRL0, CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane)); - mcam_reg_write(mcam, REG_CLKCTRL, - (mcam->mclk_src << 29) | mcam->mclk_div); - mcam->mipi_enabled = true; } } @@ -830,31 +828,6 @@ static void mcam_ctlr_irq_disable(struct mcam_camera *cam) mcam_reg_clear_bit(cam, REG_IRQMASK, FRAMEIRQS); } - - -static void mcam_ctlr_init(struct mcam_camera *cam) -{ - unsigned long flags; - - spin_lock_irqsave(&cam->dev_lock, flags); - /* - * Make sure it's not powered down. - */ - mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); - /* - * Turn off the enable bit. It sure should be off anyway, - * but it's good to be sure. - */ - mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); - /* - * Clock the sensor appropriately. Controller clock should - * be 48MHz, sensor "typical" value is half that. - */ - mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); - spin_unlock_irqrestore(&cam->dev_lock, flags); -} - - /* * Stop the controller, and don't return until we're really sure that no * further DMA is going on. @@ -898,14 +871,15 @@ static int mcam_ctlr_power_up(struct mcam_camera *cam) int ret; spin_lock_irqsave(&cam->dev_lock, flags); - ret = cam->plat_power_up(cam); - if (ret) { - spin_unlock_irqrestore(&cam->dev_lock, flags); - return ret; + if (cam->plat_power_up) { + ret = cam->plat_power_up(cam); + if (ret) { + spin_unlock_irqrestore(&cam->dev_lock, flags); + return ret; + } } mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); spin_unlock_irqrestore(&cam->dev_lock, flags); - msleep(5); /* Just to be sure */ return 0; } @@ -920,10 +894,101 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam) * power down routine. */ mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); - cam->plat_power_down(cam); + if (cam->plat_power_down) + cam->plat_power_down(cam); spin_unlock_irqrestore(&cam->dev_lock, flags); } +/* ---------------------------------------------------------------------- */ +/* + * Controller clocks. + */ +static void mcam_clk_enable(struct mcam_camera *mcam) +{ + unsigned int i; + + for (i = 0; i < NR_MCAM_CLK; i++) { + if (!IS_ERR(mcam->clk[i])) + clk_prepare_enable(mcam->clk[i]); + } +} + +static void mcam_clk_disable(struct mcam_camera *mcam) +{ + int i; + + for (i = NR_MCAM_CLK - 1; i >= 0; i--) { + if (!IS_ERR(mcam->clk[i])) + clk_disable_unprepare(mcam->clk[i]); + } +} + +/* ---------------------------------------------------------------------- */ +/* + * Master sensor clock. + */ +static int mclk_prepare(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + + clk_prepare(cam->clk[0]); + return 0; +} + +static void mclk_unprepare(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + + clk_unprepare(cam->clk[0]); +} + +static int mclk_enable(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + int mclk_src; + int mclk_div; + + /* + * Clock the sensor appropriately. Controller clock should + * be 48MHz, sensor "typical" value is half that. + */ + if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) { + mclk_src = cam->mclk_src; + mclk_div = cam->mclk_div; + } else { + mclk_src = 3; + mclk_div = 2; + } + + clk_enable(cam->clk[0]); + mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div); + mcam_ctlr_power_up(cam); + + return 0; +} + +static void mclk_disable(struct clk_hw *hw) +{ + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); + + mcam_ctlr_power_down(cam); + clk_disable(cam->clk[0]); +} + +static unsigned long mclk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + return 48000000; +} + +static const struct clk_ops mclk_ops = { + .prepare = mclk_prepare, + .unprepare = mclk_unprepare, + .enable = mclk_enable, + .disable = mclk_disable, + .recalc_rate = mclk_recalc_rate, +}; + /* -------------------------------------------------------------------- */ /* * Communications with the sensor. @@ -948,7 +1013,6 @@ static int mcam_cam_init(struct mcam_camera *cam) ret = __mcam_cam_reset(cam); /* Get/set parameters? */ cam->state = S_IDLE; - mcam_ctlr_power_down(cam); return ret; } @@ -1584,9 +1648,10 @@ static int mcam_v4l_open(struct file *filp) if (ret) goto out; if (v4l2_fh_is_singular_file(filp)) { - ret = mcam_ctlr_power_up(cam); + ret = sensor_call(cam, core, s_power, 1); if (ret) goto out; + mcam_clk_enable(cam); __mcam_cam_reset(cam); mcam_set_config_needed(cam, 1); } @@ -1608,7 +1673,8 @@ static int mcam_v4l_release(struct file *filp) _vb2_fop_release(filp, NULL); if (last_open) { mcam_disable_mipi(cam); - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); + mcam_clk_disable(cam); if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) mcam_free_dma_bufs(cam); } @@ -1806,6 +1872,7 @@ static const struct v4l2_async_notifier_operations mccic_notify_ops = { int mccic_register(struct mcam_camera *cam) { + struct clk_init_data mclk_init = { }; int ret; /* @@ -1838,7 +1905,6 @@ int mccic_register(struct mcam_camera *cam) mcam_set_config_needed(cam, 1); cam->pix_format = mcam_def_pix_format; cam->mbus_code = mcam_def_mbus_code; - mcam_ctlr_init(cam); /* * Register sensor notifier. @@ -1857,6 +1923,26 @@ int mccic_register(struct mcam_camera *cam) goto out; } + /* + * Register sensor master clock. + */ + mclk_init.parent_names = NULL; + mclk_init.num_parents = 0; + mclk_init.ops = &mclk_ops; + mclk_init.name = "mclk"; + + of_property_read_string(cam->dev->of_node, "clock-output-names", + &mclk_init.name); + + cam->mclk_hw.init = &mclk_init; + + cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw); + if (IS_ERR(cam->mclk)) { + ret = PTR_ERR(cam->mclk); + dev_err(cam->dev, "can't register clock\n"); + goto out; + } + /* * If so requested, try to get our DMA buffers now. */ @@ -1884,7 +1970,7 @@ void mccic_shutdown(struct mcam_camera *cam) */ if (!list_empty(&cam->vdev.fh_list)) { cam_warn(cam, "Removing a device with users!\n"); - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); } if (cam->buffer_mode == B_vmalloc) mcam_free_dma_bufs(cam); @@ -1906,7 +1992,8 @@ void mccic_suspend(struct mcam_camera *cam) enum mcam_state cstate = cam->state; mcam_ctlr_stop_dma(cam); - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); + mcam_clk_disable(cam); cam->state = cstate; } mutex_unlock(&cam->s_mutex); @@ -1919,14 +2006,15 @@ int mccic_resume(struct mcam_camera *cam) mutex_lock(&cam->s_mutex); if (!list_empty(&cam->vdev.fh_list)) { - ret = mcam_ctlr_power_up(cam); + mcam_clk_enable(cam); + ret = sensor_call(cam, core, s_power, 1); if (ret) { mutex_unlock(&cam->s_mutex); return ret; } __mcam_cam_reset(cam); } else { - mcam_ctlr_power_down(cam); + sensor_call(cam, core, s_power, 0); } mutex_unlock(&cam->s_mutex); diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h index 4a72213aca1a..2e3a7567a76a 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.h +++ b/drivers/media/platform/marvell-ccic/mcam-core.h @@ -8,6 +8,7 @@ #define _MCAM_CORE_H #include +#include #include #include #include @@ -125,6 +126,8 @@ struct mcam_camera { /* clock tree support */ struct clk *clk[NR_MCAM_CLK]; + struct clk_hw mclk_hw; + struct clk *mclk; /* * Callbacks from the core to the platform code. diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 92061e4adbfd..450693e6657d 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -20,9 +20,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -36,7 +34,6 @@ MODULE_LICENSE("GPL"); static char *mcam_clks[] = {"axi", "func", "phy"}; struct mmp_camera { - void __iomem *power_regs; struct platform_device *pdev; struct mcam_camera mcam; struct list_head devlist; @@ -92,94 +89,6 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev) return NULL; } - - - -/* - * Power-related registers; this almost certainly belongs - * somewhere else. - * - * ARMADA 610 register manual, sec 7.2.1, p1842. - */ -#define CPU_SUBSYS_PMU_BASE 0xd4282800 -#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */ -#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */ - -static void mcam_clk_enable(struct mcam_camera *mcam) -{ - unsigned int i; - - for (i = 0; i < NR_MCAM_CLK; i++) { - if (!IS_ERR(mcam->clk[i])) - clk_prepare_enable(mcam->clk[i]); - } -} - -static void mcam_clk_disable(struct mcam_camera *mcam) -{ - int i; - - for (i = NR_MCAM_CLK - 1; i >= 0; i--) { - if (!IS_ERR(mcam->clk[i])) - clk_disable_unprepare(mcam->clk[i]); - } -} - -/* - * Power control. - */ -static void mmpcam_power_up_ctlr(struct mmp_camera *cam) -{ - iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR); - iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR); - mdelay(1); -} - -static int mmpcam_power_up(struct mcam_camera *mcam) -{ - struct mmp_camera *cam = mcam_to_cam(mcam); - struct mmp_camera_platform_data *pdata; - -/* - * Turn on power and clocks to the controller. - */ - mmpcam_power_up_ctlr(cam); - mcam_clk_enable(mcam); -/* - * Provide power to the sensor. - */ - mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002); - pdata = cam->pdev->dev.platform_data; - gpio_set_value(pdata->sensor_power_gpio, 1); - mdelay(5); - mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000); - gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */ - mdelay(5); - gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */ - mdelay(5); - - return 0; -} - -static void mmpcam_power_down(struct mcam_camera *mcam) -{ - struct mmp_camera *cam = mcam_to_cam(mcam); - struct mmp_camera_platform_data *pdata; -/* - * Turn off clocks and set reset lines - */ - iowrite32(0, cam->power_regs + REG_CCIC_DCGCR); - iowrite32(0, cam->power_regs + REG_CCIC_CRCR); -/* - * Shut down the sensor. - */ - pdata = cam->pdev->dev.platform_data; - gpio_set_value(pdata->sensor_power_gpio, 0); - gpio_set_value(pdata->sensor_reset_gpio, 0); - - mcam_clk_disable(mcam); -} - /* * calc the dphy register values * There are three dphy registers being used. @@ -325,8 +234,6 @@ static int mmpcam_probe(struct platform_device *pdev) INIT_LIST_HEAD(&cam->devlist); mcam = &cam->mcam; - mcam->plat_power_up = mmpcam_power_up; - mcam->plat_power_down = mmpcam_power_down; mcam->calc_dphy = mmpcam_calc_dphy; mcam->dev = &pdev->dev; pdata = pdev->dev.platform_data; @@ -364,33 +271,6 @@ static int mmpcam_probe(struct platform_device *pdev) if (IS_ERR(mcam->regs)) return PTR_ERR(mcam->regs); mcam->regs_size = resource_size(res); - /* - * Power/clock memory is elsewhere; get it too. Perhaps this - * should really be managed outside of this driver? - */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - cam->power_regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(cam->power_regs)) - return PTR_ERR(cam->power_regs); - /* - * Sensor GPIO pins. - */ - ret = devm_gpio_request(&pdev->dev, pdata->sensor_power_gpio, - "cam-power"); - if (ret) { - dev_err(&pdev->dev, "Can't get sensor power gpio %d", - pdata->sensor_power_gpio); - return ret; - } - gpio_direction_output(pdata->sensor_power_gpio, 0); - ret = devm_gpio_request(&pdev->dev, pdata->sensor_reset_gpio, - "cam-reset"); - if (ret) { - dev_err(&pdev->dev, "Can't get sensor reset gpio %d", - pdata->sensor_reset_gpio); - return ret; - } - gpio_direction_output(pdata->sensor_reset_gpio, 0); mcam_init_clk(mcam); @@ -408,14 +288,21 @@ static int mmpcam_probe(struct platform_device *pdev) fwnode_handle_put(ep); /* - * Power the device up and hand it off to the core. + * Register the device with the core. */ - ret = mmpcam_power_up(mcam); - if (ret) - return ret; ret = mccic_register(mcam); if (ret) - goto out_power_down; + return ret; + + /* + * Add OF clock provider. + */ + ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, + mcam->mclk); + if (ret) { + dev_err(&pdev->dev, "can't add DT clock provider\n"); + goto out; + } /* * Finally, set up our IRQ now that the core is ready to @@ -424,7 +311,7 @@ static int mmpcam_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res == NULL) { ret = -ENODEV; - goto out_unregister; + goto out; } cam->irq = res->start; ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED, @@ -434,10 +321,10 @@ static int mmpcam_probe(struct platform_device *pdev) return 0; } -out_unregister: +out: + fwnode_handle_put(mcam->asd.match.fwnode); mccic_shutdown(mcam); -out_power_down: - mmpcam_power_down(mcam); + return ret; } @@ -448,7 +335,6 @@ static int mmpcam_remove(struct mmp_camera *cam) mmpcam_remove_device(cam); mccic_shutdown(mcam); - mmpcam_power_down(mcam); return 0; } @@ -480,12 +366,6 @@ static int mmpcam_resume(struct platform_device *pdev) { struct mmp_camera *cam = mmpcam_find_device(pdev); - /* - * Power up unconditionally just in case the core tries to - * touch a register even if nothing was active before; trust - * me, it's better this way. - */ - mmpcam_power_up_ctlr(cam); return mccic_resume(&cam->mcam); } diff --git a/include/linux/platform_data/media/mmp-camera.h b/include/linux/platform_data/media/mmp-camera.h index c573ebc40035..53adaab64f28 100644 --- a/include/linux/platform_data/media/mmp-camera.h +++ b/include/linux/platform_data/media/mmp-camera.h @@ -12,8 +12,6 @@ enum dphy3_algo { }; struct mmp_camera_platform_data { - int sensor_power_gpio; - int sensor_reset_gpio; enum v4l2_mbus_type bus_type; int mclk_src; /* which clock source the MCLK derives from */ int mclk_div; /* Clock Divider Value for MCLK */ -- cgit v1.2.3-59-g8ed1b From 6a381d1072f174cb80a27526a7ccdcfd6604ecb2 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 17 Jun 2019 09:43:31 -0400 Subject: media: st-mipid02: add support of V4L2_CID_LINK_FREQ Ask device connected on sink pad for link frequency in order to configure CLK_LANE_REG1 (ui_x4). If not available, ask for pixel rate information to compute it. This is needed to deal with compressed format such as JPEG where number of bits per pixel is unknown: computation of link frequency from pixel rate is not possible. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/st-mipid02.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 9369f38dbf3d..8623f3085b67 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -331,6 +331,25 @@ static int mipid02_detect(struct mipid02_dev *bridge) return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); } +static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge, + struct v4l2_subdev *subdev) +{ + struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; + struct v4l2_ctrl *ctrl; + int ret; + + ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ); + if (!ctrl) + return 0; + qm.index = v4l2_ctrl_g_ctrl(ctrl); + + ret = v4l2_querymenu(subdev->ctrl_handler, &qm); + if (ret) + return 0; + + return qm.value; +} + static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, struct v4l2_subdev *subdev) { @@ -358,10 +377,14 @@ static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) struct v4l2_subdev *subdev = bridge->s_subdev; u32 link_freq; - link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, subdev); + link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev); if (!link_freq) { - dev_err(&client->dev, "Failed to detect link frequency"); - return -EINVAL; + link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, + subdev); + if (!link_freq) { + dev_err(&client->dev, "Failed to get link frequency"); + return -EINVAL; + } } dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); -- cgit v1.2.3-59-g8ed1b From 197adee605642c72732fd07ed59a3950a80f4e77 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 17 Jun 2019 09:43:56 -0400 Subject: media: st-mipid02: add support of RGB565 Add support of RGB565 pixel format. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/st-mipid02.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index 8623f3085b67..cbe476eb5d59 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -61,7 +61,8 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, - MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24 + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, + MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, }; /* regulator supplies */ @@ -128,6 +129,8 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_SRGGB12_1X12: return 12; case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: return 16; case MEDIA_BUS_FMT_BGR888_1X24: return 24; @@ -158,6 +161,9 @@ static u8 data_type_from_code(__u32 code) return 0x1e; case MEDIA_BUS_FMT_BGR888_1X24: return 0x24; + case MEDIA_BUS_FMT_RGB565_2X8_LE: + case MEDIA_BUS_FMT_RGB565_2X8_BE: + return 0x22; default: return 0; } -- cgit v1.2.3-59-g8ed1b From b9f343dfc65ee692b3e47cb34b3fa5ae4979f066 Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 17 Jun 2019 09:43:57 -0400 Subject: media: st-mipid02: add support of YUYV8 and UYVY8 Add support of YUYV8 and UYVY8 pixel formats. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/st-mipid02.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index cbe476eb5d59..f9aa96fdf387 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -63,6 +63,7 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, + MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, }; /* regulator supplies */ @@ -129,6 +130,8 @@ static int bpp_from_code(__u32 code) case MEDIA_BUS_FMT_SRGGB12_1X12: return 12; case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_RGB565_2X8_LE: case MEDIA_BUS_FMT_RGB565_2X8_BE: return 16; @@ -158,6 +161,8 @@ static u8 data_type_from_code(__u32 code) case MEDIA_BUS_FMT_SRGGB12_1X12: return 0x2c; case MEDIA_BUS_FMT_UYVY8_1X16: + case MEDIA_BUS_FMT_YUYV8_2X8: + case MEDIA_BUS_FMT_UYVY8_2X8: return 0x1e; case MEDIA_BUS_FMT_BGR888_1X24: return 0x24; -- cgit v1.2.3-59-g8ed1b From 03aedb1d2cd7d137c01b5e33eabbf58a48266a3b Mon Sep 17 00:00:00 2001 From: Hugues Fruchet Date: Mon, 17 Jun 2019 09:43:58 -0400 Subject: media: st-mipid02: add support of JPEG Add support of JPEG pixel format. This requires auto detection of data type from CSI-2 stream. Signed-off-by: Hugues Fruchet Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/st-mipid02.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index f9aa96fdf387..81285b8d5cfb 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -64,6 +64,7 @@ static const u32 mipid02_supported_fmt_codes[] = { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24, MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_JPEG_1X8 }; /* regulator supplies */ @@ -101,6 +102,7 @@ struct mipid02_dev { u8 data_lane1_reg1; u8 mode_reg1; u8 mode_reg2; + u8 data_selection_ctrl; u8 data_id_rreg; u8 pix_width_ctrl; u8 pix_width_ctrl_emb; @@ -486,6 +488,7 @@ static int mipid02_configure_from_tx(struct mipid02_dev *bridge) { struct v4l2_fwnode_endpoint *ep = &bridge->tx; + bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH; bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) @@ -501,10 +504,15 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge) u8 data_type; bridge->r.data_id_rreg = 0; - data_type = data_type_from_code(bridge->fmt.code); - if (!data_type) - return -EINVAL; - bridge->r.data_id_rreg = data_type; + + if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) { + bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; + + data_type = data_type_from_code(bridge->fmt.code); + if (!data_type) + return -EINVAL; + bridge->r.data_id_rreg = data_type; + } return 0; } @@ -588,7 +596,7 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge) if (ret) goto error; ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, - SELECTION_MANUAL_DATA | SELECTION_MANUAL_WIDTH); + bridge->r.data_selection_ctrl); if (ret) goto error; ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, -- cgit v1.2.3-59-g8ed1b From 901ecb02113757df8a1b6a6ff29c6941baeec3df Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 20 Jun 2019 10:49:03 -0400 Subject: media: marvell-ccic: only calculate the DPHY registers when needed Avoid pointlessly calling calc_dphy() when the bus is not V4L2_MBUS_CSI2_DPHY. This will make it easier to replace the platform data with devicetree. Signed-off-by: Lubomir Rintel Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index f9ac1547d093..dc30c48d4671 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -285,6 +285,8 @@ static void mcam_ctlr_stop(struct mcam_camera *cam) static void mcam_enable_mipi(struct mcam_camera *mcam) { /* Using MIPI mode and enable MIPI */ + if (mcam->calc_dphy) + mcam->calc_dphy(mcam); cam_dbg(mcam, "camera: DPHY3=0x%x, DPHY5=0x%x, DPHY6=0x%x\n", mcam->dphy[0], mcam->dphy[1], mcam->dphy[2]); mcam_reg_write(mcam, REG_CSI2_DPHY3, mcam->dphy[0]); @@ -1078,13 +1080,6 @@ static int mcam_read_setup(struct mcam_camera *cam) spin_lock_irqsave(&cam->dev_lock, flags); clear_bit(CF_DMA_ACTIVE, &cam->flags); mcam_reset_buffers(cam); - /* - * Update CSI2_DPHY value - */ - if (cam->calc_dphy) - cam->calc_dphy(cam); - cam_dbg(cam, "camera: DPHY sets: dphy3=0x%x, dphy5=0x%x, dphy6=0x%x\n", - cam->dphy[0], cam->dphy[1], cam->dphy[2]); if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) mcam_enable_mipi(cam); else -- cgit v1.2.3-59-g8ed1b From ff250c6147f36a8b7a5305ffbde7881973fed5af Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 20 Jun 2019 10:49:04 -0400 Subject: media: marvell-ccic: mmp: don't chicken out w/o pdata It's impossible for mmpcam_calc_dphy() to be called without it. Signed-off-by: Lubomir Rintel Reviewed-by: Jacopo Mondi Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mmp-driver.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c index 450693e6657d..10559492e09e 100644 --- a/drivers/media/platform/marvell-ccic/mmp-driver.c +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c @@ -105,9 +105,6 @@ static void mmpcam_calc_dphy(struct mcam_camera *mcam) struct device *dev = &cam->pdev->dev; unsigned long tx_clk_esc; - if (!pdata) - return; - /* * If CSI2_DPHY3 is calculated dynamically, * pdata->lane_clk should be already set -- cgit v1.2.3-59-g8ed1b From 932952e525e5c8d38cf3df4a3265be5652d57c97 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Jun 2019 13:08:59 -0400 Subject: media: cafe-driver: mark an static var as such As warned by sparse: drivers/media/platform/marvell-ccic/cafe-driver.c:475:23: warning: symbol 'ov7670_info' was not declared. Should it be static? Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/cafe-driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c index 16602628f895..37fdcc53a1c4 100644 --- a/drivers/media/platform/marvell-ccic/cafe-driver.c +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c @@ -472,7 +472,7 @@ static struct ov7670_config sensor_cfg = { .use_smbus = 1, }; -struct i2c_board_info ov7670_info = { +static struct i2c_board_info ov7670_info = { .type = "ov7670", .addr = 0x42 >> 1, .platform_data = &sensor_cfg, -- cgit v1.2.3-59-g8ed1b From 60c74167fef4d25112ce32030bdbb958a8d01cae Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Tue, 18 Jun 2019 12:45:08 -0400 Subject: media: coda: implement CMD_START to restart decoding The CMD_START shall be used to start the processing after a drain that was initiated with CMD_STOP. Up until now, a drain on coda could only be finished with a STREAMOFF-STREAMON, which resulted in a reset of the device. Signed-off-by: Michael Tretter Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index de64040dad8a..c7dcab4d1f6c 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1059,16 +1059,29 @@ static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { struct coda_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *dst_vq; int ret; ret = coda_try_decoder_cmd(file, fh, dc); if (ret < 0) return ret; - /* Set the stream-end flag on this context */ - coda_bit_stream_end_flag(ctx); - ctx->hold = false; - v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + switch (dc->cmd) { + case V4L2_DEC_CMD_START: + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + vb2_clear_last_buffer_dequeued(dst_vq); + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; + break; + case V4L2_DEC_CMD_STOP: + /* Set the stream-end flag on this context */ + coda_bit_stream_end_flag(ctx); + ctx->hold = false; + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + break; + default: + return -EINVAL; + } return 0; } -- cgit v1.2.3-59-g8ed1b From f66a607d73389263694c9d597bcf8d36ffe3b12d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:09 -0400 Subject: media: coda: use mem2mem try_en/decoder_cmd helpers Use mem2mem try_en/decoder_cmd helpers to ensure consistent behaviour with other video codec drivers. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index c7dcab4d1f6c..8347169fadc0 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1001,13 +1001,7 @@ static int coda_try_encoder_cmd(struct file *file, void *fh, if (ctx->inst_type != CODA_INST_ENCODER) return -ENOTTY; - if (ec->cmd != V4L2_ENC_CMD_STOP) - return -EINVAL; - - if (ec->flags & V4L2_ENC_CMD_STOP_AT_GOP_END) - return -EINVAL; - - return 0; + return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); } static int coda_encoder_cmd(struct file *file, void *fh, @@ -1043,16 +1037,7 @@ static int coda_try_decoder_cmd(struct file *file, void *fh, if (ctx->inst_type != CODA_INST_DECODER) return -ENOTTY; - if (dc->cmd != V4L2_DEC_CMD_STOP) - return -EINVAL; - - if (dc->flags & V4L2_DEC_CMD_STOP_TO_BLACK) - return -EINVAL; - - if (!(dc->flags & V4L2_DEC_CMD_STOP_IMMEDIATELY) && (dc->stop.pts != 0)) - return -EINVAL; - - return 0; + return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); } static int coda_decoder_cmd(struct file *file, void *fh, -- cgit v1.2.3-59-g8ed1b From 56d159a4ec6d8da7313aac6fcbb95d8fffe689ba Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:10 -0400 Subject: media: coda: fix mpeg2 sequence number handling Sequence number handling assumed that the BIT processor frame number starts counting at 1, but this is not true for the MPEG-2 decoder, which starts at 0. Fix the sequence counter offset detection to handle this. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 06a352659bae..45ffe2e87e0a 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1746,6 +1746,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_SEQ_INIT timeout\n"); return ret; } + ctx->sequence_offset = ~0U; ctx->initialized = 1; /* Update kfifo out pointer from coda bitstream read pointer */ @@ -2169,7 +2170,9 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { - val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); + if (ctx->sequence_offset == -1) + ctx->sequence_offset = val; val -= ctx->sequence_offset; spin_lock(&ctx->buffer_meta_lock); if (!list_empty(&ctx->buffer_meta_list)) { -- cgit v1.2.3-59-g8ed1b From f3775f89852d167990b0d718587774cf00d22ac2 Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 18 Jun 2019 12:45:11 -0400 Subject: media: coda: fix last buffer handling in V4L2_ENC_CMD_STOP coda_encoder_cmd() is racy, as the last scheduled picture run worker can still be in-flight while the ENC_CMD_STOP command is issued. Depending on the exact timing the sequence numbers might already be changed, but the last buffer might not have been put on the destination queue yet. In this case the current implementation would prematurely wake the destination queue with last_buffer_dequeued=true, causing userspace to call streamoff before the last buffer is handled. Close this race window by synchronizing with the pic_run_worker before doing the sequence check. Signed-off-by: Marco Felsch [l.stach@pengutronix.de: switch to flush_work, reword commit message] Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 8347169fadc0..b9ddf0cfdb83 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1018,6 +1018,8 @@ static int coda_encoder_cmd(struct file *file, void *fh, /* Set the stream-end flag on this context */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; + flush_work(&ctx->pic_run_work); + /* If there is no buffer in flight, wake up */ if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) { dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, -- cgit v1.2.3-59-g8ed1b From cce5b73265db051e3259964f2f4e3b7faa661ab8 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:12 -0400 Subject: media: coda: add coda_wake_up_capture_queue Combine setting the last_buffer_dequeued flag on the capture video queue and waking up its done workqueue into a helper function. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index b9ddf0cfdb83..095747ae1c40 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1004,11 +1004,21 @@ static int coda_try_encoder_cmd(struct file *file, void *fh, return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); } +static void coda_wake_up_capture_queue(struct coda_ctx *ctx) +{ + struct vb2_queue *dst_vq; + + coda_dbg(1, ctx, "waking up capture queue\n"); + + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_vq->last_buffer_dequeued = true; + wake_up(&dst_vq->done_wq); +} + static int coda_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { struct coda_ctx *ctx = fh_to_ctx(fh); - struct vb2_queue *dst_vq; int ret; ret = coda_try_encoder_cmd(file, fh, ec); @@ -1021,12 +1031,8 @@ static int coda_encoder_cmd(struct file *file, void *fh, flush_work(&ctx->pic_run_work); /* If there is no buffer in flight, wake up */ - if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) { - dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_vq->last_buffer_dequeued = true; - wake_up(&dst_vq->done_wq); - } + if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) + coda_wake_up_capture_queue(ctx); return 0; } -- cgit v1.2.3-59-g8ed1b From 7e5eaae0af2eccb7ac94eb3d958d4c052f960e7b Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Tue, 18 Jun 2019 12:45:13 -0400 Subject: media: coda: fix V4L2_DEC_CMD_STOP when all buffers are already consumed When the DEC_CMD_STOP command is issued after the context has already consumed all the queued buffers, we need to make sure to wake the destination queue with last_buffer_dequeued set, to allow userspace to make progress in its EOS handling. As there might still be picture run workers pending at that point, we need to synchronize with them, so the sequence number comparison reads stable values. reword commit message] Signed-off-by: Marco Felsch Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 095747ae1c40..43820cfac76c 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1071,6 +1071,12 @@ static int coda_decoder_cmd(struct file *file, void *fh, coda_bit_stream_end_flag(ctx); ctx->hold = false; v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + + flush_work(&ctx->pic_run_work); + + /* If there is no buffer in flight, wake up */ + if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) + coda_wake_up_capture_queue(ctx); break; default: return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 8e717396d87ec0a26ad6f72ba5697c850ed0b8f8 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:14 -0400 Subject: media: coda: split decoder sequence initialization out of start decoding The sequence initialization already has to happen during the initialization phase, after headers have been queued on the OUTPUT queue. This means that sequence initialization has to be queued as a work item from QBUF on the OUTPUT queue. The internal framebuffer setup should be done later during VIDIOC_REQBUFS() on the CAPTURE queue. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 45ffe2e87e0a..cecfd51e3838 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1661,7 +1661,7 @@ static bool coda_reorder_enable(struct coda_ctx *ctx) return profile > V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE; } -static int __coda_start_decoding(struct coda_ctx *ctx) +static int __coda_decoder_seq_init(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; u32 bitstream_buf, bitstream_size; @@ -1684,8 +1684,6 @@ static int __coda_start_decoding(struct coda_ctx *ctx) src_fourcc = q_data_src->fourcc; dst_fourcc = q_data_dst->fourcc; - coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); - /* Update coda bitstream read and write pointers from kfifo */ coda_kfifo_sync_to_device_full(ctx); @@ -1823,6 +1821,29 @@ static int __coda_start_decoding(struct coda_ctx *ctx) coda_update_profile_level_ctrls(ctx, profile, level); } + return 0; +} + +static int __coda_start_decoding(struct coda_ctx *ctx) +{ + struct coda_q_data *q_data_src, *q_data_dst; + struct coda_dev *dev = ctx->dev; + u32 src_fourcc, dst_fourcc; + int ret; + + if (!ctx->initialized) { + ret = __coda_decoder_seq_init(ctx); + if (ret < 0) + return ret; + } + + q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + src_fourcc = q_data_src->fourcc; + dst_fourcc = q_data_dst->fourcc; + + coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR); + ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to allocate framebuffers\n"); @@ -1831,7 +1852,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx) /* Tell the decoder how many frame buffers we allocated. */ coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM); - coda_write(dev, width, CODA_CMD_SET_FRAME_BUF_STRIDE); + coda_write(dev, round_up(q_data_dst->rect.width, 16), + CODA_CMD_SET_FRAME_BUF_STRIDE); if (dev->devtype->product != CODA_DX6) { /* Set secondary AXI IRAM */ -- cgit v1.2.3-59-g8ed1b From 497e6b8559a64f41d6dd65a68e8a8576ba637fda Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:15 -0400 Subject: media: coda: add sequence initialization work Add a sequence initialization work item to be run when OUTPUT buffers are queued in the initialization state. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 25 +++++++++++++++++++++++++ drivers/media/platform/coda/coda-common.c | 24 ++++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 2 ++ 3 files changed, 51 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index cecfd51e3838..9f8e2342d175 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1824,6 +1824,30 @@ static int __coda_decoder_seq_init(struct coda_ctx *ctx) return 0; } +static void coda_dec_seq_init_work(struct work_struct *work) +{ + struct coda_ctx *ctx = container_of(work, + struct coda_ctx, seq_init_work); + struct coda_dev *dev = ctx->dev; + int ret; + + mutex_lock(&ctx->buffer_mutex); + mutex_lock(&dev->coda_mutex); + + if (ctx->initialized == 1) + goto out; + + ret = __coda_decoder_seq_init(ctx); + if (ret < 0) + goto out; + + ctx->initialized = 1; + +out: + mutex_unlock(&dev->coda_mutex); + mutex_unlock(&ctx->buffer_mutex); +} + static int __coda_start_decoding(struct coda_ctx *ctx) { struct coda_q_data *q_data_src, *q_data_dst; @@ -2352,6 +2376,7 @@ const struct coda_context_ops coda_bit_decode_ops = { .prepare_run = coda_prepare_decode, .finish_run = coda_finish_decode, .run_timeout = coda_decode_timeout, + .seq_init_work = coda_dec_seq_init_work, .seq_end_work = coda_seq_end_work, .release = coda_bit_release, }; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 43820cfac76c..3fe374287600 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1684,6 +1684,19 @@ static void coda_buf_queue(struct vb2_buffer *vb) /* This set buf->sequence = ctx->qsequence++ */ coda_fill_bitstream(ctx, NULL); mutex_unlock(&ctx->bitstream_mutex); + + if (!ctx->initialized) { + /* + * Run sequence initialization in case the queued + * buffer contained headers. + */ + if (vb2_is_streaming(vb->vb2_queue) && + ctx->ops->seq_init_work) { + queue_work(ctx->dev->workqueue, + &ctx->seq_init_work); + flush_work(&ctx->seq_init_work); + } + } } else { if (ctx->inst_type == CODA_INST_ENCODER && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) @@ -1761,6 +1774,15 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) ret = -EINVAL; goto err; } + + if (!ctx->initialized) { + /* Run sequence initialization */ + if (ctx->ops->seq_init_work) { + queue_work(ctx->dev->workqueue, + &ctx->seq_init_work); + flush_work(&ctx->seq_init_work); + } + } } ctx->streamon_out = 1; @@ -2317,6 +2339,8 @@ static int coda_open(struct file *file) ctx->use_bit = !ctx->cvd->direct; init_completion(&ctx->completion); INIT_WORK(&ctx->pic_run_work, coda_pic_run_work); + if (ctx->ops->seq_init_work) + INIT_WORK(&ctx->seq_init_work, ctx->ops->seq_init_work); if (ctx->ops->seq_end_work) INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work); v4l2_fh_init(&ctx->fh, video_devdata(file)); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 0c2cace53ce8..c97ea3e24b80 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -185,6 +185,7 @@ struct coda_context_ops { int (*prepare_run)(struct coda_ctx *ctx); void (*finish_run)(struct coda_ctx *ctx); void (*run_timeout)(struct coda_ctx *ctx); + void (*seq_init_work)(struct work_struct *work); void (*seq_end_work)(struct work_struct *work); void (*release)(struct coda_ctx *ctx); }; @@ -193,6 +194,7 @@ struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; struct work_struct pic_run_work; + struct work_struct seq_init_work; struct work_struct seq_end_work; struct completion completion; const struct coda_video_device *cvd; -- cgit v1.2.3-59-g8ed1b From 236306be0b2cbb52d4f18b2550d05f7463caf3c3 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:16 -0400 Subject: media: coda: implement decoder source change event The stateful decoder API requires decoders to signal detection of stream dimensions via the V4L2_EVENT_SOURCE_CHANGE event. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3fe374287600..19e3afa4f24d 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1255,9 +1255,16 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) static int coda_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { + struct coda_ctx *ctx = fh_to_ctx(fh); + switch (sub->type) { case V4L2_EVENT_EOS: return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + if (ctx->inst_type == CODA_INST_DECODER) + return v4l2_event_subscribe(fh, sub, 0, NULL); + else + return -EINVAL; default: return v4l2_ctrl_subscribe_event(fh, sub); } @@ -1642,6 +1649,16 @@ void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, } } +static void coda_queue_source_change_event(struct coda_ctx *ctx) +{ + static const struct v4l2_event source_change_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + v4l2_event_queue_fh(&ctx->fh, &source_change_event); +} + static void coda_buf_queue(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -1696,6 +1713,9 @@ static void coda_buf_queue(struct vb2_buffer *vb) &ctx->seq_init_work); flush_work(&ctx->seq_init_work); } + + if (ctx->initialized) + coda_queue_source_change_event(ctx); } } else { if (ctx->inst_type == CODA_INST_ENCODER && -- cgit v1.2.3-59-g8ed1b From 94af4c45a7a6f2f4f6fcd93e07078b319ac78016 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:17 -0400 Subject: media: coda: integrate internal frame metadata into a structure Combine the separate auxiliary buffer, buffer meta, frame type, and decode error arrays into an array of struct coda_internal_frame. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 62 ++++++++++++++++++---------------- drivers/media/platform/coda/coda.h | 12 ++++--- 2 files changed, 40 insertions(+), 34 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9f8e2342d175..494bc130c7af 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -395,7 +395,7 @@ static void coda_free_framebuffers(struct coda_ctx *ctx) int i; for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) - coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]); + coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i].buf); } static int coda_alloc_framebuffers(struct coda_ctx *ctx, @@ -435,7 +435,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, coda_free_framebuffers(ctx); return -ENOMEM; } - ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], + ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i].buf, size, name); kfree(name); if (ret < 0) { @@ -449,7 +449,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, u32 y, cb, cr, mvcol; /* Start addresses of Y, Cb, Cr planes */ - y = ctx->internal_frames[i].paddr; + y = ctx->internal_frames[i].buf.paddr; cb = y + ysize; cr = y + ysize + ysize/4; mvcol = y + ysize + ysize/4 + ysize/4; @@ -1202,9 +1202,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda9_set_frame_cache(ctx, q_data_src->fourcc); /* FIXME */ - coda_write(dev, ctx->internal_frames[2].paddr, + coda_write(dev, ctx->internal_frames[2].buf.paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); - coda_write(dev, ctx->internal_frames[3].paddr, + coda_write(dev, ctx->internal_frames[3].buf.paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B); } } @@ -1993,7 +1993,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) ctx->display_idx < ctx->num_internal_frames) { vdoa_device_run(ctx->vdoa, vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0), - ctx->internal_frames[ctx->display_idx].paddr); + ctx->internal_frames[ctx->display_idx].buf.paddr); } else { if (dev->devtype->product == CODA_960) { /* @@ -2091,6 +2091,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) int width, height; int decoded_idx; int display_idx; + struct coda_internal_frame *decoded_frame = NULL; u32 src_fourcc; int success; u32 err_mb; @@ -2216,6 +2217,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) v4l2_err(&dev->v4l2_dev, "decoded frame index out of range: %d\n", decoded_idx); } else { + decoded_frame = &ctx->internal_frames[decoded_idx]; + val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM); if (ctx->sequence_offset == -1) ctx->sequence_offset = val; @@ -2240,28 +2243,25 @@ static void coda_finish_decode(struct coda_ctx *ctx) val, ctx->sequence_offset, meta->sequence); } - ctx->frame_metas[decoded_idx] = *meta; + decoded_frame->meta = *meta; kfree(meta); } else { spin_unlock(&ctx->buffer_meta_lock); v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); - memset(&ctx->frame_metas[decoded_idx], 0, + memset(&decoded_frame->meta, 0, sizeof(struct coda_buffer_meta)); - ctx->frame_metas[decoded_idx].sequence = val; + decoded_frame->meta.sequence = val; ctx->sequence_offset++; } - trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]); + trace_coda_dec_pic_done(ctx, &decoded_frame->meta); val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7; - if (val == 0) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME; - else if (val == 1) - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME; - else - ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME; + decoded_frame->type = (val == 0) ? V4L2_BUF_FLAG_KEYFRAME : + (val == 1) ? V4L2_BUF_FLAG_PFRAME : + V4L2_BUF_FLAG_BFRAME; - ctx->frame_errors[decoded_idx] = err_mb; + decoded_frame->error = err_mb; } if (display_idx == -1) { @@ -2281,6 +2281,10 @@ static void coda_finish_decode(struct coda_ctx *ctx) /* If a frame was copied out, return it */ if (ctx->display_idx >= 0 && ctx->display_idx < ctx->num_internal_frames) { + struct coda_internal_frame *ready_frame; + + ready_frame = &ctx->internal_frames[ctx->display_idx]; + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); dst_buf->sequence = ctx->osequence++; @@ -2288,8 +2292,8 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | V4L2_BUF_FLAG_PFRAME | V4L2_BUF_FLAG_BFRAME); - dst_buf->flags |= ctx->frame_types[ctx->display_idx]; - meta = &ctx->frame_metas[ctx->display_idx]; + dst_buf->flags |= ready_frame->type; + meta = &ready_frame->meta; dst_buf->timecode = meta->timecode; dst_buf->vb2_buf.timestamp = meta->timestamp; @@ -2298,18 +2302,17 @@ static void coda_finish_decode(struct coda_ctx *ctx) vb2_set_plane_payload(&dst_buf->vb2_buf, 0, q_data_dst->sizeimage); - if (ctx->frame_errors[ctx->display_idx] || err_vdoa) + if (ready_frame->error || err_vdoa) coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_ERROR); else coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); - if (decoded_idx >= 0 && - decoded_idx < ctx->num_internal_frames) { + if (decoded_frame) { coda_dbg(1, ctx, "job finished: decoded %c frame %u, returned %c frame %u (%u/%u)%s\n", - coda_frame_type_char(ctx->frame_types[decoded_idx]), - ctx->frame_metas[decoded_idx].sequence, + coda_frame_type_char(decoded_frame->type), + decoded_frame->meta.sequence, coda_frame_type_char(dst_buf->flags), - ctx->frame_metas[ctx->display_idx].sequence, + ready_frame->meta.sequence, dst_buf->sequence, ctx->qsequence, (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); @@ -2317,17 +2320,16 @@ static void coda_finish_decode(struct coda_ctx *ctx) coda_dbg(1, ctx, "job finished: no frame decoded (%d), returned %c frame %u (%u/%u)%s\n", decoded_idx, coda_frame_type_char(dst_buf->flags), - ctx->frame_metas[ctx->display_idx].sequence, + ready_frame->meta.sequence, dst_buf->sequence, ctx->qsequence, (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); } } else { - if (decoded_idx >= 0 && - decoded_idx < ctx->num_internal_frames) { + if (decoded_frame) { coda_dbg(1, ctx, "job finished: decoded %c frame %u, no frame returned (%d)\n", - coda_frame_type_char(ctx->frame_types[decoded_idx]), - ctx->frame_metas[decoded_idx].sequence, + coda_frame_type_char(decoded_frame->type), + decoded_frame->meta.sequence, ctx->display_idx); } else { coda_dbg(1, ctx, "job finished: no frame decoded (%d) or returned (%d)\n", diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index c97ea3e24b80..10207e9534c2 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -190,6 +190,13 @@ struct coda_context_ops { void (*release)(struct coda_ctx *ctx); }; +struct coda_internal_frame { + struct coda_aux_buf buf; + struct coda_buffer_meta meta; + u32 type; + u32 error; +}; + struct coda_ctx { struct coda_dev *dev; struct mutex buffer_mutex; @@ -233,10 +240,7 @@ struct coda_ctx { struct coda_aux_buf parabuf; struct coda_aux_buf psbuf; struct coda_aux_buf slicebuf; - struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS]; - u32 frame_types[CODA_MAX_FRAMEBUFFERS]; - struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS]; - u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; + struct coda_internal_frame internal_frames[CODA_MAX_FRAMEBUFFERS]; struct list_head buffer_meta_list; spinlock_t buffer_meta_lock; int num_metas; -- cgit v1.2.3-59-g8ed1b From ccb901196ec5298458f2cd2c4c43652c3c0d5032 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:18 -0400 Subject: media: coda: make coda_bitstream_queue more versatile Pass vaddr and size to coda_bitstream_queue instead of a struct vb2_v4l2_buffer to make it reusable for queueing data that is not exactly a whole v4l2 buffer into the bitstream ringbuffer. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 494bc130c7af..4f96f808b4dd 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -199,33 +199,25 @@ static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size) return (n < size) ? -ENOSPC : 0; } -static int coda_bitstream_queue(struct coda_ctx *ctx, - struct vb2_v4l2_buffer *src_buf) +static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) { - u32 src_size = vb2_get_plane_payload(&src_buf->vb2_buf, 0); - u32 n; - - n = kfifo_in(&ctx->bitstream_fifo, - vb2_plane_vaddr(&src_buf->vb2_buf, 0), src_size); - if (n < src_size) - return -ENOSPC; + u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); - src_buf->sequence = ctx->qsequence++; - - return 0; + return (n < size) ? -ENOSPC : 0; } static bool coda_bitstream_try_queue(struct coda_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); int ret; if (coda_get_bitstream_payload(ctx) + payload + 512 >= ctx->bitstream.size) return false; - if (vb2_plane_vaddr(&src_buf->vb2_buf, 0) == NULL) { + if (!vaddr) { v4l2_err(&ctx->dev->v4l2_dev, "trying to queue empty buffer\n"); return true; } @@ -235,11 +227,14 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) coda_bitstream_pad(ctx, 512 - payload); - ret = coda_bitstream_queue(ctx, src_buf); + ret = coda_bitstream_queue(ctx, vaddr, payload); if (ret < 0) { v4l2_err(&ctx->dev->v4l2_dev, "bitstream buffer overflow\n"); return false; } + + src_buf->sequence = ctx->qsequence++; + /* Sync read pointer to device */ if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) coda_kfifo_sync_to_device_write(ctx); -- cgit v1.2.3-59-g8ed1b From 2719ef7d1b1107892923a1f5b7cbc28cccbdea3d Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:19 -0400 Subject: media: coda: pad first buffer with repeated MPEG headers to fix sequence init If the first buffer contains only headers, the sequence initialization command fails. On CodaHx4 the buffer must be padded to at least 512 bytes, on CODA960 it seems to be enough to just repeat the sequence and extension headers (MPEG-2) or the VOS and VO headers (MPEG-4) once for for sequence initialization to succeed without further bitstream data. On CodaHx4 the headers can be repeated multiple times until the 512 byte mark is reached. A similar issue was solved for h.264 by padding with a filler NAL in commit 0eef89403ece ("[media] coda: pad first h.264 buffer to 512 bytes"). Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 59 ++++++++++++++++++++++++++++++-- drivers/media/platform/coda/coda-mpeg2.c | 43 +++++++++++++++++++++++ drivers/media/platform/coda/coda-mpeg4.c | 38 ++++++++++++++++++++ drivers/media/platform/coda/coda.h | 2 ++ 4 files changed, 139 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 4f96f808b4dd..5a1016243032 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -180,7 +180,7 @@ static void coda_kfifo_sync_to_device_write(struct coda_ctx *ctx) coda_write(dev, wr_ptr, CODA_REG_BIT_WR_PTR(ctx->reg_idx)); } -static int coda_bitstream_pad(struct coda_ctx *ctx, u32 size) +static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) { unsigned char *buf; u32 n; @@ -206,12 +206,34 @@ static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) return (n < size) ? -ENOSPC : 0; } +static u32 coda_buffer_parse_headers(struct coda_ctx *ctx, + struct vb2_v4l2_buffer *src_buf, + u32 payload) +{ + u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + u32 size = 0; + + switch (ctx->codec->src_fourcc) { + case V4L2_PIX_FMT_MPEG2: + size = coda_mpeg2_parse_headers(ctx, vaddr, payload); + break; + case V4L2_PIX_FMT_MPEG4: + size = coda_mpeg4_parse_headers(ctx, vaddr, payload); + break; + default: + break; + } + + return size; +} + static bool coda_bitstream_try_queue(struct coda_ctx *ctx, struct vb2_v4l2_buffer *src_buf) { unsigned long payload = vb2_get_plane_payload(&src_buf->vb2_buf, 0); u8 *vaddr = vb2_plane_vaddr(&src_buf->vb2_buf, 0); int ret; + int i; if (coda_get_bitstream_payload(ctx) + payload + 512 >= ctx->bitstream.size) @@ -222,10 +244,41 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, return true; } - /* Add zero padding before the first H.264 buffer, if it is too small */ + if (ctx->qsequence == 0 && payload < 512) { + /* + * Add padding after the first buffer, if it is too small to be + * fetched by the CODA, by repeating the headers. Without + * repeated headers, or the first frame already queued, decoder + * sequence initialization fails with error code 0x2000 on i.MX6 + * or error code 0x1 on i.MX51. + */ + u32 header_size = coda_buffer_parse_headers(ctx, src_buf, + payload); + + if (header_size) { + coda_dbg(1, ctx, "pad with %u-byte header\n", + header_size); + for (i = payload; i < 512; i += header_size) { + ret = coda_bitstream_queue(ctx, vaddr, + header_size); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, + "bitstream buffer overflow\n"); + return false; + } + if (ctx->dev->devtype->product == CODA_960) + break; + } + } else { + coda_dbg(1, ctx, + "could not parse header, sequence initialization might fail\n"); + } + } + + /* Add padding before the first buffer, if it is too small */ if (ctx->qsequence == 0 && payload < 512 && ctx->codec->src_fourcc == V4L2_PIX_FMT_H264) - coda_bitstream_pad(ctx, 512 - payload); + coda_h264_bitstream_pad(ctx, 512 - payload); ret = coda_bitstream_queue(ctx, vaddr, payload); if (ret < 0) { diff --git a/drivers/media/platform/coda/coda-mpeg2.c b/drivers/media/platform/coda/coda-mpeg2.c index 73e50dabce19..6f3f6721d286 100644 --- a/drivers/media/platform/coda/coda-mpeg2.c +++ b/drivers/media/platform/coda/coda-mpeg2.c @@ -42,3 +42,46 @@ int coda_mpeg2_level(int level_idc) return -EINVAL; } } + +/* + * Check if the buffer starts with the MPEG-2 sequence header (with or without + * quantization matrix) and extension header, for example: + * + * 00 00 01 b3 2d 01 e0 34 08 8b a3 81 + * 10 11 11 12 12 12 13 13 13 13 14 14 14 14 14 15 + * 15 15 15 15 15 16 16 16 16 16 16 16 17 17 17 17 + * 17 17 17 17 18 18 18 19 18 18 18 19 1a 1a 1a 1a + * 19 1b 1b 1b 1b 1b 1c 1c 1c 1c 1e 1e 1e 1f 1f 21 + * 00 00 01 b5 14 8a 00 01 00 00 + * + * or: + * + * 00 00 01 b3 08 00 40 15 ff ff e0 28 + * 00 00 01 b5 14 8a 00 01 00 00 + * + * Returns the detected header size in bytes or 0. + */ +u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) +{ + static const u8 sequence_header_start[4] = { 0x00, 0x00, 0x01, 0xb3 }; + static const union { + u8 extension_start[4]; + u8 start_code_prefix[3]; + } u = { { 0x00, 0x00, 0x01, 0xb5 } }; + + if (size < 22 || + memcmp(buf, sequence_header_start, 4) != 0) + return 0; + + if ((size == 22 || + (size >= 25 && memcmp(buf + 22, u.start_code_prefix, 3) == 0)) && + memcmp(buf + 12, u.extension_start, 4) == 0) + return 22; + + if ((size == 86 || + (size > 89 && memcmp(buf + 86, u.start_code_prefix, 3) == 0)) && + memcmp(buf + 76, u.extension_start, 4) == 0) + return 86; + + return 0; +} diff --git a/drivers/media/platform/coda/coda-mpeg4.c b/drivers/media/platform/coda/coda-mpeg4.c index c3aca763c320..483a4fba1b4f 100644 --- a/drivers/media/platform/coda/coda-mpeg4.c +++ b/drivers/media/platform/coda/coda-mpeg4.c @@ -47,3 +47,41 @@ int coda_mpeg4_level(int level_idc) return -EINVAL; } } + +/* + * Check if the buffer starts with the MPEG-4 visual object sequence and visual + * object headers, for example: + * + * 00 00 01 b0 f1 + * 00 00 01 b5 a9 13 00 00 01 00 00 00 01 20 08 + * d4 8d 88 00 f5 04 04 08 14 30 3f + * + * Returns the detected header size in bytes or 0. + */ +u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size) +{ + static const u8 vos_start[4] = { 0x00, 0x00, 0x01, 0xb0 }; + static const union { + u8 vo_start[4]; + u8 start_code_prefix[3]; + } u = { { 0x00, 0x00, 0x01, 0xb5 } }; + + if (size < 30 || + memcmp(buf, vos_start, 4) != 0 || + memcmp(buf + 5, u.vo_start, 4) != 0) + return 0; + + if (size == 30 || + (size >= 33 && memcmp(buf + 30, u.start_code_prefix, 3) == 0)) + return 30; + + if (size == 31 || + (size >= 34 && memcmp(buf + 31, u.start_code_prefix, 3) == 0)) + return 31; + + if (size == 32 || + (size >= 35 && memcmp(buf + 32, u.start_code_prefix, 3) == 0)) + return 32; + + return 0; +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 10207e9534c2..12bbd3129269 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -338,8 +338,10 @@ int coda_h264_sps_fixup(struct coda_ctx *ctx, int width, int height, char *buf, int coda_mpeg2_profile(int profile_idc); int coda_mpeg2_level(int level_idc); +u32 coda_mpeg2_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); int coda_mpeg4_profile(int profile_idc); int coda_mpeg4_level(int level_idc); +u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size); void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc, u8 level_idc); -- cgit v1.2.3-59-g8ed1b From f74c0a29eca57e0024d31d41cbc4fc3d020bb42a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:20 -0400 Subject: media: coda: do not enforce 512-byte initial bitstream payload on CODA960 On CODA960, sequence initialization can succeed if less than 512 bytes are ready in the bitstream ring buffer. On other variants, warn about too small payload in start_streaming. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 19e3afa4f24d..1f1eb9685bc4 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1790,7 +1790,9 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) coda_fill_bitstream(ctx, &list); mutex_unlock(&ctx->bitstream_mutex); - if (coda_get_bitstream_payload(ctx) < 512) { + if (ctx->dev->devtype->product != CODA_960 && + coda_get_bitstream_payload(ctx) < 512) { + v4l2_err(v4l2_dev, "start payload < 512\n"); ret = -EINVAL; goto err; } -- cgit v1.2.3-59-g8ed1b From e7fd95849b3c25ae1604ba2788e63fe6570ba0ff Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:21 -0400 Subject: media: coda: flush bitstream ring buffer on decoder restart The bitstream ringbuffer might be in an underrun state after draining, or it might still contain unread data if the previous decoder stop command was flagged as immediate. Flush the bitstream ring buffer during V4L2_DEC_CMD_START to get into a well defined state. Also fill the bitstream with buffers that have been queued during draining, to resume decoding immediately. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 20 ++++++++++++++++++++ drivers/media/platform/coda/coda-common.c | 7 +++++++ drivers/media/platform/coda/coda.h | 1 + 3 files changed, 28 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 5a1016243032..843f92312f47 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -199,6 +199,26 @@ static int coda_h264_bitstream_pad(struct coda_ctx *ctx, u32 size) return (n < size) ? -ENOSPC : 0; } +int coda_bitstream_flush(struct coda_ctx *ctx) +{ + int ret; + + if (ctx->inst_type != CODA_INST_DECODER || !ctx->use_bit) + return 0; + + ret = coda_command_sync(ctx, CODA_COMMAND_DEC_BUF_FLUSH); + if (ret < 0) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to flush bitstream\n"); + return ret; + } + + kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, + ctx->bitstream.size); + coda_kfifo_sync_to_device_full(ctx); + + return 0; +} + static int coda_bitstream_queue(struct coda_ctx *ctx, const u8 *buf, u32 size) { u32 n = kfifo_in(&ctx->bitstream_fifo, buf, size); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 1f1eb9685bc4..0f5e6dcded99 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1052,6 +1052,7 @@ static int coda_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_dev *dev = ctx->dev; struct vb2_queue *dst_vq; int ret; @@ -1061,10 +1062,16 @@ static int coda_decoder_cmd(struct file *file, void *fh, switch (dc->cmd) { case V4L2_DEC_CMD_START: + mutex_lock(&ctx->bitstream_mutex); + mutex_lock(&dev->coda_mutex); + coda_bitstream_flush(ctx); + mutex_unlock(&dev->coda_mutex); dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); vb2_clear_last_buffer_dequeued(dst_vq); ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; + coda_fill_bitstream(ctx, NULL); + mutex_unlock(&ctx->bitstream_mutex); break; case V4L2_DEC_CMD_STOP: /* Set the stream-end flag on this context */ diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 12bbd3129269..6911c1c811ce 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -322,6 +322,7 @@ static inline bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, } bool coda_bitstream_can_fetch_past(struct coda_ctx *ctx, unsigned int pos); +int coda_bitstream_flush(struct coda_ctx *ctx); void coda_bit_stream_end_flag(struct coda_ctx *ctx); -- cgit v1.2.3-59-g8ed1b From b3b7d96817cdb8b6fc353867705275dce8f41ccc Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:22 -0400 Subject: media: coda: increment sequence offset for the last returned frame If no more frames are decoded in bitstream end mode, and a previously decoded frame has been returned, the firmware still increments the frame number. To avoid a sequence number mismatch after decoder restart, increment the sequence_offset correction parameter. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 843f92312f47..bfe6019e68a8 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2280,6 +2280,9 @@ static void coda_finish_decode(struct coda_ctx *ctx) else if (ctx->display_idx < 0) ctx->hold = true; } else if (decoded_idx == -2) { + if (ctx->display_idx >= 0 && + ctx->display_idx < ctx->num_internal_frames) + ctx->sequence_offset++; /* no frame was decoded, we still return remaining buffers */ } else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) { v4l2_err(&dev->v4l2_dev, -- cgit v1.2.3-59-g8ed1b From aa3972a358b6f13b482975152e3fa449b7a32974 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:23 -0400 Subject: media: coda: allow flagging last output buffer internally Since V4L2_BUF_FLAG_LAST is a CAPTURE only flag, clear it from OUTPUT buffers in QBUF and DQBUF. This allows to use the flag internally to signal the last buffer to decode after a decoder stop command was issued. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 0f5e6dcded99..935e8c408feb 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -879,9 +879,27 @@ static int coda_qbuf(struct file *file, void *priv, { struct coda_ctx *ctx = fh_to_ctx(priv); + if (ctx->inst_type == CODA_INST_DECODER && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + buf->flags &= ~V4L2_BUF_FLAG_LAST; + return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf); } +static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) +{ + struct coda_ctx *ctx = fh_to_ctx(priv); + int ret; + + ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf); + + if (ctx->inst_type == CODA_INST_DECODER && + buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + buf->flags &= ~V4L2_BUF_FLAG_LAST; + + return ret; +} + static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf) { @@ -1295,7 +1313,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_qbuf = coda_qbuf, .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_dqbuf = coda_dqbuf, .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, -- cgit v1.2.3-59-g8ed1b From 1b438b454085238b44875ac6cd508fc1106f07d1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:24 -0400 Subject: media: coda: mark the last output buffer on decoder stop command Mark the last output buffer to be decoded and only copy pending queued output buffers into the bitstream ring buffer in the BIT processor decoder case. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 3 +++ drivers/media/platform/coda/coda-common.c | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index bfe6019e68a8..cbcec571a014 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -312,6 +312,9 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx, if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev)) coda_kfifo_sync_to_device_write(ctx); + /* Set the stream-end flag after the last buffer is queued */ + if (src_buf->flags & V4L2_BUF_FLAG_LAST) + coda_bit_stream_end_flag(ctx); ctx->hold = false; return true; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 935e8c408feb..b35e6ea70424 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1071,6 +1071,7 @@ static int coda_decoder_cmd(struct file *file, void *fh, { struct coda_ctx *ctx = fh_to_ctx(fh); struct coda_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *buf; struct vb2_queue *dst_vq; int ret; @@ -1092,6 +1093,11 @@ static int coda_decoder_cmd(struct file *file, void *fh, mutex_unlock(&ctx->bitstream_mutex); break; case V4L2_DEC_CMD_STOP: + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + if (buf) + /* Mark last buffer */ + buf->flags |= V4L2_BUF_FLAG_LAST; + /* Set the stream-end flag on this context */ coda_bit_stream_end_flag(ctx); ctx->hold = false; -- cgit v1.2.3-59-g8ed1b From a02f6ca3367e1fd3cbd14e8798af90b8b667bbbe Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:25 -0400 Subject: media: coda: only set the stream end flags if there are no more pending output buffers If there are still queued output buffers pending to be copied into the bitstream ring buffer, setting the stream end flag should be deferred until the marked last output buffer is written into the bitstream ring buffer. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index b35e6ea70424..a1277d321aa3 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1098,16 +1098,20 @@ static int coda_decoder_cmd(struct file *file, void *fh, /* Mark last buffer */ buf->flags |= V4L2_BUF_FLAG_LAST; - /* Set the stream-end flag on this context */ - coda_bit_stream_end_flag(ctx); - ctx->hold = false; - v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { + /* Set the stream-end flag on this context */ + coda_bit_stream_end_flag(ctx); + ctx->hold = false; + v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); - flush_work(&ctx->pic_run_work); + flush_work(&ctx->pic_run_work); + + /* If there is no buffer in flight, wake up */ + if (!ctx->streamon_out || + ctx->qsequence == ctx->osequence) + coda_wake_up_capture_queue(ctx); + } - /* If there is no buffer in flight, wake up */ - if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) - coda_wake_up_capture_queue(ctx); break; default: return -EINVAL; -- cgit v1.2.3-59-g8ed1b From 9e3b94cc03db36c4735f0daa5a8789557550efc1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:26 -0400 Subject: media: coda: mark the last output buffer on encoder stop command Mark the last output buffer to be encoded. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index a1277d321aa3..d0de3b325b14 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1037,12 +1037,17 @@ static int coda_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { struct coda_ctx *ctx = fh_to_ctx(fh); + struct vb2_v4l2_buffer *buf; int ret; ret = coda_try_encoder_cmd(file, fh, ec); if (ret < 0) return ret; + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); + if (buf) + buf->flags |= V4L2_BUF_FLAG_LAST; + /* Set the stream-end flag on this context */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; -- cgit v1.2.3-59-g8ed1b From 0ee08a1e7b713dcf0d2526af35314dd7f21c8138 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:27 -0400 Subject: media: coda: retire coda_buf_is_end_of_stream Using the output queue sequence counter to determine the last buffer to be encoded or decoded always was fragile at best. Now that we have the last buffer flag propagating from the output queue to the capture queue correctly, this is not needed anymore. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index d0de3b325b14..46f2bb6febde 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -900,13 +900,6 @@ static int coda_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return ret; } -static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx, - struct vb2_v4l2_buffer *buf) -{ - return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) && - (buf->sequence == (ctx->qsequence - 1))); -} - void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state) { @@ -914,11 +907,8 @@ void coda_m2m_buf_done(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, .type = V4L2_EVENT_EOS }; - if (coda_buf_is_end_of_stream(ctx, buf)) { - buf->flags |= V4L2_BUF_FLAG_LAST; - + if (buf->flags & V4L2_BUF_FLAG_LAST) v4l2_event_queue_fh(&ctx->fh, &eos_event); - } v4l2_m2m_buf_done(buf, state); } -- cgit v1.2.3-59-g8ed1b From 0f8f633834357f2513d21a6468db6d5989e8c494 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:28 -0400 Subject: media: coda: only wake up capture queue if no pending buffers to encode If there are no pending queued output buffers to be encoded, waking up the capture queue with -EPIPE signals end of stream. If there are pending buffers on the other hand, setting the V4L2_BUF_FLAG_LAST on the resulting encoded capture buffers is all that is needed. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 46f2bb6febde..73c18be14cbf 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1035,17 +1035,18 @@ static int coda_encoder_cmd(struct file *file, void *fh, return ret; buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); - if (buf) + if (buf) { buf->flags |= V4L2_BUF_FLAG_LAST; + } else { + /* Set the stream-end flag on this context */ + ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - /* Set the stream-end flag on this context */ - ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - - flush_work(&ctx->pic_run_work); + flush_work(&ctx->pic_run_work); - /* If there is no buffer in flight, wake up */ - if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) - coda_wake_up_capture_queue(ctx); + /* If there is no buffer in flight, wake up */ + if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) + coda_wake_up_capture_queue(ctx); + } return 0; } -- cgit v1.2.3-59-g8ed1b From cf895efc4d9c2dfb3cd03cf298ea55637feba901 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:29 -0400 Subject: media: coda: flag the last encoded buffer Use the flagged last output buffer to also flag the corresponding capture buffer after encoding. This causes the end of stream event to be issued and the buffer to be dequeued with the last flag set. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index cbcec571a014..7bcdfe8dcf3d 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1565,13 +1565,14 @@ static void coda_finish_encode(struct coda_ctx *ctx) coda_read(dev, CODA_RET_ENC_PIC_SLICE_NUM); coda_read(dev, CODA_RET_ENC_PIC_FLAG); - if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) { + dst_buf->flags &= ~(V4L2_BUF_FLAG_KEYFRAME | + V4L2_BUF_FLAG_PFRAME | + V4L2_BUF_FLAG_LAST); + if (coda_read(dev, CODA_RET_ENC_PIC_TYPE) == 0) dst_buf->flags |= V4L2_BUF_FLAG_KEYFRAME; - dst_buf->flags &= ~V4L2_BUF_FLAG_PFRAME; - } else { + else dst_buf->flags |= V4L2_BUF_FLAG_PFRAME; - dst_buf->flags &= ~V4L2_BUF_FLAG_KEYFRAME; - } + dst_buf->flags |= src_buf->flags & V4L2_BUF_FLAG_LAST; v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); @@ -1584,8 +1585,9 @@ static void coda_finish_encode(struct coda_ctx *ctx) if (ctx->gopcounter < 0) ctx->gopcounter = ctx->params.gop_size - 1; - coda_dbg(1, ctx, "job finished: encoded %c frame (%d)\n", - coda_frame_type_char(dst_buf->flags), dst_buf->sequence); + coda_dbg(1, ctx, "job finished: encoded %c frame (%d)%s\n", + coda_frame_type_char(dst_buf->flags), dst_buf->sequence, + (dst_buf->flags & V4L2_BUF_FLAG_LAST) ? " (last)" : ""); } static void coda_seq_end_work(struct work_struct *work) -- cgit v1.2.3-59-g8ed1b From 9ee50a9489f16048a82c94139f5436f4bb2620d9 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:30 -0400 Subject: media: coda: lock capture queue wakeup against encoder stop command Make sure that an encoder stop command running concurrently with an encoder finish_run always either flags the last returned buffer or wakes up the capture queue to signal the end of stream condition afterwards. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 7 +++++++ drivers/media/platform/coda/coda-common.c | 19 ++++++++++++++----- drivers/media/platform/coda/coda.h | 6 ++++++ 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 7bcdfe8dcf3d..44085e3d43d5 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1540,6 +1540,12 @@ static void coda_finish_encode(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; u32 wr_ptr, start_ptr; + /* + * Lock to make sure that an encoder stop command running in parallel + * will either already have marked src_buf as last, or it will wake up + * the capture queue after the buffers are returned. + */ + mutex_lock(&ctx->wakeup_mutex); src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1580,6 +1586,7 @@ static void coda_finish_encode(struct coda_ctx *ctx) dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); coda_m2m_buf_done(ctx, dst_buf, VB2_BUF_STATE_DONE); + mutex_unlock(&ctx->wakeup_mutex); ctx->gopcounter--; if (ctx->gopcounter < 0) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 73c18be14cbf..95c233b2cbf8 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1034,19 +1034,27 @@ static int coda_encoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; + mutex_lock(&ctx->wakeup_mutex); buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); if (buf) { + /* + * If the last output buffer is still on the queue, make sure + * that decoder finish_run will see the last flag and report it + * to userspace. + */ buf->flags |= V4L2_BUF_FLAG_LAST; } else { /* Set the stream-end flag on this context */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; - flush_work(&ctx->pic_run_work); - - /* If there is no buffer in flight, wake up */ - if (!ctx->streamon_out || ctx->qsequence == ctx->osequence) - coda_wake_up_capture_queue(ctx); + /* + * If the last output buffer has already been taken from the + * queue, wake up the capture queue and signal end of stream + * via the -EPIPE mechanism. + */ + coda_wake_up_capture_queue(ctx); } + mutex_unlock(&ctx->wakeup_mutex); return 0; } @@ -2466,6 +2474,7 @@ static int coda_open(struct file *file) mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); + mutex_init(&ctx->wakeup_mutex); INIT_LIST_HEAD(&ctx->buffer_meta_list); spin_lock_init(&ctx->buffer_meta_lock); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 6911c1c811ce..97845e58fb8b 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -258,6 +258,12 @@ struct coda_ctx { bool use_bit; bool use_vdoa; struct vdoa_ctx *vdoa; + /* + * wakeup mutex used to serialize encoder stop command and finish_run, + * ensures that finish_run always either flags the last returned buffer + * or wakes up the capture queue to signal EOS afterwards. + */ + struct mutex wakeup_mutex; }; extern int coda_debug; -- cgit v1.2.3-59-g8ed1b From d09ed310142af3e87359620d12f256969f8de439 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:31 -0400 Subject: media: coda: mark last pending buffer or last meta on decoder stop command If there is still a buffer pending, mark it as the last buffer. It will create a meta that is flagged as last when the buffer is copied into the bitstream ring buffer. If there are no more buffers pending, find the last bitstream meta and mark it as last. If there is no bitstream meta either, wake up the capture queue as there will be no more decoded frames. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 4 +++ drivers/media/platform/coda/coda-common.c | 44 ++++++++++++++++++++++++++----- drivers/media/platform/coda/coda.h | 1 + 3 files changed, 42 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 44085e3d43d5..1157454e3bc8 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -402,6 +402,9 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list) meta->timestamp = src_buf->vb2_buf.timestamp; meta->start = start; meta->end = ctx->bitstream_fifo.kfifo.in; + meta->last = src_buf->flags & V4L2_BUF_FLAG_LAST; + if (meta->last) + coda_dbg(1, ctx, "marking last meta"); spin_lock(&ctx->buffer_meta_lock); list_add_tail(&meta->list, &ctx->buffer_meta_list); @@ -2334,6 +2337,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) memset(&decoded_frame->meta, 0, sizeof(struct coda_buffer_meta)); decoded_frame->meta.sequence = val; + decoded_frame->meta.last = false; ctx->sequence_offset++; } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 95c233b2cbf8..11baa5b1eed8 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1077,6 +1077,8 @@ static int coda_decoder_cmd(struct file *file, void *fh, struct coda_dev *dev = ctx->dev; struct vb2_v4l2_buffer *buf; struct vb2_queue *dst_vq; + bool stream_end; + bool wakeup; int ret; ret = coda_try_decoder_cmd(file, fh, dc); @@ -1097,23 +1099,51 @@ static int coda_decoder_cmd(struct file *file, void *fh, mutex_unlock(&ctx->bitstream_mutex); break; case V4L2_DEC_CMD_STOP: + stream_end = false; + wakeup = false; + buf = v4l2_m2m_last_src_buf(ctx->fh.m2m_ctx); - if (buf) + if (buf) { + coda_dbg(1, ctx, "marking last pending buffer\n"); + /* Mark last buffer */ buf->flags |= V4L2_BUF_FLAG_LAST; - if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) == 0) { + coda_dbg(1, ctx, "all remaining buffers queued\n"); + stream_end = true; + } + } else { + coda_dbg(1, ctx, "marking last meta\n"); + + /* Mark last meta */ + spin_lock(&ctx->buffer_meta_lock); + if (!list_empty(&ctx->buffer_meta_list)) { + struct coda_buffer_meta *meta; + + meta = list_last_entry(&ctx->buffer_meta_list, + struct coda_buffer_meta, + list); + meta->last = true; + stream_end = true; + } else { + wakeup = true; + } + spin_unlock(&ctx->buffer_meta_lock); + } + + if (stream_end) { + coda_dbg(1, ctx, "all remaining buffers queued\n"); + /* Set the stream-end flag on this context */ coda_bit_stream_end_flag(ctx); ctx->hold = false; v4l2_m2m_try_schedule(ctx->fh.m2m_ctx); + } - flush_work(&ctx->pic_run_work); - + if (wakeup) { /* If there is no buffer in flight, wake up */ - if (!ctx->streamon_out || - ctx->qsequence == ctx->osequence) - coda_wake_up_capture_queue(ctx); + coda_wake_up_capture_queue(ctx); } break; diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 97845e58fb8b..5c183c1944fe 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -146,6 +146,7 @@ struct coda_buffer_meta { u64 timestamp; unsigned int start; unsigned int end; + bool last; }; /* Per-queue, driver-specific private data */ -- cgit v1.2.3-59-g8ed1b From 4b424e9e01e6aec16d6e1deaa99f03598ccb8975 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:32 -0400 Subject: media: coda: mark last returned frame If reordering is not enabled, the last decoded frame has to be the last returned buffer. Otherwise wait for the firmware to report no more frame to display. In that case the return buffer is the last one as well, and can be reported as such. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 1157454e3bc8..167a92772c84 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2381,6 +2381,23 @@ static void coda_finish_decode(struct coda_ctx *ctx) V4L2_BUF_FLAG_BFRAME); dst_buf->flags |= ready_frame->type; meta = &ready_frame->meta; + if (meta->last && !coda_reorder_enable(ctx)) { + /* + * If this was the last decoded frame, and reordering + * is disabled, this will be the last display frame. + */ + coda_dbg(1, ctx, "last meta, marking as last frame\n"); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + } else if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG && + display_idx == -1) { + /* + * If there is no designated presentation frame anymore, + * this frame has to be the last one. + */ + coda_dbg(1, ctx, + "no more frames to return, marking as last frame\n"); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + } dst_buf->timecode = meta->timecode; dst_buf->vb2_buf.timestamp = meta->timestamp; -- cgit v1.2.3-59-g8ed1b From cdc841b5ac05fa9fcfe1be5d55bb57c0d4749a49 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:33 -0400 Subject: media: coda: store device pointer in driver structure instead of pdev Currently the platform device pointer is stored in struct coda_dev, only to convert it into a device pointer wherever it is used. Just store the device pointer directly. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 7 +++---- drivers/media/platform/coda/coda-common.c | 33 ++++++++++++++----------------- drivers/media/platform/coda/coda.h | 2 +- 3 files changed, 19 insertions(+), 23 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 167a92772c84..de6a4216a182 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1667,8 +1667,7 @@ static int coda_alloc_bitstream_buffer(struct coda_ctx *ctx, return 0; ctx->bitstream.size = roundup_pow_of_two(q_data->sizeimage * 2); - ctx->bitstream.vaddr = dma_alloc_wc(&ctx->dev->plat_dev->dev, - ctx->bitstream.size, + ctx->bitstream.vaddr = dma_alloc_wc(ctx->dev->dev, ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL); if (!ctx->bitstream.vaddr) { v4l2_err(&ctx->dev->v4l2_dev, @@ -1686,8 +1685,8 @@ static void coda_free_bitstream_buffer(struct coda_ctx *ctx) if (ctx->bitstream.vaddr == NULL) return; - dma_free_wc(&ctx->dev->plat_dev->dev, ctx->bitstream.size, - ctx->bitstream.vaddr, ctx->bitstream.paddr); + dma_free_wc(ctx->dev->dev, ctx->bitstream.size, ctx->bitstream.vaddr, + ctx->bitstream.paddr); ctx->bitstream.vaddr = NULL; kfifo_init(&ctx->bitstream_fifo, NULL, 0); } diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 11baa5b1eed8..f43f38888102 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1413,7 +1413,7 @@ static void coda_pic_run_work(struct work_struct *work) if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) { - dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n"); + dev_err(dev->dev, "CODA PIC_RUN timeout\n"); ctx->hold = true; @@ -1797,7 +1797,7 @@ static void coda_buf_queue(struct vb2_buffer *vb) int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, size_t size, const char *name, struct dentry *parent) { - buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr, + buf->vaddr = dma_alloc_coherent(dev->dev, size, &buf->paddr, GFP_KERNEL); if (!buf->vaddr) { v4l2_err(&dev->v4l2_dev, @@ -1814,7 +1814,7 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf, buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob); if (!buf->dentry) - dev_warn(&dev->plat_dev->dev, + dev_warn(dev->dev, "failed to create debugfs entry %s\n", name); } @@ -1825,8 +1825,7 @@ void coda_free_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf) { if (buf->vaddr) { - dma_free_coherent(&dev->plat_dev->dev, buf->size, - buf->vaddr, buf->paddr); + dma_free_coherent(dev->dev, buf->size, buf->vaddr, buf->paddr); buf->vaddr = NULL; buf->size = 0; debugfs_remove(buf->dentry); @@ -2344,7 +2343,7 @@ static int coda_queue_init(struct coda_ctx *ctx, struct vb2_queue *vq) * queues to have at least one buffer queued. */ vq->min_buffers_needed = 1; - vq->dev = &ctx->dev->plat_dev->dev; + vq->dev = ctx->dev->dev; return vb2_queue_init(vq); } @@ -2469,7 +2468,7 @@ static int coda_open(struct file *file) ctx->use_vdoa = false; /* Power up and upload firmware if necessary */ - ret = pm_runtime_get_sync(&dev->plat_dev->dev); + ret = pm_runtime_get_sync(dev->dev); if (ret < 0) { v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret); goto err_pm_get; @@ -2517,7 +2516,7 @@ err_ctx_init: err_clk_ahb: clk_disable_unprepare(dev->clk_per); err_clk_per: - pm_runtime_put_sync(&dev->plat_dev->dev); + pm_runtime_put_sync(dev->dev); err_pm_get: v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); @@ -2556,7 +2555,7 @@ static int coda_release(struct file *file) v4l2_ctrl_handler_free(&ctx->ctrls); clk_disable_unprepare(dev->clk_ahb); clk_disable_unprepare(dev->clk_per); - pm_runtime_put_sync(&dev->plat_dev->dev); + pm_runtime_put_sync(dev->dev); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); ida_free(&dev->ida, ctx->idx); @@ -2751,18 +2750,16 @@ static int coda_firmware_request(struct coda_dev *dev) fw = dev->devtype->firmware[dev->firmware]; - dev_dbg(&dev->plat_dev->dev, "requesting firmware '%s' for %s\n", fw, + dev_dbg(dev->dev, "requesting firmware '%s' for %s\n", fw, coda_product_name(dev->devtype->product)); - return request_firmware_nowait(THIS_MODULE, true, fw, - &dev->plat_dev->dev, GFP_KERNEL, dev, - coda_fw_callback); + return request_firmware_nowait(THIS_MODULE, true, fw, dev->dev, + GFP_KERNEL, dev, coda_fw_callback); } static void coda_fw_callback(const struct firmware *fw, void *context) { struct coda_dev *dev = context; - struct platform_device *pdev = dev->plat_dev; int i, ret; if (!fw) { @@ -2780,7 +2777,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) * firmware requests, report that the fallback firmware was * found. */ - dev_info(&pdev->dev, "Using fallback firmware %s\n", + dev_info(dev->dev, "Using fallback firmware %s\n", dev->devtype->firmware[dev->firmware]); } @@ -2819,7 +2816,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context) } } - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(dev->dev); return; rel_vfd: @@ -2827,7 +2824,7 @@ rel_vfd: video_unregister_device(&dev->vfd[i]); v4l2_m2m_release(dev->m2m_dev); put_pm: - pm_runtime_put_sync(&pdev->dev); + pm_runtime_put_sync(dev->dev); } enum coda_platform { @@ -2959,7 +2956,7 @@ static int coda_probe(struct platform_device *pdev) spin_lock_init(&dev->irqlock); - dev->plat_dev = pdev; + dev->dev = &pdev->dev; dev->clk_per = devm_clk_get(&pdev->dev, "per"); if (IS_ERR(dev->clk_per)) { dev_err(&pdev->dev, "Could not get per clock\n"); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 5c183c1944fe..502a6272629a 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -70,7 +70,7 @@ struct coda_aux_buf { struct coda_dev { struct v4l2_device v4l2_dev; struct video_device vfd[5]; - struct platform_device *plat_dev; + struct device *dev; const struct coda_devtype *devtype; int firmware; struct vdoa_data *vdoa; -- cgit v1.2.3-59-g8ed1b From 0414b4756820e1ec908f95953cea959d26b0063b Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:34 -0400 Subject: media: coda: add coda_slice_mode() function Changing slice mode dynamically while encoding will require to calculate the register value again, so split it out into a separate function. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 45 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index de6a4216a182..b59cb16f75a1 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -675,6 +675,29 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_v4l2_buffer *buf, return 0; } +static u32 coda_slice_mode(struct coda_ctx *ctx) +{ + int size, unit; + + switch (ctx->params.slice_mode) { + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: + default: + return 0; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: + size = ctx->params.slice_max_mb; + unit = 1; + break; + case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: + size = ctx->params.slice_max_bits; + unit = 0; + break; + } + + return ((size & CODA_SLICING_SIZE_MASK) << CODA_SLICING_SIZE_OFFSET) | + ((unit & CODA_SLICING_UNIT_MASK) << CODA_SLICING_UNIT_OFFSET) | + ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); +} + static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) { phys_addr_t ret; @@ -1113,27 +1136,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) * in JPEG mode */ if (dst_fourcc != V4L2_PIX_FMT_JPEG) { - switch (ctx->params.slice_mode) { - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE: - value = 0; - break; - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_MB: - value = (ctx->params.slice_max_mb & - CODA_SLICING_SIZE_MASK) - << CODA_SLICING_SIZE_OFFSET; - value |= (1 & CODA_SLICING_UNIT_MASK) - << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_MAX_BYTES: - value = (ctx->params.slice_max_bits & - CODA_SLICING_SIZE_MASK) - << CODA_SLICING_SIZE_OFFSET; - value |= (0 & CODA_SLICING_UNIT_MASK) - << CODA_SLICING_UNIT_OFFSET; - value |= 1 & CODA_SLICING_MODE_MASK; - break; - } + value = coda_slice_mode(ctx); coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE); value = ctx->params.gop_size; coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE); -- cgit v1.2.3-59-g8ed1b From b152a403a0208aad25f9977f12a2e5a039e246b0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Tue, 18 Jun 2019 12:45:35 -0400 Subject: media: coda: encoder parameter change support Add support for dynamically changing the GOP size, bitrate, frame rate, constant intra quantization parameter, number of intra refresh macro blocks and slice mode parameters. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 83 +++++++++++++++++++++++++++++++ drivers/media/platform/coda/coda-common.c | 7 +++ drivers/media/platform/coda/coda.h | 7 +++ drivers/media/platform/coda/coda_regs.h | 18 +++++++ 4 files changed, 115 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b59cb16f75a1..00c7bed3dd57 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -698,6 +698,79 @@ static u32 coda_slice_mode(struct coda_ctx *ctx) ((1 & CODA_SLICING_MODE_MASK) << CODA_SLICING_MODE_OFFSET); } +static int coda_enc_param_change(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + u32 change_enable = 0; + u32 success; + int ret; + + if (ctx->params.gop_size_changed) { + change_enable |= CODA_PARAM_CHANGE_RC_GOP; + coda_write(dev, ctx->params.gop_size, + CODA_CMD_ENC_PARAM_RC_GOP); + ctx->gopcounter = ctx->params.gop_size - 1; + ctx->params.gop_size_changed = false; + } + if (ctx->params.h264_intra_qp_changed) { + coda_dbg(1, ctx, "parameter change: intra Qp %u\n", + ctx->params.h264_intra_qp); + + if (ctx->params.bitrate) { + change_enable |= CODA_PARAM_CHANGE_RC_INTRA_QP; + coda_write(dev, ctx->params.h264_intra_qp, + CODA_CMD_ENC_PARAM_RC_INTRA_QP); + } + ctx->params.h264_intra_qp_changed = false; + } + if (ctx->params.bitrate_changed) { + coda_dbg(1, ctx, "parameter change: bitrate %u kbit/s\n", + ctx->params.bitrate); + change_enable |= CODA_PARAM_CHANGE_RC_BITRATE; + coda_write(dev, ctx->params.bitrate, + CODA_CMD_ENC_PARAM_RC_BITRATE); + ctx->params.bitrate_changed = false; + } + if (ctx->params.framerate_changed) { + coda_dbg(1, ctx, "parameter change: frame rate %u/%u Hz\n", + ctx->params.framerate & 0xffff, + (ctx->params.framerate >> 16) + 1); + change_enable |= CODA_PARAM_CHANGE_RC_FRAME_RATE; + coda_write(dev, ctx->params.framerate, + CODA_CMD_ENC_PARAM_RC_FRAME_RATE); + ctx->params.framerate_changed = false; + } + if (ctx->params.intra_refresh_changed) { + coda_dbg(1, ctx, "parameter change: intra refresh MBs %u\n", + ctx->params.intra_refresh); + change_enable |= CODA_PARAM_CHANGE_INTRA_MB_NUM; + coda_write(dev, ctx->params.intra_refresh, + CODA_CMD_ENC_PARAM_INTRA_MB_NUM); + ctx->params.intra_refresh_changed = false; + } + if (ctx->params.slice_mode_changed) { + change_enable |= CODA_PARAM_CHANGE_SLICE_MODE; + coda_write(dev, coda_slice_mode(ctx), + CODA_CMD_ENC_PARAM_SLICE_MODE); + ctx->params.slice_mode_changed = false; + } + + if (!change_enable) + return 0; + + coda_write(dev, change_enable, CODA_CMD_ENC_PARAM_CHANGE_ENABLE); + + ret = coda_command_sync(ctx, CODA_COMMAND_RC_CHANGE_PARAMETER); + if (ret < 0) + return ret; + + success = coda_read(dev, CODA_RET_ENC_PARAM_CHANGE_SUCCESS); + if (success != 1) + coda_dbg(1, ctx, "parameter change failed: %u\n", success); + + return 0; +} + static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size) { phys_addr_t ret; @@ -1143,6 +1216,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) } if (ctx->params.bitrate) { + ctx->params.bitrate_changed = false; + ctx->params.h264_intra_qp_changed = false; + /* Rate control enabled */ value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; @@ -1397,6 +1473,13 @@ static int coda_prepare_encode(struct coda_ctx *ctx) u32 rot_mode = 0; u32 dst_fourcc; u32 reg; + int ret; + + ret = coda_enc_param_change(ctx); + if (ret < 0) { + v4l2_warn(&ctx->dev->v4l2_dev, "parameter change failed: %d\n", + ret); + } src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index f43f38888102..01428de2596e 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1317,6 +1317,7 @@ static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) tpf = &a->parm.output.timeperframe; coda_approximate_timeperframe(tpf); ctx->params.framerate = coda_timeperframe_to_frate(tpf); + ctx->params.framerate_changed = true; return 0; } @@ -2033,12 +2034,14 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_BITRATE: ctx->params.bitrate = ctrl->val / 1000; + ctx->params.bitrate_changed = true; break; case V4L2_CID_MPEG_VIDEO_GOP_SIZE: ctx->params.gop_size = ctrl->val; break; case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP: ctx->params.h264_intra_qp = ctrl->val; + ctx->params.h264_intra_qp_changed = true; break; case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP: ctx->params.h264_inter_qp = ctrl->val; @@ -2086,17 +2089,21 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE: ctx->params.slice_mode = ctrl->val; + ctx->params.slice_mode_changed = true; break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_MB: ctx->params.slice_max_mb = ctrl->val; + ctx->params.slice_mode_changed = true; break; case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MAX_BYTES: ctx->params.slice_max_bits = ctrl->val * 8; + ctx->params.slice_mode_changed = true; break; case V4L2_CID_MPEG_VIDEO_HEADER_MODE: break; case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB: ctx->params.intra_refresh = ctrl->val; + ctx->params.intra_refresh_changed = true; break; case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: ctx->params.force_ipicture = true; diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 502a6272629a..848bf1da401e 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -137,6 +137,12 @@ struct coda_params { u32 slice_max_bits; u32 slice_max_mb; bool force_ipicture; + bool gop_size_changed; + bool bitrate_changed; + bool framerate_changed; + bool h264_intra_qp_changed; + bool intra_refresh_changed; + bool slice_mode_changed; }; struct coda_buffer_meta { @@ -254,6 +260,7 @@ struct coda_ctx { u32 bit_stream_param; u32 frm_dis_flg; u32 frame_mem_ctrl; + u32 para_change; int display_idx; struct dentry *debugfs_entry; bool use_bit; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 4d503f472397..b17464b56d3d 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -342,6 +342,24 @@ #define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4 #define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8 +/* Encoder Parameter Change */ +#define CODA_CMD_ENC_PARAM_CHANGE_ENABLE 0x180 +#define CODA_PARAM_CHANGE_RC_GOP BIT(0) +#define CODA_PARAM_CHANGE_RC_INTRA_QP BIT(1) +#define CODA_PARAM_CHANGE_RC_BITRATE BIT(2) +#define CODA_PARAM_CHANGE_RC_FRAME_RATE BIT(3) +#define CODA_PARAM_CHANGE_INTRA_MB_NUM BIT(4) +#define CODA_PARAM_CHANGE_SLICE_MODE BIT(5) +#define CODA_PARAM_CHANGE_HEC_MODE BIT(6) +#define CODA_CMD_ENC_PARAM_RC_GOP 0x184 +#define CODA_CMD_ENC_PARAM_RC_INTRA_QP 0x188 +#define CODA_CMD_ENC_PARAM_RC_BITRATE 0x18c +#define CODA_CMD_ENC_PARAM_RC_FRAME_RATE 0x190 +#define CODA_CMD_ENC_PARAM_INTRA_MB_NUM 0x194 +#define CODA_CMD_ENC_PARAM_SLICE_MODE 0x198 +#define CODA_CMD_ENC_PARAM_HEC_MODE 0x19c +#define CODA_RET_ENC_PARAM_CHANGE_SUCCESS 0x1c0 + /* Encoder Picture Run */ #define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180 #define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184 -- cgit v1.2.3-59-g8ed1b From a8fa55078a7784a99a2ce389b5d7456a3be9a941 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 20 May 2019 17:27:45 -0400 Subject: media: v4l2-subdev: Verify arguments in v4l2_subdev_call() Correctness of format type (try or active) and pad number parameters passed to subdevice operation callbacks is now verified only for IOCTL calls. However, those callbacks are also used by drivers, e.g., V4L2 host interfaces. Since both subdev_do_ioctl() and drivers are using v4l2_subdev_call() macro while calling subdevice operations, move those parameter checks from subdev_do_ioctl() to v4l2_subdev_call() so we can avoid taking care of those checks inside drivers. Define a wrapper function for each operation callback in scope, then gather those wrappers in a static v4l2_subdev_ops structure so the v4l2_subdev_call() macro can find them easy if provided. Signed-off-by: Janusz Krzysztofik Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 238 +++++++++++++++++++++------------- include/media/v4l2-subdev.h | 6 + 2 files changed, 152 insertions(+), 92 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f24978b80440..81b08f66da9b 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -112,56 +112,175 @@ static int subdev_close(struct file *file) return 0; } -#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) -static int check_format(struct v4l2_subdev *sd, - struct v4l2_subdev_format *format) +static inline int check_which(__u32 which) { - if (format->which != V4L2_SUBDEV_FORMAT_TRY && - format->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (format->pad >= sd->entity.num_pads) + if (which != V4L2_SUBDEV_FORMAT_TRY && + which != V4L2_SUBDEV_FORMAT_ACTIVE) return -EINVAL; return 0; } -static int check_crop(struct v4l2_subdev *sd, struct v4l2_subdev_crop *crop) +static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) { - if (crop->which != V4L2_SUBDEV_FORMAT_TRY && - crop->which != V4L2_SUBDEV_FORMAT_ACTIVE) +#if defined(CONFIG_MEDIA_CONTROLLER) + if (sd->entity.graph_obj.mdev) { + if (pad >= sd->entity.num_pads) + return -EINVAL; + return 0; + } +#endif + /* allow pad 0 on subdevices not registered as media entities */ + if (pad > 0) return -EINVAL; + return 0; +} - if (crop->pad >= sd->entity.num_pads) - return -EINVAL; +static inline int check_format(struct v4l2_subdev *sd, + struct v4l2_subdev_format *format) +{ + return check_which(format->which) ? : check_pad(sd, format->pad); +} - return 0; +static int call_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + return check_format(sd, format) ? : + sd->ops->pad->get_fmt(sd, cfg, format); } -static int check_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_selection *sel) +static int call_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) { - if (sel->which != V4L2_SUBDEV_FORMAT_TRY && - sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; + return check_format(sd, format) ? : + sd->ops->pad->set_fmt(sd, cfg, format); +} - if (sel->pad >= sd->entity.num_pads) - return -EINVAL; +static int call_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + return check_which(code->which) ? : check_pad(sd, code->pad) ? : + sd->ops->pad->enum_mbus_code(sd, cfg, code); +} - return 0; +static int call_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + return check_which(fse->which) ? : check_pad(sd, fse->pad) ? : + sd->ops->pad->enum_frame_size(sd, cfg, fse); } -static int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +static inline int check_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) { - if (edid->pad >= sd->entity.num_pads) - return -EINVAL; + return check_pad(sd, fi->pad); +} + +static int call_g_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_frame_interval(sd, fi) ? : + sd->ops->video->g_frame_interval(sd, fi); +} + +static int call_s_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_frame_interval *fi) +{ + return check_frame_interval(sd, fi) ? : + sd->ops->video->s_frame_interval(sd, fi); +} + +static int call_enum_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_interval_enum *fie) +{ + return check_which(fie->which) ? : check_pad(sd, fie->pad) ? : + sd->ops->pad->enum_frame_interval(sd, cfg, fie); +} +static inline int check_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_selection *sel) +{ + return check_which(sel->which) ? : check_pad(sd, sel->pad); +} + +static int call_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + return check_selection(sd, sel) ? : + sd->ops->pad->get_selection(sd, cfg, sel); +} + +static int call_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + return check_selection(sd, sel) ? : + sd->ops->pad->set_selection(sd, cfg, sel); +} + +static inline int check_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) +{ if (edid->blocks && edid->edid == NULL) return -EINVAL; - return 0; + return check_pad(sd, edid->pad); } -#endif + +static int call_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +{ + return check_edid(sd, edid) ? : sd->ops->pad->get_edid(sd, edid); +} + +static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) +{ + return check_edid(sd, edid) ? : sd->ops->pad->set_edid(sd, edid); +} + +static int call_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + return check_pad(sd, cap->pad) ? : + sd->ops->pad->dv_timings_cap(sd, cap); +} + +static int call_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *dvt) +{ + return check_pad(sd, dvt->pad) ? : + sd->ops->pad->enum_dv_timings(sd, dvt); +} + +static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = { + .get_fmt = call_get_fmt, + .set_fmt = call_set_fmt, + .enum_mbus_code = call_enum_mbus_code, + .enum_frame_size = call_enum_frame_size, + .enum_frame_interval = call_enum_frame_interval, + .get_selection = call_get_selection, + .set_selection = call_set_selection, + .get_edid = call_get_edid, + .set_edid = call_set_edid, + .dv_timings_cap = call_dv_timings_cap, + .enum_dv_timings = call_enum_dv_timings, +}; + +static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = { + .g_frame_interval = call_g_frame_interval, + .s_frame_interval = call_s_frame_interval, +}; + +const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = { + .pad = &v4l2_subdev_call_pad_wrappers, + .video = &v4l2_subdev_call_video_wrappers, +}; +EXPORT_SYMBOL(v4l2_subdev_call_wrappers); static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) { @@ -284,10 +403,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_FMT: { struct v4l2_subdev_format *format = arg; - rval = check_format(sd, format); - if (rval) - return rval; - memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->pad, format); @@ -296,10 +411,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; - rval = check_format(sd, format); - if (rval) - return rval; - memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); @@ -309,10 +420,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; - rval = check_crop(sd, crop); - if (rval) - return rval; - memset(crop->reserved, 0, sizeof(crop->reserved)); memset(&sel, 0, sizeof(sel)); sel.which = crop->which; @@ -332,10 +439,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_selection sel; memset(crop->reserved, 0, sizeof(crop->reserved)); - rval = check_crop(sd, crop); - if (rval) - return rval; - memset(&sel, 0, sizeof(sel)); sel.which = crop->which; sel.pad = crop->pad; @@ -353,13 +456,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_MBUS_CODE: { struct v4l2_subdev_mbus_code_enum *code = arg; - if (code->which != V4L2_SUBDEV_FORMAT_TRY && - code->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (code->pad >= sd->entity.num_pads) - return -EINVAL; - memset(code->reserved, 0, sizeof(code->reserved)); return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->pad, code); @@ -368,13 +464,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: { struct v4l2_subdev_frame_size_enum *fse = arg; - if (fse->which != V4L2_SUBDEV_FORMAT_TRY && - fse->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (fse->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fse->reserved, 0, sizeof(fse->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->pad, fse); @@ -383,9 +472,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; - if (fi->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, g_frame_interval, arg); } @@ -393,9 +479,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; - if (fi->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, s_frame_interval, arg); } @@ -403,13 +486,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval_enum *fie = arg; - if (fie->which != V4L2_SUBDEV_FORMAT_TRY && - fie->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (fie->pad >= sd->entity.num_pads) - return -EINVAL; - memset(fie->reserved, 0, sizeof(fie->reserved)); return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->pad, fie); @@ -418,10 +494,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_G_SELECTION: { struct v4l2_subdev_selection *sel = arg; - rval = check_selection(sd, sel); - if (rval) - return rval; - memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, get_selection, subdev_fh->pad, sel); @@ -430,10 +502,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_SELECTION: { struct v4l2_subdev_selection *sel = arg; - rval = check_selection(sd, sel); - if (rval) - return rval; - memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); @@ -442,38 +510,24 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_G_EDID: { struct v4l2_subdev_edid *edid = arg; - rval = check_edid(sd, edid); - if (rval) - return rval; - return v4l2_subdev_call(sd, pad, get_edid, edid); } case VIDIOC_S_EDID: { struct v4l2_subdev_edid *edid = arg; - rval = check_edid(sd, edid); - if (rval) - return rval; - return v4l2_subdev_call(sd, pad, set_edid, edid); } case VIDIOC_SUBDEV_DV_TIMINGS_CAP: { struct v4l2_dv_timings_cap *cap = arg; - if (cap->pad >= sd->entity.num_pads) - return -EINVAL; - return v4l2_subdev_call(sd, pad, dv_timings_cap, cap); } case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: { struct v4l2_enum_dv_timings *dvt = arg; - if (dvt->pad >= sd->entity.num_pads) - return -EINVAL; - return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt); } diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 7168311e8ecc..71f1f2f0da53 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1082,6 +1082,8 @@ void v4l2_subdev_free_pad_config(struct v4l2_subdev_pad_config *cfg); void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops); +extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers; + /** * v4l2_subdev_call - call an operation of a v4l2_subdev. * @@ -1103,6 +1105,10 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, __result = -ENODEV; \ else if (!(__sd->ops->o && __sd->ops->o->f)) \ __result = -ENOIOCTLCMD; \ + else if (v4l2_subdev_call_wrappers.o && \ + v4l2_subdev_call_wrappers.o->f) \ + __result = v4l2_subdev_call_wrappers.o->f( \ + __sd, ##args); \ else \ __result = __sd->ops->o->f(__sd, ##args); \ __result; \ -- cgit v1.2.3-59-g8ed1b From a4f4a763d8a01d0f461e3b8c4774ed45e9ded5f4 Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 20 May 2019 17:27:46 -0400 Subject: media: v4l2-subdev: Verify v4l2_subdev_call() pointer arguments Parameters passed to check helpers are now obtained by dereferencing unverified pointer arguments. Check validity of those pointers first. Signed-off-by: Janusz Krzysztofik Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 81b08f66da9b..4036d30450d3 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -139,6 +139,9 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) static inline int check_format(struct v4l2_subdev *sd, struct v4l2_subdev_format *format) { + if (!format) + return -EINVAL; + return check_which(format->which) ? : check_pad(sd, format->pad); } @@ -162,6 +165,9 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { + if (!code) + return -EINVAL; + return check_which(code->which) ? : check_pad(sd, code->pad) ? : sd->ops->pad->enum_mbus_code(sd, cfg, code); } @@ -170,6 +176,9 @@ static int call_enum_frame_size(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + if (!fse) + return -EINVAL; + return check_which(fse->which) ? : check_pad(sd, fse->pad) ? : sd->ops->pad->enum_frame_size(sd, cfg, fse); } @@ -177,6 +186,9 @@ static int call_enum_frame_size(struct v4l2_subdev *sd, static inline int check_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_frame_interval *fi) { + if (!fi) + return -EINVAL; + return check_pad(sd, fi->pad); } @@ -198,6 +210,9 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { + if (!fie) + return -EINVAL; + return check_which(fie->which) ? : check_pad(sd, fie->pad) ? : sd->ops->pad->enum_frame_interval(sd, cfg, fie); } @@ -205,6 +220,9 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd, static inline int check_selection(struct v4l2_subdev *sd, struct v4l2_subdev_selection *sel) { + if (!sel) + return -EINVAL; + return check_which(sel->which) ? : check_pad(sd, sel->pad); } @@ -227,6 +245,9 @@ static int call_set_selection(struct v4l2_subdev *sd, static inline int check_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) { + if (!edid) + return -EINVAL; + if (edid->blocks && edid->edid == NULL) return -EINVAL; @@ -246,6 +267,9 @@ static int call_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid) static int call_dv_timings_cap(struct v4l2_subdev *sd, struct v4l2_dv_timings_cap *cap) { + if (!cap) + return -EINVAL; + return check_pad(sd, cap->pad) ? : sd->ops->pad->dv_timings_cap(sd, cap); } @@ -253,6 +277,9 @@ static int call_dv_timings_cap(struct v4l2_subdev *sd, static int call_enum_dv_timings(struct v4l2_subdev *sd, struct v4l2_enum_dv_timings *dvt) { + if (!dvt) + return -EINVAL; + return check_pad(sd, dvt->pad) ? : sd->ops->pad->enum_dv_timings(sd, dvt); } -- cgit v1.2.3-59-g8ed1b From 374d62e7aa50f66c1a4316be9221df4d0f38addd Mon Sep 17 00:00:00 2001 From: Janusz Krzysztofik Date: Mon, 20 May 2019 17:27:47 -0400 Subject: media: v4l2-subdev: Verify v4l2_subdev_call() pad config argument Extend parameter checks performed by v4l2_subdev_call() with a check for a non-NULL pad config pointer if V4L2_SUBDEV_FORMAT_TRY format type is requested so drivers don't need to care. Signed-off-by: Janusz Krzysztofik Reviewed-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 4036d30450d3..21fb90d66bfc 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -136,20 +136,30 @@ static inline int check_pad(struct v4l2_subdev *sd, __u32 pad) return 0; } +static int check_cfg(__u32 which, struct v4l2_subdev_pad_config *cfg) +{ + if (which == V4L2_SUBDEV_FORMAT_TRY && !cfg) + return -EINVAL; + + return 0; +} + static inline int check_format(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { if (!format) return -EINVAL; - return check_which(format->which) ? : check_pad(sd, format->pad); + return check_which(format->which) ? : check_pad(sd, format->pad) ? : + check_cfg(format->which, cfg); } static int call_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { - return check_format(sd, format) ? : + return check_format(sd, cfg, format) ? : sd->ops->pad->get_fmt(sd, cfg, format); } @@ -157,7 +167,7 @@ static int call_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *format) { - return check_format(sd, format) ? : + return check_format(sd, cfg, format) ? : sd->ops->pad->set_fmt(sd, cfg, format); } @@ -169,6 +179,7 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd, return -EINVAL; return check_which(code->which) ? : check_pad(sd, code->pad) ? : + check_cfg(code->which, cfg) ? : sd->ops->pad->enum_mbus_code(sd, cfg, code); } @@ -180,6 +191,7 @@ static int call_enum_frame_size(struct v4l2_subdev *sd, return -EINVAL; return check_which(fse->which) ? : check_pad(sd, fse->pad) ? : + check_cfg(fse->which, cfg) ? : sd->ops->pad->enum_frame_size(sd, cfg, fse); } @@ -214,23 +226,26 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd, return -EINVAL; return check_which(fie->which) ? : check_pad(sd, fie->pad) ? : + check_cfg(fie->which, cfg) ? : sd->ops->pad->enum_frame_interval(sd, cfg, fie); } static inline int check_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { if (!sel) return -EINVAL; - return check_which(sel->which) ? : check_pad(sd, sel->pad); + return check_which(sel->which) ? : check_pad(sd, sel->pad) ? : + check_cfg(sel->which, cfg); } static int call_get_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { - return check_selection(sd, sel) ? : + return check_selection(sd, cfg, sel) ? : sd->ops->pad->get_selection(sd, cfg, sel); } @@ -238,7 +253,7 @@ static int call_set_selection(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) { - return check_selection(sd, sel) ? : + return check_selection(sd, cfg, sel) ? : sd->ops->pad->set_selection(sd, cfg, sel); } -- cgit v1.2.3-59-g8ed1b From 2161536516edcc0be31109eb1284939119e7ba6d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 17 Jun 2019 05:36:16 -0400 Subject: media: media/pci: set device_caps in struct video_device Instead of filling in the struct v4l2_capability device_caps field, fill in the struct video_device device_caps field. That way the V4L2 core knows what the capabilities of the video device are. But this only really works if all drivers use this, so convert all pci drivers in this patch. Tested with cx88-blackbird and ivtv PVR-350. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_fops.c | 9 +++++ drivers/media/common/saa7146/saa7146_video.c | 18 +++------- drivers/media/pci/bt8xx/bttv-driver.c | 50 ++++++++++++-------------- drivers/media/pci/cobalt/cobalt-v4l2.c | 14 ++++---- drivers/media/pci/cx18/cx18-ioctl.c | 5 +-- drivers/media/pci/cx18/cx18-streams.c | 1 + drivers/media/pci/cx23885/cx23885-417.c | 13 ++++--- drivers/media/pci/cx23885/cx23885-video.c | 22 +++++++----- drivers/media/pci/cx25821/cx25821-video.c | 14 ++++---- drivers/media/pci/cx88/cx88-blackbird.c | 4 +++ drivers/media/pci/cx88/cx88-video.c | 32 +++++++---------- drivers/media/pci/dt3155/dt3155.c | 5 ++- drivers/media/pci/ivtv/ivtv-cards.h | 3 +- drivers/media/pci/ivtv/ivtv-ioctl.c | 7 ---- drivers/media/pci/ivtv/ivtv-streams.c | 14 +++++--- drivers/media/pci/ivtv/ivtvfb.c | 10 ++++++ drivers/media/pci/meye/meye.c | 6 +--- drivers/media/pci/saa7134/saa7134-core.c | 15 ++++++++ drivers/media/pci/saa7134/saa7134-empress.c | 4 +++ drivers/media/pci/saa7134/saa7134-video.c | 46 +++++------------------- drivers/media/pci/saa7164/saa7164-encoder.c | 15 +++----- drivers/media/pci/saa7164/saa7164-vbi.c | 15 +++----- drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c | 5 ++- drivers/media/pci/solo6x10/solo6x10-v4l2.c | 5 ++- drivers/media/pci/sta2x11/sta2x11_vip.c | 6 ++-- drivers/media/pci/tw68/tw68-video.c | 8 ++--- drivers/media/pci/tw686x/tw686x-video.c | 5 ++- 27 files changed, 159 insertions(+), 192 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index be4f80a40214..aabb830e7468 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -608,6 +608,15 @@ int saa7146_register_device(struct video_device *vfd, struct saa7146_dev *dev, for (i = 0; i < dev->ext_vv_data->num_stds; i++) vfd->tvnorms |= dev->ext_vv_data->stds[i].id; strscpy(vfd->name, name, sizeof(vfd->name)); + vfd->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + vfd->device_caps |= dev->ext_vv_data->capabilities; + if (type == VFL_TYPE_GRABBER) + vfd->device_caps &= + ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); + else + vfd->device_caps &= + ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO); video_set_drvdata(vfd, dev); err = video_register_device(vfd, type, -1); diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index a0f0b5eef0bd..4c399a42e874 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -448,25 +448,15 @@ static int video_end(struct saa7146_fh *fh, struct file *file) static int vidioc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct saa7146_dev *dev = ((struct saa7146_fh *)fh)->dev; strscpy((char *)cap->driver, "saa7146 v4l2", sizeof(cap->driver)); strscpy((char *)cap->card, dev->ext->name, sizeof(cap->card)); sprintf((char *)cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->device_caps |= dev->ext_vv_data->capabilities; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps &= - ~(V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT); - else - cap->device_caps &= - ~(V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_AUDIO); + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= dev->ext_vv_data->capabilities; return 0; } diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 636e6a2549a9..612d1c0010c1 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -2453,7 +2453,6 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv, static int bttv_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); struct bttv_fh *fh = priv; struct bttv *btv = fh->btv; @@ -2464,17 +2463,17 @@ static int bttv_querycap(struct file *file, void *priv, strscpy(cap->card, btv->video_dev.name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(btv->c.pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_DEVICE_CAPS; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; if (no_overlay <= 0) cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; if (video_is_registered(&btv->vbi_dev)) cap->capabilities |= V4L2_CAP_VBI_CAPTURE; - if (video_is_registered(&btv->radio_dev)) + if (video_is_registered(&btv->radio_dev)) { cap->capabilities |= V4L2_CAP_RADIO; + if (btv->has_tea575x) + cap->capabilities |= V4L2_CAP_HW_FREQ_SEEK; + } /* * No need to lock here: those vars are initialized during board @@ -2484,27 +2483,6 @@ static int bttv_querycap(struct file *file, void *priv, cap->capabilities |= V4L2_CAP_RDS_CAPTURE; if (btv->tuner_type != TUNER_ABSENT) cap->capabilities |= V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_GRABBER) - cap->device_caps = cap->capabilities & - (V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VIDEO_OVERLAY | - V4L2_CAP_TUNER); - else if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps = cap->capabilities & - (V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_TUNER); - else { - cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - if (btv->has_saa6588) - cap->device_caps |= V4L2_CAP_READWRITE | - V4L2_CAP_RDS_CAPTURE; - if (btv->has_tea575x) - cap->device_caps |= V4L2_CAP_HW_FREQ_SEEK; - } return 0; } @@ -3939,6 +3917,12 @@ static int bttv_register_video(struct bttv *btv) /* video */ vdev_init(btv, &btv->video_dev, &bttv_video_template, "video"); + btv->video_dev.device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (btv->tuner_type != TUNER_ABSENT) + btv->video_dev.device_caps |= V4L2_CAP_TUNER; + if (no_overlay <= 0) + btv->video_dev.device_caps |= V4L2_CAP_VIDEO_OVERLAY; if (video_register_device(&btv->video_dev, VFL_TYPE_GRABBER, video_nr[btv->c.nr]) < 0) @@ -3953,6 +3937,10 @@ static int bttv_register_video(struct bttv *btv) /* vbi */ vdev_init(btv, &btv->vbi_dev, &bttv_video_template, "vbi"); + btv->vbi_dev.device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_TUNER; + if (btv->tuner_type != TUNER_ABSENT) + btv->vbi_dev.device_caps |= V4L2_CAP_TUNER; if (video_register_device(&btv->vbi_dev, VFL_TYPE_VBI, vbi_nr[btv->c.nr]) < 0) @@ -3964,6 +3952,12 @@ static int bttv_register_video(struct bttv *btv) return 0; /* radio */ vdev_init(btv, &btv->radio_dev, &radio_template, "radio"); + btv->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + if (btv->has_saa6588) + btv->radio_dev.device_caps |= V4L2_CAP_READWRITE | + V4L2_CAP_RDS_CAPTURE; + if (btv->has_tea575x) + btv->radio_dev.device_caps |= V4L2_CAP_HW_FREQ_SEEK; btv->radio_dev.ctrl_handler = &btv->radio_ctrl_handler; if (video_register_device(&btv->radio_dev, VFL_TYPE_RADIO, radio_nr[btv->c.nr]) < 0) diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index f9fa3a7c3b8f..39dabd4da60f 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -483,13 +483,8 @@ static int cobalt_querycap(struct file *file, void *priv_fh, strscpy(vcap->card, "cobalt", sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCIe:%s", pci_name(cobalt->pci_dev)); - vcap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (s->is_output) - vcap->device_caps |= V4L2_CAP_VIDEO_OUTPUT; - else - vcap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS | - V4L2_CAP_VIDEO_CAPTURE; + vcap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; if (cobalt->have_hsma_tx) vcap->capabilities |= V4L2_CAP_VIDEO_OUTPUT; return 0; @@ -1274,6 +1269,11 @@ static int cobalt_node_register(struct cobalt *cobalt, int node) q->lock = &s->lock; q->dev = &cobalt->pci_dev->dev; vdev->queue = q; + vdev->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (s->is_output) + vdev->device_caps |= V4L2_CAP_VIDEO_OUTPUT; + else + vdev->device_caps |= V4L2_CAP_VIDEO_CAPTURE; video_set_drvdata(vdev, s); ret = vb2_queue_init(q); diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index 9f5972f6d3a6..d9ffc9c359ca 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -385,16 +385,13 @@ static int cx18_querycap(struct file *file, void *fh, struct v4l2_capability *vcap) { struct cx18_open_id *id = fh2id(fh); - struct cx18_stream *s = video_drvdata(file); struct cx18 *cx = id->cx; strscpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); strscpy(vcap->card, cx->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(cx->pci_dev)); - vcap->capabilities = cx->v4l2_cap; /* capabilities */ - vcap->device_caps = s->v4l2_dev_caps; /* device capabilities */ - vcap->capabilities |= V4L2_CAP_DEVICE_CAPS; + vcap->capabilities = cx->v4l2_cap | V4L2_CAP_DEVICE_CAPS; return 0; } diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 9805e50c2477..b79718519b9b 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -411,6 +411,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type) return 0; num = s->video_dev.num; + s->video_dev.device_caps = s->v4l2_dev_caps; /* device capabilities */ /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 8aa5f9b1498a..82f96a4091ac 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -1324,12 +1324,11 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, cx23885_boards[tsport->dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_AUDIO | V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1542,6 +1541,10 @@ int cx23885_417_register(struct cx23885_dev *dev) video_set_drvdata(dev->v4l_device, dev); dev->v4l_device->lock = &dev->lock; dev->v4l_device->queue = q; + dev->v4l_device->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (dev->tuner_type != TUNER_ABSENT) + dev->v4l_device->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 0c59ecccc38a..b254473db9a3 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -627,21 +627,17 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx23885_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); strscpy(cap->driver, "cx23885", sizeof(cap->driver)); strscpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO; + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; if (dev->tuner_type != TUNER_ABSENT) - cap->device_caps |= V4L2_CAP_TUNER; - if (vdev->vfl_type == VFL_TYPE_VBI) - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - else - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= V4L2_CAP_TUNER; return 0; } @@ -1306,6 +1302,10 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); dev->video_dev->queue = &dev->vb2_vidq; + dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->video_dev->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1320,6 +1320,10 @@ int cx23885_video_register(struct cx23885_dev *dev) dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); dev->vbi_dev->queue = &dev->vb2_vbiq; + dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT) + dev->vbi_dev->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 1bb5dfc74e27..de7641170478 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -426,18 +426,13 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv, { struct cx25821_channel *chan = video_drvdata(file); struct cx25821_dev *dev = chan->dev; - const u32 cap_input = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - const u32 cap_output = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE; strscpy(cap->driver, "cx25821", sizeof(cap->driver)); strscpy(cap->card, cx25821_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - if (chan->id >= VID_CHANNEL_NUM) - cap->device_caps = cap_output; - else - cap->device_caps = cap_input; - cap->capabilities = cap_input | cap_output | V4L2_CAP_DEVICE_CAPS; + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -624,6 +619,8 @@ static const struct video_device cx25821_video_device = { .minor = -1, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX25821_NORMS, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static const struct v4l2_file_operations video_out_fops = { @@ -657,6 +654,7 @@ static const struct video_device cx25821_video_out_device = { .minor = -1, .ioctl_ops = &video_out_ioctl_ops, .tvnorms = CX25821_NORMS, + .device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE, }; void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num) diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 64dd8b6cf808..200d68827073 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1136,6 +1136,10 @@ static int blackbird_register_video(struct cx8802_dev *dev) dev->mpeg_dev.ctrl_handler = &dev->cxhdl.hdl; video_set_drvdata(&dev->mpeg_dev, dev); dev->mpeg_dev.queue = &dev->vb2_mpegq; + dev->mpeg_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->core->board.tuner_type != UNSET) + dev->mpeg_dev.device_caps |= V4L2_CAP_TUNER; err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1); if (err < 0) { pr_info("can't register mpeg device\n"); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 5256ad7ead38..e59a74514c7c 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -800,27 +800,12 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, int cx88_querycap(struct file *file, struct cx88_core *core, struct v4l2_capability *cap) { - struct video_device *vdev = video_devdata(file); - strscpy(cap->card, core->board.name, sizeof(cap->card)); - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; if (core->board.tuner_type != UNSET) - cap->device_caps |= V4L2_CAP_TUNER; - switch (vdev->vfl_type) { - case VFL_TYPE_RADIO: - cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; - break; - case VFL_TYPE_GRABBER: - cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - cap->device_caps |= V4L2_CAP_VBI_CAPTURE; - break; - default: - return -EINVAL; - } - cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; + cap->capabilities |= V4L2_CAP_TUNER; if (core->board.radio.type == CX88_RADIO) cap->capabilities |= V4L2_CAP_RADIO; return 0; @@ -1473,6 +1458,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev, video_set_drvdata(&dev->video_dev, dev); dev->video_dev.ctrl_handler = &core->video_hdl; dev->video_dev.queue = &dev->vb2_vidq; + dev->video_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (core->board.tuner_type != UNSET) + dev->video_dev.device_caps |= V4L2_CAP_TUNER; err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { @@ -1486,6 +1475,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev, &cx8800_vbi_template, "vbi"); video_set_drvdata(&dev->vbi_dev, dev); dev->vbi_dev.queue = &dev->vb2_vbiq; + dev->vbi_dev.device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (core->board.tuner_type != UNSET) + dev->vbi_dev.device_caps |= V4L2_CAP_TUNER; err = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { @@ -1500,6 +1493,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, &cx8800_radio_template, "radio"); video_set_drvdata(&dev->radio_dev, dev); dev->radio_dev.ctrl_handler = &core->audio_hdl; + dev->radio_dev.device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; err = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c index d6d29e61aae9..b4cdda50e742 100644 --- a/drivers/media/pci/dt3155/dt3155.c +++ b/drivers/media/pci/dt3155/dt3155.c @@ -297,9 +297,6 @@ static int dt3155_querycap(struct file *filp, void *p, strscpy(cap->driver, DT3155_NAME, sizeof(cap->driver)); strscpy(cap->card, DT3155_NAME " frame grabber", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -490,6 +487,8 @@ static const struct video_device dt3155_vdev = { .minor = -1, .release = video_device_release_empty, .tvnorms = V4L2_STD_ALL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE, }; static int dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id) diff --git a/drivers/media/pci/ivtv/ivtv-cards.h b/drivers/media/pci/ivtv/ivtv-cards.h index 965def0cbfaa..f3e2c5634962 100644 --- a/drivers/media/pci/ivtv/ivtv-cards.h +++ b/drivers/media/pci/ivtv/ivtv-cards.h @@ -156,8 +156,7 @@ #define IVTV_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE | \ V4L2_CAP_SLICED_VBI_CAPTURE) -#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | \ - V4L2_CAP_SLICED_VBI_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_OVERLAY) +#define IVTV_CAP_DECODER (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_SLICED_VBI_OUTPUT) struct ivtv_card_video_input { u8 video_type; /* video input type */ diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index d1e358a2273e..5595f6a274e7 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -734,18 +734,11 @@ static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vc { struct ivtv_open_id *id = fh2id(file->private_data); struct ivtv *itv = id->itv; - struct ivtv_stream *s = &itv->streams[id->type]; strscpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver)); strscpy(vcap->card, itv->card_name, sizeof(vcap->card)); snprintf(vcap->bus_info, sizeof(vcap->bus_info), "PCI:%s", pci_name(itv->pdev)); vcap->capabilities = itv->v4l2_cap | V4L2_CAP_DEVICE_CAPS; - vcap->device_caps = s->caps; - if ((s->caps & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) && - !itv->osd_video_pbase) { - vcap->capabilities &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - vcap->device_caps &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - } return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c index a641f20e3f86..f7de9118f609 100644 --- a/drivers/media/pci/ivtv/ivtv-streams.c +++ b/drivers/media/pci/ivtv/ivtv-streams.c @@ -139,8 +139,7 @@ static struct { "decoder MPG", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_MPG_OFFSET, PCI_DMA_TODEVICE, 0, - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_OUTPUT_OVERLAY, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops }, { /* IVTV_DEC_STREAM_TYPE_VBI */ @@ -161,8 +160,7 @@ static struct { "decoder YUV", VFL_TYPE_GRABBER, IVTV_V4L2_DEC_YUV_OFFSET, PCI_DMA_TODEVICE, 0, - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | - V4L2_CAP_VIDEO_OUTPUT_OVERLAY, + V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_AUDIO | V4L2_CAP_READWRITE, &ivtv_v4l2_dec_fops } }; @@ -301,6 +299,14 @@ static int ivtv_reg_dev(struct ivtv *itv, int type) if (s_mpg->vdev.v4l2_dev) num = s_mpg->vdev.num + ivtv_stream_info[type].num_offset; } + s->vdev.device_caps = s->caps; + if (itv->osd_video_pbase) { + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + } video_set_drvdata(&s->vdev, s); /* Register device. First try the desired minor, then any free one. */ diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 66be490ec563..800b3654cac5 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -1220,6 +1220,11 @@ static int ivtvfb_init_card(struct ivtv *itv) /* Allocate DMA */ ivtv_udma_alloc(itv); + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps |= + V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->v4l2_cap |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; return 0; } @@ -1246,6 +1251,11 @@ static int ivtvfb_callback_cleanup(struct device *dev, void *p) struct osd_info *oi = itv->osd_info; if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { + itv->streams[IVTV_DEC_STREAM_TYPE_YUV].vdev.device_caps &= + ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->streams[IVTV_DEC_STREAM_TYPE_MPG].vdev.device_caps &= + ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + itv->v4l2_cap &= ~V4L2_CAP_VIDEO_OUTPUT_OVERLAY; if (unregister_framebuffer(&itv->osd_info->ivtvfb_info)) { IVTVFB_WARN("Framebuffer %d is in use, cannot unload\n", itv->instance); diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index bbe91b0f2565..8218810c899e 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1013,11 +1013,6 @@ static int vidioc_querycap(struct file *file, void *fh, strscpy(cap->driver, "meye", sizeof(cap->driver)); strscpy(cap->card, "meye", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev)); - - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -1529,6 +1524,7 @@ static const struct video_device meye_template = { .fops = &meye_fops, .ioctl_ops = &meye_ioctl_ops, .release = video_device_release_empty, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING, }; static const struct v4l2_ctrl_ops meye_ctrl_ops = { diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index fa9a0ead46d5..2d582c02adbf 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -1206,6 +1206,14 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->video_dev->ctrl_handler = &dev->ctrl_handler; dev->video_dev->lock = &dev->lock; dev->video_dev->queue = &dev->video_vbq; + dev->video_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + dev->video_dev->device_caps |= V4L2_CAP_TUNER; + + if (saa7134_no_overlay <= 0) + dev->video_dev->device_caps |= V4L2_CAP_VIDEO_OVERLAY; + err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1220,6 +1228,10 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->vbi_dev->ctrl_handler = &dev->ctrl_handler; dev->vbi_dev->lock = &dev->lock; dev->vbi_dev->queue = &dev->vbi_vbq; + dev->vbi_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VBI_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + dev->vbi_dev->device_caps |= V4L2_CAP_TUNER; err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[dev->nr]); @@ -1232,6 +1244,9 @@ static int saa7134_initdev(struct pci_dev *pci_dev, dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler; dev->radio_dev->lock = &dev->lock; + dev->radio_dev->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + if (dev->has_rds) + dev->radio_dev->device_caps |= V4L2_CAP_RDS_CAPTURE; err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[dev->nr]); if (err < 0) diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 17eafaa5bf02..1a41a56afec6 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -287,6 +287,10 @@ static int empress_init(struct saa7134_dev *dev) if (err) return err; dev->empress_dev->queue = q; + dev->empress_dev->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_VIDEO_CAPTURE; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + dev->empress_dev->device_caps |= V4L2_CAP_TUNER; video_set_drvdata(dev->empress_dev, dev); err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 89c1271476c7..606df51bb636 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -1489,50 +1489,20 @@ int saa7134_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct saa7134_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - u32 radio_caps, video_caps, vbi_caps; - - unsigned int tuner_type = dev->tuner_type; strscpy(cap->driver, "saa7134", sizeof(cap->driver)); strscpy(cap->card, saa7134_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if ((tuner_type != TUNER_ABSENT) && (tuner_type != UNSET)) - cap->device_caps |= V4L2_CAP_TUNER; - - radio_caps = V4L2_CAP_RADIO; + cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | + V4L2_CAP_RADIO | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; + if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type != UNSET) + cap->capabilities |= V4L2_CAP_TUNER; if (dev->has_rds) - radio_caps |= V4L2_CAP_RDS_CAPTURE; - - video_caps = V4L2_CAP_VIDEO_CAPTURE; - if (saa7134_no_overlay <= 0 && !is_empress(file)) - video_caps |= V4L2_CAP_VIDEO_OVERLAY; - - vbi_caps = V4L2_CAP_VBI_CAPTURE; - - switch (vdev->vfl_type) { - case VFL_TYPE_RADIO: - cap->device_caps |= radio_caps; - break; - case VFL_TYPE_GRABBER: - cap->device_caps |= video_caps; - break; - case VFL_TYPE_VBI: - cap->device_caps |= vbi_caps; - break; - default: - return -EINVAL; - } - cap->capabilities = radio_caps | video_caps | vbi_caps | - cap->device_caps | V4L2_CAP_DEVICE_CAPS; - if (vdev->vfl_type == VFL_TYPE_RADIO) { - cap->device_caps &= ~V4L2_CAP_STREAMING; - if (!dev->has_rds) - cap->device_caps &= ~V4L2_CAP_READWRITE; - } + cap->capabilities |= V4L2_CAP_RDS_CAPTURE; + if (saa7134_no_overlay <= 0) + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; return 0; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index dcfabad8b284..43fdaa2d32bd 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -491,16 +491,9 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, saa7164_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_TUNER; - - cap->capabilities = cap->device_caps | - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_DEVICE_CAPS; - + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -973,6 +966,8 @@ static struct video_device saa7164_mpeg_template = { .ioctl_ops = &mpeg_ioctl_ops, .minor = -1, .tvnorms = SAA7164_NORMS, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER, }; static struct video_device *saa7164_encoder_alloc( diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index 154a04d17ce5..49d61a64c8cb 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -202,16 +202,9 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, saa7164_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - - cap->device_caps = - V4L2_CAP_VBI_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_TUNER; - - cap->capabilities = cap->device_caps | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_DEVICE_CAPS; - + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_DEVICE_CAPS; return 0; } @@ -675,6 +668,8 @@ static struct video_device saa7164_vbi_template = { .ioctl_ops = &vbi_ioctl_ops, .minor = -1, .tvnorms = SAA7164_NORMS, + .device_caps = V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_TUNER, }; static struct video_device *saa7164_vbi_alloc( diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c index 73698cc26dd5..609100a46ff8 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c @@ -771,9 +771,6 @@ static int solo_enc_querycap(struct file *file, void *priv, solo_enc->ch); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(solo_dev->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1191,6 +1188,8 @@ static const struct video_device solo_enc_template = { .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static const struct v4l2_ctrl_ops solo_ctrl_ops = { diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index 1ce431af8fc6..a968f75920b5 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -378,9 +378,6 @@ static int solo_querycap(struct file *file, void *priv, strscpy(cap->card, "Softlogic 6x10", sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(solo_dev->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -628,6 +625,8 @@ static const struct video_device solo_v4l2_template = { .minor = -1, .release = video_device_release, .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; static const struct v4l2_ctrl_ops solo_ctrl_ops = { diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c index 9de5b2a35519..e52e29814378 100644 --- a/drivers/media/pci/sta2x11/sta2x11_vip.c +++ b/drivers/media/pci/sta2x11/sta2x11_vip.c @@ -407,10 +407,6 @@ static int vidioc_querycap(struct file *file, void *priv, strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(vip->pdev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; } @@ -759,6 +755,8 @@ static const struct video_device video_dev_template = { .fops = &vip_fops, .ioctl_ops = &vip_ioctl_ops, .tvnorms = V4L2_STD_ALL, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /** diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index 5b469cf578f5..8e0952d65ad4 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -729,12 +729,6 @@ static int tw68_querycap(struct file *file, void *priv, strscpy(cap->card, "Techwell Capture Card", sizeof(cap->card)); sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->device_caps = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -913,6 +907,8 @@ static const struct video_device tw68_video_template = { .ioctl_ops = &video_ioctl_ops, .release = video_device_release_empty, .tvnorms = TW68_NORMS, + .device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING, }; /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c index 377fb1e453fa..9be8c6e4fb69 100644 --- a/drivers/media/pci/tw686x/tw686x-video.c +++ b/drivers/media/pci/tw686x/tw686x-video.c @@ -765,9 +765,6 @@ static int tw686x_querycap(struct file *file, void *priv, strscpy(cap->card, dev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", pci_name(dev->pci_dev)); - cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1280,6 +1277,8 @@ int tw686x_video_init(struct tw686x_dev *dev) vdev->minor = -1; vdev->lock = &vc->vb_mutex; vdev->ctrl_handler = &vc->ctrl_handler; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; vc->device = vdev; video_set_drvdata(vdev, vc); -- cgit v1.2.3-59-g8ed1b From 77ae46e11df5c96bb4582633851f838f5d954df4 Mon Sep 17 00:00:00 2001 From: André Almeida Date: Mon, 17 Jun 2019 12:28:02 -0400 Subject: media: vimc: cap: check v4l2_fill_pixfmt return value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v4l2_fill_pixfmt() returns -EINVAL if the pixelformat used as parameter is invalid or if the user is trying to use a multiplanar format with the singleplanar API. Currently, the vimc_cap_try_fmt_vid_cap() returns such value, but vimc_cap_s_fmt_vid_cap() is ignoring it. Fix that and returns an error value if vimc_cap_try_fmt_vid_cap() has failed. Signed-off-by: André Almeida Suggested-by: Helen Koike Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vimc/vimc-capture.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index 946dc0908566..664855708fdf 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -142,12 +142,15 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct vimc_cap_device *vcap = video_drvdata(file); + int ret; /* Do not change the format while stream is on */ if (vb2_is_busy(&vcap->queue)) return -EBUSY; - vimc_cap_try_fmt_vid_cap(file, priv, f); + ret = vimc_cap_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; dev_dbg(vcap->dev, "%s: format update: " "old:%dx%d (0x%x, %d, %d, %d, %d) " -- cgit v1.2.3-59-g8ed1b From 782dc2d58923a4e180c48733b6c70d8d73d972cd Mon Sep 17 00:00:00 2001 From: Puranjay Mohan Date: Tue, 18 Jun 2019 00:19:37 -0400 Subject: media: pci: cx88: Change the type of 'missed' to u64 Callers of hrtimer_forward_now() should save the return value in u64. change type of missed from unsigned long to u64. Signed-off-by: Puranjay Mohan Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: type changed, so %ld -> %llu in printk] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-input.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 27f690b54e0c..589f52d961eb 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -167,14 +167,14 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) static enum hrtimer_restart cx88_ir_work(struct hrtimer *timer) { - unsigned long missed; + u64 missed; struct cx88_IR *ir = container_of(timer, struct cx88_IR, timer); cx88_ir_handle_key(ir); missed = hrtimer_forward_now(&ir->timer, ktime_set(0, ir->polling * 1000000)); if (missed > 1) - ir_dprintk("Missed ticks %ld\n", missed - 1); + ir_dprintk("Missed ticks %llu\n", missed - 1); return HRTIMER_RESTART; } -- cgit v1.2.3-59-g8ed1b From ba74edc6def24325af256eea8e8790ce6cdb838d Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Tue, 18 Jun 2019 19:17:31 -0400 Subject: media: v4l2-ctrl: Move compound control initialization Rework std_init adding an explicit initialization for compound controls. While here, make sure the control is initialized to zero, before providing default values for all its fields. Reviewed-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 37 +++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 2d7525e2d9eb..29b86d7448dc 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1494,10 +1494,13 @@ static bool std_equal(const struct v4l2_ctrl *ctrl, u32 idx, } } -static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, - union v4l2_ctrl_ptr ptr) +static void std_init_compound(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) { struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; + void *p = ptr.p + idx * ctrl->elem_size; + + memset(p, 0, ctrl->elem_size); /* * The cast is needed to get rid of a gcc warning complaining that @@ -1505,6 +1508,22 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, * v4l2_ctrl_type enum. */ switch ((u32)ctrl->type) { + case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: + p_mpeg2_slice_params = p; + /* 4:2:0 */ + p_mpeg2_slice_params->sequence.chroma_format = 1; + /* interlaced top field */ + p_mpeg2_slice_params->picture.picture_structure = 1; + p_mpeg2_slice_params->picture.picture_coding_type = + V4L2_MPEG2_PICTURE_CODING_TYPE_I; + break; + } +} + +static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, + union v4l2_ctrl_ptr ptr) +{ + switch (ctrl->type) { case V4L2_CTRL_TYPE_STRING: idx *= ctrl->elem_size; memset(ptr.p_char + idx, ' ', ctrl->minimum); @@ -1533,20 +1552,8 @@ static void std_init(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_U32: ptr.p_u32[idx] = ctrl->default_value; break; - case V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS: - p_mpeg2_slice_params = ptr.p; - /* 4:2:0 */ - p_mpeg2_slice_params->sequence.chroma_format = 1; - /* 8 bits */ - p_mpeg2_slice_params->picture.intra_dc_precision = 0; - /* interlaced top field */ - p_mpeg2_slice_params->picture.picture_structure = 1; - p_mpeg2_slice_params->picture.picture_coding_type = - V4L2_MPEG2_PICTURE_CODING_TYPE_I; - break; default: - idx *= ctrl->elem_size; - memset(ptr.p + idx, 0, ctrl->elem_size); + std_init_compound(ctrl, idx, ptr); break; } } -- cgit v1.2.3-59-g8ed1b From 021d2ad0f6955d41b19fdb3190f5c351930c9a2d Mon Sep 17 00:00:00 2001 From: Eugen Hristev Date: Wed, 19 Jun 2019 03:24:41 -0400 Subject: media: atmel: atmel-isc: fix i386 build error Changed module parameters to static. Reported-by: kbuild test robot Signed-off-by: Eugen Hristev Acked-by: Sakari Ailus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc-base.c | 4 ++-- drivers/media/platform/atmel/atmel-isc.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/platform/atmel/atmel-isc-base.c b/drivers/media/platform/atmel/atmel-isc-base.c index eb1f5d4c207e..c1c776b348a9 100644 --- a/drivers/media/platform/atmel/atmel-isc-base.c +++ b/drivers/media/platform/atmel/atmel-isc-base.c @@ -35,11 +35,11 @@ #include "atmel-isc-regs.h" #include "atmel-isc.h" -unsigned int debug; +static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); -unsigned int sensor_preferred = 1; +static unsigned int sensor_preferred = 1; module_param(sensor_preferred, uint, 0644); MODULE_PARM_DESC(sensor_preferred, "Sensor is preferred to output the specified format (1-on 0-off), default 1"); diff --git a/drivers/media/platform/atmel/atmel-isc.h b/drivers/media/platform/atmel/atmel-isc.h index f5f5932ac1e2..bfaed2fad2b5 100644 --- a/drivers/media/platform/atmel/atmel-isc.h +++ b/drivers/media/platform/atmel/atmel-isc.h @@ -230,10 +230,6 @@ struct isc_device { #define ATMEL_ISC_NAME "atmel-isc" -/* module parameters */ -extern unsigned int debug; -extern unsigned int sensor_preferred; - extern struct isc_format formats_list[]; extern const struct isc_format controller_formats[]; extern const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES]; -- cgit v1.2.3-59-g8ed1b From 07d89227a983df957a6a7c56f7c040cde9ac571f Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 19 Jun 2019 05:21:33 -0400 Subject: media: v4l2: Test type instead of cfg->type in v4l2_ctrl_new_custom() cfg->type can be overridden by v4l2_ctrl_fill() and the new value is stored in the local type var. Fix the tests to use this local var. Fixes: 0996517cf8ea ("V4L/DVB: v4l2: Add new control handling framework") Cc: Signed-off-by: Boris Brezillon [hverkuil-cisco@xs4all.nl: change to !qmenu and !qmenu_int (checkpatch)] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 29b86d7448dc..371537dd8cd3 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -2464,16 +2464,15 @@ struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl, v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step, &def, &flags); - is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU || - cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU); + is_menu = (type == V4L2_CTRL_TYPE_MENU || + type == V4L2_CTRL_TYPE_INTEGER_MENU); if (is_menu) WARN_ON(step); else WARN_ON(cfg->menu_skip_mask); - if (cfg->type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) + if (type == V4L2_CTRL_TYPE_MENU && !qmenu) { qmenu = v4l2_ctrl_get_menu(cfg->id); - else if (cfg->type == V4L2_CTRL_TYPE_INTEGER_MENU && - qmenu_int == NULL) { + } else if (type == V4L2_CTRL_TYPE_INTEGER_MENU && !qmenu_int) { handler_set_err(hdl, -EINVAL); return NULL; } -- cgit v1.2.3-59-g8ed1b From 6bc5a4a1927556ff9adce1aa95ea408c95453225 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Jun 2019 07:43:41 -0400 Subject: media: hdpvr: fix locking and a missing msleep This driver has three locking issues: - The wait_event_interruptible() condition calls hdpvr_get_next_buffer(dev) which uses a mutex, which is not allowed. Rewrite with list_empty_careful() that doesn't need locking. - In hdpvr_read() the call to hdpvr_stop_streaming() didn't lock io_mutex, but it should have since stop_streaming expects that. - In hdpvr_device_release() io_mutex was locked when calling flush_work(), but there it shouldn't take that mutex since the work done by flush_work() also wants to lock that mutex. There are also two other changes (suggested by Keith): - msecs_to_jiffies(4000); (a NOP) should have been msleep(4000). - Change v4l2_dbg to v4l2_info to always log if streaming had to be restarted. Reported-by: Keith Pyle Suggested-by: Keith Pyle Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 3786ddcc0d18..5b3e67b80627 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -435,7 +435,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, /* wait for the first buffer */ if (!(file->f_flags & O_NONBLOCK)) { if (wait_event_interruptible(dev->wait_data, - hdpvr_get_next_buffer(dev))) + !list_empty_careful(&dev->rec_buff_list))) return -ERESTARTSYS; } @@ -461,10 +461,17 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, goto err; } if (!err) { - v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, - "timeout: restart streaming\n"); + v4l2_info(&dev->v4l2_dev, + "timeout: restart streaming\n"); + mutex_lock(&dev->io_mutex); hdpvr_stop_streaming(dev); - msecs_to_jiffies(4000); + mutex_unlock(&dev->io_mutex); + /* + * The FW needs about 4 seconds after streaming + * stopped before it is ready to restart + * streaming. + */ + msleep(4000); err = hdpvr_start_streaming(dev); if (err) { ret = err; @@ -1124,9 +1131,7 @@ static void hdpvr_device_release(struct video_device *vdev) struct hdpvr_device *dev = video_get_drvdata(vdev); hdpvr_delete(dev); - mutex_lock(&dev->io_mutex); flush_work(&dev->worker); - mutex_unlock(&dev->io_mutex); v4l2_device_unregister(&dev->v4l2_dev); v4l2_ctrl_handler_free(&dev->hdl); -- cgit v1.2.3-59-g8ed1b From 3d51dc03a4eeb78eac676a559ee984f4f1bb455c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Jun 2019 04:39:00 -0400 Subject: media: cec-notifier: rename variables, check kstrdup and n->conn_name dev -> hdmi_dev conn -> conn_name Check if n->conn_name is not NULL before calling strcmp. Check the result of kstrdup, and clean up on error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-notifier.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index 9598c7778871..f72b19c351dd 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -21,8 +21,8 @@ struct cec_notifier { struct mutex lock; struct list_head head; struct kref kref; - struct device *dev; - const char *conn; + struct device *hdmi_dev; + const char *conn_name; struct cec_adapter *cec_adap; void (*callback)(struct cec_adapter *adap, u16 pa); @@ -32,14 +32,16 @@ struct cec_notifier { static LIST_HEAD(cec_notifiers); static DEFINE_MUTEX(cec_notifiers_lock); -struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) +struct cec_notifier * +cec_notifier_get_conn(struct device *hdmi_dev, const char *conn_name) { struct cec_notifier *n; mutex_lock(&cec_notifiers_lock); list_for_each_entry(n, &cec_notifiers, head) { - if (n->dev == dev && - (!conn || !strcmp(n->conn, conn))) { + if (n->hdmi_dev == hdmi_dev && + (!conn_name || + (n->conn_name && !strcmp(n->conn_name, conn_name)))) { kref_get(&n->kref); mutex_unlock(&cec_notifiers_lock); return n; @@ -48,10 +50,17 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) n = kzalloc(sizeof(*n), GFP_KERNEL); if (!n) goto unlock; - n->dev = dev; - if (conn) - n->conn = kstrdup(conn, GFP_KERNEL); + n->hdmi_dev = hdmi_dev; + if (conn_name) { + n->conn_name = kstrdup(conn_name, GFP_KERNEL); + if (!n->conn_name) { + kfree(n); + n = NULL; + goto unlock; + } + } n->phys_addr = CEC_PHYS_ADDR_INVALID; + mutex_init(&n->lock); kref_init(&n->kref); list_add_tail(&n->head, &cec_notifiers); @@ -67,7 +76,7 @@ static void cec_notifier_release(struct kref *kref) container_of(kref, struct cec_notifier, kref); list_del(&n->head); - kfree(n->conn); + kfree(n->conn_name); kfree(n); } -- cgit v1.2.3-59-g8ed1b From 32a847f9fa40ec1b03ead2c514862764983ff9ca Mon Sep 17 00:00:00 2001 From: Dariusz Marcinkiewicz Date: Thu, 20 Jun 2019 05:17:18 -0400 Subject: media: cec: add struct cec_connector_info support Define struct cec_connector_info in media/cec.h and define CEC_CAP_CONNECTOR_INFO. In a later patch this will be moved to uapi/linux/cec.h. The CEC_CAP_CONNECTOR_INFO capability can be set by drivers, but cec_allocate_adapter() will remove it again until the public API for this can be enabled once all drm drivers wire this up correctly. Also add the cec_fill_conn_info_from_drm and cec_s_conn_info functions, which are needed by drm drivers to fill in the cec_connector info based on a drm_connector. The cec_notifier_(un)register and cec_register_cec_notifier prototypes were moved from cec-notifier.h to cec.h since cec.h no longer includes cec-notifier.h. These headers included each other before, which caused various problems. Due to these changes the seco-cec driver was changed as well: it should include cec-notifier.h, not cec.h. Signed-off-by: Dariusz Marcinkiewicz Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 29 +++++++++ drivers/media/cec/cec-core.c | 5 ++ drivers/media/platform/seco-cec/seco-cec.c | 2 +- include/media/cec-notifier.h | 39 ------------ include/media/cec.h | 98 +++++++++++++++++++++++++++++- 5 files changed, 132 insertions(+), 41 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index ac3683a7b2ab..451c61bde4d4 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -16,7 +16,10 @@ #include #include +#include +#include #include +#include #include "cec-priv.h" @@ -75,6 +78,16 @@ u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, } EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr); +void cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info, + const struct drm_connector *connector) +{ + memset(conn_info, 0, sizeof(*conn_info)); + conn_info->type = CEC_CONNECTOR_TYPE_DRM; + conn_info->drm.card_no = connector->dev->primary->index; + conn_info->drm.connector_id = connector->base.id; +} +EXPORT_SYMBOL_GPL(cec_fill_conn_info_from_drm); + /* * Queue a new event for this filehandle. If ts == 0, then set it * to the current time. @@ -1598,6 +1611,22 @@ void cec_s_phys_addr_from_edid(struct cec_adapter *adap, } EXPORT_SYMBOL_GPL(cec_s_phys_addr_from_edid); +void cec_s_conn_info(struct cec_adapter *adap, + const struct cec_connector_info *conn_info) +{ + if (!(adap->capabilities & CEC_CAP_CONNECTOR_INFO)) + return; + + mutex_lock(&adap->lock); + if (conn_info) + adap->conn_info = *conn_info; + else + memset(&adap->conn_info, 0, sizeof(adap->conn_info)); + cec_post_state_event(adap); + mutex_unlock(&adap->lock); +} +EXPORT_SYMBOL_GPL(cec_s_conn_info); + /* * Called from either the ioctl or a driver to set the logical addresses. * diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index db7adffcdc76..9c610e1e99b8 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -257,6 +257,11 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, struct cec_adapter *adap; int res; + /* + * Disable this capability until the connector info public API + * is ready. + */ + caps &= ~CEC_CAP_CONNECTOR_INFO; #ifndef CONFIG_MEDIA_CEC_RC caps &= ~CEC_CAP_RC; #endif diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c index e5080d6f5b2d..1d0133f01e00 100644 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ b/drivers/media/platform/seco-cec/seco-cec.c @@ -18,7 +18,7 @@ #include /* CEC Framework */ -#include +#include #include "seco-cec.h" diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h index 57b3a9f6ea1d..0e3bd3415724 100644 --- a/include/media/cec-notifier.h +++ b/include/media/cec-notifier.h @@ -63,30 +63,6 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa); void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n, const struct edid *edid); -/** - * cec_notifier_register - register a callback with the notifier - * @n: the CEC notifier - * @adap: the CEC adapter, passed as argument to the callback function - * @callback: the callback function - */ -void cec_notifier_register(struct cec_notifier *n, - struct cec_adapter *adap, - void (*callback)(struct cec_adapter *adap, u16 pa)); - -/** - * cec_notifier_unregister - unregister the callback from the notifier. - * @n: the CEC notifier - */ -void cec_notifier_unregister(struct cec_notifier *n); - -/** - * cec_register_cec_notifier - register the notifier with the cec adapter. - * @adap: the CEC adapter - * @notifier: the CEC notifier - */ -void cec_register_cec_notifier(struct cec_adapter *adap, - struct cec_notifier *notifier); - /** * cec_notifier_parse_hdmi_phandle - find the hdmi device from "hdmi-phandle" * @dev: the device with the "hdmi-phandle" device tree property @@ -119,21 +95,6 @@ static inline void cec_notifier_set_phys_addr_from_edid(struct cec_notifier *n, { } -static inline void cec_notifier_register(struct cec_notifier *n, - struct cec_adapter *adap, - void (*callback)(struct cec_adapter *adap, u16 pa)) -{ -} - -static inline void cec_notifier_unregister(struct cec_notifier *n) -{ -} - -static inline void cec_register_cec_notifier(struct cec_adapter *adap, - struct cec_notifier *notifier) -{ -} - static inline struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) { return ERR_PTR(-ENODEV); diff --git a/include/media/cec.h b/include/media/cec.h index 707411ef8ba2..4d59387bc61b 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -17,7 +17,9 @@ #include #include #include -#include + +/* CEC_ADAP_G_CONNECTOR_INFO is available */ +#define CEC_CAP_CONNECTOR_INFO (1 << 8) #define CEC_CAP_DEFAULTS (CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | \ CEC_CAP_PASSTHROUGH | CEC_CAP_RC) @@ -53,6 +55,7 @@ struct cec_devnode { struct cec_adapter; struct cec_data; struct cec_pin; +struct cec_notifier; struct cec_data { struct list_head list; @@ -144,6 +147,34 @@ struct cec_adap_ops { */ #define CEC_MAX_MSG_TX_QUEUE_SZ (18 * 1) +/** + * struct cec_drm_connector_info - tells which drm connector is + * associated with the CEC adapter. + * @card_no: drm card number + * @connector_id: drm connector ID + */ +struct cec_drm_connector_info { + __u32 card_no; + __u32 connector_id; +}; + +#define CEC_CONNECTOR_TYPE_NO_CONNECTOR 0 +#define CEC_CONNECTOR_TYPE_DRM 1 + +/** + * struct cec_connector_info - tells if and which connector is + * associated with the CEC adapter. + * @type: connector type (if any) + * @drm: drm connector info + */ +struct cec_connector_info { + __u32 type; + union { + struct cec_drm_connector_info drm; + __u32 raw[16]; + }; +}; + struct cec_adapter { struct module *owner; char name[32]; @@ -182,6 +213,7 @@ struct cec_adapter { struct cec_fh *cec_initiator; bool passthrough; struct cec_log_addrs log_addrs; + struct cec_connector_info conn_info; u32 tx_timeouts; @@ -233,6 +265,7 @@ static inline bool cec_is_registered(const struct cec_adapter *adap) ((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf struct edid; +struct drm_connector; #if IS_REACHABLE(CONFIG_CEC_CORE) struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, @@ -247,6 +280,8 @@ void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); void cec_s_phys_addr_from_edid(struct cec_adapter *adap, const struct edid *edid); +void cec_s_conn_info(struct cec_adapter *adap, + const struct cec_connector_info *conn_info); int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, bool block); @@ -331,6 +366,9 @@ void cec_queue_pin_5v_event(struct cec_adapter *adap, bool is_high, ktime_t ts); u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, unsigned int *offset); +void cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info, + const struct drm_connector *connector); + #else static inline int cec_register_adapter(struct cec_adapter *adap, @@ -365,6 +403,64 @@ static inline u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size, return CEC_PHYS_ADDR_INVALID; } +static inline void cec_s_conn_info(struct cec_adapter *adap, + const struct cec_connector_info *conn_info) +{ +} + +static inline void +cec_fill_conn_info_from_drm(struct cec_connector_info *conn_info, + const struct drm_connector *connector) +{ + memset(conn_info, 0, sizeof(*conn_info)); +} + +#endif + +#if IS_REACHABLE(CONFIG_CEC_CORE) && IS_ENABLED(CONFIG_CEC_NOTIFIER) + +/** + * cec_notifier_register - register a callback with the notifier + * @n: the CEC notifier + * @adap: the CEC adapter, passed as argument to the callback function + * @callback: the callback function + */ +void cec_notifier_register(struct cec_notifier *n, + struct cec_adapter *adap, + void (*callback)(struct cec_adapter *adap, u16 pa)); + +/** + * cec_notifier_unregister - unregister the callback from the notifier. + * @n: the CEC notifier + */ +void cec_notifier_unregister(struct cec_notifier *n); + +/** + * cec_register_cec_notifier - register the notifier with the cec adapter. + * @adap: the CEC adapter + * @notifier: the CEC notifier + */ +void cec_register_cec_notifier(struct cec_adapter *adap, + struct cec_notifier *notifier); + +#else + +static inline void +cec_notifier_register(struct cec_notifier *n, + struct cec_adapter *adap, + void (*callback)(struct cec_adapter *adap, u16 pa)) +{ +} + +static inline void cec_notifier_unregister(struct cec_notifier *n) +{ +} + +static inline void cec_register_cec_notifier(struct cec_adapter *adap, + struct cec_notifier *notifier) +{ +} + #endif /** -- cgit v1.2.3-59-g8ed1b From b48cb35c6a7babdc317edb4c752ecf3da0691228 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 20 Jun 2019 06:10:00 -0400 Subject: media: cec-notifier: add new notifier functions In order to support multiple CEC devices for an HDMI connector, and to support cec_connector_info, drivers should use either a cec_notifier_conn_(un)register pair of functions (HDMI drivers) or a cec_notifier_cec_adap_(un)register pair (CEC adapter drivers). This replaces cec_notifier_get_conn/cec_notifier_put. For CEC adapters it is also no longer needed to call cec_notifier_register, cec_register_cec_notifier and cec_notifier_unregister. This is now all handled internally by the new functions. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-notifier.c | 85 ++++++++++++++++++++++++++++++++++++++++ include/media/cec-notifier.h | 78 ++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index f72b19c351dd..52a867bde15f 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -22,6 +22,7 @@ struct cec_notifier { struct list_head head; struct kref kref; struct device *hdmi_dev; + struct cec_connector_info conn_info; const char *conn_name; struct cec_adapter *cec_adap; void (*callback)(struct cec_adapter *adap, u16 pa); @@ -88,6 +89,84 @@ void cec_notifier_put(struct cec_notifier *n) } EXPORT_SYMBOL_GPL(cec_notifier_put); +struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info) +{ + struct cec_notifier *n = cec_notifier_get_conn(hdmi_dev, conn_name); + + if (!n) + return n; + + mutex_lock(&n->lock); + n->phys_addr = CEC_PHYS_ADDR_INVALID; + if (conn_info) + n->conn_info = *conn_info; + else + memset(&n->conn_info, 0, sizeof(n->conn_info)); + if (n->cec_adap) { + cec_phys_addr_invalidate(n->cec_adap); + cec_s_conn_info(n->cec_adap, conn_info); + } + mutex_unlock(&n->lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_conn_register); + +void cec_notifier_conn_unregister(struct cec_notifier *n) +{ + if (!n) + return; + + mutex_lock(&n->lock); + memset(&n->conn_info, 0, sizeof(n->conn_info)); + n->phys_addr = CEC_PHYS_ADDR_INVALID; + if (n->cec_adap) { + cec_phys_addr_invalidate(n->cec_adap); + cec_s_conn_info(n->cec_adap, NULL); + } + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_conn_unregister); + +struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap) +{ + struct cec_notifier *n; + + if (WARN_ON(!adap)) + return NULL; + + n = cec_notifier_get_conn(hdmi_dev, conn_name); + if (!n) + return n; + + mutex_lock(&n->lock); + n->cec_adap = adap; + adap->conn_info = n->conn_info; + adap->notifier = n; + cec_s_phys_addr(adap, n->phys_addr, false); + mutex_unlock(&n->lock); + return n; +} +EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_register); + +void cec_notifier_cec_adap_unregister(struct cec_notifier *n) +{ + if (!n) + return; + + mutex_lock(&n->lock); + n->cec_adap->notifier = NULL; + n->cec_adap = NULL; + n->callback = NULL; + mutex_unlock(&n->lock); + cec_notifier_put(n); +} +EXPORT_SYMBOL_GPL(cec_notifier_cec_adap_unregister); + void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) { if (n == NULL) @@ -97,6 +176,8 @@ void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) n->phys_addr = pa; if (n->callback) n->callback(n->cec_adap, n->phys_addr); + else if (n->cec_adap) + cec_s_phys_addr(n->cec_adap, n->phys_addr, false); mutex_unlock(&n->lock); } EXPORT_SYMBOL_GPL(cec_notifier_set_phys_addr); @@ -131,6 +212,10 @@ EXPORT_SYMBOL_GPL(cec_notifier_register); void cec_notifier_unregister(struct cec_notifier *n) { + /* Do nothing unless cec_notifier_register was called first */ + if (!n->callback) + return; + mutex_lock(&n->lock); n->callback = NULL; mutex_unlock(&n->lock); diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h index 0e3bd3415724..f161f8a493ac 100644 --- a/include/media/cec-notifier.h +++ b/include/media/cec-notifier.h @@ -42,6 +42,60 @@ struct cec_notifier *cec_notifier_get_conn(struct device *dev, */ void cec_notifier_put(struct cec_notifier *n); +/** + * cec_notifier_conn_register - find or create a new cec_notifier for the given + * HDMI device and connector tuple. + * @hdmi_dev: HDMI device that sends the events. + * @conn_name: the connector name from which the event occurs. May be NULL + * if there is always only one HDMI connector created by the HDMI device. + * @conn_info: the connector info from which the event occurs (may be NULL) + * + * If a notifier for device @dev and connector @conn_name already exists, then + * increase the refcount and return that notifier. + * + * If it doesn't exist, then allocate a new notifier struct and return a + * pointer to that new struct. + * + * Return NULL if the memory could not be allocated. + */ +struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info); + +/** + * cec_notifier_conn_unregister - decrease refcount and delete when the + * refcount reaches 0. + * @n: notifier. If NULL, then this function does nothing. + */ +void cec_notifier_conn_unregister(struct cec_notifier *n); + +/** + * cec_notifier_cec_adap_register - find or create a new cec_notifier for the + * given device. + * @hdmi_dev: HDMI device that sends the events. + * @conn_name: the connector name from which the event occurs. May be NULL + * if there is always only one HDMI connector created by the HDMI device. + * @adap: the cec adapter that registered this notifier. + * + * If a notifier for device @dev and connector @conn_name already exists, then + * increase the refcount and return that notifier. + * + * If it doesn't exist, then allocate a new notifier struct and return a + * pointer to that new struct. + * + * Return NULL if the memory could not be allocated. + */ +struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap); + +/** + * cec_notifier_cec_adap_unregister - decrease refcount and delete when the + * refcount reaches 0. + * @n: notifier. If NULL, then this function does nothing. + */ +void cec_notifier_cec_adap_unregister(struct cec_notifier *n); + /** * cec_notifier_set_phys_addr - set a new physical address. * @n: the CEC notifier @@ -86,6 +140,30 @@ static inline void cec_notifier_put(struct cec_notifier *n) { } +static inline struct cec_notifier * +cec_notifier_conn_register(struct device *hdmi_dev, const char *conn_name, + const struct cec_connector_info *conn_info) +{ + /* A non-NULL pointer is expected on success */ + return (struct cec_notifier *)0xdeadfeed; +} + +static inline void cec_notifier_conn_unregister(struct cec_notifier *n) +{ +} + +static inline struct cec_notifier * +cec_notifier_cec_adap_register(struct device *hdmi_dev, const char *conn_name, + struct cec_adapter *adap) +{ + /* A non-NULL pointer is expected on success */ + return (struct cec_notifier *)0xdeadfeed; +} + +static inline void cec_notifier_cec_adap_unregister(struct cec_notifier *n) +{ +} + static inline void cec_notifier_set_phys_addr(struct cec_notifier *n, u16 pa) { } -- cgit v1.2.3-59-g8ed1b From 9e2e4382ec72d9f3a288b4218f684faee7bb3c92 Mon Sep 17 00:00:00 2001 From: Ding Xiang Date: Tue, 18 Jun 2019 05:13:09 -0400 Subject: media: rc: remove redundant dev_err message devm_ioremap_resource already contains error message, so remove the redundant dev_err message Signed-off-by: Ding Xiang Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir.c | 4 +--- drivers/media/rc/mtk-cir.c | 4 +--- drivers/media/rc/sunxi-cir.c | 1 - 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 02914da8cce5..72a7bbbf6b1f 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -113,10 +113,8 @@ static int meson_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->reg = devm_ioremap_resource(dev, res); - if (IS_ERR(ir->reg)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(ir->reg)) return PTR_ERR(ir->reg); - } irq = platform_get_irq(pdev, 0); if (irq < 0) { diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c index 46101efe017b..50fb0aebb8d4 100644 --- a/drivers/media/rc/mtk-cir.c +++ b/drivers/media/rc/mtk-cir.c @@ -320,10 +320,8 @@ static int mtk_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->base = devm_ioremap_resource(dev, res); - if (IS_ERR(ir->base)) { - dev_err(dev, "failed to map registers\n"); + if (IS_ERR(ir->base)) return PTR_ERR(ir->base); - } ir->rc = devm_rc_allocate_device(dev, RC_DRIVER_IR_RAW); if (!ir->rc) { diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c index a48f68539231..aa719d0ae6b0 100644 --- a/drivers/media/rc/sunxi-cir.c +++ b/drivers/media/rc/sunxi-cir.c @@ -195,7 +195,6 @@ static int sunxi_ir_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ir->base = devm_ioremap_resource(dev, res); if (IS_ERR(ir->base)) { - dev_err(dev, "failed to map registers\n"); ret = PTR_ERR(ir->base); goto exit_clkdisable_clk; } -- cgit v1.2.3-59-g8ed1b From a91418ac130d1abff38e86ba6f5cbf19a5daacec Mon Sep 17 00:00:00 2001 From: A Sun Date: Wed, 19 Jun 2019 03:53:53 -0400 Subject: media: mceusb: disable "nonsensical irdata" messages mceusb device 2304:0225, and likely others, produces numerous [ 4231.111310] mceusb 1-1.1.2:1.0: nonsensical irdata 80 with duration 0 [ 4381.493597] mceusb 1-1.1.2:1.0: nonsensical irdata 80 with duration 0 [ 4410.247568] mceusb 1-1.1.2:1.0: nonsensical irdata 80 with duration 0 ... [60153.264064] mceusb 1-1.1.2:1.0: nonsensical irdata 00 with duration 0 ... due to reception of ambient IR noise. Change these warning messages to debug messages. Signed-off-by: A Sun Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 72862e4bec62..4d5351ebb940 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1176,8 +1176,8 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0); rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK); if (unlikely(!rawir.duration)) { - dev_warn(ir->dev, "nonsensical irdata %02x with duration 0", - ir->buf_in[i]); + dev_dbg(ir->dev, "nonsensical irdata %02x with duration 0", + ir->buf_in[i]); break; } if (rawir.pulse) { -- cgit v1.2.3-59-g8ed1b From 15a98fb2fc287bbfe430e854d56dcfc86eae21db Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 17 Jun 2019 07:16:52 -0400 Subject: media: dvb_frontend: split dvb_frontend_handle_ioctl function Over time, dvb_frontend_handle_ioctl() has grown to the point where we now get a warning from the compiler about excessive stack usage: drivers/media/dvb-core/dvb_frontend.c: In function 'dvb_frontend_handle_ioctl': drivers/media/dvb-core/dvb_frontend.c:2692:1: error: the frame size of 1048 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] Almost all of this is used by the dtv_frontend_properties structure in the FE_GET_PROPERTY and FE_GET_FRONTEND commands. Splitting those into separate function reduces the stack usage of the main function to just 136 bytes, the others are under 500 each. Signed-off-by: Arnd Bergmann Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 140 +++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 63 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 6351a97f3d18..209186c5cd9b 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2311,6 +2311,78 @@ static int dtv_set_frontend(struct dvb_frontend *fe) return 0; } +static int dvb_get_property(struct dvb_frontend *fe, struct file *file, + struct dtv_properties *tvps) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_property *tvp = NULL; + struct dtv_frontend_properties getp; + int i, err; + + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS) + return -EINVAL; + + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, &getp, NULL); + if (err < 0) + goto out; + } + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, &getp, + tvp + i, file); + if (err < 0) + goto out; + } + + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + err = 0; +out: + kfree(tvp); + return err; +} + +static int dvb_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out) +{ + struct dtv_frontend_properties getp; + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + return dtv_get_frontend(fe, &getp, p_out); +} + static int dvb_frontend_handle_ioctl(struct file *file, unsigned int cmd, void *parg) { @@ -2356,58 +2428,9 @@ static int dvb_frontend_handle_ioctl(struct file *file, err = 0; break; } - case FE_GET_PROPERTY: { - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - struct dtv_frontend_properties getp = fe->dtv_property_cache; - - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", - __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", - __func__, tvps->props); - - /* - * Put an arbitrary limit on the number of messages that can - * be sent at once - */ - if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) - return -EINVAL; - - tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); - if (IS_ERR(tvp)) - return PTR_ERR(tvp); - - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - if (fepriv->state != FESTATE_IDLE) { - err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) { - kfree(tvp); - return err; - } - } - for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, - tvp + i, file); - if (err < 0) { - kfree(tvp); - return err; - } - } - - if (copy_to_user((void __user *)tvps->props, tvp, - tvps->num * sizeof(struct dtv_property))) { - kfree(tvp); - return -EFAULT; - } - kfree(tvp); - err = 0; + case FE_GET_PROPERTY: + err = dvb_get_property(fe, file, parg); break; - } case FE_GET_INFO: { struct dvb_frontend_info *info = parg; @@ -2545,7 +2568,6 @@ static int dvb_frontend_handle_ioctl(struct file *file, fepriv->tune_mode_flags = (unsigned long)parg; err = 0; break; - /* DEPRECATED dish control ioctls */ case FE_DISHNETWORK_SEND_LEGACY_CMD: @@ -2664,22 +2686,14 @@ static int dvb_frontend_handle_ioctl(struct file *file, break; err = dtv_set_frontend(fe); break; + case FE_GET_EVENT: err = dvb_frontend_get_event(fe, parg, file->f_flags); break; - case FE_GET_FRONTEND: { - struct dtv_frontend_properties getp = fe->dtv_property_cache; - - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - err = dtv_get_frontend(fe, &getp, parg); + case FE_GET_FRONTEND: + err = dvb_get_frontend(fe, parg); break; - } default: return -ENOTSUPP; -- cgit v1.2.3-59-g8ed1b From 1910ea428f28e5731a2cea32b86e71953829f15d Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Mon, 24 Jun 2019 11:42:14 -0400 Subject: media: rc: Prefer KEY_NUMERIC_* for number buttons on remotes Prefer KEY_NUMERIC_* for number buttons on remotes. Now all the remotes use KEY_NUMERIC_[0-9] for the number buttons rather than keys that could be affected by modifiers (Caps-Lock, or Num-Lock) or regional keymaps. Created using: sed -i 's/KEY_\([0-9]\) /KEY_NUMERIC_\1 /' *.c sed -i 's/KEY_\([0-9]\)}/KEY_NUMERIC_\1}/' *.c sed -i 's/``KEY_\([0-9]\)/``KEY_NUMERIC_\1/' Documentation/media/uapi/rc/rc-tables.rst Signed-off-by: Bastien Nocera Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/rc/rc-tables.rst | 20 ++--- drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c | 20 ++--- drivers/media/rc/keymaps/rc-alink-dtu-m.c | 20 ++--- drivers/media/rc/keymaps/rc-anysee.c | 20 ++--- drivers/media/rc/keymaps/rc-apac-viewcomp.c | 20 ++--- drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c | 20 ++--- drivers/media/rc/keymaps/rc-asus-pc39.c | 20 ++--- drivers/media/rc/keymaps/rc-asus-ps3-100.c | 20 ++--- drivers/media/rc/keymaps/rc-ati-x10.c | 20 ++--- drivers/media/rc/keymaps/rc-avermedia-a16d.c | 20 ++--- drivers/media/rc/keymaps/rc-avermedia-cardbus.c | 20 ++--- drivers/media/rc/keymaps/rc-avermedia-dvbt.c | 20 ++--- drivers/media/rc/keymaps/rc-avermedia-m135a.c | 40 ++++----- .../media/rc/keymaps/rc-avermedia-m733a-rm-k6.c | 20 ++--- drivers/media/rc/keymaps/rc-avermedia-rm-ks.c | 20 ++--- drivers/media/rc/keymaps/rc-avermedia.c | 20 ++--- drivers/media/rc/keymaps/rc-avertv-303.c | 20 ++--- drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c | 20 ++--- drivers/media/rc/keymaps/rc-behold-columbus.c | 20 ++--- drivers/media/rc/keymaps/rc-behold.c | 20 ++--- drivers/media/rc/keymaps/rc-budget-ci-old.c | 20 ++--- drivers/media/rc/keymaps/rc-cinergy-1400.c | 20 ++--- drivers/media/rc/keymaps/rc-cinergy.c | 20 ++--- drivers/media/rc/keymaps/rc-d680-dmb.c | 20 ++--- drivers/media/rc/keymaps/rc-delock-61959.c | 20 ++--- drivers/media/rc/keymaps/rc-dib0700-nec.c | 40 ++++----- drivers/media/rc/keymaps/rc-dib0700-rc5.c | 100 ++++++++++----------- drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c | 20 ++--- drivers/media/rc/keymaps/rc-digittrade.c | 20 ++--- drivers/media/rc/keymaps/rc-dm1105-nec.c | 20 ++--- drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c | 20 ++--- drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c | 20 ++--- drivers/media/rc/keymaps/rc-dtt200u.c | 20 ++--- drivers/media/rc/keymaps/rc-dvbsky.c | 20 ++--- drivers/media/rc/keymaps/rc-dvico-mce.c | 20 ++--- drivers/media/rc/keymaps/rc-dvico-portable.c | 20 ++--- drivers/media/rc/keymaps/rc-em-terratec.c | 20 ++--- drivers/media/rc/keymaps/rc-encore-enltv-fm53.c | 20 ++--- drivers/media/rc/keymaps/rc-encore-enltv.c | 20 ++--- drivers/media/rc/keymaps/rc-encore-enltv2.c | 20 ++--- drivers/media/rc/keymaps/rc-eztv.c | 20 ++--- drivers/media/rc/keymaps/rc-flydvb.c | 20 ++--- drivers/media/rc/keymaps/rc-flyvideo.c | 20 ++--- drivers/media/rc/keymaps/rc-fusionhdtv-mce.c | 20 ++--- drivers/media/rc/keymaps/rc-gadmei-rm008z.c | 20 ++--- drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c | 20 ++--- drivers/media/rc/keymaps/rc-gotview7135.c | 20 ++--- drivers/media/rc/keymaps/rc-hauppauge.c | 100 ++++++++++----------- drivers/media/rc/keymaps/rc-hisi-poplar.c | 20 ++--- drivers/media/rc/keymaps/rc-hisi-tv-demo.c | 20 ++--- drivers/media/rc/keymaps/rc-iodata-bctv7e.c | 20 ++--- drivers/media/rc/keymaps/rc-it913x-v1.c | 40 ++++----- drivers/media/rc/keymaps/rc-it913x-v2.c | 40 ++++----- drivers/media/rc/keymaps/rc-kaiomy.c | 20 ++--- drivers/media/rc/keymaps/rc-kworld-315u.c | 20 ++--- drivers/media/rc/keymaps/rc-kworld-pc150u.c | 20 ++--- .../media/rc/keymaps/rc-kworld-plus-tv-analog.c | 24 ++--- drivers/media/rc/keymaps/rc-leadtek-y04g0051.c | 20 ++--- drivers/media/rc/keymaps/rc-lme2510.c | 60 ++++++------- drivers/media/rc/keymaps/rc-manli.c | 20 ++--- .../media/rc/keymaps/rc-medion-x10-digitainer.c | 20 ++--- drivers/media/rc/keymaps/rc-medion-x10-or2x.c | 20 ++--- drivers/media/rc/keymaps/rc-medion-x10.c | 20 ++--- drivers/media/rc/keymaps/rc-msi-digivox-ii.c | 20 ++--- drivers/media/rc/keymaps/rc-msi-digivox-iii.c | 20 ++--- drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c | 20 ++--- drivers/media/rc/keymaps/rc-msi-tvanywhere.c | 20 ++--- drivers/media/rc/keymaps/rc-nebula.c | 20 ++--- .../media/rc/keymaps/rc-nec-terratec-cinergy-xs.c | 40 ++++----- drivers/media/rc/keymaps/rc-norwood.c | 20 ++--- drivers/media/rc/keymaps/rc-npgtech.c | 20 ++--- drivers/media/rc/keymaps/rc-pctv-sedna.c | 20 ++--- drivers/media/rc/keymaps/rc-pinnacle-color.c | 20 ++--- drivers/media/rc/keymaps/rc-pinnacle-grey.c | 20 ++--- drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c | 20 ++--- drivers/media/rc/keymaps/rc-pixelview-002t.c | 20 ++--- drivers/media/rc/keymaps/rc-pixelview-mk12.c | 20 ++--- drivers/media/rc/keymaps/rc-pixelview-new.c | 20 ++--- drivers/media/rc/keymaps/rc-pixelview.c | 20 ++--- .../media/rc/keymaps/rc-powercolor-real-angel.c | 20 ++--- drivers/media/rc/keymaps/rc-proteus-2309.c | 20 ++--- drivers/media/rc/keymaps/rc-purpletv.c | 20 ++--- drivers/media/rc/keymaps/rc-pv951.c | 20 ++--- .../media/rc/keymaps/rc-real-audio-220-32-keys.c | 20 ++--- drivers/media/rc/keymaps/rc-reddo.c | 20 ++--- drivers/media/rc/keymaps/rc-snapstream-firefly.c | 20 ++--- drivers/media/rc/keymaps/rc-su3000.c | 20 ++--- drivers/media/rc/keymaps/rc-tango.c | 20 ++--- drivers/media/rc/keymaps/rc-tbs-nec.c | 20 ++--- drivers/media/rc/keymaps/rc-technisat-ts35.c | 20 ++--- drivers/media/rc/keymaps/rc-technisat-usb2.c | 20 ++--- .../media/rc/keymaps/rc-terratec-cinergy-c-pci.c | 20 ++--- .../media/rc/keymaps/rc-terratec-cinergy-s2-hd.c | 20 ++--- drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c | 20 ++--- drivers/media/rc/keymaps/rc-terratec-slim-2.c | 20 ++--- drivers/media/rc/keymaps/rc-terratec-slim.c | 20 ++--- drivers/media/rc/keymaps/rc-tevii-nec.c | 20 ++--- .../media/rc/keymaps/rc-total-media-in-hand-02.c | 20 ++--- drivers/media/rc/keymaps/rc-total-media-in-hand.c | 20 ++--- drivers/media/rc/keymaps/rc-trekstor.c | 20 ++--- drivers/media/rc/keymaps/rc-tt-1500.c | 20 ++--- drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c | 20 ++--- drivers/media/rc/keymaps/rc-twinhan1027.c | 20 ++--- drivers/media/rc/keymaps/rc-videomate-m1f.c | 20 ++--- drivers/media/rc/keymaps/rc-videomate-s350.c | 20 ++--- drivers/media/rc/keymaps/rc-videomate-tv-pvr.c | 20 ++--- drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c | 20 ++--- drivers/media/rc/keymaps/rc-winfast.c | 20 ++--- drivers/media/rc/keymaps/rc-xbox-dvd.c | 20 ++--- drivers/media/rc/keymaps/rc-zx-irdec.c | 20 ++--- 110 files changed, 1254 insertions(+), 1250 deletions(-) (limited to 'drivers/media') diff --git a/Documentation/media/uapi/rc/rc-tables.rst b/Documentation/media/uapi/rc/rc-tables.rst index 177ac44fa0fa..468d8aa3849b 100644 --- a/Documentation/media/uapi/rc/rc-tables.rst +++ b/Documentation/media/uapi/rc/rc-tables.rst @@ -54,7 +54,7 @@ the remote via /dev/input/event devices. - .. row 3 - - ``KEY_0`` + - ``KEY_NUMERIC_0`` - Keyboard digit 0 @@ -62,7 +62,7 @@ the remote via /dev/input/event devices. - .. row 4 - - ``KEY_1`` + - ``KEY_NUMERIC_1`` - Keyboard digit 1 @@ -70,7 +70,7 @@ the remote via /dev/input/event devices. - .. row 5 - - ``KEY_2`` + - ``KEY_NUMERIC_2`` - Keyboard digit 2 @@ -78,7 +78,7 @@ the remote via /dev/input/event devices. - .. row 6 - - ``KEY_3`` + - ``KEY_NUMERIC_3`` - Keyboard digit 3 @@ -86,7 +86,7 @@ the remote via /dev/input/event devices. - .. row 7 - - ``KEY_4`` + - ``KEY_NUMERIC_4`` - Keyboard digit 4 @@ -94,7 +94,7 @@ the remote via /dev/input/event devices. - .. row 8 - - ``KEY_5`` + - ``KEY_NUMERIC_5`` - Keyboard digit 5 @@ -102,7 +102,7 @@ the remote via /dev/input/event devices. - .. row 9 - - ``KEY_6`` + - ``KEY_NUMERIC_6`` - Keyboard digit 6 @@ -110,7 +110,7 @@ the remote via /dev/input/event devices. - .. row 10 - - ``KEY_7`` + - ``KEY_NUMERIC_7`` - Keyboard digit 7 @@ -118,7 +118,7 @@ the remote via /dev/input/event devices. - .. row 11 - - ``KEY_8`` + - ``KEY_NUMERIC_8`` - Keyboard digit 8 @@ -126,7 +126,7 @@ the remote via /dev/input/event devices. - .. row 12 - - ``KEY_9`` + - ``KEY_NUMERIC_9`` - Keyboard digit 9 diff --git a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c index 732687ce0637..0a867ca90038 100644 --- a/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c +++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c @@ -12,16 +12,16 @@ static struct rc_map_table adstech_dvb_t_pci[] = { /* Keys 0 to 9 */ - { 0x4d, KEY_0 }, - { 0x57, KEY_1 }, - { 0x4f, KEY_2 }, - { 0x53, KEY_3 }, - { 0x56, KEY_4 }, - { 0x4e, KEY_5 }, - { 0x5e, KEY_6 }, - { 0x54, KEY_7 }, - { 0x4c, KEY_8 }, - { 0x5c, KEY_9 }, + { 0x4d, KEY_NUMERIC_0 }, + { 0x57, KEY_NUMERIC_1 }, + { 0x4f, KEY_NUMERIC_2 }, + { 0x53, KEY_NUMERIC_3 }, + { 0x56, KEY_NUMERIC_4 }, + { 0x4e, KEY_NUMERIC_5 }, + { 0x5e, KEY_NUMERIC_6 }, + { 0x54, KEY_NUMERIC_7 }, + { 0x4c, KEY_NUMERIC_8 }, + { 0x5c, KEY_NUMERIC_9 }, { 0x5b, KEY_POWER }, { 0x5f, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c index 530af333af8e..8a2ccaf3b817 100644 --- a/drivers/media/rc/keymaps/rc-alink-dtu-m.c +++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c @@ -11,22 +11,22 @@ /* A-Link DTU(m) slim remote, 6 rows, 3 columns. */ static struct rc_map_table alink_dtu_m[] = { { 0x0800, KEY_VOLUMEUP }, - { 0x0801, KEY_1 }, - { 0x0802, KEY_3 }, - { 0x0803, KEY_7 }, - { 0x0804, KEY_9 }, + { 0x0801, KEY_NUMERIC_1 }, + { 0x0802, KEY_NUMERIC_3 }, + { 0x0803, KEY_NUMERIC_7 }, + { 0x0804, KEY_NUMERIC_9 }, { 0x0805, KEY_NEW }, /* symbol: PIP */ - { 0x0806, KEY_0 }, + { 0x0806, KEY_NUMERIC_0 }, { 0x0807, KEY_CHANNEL }, /* JUMP */ - { 0x080d, KEY_5 }, - { 0x080f, KEY_2 }, + { 0x080d, KEY_NUMERIC_5 }, + { 0x080f, KEY_NUMERIC_2 }, { 0x0812, KEY_POWER2 }, { 0x0814, KEY_CHANNELUP }, { 0x0816, KEY_VOLUMEDOWN }, - { 0x0818, KEY_6 }, + { 0x0818, KEY_NUMERIC_6 }, { 0x081a, KEY_MUTE }, - { 0x081b, KEY_8 }, - { 0x081c, KEY_4 }, + { 0x081b, KEY_NUMERIC_8 }, + { 0x081c, KEY_NUMERIC_4 }, { 0x081d, KEY_CHANNELDOWN }, }; diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c index 9d1eee1f0515..34da03c46104 100644 --- a/drivers/media/rc/keymaps/rc-anysee.c +++ b/drivers/media/rc/keymaps/rc-anysee.c @@ -9,16 +9,16 @@ #include static struct rc_map_table anysee[] = { - { 0x0800, KEY_0 }, - { 0x0801, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0803, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0805, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0807, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0809, KEY_9 }, + { 0x0800, KEY_NUMERIC_0 }, + { 0x0801, KEY_NUMERIC_1 }, + { 0x0802, KEY_NUMERIC_2 }, + { 0x0803, KEY_NUMERIC_3 }, + { 0x0804, KEY_NUMERIC_4 }, + { 0x0805, KEY_NUMERIC_5 }, + { 0x0806, KEY_NUMERIC_6 }, + { 0x0807, KEY_NUMERIC_7 }, + { 0x0808, KEY_NUMERIC_8 }, + { 0x0809, KEY_NUMERIC_9 }, { 0x080a, KEY_POWER2 }, /* [red power button] */ { 0x080b, KEY_VIDEO }, /* [*] MODE */ { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */ diff --git a/drivers/media/rc/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c index af2e7fdc7b85..bdc47e25d46e 100644 --- a/drivers/media/rc/keymaps/rc-apac-viewcomp.c +++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c @@ -12,16 +12,16 @@ static struct rc_map_table apac_viewcomp[] = { - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, + { 0x00, KEY_NUMERIC_0 }, { 0x17, KEY_LAST }, /* +100 */ { 0x0a, KEY_LIST }, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c index 727e35c31039..1d322137898e 100644 --- a/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c +++ b/drivers/media/rc/keymaps/rc-astrometa-t2hybrid.c @@ -21,21 +21,21 @@ static struct rc_map_table t2hybrid[] = { { 0x40, KEY_ZOOM }, /* Fullscreen */ { 0x1e, KEY_VOLUMEUP }, - { 0x12, KEY_0 }, + { 0x12, KEY_NUMERIC_0 }, { 0x02, KEY_CHANNELDOWN }, { 0x1c, KEY_AGAIN }, /* Recall */ - { 0x09, KEY_1 }, - { 0x1d, KEY_2 }, - { 0x1f, KEY_3 }, + { 0x09, KEY_NUMERIC_1 }, + { 0x1d, KEY_NUMERIC_2 }, + { 0x1f, KEY_NUMERIC_3 }, - { 0x0d, KEY_4 }, - { 0x19, KEY_5 }, - { 0x1b, KEY_6 }, + { 0x0d, KEY_NUMERIC_4 }, + { 0x19, KEY_NUMERIC_5 }, + { 0x1b, KEY_NUMERIC_6 }, - { 0x11, KEY_7 }, - { 0x15, KEY_8 }, - { 0x17, KEY_9 }, + { 0x11, KEY_NUMERIC_7 }, + { 0x15, KEY_NUMERIC_8 }, + { 0x17, KEY_NUMERIC_9 }, }; static struct rc_map_list t2hybrid_map = { diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c index 13a935c3ac59..7a4b3a6e3a49 100644 --- a/drivers/media/rc/keymaps/rc-asus-pc39.c +++ b/drivers/media/rc/keymaps/rc-asus-pc39.c @@ -16,16 +16,16 @@ static struct rc_map_table asus_pc39[] = { /* Keys 0 to 9 */ - { 0x082a, KEY_0 }, - { 0x0816, KEY_1 }, - { 0x0812, KEY_2 }, - { 0x0814, KEY_3 }, - { 0x0836, KEY_4 }, - { 0x0832, KEY_5 }, - { 0x0834, KEY_6 }, - { 0x080e, KEY_7 }, - { 0x080a, KEY_8 }, - { 0x080c, KEY_9 }, + { 0x082a, KEY_NUMERIC_0 }, + { 0x0816, KEY_NUMERIC_1 }, + { 0x0812, KEY_NUMERIC_2 }, + { 0x0814, KEY_NUMERIC_3 }, + { 0x0836, KEY_NUMERIC_4 }, + { 0x0832, KEY_NUMERIC_5 }, + { 0x0834, KEY_NUMERIC_6 }, + { 0x080e, KEY_NUMERIC_7 }, + { 0x080a, KEY_NUMERIC_8 }, + { 0x080c, KEY_NUMERIC_9 }, { 0x0801, KEY_RADIO }, /* radio */ { 0x083c, KEY_MENU }, /* dvd/menu */ diff --git a/drivers/media/rc/keymaps/rc-asus-ps3-100.c b/drivers/media/rc/keymaps/rc-asus-ps3-100.c index 7f836fcc68ac..09b60fa335e3 100644 --- a/drivers/media/rc/keymaps/rc-asus-ps3-100.c +++ b/drivers/media/rc/keymaps/rc-asus-ps3-100.c @@ -20,16 +20,16 @@ static struct rc_map_table asus_ps3_100[] = { { 0x0807, KEY_GREEN }, /* green */ /* Keys 0 to 9 */ - { 0x082a, KEY_0 }, - { 0x0816, KEY_1 }, - { 0x0812, KEY_2 }, - { 0x0814, KEY_3 }, - { 0x0836, KEY_4 }, - { 0x0832, KEY_5 }, - { 0x0834, KEY_6 }, - { 0x080e, KEY_7 }, - { 0x080a, KEY_8 }, - { 0x080c, KEY_9 }, + { 0x082a, KEY_NUMERIC_0 }, + { 0x0816, KEY_NUMERIC_1 }, + { 0x0812, KEY_NUMERIC_2 }, + { 0x0814, KEY_NUMERIC_3 }, + { 0x0836, KEY_NUMERIC_4 }, + { 0x0832, KEY_NUMERIC_5 }, + { 0x0834, KEY_NUMERIC_6 }, + { 0x080e, KEY_NUMERIC_7 }, + { 0x080a, KEY_NUMERIC_8 }, + { 0x080c, KEY_NUMERIC_9 }, { 0x0815, KEY_VOLUMEUP }, { 0x0826, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c index 2f800dd5aa19..31fe1106b708 100644 --- a/drivers/media/rc/keymaps/rc-ati-x10.c +++ b/drivers/media/rc/keymaps/rc-ati-x10.c @@ -49,18 +49,18 @@ static struct rc_map_table ati_x10[] = { * has problems with keycodes greater than 255, so avoid those high * keycodes in default maps. */ - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, { 0x16, KEY_MENU }, /* "menu": DVD root menu */ /* KEY_NUMERIC_STAR? */ - { 0x17, KEY_0 }, + { 0x17, KEY_NUMERIC_0 }, { 0x18, KEY_SETUP }, /* "check": DVD setup menu */ /* KEY_NUMERIC_POUND? */ diff --git a/drivers/media/rc/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c index 5549c043cfe4..6467ff6e48d7 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-a16d.c +++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c @@ -11,17 +11,17 @@ static struct rc_map_table avermedia_a16d[] = { { 0x20, KEY_LIST}, { 0x00, KEY_POWER}, - { 0x28, KEY_1}, - { 0x18, KEY_2}, - { 0x38, KEY_3}, - { 0x24, KEY_4}, - { 0x14, KEY_5}, - { 0x34, KEY_6}, - { 0x2c, KEY_7}, - { 0x1c, KEY_8}, - { 0x3c, KEY_9}, + { 0x28, KEY_NUMERIC_1}, + { 0x18, KEY_NUMERIC_2}, + { 0x38, KEY_NUMERIC_3}, + { 0x24, KEY_NUMERIC_4}, + { 0x14, KEY_NUMERIC_5}, + { 0x34, KEY_NUMERIC_6}, + { 0x2c, KEY_NUMERIC_7}, + { 0x1c, KEY_NUMERIC_8}, + { 0x3c, KEY_NUMERIC_9}, { 0x12, KEY_SUBTITLE}, - { 0x22, KEY_0}, + { 0x22, KEY_NUMERIC_0}, { 0x32, KEY_REWIND}, { 0x3a, KEY_SHUFFLE}, { 0x02, KEY_PRINT}, diff --git a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c index 74edcd82e685..54fc6d9022c2 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-cardbus.c +++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c @@ -15,19 +15,19 @@ static struct rc_map_table avermedia_cardbus[] = { { 0x01, KEY_TUNER }, /* TV/FM */ { 0x03, KEY_TEXT }, /* Teletext */ { 0x04, KEY_EPG }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, { 0x08, KEY_AUDIO }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, { 0x0c, KEY_ZOOM }, /* Full screen */ - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x10, KEY_PAGEUP }, /* 16-CH PREV */ - { 0x11, KEY_0 }, + { 0x11, KEY_NUMERIC_0 }, { 0x12, KEY_INFO }, { 0x13, KEY_AGAIN }, /* CH RTN - channel return */ { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c index 796184160a48..92c6df3360b3 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-dvbt.c +++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c @@ -11,16 +11,16 @@ /* Matt Jesson or L */ { 0x0212, KEY_LEFT }, /* <- or R */ @@ -70,17 +70,17 @@ static struct rc_map_table avermedia_m135a[] = { { 0x0406, KEY_MUTE }, { 0x0408, KEY_MODE }, /* TV/FM */ - { 0x0409, KEY_1 }, - { 0x040a, KEY_2 }, - { 0x040b, KEY_3 }, - { 0x040c, KEY_4 }, - { 0x040d, KEY_5 }, - { 0x040e, KEY_6 }, - { 0x040f, KEY_7 }, - { 0x0410, KEY_8 }, - { 0x0411, KEY_9 }, + { 0x0409, KEY_NUMERIC_1 }, + { 0x040a, KEY_NUMERIC_2 }, + { 0x040b, KEY_NUMERIC_3 }, + { 0x040c, KEY_NUMERIC_4 }, + { 0x040d, KEY_NUMERIC_5 }, + { 0x040e, KEY_NUMERIC_6 }, + { 0x040f, KEY_NUMERIC_7 }, + { 0x0410, KEY_NUMERIC_8 }, + { 0x0411, KEY_NUMERIC_9 }, { 0x044c, KEY_DOT }, /* '.' */ - { 0x0412, KEY_0 }, + { 0x0412, KEY_NUMERIC_0 }, { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ { 0x0413, KEY_AUDIO }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c index 6a70aba92dfb..a970ed5a090b 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c +++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c @@ -18,17 +18,17 @@ static struct rc_map_table avermedia_m733a_rm_k6[] = { { 0x0406, KEY_MUTE }, { 0x0408, KEY_MODE }, /* TV/FM */ - { 0x0409, KEY_1 }, - { 0x040a, KEY_2 }, - { 0x040b, KEY_3 }, - { 0x040c, KEY_4 }, - { 0x040d, KEY_5 }, - { 0x040e, KEY_6 }, - { 0x040f, KEY_7 }, - { 0x0410, KEY_8 }, - { 0x0411, KEY_9 }, + { 0x0409, KEY_NUMERIC_1 }, + { 0x040a, KEY_NUMERIC_2 }, + { 0x040b, KEY_NUMERIC_3 }, + { 0x040c, KEY_NUMERIC_4 }, + { 0x040d, KEY_NUMERIC_5 }, + { 0x040e, KEY_NUMERIC_6 }, + { 0x040f, KEY_NUMERIC_7 }, + { 0x0410, KEY_NUMERIC_8 }, + { 0x0411, KEY_NUMERIC_9 }, { 0x044c, KEY_DOT }, /* '.' */ - { 0x0412, KEY_0 }, + { 0x0412, KEY_NUMERIC_0 }, { 0x0407, KEY_REFRESH }, /* Refresh/Reload */ { 0x0413, KEY_AUDIO }, diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c index 61348894c93b..cf8a4fd107f4 100644 --- a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c +++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c @@ -20,16 +20,16 @@ static struct rc_map_table avermedia_rm_ks[] = { { 0x0506, KEY_MUTE }, /* Mute */ { 0x0507, KEY_AGAIN }, /* Recall */ { 0x0508, KEY_VIDEO }, /* Source */ - { 0x0509, KEY_1 }, /* 1 */ - { 0x050a, KEY_2 }, /* 2 */ - { 0x050b, KEY_3 }, /* 3 */ - { 0x050c, KEY_4 }, /* 4 */ - { 0x050d, KEY_5 }, /* 5 */ - { 0x050e, KEY_6 }, /* 6 */ - { 0x050f, KEY_7 }, /* 7 */ - { 0x0510, KEY_8 }, /* 8 */ - { 0x0511, KEY_9 }, /* 9 */ - { 0x0512, KEY_0 }, /* 0 */ + { 0x0509, KEY_NUMERIC_1 }, /* 1 */ + { 0x050a, KEY_NUMERIC_2 }, /* 2 */ + { 0x050b, KEY_NUMERIC_3 }, /* 3 */ + { 0x050c, KEY_NUMERIC_4 }, /* 4 */ + { 0x050d, KEY_NUMERIC_5 }, /* 5 */ + { 0x050e, KEY_NUMERIC_6 }, /* 6 */ + { 0x050f, KEY_NUMERIC_7 }, /* 7 */ + { 0x0510, KEY_NUMERIC_8 }, /* 8 */ + { 0x0511, KEY_NUMERIC_9 }, /* 9 */ + { 0x0512, KEY_NUMERIC_0 }, /* 0 */ { 0x0513, KEY_AUDIO }, /* Audio */ { 0x0515, KEY_EPG }, /* EPG */ { 0x0516, KEY_PLAYPAUSE }, /* Play/Pause */ diff --git a/drivers/media/rc/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c index 631ff52564f0..f96f229b70bb 100644 --- a/drivers/media/rc/keymaps/rc-avermedia.c +++ b/drivers/media/rc/keymaps/rc-avermedia.c @@ -11,16 +11,16 @@ /* Alex Hermann */ static struct rc_map_table avermedia[] = { - { 0x28, KEY_1 }, - { 0x18, KEY_2 }, - { 0x38, KEY_3 }, - { 0x24, KEY_4 }, - { 0x14, KEY_5 }, - { 0x34, KEY_6 }, - { 0x2c, KEY_7 }, - { 0x1c, KEY_8 }, - { 0x3c, KEY_9 }, - { 0x22, KEY_0 }, + { 0x28, KEY_NUMERIC_1 }, + { 0x18, KEY_NUMERIC_2 }, + { 0x38, KEY_NUMERIC_3 }, + { 0x24, KEY_NUMERIC_4 }, + { 0x14, KEY_NUMERIC_5 }, + { 0x34, KEY_NUMERIC_6 }, + { 0x2c, KEY_NUMERIC_7 }, + { 0x1c, KEY_NUMERIC_8 }, + { 0x3c, KEY_NUMERIC_9 }, + { 0x22, KEY_NUMERIC_0 }, { 0x20, KEY_TV }, /* TV/FM */ { 0x10, KEY_CD }, /* CD */ diff --git a/drivers/media/rc/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c index 47ca8b7ea532..a3e2e945c769 100644 --- a/drivers/media/rc/keymaps/rc-avertv-303.c +++ b/drivers/media/rc/keymaps/rc-avertv-303.c @@ -11,16 +11,16 @@ /* AVERTV STUDIO 303 Remote */ static struct rc_map_table avertv_303[] = { - { 0x2a, KEY_1 }, - { 0x32, KEY_2 }, - { 0x3a, KEY_3 }, - { 0x4a, KEY_4 }, - { 0x52, KEY_5 }, - { 0x5a, KEY_6 }, - { 0x6a, KEY_7 }, - { 0x72, KEY_8 }, - { 0x7a, KEY_9 }, - { 0x0e, KEY_0 }, + { 0x2a, KEY_NUMERIC_1 }, + { 0x32, KEY_NUMERIC_2 }, + { 0x3a, KEY_NUMERIC_3 }, + { 0x4a, KEY_NUMERIC_4 }, + { 0x52, KEY_NUMERIC_5 }, + { 0x5a, KEY_NUMERIC_6 }, + { 0x6a, KEY_NUMERIC_7 }, + { 0x72, KEY_NUMERIC_8 }, + { 0x7a, KEY_NUMERIC_9 }, + { 0x0e, KEY_NUMERIC_0 }, { 0x02, KEY_POWER }, { 0x22, KEY_VIDEO }, diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c index 8e7e95306a5c..5fc8e4cd102e 100644 --- a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c +++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c @@ -10,18 +10,18 @@ static struct rc_map_table azurewave_ad_tu700[] = { { 0x0000, KEY_TAB }, /* Tab */ - { 0x0001, KEY_2 }, + { 0x0001, KEY_NUMERIC_2 }, { 0x0002, KEY_CHANNELDOWN }, - { 0x0003, KEY_1 }, + { 0x0003, KEY_NUMERIC_1 }, { 0x0004, KEY_MENU }, /* Record List */ { 0x0005, KEY_CHANNELUP }, - { 0x0006, KEY_3 }, + { 0x0006, KEY_NUMERIC_3 }, { 0x0007, KEY_SLEEP }, /* Hibernate */ { 0x0008, KEY_VIDEO }, /* A/V */ - { 0x0009, KEY_4 }, + { 0x0009, KEY_NUMERIC_4 }, { 0x000a, KEY_VOLUMEDOWN }, { 0x000c, KEY_CANCEL }, /* Cancel */ - { 0x000d, KEY_7 }, + { 0x000d, KEY_NUMERIC_7 }, { 0x000e, KEY_AGAIN }, /* Recall */ { 0x000f, KEY_TEXT }, /* Teletext */ { 0x0010, KEY_MUTE }, @@ -29,17 +29,17 @@ static struct rc_map_table azurewave_ad_tu700[] = { { 0x0012, KEY_FASTFORWARD }, /* FF >> */ { 0x0013, KEY_BACK }, /* Back */ { 0x0014, KEY_PLAY }, - { 0x0015, KEY_0 }, + { 0x0015, KEY_NUMERIC_0 }, { 0x0016, KEY_POWER2 }, /* [red power button] */ { 0x0017, KEY_FAVORITES }, /* Favorite List */ { 0x0018, KEY_RED }, - { 0x0019, KEY_8 }, + { 0x0019, KEY_NUMERIC_8 }, { 0x001a, KEY_STOP }, - { 0x001b, KEY_9 }, + { 0x001b, KEY_NUMERIC_9 }, { 0x001c, KEY_EPG }, /* Info/EPG */ - { 0x001d, KEY_5 }, + { 0x001d, KEY_NUMERIC_5 }, { 0x001e, KEY_VOLUMEUP }, - { 0x001f, KEY_6 }, + { 0x001f, KEY_NUMERIC_6 }, { 0x0040, KEY_REWIND }, /* FR << */ { 0x0041, KEY_PREVIOUS }, /* Replay */ { 0x0042, KEY_NEXT }, /* Skip */ diff --git a/drivers/media/rc/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c index b68380a76010..8579b3d5128d 100644 --- a/drivers/media/rc/keymaps/rc-behold-columbus.c +++ b/drivers/media/rc/keymaps/rc-behold-columbus.c @@ -37,24 +37,24 @@ static struct rc_map_table behold_columbus[] = { * 0x07 0x08 0x09 0x10 * * 7 8 9 Zoom * * */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, { 0x0D, KEY_SETUP }, /* Setup key */ - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, { 0x19, KEY_CAMERA }, /* Snapshot key */ - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x10, KEY_ZOOM }, /* 0x0A 0x00 0x0B 0x0C * * RECALL 0 ChannelUp VolumeUp * * */ { 0x0A, KEY_AGAIN }, - { 0x00, KEY_0 }, + { 0x00, KEY_NUMERIC_0 }, { 0x0B, KEY_CHANNELUP }, { 0x0C, KEY_VOLUMEUP }, diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c index 2b7cddb2f36d..28397ce05a7f 100644 --- a/drivers/media/rc/keymaps/rc-behold.c +++ b/drivers/media/rc/keymaps/rc-behold.c @@ -37,21 +37,21 @@ static struct rc_map_table behold[] = { * 0x07 0x08 0x09 * * 7 8 9 * * */ - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, /* 0x0a 0x00 0x17 * * RECALL 0 MODE * * */ { 0x866b0a, KEY_AGAIN }, - { 0x866b00, KEY_0 }, + { 0x866b00, KEY_NUMERIC_0 }, { 0x866b17, KEY_MODE }, /* 0x14 0x10 * diff --git a/drivers/media/rc/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c index 56f051af6154..6ca822256862 100644 --- a/drivers/media/rc/keymaps/rc-budget-ci-old.c +++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c @@ -16,16 +16,16 @@ */ static struct rc_map_table budget_ci_old[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_ENTER }, { 0x0b, KEY_RED }, { 0x0c, KEY_POWER }, /* RADIO on Hauppauge */ diff --git a/drivers/media/rc/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c index dacb13c53bb4..4433d28b219c 100644 --- a/drivers/media/rc/keymaps/rc-cinergy-1400.c +++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c @@ -12,16 +12,16 @@ static struct rc_map_table cinergy_1400[] = { { 0x01, KEY_POWER }, - { 0x02, KEY_1 }, - { 0x03, KEY_2 }, - { 0x04, KEY_3 }, - { 0x05, KEY_4 }, - { 0x06, KEY_5 }, - { 0x07, KEY_6 }, - { 0x08, KEY_7 }, - { 0x09, KEY_8 }, - { 0x0a, KEY_9 }, - { 0x0c, KEY_0 }, + { 0x02, KEY_NUMERIC_1 }, + { 0x03, KEY_NUMERIC_2 }, + { 0x04, KEY_NUMERIC_3 }, + { 0x05, KEY_NUMERIC_4 }, + { 0x06, KEY_NUMERIC_5 }, + { 0x07, KEY_NUMERIC_6 }, + { 0x08, KEY_NUMERIC_7 }, + { 0x09, KEY_NUMERIC_8 }, + { 0x0a, KEY_NUMERIC_9 }, + { 0x0c, KEY_NUMERIC_0 }, { 0x0b, KEY_VIDEO }, { 0x0d, KEY_REFRESH }, diff --git a/drivers/media/rc/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c index 6ab2e51b764d..b34a37b8fe61 100644 --- a/drivers/media/rc/keymaps/rc-cinergy.c +++ b/drivers/media/rc/keymaps/rc-cinergy.c @@ -9,16 +9,16 @@ #include static struct rc_map_table cinergy[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_POWER }, { 0x0b, KEY_MEDIA }, /* app */ diff --git a/drivers/media/rc/keymaps/rc-d680-dmb.c b/drivers/media/rc/keymaps/rc-d680-dmb.c index f67aa597a75b..d491a5e9750f 100644 --- a/drivers/media/rc/keymaps/rc-d680-dmb.c +++ b/drivers/media/rc/keymaps/rc-d680-dmb.c @@ -11,16 +11,16 @@ static struct rc_map_table rc_map_d680_dmb_table[] = { { 0x0038, KEY_SWITCHVIDEOMODE }, /* TV/AV */ { 0x080c, KEY_ZOOM }, - { 0x0800, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0802, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0804, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0806, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0808, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0800, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0802, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0804, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0806, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0808, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_MUTE }, { 0x0829, KEY_BACK }, { 0x0012, KEY_CHANNELUP }, diff --git a/drivers/media/rc/keymaps/rc-delock-61959.c b/drivers/media/rc/keymaps/rc-delock-61959.c index c60fc1e46fc5..529435e8d416 100644 --- a/drivers/media/rc/keymaps/rc-delock-61959.c +++ b/drivers/media/rc/keymaps/rc-delock-61959.c @@ -14,16 +14,16 @@ static struct rc_map_table delock_61959[] = { { 0x866b16, KEY_POWER2 }, /* Power */ { 0x866b0c, KEY_POWER }, /* Shut Down */ - { 0x866b00, KEY_1}, - { 0x866b01, KEY_2}, - { 0x866b02, KEY_3}, - { 0x866b03, KEY_4}, - { 0x866b04, KEY_5}, - { 0x866b05, KEY_6}, - { 0x866b06, KEY_7}, - { 0x866b07, KEY_8}, - { 0x866b08, KEY_9}, - { 0x866b14, KEY_0}, + { 0x866b00, KEY_NUMERIC_1}, + { 0x866b01, KEY_NUMERIC_2}, + { 0x866b02, KEY_NUMERIC_3}, + { 0x866b03, KEY_NUMERIC_4}, + { 0x866b04, KEY_NUMERIC_5}, + { 0x866b05, KEY_NUMERIC_6}, + { 0x866b06, KEY_NUMERIC_7}, + { 0x866b07, KEY_NUMERIC_8}, + { 0x866b08, KEY_NUMERIC_9}, + { 0x866b14, KEY_NUMERIC_0}, { 0x866b0a, KEY_ZOOM}, /* Full Screen */ { 0x866b10, KEY_CAMERA}, /* Photo */ diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c index 4ee801acb089..f1fcdf16f485 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-nec.c +++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c @@ -17,16 +17,16 @@ static struct rc_map_table dib0700_nec_table[] = { /* Key codes for the Pixelview SBTVD remote */ { 0x866b13, KEY_MUTE }, { 0x866b12, KEY_POWER }, - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, - { 0x866b00, KEY_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, + { 0x866b00, KEY_NUMERIC_0 }, { 0x866b0d, KEY_CHANNELUP }, { 0x866b19, KEY_CHANNELDOWN }, { 0x866b10, KEY_VOLUMEUP }, @@ -60,17 +60,17 @@ static struct rc_map_table dib0700_nec_table[] = { /* Key codes for the Elgato EyeTV Diversity silver remote */ { 0x4501, KEY_POWER }, { 0x4502, KEY_MUTE }, - { 0x4503, KEY_1 }, - { 0x4504, KEY_2 }, - { 0x4505, KEY_3 }, - { 0x4506, KEY_4 }, - { 0x4507, KEY_5 }, - { 0x4508, KEY_6 }, - { 0x4509, KEY_7 }, - { 0x450a, KEY_8 }, - { 0x450b, KEY_9 }, + { 0x4503, KEY_NUMERIC_1 }, + { 0x4504, KEY_NUMERIC_2 }, + { 0x4505, KEY_NUMERIC_3 }, + { 0x4506, KEY_NUMERIC_4 }, + { 0x4507, KEY_NUMERIC_5 }, + { 0x4508, KEY_NUMERIC_6 }, + { 0x4509, KEY_NUMERIC_7 }, + { 0x450a, KEY_NUMERIC_8 }, + { 0x450b, KEY_NUMERIC_9 }, { 0x450c, KEY_LAST }, - { 0x450d, KEY_0 }, + { 0x450d, KEY_NUMERIC_0 }, { 0x450e, KEY_ENTER }, { 0x450f, KEY_RED }, { 0x4510, KEY_CHANNELUP }, diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c index ef4085a0fda3..002fffcba95d 100644 --- a/drivers/media/rc/keymaps/rc-dib0700-rc5.c +++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c @@ -22,16 +22,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0x0709, KEY_VOLUMEDOWN }, { 0x0706, KEY_CHANNELUP }, { 0x070c, KEY_CHANNELDOWN }, - { 0x070f, KEY_1 }, - { 0x0715, KEY_2 }, - { 0x0710, KEY_3 }, - { 0x0718, KEY_4 }, - { 0x071b, KEY_5 }, - { 0x071e, KEY_6 }, - { 0x0711, KEY_7 }, - { 0x0721, KEY_8 }, - { 0x0712, KEY_9 }, - { 0x0727, KEY_0 }, + { 0x070f, KEY_NUMERIC_1 }, + { 0x0715, KEY_NUMERIC_2 }, + { 0x0710, KEY_NUMERIC_3 }, + { 0x0718, KEY_NUMERIC_4 }, + { 0x071b, KEY_NUMERIC_5 }, + { 0x071e, KEY_NUMERIC_6 }, + { 0x0711, KEY_NUMERIC_7 }, + { 0x0721, KEY_NUMERIC_8 }, + { 0x0712, KEY_NUMERIC_9 }, + { 0x0727, KEY_NUMERIC_0 }, { 0x0724, KEY_SCREEN }, /* 'Square' key */ { 0x072a, KEY_TEXT }, /* 'T' key */ { 0x072d, KEY_REWIND }, @@ -43,17 +43,17 @@ static struct rc_map_table dib0700_rc5_table[] = { /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */ { 0xeb01, KEY_POWER }, - { 0xeb02, KEY_1 }, - { 0xeb03, KEY_2 }, - { 0xeb04, KEY_3 }, - { 0xeb05, KEY_4 }, - { 0xeb06, KEY_5 }, - { 0xeb07, KEY_6 }, - { 0xeb08, KEY_7 }, - { 0xeb09, KEY_8 }, - { 0xeb0a, KEY_9 }, + { 0xeb02, KEY_NUMERIC_1 }, + { 0xeb03, KEY_NUMERIC_2 }, + { 0xeb04, KEY_NUMERIC_3 }, + { 0xeb05, KEY_NUMERIC_4 }, + { 0xeb06, KEY_NUMERIC_5 }, + { 0xeb07, KEY_NUMERIC_6 }, + { 0xeb08, KEY_NUMERIC_7 }, + { 0xeb09, KEY_NUMERIC_8 }, + { 0xeb0a, KEY_NUMERIC_9 }, { 0xeb0b, KEY_VIDEO }, - { 0xeb0c, KEY_0 }, + { 0xeb0c, KEY_NUMERIC_0 }, { 0xeb0d, KEY_REFRESH }, { 0xeb0f, KEY_EPG }, { 0xeb10, KEY_UP }, @@ -92,16 +92,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0xeb5c, KEY_NEXT }, /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */ - { 0x1e00, KEY_0 }, - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, + { 0x1e00, KEY_NUMERIC_0 }, + { 0x1e01, KEY_NUMERIC_1 }, + { 0x1e02, KEY_NUMERIC_2 }, + { 0x1e03, KEY_NUMERIC_3 }, + { 0x1e04, KEY_NUMERIC_4 }, + { 0x1e05, KEY_NUMERIC_5 }, + { 0x1e06, KEY_NUMERIC_6 }, + { 0x1e07, KEY_NUMERIC_7 }, + { 0x1e08, KEY_NUMERIC_8 }, + { 0x1e09, KEY_NUMERIC_9 }, { 0x1e0a, KEY_KPASTERISK }, { 0x1e0b, KEY_RED }, { 0x1e0c, KEY_RADIO }, @@ -144,16 +144,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0x0f4e, KEY_PRINT }, /* PREVIEW */ { 0x0840, KEY_SCREEN }, /* full screen toggle*/ { 0x0f71, KEY_DOT }, /* frequency */ - { 0x0743, KEY_0 }, - { 0x0c41, KEY_1 }, - { 0x0443, KEY_2 }, - { 0x0b7f, KEY_3 }, - { 0x0e41, KEY_4 }, - { 0x0643, KEY_5 }, - { 0x097f, KEY_6 }, - { 0x0d7e, KEY_7 }, - { 0x057c, KEY_8 }, - { 0x0a40, KEY_9 }, + { 0x0743, KEY_NUMERIC_0 }, + { 0x0c41, KEY_NUMERIC_1 }, + { 0x0443, KEY_NUMERIC_2 }, + { 0x0b7f, KEY_NUMERIC_3 }, + { 0x0e41, KEY_NUMERIC_4 }, + { 0x0643, KEY_NUMERIC_5 }, + { 0x097f, KEY_NUMERIC_6 }, + { 0x0d7e, KEY_NUMERIC_7 }, + { 0x057c, KEY_NUMERIC_8 }, + { 0x0a40, KEY_NUMERIC_9 }, { 0x0e4e, KEY_CLEAR }, { 0x047c, KEY_CHANNEL }, /* show channel number */ { 0x0f41, KEY_LAST }, /* recall */ @@ -168,16 +168,16 @@ static struct rc_map_table dib0700_rc5_table[] = { { 0x007d, KEY_CHANNELDOWN }, /* Key codes for Nova-TD "credit card" remote control. */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, + { 0x1d00, KEY_NUMERIC_0 }, + { 0x1d01, KEY_NUMERIC_1 }, + { 0x1d02, KEY_NUMERIC_2 }, + { 0x1d03, KEY_NUMERIC_3 }, + { 0x1d04, KEY_NUMERIC_4 }, + { 0x1d05, KEY_NUMERIC_5 }, + { 0x1d06, KEY_NUMERIC_6 }, + { 0x1d07, KEY_NUMERIC_7 }, + { 0x1d08, KEY_NUMERIC_8 }, + { 0x1d09, KEY_NUMERIC_9 }, { 0x1d0a, KEY_TEXT }, { 0x1d0d, KEY_MENU }, { 0x1d0f, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c index f4d0799dcc72..2466d8c50226 100644 --- a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c +++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c @@ -12,14 +12,14 @@ static struct rc_map_table digitalnow_tinytwin[] = { { 0x0000, KEY_MUTE }, /* [symbol speaker] */ { 0x0001, KEY_VOLUMEUP }, { 0x0002, KEY_POWER2 }, /* TV [power button] */ - { 0x0003, KEY_2 }, - { 0x0004, KEY_3 }, - { 0x0005, KEY_4 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, + { 0x0003, KEY_NUMERIC_2 }, + { 0x0004, KEY_NUMERIC_3 }, + { 0x0005, KEY_NUMERIC_4 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, { 0x0009, KEY_NUMERIC_STAR }, /* [*] */ - { 0x000a, KEY_0 }, + { 0x000a, KEY_NUMERIC_0 }, { 0x000b, KEY_NUMERIC_POUND }, /* [#] */ { 0x000c, KEY_RIGHT }, /* [right arrow] */ { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */ @@ -36,10 +36,10 @@ static struct rc_map_table digitalnow_tinytwin[] = { { 0x0019, KEY_BLUE }, /* [blue] MyTV */ { 0x001a, KEY_REWIND }, /* REW [<<] */ { 0x001b, KEY_PLAY }, /* PLAY */ - { 0x001c, KEY_5 }, - { 0x001d, KEY_9 }, + { 0x001c, KEY_NUMERIC_5 }, + { 0x001d, KEY_NUMERIC_9 }, { 0x001e, KEY_VOLUMEDOWN }, - { 0x001f, KEY_1 }, + { 0x001f, KEY_NUMERIC_1 }, { 0x0040, KEY_STOP }, /* STOP */ { 0x0042, KEY_PAUSE }, /* PAUSE */ { 0x0043, KEY_SCREEN }, /* Aspect */ diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c index 6849f1a5721c..65bc8ad7e52c 100644 --- a/drivers/media/rc/keymaps/rc-digittrade.c +++ b/drivers/media/rc/keymaps/rc-digittrade.c @@ -14,11 +14,11 @@ /* Digittrade DVB-T USB Stick */ static struct rc_map_table digittrade[] = { - { 0x0000, KEY_9 }, + { 0x0000, KEY_NUMERIC_9 }, { 0x0001, KEY_EPG }, /* EPG */ { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */ { 0x0003, KEY_TEXT }, /* TELETEXT */ - { 0x0004, KEY_8 }, + { 0x0004, KEY_NUMERIC_8 }, { 0x0005, KEY_MUTE }, /* MUTE */ { 0x0006, KEY_POWER2 }, /* POWER */ { 0x0009, KEY_ZOOM }, /* FULLSCREEN */ @@ -26,22 +26,22 @@ static struct rc_map_table digittrade[] = { { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */ { 0x000e, KEY_STOP }, /* STOP */ { 0x0010, KEY_OK }, /* RETURN */ - { 0x0011, KEY_2 }, - { 0x0012, KEY_4 }, - { 0x0015, KEY_3 }, - { 0x0016, KEY_5 }, + { 0x0011, KEY_NUMERIC_2 }, + { 0x0012, KEY_NUMERIC_4 }, + { 0x0015, KEY_NUMERIC_3 }, + { 0x0016, KEY_NUMERIC_5 }, { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */ { 0x0019, KEY_CHANNELUP }, /* CH Up */ { 0x001a, KEY_PAUSE }, /* PAUSE */ - { 0x001b, KEY_1 }, + { 0x001b, KEY_NUMERIC_1 }, { 0x001d, KEY_AUDIO }, /* DUAL SOUND */ { 0x001e, KEY_PLAY }, /* PLAY */ { 0x001f, KEY_CAMERA }, /* SNAPSHOT */ { 0x0040, KEY_VOLUMEUP }, /* Vol Up */ - { 0x0048, KEY_7 }, - { 0x004c, KEY_6 }, + { 0x0048, KEY_NUMERIC_7 }, + { 0x004c, KEY_NUMERIC_6 }, { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */ - { 0x0054, KEY_0 }, + { 0x0054, KEY_NUMERIC_0 }, }; static struct rc_map_list digittrade_map = { diff --git a/drivers/media/rc/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c index d853cd9a0936..cd0b985c994d 100644 --- a/drivers/media/rc/keymaps/rc-dm1105-nec.c +++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c @@ -15,16 +15,16 @@ static struct rc_map_table dm1105_nec[] = { { 0x0a, KEY_POWER2}, /* power */ { 0x0c, KEY_MUTE}, /* mute */ - { 0x11, KEY_1}, - { 0x12, KEY_2}, - { 0x13, KEY_3}, - { 0x14, KEY_4}, - { 0x15, KEY_5}, - { 0x16, KEY_6}, - { 0x17, KEY_7}, - { 0x18, KEY_8}, - { 0x19, KEY_9}, - { 0x10, KEY_0}, + { 0x11, KEY_NUMERIC_1}, + { 0x12, KEY_NUMERIC_2}, + { 0x13, KEY_NUMERIC_3}, + { 0x14, KEY_NUMERIC_4}, + { 0x15, KEY_NUMERIC_5}, + { 0x16, KEY_NUMERIC_6}, + { 0x17, KEY_NUMERIC_7}, + { 0x18, KEY_NUMERIC_8}, + { 0x19, KEY_NUMERIC_9}, + { 0x10, KEY_NUMERIC_0}, { 0x1c, KEY_CHANNELUP}, /* ch+ */ { 0x0f, KEY_CHANNELDOWN}, /* ch- */ { 0x1a, KEY_VOLUMEUP}, /* vol+ */ diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c index cdc1d8c990cb..a82f64dc9411 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c @@ -13,16 +13,16 @@ static struct rc_map_table dntv_live_dvb_t[] = { { 0x00, KEY_ESC }, /* 'go up a level?' */ /* Keys 0 to 9 */ - { 0x0a, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x0a, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0b, KEY_TUNER }, /* tv/fm */ { 0x0c, KEY_SEARCH }, /* scan */ diff --git a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c index 38e1d1b837da..d3f5048a0220 100644 --- a/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c +++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c @@ -18,17 +18,17 @@ static struct rc_map_table dntv_live_dvbt_pro[] = { { 0x58, KEY_TUNER }, /* digital Radio */ { 0x5a, KEY_RADIO }, /* FM radio */ { 0x59, KEY_DVD }, /* dvd menu */ - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x1d, KEY_NUMERIC_5 }, + { 0x1f, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x19, KEY_NUMERIC_8 }, + { 0x1b, KEY_NUMERIC_9 }, { 0x0c, KEY_CANCEL }, - { 0x15, KEY_0 }, + { 0x15, KEY_NUMERIC_0 }, { 0x4a, KEY_CLEAR }, { 0x13, KEY_BACK }, { 0x00, KEY_TAB }, diff --git a/drivers/media/rc/keymaps/rc-dtt200u.c b/drivers/media/rc/keymaps/rc-dtt200u.c index 86fd6a1668af..e7f87baa3212 100644 --- a/drivers/media/rc/keymaps/rc-dtt200u.c +++ b/drivers/media/rc/keymaps/rc-dtt200u.c @@ -12,21 +12,21 @@ static struct rc_map_table dtt200u_table[] = { { 0x8001, KEY_MUTE }, { 0x8002, KEY_CHANNELDOWN }, { 0x8003, KEY_VOLUMEDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, + { 0x8004, KEY_NUMERIC_1 }, + { 0x8005, KEY_NUMERIC_2 }, + { 0x8006, KEY_NUMERIC_3 }, + { 0x8007, KEY_NUMERIC_4 }, + { 0x8008, KEY_NUMERIC_5 }, + { 0x8009, KEY_NUMERIC_6 }, + { 0x800a, KEY_NUMERIC_7 }, { 0x800c, KEY_ZOOM }, - { 0x800d, KEY_0 }, + { 0x800d, KEY_NUMERIC_0 }, { 0x800e, KEY_SELECT }, { 0x8012, KEY_POWER }, { 0x801a, KEY_CHANNELUP }, - { 0x801b, KEY_8 }, + { 0x801b, KEY_NUMERIC_8 }, { 0x801e, KEY_VOLUMEUP }, - { 0x801f, KEY_9 }, + { 0x801f, KEY_NUMERIC_9 }, }; static struct rc_map_list dtt200u_map = { diff --git a/drivers/media/rc/keymaps/rc-dvbsky.c b/drivers/media/rc/keymaps/rc-dvbsky.c index 4b61f60a4854..f5063af2e5bc 100644 --- a/drivers/media/rc/keymaps/rc-dvbsky.c +++ b/drivers/media/rc/keymaps/rc-dvbsky.c @@ -13,16 +13,16 @@ */ static struct rc_map_table rc5_dvbsky[] = { - { 0x0000, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0000, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_MUTE }, { 0x000d, KEY_OK }, { 0x000b, KEY_STOP }, diff --git a/drivers/media/rc/keymaps/rc-dvico-mce.c b/drivers/media/rc/keymaps/rc-dvico-mce.c index 8342c32f58fd..b1bb8cdb3705 100644 --- a/drivers/media/rc/keymaps/rc-dvico-mce.c +++ b/drivers/media/rc/keymaps/rc-dvico-mce.c @@ -35,17 +35,17 @@ static struct rc_map_table rc_map_dvico_mce_table[] = { { 0x0152, KEY_CAMERA }, { 0x015a, KEY_TUNER }, /* Live */ { 0x0119, KEY_OPEN }, - { 0x010b, KEY_1 }, - { 0x0117, KEY_2 }, - { 0x011b, KEY_3 }, - { 0x0107, KEY_4 }, - { 0x0150, KEY_5 }, - { 0x0154, KEY_6 }, - { 0x0148, KEY_7 }, - { 0x014c, KEY_8 }, - { 0x0158, KEY_9 }, + { 0x010b, KEY_NUMERIC_1 }, + { 0x0117, KEY_NUMERIC_2 }, + { 0x011b, KEY_NUMERIC_3 }, + { 0x0107, KEY_NUMERIC_4 }, + { 0x0150, KEY_NUMERIC_5 }, + { 0x0154, KEY_NUMERIC_6 }, + { 0x0148, KEY_NUMERIC_7 }, + { 0x014c, KEY_NUMERIC_8 }, + { 0x0158, KEY_NUMERIC_9 }, { 0x0113, KEY_ANGLE }, /* Aspect */ - { 0x0103, KEY_0 }, + { 0x0103, KEY_NUMERIC_0 }, { 0x011f, KEY_ZOOM }, { 0x0143, KEY_REWIND }, { 0x0147, KEY_PLAYPAUSE }, diff --git a/drivers/media/rc/keymaps/rc-dvico-portable.c b/drivers/media/rc/keymaps/rc-dvico-portable.c index 366bd10bf987..ec12ba6995dc 100644 --- a/drivers/media/rc/keymaps/rc-dvico-portable.c +++ b/drivers/media/rc/keymaps/rc-dvico-portable.c @@ -24,17 +24,17 @@ static struct rc_map_table rc_map_dvico_portable_table[] = { { 0x0316, KEY_CAMERA }, { 0x0340, KEY_TUNER }, /* ATV/DTV */ { 0x0345, KEY_OPEN }, - { 0x0319, KEY_1 }, - { 0x0318, KEY_2 }, - { 0x031b, KEY_3 }, - { 0x031a, KEY_4 }, - { 0x0358, KEY_5 }, - { 0x0359, KEY_6 }, - { 0x0315, KEY_7 }, - { 0x0314, KEY_8 }, - { 0x0317, KEY_9 }, + { 0x0319, KEY_NUMERIC_1 }, + { 0x0318, KEY_NUMERIC_2 }, + { 0x031b, KEY_NUMERIC_3 }, + { 0x031a, KEY_NUMERIC_4 }, + { 0x0358, KEY_NUMERIC_5 }, + { 0x0359, KEY_NUMERIC_6 }, + { 0x0315, KEY_NUMERIC_7 }, + { 0x0314, KEY_NUMERIC_8 }, + { 0x0317, KEY_NUMERIC_9 }, { 0x0344, KEY_ANGLE }, /* Aspect */ - { 0x0355, KEY_0 }, + { 0x0355, KEY_NUMERIC_0 }, { 0x0307, KEY_ZOOM }, { 0x030a, KEY_REWIND }, { 0x0308, KEY_PLAYPAUSE }, diff --git a/drivers/media/rc/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c index cbbba21484fb..a1f59aa6ff23 100644 --- a/drivers/media/rc/keymaps/rc-em-terratec.c +++ b/drivers/media/rc/keymaps/rc-em-terratec.c @@ -13,19 +13,19 @@ static struct rc_map_table em_terratec[] = { { 0x02, KEY_SELECT }, { 0x03, KEY_MUTE }, { 0x04, KEY_POWER }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, { 0x08, KEY_CHANNELUP }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, { 0x0c, KEY_CHANNELDOWN }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x10, KEY_VOLUMEUP }, - { 0x11, KEY_0 }, + { 0x11, KEY_NUMERIC_0 }, { 0x12, KEY_MENU }, { 0x13, KEY_PRINT }, { 0x14, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c index 057c13b765ef..7a00471b6005 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c @@ -16,16 +16,16 @@ static struct rc_map_table encore_enltv_fm53[] = { { 0x10, KEY_POWER2}, { 0x06, KEY_MUTE}, - { 0x09, KEY_1}, - { 0x1d, KEY_2}, - { 0x1f, KEY_3}, - { 0x19, KEY_4}, - { 0x1b, KEY_5}, - { 0x11, KEY_6}, - { 0x17, KEY_7}, - { 0x12, KEY_8}, - { 0x16, KEY_9}, - { 0x48, KEY_0}, + { 0x09, KEY_NUMERIC_1}, + { 0x1d, KEY_NUMERIC_2}, + { 0x1f, KEY_NUMERIC_3}, + { 0x19, KEY_NUMERIC_4}, + { 0x1b, KEY_NUMERIC_5}, + { 0x11, KEY_NUMERIC_6}, + { 0x17, KEY_NUMERIC_7}, + { 0x12, KEY_NUMERIC_8}, + { 0x16, KEY_NUMERIC_9}, + { 0x48, KEY_NUMERIC_0}, { 0x04, KEY_LIST}, /* -/-- */ { 0x40, KEY_LAST}, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c index 5b4e832d5fac..712210097b4d 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv.c @@ -22,16 +22,16 @@ static struct rc_map_table encore_enltv[] = { { 0x01, KEY_AUDIO }, /* music */ { 0x02, KEY_CAMERA }, /* picture */ - { 0x1f, KEY_1 }, - { 0x03, KEY_2 }, - { 0x04, KEY_3 }, - { 0x05, KEY_4 }, - { 0x1c, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x1d, KEY_9 }, - { 0x0a, KEY_0 }, + { 0x1f, KEY_NUMERIC_1 }, + { 0x03, KEY_NUMERIC_2 }, + { 0x04, KEY_NUMERIC_3 }, + { 0x05, KEY_NUMERIC_4 }, + { 0x1c, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x1d, KEY_NUMERIC_9 }, + { 0x0a, KEY_NUMERIC_0 }, { 0x09, KEY_LIST }, /* -/-- */ { 0x0b, KEY_LAST }, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c index cd0555924456..a08470b4f187 100644 --- a/drivers/media/rc/keymaps/rc-encore-enltv2.c +++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c @@ -14,16 +14,16 @@ static struct rc_map_table encore_enltv2[] = { { 0x4c, KEY_POWER2 }, { 0x4a, KEY_TUNER }, - { 0x40, KEY_1 }, - { 0x60, KEY_2 }, - { 0x50, KEY_3 }, - { 0x70, KEY_4 }, - { 0x48, KEY_5 }, - { 0x68, KEY_6 }, - { 0x58, KEY_7 }, - { 0x78, KEY_8 }, - { 0x44, KEY_9 }, - { 0x54, KEY_0 }, + { 0x40, KEY_NUMERIC_1 }, + { 0x60, KEY_NUMERIC_2 }, + { 0x50, KEY_NUMERIC_3 }, + { 0x70, KEY_NUMERIC_4 }, + { 0x48, KEY_NUMERIC_5 }, + { 0x68, KEY_NUMERIC_6 }, + { 0x58, KEY_NUMERIC_7 }, + { 0x78, KEY_NUMERIC_8 }, + { 0x44, KEY_NUMERIC_9 }, + { 0x54, KEY_NUMERIC_0 }, { 0x64, KEY_LAST }, /* +100 */ { 0x4e, KEY_AGAIN }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c index 0e481d51fcb5..4e494d953e33 100644 --- a/drivers/media/rc/keymaps/rc-eztv.c +++ b/drivers/media/rc/keymaps/rc-eztv.c @@ -46,16 +46,16 @@ static struct rc_map_table eztv[] = { { 0x2d, KEY_PLAY }, /* play */ { 0x2e, KEY_CAMERA }, /* snapshot / shuffle */ - { 0x00, KEY_0 }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x2a, KEY_VOLUMEUP }, { 0x11, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c index 45940d7c92d0..202a1fbd1935 100644 --- a/drivers/media/rc/keymaps/rc-flydvb.c +++ b/drivers/media/rc/keymaps/rc-flydvb.c @@ -12,17 +12,17 @@ static struct rc_map_table flydvb[] = { { 0x01, KEY_ZOOM }, /* Full Screen */ { 0x00, KEY_POWER }, /* Power */ - { 0x03, KEY_1 }, - { 0x04, KEY_2 }, - { 0x05, KEY_3 }, - { 0x07, KEY_4 }, - { 0x08, KEY_5 }, - { 0x09, KEY_6 }, - { 0x0b, KEY_7 }, - { 0x0c, KEY_8 }, - { 0x0d, KEY_9 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x04, KEY_NUMERIC_2 }, + { 0x05, KEY_NUMERIC_3 }, + { 0x07, KEY_NUMERIC_4 }, + { 0x08, KEY_NUMERIC_5 }, + { 0x09, KEY_NUMERIC_6 }, + { 0x0b, KEY_NUMERIC_7 }, + { 0x0c, KEY_NUMERIC_8 }, + { 0x0d, KEY_NUMERIC_9 }, { 0x06, KEY_AGAIN }, /* Recall */ - { 0x0f, KEY_0 }, + { 0x0f, KEY_NUMERIC_0 }, { 0x10, KEY_MUTE }, /* Mute */ { 0x02, KEY_RADIO }, /* TV/Radio */ { 0x1b, KEY_LANGUAGE }, /* SAP (Second Audio Program) */ diff --git a/drivers/media/rc/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c index b2d4e4c7b192..a44467fb15cb 100644 --- a/drivers/media/rc/keymaps/rc-flyvideo.c +++ b/drivers/media/rc/keymaps/rc-flyvideo.c @@ -9,16 +9,16 @@ #include static struct rc_map_table flyvideo[] = { - { 0x0f, KEY_0 }, - { 0x03, KEY_1 }, - { 0x04, KEY_2 }, - { 0x05, KEY_3 }, - { 0x07, KEY_4 }, - { 0x08, KEY_5 }, - { 0x09, KEY_6 }, - { 0x0b, KEY_7 }, - { 0x0c, KEY_8 }, - { 0x0d, KEY_9 }, + { 0x0f, KEY_NUMERIC_0 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x04, KEY_NUMERIC_2 }, + { 0x05, KEY_NUMERIC_3 }, + { 0x07, KEY_NUMERIC_4 }, + { 0x08, KEY_NUMERIC_5 }, + { 0x09, KEY_NUMERIC_6 }, + { 0x0b, KEY_NUMERIC_7 }, + { 0x0c, KEY_NUMERIC_8 }, + { 0x0d, KEY_NUMERIC_9 }, { 0x0e, KEY_MODE }, /* Air/Cable */ { 0x11, KEY_VIDEO }, /* Video */ diff --git a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c index 1c63fc7d4576..253199f5531a 100644 --- a/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c +++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c @@ -12,16 +12,16 @@ static struct rc_map_table fusionhdtv_mce[] = { - { 0x0b, KEY_1 }, - { 0x17, KEY_2 }, - { 0x1b, KEY_3 }, - { 0x07, KEY_4 }, - { 0x50, KEY_5 }, - { 0x54, KEY_6 }, - { 0x48, KEY_7 }, - { 0x4c, KEY_8 }, - { 0x58, KEY_9 }, - { 0x03, KEY_0 }, + { 0x0b, KEY_NUMERIC_1 }, + { 0x17, KEY_NUMERIC_2 }, + { 0x1b, KEY_NUMERIC_3 }, + { 0x07, KEY_NUMERIC_4 }, + { 0x50, KEY_NUMERIC_5 }, + { 0x54, KEY_NUMERIC_6 }, + { 0x48, KEY_NUMERIC_7 }, + { 0x4c, KEY_NUMERIC_8 }, + { 0x58, KEY_NUMERIC_9 }, + { 0x03, KEY_NUMERIC_0 }, { 0x5e, KEY_OK }, { 0x51, KEY_UP }, diff --git a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c index 4a0a9786914f..c630ef306f11 100644 --- a/drivers/media/rc/keymaps/rc-gadmei-rm008z.c +++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c @@ -21,16 +21,16 @@ static struct rc_map_table gadmei_rm008z[] = { { 0x0b, KEY_AUDIO}, /* SV */ { 0x0f, KEY_RADIO}, /* FM */ - { 0x00, KEY_1}, - { 0x01, KEY_2}, - { 0x02, KEY_3}, - { 0x03, KEY_4}, - { 0x04, KEY_5}, - { 0x05, KEY_6}, - { 0x06, KEY_7}, - { 0x07, KEY_8}, - { 0x08, KEY_9}, - { 0x09, KEY_0}, + { 0x00, KEY_NUMERIC_1}, + { 0x01, KEY_NUMERIC_2}, + { 0x02, KEY_NUMERIC_3}, + { 0x03, KEY_NUMERIC_4}, + { 0x04, KEY_NUMERIC_5}, + { 0x05, KEY_NUMERIC_6}, + { 0x06, KEY_NUMERIC_7}, + { 0x07, KEY_NUMERIC_8}, + { 0x08, KEY_NUMERIC_9}, + { 0x09, KEY_NUMERIC_0}, { 0x0a, KEY_INFO}, /* OSD */ { 0x1c, KEY_BACKSPACE}, /* LAST */ diff --git a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c index cc876a85cc31..c966c130b05d 100644 --- a/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c +++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c @@ -15,16 +15,16 @@ static struct rc_map_table genius_tvgo_a11mce[] = { /* Keys 0 to 9 */ - { 0x48, KEY_0 }, - { 0x09, KEY_1 }, - { 0x1d, KEY_2 }, - { 0x1f, KEY_3 }, - { 0x19, KEY_4 }, - { 0x1b, KEY_5 }, - { 0x11, KEY_6 }, - { 0x17, KEY_7 }, - { 0x12, KEY_8 }, - { 0x16, KEY_9 }, + { 0x48, KEY_NUMERIC_0 }, + { 0x09, KEY_NUMERIC_1 }, + { 0x1d, KEY_NUMERIC_2 }, + { 0x1f, KEY_NUMERIC_3 }, + { 0x19, KEY_NUMERIC_4 }, + { 0x1b, KEY_NUMERIC_5 }, + { 0x11, KEY_NUMERIC_6 }, + { 0x17, KEY_NUMERIC_7 }, + { 0x12, KEY_NUMERIC_8 }, + { 0x16, KEY_NUMERIC_9 }, { 0x54, KEY_RECORD }, /* recording */ { 0x06, KEY_MUTE }, /* mute */ diff --git a/drivers/media/rc/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c index 6b94bd39d977..0dc4ef36d76f 100644 --- a/drivers/media/rc/keymaps/rc-gotview7135.c +++ b/drivers/media/rc/keymaps/rc-gotview7135.c @@ -14,16 +14,16 @@ static struct rc_map_table gotview7135[] = { { 0x11, KEY_POWER }, { 0x35, KEY_TV }, - { 0x1b, KEY_0 }, - { 0x29, KEY_1 }, - { 0x19, KEY_2 }, - { 0x39, KEY_3 }, - { 0x1f, KEY_4 }, - { 0x2c, KEY_5 }, - { 0x21, KEY_6 }, - { 0x24, KEY_7 }, - { 0x18, KEY_8 }, - { 0x2b, KEY_9 }, + { 0x1b, KEY_NUMERIC_0 }, + { 0x29, KEY_NUMERIC_1 }, + { 0x19, KEY_NUMERIC_2 }, + { 0x39, KEY_NUMERIC_3 }, + { 0x1f, KEY_NUMERIC_4 }, + { 0x2c, KEY_NUMERIC_5 }, + { 0x21, KEY_NUMERIC_6 }, + { 0x24, KEY_NUMERIC_7 }, + { 0x18, KEY_NUMERIC_8 }, + { 0x2b, KEY_NUMERIC_9 }, { 0x3b, KEY_AGAIN }, /* LOOP */ { 0x06, KEY_AUDIO }, { 0x31, KEY_PRINT }, /* PREVIEW */ diff --git a/drivers/media/rc/keymaps/rc-hauppauge.c b/drivers/media/rc/keymaps/rc-hauppauge.c index c117e9fc2697..82552360c3c3 100644 --- a/drivers/media/rc/keymaps/rc-hauppauge.c +++ b/drivers/media/rc/keymaps/rc-hauppauge.c @@ -67,20 +67,20 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1e30, KEY_PAUSE }, /* pause */ { 0x1e1e, KEY_NEXTSONG }, /* skip >| */ - { 0x1e01, KEY_1 }, - { 0x1e02, KEY_2 }, - { 0x1e03, KEY_3 }, + { 0x1e01, KEY_NUMERIC_1 }, + { 0x1e02, KEY_NUMERIC_2 }, + { 0x1e03, KEY_NUMERIC_3 }, - { 0x1e04, KEY_4 }, - { 0x1e05, KEY_5 }, - { 0x1e06, KEY_6 }, + { 0x1e04, KEY_NUMERIC_4 }, + { 0x1e05, KEY_NUMERIC_5 }, + { 0x1e06, KEY_NUMERIC_6 }, - { 0x1e07, KEY_7 }, - { 0x1e08, KEY_8 }, - { 0x1e09, KEY_9 }, + { 0x1e07, KEY_NUMERIC_7 }, + { 0x1e08, KEY_NUMERIC_8 }, + { 0x1e09, KEY_NUMERIC_9 }, { 0x1e0a, KEY_TEXT }, /* keypad asterisk as well */ - { 0x1e00, KEY_0 }, + { 0x1e00, KEY_NUMERIC_0 }, { 0x1e0e, KEY_SUBTITLE }, /* also the Pound key (#) */ { 0x1e0b, KEY_RED }, /* red button */ @@ -96,16 +96,16 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1f3b, KEY_SELECT }, /* GO */ /* Keys 0 to 9 */ - { 0x1f00, KEY_0 }, - { 0x1f01, KEY_1 }, - { 0x1f02, KEY_2 }, - { 0x1f03, KEY_3 }, - { 0x1f04, KEY_4 }, - { 0x1f05, KEY_5 }, - { 0x1f06, KEY_6 }, - { 0x1f07, KEY_7 }, - { 0x1f08, KEY_8 }, - { 0x1f09, KEY_9 }, + { 0x1f00, KEY_NUMERIC_0 }, + { 0x1f01, KEY_NUMERIC_1 }, + { 0x1f02, KEY_NUMERIC_2 }, + { 0x1f03, KEY_NUMERIC_3 }, + { 0x1f04, KEY_NUMERIC_4 }, + { 0x1f05, KEY_NUMERIC_5 }, + { 0x1f06, KEY_NUMERIC_6 }, + { 0x1f07, KEY_NUMERIC_7 }, + { 0x1f08, KEY_NUMERIC_8 }, + { 0x1f09, KEY_NUMERIC_9 }, { 0x1f1f, KEY_EXIT }, /* back/exit */ { 0x1f0d, KEY_MENU }, @@ -140,16 +140,16 @@ static struct rc_map_table rc5_hauppauge_new[] = { * Keycodes for DSR-0112 remote bundled with Haupauge MiniStick * Keycodes start with address = 0x1d */ - { 0x1d00, KEY_0 }, - { 0x1d01, KEY_1 }, - { 0x1d02, KEY_2 }, - { 0x1d03, KEY_3 }, - { 0x1d04, KEY_4 }, - { 0x1d05, KEY_5 }, - { 0x1d06, KEY_6 }, - { 0x1d07, KEY_7 }, - { 0x1d08, KEY_8 }, - { 0x1d09, KEY_9 }, + { 0x1d00, KEY_NUMERIC_0 }, + { 0x1d01, KEY_NUMERIC_1 }, + { 0x1d02, KEY_NUMERIC_2 }, + { 0x1d03, KEY_NUMERIC_3 }, + { 0x1d04, KEY_NUMERIC_4 }, + { 0x1d05, KEY_NUMERIC_5 }, + { 0x1d06, KEY_NUMERIC_6 }, + { 0x1d07, KEY_NUMERIC_7 }, + { 0x1d08, KEY_NUMERIC_8 }, + { 0x1d09, KEY_NUMERIC_9 }, { 0x1d0a, KEY_TEXT }, { 0x1d0d, KEY_MENU }, { 0x1d0f, KEY_MUTE }, @@ -190,16 +190,16 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x1c17, KEY_RIGHT }, { 0x1c25, KEY_OK }, - { 0x1c00, KEY_0 }, - { 0x1c01, KEY_1 }, - { 0x1c02, KEY_2 }, - { 0x1c03, KEY_3 }, - { 0x1c04, KEY_4 }, - { 0x1c05, KEY_5 }, - { 0x1c06, KEY_6 }, - { 0x1c07, KEY_7 }, - { 0x1c08, KEY_8 }, - { 0x1c09, KEY_9 }, + { 0x1c00, KEY_NUMERIC_0 }, + { 0x1c01, KEY_NUMERIC_1 }, + { 0x1c02, KEY_NUMERIC_2 }, + { 0x1c03, KEY_NUMERIC_3 }, + { 0x1c04, KEY_NUMERIC_4 }, + { 0x1c05, KEY_NUMERIC_5 }, + { 0x1c06, KEY_NUMERIC_6 }, + { 0x1c07, KEY_NUMERIC_7 }, + { 0x1c08, KEY_NUMERIC_8 }, + { 0x1c09, KEY_NUMERIC_9 }, { 0x1c1f, KEY_EXIT }, /* BACK */ { 0x1c0d, KEY_MENU }, @@ -246,20 +246,20 @@ static struct rc_map_table rc5_hauppauge_new[] = { { 0x0021, KEY_CHANNELDOWN }, { 0x0022, KEY_VIDEO }, /* source */ - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x001e, KEY_RED }, /* Reserved */ - { 0x0000, KEY_0 }, + { 0x0000, KEY_NUMERIC_0 }, { 0x0026, KEY_SLEEP }, /* Minimize */ }; diff --git a/drivers/media/rc/keymaps/rc-hisi-poplar.c b/drivers/media/rc/keymaps/rc-hisi-poplar.c index b4dbec6e70ce..49a18e916915 100644 --- a/drivers/media/rc/keymaps/rc-hisi-poplar.c +++ b/drivers/media/rc/keymaps/rc-hisi-poplar.c @@ -9,16 +9,16 @@ #include static struct rc_map_table hisi_poplar_keymap[] = { - { 0x0000b292, KEY_1}, - { 0x0000b293, KEY_2}, - { 0x0000b2cc, KEY_3}, - { 0x0000b28e, KEY_4}, - { 0x0000b28f, KEY_5}, - { 0x0000b2c8, KEY_6}, - { 0x0000b28a, KEY_7}, - { 0x0000b28b, KEY_8}, - { 0x0000b2c4, KEY_9}, - { 0x0000b287, KEY_0}, + { 0x0000b292, KEY_NUMERIC_1}, + { 0x0000b293, KEY_NUMERIC_2}, + { 0x0000b2cc, KEY_NUMERIC_3}, + { 0x0000b28e, KEY_NUMERIC_4}, + { 0x0000b28f, KEY_NUMERIC_5}, + { 0x0000b2c8, KEY_NUMERIC_6}, + { 0x0000b28a, KEY_NUMERIC_7}, + { 0x0000b28b, KEY_NUMERIC_8}, + { 0x0000b2c4, KEY_NUMERIC_9}, + { 0x0000b287, KEY_NUMERIC_0}, { 0x0000b282, KEY_HOMEPAGE}, { 0x0000b2ca, KEY_UP}, { 0x0000b299, KEY_LEFT}, diff --git a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c index 8e25b40714f8..c73068b653f7 100644 --- a/drivers/media/rc/keymaps/rc-hisi-tv-demo.c +++ b/drivers/media/rc/keymaps/rc-hisi-tv-demo.c @@ -9,16 +9,16 @@ #include static struct rc_map_table hisi_tv_demo_keymap[] = { - { 0x00000092, KEY_1}, - { 0x00000093, KEY_2}, - { 0x000000cc, KEY_3}, - { 0x0000009f, KEY_4}, - { 0x0000008e, KEY_5}, - { 0x0000008f, KEY_6}, - { 0x000000c8, KEY_7}, - { 0x00000094, KEY_8}, - { 0x0000008a, KEY_9}, - { 0x0000008b, KEY_0}, + { 0x00000092, KEY_NUMERIC_1}, + { 0x00000093, KEY_NUMERIC_2}, + { 0x000000cc, KEY_NUMERIC_3}, + { 0x0000009f, KEY_NUMERIC_4}, + { 0x0000008e, KEY_NUMERIC_5}, + { 0x0000008f, KEY_NUMERIC_6}, + { 0x000000c8, KEY_NUMERIC_7}, + { 0x00000094, KEY_NUMERIC_8}, + { 0x0000008a, KEY_NUMERIC_9}, + { 0x0000008b, KEY_NUMERIC_0}, { 0x000000ce, KEY_ENTER}, { 0x000000ca, KEY_UP}, { 0x00000099, KEY_LEFT}, diff --git a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c index 6ced43458f2a..9cc6ea0f4226 100644 --- a/drivers/media/rc/keymaps/rc-iodata-bctv7e.c +++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c @@ -17,16 +17,16 @@ static struct rc_map_table iodata_bctv7e[] = { { 0x00, KEY_POWER }, /* Keys 0 to 9 */ - { 0x44, KEY_0 }, /* 10 */ - { 0x50, KEY_1 }, - { 0x30, KEY_2 }, - { 0x70, KEY_3 }, - { 0x48, KEY_4 }, - { 0x28, KEY_5 }, - { 0x68, KEY_6 }, - { 0x58, KEY_7 }, - { 0x38, KEY_8 }, - { 0x78, KEY_9 }, + { 0x44, KEY_NUMERIC_0 }, /* 10 */ + { 0x50, KEY_NUMERIC_1 }, + { 0x30, KEY_NUMERIC_2 }, + { 0x70, KEY_NUMERIC_3 }, + { 0x48, KEY_NUMERIC_4 }, + { 0x28, KEY_NUMERIC_5 }, + { 0x68, KEY_NUMERIC_6 }, + { 0x58, KEY_NUMERIC_7 }, + { 0x38, KEY_NUMERIC_8 }, + { 0x78, KEY_NUMERIC_9 }, { 0x10, KEY_L }, /* Live */ { 0x08, KEY_TIME }, /* Time Shift */ diff --git a/drivers/media/rc/keymaps/rc-it913x-v1.c b/drivers/media/rc/keymaps/rc-it913x-v1.c index d8eaba9834c2..1e049f26a246 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v1.c +++ b/drivers/media/rc/keymaps/rc-it913x-v1.c @@ -11,22 +11,22 @@ static struct rc_map_table it913x_v1_rc[] = { /* Type 1 */ { 0x61d601, KEY_VIDEO }, /* Source */ - { 0x61d602, KEY_3 }, + { 0x61d602, KEY_NUMERIC_3 }, { 0x61d603, KEY_POWER }, /* ShutDown */ - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, + { 0x61d604, KEY_NUMERIC_1 }, + { 0x61d605, KEY_NUMERIC_5 }, + { 0x61d606, KEY_NUMERIC_6 }, { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, + { 0x61d608, KEY_NUMERIC_2 }, { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, + { 0x61d60a, KEY_NUMERIC_9 }, { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, + { 0x61d60c, KEY_NUMERIC_7 }, + { 0x61d60d, KEY_NUMERIC_8 }, { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, + { 0x61d60f, KEY_NUMERIC_4 }, { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, + { 0x61d611, KEY_NUMERIC_0 }, { 0x61d612, KEY_OK }, /* [enter arrow] */ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ { 0x61d614, KEY_RECORD }, /* Rec */ @@ -43,16 +43,16 @@ static struct rc_map_table it913x_v1_rc[] = { { 0x61d61f, KEY_BLUE }, { 0x61d643, KEY_POWER2 }, /* [red power button] */ /* Type 2 - 20 buttons */ - { 0x807f0d, KEY_0 }, - { 0x807f04, KEY_1 }, - { 0x807f05, KEY_2 }, - { 0x807f06, KEY_3 }, - { 0x807f07, KEY_4 }, - { 0x807f08, KEY_5 }, - { 0x807f09, KEY_6 }, - { 0x807f0a, KEY_7 }, - { 0x807f1b, KEY_8 }, - { 0x807f1f, KEY_9 }, + { 0x807f0d, KEY_NUMERIC_0 }, + { 0x807f04, KEY_NUMERIC_1 }, + { 0x807f05, KEY_NUMERIC_2 }, + { 0x807f06, KEY_NUMERIC_3 }, + { 0x807f07, KEY_NUMERIC_4 }, + { 0x807f08, KEY_NUMERIC_5 }, + { 0x807f09, KEY_NUMERIC_6 }, + { 0x807f0a, KEY_NUMERIC_7 }, + { 0x807f1b, KEY_NUMERIC_8 }, + { 0x807f1f, KEY_NUMERIC_9 }, { 0x807f12, KEY_POWER }, { 0x807f01, KEY_MEDIA_REPEAT}, /* Recall */ { 0x807f19, KEY_PAUSE }, /* Timeshift */ diff --git a/drivers/media/rc/keymaps/rc-it913x-v2.c b/drivers/media/rc/keymaps/rc-it913x-v2.c index 26747a327d91..da3107da26b7 100644 --- a/drivers/media/rc/keymaps/rc-it913x-v2.c +++ b/drivers/media/rc/keymaps/rc-it913x-v2.c @@ -20,31 +20,31 @@ static struct rc_map_table it913x_v2_rc[] = { { 0x807f04, KEY_VOLUMEUP }, /* Volume- */ { 0x807f05, KEY_SCREEN }, /* FullScreen */ { 0x807f06, KEY_VOLUMEDOWN }, /* Volume- */ - { 0x807f07, KEY_0 }, /* 0 */ + { 0x807f07, KEY_NUMERIC_0 }, /* 0 */ { 0x807f08, KEY_CHANNELDOWN }, /* Channel- */ { 0x807f09, KEY_PREVIOUS }, /* Recall */ - { 0x807f0a, KEY_1 }, /* 1 */ - { 0x807f1b, KEY_2 }, /* 2 */ - { 0x807f1f, KEY_3 }, /* 3 */ - { 0x807f0c, KEY_4 }, /* 4 */ - { 0x807f0d, KEY_5 }, /* 5 */ - { 0x807f0e, KEY_6 }, /* 6 */ - { 0x807f00, KEY_7 }, /* 7 */ - { 0x807f0f, KEY_8 }, /* 8 */ - { 0x807f19, KEY_9 }, /* 9 */ + { 0x807f0a, KEY_NUMERIC_1 }, /* 1 */ + { 0x807f1b, KEY_NUMERIC_2 }, /* 2 */ + { 0x807f1f, KEY_NUMERIC_3 }, /* 3 */ + { 0x807f0c, KEY_NUMERIC_4 }, /* 4 */ + { 0x807f0d, KEY_NUMERIC_5 }, /* 5 */ + { 0x807f0e, KEY_NUMERIC_6 }, /* 6 */ + { 0x807f00, KEY_NUMERIC_7 }, /* 7 */ + { 0x807f0f, KEY_NUMERIC_8 }, /* 8 */ + { 0x807f19, KEY_NUMERIC_9 }, /* 9 */ /* Type 2 */ /* keys stereo, snapshot unassigned */ - { 0x866b00, KEY_0 }, - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, + { 0x866b00, KEY_NUMERIC_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, { 0x866b12, KEY_POWER }, { 0x866b13, KEY_MUTE }, { 0x866b0a, KEY_PREVIOUS }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c index a00051339842..548760e86a2d 100644 --- a/drivers/media/rc/keymaps/rc-kaiomy.c +++ b/drivers/media/rc/keymaps/rc-kaiomy.c @@ -18,19 +18,19 @@ static struct rc_map_table kaiomy[] = { { 0x0b, KEY_ZOOM}, { 0x03, KEY_POWER}, - { 0x04, KEY_1}, - { 0x08, KEY_2}, - { 0x02, KEY_3}, + { 0x04, KEY_NUMERIC_1}, + { 0x08, KEY_NUMERIC_2}, + { 0x02, KEY_NUMERIC_3}, - { 0x0f, KEY_4}, - { 0x05, KEY_5}, - { 0x06, KEY_6}, + { 0x0f, KEY_NUMERIC_4}, + { 0x05, KEY_NUMERIC_5}, + { 0x06, KEY_NUMERIC_6}, - { 0x0c, KEY_7}, - { 0x0d, KEY_8}, - { 0x0a, KEY_9}, + { 0x0c, KEY_NUMERIC_7}, + { 0x0d, KEY_NUMERIC_8}, + { 0x0a, KEY_NUMERIC_9}, - { 0x11, KEY_0}, + { 0x11, KEY_NUMERIC_0}, { 0x09, KEY_CHANNELUP}, { 0x07, KEY_CHANNELDOWN}, diff --git a/drivers/media/rc/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c index ed0e0586dea2..f5aed4b96019 100644 --- a/drivers/media/rc/keymaps/rc-kworld-315u.c +++ b/drivers/media/rc/keymaps/rc-kworld-315u.c @@ -17,23 +17,23 @@ static struct rc_map_table kworld_315u[] = { { 0x610b, KEY_ZOOM }, { 0x6103, KEY_POWER2 }, /* shutdown */ - { 0x6104, KEY_1 }, - { 0x6108, KEY_2 }, - { 0x6102, KEY_3 }, + { 0x6104, KEY_NUMERIC_1 }, + { 0x6108, KEY_NUMERIC_2 }, + { 0x6102, KEY_NUMERIC_3 }, { 0x6109, KEY_CHANNELUP }, - { 0x610f, KEY_4 }, - { 0x6105, KEY_5 }, - { 0x6106, KEY_6 }, + { 0x610f, KEY_NUMERIC_4 }, + { 0x6105, KEY_NUMERIC_5 }, + { 0x6106, KEY_NUMERIC_6 }, { 0x6107, KEY_CHANNELDOWN }, - { 0x610c, KEY_7 }, - { 0x610d, KEY_8 }, - { 0x610a, KEY_9 }, + { 0x610c, KEY_NUMERIC_7 }, + { 0x610d, KEY_NUMERIC_8 }, + { 0x610a, KEY_NUMERIC_9 }, { 0x610e, KEY_VOLUMEUP }, { 0x6110, KEY_LAST }, - { 0x6111, KEY_0 }, + { 0x6111, KEY_NUMERIC_0 }, { 0x6112, KEY_ENTER }, { 0x6113, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-kworld-pc150u.c b/drivers/media/rc/keymaps/rc-kworld-pc150u.c index 9c60cf4f3bf2..7938761eb994 100644 --- a/drivers/media/rc/keymaps/rc-kworld-pc150u.c +++ b/drivers/media/rc/keymaps/rc-kworld-pc150u.c @@ -20,16 +20,16 @@ static struct rc_map_table kworld_pc150u[] = { { 0x16, KEY_EJECTCLOSECD }, /* -> ) */ { 0x1d, KEY_POWER2 }, - { 0x00, KEY_1 }, - { 0x01, KEY_2 }, - { 0x02, KEY_3 }, - { 0x03, KEY_4 }, - { 0x04, KEY_5 }, - { 0x05, KEY_6 }, - { 0x06, KEY_7 }, - { 0x07, KEY_8 }, - { 0x08, KEY_9 }, - { 0x0a, KEY_0 }, + { 0x00, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + { 0x02, KEY_NUMERIC_3 }, + { 0x03, KEY_NUMERIC_4 }, + { 0x04, KEY_NUMERIC_5 }, + { 0x05, KEY_NUMERIC_6 }, + { 0x06, KEY_NUMERIC_7 }, + { 0x07, KEY_NUMERIC_8 }, + { 0x08, KEY_NUMERIC_9 }, + { 0x0a, KEY_NUMERIC_0 }, { 0x09, KEY_AGAIN }, { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c index db5edde3eeb1..75389b74e02d 100644 --- a/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c +++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c @@ -17,16 +17,20 @@ static struct rc_map_table kworld_plus_tv_analog[] = { { 0x16, KEY_CLOSECD }, /* -> ) */ { 0x1d, KEY_POWER2 }, - { 0x00, KEY_1 }, - { 0x01, KEY_2 }, - { 0x02, KEY_3 }, /* Two keys have the same code: 3 and left */ - { 0x03, KEY_4 }, /* Two keys have the same code: 3 and right */ - { 0x04, KEY_5 }, - { 0x05, KEY_6 }, - { 0x06, KEY_7 }, - { 0x07, KEY_8 }, - { 0x08, KEY_9 }, - { 0x0a, KEY_0 }, + { 0x00, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + + /* Two keys have the same code: 3 and left */ + { 0x02, KEY_NUMERIC_3 }, + + /* Two keys have the same code: 4 and right */ + { 0x03, KEY_NUMERIC_4 }, + { 0x04, KEY_NUMERIC_5 }, + { 0x05, KEY_NUMERIC_6 }, + { 0x06, KEY_NUMERIC_7 }, + { 0x07, KEY_NUMERIC_8 }, + { 0x08, KEY_NUMERIC_9 }, + { 0x0a, KEY_NUMERIC_0 }, { 0x09, KEY_AGAIN }, { 0x14, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c index afee942e0edf..2f2b981e1995 100644 --- a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c +++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c @@ -12,20 +12,20 @@ static struct rc_map_table leadtek_y04g0051[] = { { 0x0300, KEY_POWER2 }, { 0x0303, KEY_SCREEN }, { 0x0304, KEY_RIGHT }, - { 0x0305, KEY_1 }, - { 0x0306, KEY_2 }, - { 0x0307, KEY_3 }, + { 0x0305, KEY_NUMERIC_1 }, + { 0x0306, KEY_NUMERIC_2 }, + { 0x0307, KEY_NUMERIC_3 }, { 0x0308, KEY_LEFT }, - { 0x0309, KEY_4 }, - { 0x030a, KEY_5 }, - { 0x030b, KEY_6 }, + { 0x0309, KEY_NUMERIC_4 }, + { 0x030a, KEY_NUMERIC_5 }, + { 0x030b, KEY_NUMERIC_6 }, { 0x030c, KEY_UP }, - { 0x030d, KEY_7 }, - { 0x030e, KEY_8 }, - { 0x030f, KEY_9 }, + { 0x030d, KEY_NUMERIC_7 }, + { 0x030e, KEY_NUMERIC_8 }, + { 0x030f, KEY_NUMERIC_9 }, { 0x0310, KEY_DOWN }, { 0x0311, KEY_AGAIN }, - { 0x0312, KEY_0 }, + { 0x0312, KEY_NUMERIC_0 }, { 0x0313, KEY_OK }, /* 1st ok */ { 0x0314, KEY_MUTE }, { 0x0316, KEY_OK }, /* 2nd ok */ diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index b0901a8a72a6..181e48f0cb67 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -10,16 +10,16 @@ static struct rc_map_table lme2510_rc[] = { /* Type 1 - 26 buttons */ - { 0xef12ba45, KEY_0 }, - { 0xef12a05f, KEY_1 }, - { 0xef12af50, KEY_2 }, - { 0xef12a25d, KEY_3 }, - { 0xef12be41, KEY_4 }, - { 0xef12f50a, KEY_5 }, - { 0xef12bd42, KEY_6 }, - { 0xef12b847, KEY_7 }, - { 0xef12b649, KEY_8 }, - { 0xef12fa05, KEY_9 }, + { 0xef12ba45, KEY_NUMERIC_0 }, + { 0xef12a05f, KEY_NUMERIC_1 }, + { 0xef12af50, KEY_NUMERIC_2 }, + { 0xef12a25d, KEY_NUMERIC_3 }, + { 0xef12be41, KEY_NUMERIC_4 }, + { 0xef12f50a, KEY_NUMERIC_5 }, + { 0xef12bd42, KEY_NUMERIC_6 }, + { 0xef12b847, KEY_NUMERIC_7 }, + { 0xef12b649, KEY_NUMERIC_8 }, + { 0xef12fa05, KEY_NUMERIC_9 }, { 0xef12bc43, KEY_POWER }, { 0xef12b946, KEY_SUBTITLE }, { 0xef12f906, KEY_PAUSE }, @@ -37,16 +37,16 @@ static struct rc_map_table lme2510_rc[] = { { 0xef12f807, KEY_EPG }, { 0xef12fe01, KEY_STOP }, /* Type 2 - 20 buttons */ - { 0xff40ea15, KEY_0 }, - { 0xff40f708, KEY_1 }, - { 0xff40f609, KEY_2 }, - { 0xff40f50a, KEY_3 }, - { 0xff40f30c, KEY_4 }, - { 0xff40f20d, KEY_5 }, - { 0xff40f10e, KEY_6 }, - { 0xff40ef10, KEY_7 }, - { 0xff40ee11, KEY_8 }, - { 0xff40ed12, KEY_9 }, + { 0xff40ea15, KEY_NUMERIC_0 }, + { 0xff40f708, KEY_NUMERIC_1 }, + { 0xff40f609, KEY_NUMERIC_2 }, + { 0xff40f50a, KEY_NUMERIC_3 }, + { 0xff40f30c, KEY_NUMERIC_4 }, + { 0xff40f20d, KEY_NUMERIC_5 }, + { 0xff40f10e, KEY_NUMERIC_6 }, + { 0xff40ef10, KEY_NUMERIC_7 }, + { 0xff40ee11, KEY_NUMERIC_8 }, + { 0xff40ed12, KEY_NUMERIC_9 }, { 0xff40ff00, KEY_POWER }, { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ @@ -58,16 +58,16 @@ static struct rc_map_table lme2510_rc[] = { { 0xff40e718, KEY_RECORD }, { 0xff40e916, KEY_STOP }, /* Type 3 - 20 buttons */ - { 0xff00e31c, KEY_0 }, - { 0xff00f807, KEY_1 }, - { 0xff00ea15, KEY_2 }, - { 0xff00f609, KEY_3 }, - { 0xff00e916, KEY_4 }, - { 0xff00e619, KEY_5 }, - { 0xff00f20d, KEY_6 }, - { 0xff00f30c, KEY_7 }, - { 0xff00e718, KEY_8 }, - { 0xff00a15e, KEY_9 }, + { 0xff00e31c, KEY_NUMERIC_0 }, + { 0xff00f807, KEY_NUMERIC_1 }, + { 0xff00ea15, KEY_NUMERIC_2 }, + { 0xff00f609, KEY_NUMERIC_3 }, + { 0xff00e916, KEY_NUMERIC_4 }, + { 0xff00e619, KEY_NUMERIC_5 }, + { 0xff00f20d, KEY_NUMERIC_6 }, + { 0xff00f30c, KEY_NUMERIC_7 }, + { 0xff00e718, KEY_NUMERIC_8 }, + { 0xff00a15e, KEY_NUMERIC_9 }, { 0xff00ba45, KEY_POWER }, { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ diff --git a/drivers/media/rc/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c index 5e9a49e2dd6a..e884aeb5c3d6 100644 --- a/drivers/media/rc/keymaps/rc-manli.c +++ b/drivers/media/rc/keymaps/rc-manli.c @@ -35,22 +35,22 @@ static struct rc_map_table manli[] = { * 0x07 0x08 0x09 * * 7 8 9 * * */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, /* 0x0a 0x00 0x17 * * RECALL 0 +100 * * PLUS * * */ { 0x0a, KEY_AGAIN }, /*XXX KEY_REWIND? */ - { 0x00, KEY_0 }, + { 0x00, KEY_NUMERIC_0 }, { 0x17, KEY_DIGITS }, /*XXX*/ /* 0x14 0x10 * diff --git a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c index 407706b246f2..bf74912859b3 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c +++ b/drivers/media/rc/keymaps/rc-medion-x10-digitainer.c @@ -63,16 +63,16 @@ static struct rc_map_table medion_x10_digitainer[] = { { 0x27, KEY_RECORD }, { 0x26, KEY_FORWARD }, - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, /* these do not actually exist on this remote, but these scancodes * exist on all other Medion X10 remotes and adding them here allows diff --git a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c index 2ff5c454304d..293045c9aaa5 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10-or2x.c +++ b/drivers/media/rc/keymaps/rc-medion-x10-or2x.c @@ -52,16 +52,16 @@ static struct rc_map_table medion_x10_or2x[] = { { 0x29, KEY_PAUSE }, { 0x27, KEY_RECORD }, - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, { 0x30, KEY_CLEAR }, { 0x36, KEY_ENTER }, { 0x37, KEY_NUMERIC_STAR }, diff --git a/drivers/media/rc/keymaps/rc-medion-x10.c b/drivers/media/rc/keymaps/rc-medion-x10.c index 66b962dc982b..843dba3bad73 100644 --- a/drivers/media/rc/keymaps/rc-medion-x10.c +++ b/drivers/media/rc/keymaps/rc-medion-x10.c @@ -37,16 +37,16 @@ static struct rc_map_table medion_x10[] = { { 0x35, KEY_BLUE }, /* blue */ { 0x16, KEY_TEXT }, /* TXT */ - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, { 0x1c, KEY_SEARCH }, /* TV/RAD, CH SRC */ { 0x20, KEY_DELETE }, /* DELETE */ diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c index d361554e8a2d..ab001d2dac67 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c @@ -9,23 +9,23 @@ #include static struct rc_map_table msi_digivox_ii[] = { - { 0x0302, KEY_2 }, + { 0x0302, KEY_NUMERIC_2 }, { 0x0303, KEY_UP }, /* up */ - { 0x0304, KEY_3 }, + { 0x0304, KEY_NUMERIC_3 }, { 0x0305, KEY_CHANNELDOWN }, - { 0x0308, KEY_5 }, - { 0x0309, KEY_0 }, - { 0x030b, KEY_8 }, + { 0x0308, KEY_NUMERIC_5 }, + { 0x0309, KEY_NUMERIC_0 }, + { 0x030b, KEY_NUMERIC_8 }, { 0x030d, KEY_DOWN }, /* down */ - { 0x0310, KEY_9 }, - { 0x0311, KEY_7 }, + { 0x0310, KEY_NUMERIC_9 }, + { 0x0311, KEY_NUMERIC_7 }, { 0x0314, KEY_VOLUMEUP }, { 0x0315, KEY_CHANNELUP }, { 0x0316, KEY_OK }, { 0x0317, KEY_POWER2 }, - { 0x031a, KEY_1 }, - { 0x031c, KEY_4 }, - { 0x031d, KEY_6 }, + { 0x031a, KEY_NUMERIC_1 }, + { 0x031c, KEY_NUMERIC_4 }, + { 0x031d, KEY_NUMERIC_6 }, { 0x031f, KEY_VOLUMEDOWN }, }; diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c index 31d41564a438..6129d3e925e5 100644 --- a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c +++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c @@ -14,22 +14,22 @@ since rc-kworld-315u.c lacks NEC extended address byte. */ static struct rc_map_table msi_digivox_iii[] = { { 0x61d601, KEY_VIDEO }, /* Source */ - { 0x61d602, KEY_3 }, + { 0x61d602, KEY_NUMERIC_3 }, { 0x61d603, KEY_POWER }, /* ShutDown */ - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, + { 0x61d604, KEY_NUMERIC_1 }, + { 0x61d605, KEY_NUMERIC_5 }, + { 0x61d606, KEY_NUMERIC_6 }, { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, + { 0x61d608, KEY_NUMERIC_2 }, { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, + { 0x61d60a, KEY_NUMERIC_9 }, { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, + { 0x61d60c, KEY_NUMERIC_7 }, + { 0x61d60d, KEY_NUMERIC_8 }, { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, + { 0x61d60f, KEY_NUMERIC_4 }, { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, + { 0x61d611, KEY_NUMERIC_0 }, { 0x61d612, KEY_OK }, /* [enter arrow] */ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ { 0x61d614, KEY_RECORD }, /* Rec */ diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c index 78cf2c286083..42270a7ef3ee 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c @@ -44,16 +44,16 @@ static struct rc_map_table msi_tvanywhere_plus[] = { << FUNC >> RESET */ - { 0x01, KEY_1 }, /* 1 */ - { 0x0b, KEY_2 }, /* 2 */ - { 0x1b, KEY_3 }, /* 3 */ - { 0x05, KEY_4 }, /* 4 */ - { 0x09, KEY_5 }, /* 5 */ - { 0x15, KEY_6 }, /* 6 */ - { 0x06, KEY_7 }, /* 7 */ - { 0x0a, KEY_8 }, /* 8 */ - { 0x12, KEY_9 }, /* 9 */ - { 0x02, KEY_0 }, /* 0 */ + { 0x01, KEY_NUMERIC_1 }, /* 1 */ + { 0x0b, KEY_NUMERIC_2 }, /* 2 */ + { 0x1b, KEY_NUMERIC_3 }, /* 3 */ + { 0x05, KEY_NUMERIC_4 }, /* 4 */ + { 0x09, KEY_NUMERIC_5 }, /* 5 */ + { 0x15, KEY_NUMERIC_6 }, /* 6 */ + { 0x06, KEY_NUMERIC_7 }, /* 7 */ + { 0x0a, KEY_NUMERIC_8 }, /* 8 */ + { 0x12, KEY_NUMERIC_9 }, /* 9 */ + { 0x02, KEY_NUMERIC_0 }, /* 0 */ { 0x10, KEY_KPPLUS }, /* + */ { 0x13, KEY_AGAIN }, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c index 359a57be3a66..45793c641009 100644 --- a/drivers/media/rc/keymaps/rc-msi-tvanywhere.c +++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c @@ -12,16 +12,16 @@ static struct rc_map_table msi_tvanywhere[] = { /* Keys 0 to 9 */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0c, KEY_MUTE }, { 0x0f, KEY_SCREEN }, /* Full Screen */ diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c index 17d7c1b324da..2dc6061f69b3 100644 --- a/drivers/media/rc/keymaps/rc-nebula.c +++ b/drivers/media/rc/keymaps/rc-nebula.c @@ -9,16 +9,16 @@ #include static struct rc_map_table nebula[] = { - { 0x0000, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0000, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_TV }, { 0x000b, KEY_AUX }, { 0x000c, KEY_DVD }, diff --git a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c index 76beef44a8d7..b12c54d47db3 100644 --- a/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c @@ -23,16 +23,16 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = { { 0x1444, KEY_TEXT}, /* Teletext */ { 0x1445, KEY_DELETE}, - { 0x1402, KEY_1}, - { 0x1403, KEY_2}, - { 0x1404, KEY_3}, - { 0x1405, KEY_4}, - { 0x1406, KEY_5}, - { 0x1407, KEY_6}, - { 0x1408, KEY_7}, - { 0x1409, KEY_8}, - { 0x140a, KEY_9}, - { 0x140c, KEY_0}, + { 0x1402, KEY_NUMERIC_1}, + { 0x1403, KEY_NUMERIC_2}, + { 0x1404, KEY_NUMERIC_3}, + { 0x1405, KEY_NUMERIC_4}, + { 0x1406, KEY_NUMERIC_5}, + { 0x1407, KEY_NUMERIC_6}, + { 0x1408, KEY_NUMERIC_7}, + { 0x1409, KEY_NUMERIC_8}, + { 0x140a, KEY_NUMERIC_9}, + { 0x140c, KEY_NUMERIC_0}, { 0x140b, KEY_TUNER}, /* AV */ { 0x140d, KEY_MODE}, /* A.B */ @@ -79,16 +79,16 @@ static struct rc_map_table nec_terratec_cinergy_xs[] = { /* Terratec Black IR, with most keys in black */ { 0x04eb01, KEY_POWER2}, - { 0x04eb02, KEY_1}, - { 0x04eb03, KEY_2}, - { 0x04eb04, KEY_3}, - { 0x04eb05, KEY_4}, - { 0x04eb06, KEY_5}, - { 0x04eb07, KEY_6}, - { 0x04eb08, KEY_7}, - { 0x04eb09, KEY_8}, - { 0x04eb0a, KEY_9}, - { 0x04eb0c, KEY_0}, + { 0x04eb02, KEY_NUMERIC_1}, + { 0x04eb03, KEY_NUMERIC_2}, + { 0x04eb04, KEY_NUMERIC_3}, + { 0x04eb05, KEY_NUMERIC_4}, + { 0x04eb06, KEY_NUMERIC_5}, + { 0x04eb07, KEY_NUMERIC_6}, + { 0x04eb08, KEY_NUMERIC_7}, + { 0x04eb09, KEY_NUMERIC_8}, + { 0x04eb0a, KEY_NUMERIC_9}, + { 0x04eb0c, KEY_NUMERIC_0}, { 0x04eb0b, KEY_TEXT}, /* TXT */ { 0x04eb0d, KEY_REFRESH}, /* Refresh */ diff --git a/drivers/media/rc/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c index 3765705c5549..acd5b1ccf8d0 100644 --- a/drivers/media/rc/keymaps/rc-norwood.c +++ b/drivers/media/rc/keymaps/rc-norwood.c @@ -14,16 +14,16 @@ static struct rc_map_table norwood[] = { /* Keys 0 to 9 */ - { 0x20, KEY_0 }, - { 0x21, KEY_1 }, - { 0x22, KEY_2 }, - { 0x23, KEY_3 }, - { 0x24, KEY_4 }, - { 0x25, KEY_5 }, - { 0x26, KEY_6 }, - { 0x27, KEY_7 }, - { 0x28, KEY_8 }, - { 0x29, KEY_9 }, + { 0x20, KEY_NUMERIC_0 }, + { 0x21, KEY_NUMERIC_1 }, + { 0x22, KEY_NUMERIC_2 }, + { 0x23, KEY_NUMERIC_3 }, + { 0x24, KEY_NUMERIC_4 }, + { 0x25, KEY_NUMERIC_5 }, + { 0x26, KEY_NUMERIC_6 }, + { 0x27, KEY_NUMERIC_7 }, + { 0x28, KEY_NUMERIC_8 }, + { 0x29, KEY_NUMERIC_9 }, { 0x78, KEY_VIDEO }, /* Video Source */ { 0x2c, KEY_EXIT }, /* Open/Close software */ diff --git a/drivers/media/rc/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c index abaf7f6d4cb7..98a755e8bc18 100644 --- a/drivers/media/rc/keymaps/rc-npgtech.c +++ b/drivers/media/rc/keymaps/rc-npgtech.c @@ -12,16 +12,16 @@ static struct rc_map_table npgtech[] = { { 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */ { 0x2a, KEY_FRONT }, - { 0x3e, KEY_1 }, - { 0x02, KEY_2 }, - { 0x06, KEY_3 }, - { 0x0a, KEY_4 }, - { 0x0e, KEY_5 }, - { 0x12, KEY_6 }, - { 0x16, KEY_7 }, - { 0x1a, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x3a, KEY_0 }, + { 0x3e, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x0a, KEY_NUMERIC_4 }, + { 0x0e, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x16, KEY_NUMERIC_7 }, + { 0x1a, KEY_NUMERIC_8 }, + { 0x1e, KEY_NUMERIC_9 }, + { 0x3a, KEY_NUMERIC_0 }, { 0x22, KEY_NUMLOCK }, /* -/-- */ { 0x20, KEY_REFRESH }, diff --git a/drivers/media/rc/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c index e3462c5c8984..c3bb1ecdd0ca 100644 --- a/drivers/media/rc/keymaps/rc-pctv-sedna.c +++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c @@ -14,16 +14,16 @@ Also for the remote bundled with Kozumi KTV-01C card */ static struct rc_map_table pctv_sedna[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_AGAIN }, /* Recall */ { 0x0b, KEY_CHANNELUP }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c index 63c2851e9dfe..b862725635b9 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-color.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c @@ -49,16 +49,16 @@ static struct rc_map_table pinnacle_color[] = { { 0x4c, KEY_STOP }, { 0x54, KEY_NEXT }, - { 0x69, KEY_0 }, - { 0x6a, KEY_1 }, - { 0x6b, KEY_2 }, - { 0x6c, KEY_3 }, - { 0x6d, KEY_4 }, - { 0x6e, KEY_5 }, - { 0x6f, KEY_6 }, - { 0x70, KEY_7 }, - { 0x71, KEY_8 }, - { 0x72, KEY_9 }, + { 0x69, KEY_NUMERIC_0 }, + { 0x6a, KEY_NUMERIC_1 }, + { 0x6b, KEY_NUMERIC_2 }, + { 0x6c, KEY_NUMERIC_3 }, + { 0x6d, KEY_NUMERIC_4 }, + { 0x6e, KEY_NUMERIC_5 }, + { 0x6f, KEY_NUMERIC_6 }, + { 0x70, KEY_NUMERIC_7 }, + { 0x71, KEY_NUMERIC_8 }, + { 0x72, KEY_NUMERIC_9 }, { 0x74, KEY_CHANNEL }, { 0x0a, KEY_BACKSPACE }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c index 31794d4180db..3853b653cee6 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-grey.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c @@ -9,16 +9,16 @@ #include static struct rc_map_table pinnacle_grey[] = { - { 0x3a, KEY_0 }, - { 0x31, KEY_1 }, - { 0x32, KEY_2 }, - { 0x33, KEY_3 }, - { 0x34, KEY_4 }, - { 0x35, KEY_5 }, - { 0x36, KEY_6 }, - { 0x37, KEY_7 }, - { 0x38, KEY_8 }, - { 0x39, KEY_9 }, + { 0x3a, KEY_NUMERIC_0 }, + { 0x31, KEY_NUMERIC_1 }, + { 0x32, KEY_NUMERIC_2 }, + { 0x33, KEY_NUMERIC_3 }, + { 0x34, KEY_NUMERIC_4 }, + { 0x35, KEY_NUMERIC_5 }, + { 0x36, KEY_NUMERIC_6 }, + { 0x37, KEY_NUMERIC_7 }, + { 0x38, KEY_NUMERIC_8 }, + { 0x39, KEY_NUMERIC_9 }, { 0x2f, KEY_POWER }, diff --git a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c index 876aeb6e1d9c..96d8112fb468 100644 --- a/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c +++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c @@ -20,16 +20,16 @@ static struct rc_map_table pinnacle_pctv_hd[] = { { 0x0709, KEY_VOLUMEDOWN }, { 0x0706, KEY_CHANNELUP }, { 0x070c, KEY_CHANNELDOWN }, - { 0x070f, KEY_1 }, - { 0x0715, KEY_2 }, - { 0x0710, KEY_3 }, - { 0x0718, KEY_4 }, - { 0x071b, KEY_5 }, - { 0x071e, KEY_6 }, - { 0x0711, KEY_7 }, - { 0x0721, KEY_8 }, - { 0x0712, KEY_9 }, - { 0x0727, KEY_0 }, + { 0x070f, KEY_NUMERIC_1 }, + { 0x0715, KEY_NUMERIC_2 }, + { 0x0710, KEY_NUMERIC_3 }, + { 0x0718, KEY_NUMERIC_4 }, + { 0x071b, KEY_NUMERIC_5 }, + { 0x071e, KEY_NUMERIC_6 }, + { 0x0711, KEY_NUMERIC_7 }, + { 0x0721, KEY_NUMERIC_8 }, + { 0x0712, KEY_NUMERIC_9 }, + { 0x0727, KEY_NUMERIC_0 }, { 0x0724, KEY_ZOOM }, /* 'Square' key */ { 0x072a, KEY_SUBTITLE }, /* 'T' key */ { 0x072d, KEY_REWIND }, diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c index c0550e09f255..c3439c46644c 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-002t.c +++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c @@ -16,16 +16,16 @@ static struct rc_map_table pixelview_002t[] = { { 0x866b13, KEY_MUTE }, { 0x866b12, KEY_POWER2 }, /* power */ - { 0x866b01, KEY_1 }, - { 0x866b02, KEY_2 }, - { 0x866b03, KEY_3 }, - { 0x866b04, KEY_4 }, - { 0x866b05, KEY_5 }, - { 0x866b06, KEY_6 }, - { 0x866b07, KEY_7 }, - { 0x866b08, KEY_8 }, - { 0x866b09, KEY_9 }, - { 0x866b00, KEY_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b02, KEY_NUMERIC_2 }, + { 0x866b03, KEY_NUMERIC_3 }, + { 0x866b04, KEY_NUMERIC_4 }, + { 0x866b05, KEY_NUMERIC_5 }, + { 0x866b06, KEY_NUMERIC_6 }, + { 0x866b07, KEY_NUMERIC_7 }, + { 0x866b08, KEY_NUMERIC_8 }, + { 0x866b09, KEY_NUMERIC_9 }, + { 0x866b00, KEY_NUMERIC_0 }, { 0x866b0d, KEY_CHANNELUP }, { 0x866b19, KEY_CHANNELDOWN }, diff --git a/drivers/media/rc/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c index 864c8ea5d8e3..ea11ccde8442 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-mk12.c +++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c @@ -16,16 +16,16 @@ static struct rc_map_table pixelview_mk12[] = { { 0x866b03, KEY_TUNER }, /* Timeshift */ { 0x866b1e, KEY_POWER2 }, /* power */ - { 0x866b01, KEY_1 }, - { 0x866b0b, KEY_2 }, - { 0x866b1b, KEY_3 }, - { 0x866b05, KEY_4 }, - { 0x866b09, KEY_5 }, - { 0x866b15, KEY_6 }, - { 0x866b06, KEY_7 }, - { 0x866b0a, KEY_8 }, - { 0x866b12, KEY_9 }, - { 0x866b02, KEY_0 }, + { 0x866b01, KEY_NUMERIC_1 }, + { 0x866b0b, KEY_NUMERIC_2 }, + { 0x866b1b, KEY_NUMERIC_3 }, + { 0x866b05, KEY_NUMERIC_4 }, + { 0x866b09, KEY_NUMERIC_5 }, + { 0x866b15, KEY_NUMERIC_6 }, + { 0x866b06, KEY_NUMERIC_7 }, + { 0x866b0a, KEY_NUMERIC_8 }, + { 0x866b12, KEY_NUMERIC_9 }, + { 0x866b02, KEY_NUMERIC_0 }, { 0x866b13, KEY_AGAIN }, /* loop */ { 0x866b10, KEY_DIGITS }, /* +100 */ diff --git a/drivers/media/rc/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c index e4e34f2ccf74..0259666831b0 100644 --- a/drivers/media/rc/keymaps/rc-pixelview-new.c +++ b/drivers/media/rc/keymaps/rc-pixelview-new.c @@ -17,16 +17,16 @@ static struct rc_map_table pixelview_new[] = { { 0x3c, KEY_TIME }, /* Timeshift */ { 0x12, KEY_POWER }, - { 0x3d, KEY_1 }, - { 0x38, KEY_2 }, - { 0x18, KEY_3 }, - { 0x35, KEY_4 }, - { 0x39, KEY_5 }, - { 0x15, KEY_6 }, - { 0x36, KEY_7 }, - { 0x3a, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x3e, KEY_0 }, + { 0x3d, KEY_NUMERIC_1 }, + { 0x38, KEY_NUMERIC_2 }, + { 0x18, KEY_NUMERIC_3 }, + { 0x35, KEY_NUMERIC_4 }, + { 0x39, KEY_NUMERIC_5 }, + { 0x15, KEY_NUMERIC_6 }, + { 0x36, KEY_NUMERIC_7 }, + { 0x3a, KEY_NUMERIC_8 }, + { 0x1e, KEY_NUMERIC_9 }, + { 0x3e, KEY_NUMERIC_0 }, { 0x1c, KEY_AGAIN }, /* LOOP */ { 0x3f, KEY_VIDEO }, /* Source */ diff --git a/drivers/media/rc/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c index 988919735165..29f6d2c013e4 100644 --- a/drivers/media/rc/keymaps/rc-pixelview.c +++ b/drivers/media/rc/keymaps/rc-pixelview.c @@ -25,16 +25,16 @@ static struct rc_map_table pixelview[] = { { 0x19, KEY_ZOOM }, /* zoom */ { 0x0f, KEY_TEXT }, /* min */ - { 0x01, KEY_1 }, - { 0x0b, KEY_2 }, - { 0x1b, KEY_3 }, - { 0x05, KEY_4 }, - { 0x09, KEY_5 }, - { 0x15, KEY_6 }, - { 0x06, KEY_7 }, - { 0x0a, KEY_8 }, - { 0x12, KEY_9 }, - { 0x02, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x0b, KEY_NUMERIC_2 }, + { 0x1b, KEY_NUMERIC_3 }, + { 0x05, KEY_NUMERIC_4 }, + { 0x09, KEY_NUMERIC_5 }, + { 0x15, KEY_NUMERIC_6 }, + { 0x06, KEY_NUMERIC_7 }, + { 0x0a, KEY_NUMERIC_8 }, + { 0x12, KEY_NUMERIC_9 }, + { 0x02, KEY_NUMERIC_0 }, { 0x10, KEY_LAST }, /* +100 */ { 0x13, KEY_LIST }, /* recall */ diff --git a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c index cf98cf8dc13c..66fe2e52e7c8 100644 --- a/drivers/media/rc/keymaps/rc-powercolor-real-angel.c +++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c @@ -16,16 +16,16 @@ static struct rc_map_table powercolor_real_angel[] = { { 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */ { 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x0a, KEY_DIGITS }, /* single, double, triple digit */ { 0x29, KEY_PREVIOUS }, /* previous channel */ { 0x12, KEY_BRIGHTNESSUP }, diff --git a/drivers/media/rc/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c index d2c13d0e7bff..36eebefd975c 100644 --- a/drivers/media/rc/keymaps/rc-proteus-2309.c +++ b/drivers/media/rc/keymaps/rc-proteus-2309.c @@ -12,16 +12,16 @@ static struct rc_map_table proteus_2309[] = { /* numeric */ - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x5c, KEY_POWER }, /* power */ { 0x20, KEY_ZOOM }, /* full screen */ diff --git a/drivers/media/rc/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c index c8011f4d96ea..bf4543fecb6f 100644 --- a/drivers/media/rc/keymaps/rc-purpletv.c +++ b/drivers/media/rc/keymaps/rc-purpletv.c @@ -13,16 +13,16 @@ static struct rc_map_table purpletv[] = { { 0x6f, KEY_MUTE }, { 0x10, KEY_BACKSPACE }, /* Recall */ - { 0x11, KEY_0 }, - { 0x04, KEY_1 }, - { 0x05, KEY_2 }, - { 0x06, KEY_3 }, - { 0x08, KEY_4 }, - { 0x09, KEY_5 }, - { 0x0a, KEY_6 }, - { 0x0c, KEY_7 }, - { 0x0d, KEY_8 }, - { 0x0e, KEY_9 }, + { 0x11, KEY_NUMERIC_0 }, + { 0x04, KEY_NUMERIC_1 }, + { 0x05, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x08, KEY_NUMERIC_4 }, + { 0x09, KEY_NUMERIC_5 }, + { 0x0a, KEY_NUMERIC_6 }, + { 0x0c, KEY_NUMERIC_7 }, + { 0x0d, KEY_NUMERIC_8 }, + { 0x0e, KEY_NUMERIC_9 }, { 0x12, KEY_DOT }, /* 100+ */ { 0x07, KEY_VOLUMEUP }, diff --git a/drivers/media/rc/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c index 5235ee899c30..69db55463000 100644 --- a/drivers/media/rc/keymaps/rc-pv951.c +++ b/drivers/media/rc/keymaps/rc-pv951.c @@ -11,16 +11,16 @@ /* Mark Phalan */ static struct rc_map_table pv951[] = { - { 0x00, KEY_0 }, - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, + { 0x00, KEY_NUMERIC_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, { 0x12, KEY_POWER }, { 0x10, KEY_MUTE }, diff --git a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c index 1cf786649675..33bb458b81fd 100644 --- a/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c +++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c @@ -14,16 +14,16 @@ static struct rc_map_table real_audio_220_32_keys[] = { { 0x1c, KEY_RADIO}, { 0x12, KEY_POWER2}, - { 0x01, KEY_1}, - { 0x02, KEY_2}, - { 0x03, KEY_3}, - { 0x04, KEY_4}, - { 0x05, KEY_5}, - { 0x06, KEY_6}, - { 0x07, KEY_7}, - { 0x08, KEY_8}, - { 0x09, KEY_9}, - { 0x00, KEY_0}, + { 0x01, KEY_NUMERIC_1}, + { 0x02, KEY_NUMERIC_2}, + { 0x03, KEY_NUMERIC_3}, + { 0x04, KEY_NUMERIC_4}, + { 0x05, KEY_NUMERIC_5}, + { 0x06, KEY_NUMERIC_6}, + { 0x07, KEY_NUMERIC_7}, + { 0x08, KEY_NUMERIC_8}, + { 0x09, KEY_NUMERIC_9}, + { 0x00, KEY_NUMERIC_0}, { 0x0c, KEY_VOLUMEUP}, { 0x18, KEY_VOLUMEDOWN}, diff --git a/drivers/media/rc/keymaps/rc-reddo.c b/drivers/media/rc/keymaps/rc-reddo.c index a68003381540..b70390d19e78 100644 --- a/drivers/media/rc/keymaps/rc-reddo.c +++ b/drivers/media/rc/keymaps/rc-reddo.c @@ -23,21 +23,21 @@ static struct rc_map_table reddo[] = { { 0x61d601, KEY_EPG }, /* EPG */ - { 0x61d602, KEY_3 }, - { 0x61d604, KEY_1 }, - { 0x61d605, KEY_5 }, - { 0x61d606, KEY_6 }, + { 0x61d602, KEY_NUMERIC_3 }, + { 0x61d604, KEY_NUMERIC_1 }, + { 0x61d605, KEY_NUMERIC_5 }, + { 0x61d606, KEY_NUMERIC_6 }, { 0x61d607, KEY_CHANNELDOWN }, /* CH- */ - { 0x61d608, KEY_2 }, + { 0x61d608, KEY_NUMERIC_2 }, { 0x61d609, KEY_CHANNELUP }, /* CH+ */ - { 0x61d60a, KEY_9 }, + { 0x61d60a, KEY_NUMERIC_9 }, { 0x61d60b, KEY_ZOOM }, /* Zoom */ - { 0x61d60c, KEY_7 }, - { 0x61d60d, KEY_8 }, + { 0x61d60c, KEY_NUMERIC_7 }, + { 0x61d60d, KEY_NUMERIC_8 }, { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */ - { 0x61d60f, KEY_4 }, + { 0x61d60f, KEY_NUMERIC_4 }, { 0x61d610, KEY_ESC }, /* [back up arrow] */ - { 0x61d611, KEY_0 }, + { 0x61d611, KEY_NUMERIC_0 }, { 0x61d612, KEY_OK }, /* [enter arrow] */ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */ { 0x61d614, KEY_RECORD }, /* Rec */ diff --git a/drivers/media/rc/keymaps/rc-snapstream-firefly.c b/drivers/media/rc/keymaps/rc-snapstream-firefly.c index 8d55b4ccee83..e3d5bff3bd9e 100644 --- a/drivers/media/rc/keymaps/rc-snapstream-firefly.c +++ b/drivers/media/rc/keymaps/rc-snapstream-firefly.c @@ -12,16 +12,16 @@ static struct rc_map_table snapstream_firefly[] = { { 0x2c, KEY_ZOOM }, /* Maximize */ { 0x02, KEY_CLOSE }, - { 0x0d, KEY_1 }, - { 0x0e, KEY_2 }, - { 0x0f, KEY_3 }, - { 0x10, KEY_4 }, - { 0x11, KEY_5 }, - { 0x12, KEY_6 }, - { 0x13, KEY_7 }, - { 0x14, KEY_8 }, - { 0x15, KEY_9 }, - { 0x17, KEY_0 }, + { 0x0d, KEY_NUMERIC_1 }, + { 0x0e, KEY_NUMERIC_2 }, + { 0x0f, KEY_NUMERIC_3 }, + { 0x10, KEY_NUMERIC_4 }, + { 0x11, KEY_NUMERIC_5 }, + { 0x12, KEY_NUMERIC_6 }, + { 0x13, KEY_NUMERIC_7 }, + { 0x14, KEY_NUMERIC_8 }, + { 0x15, KEY_NUMERIC_9 }, + { 0x17, KEY_NUMERIC_0 }, { 0x16, KEY_BACK }, { 0x18, KEY_KPENTER }, /* ent */ diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c index 1c82737e3999..64cfc01aa48f 100644 --- a/drivers/media/rc/keymaps/rc-su3000.c +++ b/drivers/media/rc/keymaps/rc-su3000.c @@ -10,16 +10,16 @@ static struct rc_map_table su3000[] = { { 0x25, KEY_POWER }, /* right-bottom Red */ { 0x0a, KEY_MUTE }, /* -/-- */ - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x00, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, + { 0x00, KEY_NUMERIC_0 }, { 0x20, KEY_UP }, /* CH+ */ { 0x21, KEY_DOWN }, /* CH+ */ { 0x12, KEY_VOLUMEUP }, /* Brightness Up */ diff --git a/drivers/media/rc/keymaps/rc-tango.c b/drivers/media/rc/keymaps/rc-tango.c index 1c6e8875d46f..510bb25e0d56 100644 --- a/drivers/media/rc/keymaps/rc-tango.c +++ b/drivers/media/rc/keymaps/rc-tango.c @@ -20,16 +20,16 @@ static struct rc_map_table tango_table[] = { { 0x4cb51, KEY_MUTE }, { 0x4cb52, KEY_VOLUMEDOWN }, - { 0x4cb41, KEY_1 }, - { 0x4cb03, KEY_2 }, - { 0x4cb42, KEY_3 }, - { 0x4cb45, KEY_4 }, - { 0x4cb07, KEY_5 }, - { 0x4cb46, KEY_6 }, - { 0x4cb55, KEY_7 }, - { 0x4cb17, KEY_8 }, - { 0x4cb56, KEY_9 }, - { 0x4cb1b, KEY_0 }, + { 0x4cb41, KEY_NUMERIC_1 }, + { 0x4cb03, KEY_NUMERIC_2 }, + { 0x4cb42, KEY_NUMERIC_3 }, + { 0x4cb45, KEY_NUMERIC_4 }, + { 0x4cb07, KEY_NUMERIC_5 }, + { 0x4cb46, KEY_NUMERIC_6 }, + { 0x4cb55, KEY_NUMERIC_7 }, + { 0x4cb17, KEY_NUMERIC_8 }, + { 0x4cb56, KEY_NUMERIC_9 }, + { 0x4cb1b, KEY_NUMERIC_0 }, { 0x4cb59, KEY_DELETE }, { 0x4cb5a, KEY_CAPSLOCK }, diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c index 42766cb877c3..420980925f29 100644 --- a/drivers/media/rc/keymaps/rc-tbs-nec.c +++ b/drivers/media/rc/keymaps/rc-tbs-nec.c @@ -11,16 +11,16 @@ static struct rc_map_table tbs_nec[] = { { 0x84, KEY_POWER2}, /* power */ { 0x94, KEY_MUTE}, /* mute */ - { 0x87, KEY_1}, - { 0x86, KEY_2}, - { 0x85, KEY_3}, - { 0x8b, KEY_4}, - { 0x8a, KEY_5}, - { 0x89, KEY_6}, - { 0x8f, KEY_7}, - { 0x8e, KEY_8}, - { 0x8d, KEY_9}, - { 0x92, KEY_0}, + { 0x87, KEY_NUMERIC_1}, + { 0x86, KEY_NUMERIC_2}, + { 0x85, KEY_NUMERIC_3}, + { 0x8b, KEY_NUMERIC_4}, + { 0x8a, KEY_NUMERIC_5}, + { 0x89, KEY_NUMERIC_6}, + { 0x8f, KEY_NUMERIC_7}, + { 0x8e, KEY_NUMERIC_8}, + { 0x8d, KEY_NUMERIC_9}, + { 0x92, KEY_NUMERIC_0}, { 0xc0, KEY_10CHANNELSUP}, /* 10+ */ { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */ { 0x96, KEY_CHANNELUP}, /* ch+ */ diff --git a/drivers/media/rc/keymaps/rc-technisat-ts35.c b/drivers/media/rc/keymaps/rc-technisat-ts35.c index 34bd04a75277..9a917ea0ceba 100644 --- a/drivers/media/rc/keymaps/rc-technisat-ts35.c +++ b/drivers/media/rc/keymaps/rc-technisat-ts35.c @@ -13,16 +13,16 @@ static struct rc_map_table technisat_ts35[] = { {0x1c, KEY_AB}, {0x33, KEY_POWER}, - {0x3e, KEY_1}, - {0x3d, KEY_2}, - {0x3c, KEY_3}, - {0x3b, KEY_4}, - {0x3a, KEY_5}, - {0x39, KEY_6}, - {0x38, KEY_7}, - {0x37, KEY_8}, - {0x36, KEY_9}, - {0x3f, KEY_0}, + {0x3e, KEY_NUMERIC_1}, + {0x3d, KEY_NUMERIC_2}, + {0x3c, KEY_NUMERIC_3}, + {0x3b, KEY_NUMERIC_4}, + {0x3a, KEY_NUMERIC_5}, + {0x39, KEY_NUMERIC_6}, + {0x38, KEY_NUMERIC_7}, + {0x37, KEY_NUMERIC_8}, + {0x36, KEY_NUMERIC_9}, + {0x3f, KEY_NUMERIC_0}, {0x35, KEY_DIGITS}, {0x2c, KEY_TV}, diff --git a/drivers/media/rc/keymaps/rc-technisat-usb2.c b/drivers/media/rc/keymaps/rc-technisat-usb2.c index 58b3baf5ee96..942100686c82 100644 --- a/drivers/media/rc/keymaps/rc-technisat-usb2.c +++ b/drivers/media/rc/keymaps/rc-technisat-usb2.c @@ -30,18 +30,18 @@ static struct rc_map_table technisat_usb2[] = { {0x0a0c, KEY_POWER}, - {0x0a01, KEY_1}, - {0x0a02, KEY_2}, - {0x0a03, KEY_3}, + {0x0a01, KEY_NUMERIC_1}, + {0x0a02, KEY_NUMERIC_2}, + {0x0a03, KEY_NUMERIC_3}, {0x0a0d, KEY_MUTE}, - {0x0a04, KEY_4}, - {0x0a05, KEY_5}, - {0x0a06, KEY_6}, + {0x0a04, KEY_NUMERIC_4}, + {0x0a05, KEY_NUMERIC_5}, + {0x0a06, KEY_NUMERIC_6}, {0x0a38, KEY_VIDEO}, /* EXT */ - {0x0a07, KEY_7}, - {0x0a08, KEY_8}, - {0x0a09, KEY_9}, - {0x0a00, KEY_0}, + {0x0a07, KEY_NUMERIC_7}, + {0x0a08, KEY_NUMERIC_8}, + {0x0a09, KEY_NUMERIC_9}, + {0x0a00, KEY_NUMERIC_0}, {0x0a4f, KEY_INFO}, {0x0a20, KEY_CHANNELUP}, {0x0a52, KEY_MENU}, diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c index 4b2741b158c4..da06f844d8fb 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-c-pci.c @@ -9,17 +9,17 @@ static struct rc_map_table terratec_cinergy_c_pci[] = { { 0x3e, KEY_POWER}, - { 0x3d, KEY_1}, - { 0x3c, KEY_2}, - { 0x3b, KEY_3}, - { 0x3a, KEY_4}, - { 0x39, KEY_5}, - { 0x38, KEY_6}, - { 0x37, KEY_7}, - { 0x36, KEY_8}, - { 0x35, KEY_9}, + { 0x3d, KEY_NUMERIC_1}, + { 0x3c, KEY_NUMERIC_2}, + { 0x3b, KEY_NUMERIC_3}, + { 0x3a, KEY_NUMERIC_4}, + { 0x39, KEY_NUMERIC_5}, + { 0x38, KEY_NUMERIC_6}, + { 0x37, KEY_NUMERIC_7}, + { 0x36, KEY_NUMERIC_8}, + { 0x35, KEY_NUMERIC_9}, { 0x34, KEY_VIDEO_NEXT}, /* AV */ - { 0x33, KEY_0}, + { 0x33, KEY_NUMERIC_0}, { 0x32, KEY_REFRESH}, { 0x30, KEY_EPG}, { 0x2f, KEY_UP}, diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c index 631f86665206..a1844b531572 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-s2-hd.c @@ -42,17 +42,17 @@ static struct rc_map_table terratec_cinergy_s2_hd[] = { { 0x2f, KEY_UP}, { 0x30, KEY_EPG}, { 0x32, KEY_VIDEO}, /* A<=>B */ - { 0x33, KEY_0}, + { 0x33, KEY_NUMERIC_0}, { 0x34, KEY_VCR}, /* AV */ - { 0x35, KEY_9}, - { 0x36, KEY_8}, - { 0x37, KEY_7}, - { 0x38, KEY_6}, - { 0x39, KEY_5}, - { 0x3a, KEY_4}, - { 0x3b, KEY_3}, - { 0x3c, KEY_2}, - { 0x3d, KEY_1}, + { 0x35, KEY_NUMERIC_9}, + { 0x36, KEY_NUMERIC_8}, + { 0x37, KEY_NUMERIC_7}, + { 0x38, KEY_NUMERIC_6}, + { 0x39, KEY_NUMERIC_5}, + { 0x3a, KEY_NUMERIC_4}, + { 0x3b, KEY_NUMERIC_3}, + { 0x3c, KEY_NUMERIC_2}, + { 0x3d, KEY_NUMERIC_1}, { 0x3e, KEY_POWER}, }; diff --git a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c index 6cf53a56bce4..fe587e3f0240 100644 --- a/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c +++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c @@ -16,20 +16,20 @@ static struct rc_map_table terratec_cinergy_xs[] = { { 0x41, KEY_HOME}, { 0x01, KEY_POWER}, { 0x42, KEY_MENU}, - { 0x02, KEY_1}, - { 0x03, KEY_2}, - { 0x04, KEY_3}, + { 0x02, KEY_NUMERIC_1}, + { 0x03, KEY_NUMERIC_2}, + { 0x04, KEY_NUMERIC_3}, { 0x43, KEY_SUBTITLE}, - { 0x05, KEY_4}, - { 0x06, KEY_5}, - { 0x07, KEY_6}, + { 0x05, KEY_NUMERIC_4}, + { 0x06, KEY_NUMERIC_5}, + { 0x07, KEY_NUMERIC_6}, { 0x44, KEY_TEXT}, - { 0x08, KEY_7}, - { 0x09, KEY_8}, - { 0x0a, KEY_9}, + { 0x08, KEY_NUMERIC_7}, + { 0x09, KEY_NUMERIC_8}, + { 0x0a, KEY_NUMERIC_9}, { 0x45, KEY_DELETE}, { 0x0b, KEY_TUNER}, - { 0x0c, KEY_0}, + { 0x0c, KEY_NUMERIC_0}, { 0x0d, KEY_MODE}, { 0x46, KEY_TV}, { 0x47, KEY_DVD}, diff --git a/drivers/media/rc/keymaps/rc-terratec-slim-2.c b/drivers/media/rc/keymaps/rc-terratec-slim-2.c index bd1c1761b550..a54a59f90313 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim-2.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim-2.c @@ -17,21 +17,21 @@ static struct rc_map_table terratec_slim_2[] = { { 0x8001, KEY_MUTE }, /* MUTE */ { 0x8002, KEY_VOLUMEDOWN }, { 0x8003, KEY_CHANNELDOWN }, - { 0x8004, KEY_1 }, - { 0x8005, KEY_2 }, - { 0x8006, KEY_3 }, - { 0x8007, KEY_4 }, - { 0x8008, KEY_5 }, - { 0x8009, KEY_6 }, - { 0x800a, KEY_7 }, + { 0x8004, KEY_NUMERIC_1 }, + { 0x8005, KEY_NUMERIC_2 }, + { 0x8006, KEY_NUMERIC_3 }, + { 0x8007, KEY_NUMERIC_4 }, + { 0x8008, KEY_NUMERIC_5 }, + { 0x8009, KEY_NUMERIC_6 }, + { 0x800a, KEY_NUMERIC_7 }, { 0x800c, KEY_ZOOM }, /* [fullscreen] */ - { 0x800d, KEY_0 }, + { 0x800d, KEY_NUMERIC_0 }, { 0x800e, KEY_AGAIN }, /* [two arrows forming a circle] */ { 0x8012, KEY_POWER2 }, /* [red power button] */ { 0x801a, KEY_VOLUMEUP }, - { 0x801b, KEY_8 }, + { 0x801b, KEY_NUMERIC_8 }, { 0x801e, KEY_CHANNELUP }, - { 0x801f, KEY_9 }, + { 0x801f, KEY_NUMERIC_9 }, }; static struct rc_map_list terratec_slim_2_map = { diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c index b44942691388..146e3a3480dc 100644 --- a/drivers/media/rc/keymaps/rc-terratec-slim.c +++ b/drivers/media/rc/keymaps/rc-terratec-slim.c @@ -11,16 +11,16 @@ /* TerraTec slim remote, 7 rows, 4 columns. */ /* Uses NEC extended 0x02bd. */ static struct rc_map_table terratec_slim[] = { - { 0x02bd00, KEY_1 }, - { 0x02bd01, KEY_2 }, - { 0x02bd02, KEY_3 }, - { 0x02bd03, KEY_4 }, - { 0x02bd04, KEY_5 }, - { 0x02bd05, KEY_6 }, - { 0x02bd06, KEY_7 }, - { 0x02bd07, KEY_8 }, - { 0x02bd08, KEY_9 }, - { 0x02bd09, KEY_0 }, + { 0x02bd00, KEY_NUMERIC_1 }, + { 0x02bd01, KEY_NUMERIC_2 }, + { 0x02bd02, KEY_NUMERIC_3 }, + { 0x02bd03, KEY_NUMERIC_4 }, + { 0x02bd04, KEY_NUMERIC_5 }, + { 0x02bd05, KEY_NUMERIC_6 }, + { 0x02bd06, KEY_NUMERIC_7 }, + { 0x02bd07, KEY_NUMERIC_8 }, + { 0x02bd08, KEY_NUMERIC_9 }, + { 0x02bd09, KEY_NUMERIC_0 }, { 0x02bd0a, KEY_MUTE }, { 0x02bd0b, KEY_NEW }, /* symbol: PIP */ { 0x02bd0e, KEY_VOLUMEDOWN }, diff --git a/drivers/media/rc/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c index 58fcc72f528e..5b96e9a38e9d 100644 --- a/drivers/media/rc/keymaps/rc-tevii-nec.c +++ b/drivers/media/rc/keymaps/rc-tevii-nec.c @@ -11,16 +11,16 @@ static struct rc_map_table tevii_nec[] = { { 0x0a, KEY_POWER2}, { 0x0c, KEY_MUTE}, - { 0x11, KEY_1}, - { 0x12, KEY_2}, - { 0x13, KEY_3}, - { 0x14, KEY_4}, - { 0x15, KEY_5}, - { 0x16, KEY_6}, - { 0x17, KEY_7}, - { 0x18, KEY_8}, - { 0x19, KEY_9}, - { 0x10, KEY_0}, + { 0x11, KEY_NUMERIC_1}, + { 0x12, KEY_NUMERIC_2}, + { 0x13, KEY_NUMERIC_3}, + { 0x14, KEY_NUMERIC_4}, + { 0x15, KEY_NUMERIC_5}, + { 0x16, KEY_NUMERIC_6}, + { 0x17, KEY_NUMERIC_7}, + { 0x18, KEY_NUMERIC_8}, + { 0x19, KEY_NUMERIC_9}, + { 0x10, KEY_NUMERIC_0}, { 0x1c, KEY_MENU}, { 0x0f, KEY_VOLUMEDOWN}, { 0x1a, KEY_LAST}, diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c index 7dfaf05f4934..40b773ba45b9 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand-02.c @@ -10,16 +10,16 @@ static struct rc_map_table total_media_in_hand_02[] = { - { 0x0000, KEY_0 }, - { 0x0001, KEY_1 }, - { 0x0002, KEY_2 }, - { 0x0003, KEY_3 }, - { 0x0004, KEY_4 }, - { 0x0005, KEY_5 }, - { 0x0006, KEY_6 }, - { 0x0007, KEY_7 }, - { 0x0008, KEY_8 }, - { 0x0009, KEY_9 }, + { 0x0000, KEY_NUMERIC_0 }, + { 0x0001, KEY_NUMERIC_1 }, + { 0x0002, KEY_NUMERIC_2 }, + { 0x0003, KEY_NUMERIC_3 }, + { 0x0004, KEY_NUMERIC_4 }, + { 0x0005, KEY_NUMERIC_5 }, + { 0x0006, KEY_NUMERIC_6 }, + { 0x0007, KEY_NUMERIC_7 }, + { 0x0008, KEY_NUMERIC_8 }, + { 0x0009, KEY_NUMERIC_9 }, { 0x000a, KEY_MUTE }, { 0x000b, KEY_STOP }, /* Stop */ { 0x000c, KEY_POWER2 }, /* Turn on/off application */ diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c index a12569425b8b..2144db485d83 100644 --- a/drivers/media/rc/keymaps/rc-total-media-in-hand.c +++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c @@ -10,16 +10,16 @@ /* Uses NEC extended 0x02bd */ static struct rc_map_table total_media_in_hand[] = { - { 0x02bd00, KEY_1 }, - { 0x02bd01, KEY_2 }, - { 0x02bd02, KEY_3 }, - { 0x02bd03, KEY_4 }, - { 0x02bd04, KEY_5 }, - { 0x02bd05, KEY_6 }, - { 0x02bd06, KEY_7 }, - { 0x02bd07, KEY_8 }, - { 0x02bd08, KEY_9 }, - { 0x02bd09, KEY_0 }, + { 0x02bd00, KEY_NUMERIC_1 }, + { 0x02bd01, KEY_NUMERIC_2 }, + { 0x02bd02, KEY_NUMERIC_3 }, + { 0x02bd03, KEY_NUMERIC_4 }, + { 0x02bd04, KEY_NUMERIC_5 }, + { 0x02bd05, KEY_NUMERIC_6 }, + { 0x02bd06, KEY_NUMERIC_7 }, + { 0x02bd07, KEY_NUMERIC_8 }, + { 0x02bd08, KEY_NUMERIC_9 }, + { 0x02bd09, KEY_NUMERIC_0 }, { 0x02bd0a, KEY_MUTE }, { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */ { 0x02bd0c, KEY_VIDEO }, /* TV / AV */ diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c index 8576831b20bd..e938e0da51a6 100644 --- a/drivers/media/rc/keymaps/rc-trekstor.c +++ b/drivers/media/rc/keymaps/rc-trekstor.c @@ -12,7 +12,7 @@ /* Imported from af9015.h. Initial keytable was from Marc Schneider */ static struct rc_map_table trekstor[] = { - { 0x0084, KEY_0 }, + { 0x0084, KEY_NUMERIC_0 }, { 0x0085, KEY_MUTE }, /* Mute */ { 0x0086, KEY_HOMEPAGE }, /* Home */ { 0x0087, KEY_UP }, /* Up */ @@ -24,17 +24,17 @@ static struct rc_map_table trekstor[] = { { 0x008d, KEY_PLAY }, /* Play/Pause */ { 0x008e, KEY_STOP }, /* Stop */ { 0x008f, KEY_EPG }, /* Info/EPG */ - { 0x0090, KEY_7 }, - { 0x0091, KEY_4 }, - { 0x0092, KEY_1 }, + { 0x0090, KEY_NUMERIC_7 }, + { 0x0091, KEY_NUMERIC_4 }, + { 0x0092, KEY_NUMERIC_1 }, { 0x0093, KEY_CHANNELDOWN }, /* Channel - */ - { 0x0094, KEY_8 }, - { 0x0095, KEY_5 }, - { 0x0096, KEY_2 }, + { 0x0094, KEY_NUMERIC_8 }, + { 0x0095, KEY_NUMERIC_5 }, + { 0x0096, KEY_NUMERIC_2 }, { 0x0097, KEY_CHANNELUP }, /* Channel + */ - { 0x0098, KEY_9 }, - { 0x0099, KEY_6 }, - { 0x009a, KEY_3 }, + { 0x0098, KEY_NUMERIC_9 }, + { 0x0099, KEY_NUMERIC_6 }, + { 0x009a, KEY_NUMERIC_3 }, { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */ { 0x009c, KEY_TV }, /* TV */ { 0x009d, KEY_RECORD }, /* Record */ diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c index 52f239d2c025..ff70aab13b48 100644 --- a/drivers/media/rc/keymaps/rc-tt-1500.c +++ b/drivers/media/rc/keymaps/rc-tt-1500.c @@ -13,16 +13,16 @@ static struct rc_map_table tt_1500[] = { { 0x1501, KEY_POWER }, { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */ - { 0x1503, KEY_1 }, - { 0x1504, KEY_2 }, - { 0x1505, KEY_3 }, - { 0x1506, KEY_4 }, - { 0x1507, KEY_5 }, - { 0x1508, KEY_6 }, - { 0x1509, KEY_7 }, - { 0x150a, KEY_8 }, - { 0x150b, KEY_9 }, - { 0x150c, KEY_0 }, + { 0x1503, KEY_NUMERIC_1 }, + { 0x1504, KEY_NUMERIC_2 }, + { 0x1505, KEY_NUMERIC_3 }, + { 0x1506, KEY_NUMERIC_4 }, + { 0x1507, KEY_NUMERIC_5 }, + { 0x1508, KEY_NUMERIC_6 }, + { 0x1509, KEY_NUMERIC_7 }, + { 0x150a, KEY_NUMERIC_8 }, + { 0x150b, KEY_NUMERIC_9 }, + { 0x150c, KEY_NUMERIC_0 }, { 0x150d, KEY_UP }, { 0x150e, KEY_LEFT }, { 0x150f, KEY_OK }, diff --git a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c index a72cb06a811e..5fc696d9e583 100644 --- a/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c +++ b/drivers/media/rc/keymaps/rc-twinhan-dtv-cab-ci.c @@ -15,16 +15,16 @@ static struct rc_map_table twinhan_dtv_cab_ci[] = { { 0x23, KEY_EPG}, { 0x3b, KEY_F22}, /* Record List */ - { 0x3c, KEY_1}, - { 0x3e, KEY_2}, - { 0x39, KEY_3}, - { 0x36, KEY_4}, - { 0x22, KEY_5}, - { 0x20, KEY_6}, - { 0x32, KEY_7}, - { 0x26, KEY_8}, - { 0x24, KEY_9}, - { 0x2a, KEY_0}, + { 0x3c, KEY_NUMERIC_1}, + { 0x3e, KEY_NUMERIC_2}, + { 0x39, KEY_NUMERIC_3}, + { 0x36, KEY_NUMERIC_4}, + { 0x22, KEY_NUMERIC_5}, + { 0x20, KEY_NUMERIC_6}, + { 0x32, KEY_NUMERIC_7}, + { 0x26, KEY_NUMERIC_8}, + { 0x24, KEY_NUMERIC_9}, + { 0x2a, KEY_NUMERIC_0}, { 0x33, KEY_CANCEL}, { 0x2c, KEY_BACK}, diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c index 3ee28bcf31dc..e1cdcfa792dc 100644 --- a/drivers/media/rc/keymaps/rc-twinhan1027.c +++ b/drivers/media/rc/keymaps/rc-twinhan1027.c @@ -10,16 +10,16 @@ static struct rc_map_table twinhan_vp1027[] = { { 0x1c, KEY_EPG }, { 0x04, KEY_LIST }, - { 0x03, KEY_1 }, - { 0x01, KEY_2 }, - { 0x06, KEY_3 }, - { 0x09, KEY_4 }, - { 0x1d, KEY_5 }, - { 0x1f, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x19, KEY_8 }, - { 0x1b, KEY_9 }, - { 0x15, KEY_0 }, + { 0x03, KEY_NUMERIC_1 }, + { 0x01, KEY_NUMERIC_2 }, + { 0x06, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x1d, KEY_NUMERIC_5 }, + { 0x1f, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x19, KEY_NUMERIC_8 }, + { 0x1b, KEY_NUMERIC_9 }, + { 0x15, KEY_NUMERIC_0 }, { 0x0c, KEY_CANCEL }, { 0x4a, KEY_CLEAR }, diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c index d2d183759a03..e16b9b851c72 100644 --- a/drivers/media/rc/keymaps/rc-videomate-m1f.c +++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c @@ -41,17 +41,17 @@ static struct rc_map_table videomate_k100[] = { { 0x10, KEY_PREVIOUS }, { 0x0d, KEY_PAUSE }, { 0x0f, KEY_NEXT }, - { 0x1e, KEY_1 }, - { 0x1f, KEY_2 }, - { 0x20, KEY_3 }, - { 0x21, KEY_4 }, - { 0x22, KEY_5 }, - { 0x23, KEY_6 }, - { 0x24, KEY_7 }, - { 0x25, KEY_8 }, - { 0x26, KEY_9 }, + { 0x1e, KEY_NUMERIC_1 }, + { 0x1f, KEY_NUMERIC_2 }, + { 0x20, KEY_NUMERIC_3 }, + { 0x21, KEY_NUMERIC_4 }, + { 0x22, KEY_NUMERIC_5 }, + { 0x23, KEY_NUMERIC_6 }, + { 0x24, KEY_NUMERIC_7 }, + { 0x25, KEY_NUMERIC_8 }, + { 0x26, KEY_NUMERIC_9 }, { 0x2a, KEY_NUMERIC_STAR }, /* * key */ - { 0x1d, KEY_0 }, + { 0x1d, KEY_NUMERIC_0 }, { 0x29, KEY_SUBTITLE }, /* # key */ { 0x27, KEY_CLEAR }, { 0x34, KEY_SCREEN }, diff --git a/drivers/media/rc/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c index e4d4dff06a24..a867d7a08055 100644 --- a/drivers/media/rc/keymaps/rc-videomate-s350.c +++ b/drivers/media/rc/keymaps/rc-videomate-s350.c @@ -22,16 +22,16 @@ static struct rc_map_table videomate_s350[] = { { 0x13, KEY_CHANNELDOWN}, { 0x14, KEY_MUTE}, { 0x15, KEY_VOLUMEDOWN}, - { 0x16, KEY_1}, - { 0x17, KEY_2}, - { 0x18, KEY_3}, - { 0x19, KEY_4}, - { 0x1a, KEY_5}, - { 0x1b, KEY_6}, - { 0x1c, KEY_7}, - { 0x1d, KEY_8}, - { 0x1e, KEY_9}, - { 0x1f, KEY_0}, + { 0x16, KEY_NUMERIC_1}, + { 0x17, KEY_NUMERIC_2}, + { 0x18, KEY_NUMERIC_3}, + { 0x19, KEY_NUMERIC_4}, + { 0x1a, KEY_NUMERIC_5}, + { 0x1b, KEY_NUMERIC_6}, + { 0x1c, KEY_NUMERIC_7}, + { 0x1d, KEY_NUMERIC_8}, + { 0x1e, KEY_NUMERIC_9}, + { 0x1f, KEY_NUMERIC_0}, { 0x21, KEY_SLEEP}, { 0x24, KEY_ZOOM}, { 0x25, KEY_LAST}, /* Recall */ diff --git a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c index 7c4890944407..fdc3b0e1350f 100644 --- a/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c +++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c @@ -42,16 +42,16 @@ static struct rc_map_table videomate_tv_pvr[] = { { 0x04, KEY_RECORD }, - { 0x16, KEY_1 }, - { 0x17, KEY_2 }, - { 0x18, KEY_3 }, - { 0x19, KEY_4 }, - { 0x1a, KEY_5 }, - { 0x1b, KEY_6 }, - { 0x1c, KEY_7 }, - { 0x1d, KEY_8 }, - { 0x1e, KEY_9 }, - { 0x1f, KEY_0 }, + { 0x16, KEY_NUMERIC_1 }, + { 0x17, KEY_NUMERIC_2 }, + { 0x18, KEY_NUMERIC_3 }, + { 0x19, KEY_NUMERIC_4 }, + { 0x1a, KEY_NUMERIC_5 }, + { 0x1b, KEY_NUMERIC_6 }, + { 0x1c, KEY_NUMERIC_7 }, + { 0x1d, KEY_NUMERIC_8 }, + { 0x1e, KEY_NUMERIC_9 }, + { 0x1f, KEY_NUMERIC_0 }, { 0x20, KEY_LANGUAGE }, { 0x21, KEY_SLEEP }, diff --git a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c index e443192dbe14..999ba4e084ae 100644 --- a/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c +++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c @@ -13,16 +13,16 @@ */ static struct rc_map_table winfast_usbii_deluxe[] = { - { 0x62, KEY_0}, - { 0x75, KEY_1}, - { 0x76, KEY_2}, - { 0x77, KEY_3}, - { 0x79, KEY_4}, - { 0x7a, KEY_5}, - { 0x7b, KEY_6}, - { 0x7d, KEY_7}, - { 0x7e, KEY_8}, - { 0x7f, KEY_9}, + { 0x62, KEY_NUMERIC_0}, + { 0x75, KEY_NUMERIC_1}, + { 0x76, KEY_NUMERIC_2}, + { 0x77, KEY_NUMERIC_3}, + { 0x79, KEY_NUMERIC_4}, + { 0x7a, KEY_NUMERIC_5}, + { 0x7b, KEY_NUMERIC_6}, + { 0x7d, KEY_NUMERIC_7}, + { 0x7e, KEY_NUMERIC_8}, + { 0x7f, KEY_NUMERIC_9}, { 0x38, KEY_CAMERA}, /* SNAPSHOT */ { 0x37, KEY_RECORD}, /* RECORD */ diff --git a/drivers/media/rc/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c index ee7f4c349fd6..be52a3e1f8ae 100644 --- a/drivers/media/rc/keymaps/rc-winfast.c +++ b/drivers/media/rc/keymaps/rc-winfast.c @@ -12,16 +12,16 @@ static struct rc_map_table winfast[] = { /* Keys 0 to 9 */ - { 0x12, KEY_0 }, - { 0x05, KEY_1 }, - { 0x06, KEY_2 }, - { 0x07, KEY_3 }, - { 0x09, KEY_4 }, - { 0x0a, KEY_5 }, - { 0x0b, KEY_6 }, - { 0x0d, KEY_7 }, - { 0x0e, KEY_8 }, - { 0x0f, KEY_9 }, + { 0x12, KEY_NUMERIC_0 }, + { 0x05, KEY_NUMERIC_1 }, + { 0x06, KEY_NUMERIC_2 }, + { 0x07, KEY_NUMERIC_3 }, + { 0x09, KEY_NUMERIC_4 }, + { 0x0a, KEY_NUMERIC_5 }, + { 0x0b, KEY_NUMERIC_6 }, + { 0x0d, KEY_NUMERIC_7 }, + { 0x0e, KEY_NUMERIC_8 }, + { 0x0f, KEY_NUMERIC_9 }, { 0x00, KEY_POWER2 }, { 0x1b, KEY_AUDIO }, /* Audio Source */ diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c index 42815ab57bff..9d656042a81f 100644 --- a/drivers/media/rc/keymaps/rc-xbox-dvd.c +++ b/drivers/media/rc/keymaps/rc-xbox-dvd.c @@ -14,16 +14,16 @@ static struct rc_map_table xbox_dvd[] = { {0xaa9, KEY_LEFT}, {0xac3, KEY_INFO}, - {0xac6, KEY_9}, - {0xac7, KEY_8}, - {0xac8, KEY_7}, - {0xac9, KEY_6}, - {0xaca, KEY_5}, - {0xacb, KEY_4}, - {0xacc, KEY_3}, - {0xacd, KEY_2}, - {0xace, KEY_1}, - {0xacf, KEY_0}, + {0xac6, KEY_NUMERIC_9}, + {0xac7, KEY_NUMERIC_8}, + {0xac8, KEY_NUMERIC_7}, + {0xac9, KEY_NUMERIC_6}, + {0xaca, KEY_NUMERIC_5}, + {0xacb, KEY_NUMERIC_4}, + {0xacc, KEY_NUMERIC_3}, + {0xacd, KEY_NUMERIC_2}, + {0xace, KEY_NUMERIC_1}, + {0xacf, KEY_NUMERIC_0}, {0xad5, KEY_ANGLE}, {0xad8, KEY_BACK}, diff --git a/drivers/media/rc/keymaps/rc-zx-irdec.c b/drivers/media/rc/keymaps/rc-zx-irdec.c index 5bf3ab002afc..96466aa13fb9 100644 --- a/drivers/media/rc/keymaps/rc-zx-irdec.c +++ b/drivers/media/rc/keymaps/rc-zx-irdec.c @@ -11,16 +11,16 @@ #include static struct rc_map_table zx_irdec_table[] = { - { 0x01, KEY_1 }, - { 0x02, KEY_2 }, - { 0x03, KEY_3 }, - { 0x04, KEY_4 }, - { 0x05, KEY_5 }, - { 0x06, KEY_6 }, - { 0x07, KEY_7 }, - { 0x08, KEY_8 }, - { 0x09, KEY_9 }, - { 0x31, KEY_0 }, + { 0x01, KEY_NUMERIC_1 }, + { 0x02, KEY_NUMERIC_2 }, + { 0x03, KEY_NUMERIC_3 }, + { 0x04, KEY_NUMERIC_4 }, + { 0x05, KEY_NUMERIC_5 }, + { 0x06, KEY_NUMERIC_6 }, + { 0x07, KEY_NUMERIC_7 }, + { 0x08, KEY_NUMERIC_8 }, + { 0x09, KEY_NUMERIC_9 }, + { 0x31, KEY_NUMERIC_0 }, { 0x16, KEY_DELETE }, { 0x0a, KEY_MODE }, /* Input method */ { 0x0c, KEY_VOLUMEUP }, -- cgit v1.2.3-59-g8ed1b From b09a2ab2baeb36bf7ef7780405ad172281741c7c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 25 Jun 2019 06:45:20 -0400 Subject: media: stv0297: fix frequency range limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There was a typo at the lower frequency limit for a DVB-C card, causing the driver to fail while tuning channels at the VHF range. https://bugzilla.kernel.org/show_bug.cgi?id=202083 Fixes: f1b1eabff0eb ("media: dvb: represent min/max/step/tolerance freqs in Hz") Reported-by: Ari Kohtamäki Cc: stable@vger.kernel.org Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv0297.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c index dac396c95a59..6d5962d5697a 100644 --- a/drivers/media/dvb-frontends/stv0297.c +++ b/drivers/media/dvb-frontends/stv0297.c @@ -682,7 +682,7 @@ static const struct dvb_frontend_ops stv0297_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0297 DVB-C", - .frequency_min_hz = 470 * MHz, + .frequency_min_hz = 47 * MHz, .frequency_max_hz = 862 * MHz, .frequency_stepsize_hz = 62500, .symbol_rate_min = 870000, -- cgit v1.2.3-59-g8ed1b From c666355e60ddb4748ead3bdd983e3f7f2224aaf0 Mon Sep 17 00:00:00 2001 From: Luke Nowakowski-Krijger Date: Fri, 21 Jun 2019 21:04:38 -0400 Subject: media: radio-raremono: change devm_k*alloc to k*alloc Change devm_k*alloc to k*alloc to manually allocate memory The manual allocation and freeing of memory is necessary because when the USB radio is disconnected, the memory associated with devm_k*alloc is freed. Meaning if we still have unresolved references to the radio device, then we get use-after-free errors. This patch fixes this by manually allocating memory, and freeing it in the v4l2.release callback that gets called when the last radio device exits. Reported-and-tested-by: syzbot+a4387f5b6b799f6becbf@syzkaller.appspotmail.com Signed-off-by: Luke Nowakowski-Krijger Signed-off-by: Hans Verkuil [hverkuil-cisco@xs4all.nl: cleaned up two small checkpatch.pl warnings] [hverkuil-cisco@xs4all.nl: prefix subject with driver name] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-raremono.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c index 606f588e1edf..c3180d53c282 100644 --- a/drivers/media/radio/radio-raremono.c +++ b/drivers/media/radio/radio-raremono.c @@ -269,6 +269,14 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } +static void raremono_device_release(struct v4l2_device *v4l2_dev) +{ + struct raremono_device *radio = to_raremono_dev(v4l2_dev); + + kfree(radio->buffer); + kfree(radio); +} + /* File system interface */ static const struct v4l2_file_operations usb_raremono_fops = { .owner = THIS_MODULE, @@ -293,12 +301,14 @@ static int usb_raremono_probe(struct usb_interface *intf, struct raremono_device *radio; int retval = 0; - radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL); - if (radio) - radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL); - - if (!radio || !radio->buffer) + radio = kzalloc(sizeof(*radio), GFP_KERNEL); + if (!radio) + return -ENOMEM; + radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); + if (!radio->buffer) { + kfree(radio); return -ENOMEM; + } radio->usbdev = interface_to_usbdev(intf); radio->intf = intf; @@ -322,7 +332,8 @@ static int usb_raremono_probe(struct usb_interface *intf, if (retval != 3 || (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) { dev_info(&intf->dev, "this is not Thanko's Raremono.\n"); - return -ENODEV; + retval = -ENODEV; + goto free_mem; } dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n", @@ -331,7 +342,7 @@ static int usb_raremono_probe(struct usb_interface *intf, retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); if (retval < 0) { dev_err(&intf->dev, "couldn't register v4l2_device\n"); - return retval; + goto free_mem; } mutex_init(&radio->lock); @@ -344,6 +355,7 @@ static int usb_raremono_probe(struct usb_interface *intf, radio->vdev.lock = &radio->lock; radio->vdev.release = video_device_release_empty; radio->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO; + radio->v4l2_dev.release = raremono_device_release; usb_set_intfdata(intf, &radio->v4l2_dev); @@ -359,6 +371,10 @@ static int usb_raremono_probe(struct usb_interface *intf, } dev_err(&intf->dev, "could not register video device\n"); v4l2_device_unregister(&radio->v4l2_dev); + +free_mem: + kfree(radio->buffer); + kfree(radio); return retval; } -- cgit v1.2.3-59-g8ed1b