5126f2590b
This used to be the default if the lock pointer was set, but now that lock is by default only used for ioctl serialization. Those drivers that already used core locking have this flag set explicitly, except for some drivers where it was obvious that there was no need to serialize any file operations other than ioctl. The drivers that didn't need this flag were: drivers/media/radio/dsbr100.c drivers/media/radio/radio-isa.c drivers/media/radio/radio-keene.c drivers/media/radio/radio-miropcm20.c drivers/media/radio/radio-mr800.c drivers/media/radio/radio-tea5764.c drivers/media/radio/radio-timb.c drivers/media/video/vivi.c sound/i2c/other/tea575x-tuner.c The other drivers that use core locking and where it was not immediately obvious that this flag wasn't needed were changed so that the flag is set together with a comment that that driver needs work to avoid having to set that flag. This will often involve taking the core lock in the fops themselves. Eventually this flag should go and it should not be used in new drivers. There are a few reasons why we want to avoid core locking of non-ioctl fops: in the case of mmap this can lead to a deadlock in rare situations since when mmap is called the mmap_sem is held and it is possible for other parts of the code to take that lock as well (copy_from_user()/copy_to_user() perform a down_read(&mm->mmap_sem) when a page fault occurs). It is very unlikely that that happens since the core lock serializes all fops, but the kernel warns about it if lock validation is turned on. For poll it is also undesirable to take the core lock as that can introduce increased latency. The same is true for read/write. While it was possible to make flags or something to turn on/off taking the core lock for each file operation, in practice it is much simpler to just not take it at all except for ioctl and leave it to the driver to take the lock. There are only a handful fops compared to the zillion ioctls we have. I also wanted to make it obvious which drivers still take the lock for all fops, so that's why I chose to have drivers set it explicitly. Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Acked-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
231 lines
7.2 KiB
C
231 lines
7.2 KiB
C
/*
|
|
*
|
|
* V 4 L 2 D R I V E R H E L P E R A P I
|
|
*
|
|
* Moved from videodev2.h
|
|
*
|
|
* Some commonly needed functions for drivers (v4l2-common.o module)
|
|
*/
|
|
#ifndef _V4L2_DEV_H
|
|
#define _V4L2_DEV_H
|
|
|
|
#include <linux/poll.h>
|
|
#include <linux/fs.h>
|
|
#include <linux/device.h>
|
|
#include <linux/cdev.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/videodev2.h>
|
|
|
|
#include <media/media-entity.h>
|
|
|
|
#define VIDEO_MAJOR 81
|
|
|
|
#define VFL_TYPE_GRABBER 0
|
|
#define VFL_TYPE_VBI 1
|
|
#define VFL_TYPE_RADIO 2
|
|
#define VFL_TYPE_SUBDEV 3
|
|
#define VFL_TYPE_MAX 4
|
|
|
|
struct v4l2_ioctl_callbacks;
|
|
struct video_device;
|
|
struct v4l2_device;
|
|
struct v4l2_ctrl_handler;
|
|
|
|
/* Flag to mark the video_device struct as registered.
|
|
Drivers can clear this flag if they want to block all future
|
|
device access. It is cleared by video_unregister_device. */
|
|
#define V4L2_FL_REGISTERED (0)
|
|
/* file->private_data points to struct v4l2_fh */
|
|
#define V4L2_FL_USES_V4L2_FH (1)
|
|
/* Use the prio field of v4l2_fh for core priority checking */
|
|
#define V4L2_FL_USE_FH_PRIO (2)
|
|
/* If ioctl core locking is in use, then apply that also to all
|
|
file operations. */
|
|
#define V4L2_FL_LOCK_ALL_FOPS (3)
|
|
|
|
/* Priority helper functions */
|
|
|
|
struct v4l2_prio_state {
|
|
atomic_t prios[4];
|
|
};
|
|
|
|
void v4l2_prio_init(struct v4l2_prio_state *global);
|
|
int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
|
|
enum v4l2_priority new);
|
|
void v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
|
|
void v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority local);
|
|
enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
|
|
int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local);
|
|
|
|
|
|
struct v4l2_file_operations {
|
|
struct module *owner;
|
|
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
|
|
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
|
|
unsigned int (*poll) (struct file *, struct poll_table_struct *);
|
|
long (*ioctl) (struct file *, unsigned int, unsigned long);
|
|
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
|
|
#ifdef CONFIG_COMPAT
|
|
long (*compat_ioctl32) (struct file *, unsigned int, unsigned long);
|
|
#endif
|
|
unsigned long (*get_unmapped_area) (struct file *, unsigned long,
|
|
unsigned long, unsigned long, unsigned long);
|
|
int (*mmap) (struct file *, struct vm_area_struct *);
|
|
int (*open) (struct file *);
|
|
int (*release) (struct file *);
|
|
};
|
|
|
|
/*
|
|
* Newer version of video_device, handled by videodev2.c
|
|
* This version moves redundant code from video device code to
|
|
* the common handler
|
|
*/
|
|
|
|
struct video_device
|
|
{
|
|
#if defined(CONFIG_MEDIA_CONTROLLER)
|
|
struct media_entity entity;
|
|
#endif
|
|
/* device ops */
|
|
const struct v4l2_file_operations *fops;
|
|
|
|
/* sysfs */
|
|
struct device dev; /* v4l device */
|
|
struct cdev *cdev; /* character device */
|
|
|
|
/* Set either parent or v4l2_dev if your driver uses v4l2_device */
|
|
struct device *parent; /* device parent */
|
|
struct v4l2_device *v4l2_dev; /* v4l2_device parent */
|
|
|
|
/* Control handler associated with this device node. May be NULL. */
|
|
struct v4l2_ctrl_handler *ctrl_handler;
|
|
|
|
/* Priority state. If NULL, then v4l2_dev->prio will be used. */
|
|
struct v4l2_prio_state *prio;
|
|
|
|
/* device info */
|
|
char name[32];
|
|
int vfl_type;
|
|
/* 'minor' is set to -1 if the registration failed */
|
|
int minor;
|
|
u16 num;
|
|
/* use bitops to set/clear/test flags */
|
|
unsigned long flags;
|
|
/* attribute to differentiate multiple indices on one physical device */
|
|
int index;
|
|
|
|
/* V4L2 file handles */
|
|
spinlock_t fh_lock; /* Lock for all v4l2_fhs */
|
|
struct list_head fh_list; /* List of struct v4l2_fh */
|
|
|
|
int debug; /* Activates debug level*/
|
|
|
|
/* Video standard vars */
|
|
v4l2_std_id tvnorms; /* Supported tv norms */
|
|
v4l2_std_id current_norm; /* Current tvnorm */
|
|
|
|
/* callbacks */
|
|
void (*release)(struct video_device *vdev);
|
|
|
|
/* ioctl callbacks */
|
|
const struct v4l2_ioctl_ops *ioctl_ops;
|
|
DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);
|
|
|
|
/* serialization lock */
|
|
DECLARE_BITMAP(dont_use_lock, BASE_VIDIOC_PRIVATE);
|
|
struct mutex *lock;
|
|
};
|
|
|
|
#define media_entity_to_video_device(__e) \
|
|
container_of(__e, struct video_device, entity)
|
|
/* dev to video-device */
|
|
#define to_video_device(cd) container_of(cd, struct video_device, dev)
|
|
|
|
int __must_check __video_register_device(struct video_device *vdev, int type,
|
|
int nr, int warn_if_nr_in_use, struct module *owner);
|
|
|
|
/* Register video devices. Note that if video_register_device fails,
|
|
the release() callback of the video_device structure is *not* called, so
|
|
the caller is responsible for freeing any data. Usually that means that
|
|
you call video_device_release() on failure. */
|
|
static inline int __must_check video_register_device(struct video_device *vdev,
|
|
int type, int nr)
|
|
{
|
|
return __video_register_device(vdev, type, nr, 1, vdev->fops->owner);
|
|
}
|
|
|
|
/* Same as video_register_device, but no warning is issued if the desired
|
|
device node number was already in use. */
|
|
static inline int __must_check video_register_device_no_warn(
|
|
struct video_device *vdev, int type, int nr)
|
|
{
|
|
return __video_register_device(vdev, type, nr, 0, vdev->fops->owner);
|
|
}
|
|
|
|
/* Unregister video devices. Will do nothing if vdev == NULL or
|
|
video_is_registered() returns false. */
|
|
void video_unregister_device(struct video_device *vdev);
|
|
|
|
/* helper functions to alloc/release struct video_device, the
|
|
latter can also be used for video_device->release(). */
|
|
struct video_device * __must_check video_device_alloc(void);
|
|
|
|
/* this release function frees the vdev pointer */
|
|
void video_device_release(struct video_device *vdev);
|
|
|
|
/* this release function does nothing, use when the video_device is a
|
|
static global struct. Note that having a static video_device is
|
|
a dubious construction at best. */
|
|
void video_device_release_empty(struct video_device *vdev);
|
|
|
|
/* returns true if cmd is a known V4L2 ioctl */
|
|
bool v4l2_is_known_ioctl(unsigned int cmd);
|
|
|
|
/* mark that this command shouldn't use core locking */
|
|
static inline void v4l2_dont_use_lock(struct video_device *vdev, unsigned int cmd)
|
|
{
|
|
if (_IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
|
|
set_bit(_IOC_NR(cmd), vdev->dont_use_lock);
|
|
}
|
|
|
|
/* Mark that this command isn't implemented, must be called before
|
|
video_device_register. See also the comments in determine_valid_ioctls().
|
|
This function allows drivers to provide just one v4l2_ioctl_ops struct, but
|
|
disable ioctls based on the specific card that is actually found. */
|
|
static inline void v4l2_dont_use_cmd(struct video_device *vdev, unsigned int cmd)
|
|
{
|
|
if (_IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
|
|
set_bit(_IOC_NR(cmd), vdev->valid_ioctls);
|
|
}
|
|
|
|
/* helper functions to access driver private data. */
|
|
static inline void *video_get_drvdata(struct video_device *vdev)
|
|
{
|
|
return dev_get_drvdata(&vdev->dev);
|
|
}
|
|
|
|
static inline void video_set_drvdata(struct video_device *vdev, void *data)
|
|
{
|
|
dev_set_drvdata(&vdev->dev, data);
|
|
}
|
|
|
|
struct video_device *video_devdata(struct file *file);
|
|
|
|
/* Combine video_get_drvdata and video_devdata as this is
|
|
used very often. */
|
|
static inline void *video_drvdata(struct file *file)
|
|
{
|
|
return video_get_drvdata(video_devdata(file));
|
|
}
|
|
|
|
static inline const char *video_device_node_name(struct video_device *vdev)
|
|
{
|
|
return dev_name(&vdev->dev);
|
|
}
|
|
|
|
static inline int video_is_registered(struct video_device *vdev)
|
|
{
|
|
return test_bit(V4L2_FL_REGISTERED, &vdev->flags);
|
|
}
|
|
|
|
#endif /* _V4L2_DEV_H */
|