media fixes for v4.8-rc8
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJX46bNAAoJEAhfPr2O5OEV+XUP/RLEpjSW55rHD4FfmnVj/oZu hEvrOTOuRsDhBnryvfcFVH/4rEcpQtfp7ih19av4z5//lEnSoNYAFy6JFMDHKx5C hR6txXLk6uh6Rqq2/Pk25i/8zghtSapcPAFF7/CNlZVjk8hB9asrkAgC287mX2b6 xObNvOZh4B5x65iMGcl8AxS9b+a9fFxqKeIqdnepLCreDLDI0TCR1NOWOafgVqgc iFZwmK7xmbuJ8qOLnzV1BALWLounNEZ+mGbr4YE7PxjVpjHqEyW0CwrqAu6M9UJ3 FMP50L08A2dcRa63i7ZGXIqgaubEy4KkoNRwZe/KDd78WbOviYNgpHyCp9nfBXxU gVrd7YCDe57j1Q6TSJFNLiLVXZrtiNTR1tNeupdfdH4SZlDUPQB09ZtBN9vtgX6z R5b+nCqNwT/ec/c8sIocOn5Fetcyq72oLcwwj5+8ne3pEgqWwLWqVi91cg+G2n0Z y+6Q2DdZaQPt1R3HbL5mF75sjZk4N/FdxxrDlsnD09LxeLqqeoyozcwBPEhn3c6B ue6Kj0VJWLG+EB6Az0jkz0IRgcB0GvTOIeoUO3a2iRi4CxWyLpkfSaEtqksuW4R5 fa/9oIaXHukdhLCJaZ8ztUpO6uQB6rEXPlQYT54t81NPnxFnc6yvFfMbSezv2Qlv iFW80ToW3KLEzlQqUHep =iNX5 -----END PGP SIGNATURE----- Merge tag 'media/v4.8-7' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media fixes from Mauro Carvalho Chehab: - several fixes for new drivers added for Kernel 4.8 addition (cec core, pulse8 cec driver and Mediatek vcodec) - a regression fix for cx23885 and saa7134 drivers - an important fix for rcar-fcp, making rcar_fcp_enable() return 0 on success * tag 'media/v4.8-7' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (25 commits) [media] cx23885/saa7134: assign q->dev to the PCI device [media] rcar-fcp: Make sure rcar_fcp_enable() returns 0 on success [media] cec: fix ioctl return code when not registered [media] cec: don't Feature Abort broadcast msgs when unregistered [media] vcodec:mediatek: Refine VP8 encoder driver [media] vcodec:mediatek: Refine H264 encoder driver [media] vcodec:mediatek: change H264 profile default to profile high [media] vcodec:mediatek: Add timestamp and timecode copy for V4L2 Encoder [media] vcodec:mediatek: Fix visible_height larger than coded_height issue in s_fmt_out [media] vcodec:mediatek: Fix fops_vcodec_release flow for V4L2 Encoder [media] vcodec:mediatek:code refine for v4l2 Encoder driver [media] cec-funcs.h: add missing vendor-specific messages [media] cec-edid: check for IEEE identifier [media] pulse8-cec: fix error handling [media] pulse8-cec: set correct Signal Free Time [media] mtk-vcodec: add HAS_DMA dependency [media] cec: ignore messages when log_addr_mask == 0 [media] cec: add item to TODO [media] cec: set unclaimed addresses to CEC_LOG_ADDR_INVALID [media] cec: add CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK flag ...
This commit is contained in:
commit
b1f2beb87b
|
@ -144,7 +144,7 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
|
||||
- ``flags``
|
||||
|
||||
- Flags. No flags are defined yet, so set this to 0.
|
||||
- Flags. See :ref:`cec-log-addrs-flags` for a list of available flags.
|
||||
|
||||
- .. row 7
|
||||
|
||||
|
@ -201,6 +201,25 @@ logical address types are already defined will return with error ``EBUSY``.
|
|||
give the CEC framework more information about the device type, even
|
||||
though the framework won't use it directly in the CEC message.
|
||||
|
||||
.. _cec-log-addrs-flags:
|
||||
|
||||
.. flat-table:: Flags for struct cec_log_addrs
|
||||
:header-rows: 0
|
||||
:stub-columns: 0
|
||||
:widths: 3 1 4
|
||||
|
||||
|
||||
- .. _`CEC-LOG-ADDRS-FL-ALLOW-UNREG-FALLBACK`:
|
||||
|
||||
- ``CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK``
|
||||
|
||||
- 1
|
||||
|
||||
- By default if no logical address of the requested type can be claimed, then
|
||||
it will go back to the unconfigured state. If this flag is set, then it will
|
||||
fallback to the Unregistered logical address. Note that if the Unregistered
|
||||
logical address was explicitly requested, then this flag has no effect.
|
||||
|
||||
.. _cec-versions:
|
||||
|
||||
.. flat-table:: CEC Versions
|
||||
|
|
|
@ -64,7 +64,8 @@ it is guaranteed that the state did change in between the two events.
|
|||
|
||||
- ``phys_addr``
|
||||
|
||||
- The current physical address.
|
||||
- The current physical address. This is ``CEC_PHYS_ADDR_INVALID`` if no
|
||||
valid physical address is set.
|
||||
|
||||
- .. row 2
|
||||
|
||||
|
@ -72,7 +73,10 @@ it is guaranteed that the state did change in between the two events.
|
|||
|
||||
- ``log_addr_mask``
|
||||
|
||||
- The current set of claimed logical addresses.
|
||||
- The current set of claimed logical addresses. This is 0 if no logical
|
||||
addresses are claimed or if ``phys_addr`` is ``CEC_PHYS_ADDR_INVALID``.
|
||||
If bit 15 is set (``1 << CEC_LOG_ADDR_UNREGISTERED``) then this device
|
||||
has the unregistered logical address. In that case all other bits are 0.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -70,7 +70,10 @@ static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size)
|
|||
u8 tag = edid[i] >> 5;
|
||||
u8 len = edid[i] & 0x1f;
|
||||
|
||||
if (tag == 3 && len >= 5 && i + len <= end)
|
||||
if (tag == 3 && len >= 5 && i + len <= end &&
|
||||
edid[i + 1] == 0x03 &&
|
||||
edid[i + 2] == 0x0c &&
|
||||
edid[i + 3] == 0x00)
|
||||
return i + 4;
|
||||
i += len + 1;
|
||||
} while (i < end);
|
||||
|
|
|
@ -1552,6 +1552,7 @@ int cx23885_417_register(struct cx23885_dev *dev)
|
|||
q->mem_ops = &vb2_dma_sg_memops;
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &dev->lock;
|
||||
q->dev = &dev->pci->dev;
|
||||
|
||||
err = vb2_queue_init(q);
|
||||
if (err < 0)
|
||||
|
|
|
@ -1238,6 +1238,7 @@ static int dvb_init(struct saa7134_dev *dev)
|
|||
q->buf_struct_size = sizeof(struct saa7134_buf);
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &dev->lock;
|
||||
q->dev = &dev->pci->dev;
|
||||
ret = vb2_queue_init(q);
|
||||
if (ret) {
|
||||
vb2_dvb_dealloc_frontends(&dev->frontends);
|
||||
|
|
|
@ -295,6 +295,7 @@ static int empress_init(struct saa7134_dev *dev)
|
|||
q->buf_struct_size = sizeof(struct saa7134_buf);
|
||||
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
q->lock = &dev->lock;
|
||||
q->dev = &dev->pci->dev;
|
||||
err = vb2_queue_init(q);
|
||||
if (err)
|
||||
return err;
|
||||
|
|
|
@ -169,7 +169,7 @@ config VIDEO_MEDIATEK_VPU
|
|||
config VIDEO_MEDIATEK_VCODEC
|
||||
tristate "Mediatek Video Codec driver"
|
||||
depends on MTK_IOMMU || COMPILE_TEST
|
||||
depends on VIDEO_DEV && VIDEO_V4L2
|
||||
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
|
||||
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select V4L2_MEM2MEM_DEV
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/videobuf2-core.h>
|
||||
|
||||
#include "mtk_vcodec_util.h"
|
||||
|
||||
#define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv"
|
||||
#define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc"
|
||||
|
|
|
@ -487,7 +487,6 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
|
|||
struct mtk_q_data *q_data;
|
||||
int ret, i;
|
||||
struct mtk_video_fmt *fmt;
|
||||
unsigned int pitch_w_div16;
|
||||
struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp;
|
||||
|
||||
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
|
||||
|
@ -530,15 +529,6 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
|
|||
q_data->coded_width = f->fmt.pix_mp.width;
|
||||
q_data->coded_height = f->fmt.pix_mp.height;
|
||||
|
||||
pitch_w_div16 = DIV_ROUND_UP(q_data->visible_width, 16);
|
||||
if (pitch_w_div16 % 8 != 0) {
|
||||
/* Adjust returned width/height, so application could correctly
|
||||
* allocate hw required memory
|
||||
*/
|
||||
q_data->visible_height += 32;
|
||||
vidioc_try_fmt(f, q_data->fmt);
|
||||
}
|
||||
|
||||
q_data->field = f->fmt.pix_mp.field;
|
||||
ctx->colorspace = f->fmt.pix_mp.colorspace;
|
||||
ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc;
|
||||
|
@ -878,7 +868,8 @@ static int mtk_venc_encode_header(void *priv)
|
|||
{
|
||||
struct mtk_vcodec_ctx *ctx = priv;
|
||||
int ret;
|
||||
struct vb2_buffer *dst_buf;
|
||||
struct vb2_buffer *src_buf, *dst_buf;
|
||||
struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
|
||||
struct mtk_vcodec_mem bs_buf;
|
||||
struct venc_done_result enc_result;
|
||||
|
||||
|
@ -911,6 +902,15 @@ static int mtk_venc_encode_header(void *priv)
|
|||
mtk_v4l2_err("venc_if_encode failed=%d", ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
|
||||
if (src_buf) {
|
||||
src_vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
|
||||
dst_vb2_v4l2 = to_vb2_v4l2_buffer(dst_buf);
|
||||
dst_buf->timestamp = src_buf->timestamp;
|
||||
dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode;
|
||||
} else {
|
||||
mtk_v4l2_err("No timestamp for the header buffer.");
|
||||
}
|
||||
|
||||
ctx->state = MTK_STATE_HEADER;
|
||||
dst_buf->planes[0].bytesused = enc_result.bs_size;
|
||||
|
@ -1003,7 +1003,7 @@ static void mtk_venc_worker(struct work_struct *work)
|
|||
struct mtk_vcodec_mem bs_buf;
|
||||
struct venc_done_result enc_result;
|
||||
int ret, i;
|
||||
struct vb2_v4l2_buffer *vb2_v4l2;
|
||||
struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2;
|
||||
|
||||
/* check dst_buf, dst_buf may be removed in device_run
|
||||
* to stored encdoe header so we need check dst_buf and
|
||||
|
@ -1043,9 +1043,14 @@ static void mtk_venc_worker(struct work_struct *work)
|
|||
ret = venc_if_encode(ctx, VENC_START_OPT_ENCODE_FRAME,
|
||||
&frm_buf, &bs_buf, &enc_result);
|
||||
|
||||
vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf);
|
||||
src_vb2_v4l2 = to_vb2_v4l2_buffer(src_buf);
|
||||
dst_vb2_v4l2 = to_vb2_v4l2_buffer(dst_buf);
|
||||
|
||||
dst_buf->timestamp = src_buf->timestamp;
|
||||
dst_vb2_v4l2->timecode = src_vb2_v4l2->timecode;
|
||||
|
||||
if (enc_result.is_key_frm)
|
||||
vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME;
|
||||
dst_vb2_v4l2->flags |= V4L2_BUF_FLAG_KEYFRAME;
|
||||
|
||||
if (ret) {
|
||||
v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf),
|
||||
|
@ -1217,7 +1222,7 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
|
|||
0, V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE);
|
||||
v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
|
||||
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
|
||||
0, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN);
|
||||
0, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
|
||||
v4l2_ctrl_new_std_menu(handler, ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL,
|
||||
V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
|
||||
0, V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
|
||||
|
@ -1288,5 +1293,10 @@ int mtk_venc_lock(struct mtk_vcodec_ctx *ctx)
|
|||
|
||||
void mtk_vcodec_enc_release(struct mtk_vcodec_ctx *ctx)
|
||||
{
|
||||
venc_if_deinit(ctx);
|
||||
int ret = venc_if_deinit(ctx);
|
||||
|
||||
if (ret)
|
||||
mtk_v4l2_err("venc_if_deinit failed=%d", ret);
|
||||
|
||||
ctx->state = MTK_STATE_FREE;
|
||||
}
|
||||
|
|
|
@ -218,11 +218,15 @@ static int fops_vcodec_release(struct file *file)
|
|||
mtk_v4l2_debug(1, "[%d] encoder", ctx->id);
|
||||
mutex_lock(&dev->dev_mutex);
|
||||
|
||||
/*
|
||||
* Call v4l2_m2m_ctx_release to make sure the worker thread is not
|
||||
* running after venc_if_deinit.
|
||||
*/
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
mtk_vcodec_enc_release(ctx);
|
||||
v4l2_fh_del(&ctx->fh);
|
||||
v4l2_fh_exit(&ctx->fh);
|
||||
v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
|
||||
list_del_init(&ctx->list);
|
||||
dev->num_instances--;
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#define _MTK_VCODEC_INTR_H_
|
||||
|
||||
#define MTK_INST_IRQ_RECEIVED 0x1
|
||||
#define MTK_INST_WORK_THREAD_ABORT_DONE 0x2
|
||||
|
||||
struct mtk_vcodec_ctx;
|
||||
|
||||
|
|
|
@ -61,6 +61,8 @@ enum venc_h264_bs_mode {
|
|||
|
||||
/*
|
||||
* struct venc_h264_vpu_config - Structure for h264 encoder configuration
|
||||
* AP-W/R : AP is writer/reader on this item
|
||||
* VPU-W/R: VPU is write/reader on this item
|
||||
* @input_fourcc: input fourcc
|
||||
* @bitrate: target bitrate (in bps)
|
||||
* @pic_w: picture width. Picture size is visible stream resolution, in pixels,
|
||||
|
@ -94,13 +96,13 @@ struct venc_h264_vpu_config {
|
|||
|
||||
/*
|
||||
* struct venc_h264_vpu_buf - Structure for buffer information
|
||||
* @align: buffer alignment (in bytes)
|
||||
* AP-W/R : AP is writer/reader on this item
|
||||
* VPU-W/R: VPU is write/reader on this item
|
||||
* @iova: IO virtual address
|
||||
* @vpua: VPU side memory addr which is used by RC_CODE
|
||||
* @size: buffer size (in bytes)
|
||||
*/
|
||||
struct venc_h264_vpu_buf {
|
||||
u32 align;
|
||||
u32 iova;
|
||||
u32 vpua;
|
||||
u32 size;
|
||||
|
@ -108,6 +110,8 @@ struct venc_h264_vpu_buf {
|
|||
|
||||
/*
|
||||
* struct venc_h264_vsi - Structure for VPU driver control and info share
|
||||
* AP-W/R : AP is writer/reader on this item
|
||||
* VPU-W/R: VPU is write/reader on this item
|
||||
* This structure is allocated in VPU side and shared to AP side.
|
||||
* @config: h264 encoder configuration
|
||||
* @work_bufs: working buffer information in VPU side
|
||||
|
@ -150,12 +154,6 @@ struct venc_h264_inst {
|
|||
struct mtk_vcodec_ctx *ctx;
|
||||
};
|
||||
|
||||
static inline void h264_write_reg(struct venc_h264_inst *inst, u32 addr,
|
||||
u32 val)
|
||||
{
|
||||
writel(val, inst->hw_base + addr);
|
||||
}
|
||||
|
||||
static inline u32 h264_read_reg(struct venc_h264_inst *inst, u32 addr)
|
||||
{
|
||||
return readl(inst->hw_base + addr);
|
||||
|
@ -214,6 +212,8 @@ static unsigned int h264_get_level(struct venc_h264_inst *inst,
|
|||
return 40;
|
||||
case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
|
||||
return 41;
|
||||
case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
|
||||
return 42;
|
||||
default:
|
||||
mtk_vcodec_debug(inst, "unsupported level %d", level);
|
||||
return 31;
|
||||
|
|
|
@ -56,6 +56,8 @@ enum venc_vp8_vpu_work_buf {
|
|||
|
||||
/*
|
||||
* struct venc_vp8_vpu_config - Structure for vp8 encoder configuration
|
||||
* AP-W/R : AP is writer/reader on this item
|
||||
* VPU-W/R: VPU is write/reader on this item
|
||||
* @input_fourcc: input fourcc
|
||||
* @bitrate: target bitrate (in bps)
|
||||
* @pic_w: picture width. Picture size is visible stream resolution, in pixels,
|
||||
|
@ -83,14 +85,14 @@ struct venc_vp8_vpu_config {
|
|||
};
|
||||
|
||||
/*
|
||||
* struct venc_vp8_vpu_buf -Structure for buffer information
|
||||
* @align: buffer alignment (in bytes)
|
||||
* struct venc_vp8_vpu_buf - Structure for buffer information
|
||||
* AP-W/R : AP is writer/reader on this item
|
||||
* VPU-W/R: VPU is write/reader on this item
|
||||
* @iova: IO virtual address
|
||||
* @vpua: VPU side memory addr which is used by RC_CODE
|
||||
* @size: buffer size (in bytes)
|
||||
*/
|
||||
struct venc_vp8_vpu_buf {
|
||||
u32 align;
|
||||
u32 iova;
|
||||
u32 vpua;
|
||||
u32 size;
|
||||
|
@ -98,6 +100,8 @@ struct venc_vp8_vpu_buf {
|
|||
|
||||
/*
|
||||
* struct venc_vp8_vsi - Structure for VPU driver control and info share
|
||||
* AP-W/R : AP is writer/reader on this item
|
||||
* VPU-W/R: VPU is write/reader on this item
|
||||
* This structure is allocated in VPU side and shared to AP side.
|
||||
* @config: vp8 encoder configuration
|
||||
* @work_bufs: working buffer information in VPU side
|
||||
|
@ -138,12 +142,6 @@ struct venc_vp8_inst {
|
|||
struct mtk_vcodec_ctx *ctx;
|
||||
};
|
||||
|
||||
static inline void vp8_enc_write_reg(struct venc_vp8_inst *inst, u32 addr,
|
||||
u32 val)
|
||||
{
|
||||
writel(val, inst->hw_base + addr);
|
||||
}
|
||||
|
||||
static inline u32 vp8_enc_read_reg(struct venc_vp8_inst *inst, u32 addr)
|
||||
{
|
||||
return readl(inst->hw_base + addr);
|
||||
|
|
|
@ -99,10 +99,16 @@ EXPORT_SYMBOL_GPL(rcar_fcp_put);
|
|||
*/
|
||||
int rcar_fcp_enable(struct rcar_fcp_device *fcp)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!fcp)
|
||||
return 0;
|
||||
|
||||
return pm_runtime_get_sync(fcp->dev);
|
||||
error = pm_runtime_get_sync(fcp->dev);
|
||||
if (error < 0)
|
||||
return error;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rcar_fcp_enable);
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ Hopefully this will happen later in 2016.
|
|||
|
||||
Other TODOs:
|
||||
|
||||
- There are two possible replies to CEC_MSG_INITIATE_ARC. How to handle that?
|
||||
- Add a flag to inhibit passing CEC RC messages to the rc subsystem.
|
||||
Applications should be able to choose this when calling S_LOG_ADDRS.
|
||||
- If the reply field of cec_msg is set then when the reply arrives it
|
||||
|
|
|
@ -124,10 +124,10 @@ static void cec_queue_event(struct cec_adapter *adap,
|
|||
u64 ts = ktime_get_ns();
|
||||
struct cec_fh *fh;
|
||||
|
||||
mutex_lock(&adap->devnode.fhs_lock);
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
list_for_each_entry(fh, &adap->devnode.fhs, list)
|
||||
cec_queue_event_fh(fh, ev, ts);
|
||||
mutex_unlock(&adap->devnode.fhs_lock);
|
||||
mutex_unlock(&adap->devnode.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -191,12 +191,12 @@ static void cec_queue_msg_monitor(struct cec_adapter *adap,
|
|||
u32 monitor_mode = valid_la ? CEC_MODE_MONITOR :
|
||||
CEC_MODE_MONITOR_ALL;
|
||||
|
||||
mutex_lock(&adap->devnode.fhs_lock);
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
list_for_each_entry(fh, &adap->devnode.fhs, list) {
|
||||
if (fh->mode_follower >= monitor_mode)
|
||||
cec_queue_msg_fh(fh, msg);
|
||||
}
|
||||
mutex_unlock(&adap->devnode.fhs_lock);
|
||||
mutex_unlock(&adap->devnode.lock);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -207,12 +207,12 @@ static void cec_queue_msg_followers(struct cec_adapter *adap,
|
|||
{
|
||||
struct cec_fh *fh;
|
||||
|
||||
mutex_lock(&adap->devnode.fhs_lock);
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
list_for_each_entry(fh, &adap->devnode.fhs, list) {
|
||||
if (fh->mode_follower == CEC_MODE_FOLLOWER)
|
||||
cec_queue_msg_fh(fh, msg);
|
||||
}
|
||||
mutex_unlock(&adap->devnode.fhs_lock);
|
||||
mutex_unlock(&adap->devnode.lock);
|
||||
}
|
||||
|
||||
/* Notify userspace of an adapter state change. */
|
||||
|
@ -851,6 +851,9 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg)
|
|||
if (!valid_la || msg->len <= 1)
|
||||
return;
|
||||
|
||||
if (adap->log_addrs.log_addr_mask == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Process the message on the protocol level. If is_reply is true,
|
||||
* then cec_receive_notify() won't pass on the reply to the listener(s)
|
||||
|
@ -1047,11 +1050,17 @@ static int cec_config_thread_func(void *arg)
|
|||
dprintk(1, "could not claim LA %d\n", i);
|
||||
}
|
||||
|
||||
if (adap->log_addrs.log_addr_mask == 0 &&
|
||||
!(las->flags & CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK))
|
||||
goto unconfigure;
|
||||
|
||||
configured:
|
||||
if (adap->log_addrs.log_addr_mask == 0) {
|
||||
/* Fall back to unregistered */
|
||||
las->log_addr[0] = CEC_LOG_ADDR_UNREGISTERED;
|
||||
las->log_addr_mask = 1 << las->log_addr[0];
|
||||
for (i = 1; i < las->num_log_addrs; i++)
|
||||
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
|
||||
}
|
||||
adap->is_configured = true;
|
||||
adap->is_configuring = false;
|
||||
|
@ -1070,6 +1079,8 @@ configured:
|
|||
cec_report_features(adap, i);
|
||||
cec_report_phys_addr(adap, i);
|
||||
}
|
||||
for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++)
|
||||
las->log_addr[i] = CEC_LOG_ADDR_INVALID;
|
||||
mutex_lock(&adap->lock);
|
||||
adap->kthread_config = NULL;
|
||||
mutex_unlock(&adap->lock);
|
||||
|
@ -1398,7 +1409,6 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
|
|||
u8 init_laddr = cec_msg_initiator(msg);
|
||||
u8 devtype = cec_log_addr2dev(adap, dest_laddr);
|
||||
int la_idx = cec_log_addr2idx(adap, dest_laddr);
|
||||
bool is_directed = la_idx >= 0;
|
||||
bool from_unregistered = init_laddr == 0xf;
|
||||
struct cec_msg tx_cec_msg = { };
|
||||
|
||||
|
@ -1560,7 +1570,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
|
|||
* Unprocessed messages are aborted if userspace isn't doing
|
||||
* any processing either.
|
||||
*/
|
||||
if (is_directed && !is_reply && !adap->follower_cnt &&
|
||||
if (!is_broadcast && !is_reply && !adap->follower_cnt &&
|
||||
!adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT)
|
||||
return cec_feature_abort(adap, msg);
|
||||
break;
|
||||
|
|
|
@ -162,7 +162,7 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh,
|
|||
return -ENOTTY;
|
||||
if (copy_from_user(&log_addrs, parg, sizeof(log_addrs)))
|
||||
return -EFAULT;
|
||||
log_addrs.flags = 0;
|
||||
log_addrs.flags &= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK;
|
||||
mutex_lock(&adap->lock);
|
||||
if (!adap->is_configuring &&
|
||||
(!log_addrs.num_log_addrs || !adap->is_configured) &&
|
||||
|
@ -435,7 +435,7 @@ static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
|||
void __user *parg = (void __user *)arg;
|
||||
|
||||
if (!devnode->registered)
|
||||
return -EIO;
|
||||
return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
case CEC_ADAP_G_CAPS:
|
||||
|
@ -508,14 +508,14 @@ static int cec_open(struct inode *inode, struct file *filp)
|
|||
|
||||
filp->private_data = fh;
|
||||
|
||||
mutex_lock(&devnode->fhs_lock);
|
||||
mutex_lock(&devnode->lock);
|
||||
/* Queue up initial state events */
|
||||
ev_state.state_change.phys_addr = adap->phys_addr;
|
||||
ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
|
||||
cec_queue_event_fh(fh, &ev_state, 0);
|
||||
|
||||
list_add(&fh->list, &devnode->fhs);
|
||||
mutex_unlock(&devnode->fhs_lock);
|
||||
mutex_unlock(&devnode->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -540,9 +540,9 @@ static int cec_release(struct inode *inode, struct file *filp)
|
|||
cec_monitor_all_cnt_dec(adap);
|
||||
mutex_unlock(&adap->lock);
|
||||
|
||||
mutex_lock(&devnode->fhs_lock);
|
||||
mutex_lock(&devnode->lock);
|
||||
list_del(&fh->list);
|
||||
mutex_unlock(&devnode->fhs_lock);
|
||||
mutex_unlock(&devnode->lock);
|
||||
|
||||
/* Unhook pending transmits from this filehandle. */
|
||||
mutex_lock(&adap->lock);
|
||||
|
|
|
@ -51,31 +51,29 @@ int cec_get_device(struct cec_devnode *devnode)
|
|||
{
|
||||
/*
|
||||
* Check if the cec device is available. This needs to be done with
|
||||
* the cec_devnode_lock held to prevent an open/unregister race:
|
||||
* the devnode->lock held to prevent an open/unregister race:
|
||||
* without the lock, the device could be unregistered and freed between
|
||||
* the devnode->registered check and get_device() calls, leading to
|
||||
* a crash.
|
||||
*/
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
mutex_lock(&devnode->lock);
|
||||
/*
|
||||
* return ENXIO if the cec device has been removed
|
||||
* already or if it is not registered anymore.
|
||||
*/
|
||||
if (!devnode->registered) {
|
||||
mutex_unlock(&cec_devnode_lock);
|
||||
mutex_unlock(&devnode->lock);
|
||||
return -ENXIO;
|
||||
}
|
||||
/* and increase the device refcount */
|
||||
get_device(&devnode->dev);
|
||||
mutex_unlock(&cec_devnode_lock);
|
||||
mutex_unlock(&devnode->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cec_put_device(struct cec_devnode *devnode)
|
||||
{
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
put_device(&devnode->dev);
|
||||
mutex_unlock(&cec_devnode_lock);
|
||||
}
|
||||
|
||||
/* Called when the last user of the cec device exits. */
|
||||
|
@ -84,11 +82,10 @@ static void cec_devnode_release(struct device *cd)
|
|||
struct cec_devnode *devnode = to_cec_devnode(cd);
|
||||
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
|
||||
/* Mark device node number as free */
|
||||
clear_bit(devnode->minor, cec_devnode_nums);
|
||||
|
||||
mutex_unlock(&cec_devnode_lock);
|
||||
|
||||
cec_delete_adapter(to_cec_adapter(devnode));
|
||||
}
|
||||
|
||||
|
@ -117,7 +114,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
|||
|
||||
/* Initialization */
|
||||
INIT_LIST_HEAD(&devnode->fhs);
|
||||
mutex_init(&devnode->fhs_lock);
|
||||
mutex_init(&devnode->lock);
|
||||
|
||||
/* Part 1: Find a free minor number */
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
|
@ -160,7 +157,9 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
|||
cdev_del:
|
||||
cdev_del(&devnode->cdev);
|
||||
clr_bit:
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
clear_bit(devnode->minor, cec_devnode_nums);
|
||||
mutex_unlock(&cec_devnode_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -177,17 +176,21 @@ static void cec_devnode_unregister(struct cec_devnode *devnode)
|
|||
{
|
||||
struct cec_fh *fh;
|
||||
|
||||
/* Check if devnode was never registered or already unregistered */
|
||||
if (!devnode->registered || devnode->unregistered)
|
||||
return;
|
||||
mutex_lock(&devnode->lock);
|
||||
|
||||
/* Check if devnode was never registered or already unregistered */
|
||||
if (!devnode->registered || devnode->unregistered) {
|
||||
mutex_unlock(&devnode->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&devnode->fhs_lock);
|
||||
list_for_each_entry(fh, &devnode->fhs, list)
|
||||
wake_up_interruptible(&fh->wait);
|
||||
mutex_unlock(&devnode->fhs_lock);
|
||||
|
||||
devnode->registered = false;
|
||||
devnode->unregistered = true;
|
||||
mutex_unlock(&devnode->lock);
|
||||
|
||||
device_del(&devnode->dev);
|
||||
cdev_del(&devnode->cdev);
|
||||
put_device(&devnode->dev);
|
||||
|
|
|
@ -114,14 +114,11 @@ static void pulse8_irq_work_handler(struct work_struct *work)
|
|||
cec_transmit_done(pulse8->adap, CEC_TX_STATUS_OK,
|
||||
0, 0, 0, 0);
|
||||
break;
|
||||
case MSGCODE_TRANSMIT_FAILED_LINE:
|
||||
cec_transmit_done(pulse8->adap, CEC_TX_STATUS_ARB_LOST,
|
||||
1, 0, 0, 0);
|
||||
break;
|
||||
case MSGCODE_TRANSMIT_FAILED_ACK:
|
||||
cec_transmit_done(pulse8->adap, CEC_TX_STATUS_NACK,
|
||||
0, 1, 0, 0);
|
||||
break;
|
||||
case MSGCODE_TRANSMIT_FAILED_LINE:
|
||||
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA:
|
||||
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
|
||||
cec_transmit_done(pulse8->adap, CEC_TX_STATUS_ERROR,
|
||||
|
@ -170,6 +167,9 @@ static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
|
|||
case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE:
|
||||
schedule_work(&pulse8->work);
|
||||
break;
|
||||
case MSGCODE_HIGH_ERROR:
|
||||
case MSGCODE_LOW_ERROR:
|
||||
case MSGCODE_RECEIVE_FAILED:
|
||||
case MSGCODE_TIMEOUT_ERROR:
|
||||
break;
|
||||
case MSGCODE_COMMAND_ACCEPTED:
|
||||
|
@ -388,7 +388,7 @@ static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
|||
int err;
|
||||
|
||||
cmd[0] = MSGCODE_TRANSMIT_IDLETIME;
|
||||
cmd[1] = 3;
|
||||
cmd[1] = signal_free_time;
|
||||
err = pulse8_send_and_wait(pulse8, cmd, 2,
|
||||
MSGCODE_COMMAND_ACCEPTED, 1);
|
||||
cmd[0] = MSGCODE_TRANSMIT_ACK_POLARITY;
|
||||
|
|
|
@ -162,10 +162,11 @@ static inline void cec_msg_standby(struct cec_msg *msg)
|
|||
|
||||
|
||||
/* One Touch Record Feature */
|
||||
static inline void cec_msg_record_off(struct cec_msg *msg)
|
||||
static inline void cec_msg_record_off(struct cec_msg *msg, bool reply)
|
||||
{
|
||||
msg->len = 2;
|
||||
msg->msg[1] = CEC_MSG_RECORD_OFF;
|
||||
msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0;
|
||||
}
|
||||
|
||||
struct cec_op_arib_data {
|
||||
|
@ -227,7 +228,7 @@ static inline void cec_set_digital_service_id(__u8 *msg,
|
|||
if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
|
||||
*msg++ = (digital->channel.channel_number_fmt << 2) |
|
||||
(digital->channel.major >> 8);
|
||||
*msg++ = digital->channel.major && 0xff;
|
||||
*msg++ = digital->channel.major & 0xff;
|
||||
*msg++ = digital->channel.minor >> 8;
|
||||
*msg++ = digital->channel.minor & 0xff;
|
||||
*msg++ = 0;
|
||||
|
@ -323,6 +324,7 @@ static inline void cec_msg_record_on_phys_addr(struct cec_msg *msg,
|
|||
}
|
||||
|
||||
static inline void cec_msg_record_on(struct cec_msg *msg,
|
||||
bool reply,
|
||||
const struct cec_op_record_src *rec_src)
|
||||
{
|
||||
switch (rec_src->type) {
|
||||
|
@ -346,6 +348,7 @@ static inline void cec_msg_record_on(struct cec_msg *msg,
|
|||
rec_src->ext_phys_addr.phys_addr);
|
||||
break;
|
||||
}
|
||||
msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0;
|
||||
}
|
||||
|
||||
static inline void cec_ops_record_on(const struct cec_msg *msg,
|
||||
|
@ -1141,6 +1144,75 @@ static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg,
|
|||
msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0;
|
||||
}
|
||||
|
||||
static inline void cec_msg_vendor_command(struct cec_msg *msg,
|
||||
__u8 size, const __u8 *vendor_cmd)
|
||||
{
|
||||
if (size > 14)
|
||||
size = 14;
|
||||
msg->len = 2 + size;
|
||||
msg->msg[1] = CEC_MSG_VENDOR_COMMAND;
|
||||
memcpy(msg->msg + 2, vendor_cmd, size);
|
||||
}
|
||||
|
||||
static inline void cec_ops_vendor_command(const struct cec_msg *msg,
|
||||
__u8 *size,
|
||||
const __u8 **vendor_cmd)
|
||||
{
|
||||
*size = msg->len - 2;
|
||||
|
||||
if (*size > 14)
|
||||
*size = 14;
|
||||
*vendor_cmd = msg->msg + 2;
|
||||
}
|
||||
|
||||
static inline void cec_msg_vendor_command_with_id(struct cec_msg *msg,
|
||||
__u32 vendor_id, __u8 size,
|
||||
const __u8 *vendor_cmd)
|
||||
{
|
||||
if (size > 11)
|
||||
size = 11;
|
||||
msg->len = 5 + size;
|
||||
msg->msg[1] = CEC_MSG_VENDOR_COMMAND_WITH_ID;
|
||||
msg->msg[2] = vendor_id >> 16;
|
||||
msg->msg[3] = (vendor_id >> 8) & 0xff;
|
||||
msg->msg[4] = vendor_id & 0xff;
|
||||
memcpy(msg->msg + 5, vendor_cmd, size);
|
||||
}
|
||||
|
||||
static inline void cec_ops_vendor_command_with_id(const struct cec_msg *msg,
|
||||
__u32 *vendor_id, __u8 *size,
|
||||
const __u8 **vendor_cmd)
|
||||
{
|
||||
*size = msg->len - 5;
|
||||
|
||||
if (*size > 11)
|
||||
*size = 11;
|
||||
*vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4];
|
||||
*vendor_cmd = msg->msg + 5;
|
||||
}
|
||||
|
||||
static inline void cec_msg_vendor_remote_button_down(struct cec_msg *msg,
|
||||
__u8 size,
|
||||
const __u8 *rc_code)
|
||||
{
|
||||
if (size > 14)
|
||||
size = 14;
|
||||
msg->len = 2 + size;
|
||||
msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN;
|
||||
memcpy(msg->msg + 2, rc_code, size);
|
||||
}
|
||||
|
||||
static inline void cec_ops_vendor_remote_button_down(const struct cec_msg *msg,
|
||||
__u8 *size,
|
||||
const __u8 **rc_code)
|
||||
{
|
||||
*size = msg->len - 2;
|
||||
|
||||
if (*size > 14)
|
||||
*size = 14;
|
||||
*rc_code = msg->msg + 2;
|
||||
}
|
||||
|
||||
static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg)
|
||||
{
|
||||
msg->len = 2;
|
||||
|
@ -1277,7 +1349,7 @@ static inline void cec_msg_user_control_pressed(struct cec_msg *msg,
|
|||
msg->len += 4;
|
||||
msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) |
|
||||
(ui_cmd->channel_identifier.major >> 8);
|
||||
msg->msg[4] = ui_cmd->channel_identifier.major && 0xff;
|
||||
msg->msg[4] = ui_cmd->channel_identifier.major & 0xff;
|
||||
msg->msg[5] = ui_cmd->channel_identifier.minor >> 8;
|
||||
msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff;
|
||||
break;
|
||||
|
|
|
@ -364,7 +364,7 @@ struct cec_caps {
|
|||
* @num_log_addrs: how many logical addresses should be claimed. Set by the
|
||||
* caller.
|
||||
* @vendor_id: the vendor ID of the device. Set by the caller.
|
||||
* @flags: set to 0.
|
||||
* @flags: flags.
|
||||
* @osd_name: the OSD name of the device. Set by the caller.
|
||||
* @primary_device_type: the primary device type for each logical address.
|
||||
* Set by the caller.
|
||||
|
@ -389,6 +389,9 @@ struct cec_log_addrs {
|
|||
__u8 features[CEC_MAX_LOG_ADDRS][12];
|
||||
};
|
||||
|
||||
/* Allow a fallback to unregistered */
|
||||
#define CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK (1 << 0)
|
||||
|
||||
/* Events */
|
||||
|
||||
/* Event that occurs when the adapter state changes */
|
||||
|
|
|
@ -57,8 +57,8 @@ struct cec_devnode {
|
|||
int minor;
|
||||
bool registered;
|
||||
bool unregistered;
|
||||
struct mutex fhs_lock;
|
||||
struct list_head fhs;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct cec_adapter;
|
||||
|
|
Loading…
Reference in New Issue