1

media fixes for v6.12-rc7

-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEE+QmuaPwR3wnBdVwACF8+vY7k4RUFAmcuCKQACgkQCF8+vY7k
 4RWV5w/+Jc2i6rGzHU/s78cYh1MUvHOmMl6mxehvQ/NIlNlIW3mlciS8BuT/mn0O
 f/+cNQ/wkaxrQrZWyOd2oCFZu4HeEY1o4/SlOxAH0HHks0/JRKrbkmzvd6PN8rUe
 dF/b8LDcHr9XhR1u8S1WQQfvP9k68pjOjaWhCLg5ivAIe5hB5hjyl9TSTH50sEJ+
 DrIwidfsfderABDhj9Hp3JWCtxJ6KHkgucx+pDwUdsdQZHAjNMQ9r8zgDLhp3t11
 VyZEvHrVZcE2hR2nrCLVOmiyZZ/JGmUBamHageii1lBc4jBMQZmTrHgaioganK+q
 6q2D26WqfBC/6FvNiCnE8FeXF9iUUdx+F1RhX+LMochtYfKh+hRQhAGLFNNqHSha
 MfpzDeU5K7TVyY1tehwa9yZ9z1Was48vGmb3raDTUmFCkDtn8nkhuKL7OgKBKIO5
 riRtePDRdHZ3qYstARplokPBtegSiW/nSlmJOzvHqO/Lbp+ncqy13GhgQxfduOxp
 oWpmcEbEPDNItFVDqXYlLaJdaPNKkIJwkkv7uOS2ungjTFp48pgWNcCoZaWdCHCt
 J2V2tvQOsbpsQicOxw9cqQgFyhBquMem5o0NZhtPbuNW7RX5KsFk6nmLlXYf6wDd
 vVWp1X5hQIdsFpbrgD7e8WvomQ1UjnZQUZDgekaW9esDDhH0fkI=
 =SGfF
 -----END PGP SIGNATURE-----

Merge tag 'media/v6.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media fixes from Mauro Carvalho Chehab:

 - dvb-core fixes for vb2 check and device registration

 - v4l2-core: fix an issue with error handling for VIDIOC_G_CTRL

 - vb2 core: fix an issue with vb plane copy logic

 - videobuf2-core: copy vb planes unconditionally

 - vivid: fix buffer overwrite when using > 32 buffers

 - vivid: fix a potential division by zero due to an issue at v4l2-tpg

 - some spectre vulnerability fixes

 - several OOM access fixes

 - some buffer overflow fixes

* tag 'media/v6.12-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  media: videobuf2-core: copy vb planes unconditionally
  media: dvbdev: fix the logic when DVB_DYNAMIC_MINORS is not set
  media: vivid: fix buffer overwrite when using > 32 buffers
  media: pulse8-cec: fix data timestamp at pulse8_setup()
  media: cec: extron-da-hd-4k-plus: don't use -1 as an error code
  media: stb0899_algo: initialize cfr before using it
  media: adv7604: prevent underflow condition when reporting colorspace
  media: cx24116: prevent overflows on SNR calculus
  media: ar0521: don't overflow when checking PLL values
  media: s5p-jpeg: prevent buffer overflows
  media: av7110: fix a spectre vulnerability
  media: mgb4: protect driver against spectre
  media: dvb_frontend: don't play tricks with underflow values
  media: dvbdev: prevent the risk of out of memory access
  media: v4l2-tpg: prevent the risk of a division by zero
  media: v4l2-ctrls-api: fix error handling for v4l2_g_ctrl()
  media: dvb-core: add missing buffer index check
This commit is contained in:
Linus Torvalds 2024-11-08 07:41:27 -10:00
commit ceb061330d
20 changed files with 118 additions and 63 deletions

View File

@ -348,12 +348,12 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size,
/* Return if not a CTA-861 extension block */ /* Return if not a CTA-861 extension block */
if (size < 256 || edid[0] != 0x02 || edid[1] != 0x03) if (size < 256 || edid[0] != 0x02 || edid[1] != 0x03)
return -1; return -ENOENT;
/* search tag */ /* search tag */
d = edid[0x02] & 0x7f; d = edid[0x02] & 0x7f;
if (d <= 4) if (d <= 4)
return -1; return -ENOENT;
i = 0x04; i = 0x04;
end = 0x00 + d; end = 0x00 + d;
@ -371,7 +371,7 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size,
return offset + i; return offset + i;
i += len + 1; i += len + 1;
} while (i < end); } while (i < end);
return -1; return -ENOENT;
} }
static void extron_edid_crc(u8 *edid) static void extron_edid_crc(u8 *edid)

View File

@ -685,7 +685,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4); err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4);
if (err) if (err)
return err; return err;
date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; date = ((unsigned)data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
dev_info(pulse8->dev, "Firmware build date %ptT\n", &date); dev_info(pulse8->dev, "Firmware build date %ptT\n", &date);
dev_dbg(pulse8->dev, "Persistent config:\n"); dev_dbg(pulse8->dev, "Persistent config:\n");

View File

@ -1795,6 +1795,9 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
unsigned p; unsigned p;
unsigned x; unsigned x;
if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width))
return;
switch (tpg->pattern) { switch (tpg->pattern) {
case TPG_PAT_GREEN: case TPG_PAT_GREEN:
contrast = TPG_COLOR_100_RED; contrast = TPG_COLOR_100_RED;

View File

@ -1482,18 +1482,23 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
} }
vb->planes[plane].dbuf_mapped = 1; vb->planes[plane].dbuf_mapped = 1;
} }
} else {
for (plane = 0; plane < vb->num_planes; ++plane)
dma_buf_put(planes[plane].dbuf);
}
/* /*
* Now that everything is in order, copy relevant information * Now that everything is in order, copy relevant information
* provided by userspace. * provided by userspace.
*/ */
for (plane = 0; plane < vb->num_planes; ++plane) { for (plane = 0; plane < vb->num_planes; ++plane) {
vb->planes[plane].bytesused = planes[plane].bytesused; vb->planes[plane].bytesused = planes[plane].bytesused;
vb->planes[plane].length = planes[plane].length; vb->planes[plane].length = planes[plane].length;
vb->planes[plane].m.fd = planes[plane].m.fd; vb->planes[plane].m.fd = planes[plane].m.fd;
vb->planes[plane].data_offset = planes[plane].data_offset; vb->planes[plane].data_offset = planes[plane].data_offset;
} }
if (reacquired) {
/* /*
* Call driver-specific initialization on the newly acquired buffer, * Call driver-specific initialization on the newly acquired buffer,
* if provided. * if provided.
@ -1503,9 +1508,6 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
dprintk(q, 1, "buffer initialization failed\n"); dprintk(q, 1, "buffer initialization failed\n");
goto err_put_vb2_buf; goto err_put_vb2_buf;
} }
} else {
for (plane = 0; plane < vb->num_planes; ++plane)
dma_buf_put(planes[plane].dbuf);
} }
ret = call_vb_qop(vb, buf_prepare, vb); ret = call_vb_qop(vb, buf_prepare, vb);

View File

@ -443,8 +443,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
default: default:
fepriv->auto_step++; fepriv->auto_step++;
fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ fepriv->auto_sub_step = 0;
break; continue;
} }
if (!ready) fepriv->auto_sub_step++; if (!ready) fepriv->auto_sub_step++;

View File

@ -366,9 +366,15 @@ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp) int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
{ {
struct vb2_queue *q = &ctx->vb_q; struct vb2_queue *q = &ctx->vb_q;
struct vb2_buffer *vb2 = vb2_get_buffer(q, exp->index);
int ret; int ret;
ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index], if (!vb2) {
dprintk(1, "[%s] invalid buffer index\n", ctx->name);
return -EINVAL;
}
ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, vb2,
0, exp->flags); 0, exp->flags);
if (ret) { if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name, dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,

View File

@ -86,10 +86,15 @@ static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file) static int dvb_device_open(struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
unsigned int minor = iminor(inode);
if (minor >= MAX_DVB_MINORS)
return -ENODEV;
mutex_lock(&dvbdev_mutex); mutex_lock(&dvbdev_mutex);
down_read(&minor_rwsem); down_read(&minor_rwsem);
dvbdev = dvb_minors[iminor(inode)];
dvbdev = dvb_minors[minor];
if (dvbdev && dvbdev->fops) { if (dvbdev && dvbdev->fops) {
int err = 0; int err = 0;
@ -525,7 +530,10 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
for (minor = 0; minor < MAX_DVB_MINORS; minor++) for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (!dvb_minors[minor]) if (!dvb_minors[minor])
break; break;
if (minor == MAX_DVB_MINORS) { #else
minor = nums2minor(adap->num, type, id);
#endif
if (minor >= MAX_DVB_MINORS) {
if (new_node) { if (new_node) {
list_del(&new_node->list_head); list_del(&new_node->list_head);
kfree(dvbdevfops); kfree(dvbdevfops);
@ -538,9 +546,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
return -EINVAL; return -EINVAL;
} }
#else
minor = nums2minor(adap->num, type, id);
#endif
dvbdev->minor = minor; dvbdev->minor = minor;
dvb_minors[minor] = dvb_device_get(dvbdev); dvb_minors[minor] = dvb_device_get(dvbdev);
up_write(&minor_rwsem); up_write(&minor_rwsem);

View File

@ -741,6 +741,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
{ {
struct cx24116_state *state = fe->demodulator_priv; struct cx24116_state *state = fe->demodulator_priv;
u8 snr_reading; u8 snr_reading;
int ret;
static const u32 snr_tab[] = { /* 10 x Table (rounded up) */ static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667, 0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667, 0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
@ -749,7 +750,11 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
dprintk("%s()\n", __func__); dprintk("%s()\n", __func__);
snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0); ret = cx24116_readreg(state, CX24116_REG_QUALITY0);
if (ret < 0)
return ret;
snr_reading = ret;
if (snr_reading >= 0xa0 /* 100% */) if (snr_reading >= 0xa0 /* 100% */)
*snr = 0xffff; *snr = 0xffff;

View File

@ -269,7 +269,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3; short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
int index = 0; int index = 0;
u8 cfr[2]; u8 cfr[2] = {0};
u8 reg; u8 reg;
internal->status = NOCARRIER; internal->status = NOCARRIER;

View File

@ -2519,10 +2519,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
const struct adv76xx_chip_info *info = state->info; const struct adv76xx_chip_info *info = state->info;
struct v4l2_dv_timings timings; struct v4l2_dv_timings timings;
struct stdi_readback stdi; struct stdi_readback stdi;
u8 reg_io_0x02 = io_read(sd, 0x02); int ret;
u8 reg_io_0x02;
u8 edid_enabled; u8 edid_enabled;
u8 cable_det; u8 cable_det;
static const char * const csc_coeff_sel_rb[16] = { static const char * const csc_coeff_sel_rb[16] = {
"bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB", "bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB",
"reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709", "reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709",
@ -2621,13 +2621,21 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "-----Color space-----\n"); v4l2_info(sd, "-----Color space-----\n");
v4l2_info(sd, "RGB quantization range ctrl: %s\n", v4l2_info(sd, "RGB quantization range ctrl: %s\n",
rgb_quantization_range_txt[state->rgb_quantization_range]); rgb_quantization_range_txt[state->rgb_quantization_range]);
v4l2_info(sd, "Input color space: %s\n",
input_color_space_txt[reg_io_0x02 >> 4]); ret = io_read(sd, 0x02);
v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n", if (ret < 0) {
(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr", v4l2_info(sd, "Can't read Input/Output color space\n");
(((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ? } else {
"(16-235)" : "(0-255)", reg_io_0x02 = ret;
(reg_io_0x02 & 0x08) ? "enabled" : "disabled");
v4l2_info(sd, "Input color space: %s\n",
input_color_space_txt[reg_io_0x02 >> 4]);
v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
(reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
(((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
"(16-235)" : "(0-255)",
(reg_io_0x02 & 0x08) ? "enabled" : "disabled");
}
v4l2_info(sd, "Color space conversion: %s\n", v4l2_info(sd, "Color space conversion: %s\n",
csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]); csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]);

View File

@ -255,10 +255,10 @@ static u32 calc_pll(struct ar0521_dev *sensor, u32 freq, u16 *pre_ptr, u16 *mult
continue; /* Minimum value */ continue; /* Minimum value */
if (new_mult > 254) if (new_mult > 254)
break; /* Maximum, larger pre won't work either */ break; /* Maximum, larger pre won't work either */
if (sensor->extclk_freq * (u64)new_mult < AR0521_PLL_MIN * if (sensor->extclk_freq * (u64)new_mult < (u64)AR0521_PLL_MIN *
new_pre) new_pre)
continue; continue;
if (sensor->extclk_freq * (u64)new_mult > AR0521_PLL_MAX * if (sensor->extclk_freq * (u64)new_mult > (u64)AR0521_PLL_MAX *
new_pre) new_pre)
break; /* Larger pre won't work either */ break; /* Larger pre won't work either */
new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult, new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult,

View File

@ -227,6 +227,8 @@ void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev,
u32 config; u32 config;
size_t i; size_t i;
freq_range = array_index_nospec(freq_range, ARRAY_SIZE(cmt_vals_in));
addr = cmt_addrs_in[vindev->config->id]; addr = cmt_addrs_in[vindev->config->id];
reg_set = cmt_vals_in[freq_range]; reg_set = cmt_vals_in[freq_range];

View File

@ -775,11 +775,14 @@ static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
(unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2; (unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
jpeg_buffer.curr = 0; jpeg_buffer.curr = 0;
word = 0;
if (get_word_be(&jpeg_buffer, &word)) if (get_word_be(&jpeg_buffer, &word))
return; return;
jpeg_buffer.size = (long)word - 2;
if (word < 2)
jpeg_buffer.size = 0;
else
jpeg_buffer.size = (long)word - 2;
jpeg_buffer.data += 2; jpeg_buffer.data += 2;
jpeg_buffer.curr = 0; jpeg_buffer.curr = 0;
@ -1058,6 +1061,7 @@ static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
if (byte == -1) if (byte == -1)
return -1; return -1;
*word = (unsigned int)byte | temp; *word = (unsigned int)byte | temp;
return 0; return 0;
} }
@ -1145,7 +1149,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word)) if (get_word_be(&jpeg_buffer, &word))
break; break;
length = (long)word - 2; length = (long)word - 2;
if (!length) if (length <= 0)
return false; return false;
sof = jpeg_buffer.curr; /* after 0xffc0 */ sof = jpeg_buffer.curr; /* after 0xffc0 */
sof_len = length; sof_len = length;
@ -1176,7 +1180,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word)) if (get_word_be(&jpeg_buffer, &word))
break; break;
length = (long)word - 2; length = (long)word - 2;
if (!length) if (length <= 0)
return false; return false;
if (n_dqt >= S5P_JPEG_MAX_MARKER) if (n_dqt >= S5P_JPEG_MAX_MARKER)
return false; return false;
@ -1189,7 +1193,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word)) if (get_word_be(&jpeg_buffer, &word))
break; break;
length = (long)word - 2; length = (long)word - 2;
if (!length) if (length <= 0)
return false; return false;
if (n_dht >= S5P_JPEG_MAX_MARKER) if (n_dht >= S5P_JPEG_MAX_MARKER)
return false; return false;
@ -1214,6 +1218,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word)) if (get_word_be(&jpeg_buffer, &word))
break; break;
length = (long)word - 2; length = (long)word - 2;
/* No need to check underflows as skip() does it */
skip(&jpeg_buffer, length); skip(&jpeg_buffer, length);
break; break;
} }

View File

@ -910,7 +910,7 @@ static int vivid_create_queue(struct vivid_dev *dev,
* videobuf2-core.c to MAX_BUFFER_INDEX. * videobuf2-core.c to MAX_BUFFER_INDEX.
*/ */
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
q->max_num_buffers = 64; q->max_num_buffers = MAX_VID_CAP_BUFFERS;
if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE) if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE)
q->max_num_buffers = 1024; q->max_num_buffers = 1024;
if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE) if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE)

View File

@ -26,6 +26,8 @@
#define MAX_INPUTS 16 #define MAX_INPUTS 16
/* The maximum number of outputs */ /* The maximum number of outputs */
#define MAX_OUTPUTS 16 #define MAX_OUTPUTS 16
/* The maximum number of video capture buffers */
#define MAX_VID_CAP_BUFFERS 64
/* The maximum up or down scaling factor is 4 */ /* The maximum up or down scaling factor is 4 */
#define MAX_ZOOM 4 #define MAX_ZOOM 4
/* The maximum image width/height are set to 4K DMT */ /* The maximum image width/height are set to 4K DMT */
@ -481,7 +483,7 @@ struct vivid_dev {
/* video capture */ /* video capture */
struct tpg_data tpg; struct tpg_data tpg;
unsigned ms_vid_cap; unsigned ms_vid_cap;
bool must_blank[VIDEO_MAX_FRAME]; bool must_blank[MAX_VID_CAP_BUFFERS];
const struct vivid_fmt *fmt_cap; const struct vivid_fmt *fmt_cap;
struct v4l2_fract timeperframe_vid_cap; struct v4l2_fract timeperframe_vid_cap;

View File

@ -553,7 +553,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
break; break;
case VIVID_CID_PERCENTAGE_FILL: case VIVID_CID_PERCENTAGE_FILL:
tpg_s_perc_fill(&dev->tpg, ctrl->val); tpg_s_perc_fill(&dev->tpg, ctrl->val);
for (i = 0; i < VIDEO_MAX_FRAME; i++) for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = ctrl->val < 100; dev->must_blank[i] = ctrl->val < 100;
break; break;
case VIVID_CID_INSERT_SAV: case VIVID_CID_INSERT_SAV:

View File

@ -213,7 +213,7 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
dev->vid_cap_seq_count = 0; dev->vid_cap_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++) for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100; dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
if (dev->start_streaming_error) { if (dev->start_streaming_error) {
dev->start_streaming_error = false; dev->start_streaming_error = false;

View File

@ -753,9 +753,10 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
for (i = 0; i < master->ncontrols; i++) for (i = 0; i < master->ncontrols; i++)
cur_to_new(master->cluster[i]); cur_to_new(master->cluster[i]);
ret = call_op(master, g_volatile_ctrl); ret = call_op(master, g_volatile_ctrl);
new_to_user(c, ctrl); if (!ret)
ret = new_to_user(c, ctrl);
} else { } else {
cur_to_user(c, ctrl); ret = cur_to_user(c, ctrl);
} }
v4l2_ctrl_unlock(master); v4l2_ctrl_unlock(master);
return ret; return ret;
@ -770,7 +771,10 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
if (!ctrl || !ctrl->is_int) if (!ctrl || !ctrl->is_int)
return -EINVAL; return -EINVAL;
ret = get_ctrl(ctrl, &c); ret = get_ctrl(ctrl, &c);
control->value = c.value;
if (!ret)
control->value = c.value;
return ret; return ret;
} }
EXPORT_SYMBOL(v4l2_g_ctrl); EXPORT_SYMBOL(v4l2_g_ctrl);
@ -811,10 +815,11 @@ static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
int ret; int ret;
v4l2_ctrl_lock(ctrl); v4l2_ctrl_lock(ctrl);
user_to_new(c, ctrl); ret = user_to_new(c, ctrl);
ret = set_ctrl(fh, ctrl, 0);
if (!ret) if (!ret)
cur_to_user(c, ctrl); ret = set_ctrl(fh, ctrl, 0);
if (!ret)
ret = cur_to_user(c, ctrl);
v4l2_ctrl_unlock(ctrl); v4l2_ctrl_unlock(ctrl);
return ret; return ret;
} }

View File

@ -88,6 +88,8 @@ struct infrared {
u32 ir_config; u32 ir_config;
}; };
#define MAX_CI_SLOTS 2
/* place to store all the necessary device information */ /* place to store all the necessary device information */
struct av7110 { struct av7110 {
/* devices */ /* devices */
@ -163,7 +165,7 @@ struct av7110 {
/* CA */ /* CA */
struct ca_slot_info ci_slot[2]; struct ca_slot_info ci_slot[MAX_CI_SLOTS];
enum av7110_video_mode vidmode; enum av7110_video_mode vidmode;
struct dmxdev dmxdev; struct dmxdev dmxdev;

View File

@ -26,23 +26,28 @@
void CI_handle(struct av7110 *av7110, u8 *data, u16 len) void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
{ {
unsigned slot_num;
dprintk(8, "av7110:%p\n", av7110); dprintk(8, "av7110:%p\n", av7110);
if (len < 3) if (len < 3)
return; return;
switch (data[0]) { switch (data[0]) {
case CI_MSG_CI_INFO: case CI_MSG_CI_INFO:
if (data[2] != 1 && data[2] != 2) if (data[2] != 1 && data[2] != MAX_CI_SLOTS)
break; break;
slot_num = array_index_nospec(data[2] - 1, MAX_CI_SLOTS);
switch (data[1]) { switch (data[1]) {
case 0: case 0:
av7110->ci_slot[data[2] - 1].flags = 0; av7110->ci_slot[slot_num].flags = 0;
break; break;
case 1: case 1:
av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_PRESENT; av7110->ci_slot[slot_num].flags |= CA_CI_MODULE_PRESENT;
break; break;
case 2: case 2:
av7110->ci_slot[data[2] - 1].flags |= CA_CI_MODULE_READY; av7110->ci_slot[slot_num].flags |= CA_CI_MODULE_READY;
break; break;
} }
break; break;
@ -262,15 +267,19 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
case CA_GET_SLOT_INFO: case CA_GET_SLOT_INFO:
{ {
struct ca_slot_info *info = (struct ca_slot_info *)parg; struct ca_slot_info *info = (struct ca_slot_info *)parg;
unsigned int slot_num;
if (info->num < 0 || info->num > 1) { if (info->num < 0 || info->num > 1) {
mutex_unlock(&av7110->ioctl_mutex); mutex_unlock(&av7110->ioctl_mutex);
return -EINVAL; return -EINVAL;
} }
av7110->ci_slot[info->num].num = info->num; slot_num = array_index_nospec(info->num, MAX_CI_SLOTS);
av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
CA_CI_LINK : CA_CI; av7110->ci_slot[slot_num].num = info->num;
memcpy(info, &av7110->ci_slot[info->num], sizeof(struct ca_slot_info)); av7110->ci_slot[slot_num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
CA_CI_LINK : CA_CI;
memcpy(info, &av7110->ci_slot[slot_num],
sizeof(struct ca_slot_info));
break; break;
} }