linux/drivers/media/v4l2-core/v4l2-dev.c

1107 lines
33 KiB
C
Raw Normal View History

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Video capture interface for Linux version 2
*
* A generic video device interface for the LINUX operating system
* using a set of device structures/vectors for low level operations.
*
* Authors: Alan Cox, <alan@lxorguk.ukuu.org.uk> (version 1)
* Mauro Carvalho Chehab <mchehab@kernel.org> (version 2)
*
* Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
* - Added procfs support
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
#define dprintk(fmt, arg...) do { \
printk(KERN_DEBUG pr_fmt("%s: " fmt), \
__func__, ##arg); \
} while (0)
/*
* sysfs stuff
*/
static ssize_t index_show(struct device *cd,
struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
return sprintf(buf, "%i\n", vdev->index);
}
static DEVICE_ATTR_RO(index);
static ssize_t dev_debug_show(struct device *cd,
struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
return sprintf(buf, "%i\n", vdev->dev_debug);
}
static ssize_t dev_debug_store(struct device *cd, struct device_attribute *attr,
const char *buf, size_t len)
{
struct video_device *vdev = to_video_device(cd);
int res = 0;
u16 value;
res = kstrtou16(buf, 0, &value);
if (res)
return res;
vdev->dev_debug = value;
return len;
}
static DEVICE_ATTR_RW(dev_debug);
static ssize_t name_show(struct device *cd,
struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
return sprintf(buf, "%.*s\n", (int)sizeof(vdev->name), vdev->name);
}
static DEVICE_ATTR_RO(name);
static struct attribute *video_device_attrs[] = {
&dev_attr_name.attr,
&dev_attr_dev_debug.attr,
&dev_attr_index.attr,
NULL,
};
ATTRIBUTE_GROUPS(video_device);
/*
* Active devices
*/
static struct video_device *video_devices[VIDEO_NUM_DEVICES];
static DEFINE_MUTEX(videodev_lock);
static DECLARE_BITMAP(devnode_nums[VFL_TYPE_MAX], VIDEO_NUM_DEVICES);
/* Device node utility functions */
/* Note: these utility functions all assume that vfl_type is in the range
[0, VFL_TYPE_MAX-1]. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* Return the bitmap corresponding to vfl_type. */
static inline unsigned long *devnode_bits(enum vfl_devnode_type vfl_type)
{
/* Any types not assigned to fixed minor ranges must be mapped to
one single bitmap for the purposes of finding a free node number
since all those unassigned types use the same minor range. */
int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type;
return devnode_nums[idx];
}
#else
/* Return the bitmap corresponding to vfl_type. */
static inline unsigned long *devnode_bits(enum vfl_devnode_type vfl_type)
{
return devnode_nums[vfl_type];
}
#endif
/* Mark device node number vdev->num as used */
static inline void devnode_set(struct video_device *vdev)
{
set_bit(vdev->num, devnode_bits(vdev->vfl_type));
}
/* Mark device node number vdev->num as unused */
static inline void devnode_clear(struct video_device *vdev)
{
clear_bit(vdev->num, devnode_bits(vdev->vfl_type));
}
/* Try to find a free device node number in the range [from, to> */
static inline int devnode_find(struct video_device *vdev, int from, int to)
{
return find_next_zero_bit(devnode_bits(vdev->vfl_type), to, from);
}
struct video_device *video_device_alloc(void)
{
return kzalloc(sizeof(struct video_device), GFP_KERNEL);
}
EXPORT_SYMBOL(video_device_alloc);
void video_device_release(struct video_device *vdev)
{
kfree(vdev);
}
EXPORT_SYMBOL(video_device_release);
void video_device_release_empty(struct video_device *vdev)
{
/* Do nothing */
/* Only valid when the video_device struct is a static. */
}
EXPORT_SYMBOL(video_device_release_empty);
static inline void video_get(struct video_device *vdev)
{
get_device(&vdev->dev);
}
static inline void video_put(struct video_device *vdev)
{
put_device(&vdev->dev);
}
/* Called when the last user of the video device exits. */
static void v4l2_device_release(struct device *cd)
{
struct video_device *vdev = to_video_device(cd);
struct v4l2_device *v4l2_dev = vdev->v4l2_dev;
mutex_lock(&videodev_lock);
if (WARN_ON(video_devices[vdev->minor] != vdev)) {
/* should not happen */
mutex_unlock(&videodev_lock);
return;
}
/* Free up this device for reuse */
video_devices[vdev->minor] = NULL;
/* Delete the cdev on this minor as well */
cdev_del(vdev->cdev);
/* Just in case some driver tries to access this from
the release() callback. */
vdev->cdev = NULL;
/* Mark device node number as free */
devnode_clear(vdev);
mutex_unlock(&videodev_lock);
#if defined(CONFIG_MEDIA_CONTROLLER)
if (v4l2_dev->mdev && vdev->vfl_dir != VFL_DIR_M2M) {
/* Remove interfaces and interface links */
media_devnode_remove(vdev->intf_devnode);
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN)
media_device_unregister_entity(&vdev->entity);
}
#endif
/* Do not call v4l2_device_put if there is no release callback set.
* Drivers that have no v4l2_device release callback might free the
* v4l2_dev instance in the video_device release callback below, so we
* must perform this check here.
*
* TODO: In the long run all drivers that use v4l2_device should use the
* v4l2_device release callback. This check will then be unnecessary.
*/
if (v4l2_dev->release == NULL)
v4l2_dev = NULL;
/* Release video_device and perform other
cleanups as needed. */
vdev->release(vdev);
/* Decrease v4l2_device refcount */
if (v4l2_dev)
v4l2_device_put(v4l2_dev);
}
static struct class video_class = {
.name = VIDEO_NAME,
.dev_groups = video_device_groups,
};
struct video_device *video_devdata(struct file *file)
{
return video_devices[iminor(file_inode(file))];
}
EXPORT_SYMBOL(video_devdata);
/* Priority handling */
static inline bool prio_is_valid(enum v4l2_priority prio)
{
return prio == V4L2_PRIORITY_BACKGROUND ||
prio == V4L2_PRIORITY_INTERACTIVE ||
prio == V4L2_PRIORITY_RECORD;
}
void v4l2_prio_init(struct v4l2_prio_state *global)
{
memset(global, 0, sizeof(*global));
}
EXPORT_SYMBOL(v4l2_prio_init);
int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
enum v4l2_priority new)
{
if (!prio_is_valid(new))
return -EINVAL;
if (*local == new)
return 0;
atomic_inc(&global->prios[new]);
if (prio_is_valid(*local))
atomic_dec(&global->prios[*local]);
*local = new;
return 0;
}
EXPORT_SYMBOL(v4l2_prio_change);
void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local)
{
v4l2_prio_change(global, local, V4L2_PRIORITY_DEFAULT);
}
EXPORT_SYMBOL(v4l2_prio_open);
void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local)
{
if (prio_is_valid(local))
atomic_dec(&global->prios[local]);
}
EXPORT_SYMBOL(v4l2_prio_close);
enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global)
{
if (atomic_read(&global->prios[V4L2_PRIORITY_RECORD]) > 0)
return V4L2_PRIORITY_RECORD;
if (atomic_read(&global->prios[V4L2_PRIORITY_INTERACTIVE]) > 0)
return V4L2_PRIORITY_INTERACTIVE;
if (atomic_read(&global->prios[V4L2_PRIORITY_BACKGROUND]) > 0)
return V4L2_PRIORITY_BACKGROUND;
return V4L2_PRIORITY_UNSET;
}
EXPORT_SYMBOL(v4l2_prio_max);
int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local)
{
return (local < v4l2_prio_max(global)) ? -EBUSY : 0;
}
EXPORT_SYMBOL(v4l2_prio_check);
static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if (!vdev->fops->read)
return -EINVAL;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) &&
(vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING))
dprintk("%s: read: %zd (%d)\n",
video_device_node_name(vdev), sz, ret);
return ret;
}
static ssize_t v4l2_write(struct file *filp, const char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if (!vdev->fops->write)
return -EINVAL;
if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off);
if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) &&
(vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING))
dprintk("%s: write: %zd (%d)\n",
video_device_node_name(vdev), sz, ret);
return ret;
}
static __poll_t v4l2_poll(struct file *filp, struct poll_table_struct *poll)
{
struct video_device *vdev = video_devdata(filp);
__poll_t res = EPOLLERR | EPOLLHUP;
if (!vdev->fops->poll)
return DEFAULT_POLLMASK;
if (video_is_registered(vdev))
res = vdev->fops->poll(filp, poll);
if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL)
dprintk("%s: poll: %08x\n",
video_device_node_name(vdev), res);
return res;
}
static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if (vdev->fops->unlocked_ioctl) {
if (video_is_registered(vdev))
ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
} else
ret = -ENOTTY;
return ret;
}
#ifdef CONFIG_MMU
#define v4l2_get_unmapped_area NULL
#else
static unsigned long v4l2_get_unmapped_area(struct file *filp,
unsigned long addr, unsigned long len, unsigned long pgoff,
unsigned long flags)
{
struct video_device *vdev = video_devdata(filp);
int ret;
if (!vdev->fops->get_unmapped_area)
return -ENOSYS;
if (!video_is_registered(vdev))
return -ENODEV;
ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
dprintk("%s: get_unmapped_area (%d)\n",
video_device_node_name(vdev), ret);
return ret;
}
#endif
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{
struct video_device *vdev = video_devdata(filp);
int ret = -ENODEV;
if (!vdev->fops->mmap)
return -ENODEV;
if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm);
if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
dprintk("%s: mmap (%d)\n",
video_device_node_name(vdev), ret);
return ret;
}
/* Override for the open function */
static int v4l2_open(struct inode *inode, struct file *filp)
{
struct video_device *vdev;
int ret = 0;
/* Check if the video device is available */
mutex_lock(&videodev_lock);
vdev = video_devdata(filp);
/* return ENODEV if the video device has already been removed. */
if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock);
return -ENODEV;
}
/* and increase the device refcount */
video_get(vdev);
mutex_unlock(&videodev_lock);
if (vdev->fops->open) {
if (video_is_registered(vdev))
ret = vdev->fops->open(filp);
else
ret = -ENODEV;
}
if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
dprintk("%s: open (%d)\n",
video_device_node_name(vdev), ret);
/* decrease the refcount in case of an error */
if (ret)
video_put(vdev);
return ret;
}
/* Override for the release function */
static int v4l2_release(struct inode *inode, struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
int ret = 0;
/*
* We need to serialize the release() with queueing new requests.
* The release() may trigger the cancellation of a streaming
* operation, and that should not be mixed with queueing a new
* request at the same time.
*/
if (vdev->fops->release) {
if (v4l2_device_supports_requests(vdev->v4l2_dev)) {
mutex_lock(&vdev->v4l2_dev->mdev->req_queue_mutex);
ret = vdev->fops->release(filp);
mutex_unlock(&vdev->v4l2_dev->mdev->req_queue_mutex);
} else {
ret = vdev->fops->release(filp);
}
}
if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
dprintk("%s: release\n",
video_device_node_name(vdev));
/* decrease the refcount unconditionally since the release()
return value is ignored. */
video_put(vdev);
return ret;
}
static const struct file_operations v4l2_fops = {
.owner = THIS_MODULE,
.read = v4l2_read,
.write = v4l2_write,
.open = v4l2_open,
.get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
.unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
.release = v4l2_release,
.poll = v4l2_poll,
.llseek = no_llseek,
};
/**
* get_index - assign stream index number based on v4l2_dev
* @vdev: video_device to assign index number to, vdev->v4l2_dev should be assigned
*
* Note that when this is called the new device has not yet been registered
* in the video_device array, but it was able to obtain a minor number.
*
* This means that we can always obtain a free stream index number since
* the worst case scenario is that there are VIDEO_NUM_DEVICES - 1 slots in
* use of the video_device array.
*
* Returns a free index number.
*/
static int get_index(struct video_device *vdev)
{
/* This can be static since this function is called with the global
videodev_lock held. */
static DECLARE_BITMAP(used, VIDEO_NUM_DEVICES);
int i;
bitmap_zero(used, VIDEO_NUM_DEVICES);
for (i = 0; i < VIDEO_NUM_DEVICES; i++) {
if (video_devices[i] != NULL &&
video_devices[i]->v4l2_dev == vdev->v4l2_dev) {
set_bit(video_devices[i]->index, used);
}
}
return find_first_zero_bit(used, VIDEO_NUM_DEVICES);
}
#define SET_VALID_IOCTL(ops, cmd, op) \
if (ops->op) \
set_bit(_IOC_NR(cmd), valid_ioctls)
/* This determines which ioctls are actually implemented in the driver.
It's a one-time thing which simplifies video_ioctl2 as it can just do
a bit test.
Note that drivers can override this by setting bits to 1 in
vdev->valid_ioctls. If an ioctl is marked as 1 when this function is
called, then that ioctl will actually be marked as unimplemented.
It does that by first setting up the local valid_ioctls bitmap, and
at the end do a:
vdev->valid_ioctls = valid_ioctls & ~(vdev->valid_ioctls)
*/
static void determine_valid_ioctls(struct video_device *vdev)
{
const u32 vid_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_VIDEO_CAPTURE_MPLANE |
V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OUTPUT_MPLANE |
V4L2_CAP_VIDEO_M2M | V4L2_CAP_VIDEO_M2M_MPLANE;
const u32 meta_caps = V4L2_CAP_META_CAPTURE |
V4L2_CAP_META_OUTPUT;
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
bool is_vid = vdev->vfl_type == VFL_TYPE_GRABBER &&
(vdev->device_caps & vid_caps);
bool is_vbi = vdev->vfl_type == VFL_TYPE_VBI;
bool is_radio = vdev->vfl_type == VFL_TYPE_RADIO;
bool is_sdr = vdev->vfl_type == VFL_TYPE_SDR;
bool is_tch = vdev->vfl_type == VFL_TYPE_TOUCH;
bool is_meta = vdev->vfl_type == VFL_TYPE_GRABBER &&
(vdev->device_caps & meta_caps);
bool is_rx = vdev->vfl_dir != VFL_DIR_TX;
bool is_tx = vdev->vfl_dir != VFL_DIR_RX;
bitmap_zero(valid_ioctls, BASE_VIDIOC_PRIVATE);
/* vfl_type and vfl_dir independent ioctls */
SET_VALID_IOCTL(ops, VIDIOC_QUERYCAP, vidioc_querycap);
set_bit(_IOC_NR(VIDIOC_G_PRIORITY), valid_ioctls);
set_bit(_IOC_NR(VIDIOC_S_PRIORITY), valid_ioctls);
/* Note: the control handler can also be passed through the filehandle,
and that can't be tested here. If the bit for these control ioctls
is set, then the ioctl is valid. But if it is 0, then it can still
be valid if the filehandle passed the control handler. */
if (vdev->ctrl_handler || ops->vidioc_queryctrl)
set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_query_ext_ctrl)
set_bit(_IOC_NR(VIDIOC_QUERY_EXT_CTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls)
set_bit(_IOC_NR(VIDIOC_S_EXT_CTRLS), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_try_ext_ctrls)
set_bit(_IOC_NR(VIDIOC_TRY_EXT_CTRLS), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_querymenu)
set_bit(_IOC_NR(VIDIOC_QUERYMENU), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_G_FREQUENCY, vidioc_g_frequency);
SET_VALID_IOCTL(ops, VIDIOC_S_FREQUENCY, vidioc_s_frequency);
SET_VALID_IOCTL(ops, VIDIOC_LOG_STATUS, vidioc_log_status);
#ifdef CONFIG_VIDEO_ADV_DEBUG
set_bit(_IOC_NR(VIDIOC_DBG_G_CHIP_INFO), valid_ioctls);
set_bit(_IOC_NR(VIDIOC_DBG_G_REGISTER), valid_ioctls);
set_bit(_IOC_NR(VIDIOC_DBG_S_REGISTER), valid_ioctls);
#endif
/* yes, really vidioc_subscribe_event */
SET_VALID_IOCTL(ops, VIDIOC_DQEVENT, vidioc_subscribe_event);
SET_VALID_IOCTL(ops, VIDIOC_SUBSCRIBE_EVENT, vidioc_subscribe_event);
SET_VALID_IOCTL(ops, VIDIOC_UNSUBSCRIBE_EVENT, vidioc_unsubscribe_event);
if (ops->vidioc_enum_freq_bands || ops->vidioc_g_tuner || ops->vidioc_g_modulator)
set_bit(_IOC_NR(VIDIOC_ENUM_FREQ_BANDS), valid_ioctls);
if (is_vid || is_tch) {
/* video and touch specific ioctls */
if ((is_rx && (ops->vidioc_enum_fmt_vid_cap ||
ops->vidioc_enum_fmt_vid_overlay)) ||
(is_tx && ops->vidioc_enum_fmt_vid_out))
set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
if ((is_rx && (ops->vidioc_g_fmt_vid_cap ||
ops->vidioc_g_fmt_vid_cap_mplane ||
ops->vidioc_g_fmt_vid_overlay)) ||
(is_tx && (ops->vidioc_g_fmt_vid_out ||
ops->vidioc_g_fmt_vid_out_mplane ||
ops->vidioc_g_fmt_vid_out_overlay)))
set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
if ((is_rx && (ops->vidioc_s_fmt_vid_cap ||
ops->vidioc_s_fmt_vid_cap_mplane ||
ops->vidioc_s_fmt_vid_overlay)) ||
(is_tx && (ops->vidioc_s_fmt_vid_out ||
ops->vidioc_s_fmt_vid_out_mplane ||
ops->vidioc_s_fmt_vid_out_overlay)))
set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
if ((is_rx && (ops->vidioc_try_fmt_vid_cap ||
ops->vidioc_try_fmt_vid_cap_mplane ||
ops->vidioc_try_fmt_vid_overlay)) ||
(is_tx && (ops->vidioc_try_fmt_vid_out ||
ops->vidioc_try_fmt_vid_out_mplane ||
ops->vidioc_try_fmt_vid_out_overlay)))
set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_OVERLAY, vidioc_overlay);
SET_VALID_IOCTL(ops, VIDIOC_G_FBUF, vidioc_g_fbuf);
SET_VALID_IOCTL(ops, VIDIOC_S_FBUF, vidioc_s_fbuf);
SET_VALID_IOCTL(ops, VIDIOC_G_JPEGCOMP, vidioc_g_jpegcomp);
SET_VALID_IOCTL(ops, VIDIOC_S_JPEGCOMP, vidioc_s_jpegcomp);
SET_VALID_IOCTL(ops, VIDIOC_G_ENC_INDEX, vidioc_g_enc_index);
SET_VALID_IOCTL(ops, VIDIOC_ENCODER_CMD, vidioc_encoder_cmd);
SET_VALID_IOCTL(ops, VIDIOC_TRY_ENCODER_CMD, vidioc_try_encoder_cmd);
SET_VALID_IOCTL(ops, VIDIOC_DECODER_CMD, vidioc_decoder_cmd);
SET_VALID_IOCTL(ops, VIDIOC_TRY_DECODER_CMD, vidioc_try_decoder_cmd);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMESIZES, vidioc_enum_framesizes);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FRAMEINTERVALS, vidioc_enum_frameintervals);
if (ops->vidioc_g_selection) {
set_bit(_IOC_NR(VIDIOC_G_CROP), valid_ioctls);
set_bit(_IOC_NR(VIDIOC_CROPCAP), valid_ioctls);
}
if (ops->vidioc_s_selection)
set_bit(_IOC_NR(VIDIOC_S_CROP), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_G_SELECTION, vidioc_g_selection);
SET_VALID_IOCTL(ops, VIDIOC_S_SELECTION, vidioc_s_selection);
}
if (is_meta && is_rx) {
/* metadata capture specific ioctls */
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_cap);
SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_cap);
SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_cap);
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_cap);
} else if (is_meta && is_tx) {
/* metadata output specific ioctls */
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_meta_out);
SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_meta_out);
SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_meta_out);
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_meta_out);
}
if (is_vbi) {
/* vbi specific ioctls */
if ((is_rx && (ops->vidioc_g_fmt_vbi_cap ||
ops->vidioc_g_fmt_sliced_vbi_cap)) ||
(is_tx && (ops->vidioc_g_fmt_vbi_out ||
ops->vidioc_g_fmt_sliced_vbi_out)))
set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
if ((is_rx && (ops->vidioc_s_fmt_vbi_cap ||
ops->vidioc_s_fmt_sliced_vbi_cap)) ||
(is_tx && (ops->vidioc_s_fmt_vbi_out ||
ops->vidioc_s_fmt_sliced_vbi_out)))
set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
if ((is_rx && (ops->vidioc_try_fmt_vbi_cap ||
ops->vidioc_try_fmt_sliced_vbi_cap)) ||
(is_tx && (ops->vidioc_try_fmt_vbi_out ||
ops->vidioc_try_fmt_sliced_vbi_out)))
set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
} else if (is_sdr && is_rx) {
/* SDR receiver specific ioctls */
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_cap);
SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_cap);
SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_cap);
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_cap);
} else if (is_sdr && is_tx) {
/* SDR transmitter specific ioctls */
SET_VALID_IOCTL(ops, VIDIOC_ENUM_FMT, vidioc_enum_fmt_sdr_out);
SET_VALID_IOCTL(ops, VIDIOC_G_FMT, vidioc_g_fmt_sdr_out);
SET_VALID_IOCTL(ops, VIDIOC_S_FMT, vidioc_s_fmt_sdr_out);
SET_VALID_IOCTL(ops, VIDIOC_TRY_FMT, vidioc_try_fmt_sdr_out);
}
if (is_vid || is_vbi || is_sdr || is_tch || is_meta) {
/* ioctls valid for video, vbi, sdr, touch and metadata */
SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs);
SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf);
SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf);
SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf);
SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf);
SET_VALID_IOCTL(ops, VIDIOC_CREATE_BUFS, vidioc_create_bufs);
SET_VALID_IOCTL(ops, VIDIOC_PREPARE_BUF, vidioc_prepare_buf);
SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon);
SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff);
}
if (is_vid || is_vbi || is_tch || is_meta) {
/* ioctls valid for video, vbi, touch and metadata */
if (ops->vidioc_s_std)
set_bit(_IOC_NR(VIDIOC_ENUMSTD), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_S_STD, vidioc_s_std);
SET_VALID_IOCTL(ops, VIDIOC_G_STD, vidioc_g_std);
if (is_rx) {
SET_VALID_IOCTL(ops, VIDIOC_QUERYSTD, vidioc_querystd);
SET_VALID_IOCTL(ops, VIDIOC_ENUMINPUT, vidioc_enum_input);
SET_VALID_IOCTL(ops, VIDIOC_G_INPUT, vidioc_g_input);
SET_VALID_IOCTL(ops, VIDIOC_S_INPUT, vidioc_s_input);
SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDIO, vidioc_enumaudio);
SET_VALID_IOCTL(ops, VIDIOC_G_AUDIO, vidioc_g_audio);
SET_VALID_IOCTL(ops, VIDIOC_S_AUDIO, vidioc_s_audio);
SET_VALID_IOCTL(ops, VIDIOC_QUERY_DV_TIMINGS, vidioc_query_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_S_EDID, vidioc_s_edid);
}
if (is_tx) {
SET_VALID_IOCTL(ops, VIDIOC_ENUMOUTPUT, vidioc_enum_output);
SET_VALID_IOCTL(ops, VIDIOC_G_OUTPUT, vidioc_g_output);
SET_VALID_IOCTL(ops, VIDIOC_S_OUTPUT, vidioc_s_output);
SET_VALID_IOCTL(ops, VIDIOC_ENUMAUDOUT, vidioc_enumaudout);
SET_VALID_IOCTL(ops, VIDIOC_G_AUDOUT, vidioc_g_audout);
SET_VALID_IOCTL(ops, VIDIOC_S_AUDOUT, vidioc_s_audout);
}
if (ops->vidioc_g_parm || (vdev->vfl_type == VFL_TYPE_GRABBER &&
ops->vidioc_g_std))
set_bit(_IOC_NR(VIDIOC_G_PARM), valid_ioctls);
SET_VALID_IOCTL(ops, VIDIOC_S_PARM, vidioc_s_parm);
SET_VALID_IOCTL(ops, VIDIOC_S_DV_TIMINGS, vidioc_s_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_G_DV_TIMINGS, vidioc_g_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_ENUM_DV_TIMINGS, vidioc_enum_dv_timings);
SET_VALID_IOCTL(ops, VIDIOC_DV_TIMINGS_CAP, vidioc_dv_timings_cap);
SET_VALID_IOCTL(ops, VIDIOC_G_EDID, vidioc_g_edid);
}
if (is_tx && (is_radio || is_sdr)) {
/* radio transmitter only ioctls */
SET_VALID_IOCTL(ops, VIDIOC_G_MODULATOR, vidioc_g_modulator);
SET_VALID_IOCTL(ops, VIDIOC_S_MODULATOR, vidioc_s_modulator);
}
if (is_rx) {
/* receiver only ioctls */
SET_VALID_IOCTL(ops, VIDIOC_G_TUNER, vidioc_g_tuner);
SET_VALID_IOCTL(ops, VIDIOC_S_TUNER, vidioc_s_tuner);
SET_VALID_IOCTL(ops, VIDIOC_S_HW_FREQ_SEEK, vidioc_s_hw_freq_seek);
}
bitmap_andnot(vdev->valid_ioctls, valid_ioctls, vdev->valid_ioctls,
BASE_VIDIOC_PRIVATE);
}
static int video_register_media_controller(struct video_device *vdev)
{
#if defined(CONFIG_MEDIA_CONTROLLER)
u32 intf_type;
int ret;
/* Memory-to-memory devices are more complex and use
* their own function to register its mc entities.
*/
if (!vdev->v4l2_dev->mdev || vdev->vfl_dir == VFL_DIR_M2M)
return 0;
vdev->entity.obj_type = MEDIA_ENTITY_TYPE_VIDEO_DEVICE;
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
vdev->entity.function = MEDIA_ENT_F_UNKNOWN;
switch (vdev->vfl_type) {
case VFL_TYPE_GRABBER:
intf_type = MEDIA_INTF_T_V4L_VIDEO;
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
vdev->entity.function = MEDIA_ENT_F_IO_V4L;
break;
case VFL_TYPE_VBI:
intf_type = MEDIA_INTF_T_V4L_VBI;
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
vdev->entity.function = MEDIA_ENT_F_IO_VBI;
break;
case VFL_TYPE_SDR:
intf_type = MEDIA_INTF_T_V4L_SWRADIO;
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
vdev->entity.function = MEDIA_ENT_F_IO_SWRADIO;
break;
case VFL_TYPE_TOUCH:
intf_type = MEDIA_INTF_T_V4L_TOUCH;
vdev->entity.function = MEDIA_ENT_F_IO_V4L;
break;
case VFL_TYPE_RADIO:
intf_type = MEDIA_INTF_T_V4L_RADIO;
/*
* Radio doesn't have an entity at the V4L2 side to represent
* radio input or output. Instead, the audio input/output goes
* via either physical wires or ALSA.
*/
break;
case VFL_TYPE_SUBDEV:
intf_type = MEDIA_INTF_T_V4L_SUBDEV;
/* Entity will be created via v4l2_device_register_subdev() */
break;
default:
return 0;
}
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) {
vdev->entity.name = vdev->name;
/* Needed just for backward compatibility with legacy MC API */
vdev->entity.info.dev.major = VIDEO_MAJOR;
vdev->entity.info.dev.minor = vdev->minor;
ret = media_device_register_entity(vdev->v4l2_dev->mdev,
&vdev->entity);
if (ret < 0) {
pr_warn("%s: media_device_register_entity failed\n",
__func__);
return ret;
}
}
vdev->intf_devnode = media_devnode_create(vdev->v4l2_dev->mdev,
intf_type,
0, VIDEO_MAJOR,
vdev->minor);
if (!vdev->intf_devnode) {
media_device_unregister_entity(&vdev->entity);
return -ENOMEM;
}
[media] uapi/media.h: Rename entities types to functions Rename the userspace types from MEDIA_ENT_T_ to MEDIA_ENT_F_ and add the backward compatibility bits. The changes at the .c files was generated by the following coccinelle script: @@ @@ -MEDIA_ENT_T_UNKNOWN +MEDIA_ENT_F_UNKNOWN @@ @@ -MEDIA_ENT_T_DVB_BASE +MEDIA_ENT_F_DVB_BASE @@ @@ -MEDIA_ENT_T_V4L2_BASE +MEDIA_ENT_F_V4L2_BASE @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_BASE +MEDIA_ENT_F_V4L2_SUBDEV_BASE @@ @@ -MEDIA_ENT_T_CONNECTOR_BASE +MEDIA_ENT_F_CONNECTOR_BASE @@ @@ -MEDIA_ENT_T_V4L2_VIDEO +MEDIA_ENT_F_IO_V4L @@ @@ -MEDIA_ENT_T_V4L2_VBI +MEDIA_ENT_F_IO_VBI @@ @@ -MEDIA_ENT_T_V4L2_SWRADIO +MEDIA_ENT_F_IO_SWRADIO @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_UNKNOWN +MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN @@ @@ -MEDIA_ENT_T_CONN_RF +MEDIA_ENT_F_CONN_RF @@ @@ -MEDIA_ENT_T_CONN_SVIDEO +MEDIA_ENT_F_CONN_SVIDEO @@ @@ -MEDIA_ENT_T_CONN_COMPOSITE +MEDIA_ENT_F_CONN_COMPOSITE @@ @@ -MEDIA_ENT_T_CONN_TEST +MEDIA_ENT_F_CONN_TEST @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_SENSOR +MEDIA_ENT_F_CAM_SENSOR @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_FLASH +MEDIA_ENT_F_FLASH @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_LENS +MEDIA_ENT_F_LENS @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_DECODER +MEDIA_ENT_F_ATV_DECODER @@ @@ -MEDIA_ENT_T_V4L2_SUBDEV_TUNER +MEDIA_ENT_F_TUNER @@ @@ -MEDIA_ENT_T_DVB_DEMOD +MEDIA_ENT_F_DTV_DEMOD @@ @@ -MEDIA_ENT_T_DVB_DEMUX +MEDIA_ENT_F_TS_DEMUX @@ @@ -MEDIA_ENT_T_DVB_TSOUT +MEDIA_ENT_F_IO_DTV @@ @@ -MEDIA_ENT_T_DVB_CA +MEDIA_ENT_F_DTV_CA @@ @@ -MEDIA_ENT_T_DVB_NET_DECAP +MEDIA_ENT_F_DTV_NET_DECAP Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-12-11 03:25:41 +08:00
if (vdev->entity.function != MEDIA_ENT_F_UNKNOWN) {
struct media_link *link;
link = media_create_intf_link(&vdev->entity,
&vdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link) {
media_devnode_remove(vdev->intf_devnode);
media_device_unregister_entity(&vdev->entity);
return -ENOMEM;
}
}
/* FIXME: how to create the other interface links? */
#endif
return 0;
}
int __video_register_device(struct video_device *vdev,
enum vfl_devnode_type type,
int nr, int warn_if_nr_in_use,
struct module *owner)
{
int i = 0;
int ret;
int minor_offset = 0;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base;
/* A minor value of -1 marks this video device as never
having been registered */
vdev->minor = -1;
/* the release callback MUST be present */
if (WARN_ON(!vdev->release))
return -EINVAL;
/* the v4l2_dev pointer MUST be present */
if (WARN_ON(!vdev->v4l2_dev))
return -EINVAL;
/* the device_caps field MUST be set for all but subdevs */
if (WARN_ON(type != VFL_TYPE_SUBDEV && !vdev->device_caps))
return -EINVAL;
/* v4l2_fh support */
spin_lock_init(&vdev->fh_lock);
INIT_LIST_HEAD(&vdev->fh_list);
/* Part 1: check device type */
switch (type) {
case VFL_TYPE_GRABBER:
name_base = "video";
break;
case VFL_TYPE_VBI:
name_base = "vbi";
break;
case VFL_TYPE_RADIO:
name_base = "radio";
break;
case VFL_TYPE_SUBDEV:
name_base = "v4l-subdev";
break;
case VFL_TYPE_SDR:
/* Use device name 'swradio' because 'sdr' was already taken. */
name_base = "swradio";
break;
case VFL_TYPE_TOUCH:
name_base = "v4l-touch";
break;
default:
pr_err("%s called with unknown type: %d\n",
__func__, type);
return -EINVAL;
}
vdev->vfl_type = type;
vdev->cdev = NULL;
if (vdev->dev_parent == NULL)
vdev->dev_parent = vdev->v4l2_dev->dev;
if (vdev->ctrl_handler == NULL)
vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
/* If the prio state pointer is NULL, then use the v4l2_device
prio state. */
if (vdev->prio == NULL)
vdev->prio = &vdev->v4l2_dev->prio;
/* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* Keep the ranges for the first four types for historical
* reasons.
* Newer devices (not yet in place) should use the range
* of 128-191 and just pick the first free minor there
* (new style). */
switch (type) {
case VFL_TYPE_GRABBER:
minor_offset = 0;
minor_cnt = 64;
break;
case VFL_TYPE_RADIO:
minor_offset = 64;
minor_cnt = 64;
break;
case VFL_TYPE_VBI:
minor_offset = 224;
minor_cnt = 32;
break;
default:
minor_offset = 128;
minor_cnt = 64;
break;
}
#endif
/* Pick a device node number */
mutex_lock(&videodev_lock);
nr = devnode_find(vdev, nr == -1 ? 0 : nr, minor_cnt);
if (nr == minor_cnt)
nr = devnode_find(vdev, 0, minor_cnt);
if (nr == minor_cnt) {
pr_err("could not get a free device node number\n");
mutex_unlock(&videodev_lock);
return -ENFILE;
}
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
/* 1-on-1 mapping of device node number to minor number */
i = nr;
#else
/* The device node number and minor numbers are independent, so
we just find the first free minor number. */
for (i = 0; i < VIDEO_NUM_DEVICES; i++)
if (video_devices[i] == NULL)
break;
if (i == VIDEO_NUM_DEVICES) {
mutex_unlock(&videodev_lock);
pr_err("could not get a free minor\n");
return -ENFILE;
}
#endif
vdev->minor = i + minor_offset;
vdev->num = nr;
/* Should not happen since we thought this minor was free */
if (WARN_ON(video_devices[vdev->minor])) {
media: v4l2-core: fix size of devnode_nums[] bitarray The size of devnode_nums[] bit array is too short to store information for VFL_TYPE_TOUCH. That causes it to override other memory regions. Thankfully, on recent reports, it is overriding video_device[] array, trigging a WARN_ON(). Yet, it just warns about the problem, but let the code excecuting, with generates an OOPS: [ 43.177394] WARNING: CPU: 1 PID: 711 at drivers/media/v4l2-core/v4l2-dev.c:945 __video_register_device+0xc99/0x1090 [videodev] [ 43.177396] Modules linked in: hid_sensor_custom hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer kfifo_buf joydev hid_sensor_iio_common hid_rmi(+) rmi_core industrialio videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_common videodev hid_multitouch media hid_sensor_hub binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi arc4 snd_soc_skl snd_soc_skl_ipc snd_hda_ext_core snd_soc_sst_dsp snd_soc_sst_ipc snd_hda_codec_realtek snd_soc_acpi snd_hda_codec_generic snd_soc_core snd_compress ac97_bus snd_pcm_dmaengine snd_hda_intel snd_hda_codec intel_rapl snd_hda_core x86_pkg_temp_thermal snd_hwdep intel_powerclamp coretemp snd_pcm kvm_intel snd_seq_midi snd_seq_midi_event snd_rawmidi crct10dif_pclmul [ 43.177426] crc32_pclmul ghash_clmulni_intel iwlmvm pcbc mac80211 snd_seq aesni_intel iwlwifi aes_x86_64 snd_seq_device crypto_simd glue_helper cryptd snd_timer intel_cstate intel_rapl_perf input_leds serio_raw intel_wmi_thunderbolt snd wmi_bmof cfg80211 soundcore ideapad_laptop sparse_keymap idma64 virt_dma tpm_crb acpi_pad int3400_thermal acpi_thermal_rel intel_pch_thermal processor_thermal_device mac_hid int340x_thermal_zone mei_me intel_soc_dts_iosf mei intel_lpss_pci shpchp intel_lpss sch_fq_codel vfio_pci nfsd vfio_virqfd parport_pc ppdev auth_rpcgss nfs_acl lockd grace lp parport sunrpc ip_tables x_tables autofs4 hid_logitech_hidpp hid_logitech_dj hid_generic usbhid kvmgt vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass i915 i2c_algo_bit drm_kms_helper syscopyarea sdhci_pci sysfillrect [ 43.177466] sysimgblt cqhci fb_sys_fops sdhci drm i2c_hid wmi hid video pinctrl_sunrisepoint pinctrl_intel [ 43.177474] CPU: 1 PID: 711 Comm: systemd-udevd Not tainted 4.16.0 #1 [ 43.177475] Hardware name: LENOVO 80UE/VIUU4, BIOS 2UCN10T 10/14/2016 [ 43.177481] RIP: 0010:__video_register_device+0xc99/0x1090 [videodev] [ 43.177482] RSP: 0000:ffffa5c5c231b420 EFLAGS: 00010202 [ 43.177484] RAX: 0000000000000000 RBX: 0000000000000005 RCX: 0000000000000000 [ 43.177485] RDX: ffffffffc0c44cc0 RSI: ffffffffffffffff RDI: ffffffffc0c44cc0 [ 43.177486] RBP: ffffa5c5c231b478 R08: ffffffffc0c96900 R09: ffff8eda1a51f018 [ 43.177487] R10: 0000000000000600 R11: 00000000000003b6 R12: 0000000000000000 [ 43.177488] R13: 0000000000000005 R14: ffffffffc0c96900 R15: ffff8eda1d6d91c0 [ 43.177489] FS: 00007fd2d8ef2480(0000) GS:ffff8eda33480000(0000) knlGS:0000000000000000 [ 43.177490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 43.177491] CR2: 00007ffe0a6ad01c CR3: 0000000456ae2004 CR4: 00000000003606e0 [ 43.177492] Call Trace: [ 43.177498] ? devres_add+0x5f/0x70 [ 43.177502] rmi_f54_probe+0x437/0x470 [rmi_core] [ 43.177505] rmi_function_probe+0x25/0x30 [rmi_core] [ 43.177507] driver_probe_device+0x310/0x480 [ 43.177509] __device_attach_driver+0x86/0x100 [ 43.177511] ? __driver_attach+0xf0/0xf0 [ 43.177512] bus_for_each_drv+0x6b/0xb0 [ 43.177514] __device_attach+0xdd/0x160 [ 43.177516] device_initial_probe+0x13/0x20 [ 43.177518] bus_probe_device+0x95/0xa0 [ 43.177519] device_add+0x44b/0x680 [ 43.177522] rmi_register_function+0x62/0xd0 [rmi_core] [ 43.177525] rmi_create_function+0x112/0x1a0 [rmi_core] [ 43.177527] ? rmi_driver_clear_irq_bits+0xc0/0xc0 [rmi_core] [ 43.177530] rmi_scan_pdt+0xca/0x1a0 [rmi_core] [ 43.177535] rmi_init_functions+0x5b/0x120 [rmi_core] [ 43.177537] rmi_driver_probe+0x152/0x3c0 [rmi_core] [ 43.177547] ? sysfs_create_link+0x25/0x40 [ 43.177549] driver_probe_device+0x310/0x480 [ 43.177551] __device_attach_driver+0x86/0x100 [ 43.177553] ? __driver_attach+0xf0/0xf0 [ 43.177554] bus_for_each_drv+0x6b/0xb0 [ 43.177556] __device_attach+0xdd/0x160 [ 43.177558] device_initial_probe+0x13/0x20 [ 43.177560] bus_probe_device+0x95/0xa0 [ 43.177561] device_add+0x44b/0x680 [ 43.177564] rmi_register_transport_device+0x84/0x100 [rmi_core] [ 43.177568] rmi_input_configured+0xbf/0x1a0 [hid_rmi] [ 43.177571] ? input_allocate_device+0xdf/0xf0 [ 43.177574] hidinput_connect+0x4a9/0x37a0 [hid] [ 43.177578] hid_connect+0x326/0x3d0 [hid] [ 43.177581] hid_hw_start+0x42/0x70 [hid] [ 43.177583] rmi_probe+0x115/0x510 [hid_rmi] [ 43.177586] hid_device_probe+0xd3/0x150 [hid] [ 43.177588] ? sysfs_create_link+0x25/0x40 [ 43.177590] driver_probe_device+0x310/0x480 [ 43.177592] __driver_attach+0xbf/0xf0 [ 43.177593] ? driver_probe_device+0x480/0x480 [ 43.177595] bus_for_each_dev+0x74/0xb0 [ 43.177597] ? kmem_cache_alloc_trace+0x1a6/0x1c0 [ 43.177599] driver_attach+0x1e/0x20 [ 43.177600] bus_add_driver+0x167/0x260 [ 43.177602] ? 0xffffffffc0cbc000 [ 43.177604] driver_register+0x60/0xe0 [ 43.177605] ? 0xffffffffc0cbc000 [ 43.177607] __hid_register_driver+0x63/0x70 [hid] [ 43.177610] rmi_driver_init+0x23/0x1000 [hid_rmi] [ 43.177612] do_one_initcall+0x52/0x191 [ 43.177615] ? _cond_resched+0x19/0x40 [ 43.177617] ? kmem_cache_alloc_trace+0xa2/0x1c0 [ 43.177619] ? do_init_module+0x27/0x209 [ 43.177621] do_init_module+0x5f/0x209 [ 43.177623] load_module+0x1987/0x1f10 [ 43.177626] ? ima_post_read_file+0x96/0xa0 [ 43.177629] SYSC_finit_module+0xfc/0x120 [ 43.177630] ? SYSC_finit_module+0xfc/0x120 [ 43.177632] SyS_finit_module+0xe/0x10 [ 43.177634] do_syscall_64+0x73/0x130 [ 43.177637] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 43.177638] RIP: 0033:0x7fd2d880b839 [ 43.177639] RSP: 002b:00007ffe0a6b2368 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 43.177641] RAX: ffffffffffffffda RBX: 000055cdd86542e0 RCX: 00007fd2d880b839 [ 43.177641] RDX: 0000000000000000 RSI: 00007fd2d84ea0e5 RDI: 0000000000000016 [ 43.177642] RBP: 00007fd2d84ea0e5 R08: 0000000000000000 R09: 00007ffe0a6b2480 [ 43.177643] R10: 0000000000000016 R11: 0000000000000246 R12: 0000000000000000 [ 43.177644] R13: 000055cdd8688930 R14: 0000000000020000 R15: 000055cdd86542e0 [ 43.177645] Code: 48 c7 c7 54 b4 c3 c0 e8 96 9d ec dd e9 d4 fb ff ff 0f 0b 41 be ea ff ff ff e9 c7 fb ff ff 0f 0b 41 be ea ff ff ff e9 ba fb ff ff <0f> 0b e9 d8 f4 ff ff 83 fa 01 0f 84 c4 02 00 00 48 83 78 68 00 [ 43.177675] ---[ end trace d44d9bc41477c2dd ]--- [ 43.177679] BUG: unable to handle kernel NULL pointer dereference at 0000000000000499 [ 43.177723] IP: __video_register_device+0x1cc/0x1090 [videodev] [ 43.177749] PGD 0 P4D 0 [ 43.177764] Oops: 0000 [#1] SMP PTI [ 43.177780] Modules linked in: hid_sensor_custom hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer kfifo_buf joydev hid_sensor_iio_common hid_rmi(+) rmi_core industrialio videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_common videodev hid_multitouch media hid_sensor_hub binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi arc4 snd_soc_skl snd_soc_skl_ipc snd_hda_ext_core snd_soc_sst_dsp snd_soc_sst_ipc snd_hda_codec_realtek snd_soc_acpi snd_hda_codec_generic snd_soc_core snd_compress ac97_bus snd_pcm_dmaengine snd_hda_intel snd_hda_codec intel_rapl snd_hda_core x86_pkg_temp_thermal snd_hwdep intel_powerclamp coretemp snd_pcm kvm_intel snd_seq_midi snd_seq_midi_event snd_rawmidi crct10dif_pclmul [ 43.178055] crc32_pclmul ghash_clmulni_intel iwlmvm pcbc mac80211 snd_seq aesni_intel iwlwifi aes_x86_64 snd_seq_device crypto_simd glue_helper cryptd snd_timer intel_cstate intel_rapl_perf input_leds serio_raw intel_wmi_thunderbolt snd wmi_bmof cfg80211 soundcore ideapad_laptop sparse_keymap idma64 virt_dma tpm_crb acpi_pad int3400_thermal acpi_thermal_rel intel_pch_thermal processor_thermal_device mac_hid int340x_thermal_zone mei_me intel_soc_dts_iosf mei intel_lpss_pci shpchp intel_lpss sch_fq_codel vfio_pci nfsd vfio_virqfd parport_pc ppdev auth_rpcgss nfs_acl lockd grace lp parport sunrpc ip_tables x_tables autofs4 hid_logitech_hidpp hid_logitech_dj hid_generic usbhid kvmgt vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass i915 i2c_algo_bit drm_kms_helper syscopyarea sdhci_pci sysfillrect [ 43.178337] sysimgblt cqhci fb_sys_fops sdhci drm i2c_hid wmi hid video pinctrl_sunrisepoint pinctrl_intel [ 43.178380] CPU: 1 PID: 711 Comm: systemd-udevd Tainted: G W 4.16.0 #1 [ 43.178411] Hardware name: LENOVO 80UE/VIUU4, BIOS 2UCN10T 10/14/2016 [ 43.178441] RIP: 0010:__video_register_device+0x1cc/0x1090 [videodev] [ 43.178467] RSP: 0000:ffffa5c5c231b420 EFLAGS: 00010202 [ 43.178490] RAX: ffffffffc0c44cc0 RBX: 0000000000000005 RCX: ffffffffc0c454c0 [ 43.178519] RDX: 0000000000000001 RSI: ffff8eda1d6d9118 RDI: ffffffffc0c44cc0 [ 43.178549] RBP: ffffa5c5c231b478 R08: ffffffffc0c96900 R09: ffff8eda1a51f018 [ 43.178579] R10: 0000000000000600 R11: 00000000000003b6 R12: 0000000000000000 [ 43.178608] R13: 0000000000000005 R14: ffffffffc0c96900 R15: ffff8eda1d6d91c0 [ 43.178636] FS: 00007fd2d8ef2480(0000) GS:ffff8eda33480000(0000) knlGS:0000000000000000 [ 43.178669] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 43.178693] CR2: 0000000000000499 CR3: 0000000456ae2004 CR4: 00000000003606e0 [ 43.178721] Call Trace: [ 43.178736] ? devres_add+0x5f/0x70 [ 43.178755] rmi_f54_probe+0x437/0x470 [rmi_core] [ 43.178779] rmi_function_probe+0x25/0x30 [rmi_core] [ 43.178805] driver_probe_device+0x310/0x480 [ 43.178828] __device_attach_driver+0x86/0x100 [ 43.178851] ? __driver_attach+0xf0/0xf0 [ 43.178884] bus_for_each_drv+0x6b/0xb0 [ 43.178904] __device_attach+0xdd/0x160 [ 43.178925] device_initial_probe+0x13/0x20 [ 43.178948] bus_probe_device+0x95/0xa0 [ 43.178968] device_add+0x44b/0x680 [ 43.178987] rmi_register_function+0x62/0xd0 [rmi_core] [ 43.181747] rmi_create_function+0x112/0x1a0 [rmi_core] [ 43.184677] ? rmi_driver_clear_irq_bits+0xc0/0xc0 [rmi_core] [ 43.187505] rmi_scan_pdt+0xca/0x1a0 [rmi_core] [ 43.190171] rmi_init_functions+0x5b/0x120 [rmi_core] [ 43.192809] rmi_driver_probe+0x152/0x3c0 [rmi_core] [ 43.195403] ? sysfs_create_link+0x25/0x40 [ 43.198253] driver_probe_device+0x310/0x480 [ 43.201083] __device_attach_driver+0x86/0x100 [ 43.203800] ? __driver_attach+0xf0/0xf0 [ 43.206503] bus_for_each_drv+0x6b/0xb0 [ 43.209291] __device_attach+0xdd/0x160 [ 43.212207] device_initial_probe+0x13/0x20 [ 43.215146] bus_probe_device+0x95/0xa0 [ 43.217885] device_add+0x44b/0x680 [ 43.220597] rmi_register_transport_device+0x84/0x100 [rmi_core] [ 43.223321] rmi_input_configured+0xbf/0x1a0 [hid_rmi] [ 43.226051] ? input_allocate_device+0xdf/0xf0 [ 43.228814] hidinput_connect+0x4a9/0x37a0 [hid] [ 43.231701] hid_connect+0x326/0x3d0 [hid] [ 43.234548] hid_hw_start+0x42/0x70 [hid] [ 43.237302] rmi_probe+0x115/0x510 [hid_rmi] [ 43.239862] hid_device_probe+0xd3/0x150 [hid] [ 43.242558] ? sysfs_create_link+0x25/0x40 [ 43.242828] audit: type=1400 audit(1522795151.600:4): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/4206/usr/lib/snapd/snap-confine" pid=1151 comm="apparmor_parser" [ 43.244859] driver_probe_device+0x310/0x480 [ 43.244862] __driver_attach+0xbf/0xf0 [ 43.246982] audit: type=1400 audit(1522795151.600:5): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/4206/usr/lib/snapd/snap-confine//mount-namespace-capture-helper" pid=1151 comm="apparmor_parser" [ 43.249403] ? driver_probe_device+0x480/0x480 [ 43.249405] bus_for_each_dev+0x74/0xb0 [ 43.253200] audit: type=1400 audit(1522795151.600:6): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/4206/usr/lib/snapd/snap-confine//snap_update_ns" pid=1151 comm="apparmor_parser" [ 43.254055] ? kmem_cache_alloc_trace+0x1a6/0x1c0 [ 43.256282] audit: type=1400 audit(1522795151.604:7): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/sbin/dhclient" pid=1152 comm="apparmor_parser" [ 43.258436] driver_attach+0x1e/0x20 [ 43.260875] audit: type=1400 audit(1522795151.604:8): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/NetworkManager/nm-dhcp-client.action" pid=1152 comm="apparmor_parser" [ 43.263118] bus_add_driver+0x167/0x260 [ 43.267676] audit: type=1400 audit(1522795151.604:9): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/NetworkManager/nm-dhcp-helper" pid=1152 comm="apparmor_parser" [ 43.268807] ? 0xffffffffc0cbc000 [ 43.268812] driver_register+0x60/0xe0 [ 43.271184] audit: type=1400 audit(1522795151.604:10): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/connman/scripts/dhclient-script" pid=1152 comm="apparmor_parser" [ 43.274081] ? 0xffffffffc0cbc000 [ 43.274086] __hid_register_driver+0x63/0x70 [hid] [ 43.288367] rmi_driver_init+0x23/0x1000 [hid_rmi] [ 43.291501] do_one_initcall+0x52/0x191 [ 43.292348] audit: type=1400 audit(1522795151.652:11): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/bin/man" pid=1242 comm="apparmor_parser" [ 43.294212] ? _cond_resched+0x19/0x40 [ 43.300028] ? kmem_cache_alloc_trace+0xa2/0x1c0 [ 43.303475] ? do_init_module+0x27/0x209 [ 43.306842] do_init_module+0x5f/0x209 [ 43.310269] load_module+0x1987/0x1f10 [ 43.313704] ? ima_post_read_file+0x96/0xa0 [ 43.317174] SYSC_finit_module+0xfc/0x120 [ 43.320754] ? SYSC_finit_module+0xfc/0x120 [ 43.324065] SyS_finit_module+0xe/0x10 [ 43.327387] do_syscall_64+0x73/0x130 [ 43.330909] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 43.334305] RIP: 0033:0x7fd2d880b839 [ 43.337810] RSP: 002b:00007ffe0a6b2368 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 43.341259] RAX: ffffffffffffffda RBX: 000055cdd86542e0 RCX: 00007fd2d880b839 [ 43.344613] RDX: 0000000000000000 RSI: 00007fd2d84ea0e5 RDI: 0000000000000016 [ 43.347962] RBP: 00007fd2d84ea0e5 R08: 0000000000000000 R09: 00007ffe0a6b2480 [ 43.351456] R10: 0000000000000016 R11: 0000000000000246 R12: 0000000000000000 [ 43.354845] R13: 000055cdd8688930 R14: 0000000000020000 R15: 000055cdd86542e0 [ 43.358224] Code: c7 05 ad 12 02 00 00 00 00 00 48 8d 88 00 08 00 00 eb 09 48 83 c0 08 48 39 c1 74 31 48 8b 10 48 85 d2 74 ef 49 8b b7 98 04 00 00 <48> 39 b2 98 04 00 00 75 df 48 63 92 f8 04 00 00 f0 48 0f ab 15 [ 43.361764] RIP: __video_register_device+0x1cc/0x1090 [videodev] RSP: ffffa5c5c231b420 [ 43.365281] CR2: 0000000000000499 This patch fixes the array size and changes the WARN_ON() to return an error, instead of letting the Kernel to proceed with registering. Cc: stable@vger.kernel.org # For Kernel 4.16 Fixes: 4839c58f034a ("media: v4l2-dev: convert VFL_TYPE_* into an enum") Reported-by: Peter Geis <pgwipeout@gmail.com> Reported-by: Jaak Ristioja <jaak@ristioja.ee> Reported-by: Michał Siemek <mihau69@gmail.com> Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2018-04-05 17:51:15 +08:00
mutex_unlock(&videodev_lock);
pr_err("video_device not empty!\n");
media: v4l2-core: fix size of devnode_nums[] bitarray The size of devnode_nums[] bit array is too short to store information for VFL_TYPE_TOUCH. That causes it to override other memory regions. Thankfully, on recent reports, it is overriding video_device[] array, trigging a WARN_ON(). Yet, it just warns about the problem, but let the code excecuting, with generates an OOPS: [ 43.177394] WARNING: CPU: 1 PID: 711 at drivers/media/v4l2-core/v4l2-dev.c:945 __video_register_device+0xc99/0x1090 [videodev] [ 43.177396] Modules linked in: hid_sensor_custom hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer kfifo_buf joydev hid_sensor_iio_common hid_rmi(+) rmi_core industrialio videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_common videodev hid_multitouch media hid_sensor_hub binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi arc4 snd_soc_skl snd_soc_skl_ipc snd_hda_ext_core snd_soc_sst_dsp snd_soc_sst_ipc snd_hda_codec_realtek snd_soc_acpi snd_hda_codec_generic snd_soc_core snd_compress ac97_bus snd_pcm_dmaengine snd_hda_intel snd_hda_codec intel_rapl snd_hda_core x86_pkg_temp_thermal snd_hwdep intel_powerclamp coretemp snd_pcm kvm_intel snd_seq_midi snd_seq_midi_event snd_rawmidi crct10dif_pclmul [ 43.177426] crc32_pclmul ghash_clmulni_intel iwlmvm pcbc mac80211 snd_seq aesni_intel iwlwifi aes_x86_64 snd_seq_device crypto_simd glue_helper cryptd snd_timer intel_cstate intel_rapl_perf input_leds serio_raw intel_wmi_thunderbolt snd wmi_bmof cfg80211 soundcore ideapad_laptop sparse_keymap idma64 virt_dma tpm_crb acpi_pad int3400_thermal acpi_thermal_rel intel_pch_thermal processor_thermal_device mac_hid int340x_thermal_zone mei_me intel_soc_dts_iosf mei intel_lpss_pci shpchp intel_lpss sch_fq_codel vfio_pci nfsd vfio_virqfd parport_pc ppdev auth_rpcgss nfs_acl lockd grace lp parport sunrpc ip_tables x_tables autofs4 hid_logitech_hidpp hid_logitech_dj hid_generic usbhid kvmgt vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass i915 i2c_algo_bit drm_kms_helper syscopyarea sdhci_pci sysfillrect [ 43.177466] sysimgblt cqhci fb_sys_fops sdhci drm i2c_hid wmi hid video pinctrl_sunrisepoint pinctrl_intel [ 43.177474] CPU: 1 PID: 711 Comm: systemd-udevd Not tainted 4.16.0 #1 [ 43.177475] Hardware name: LENOVO 80UE/VIUU4, BIOS 2UCN10T 10/14/2016 [ 43.177481] RIP: 0010:__video_register_device+0xc99/0x1090 [videodev] [ 43.177482] RSP: 0000:ffffa5c5c231b420 EFLAGS: 00010202 [ 43.177484] RAX: 0000000000000000 RBX: 0000000000000005 RCX: 0000000000000000 [ 43.177485] RDX: ffffffffc0c44cc0 RSI: ffffffffffffffff RDI: ffffffffc0c44cc0 [ 43.177486] RBP: ffffa5c5c231b478 R08: ffffffffc0c96900 R09: ffff8eda1a51f018 [ 43.177487] R10: 0000000000000600 R11: 00000000000003b6 R12: 0000000000000000 [ 43.177488] R13: 0000000000000005 R14: ffffffffc0c96900 R15: ffff8eda1d6d91c0 [ 43.177489] FS: 00007fd2d8ef2480(0000) GS:ffff8eda33480000(0000) knlGS:0000000000000000 [ 43.177490] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 43.177491] CR2: 00007ffe0a6ad01c CR3: 0000000456ae2004 CR4: 00000000003606e0 [ 43.177492] Call Trace: [ 43.177498] ? devres_add+0x5f/0x70 [ 43.177502] rmi_f54_probe+0x437/0x470 [rmi_core] [ 43.177505] rmi_function_probe+0x25/0x30 [rmi_core] [ 43.177507] driver_probe_device+0x310/0x480 [ 43.177509] __device_attach_driver+0x86/0x100 [ 43.177511] ? __driver_attach+0xf0/0xf0 [ 43.177512] bus_for_each_drv+0x6b/0xb0 [ 43.177514] __device_attach+0xdd/0x160 [ 43.177516] device_initial_probe+0x13/0x20 [ 43.177518] bus_probe_device+0x95/0xa0 [ 43.177519] device_add+0x44b/0x680 [ 43.177522] rmi_register_function+0x62/0xd0 [rmi_core] [ 43.177525] rmi_create_function+0x112/0x1a0 [rmi_core] [ 43.177527] ? rmi_driver_clear_irq_bits+0xc0/0xc0 [rmi_core] [ 43.177530] rmi_scan_pdt+0xca/0x1a0 [rmi_core] [ 43.177535] rmi_init_functions+0x5b/0x120 [rmi_core] [ 43.177537] rmi_driver_probe+0x152/0x3c0 [rmi_core] [ 43.177547] ? sysfs_create_link+0x25/0x40 [ 43.177549] driver_probe_device+0x310/0x480 [ 43.177551] __device_attach_driver+0x86/0x100 [ 43.177553] ? __driver_attach+0xf0/0xf0 [ 43.177554] bus_for_each_drv+0x6b/0xb0 [ 43.177556] __device_attach+0xdd/0x160 [ 43.177558] device_initial_probe+0x13/0x20 [ 43.177560] bus_probe_device+0x95/0xa0 [ 43.177561] device_add+0x44b/0x680 [ 43.177564] rmi_register_transport_device+0x84/0x100 [rmi_core] [ 43.177568] rmi_input_configured+0xbf/0x1a0 [hid_rmi] [ 43.177571] ? input_allocate_device+0xdf/0xf0 [ 43.177574] hidinput_connect+0x4a9/0x37a0 [hid] [ 43.177578] hid_connect+0x326/0x3d0 [hid] [ 43.177581] hid_hw_start+0x42/0x70 [hid] [ 43.177583] rmi_probe+0x115/0x510 [hid_rmi] [ 43.177586] hid_device_probe+0xd3/0x150 [hid] [ 43.177588] ? sysfs_create_link+0x25/0x40 [ 43.177590] driver_probe_device+0x310/0x480 [ 43.177592] __driver_attach+0xbf/0xf0 [ 43.177593] ? driver_probe_device+0x480/0x480 [ 43.177595] bus_for_each_dev+0x74/0xb0 [ 43.177597] ? kmem_cache_alloc_trace+0x1a6/0x1c0 [ 43.177599] driver_attach+0x1e/0x20 [ 43.177600] bus_add_driver+0x167/0x260 [ 43.177602] ? 0xffffffffc0cbc000 [ 43.177604] driver_register+0x60/0xe0 [ 43.177605] ? 0xffffffffc0cbc000 [ 43.177607] __hid_register_driver+0x63/0x70 [hid] [ 43.177610] rmi_driver_init+0x23/0x1000 [hid_rmi] [ 43.177612] do_one_initcall+0x52/0x191 [ 43.177615] ? _cond_resched+0x19/0x40 [ 43.177617] ? kmem_cache_alloc_trace+0xa2/0x1c0 [ 43.177619] ? do_init_module+0x27/0x209 [ 43.177621] do_init_module+0x5f/0x209 [ 43.177623] load_module+0x1987/0x1f10 [ 43.177626] ? ima_post_read_file+0x96/0xa0 [ 43.177629] SYSC_finit_module+0xfc/0x120 [ 43.177630] ? SYSC_finit_module+0xfc/0x120 [ 43.177632] SyS_finit_module+0xe/0x10 [ 43.177634] do_syscall_64+0x73/0x130 [ 43.177637] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 43.177638] RIP: 0033:0x7fd2d880b839 [ 43.177639] RSP: 002b:00007ffe0a6b2368 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 43.177641] RAX: ffffffffffffffda RBX: 000055cdd86542e0 RCX: 00007fd2d880b839 [ 43.177641] RDX: 0000000000000000 RSI: 00007fd2d84ea0e5 RDI: 0000000000000016 [ 43.177642] RBP: 00007fd2d84ea0e5 R08: 0000000000000000 R09: 00007ffe0a6b2480 [ 43.177643] R10: 0000000000000016 R11: 0000000000000246 R12: 0000000000000000 [ 43.177644] R13: 000055cdd8688930 R14: 0000000000020000 R15: 000055cdd86542e0 [ 43.177645] Code: 48 c7 c7 54 b4 c3 c0 e8 96 9d ec dd e9 d4 fb ff ff 0f 0b 41 be ea ff ff ff e9 c7 fb ff ff 0f 0b 41 be ea ff ff ff e9 ba fb ff ff <0f> 0b e9 d8 f4 ff ff 83 fa 01 0f 84 c4 02 00 00 48 83 78 68 00 [ 43.177675] ---[ end trace d44d9bc41477c2dd ]--- [ 43.177679] BUG: unable to handle kernel NULL pointer dereference at 0000000000000499 [ 43.177723] IP: __video_register_device+0x1cc/0x1090 [videodev] [ 43.177749] PGD 0 P4D 0 [ 43.177764] Oops: 0000 [#1] SMP PTI [ 43.177780] Modules linked in: hid_sensor_custom hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger industrialio_triggered_buffer kfifo_buf joydev hid_sensor_iio_common hid_rmi(+) rmi_core industrialio videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_common videodev hid_multitouch media hid_sensor_hub binfmt_misc nls_iso8859_1 snd_hda_codec_hdmi arc4 snd_soc_skl snd_soc_skl_ipc snd_hda_ext_core snd_soc_sst_dsp snd_soc_sst_ipc snd_hda_codec_realtek snd_soc_acpi snd_hda_codec_generic snd_soc_core snd_compress ac97_bus snd_pcm_dmaengine snd_hda_intel snd_hda_codec intel_rapl snd_hda_core x86_pkg_temp_thermal snd_hwdep intel_powerclamp coretemp snd_pcm kvm_intel snd_seq_midi snd_seq_midi_event snd_rawmidi crct10dif_pclmul [ 43.178055] crc32_pclmul ghash_clmulni_intel iwlmvm pcbc mac80211 snd_seq aesni_intel iwlwifi aes_x86_64 snd_seq_device crypto_simd glue_helper cryptd snd_timer intel_cstate intel_rapl_perf input_leds serio_raw intel_wmi_thunderbolt snd wmi_bmof cfg80211 soundcore ideapad_laptop sparse_keymap idma64 virt_dma tpm_crb acpi_pad int3400_thermal acpi_thermal_rel intel_pch_thermal processor_thermal_device mac_hid int340x_thermal_zone mei_me intel_soc_dts_iosf mei intel_lpss_pci shpchp intel_lpss sch_fq_codel vfio_pci nfsd vfio_virqfd parport_pc ppdev auth_rpcgss nfs_acl lockd grace lp parport sunrpc ip_tables x_tables autofs4 hid_logitech_hidpp hid_logitech_dj hid_generic usbhid kvmgt vfio_mdev mdev vfio_iommu_type1 vfio kvm irqbypass i915 i2c_algo_bit drm_kms_helper syscopyarea sdhci_pci sysfillrect [ 43.178337] sysimgblt cqhci fb_sys_fops sdhci drm i2c_hid wmi hid video pinctrl_sunrisepoint pinctrl_intel [ 43.178380] CPU: 1 PID: 711 Comm: systemd-udevd Tainted: G W 4.16.0 #1 [ 43.178411] Hardware name: LENOVO 80UE/VIUU4, BIOS 2UCN10T 10/14/2016 [ 43.178441] RIP: 0010:__video_register_device+0x1cc/0x1090 [videodev] [ 43.178467] RSP: 0000:ffffa5c5c231b420 EFLAGS: 00010202 [ 43.178490] RAX: ffffffffc0c44cc0 RBX: 0000000000000005 RCX: ffffffffc0c454c0 [ 43.178519] RDX: 0000000000000001 RSI: ffff8eda1d6d9118 RDI: ffffffffc0c44cc0 [ 43.178549] RBP: ffffa5c5c231b478 R08: ffffffffc0c96900 R09: ffff8eda1a51f018 [ 43.178579] R10: 0000000000000600 R11: 00000000000003b6 R12: 0000000000000000 [ 43.178608] R13: 0000000000000005 R14: ffffffffc0c96900 R15: ffff8eda1d6d91c0 [ 43.178636] FS: 00007fd2d8ef2480(0000) GS:ffff8eda33480000(0000) knlGS:0000000000000000 [ 43.178669] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 43.178693] CR2: 0000000000000499 CR3: 0000000456ae2004 CR4: 00000000003606e0 [ 43.178721] Call Trace: [ 43.178736] ? devres_add+0x5f/0x70 [ 43.178755] rmi_f54_probe+0x437/0x470 [rmi_core] [ 43.178779] rmi_function_probe+0x25/0x30 [rmi_core] [ 43.178805] driver_probe_device+0x310/0x480 [ 43.178828] __device_attach_driver+0x86/0x100 [ 43.178851] ? __driver_attach+0xf0/0xf0 [ 43.178884] bus_for_each_drv+0x6b/0xb0 [ 43.178904] __device_attach+0xdd/0x160 [ 43.178925] device_initial_probe+0x13/0x20 [ 43.178948] bus_probe_device+0x95/0xa0 [ 43.178968] device_add+0x44b/0x680 [ 43.178987] rmi_register_function+0x62/0xd0 [rmi_core] [ 43.181747] rmi_create_function+0x112/0x1a0 [rmi_core] [ 43.184677] ? rmi_driver_clear_irq_bits+0xc0/0xc0 [rmi_core] [ 43.187505] rmi_scan_pdt+0xca/0x1a0 [rmi_core] [ 43.190171] rmi_init_functions+0x5b/0x120 [rmi_core] [ 43.192809] rmi_driver_probe+0x152/0x3c0 [rmi_core] [ 43.195403] ? sysfs_create_link+0x25/0x40 [ 43.198253] driver_probe_device+0x310/0x480 [ 43.201083] __device_attach_driver+0x86/0x100 [ 43.203800] ? __driver_attach+0xf0/0xf0 [ 43.206503] bus_for_each_drv+0x6b/0xb0 [ 43.209291] __device_attach+0xdd/0x160 [ 43.212207] device_initial_probe+0x13/0x20 [ 43.215146] bus_probe_device+0x95/0xa0 [ 43.217885] device_add+0x44b/0x680 [ 43.220597] rmi_register_transport_device+0x84/0x100 [rmi_core] [ 43.223321] rmi_input_configured+0xbf/0x1a0 [hid_rmi] [ 43.226051] ? input_allocate_device+0xdf/0xf0 [ 43.228814] hidinput_connect+0x4a9/0x37a0 [hid] [ 43.231701] hid_connect+0x326/0x3d0 [hid] [ 43.234548] hid_hw_start+0x42/0x70 [hid] [ 43.237302] rmi_probe+0x115/0x510 [hid_rmi] [ 43.239862] hid_device_probe+0xd3/0x150 [hid] [ 43.242558] ? sysfs_create_link+0x25/0x40 [ 43.242828] audit: type=1400 audit(1522795151.600:4): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/4206/usr/lib/snapd/snap-confine" pid=1151 comm="apparmor_parser" [ 43.244859] driver_probe_device+0x310/0x480 [ 43.244862] __driver_attach+0xbf/0xf0 [ 43.246982] audit: type=1400 audit(1522795151.600:5): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/4206/usr/lib/snapd/snap-confine//mount-namespace-capture-helper" pid=1151 comm="apparmor_parser" [ 43.249403] ? driver_probe_device+0x480/0x480 [ 43.249405] bus_for_each_dev+0x74/0xb0 [ 43.253200] audit: type=1400 audit(1522795151.600:6): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/snap/core/4206/usr/lib/snapd/snap-confine//snap_update_ns" pid=1151 comm="apparmor_parser" [ 43.254055] ? kmem_cache_alloc_trace+0x1a6/0x1c0 [ 43.256282] audit: type=1400 audit(1522795151.604:7): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/sbin/dhclient" pid=1152 comm="apparmor_parser" [ 43.258436] driver_attach+0x1e/0x20 [ 43.260875] audit: type=1400 audit(1522795151.604:8): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/NetworkManager/nm-dhcp-client.action" pid=1152 comm="apparmor_parser" [ 43.263118] bus_add_driver+0x167/0x260 [ 43.267676] audit: type=1400 audit(1522795151.604:9): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/NetworkManager/nm-dhcp-helper" pid=1152 comm="apparmor_parser" [ 43.268807] ? 0xffffffffc0cbc000 [ 43.268812] driver_register+0x60/0xe0 [ 43.271184] audit: type=1400 audit(1522795151.604:10): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/lib/connman/scripts/dhclient-script" pid=1152 comm="apparmor_parser" [ 43.274081] ? 0xffffffffc0cbc000 [ 43.274086] __hid_register_driver+0x63/0x70 [hid] [ 43.288367] rmi_driver_init+0x23/0x1000 [hid_rmi] [ 43.291501] do_one_initcall+0x52/0x191 [ 43.292348] audit: type=1400 audit(1522795151.652:11): apparmor="STATUS" operation="profile_load" profile="unconfined" name="/usr/bin/man" pid=1242 comm="apparmor_parser" [ 43.294212] ? _cond_resched+0x19/0x40 [ 43.300028] ? kmem_cache_alloc_trace+0xa2/0x1c0 [ 43.303475] ? do_init_module+0x27/0x209 [ 43.306842] do_init_module+0x5f/0x209 [ 43.310269] load_module+0x1987/0x1f10 [ 43.313704] ? ima_post_read_file+0x96/0xa0 [ 43.317174] SYSC_finit_module+0xfc/0x120 [ 43.320754] ? SYSC_finit_module+0xfc/0x120 [ 43.324065] SyS_finit_module+0xe/0x10 [ 43.327387] do_syscall_64+0x73/0x130 [ 43.330909] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 43.334305] RIP: 0033:0x7fd2d880b839 [ 43.337810] RSP: 002b:00007ffe0a6b2368 EFLAGS: 00000246 ORIG_RAX: 0000000000000139 [ 43.341259] RAX: ffffffffffffffda RBX: 000055cdd86542e0 RCX: 00007fd2d880b839 [ 43.344613] RDX: 0000000000000000 RSI: 00007fd2d84ea0e5 RDI: 0000000000000016 [ 43.347962] RBP: 00007fd2d84ea0e5 R08: 0000000000000000 R09: 00007ffe0a6b2480 [ 43.351456] R10: 0000000000000016 R11: 0000000000000246 R12: 0000000000000000 [ 43.354845] R13: 000055cdd8688930 R14: 0000000000020000 R15: 000055cdd86542e0 [ 43.358224] Code: c7 05 ad 12 02 00 00 00 00 00 48 8d 88 00 08 00 00 eb 09 48 83 c0 08 48 39 c1 74 31 48 8b 10 48 85 d2 74 ef 49 8b b7 98 04 00 00 <48> 39 b2 98 04 00 00 75 df 48 63 92 f8 04 00 00 f0 48 0f ab 15 [ 43.361764] RIP: __video_register_device+0x1cc/0x1090 [videodev] RSP: ffffa5c5c231b420 [ 43.365281] CR2: 0000000000000499 This patch fixes the array size and changes the WARN_ON() to return an error, instead of letting the Kernel to proceed with registering. Cc: stable@vger.kernel.org # For Kernel 4.16 Fixes: 4839c58f034a ("media: v4l2-dev: convert VFL_TYPE_* into an enum") Reported-by: Peter Geis <pgwipeout@gmail.com> Reported-by: Jaak Ristioja <jaak@ristioja.ee> Reported-by: Michał Siemek <mihau69@gmail.com> Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com> Reviewed-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2018-04-05 17:51:15 +08:00
return -ENFILE;
}
devnode_set(vdev);
vdev->index = get_index(vdev);
video_devices[vdev->minor] = vdev;
mutex_unlock(&videodev_lock);
if (vdev->ioctl_ops)
determine_valid_ioctls(vdev);
/* Part 3: Initialize the character device */
vdev->cdev = cdev_alloc();
if (vdev->cdev == NULL) {
ret = -ENOMEM;
goto cleanup;
}
vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
if (ret < 0) {
pr_err("%s: cdev_add failed\n", __func__);
kfree(vdev->cdev);
vdev->cdev = NULL;
goto cleanup;
}
/* Part 4: register the device with sysfs */
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
vdev->dev.parent = vdev->dev_parent;
dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
ret = device_register(&vdev->dev);
if (ret < 0) {
pr_err("%s: device_register failed\n", __func__);
goto cleanup;
}
/* Register the release callback that will be called when the last
reference to the device goes away. */
vdev->dev.release = v4l2_device_release;
if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
pr_warn("%s: requested %s%d, got %s\n", __func__,
name_base, nr, video_device_node_name(vdev));
/* Increase v4l2_device refcount */
v4l2_device_get(vdev->v4l2_dev);
/* Part 5: Register the entity. */
ret = video_register_media_controller(vdev);
/* Part 6: Activate this minor. The char device can now be used. */
set_bit(V4L2_FL_REGISTERED, &vdev->flags);
return 0;
cleanup:
mutex_lock(&videodev_lock);
if (vdev->cdev)
cdev_del(vdev->cdev);
video_devices[vdev->minor] = NULL;
devnode_clear(vdev);
mutex_unlock(&videodev_lock);
/* Mark this video device as never having been registered. */
vdev->minor = -1;
return ret;
}
EXPORT_SYMBOL(__video_register_device);
/**
* video_unregister_device - unregister a video4linux device
* @vdev: the device to unregister
*
* This unregisters the passed device. Future open calls will
* be met with errors.
*/
void video_unregister_device(struct video_device *vdev)
{
/* Check if vdev was ever registered at all */
if (!vdev || !video_is_registered(vdev))
return;
mutex_lock(&videodev_lock);
/* This must be in a critical section to prevent a race with v4l2_open.
* Once this bit has been cleared video_get may never be called again.
*/
clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
mutex_unlock(&videodev_lock);
device_unregister(&vdev->dev);
}
EXPORT_SYMBOL(video_unregister_device);
/*
* Initialise video for linux
*/
static int __init videodev_init(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0);
int ret;
pr_info("Linux video capture interface: v2.00\n");
ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
if (ret < 0) {
pr_warn("videodev: unable to get major %d\n",
VIDEO_MAJOR);
return ret;
}
ret = class_register(&video_class);
if (ret < 0) {
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
pr_warn("video_dev: class_register failed\n");
return -EIO;
}
return 0;
}
static void __exit videodev_exit(void)
{
dev_t dev = MKDEV(VIDEO_MAJOR, 0);
class_unregister(&video_class);
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
}
[media] V4L/v4l2-dev: Make 'videodev_init' as a subsys initcall As the V4L2 based UVC webcam gadget (g_webcam) expects the 'videodev' to present when the 'webcam_bind' routine is called, so 'videodev' should be available as early as possible. Now, when 'g_webcam' is built as a module (i.e. not a part of kernel) the late availability of 'videodev' is OK, but if 'g_webcam' is built statically as a part of the kernel, the kernel crashes (a sample crash dump using Designware 2.0 UDC is provided below). To solve the same, this patch makes 'videodev_init' as a subsys initcall. Kernel Crash Dump: ------------------ designware_udc designware_udc: Device Synopsys UDC probed csr 90810000: plug 90812000 g_webcam gadget: uvc_function_bind Unable to handle kernel NULL pointer dereference at virtual address 000000e4 pgd = 80004000 [000000e4] *pgd=00000000 Internal error: Oops: 5 [#1] SMP Modules linked in: CPU: 0 Not tainted (3.3.0-rc3-13888-ge774c03-dirty #20) PC is at do_raw_spin_lock+0x10/0x16c LR is at _raw_spin_lock+0x10/0x14 pc : [<8019e344>] lr : [<804095c0>] psr: 60000013 sp : 8f839d20 ip : 8f839d50 fp : 8f839d4c r10: 80760a94 r9 : 8042de98 r8 : 00000154 r7 : 80760e94 r6 : 805cfc10 r5 : 8fb6a008 r4 : 8fb6a008 r3 : 805dd0c8 r2 : 8f839d48 r1 : 805cfc08 r0 : 000000e0 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 10c5387d Table: 0000404a DAC: 00000015 Process swapper/0 (pid: 1, stack limit = 0x8f8382f0) Stack: (0x8f839d20 to 0x8f83a000) 9d20: ffffffff ffffffff 8fb6a008 8fb6a008 805cfc10 80760e94 00000154 8042de98 9d40: 8f839d5c 8f839d50 804095c0 8019e340 8f839d7c 8f839d60 80222b28 804095bc 9d60: 8fb12b80 8fb6a008 8fb6a010 805cfc08 8f839dc4 8f839d80 80223db8 80222adc 9d80: 8f839dac 8f839d90 8022baa0 8019e2e8 8fb6a008 8075e7f4 8fb6a008 8fb6a008 9da0: 00000000 8fb6a008 80760e94 00000154 8042de98 80760a94 8f839ddc 8f839dc8 9dc0: 802242a8 80223d1c 8fb12b80 8fb6a000 8f839e1c 8f839de0 8030132c 80224298 9de0: 80223ce8 803f2ee8 00000001 804f7750 8f839e1c 8f824008 805cff20 8f824000 9e00: 8fb6a000 ffffffff 00000000 8f8d4880 8f839e4c 8f839e20 80562e3c 80301100 9e20: 00000000 8fb13140 8f824008 805cff20 8042aa68 8f824000 8042aa8c 805e4d40 9e40: 8f839e64 8f839e50 802d20c4 80562ba8 805d0058 805cff20 8f839e8c 8f839e68 9e60: 80563034 802d206c 8042aa8c 805cff20 8f8d4880 00000000 805cfc08 8fb12a40 9e80: 8f839e9c 8f839e90 805630c4 80562ec4 8f839ebc 8f839ea0 802d2364 805630b0 9ea0: 805cfeac 8f8d4880 805cfbe8 807605e8 8f839ed4 8f839ec0 80562b3c 802d22cc 9ec0: 80562ac4 8f8d4880 8f839f04 8f839ed8 802d0b40 80562ad0 8f839ef4 805cff90 9ee0: 805cff90 805cfb98 00000000 00000000 805cfbe8 805e4d40 8f839f3c 8f839f08 9f00: 802cd078 802d0a18 00000000 802d0a0c 00000000 8fb9ba00 802d0a0c 805cff90 9f20: 00000013 00000000 00000000 805e4d40 8f839f5c 8f839f40 802cf390 802ccff0 9f40: 00000003 00000003 804fb598 00000000 8f839f74 8f839f60 802d2554 802cf2a0 9f60: 8f838000 8057731c 8f839f84 8f839f78 80562b90 802d24d0 8f839fdc 8f839f88 9f80: 800085d4 80562b84 805af2ac 805af2ac 80562b78 00000000 00000013 00000000 9fa0: 00000000 00000000 8f839fc4 8f839fb8 80043dd0 8057706c 8057731c 8002875c 9fc0: 00000013 00000000 00000000 00000000 8f839ff4 8f839fe0 805468d4 800085a0 9fe0: 00000000 80546840 00000000 8f839ff8 8002875c 8054684c 51155555 55545555 Backtrace: [<8019e334>] (do_raw_spin_lock+0x0/0x16c) from [<804095c0>] (_raw_spin_lock+0x10/0x14) r9:8042de98 r8:00000154 r7:80760e94 r6:805cfc10 r5:8fb6a008 r4:8fb6a008 [<804095b0>] (_raw_spin_lock+0x0/0x14) from [<80222b28>] (get_device_parent+0x58/0x1c0) [<80222ad0>] (get_device_parent+0x0/0x1c0) from [<80223db8>] (device_add+0xa8/0x57c) r6:805cfc08 r5:8fb6a010 r4:8fb6a008 r3:8fb12b80 [<80223d10>] (device_add+0x0/0x57c) from [<802242a8>] (device_register+0x1c/0x20) [<8022428c>] (device_register+0x0/0x20) from [<8030132c>] (__video_register_device+0x238/0x484) r4:8fb6a000 r3:8fb12b80 [<803010f4>] (__video_register_device+0x0/0x484) from [<80562e3c>] (uvc_function_bind+0x2a0/0x31c) [<80562b9c>] (uvc_function_bind+0x0/0x31c) from [<802d20c4>] (usb_add_function+0x64/0x118) [<802d2060>] (usb_add_function+0x0/0x118) from [<80563034>] (uvc_bind_config+0x17c/0x1ec) r5:805cff20 r4:805d0058 [<80562eb8>] (uvc_bind_config+0x0/0x1ec) from [<805630c4>] (webcam_config_bind+0x20/0x28) r8:8fb12a40 r7:805cfc08 r6:00000000 r5:8f8d4880 r4:805cff20 r3:8042aa8c [<805630a4>] (webcam_config_bind+0x0/0x28) from [<802d2364>] (usb_add_config+0xa4/0x124) [<802d22c0>] (usb_add_config+0x0/0x124) from [<80562b3c>] (webcam_bind+0x78/0xb4) r6:807605e8 r5:805cfbe8 r4:8f8d4880 r3:805cfeac [<80562ac4>] (webcam_bind+0x0/0xb4) from [<802d0b40>] (composite_bind+0x134/0x308) r4:8f8d4880 r3:80562ac4 [<802d0a0c>] (composite_bind+0x0/0x308) from [<802cd078>] (dw_udc_start+0x94/0x2bc) [<802ccfe4>] (dw_udc_start+0x0/0x2bc) from [<802cf390>] (usb_gadget_probe_driver+0xfc/0x180) [<802cf294>] (usb_gadget_probe_driver+0x0/0x180) from [<802d2554>] (usb_composite_probe+0x90/0xb4) r6:00000000 r5:804fb598 r4:00000003 r3:00000003 [<802d24c4>] (usb_composite_probe+0x0/0xb4) from [<80562b90>] (webcam_init+0x18/0x24) r5:8057731c r4:8f838000 [<80562b78>] (webcam_init+0x0/0x24) from [<800085d4>] (do_one_initcall+0x40/0x184) [<80008594>] (do_one_initcall+0x0/0x184) from [<805468d4>] (kernel_init+0x94/0x134) [<80546840>] (kernel_init+0x0/0x134) from [<8002875c>] (do_exit+0x0/0x6f8) r5:80546840 r4:00000000 Code: e1a0c00d e92ddbf0 e24cb004 e24dd008 (e5902004) ---[ end trace 7ecca37f36fbdc06 ]--- Signed-off-by: Bhupesh Sharma <bhupesh.sharma@st.com> Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2012-03-12 16:09:02 +08:00
subsys_initcall(videodev_init);
module_exit(videodev_exit)
MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@kernel.org>, Bill Dirks, Justin Schoeman, Gerd Knorr");
MODULE_DESCRIPTION("Video4Linux2 core driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);