diff options
Diffstat (limited to 'drivers/media/pci/saa7134/saa7134-empress.c')
-rw-r--r-- | drivers/media/pci/saa7134/saa7134-empress.c | 359 |
1 files changed, 90 insertions, 269 deletions
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c index 3022eb2a7925..0a9047e754b9 100644 --- a/drivers/media/pci/saa7134/saa7134-empress.c +++ b/drivers/media/pci/saa7134/saa7134-empress.c @@ -23,12 +23,12 @@ #include <linux/kernel.h> #include <linux/delay.h> +#include <media/v4l2-common.h> +#include <media/v4l2-event.h> + #include "saa7134-reg.h" #include "saa7134.h" -#include <media/saa6752hs.h> -#include <media/v4l2-common.h> - /* ------------------------------------------------------------------ */ MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); @@ -85,52 +85,54 @@ static int ts_open(struct file *file) { struct video_device *vdev = video_devdata(file); struct saa7134_dev *dev = video_drvdata(file); - int err; + struct saa7134_fh *fh; - dprintk("open dev=%s\n", video_device_node_name(vdev)); - err = -EBUSY; - if (!mutex_trylock(&dev->empress_tsq.vb_lock)) - return err; - if (atomic_read(&dev->empress_users)) - goto done; + /* allocate + initialize per filehandle data */ + fh = kzalloc(sizeof(*fh), GFP_KERNEL); + if (NULL == fh) + return -ENOMEM; + + v4l2_fh_init(&fh->fh, vdev); + file->private_data = fh; + fh->is_empress = true; + v4l2_fh_add(&fh->fh); /* Unmute audio */ saa_writeb(SAA7134_AUDIO_MUTE_CTRL, saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); - atomic_inc(&dev->empress_users); - file->private_data = dev; - err = 0; - -done: - mutex_unlock(&dev->empress_tsq.vb_lock); - return err; + return 0; } static int ts_release(struct file *file) { - struct saa7134_dev *dev = file->private_data; + struct saa7134_dev *dev = video_drvdata(file); + struct saa7134_fh *fh = file->private_data; - videobuf_stop(&dev->empress_tsq); - videobuf_mmap_free(&dev->empress_tsq); + if (res_check(fh, RESOURCE_EMPRESS)) { + videobuf_stop(&dev->empress_tsq); + videobuf_mmap_free(&dev->empress_tsq); - /* stop the encoder */ - ts_reset_encoder(dev); + /* stop the encoder */ + ts_reset_encoder(dev); - /* Mute audio */ - saa_writeb(SAA7134_AUDIO_MUTE_CTRL, - saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); - - atomic_dec(&dev->empress_users); + /* Mute audio */ + saa_writeb(SAA7134_AUDIO_MUTE_CTRL, + saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); + } + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); return 0; } static ssize_t ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct saa7134_dev *dev = file->private_data; + struct saa7134_dev *dev = video_drvdata(file); + if (res_locked(dev, RESOURCE_EMPRESS)) + return -EBUSY; if (!dev->empress_started) ts_init_encoder(dev); @@ -142,68 +144,27 @@ ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) static unsigned int ts_poll(struct file *file, struct poll_table_struct *wait) { - struct saa7134_dev *dev = file->private_data; + unsigned long req_events = poll_requested_events(wait); + struct saa7134_dev *dev = video_drvdata(file); + struct saa7134_fh *fh = file->private_data; + unsigned int rc = 0; - return videobuf_poll_stream(file, &dev->empress_tsq, wait); + if (v4l2_event_pending(&fh->fh)) + rc = POLLPRI; + else if (req_events & POLLPRI) + poll_wait(file, &fh->fh.wait, wait); + return rc | videobuf_poll_stream(file, &dev->empress_tsq, wait); } static int ts_mmap(struct file *file, struct vm_area_struct * vma) { - struct saa7134_dev *dev = file->private_data; + struct saa7134_dev *dev = video_drvdata(file); return videobuf_mmap_mapper(&dev->empress_tsq, vma); } -/* - * This function is _not_ called directly, but from - * video_generic_ioctl (and maybe others). userspace - * copying is done already, arg is a kernel pointer. - */ - -static int empress_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct saa7134_dev *dev = file->private_data; - - strcpy(cap->driver, "saa7134"); - strlcpy(cap->card, saa7134_boards[dev->board].name, - sizeof(cap->card)); - sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - return 0; -} - -static int empress_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - - i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name, "CCIR656"); - - return 0; -} - -static int empress_g_input(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -static int empress_s_input(struct file *file, void *priv, unsigned int i) -{ - if (i != 0) - return -EINVAL; - - return 0; -} - static int empress_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { @@ -219,7 +180,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void *priv, static int empress_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct saa7134_dev *dev = file->private_data; + struct saa7134_dev *dev = video_drvdata(file); struct v4l2_mbus_framefmt mbus_fmt; saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt); @@ -236,7 +197,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv, static int empress_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct saa7134_dev *dev = file->private_data; + struct saa7134_dev *dev = video_drvdata(file); struct v4l2_mbus_framefmt mbus_fmt; v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); @@ -254,7 +215,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv, static int empress_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct saa7134_dev *dev = file->private_data; + struct saa7134_dev *dev = video_drvdata(file); struct v4l2_mbus_framefmt mbus_fmt; v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); @@ -269,175 +230,6 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int empress_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_reqbufs(&dev->empress_tsq, p); -} - -static int empress_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_querybuf(&dev->empress_tsq, b); -} - -static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_qbuf(&dev->empress_tsq, b); -} - -static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_dqbuf(&dev->empress_tsq, b, - file->f_flags & O_NONBLOCK); -} - -static int empress_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_streamon(&dev->empress_tsq); -} - -static int empress_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct saa7134_dev *dev = file->private_data; - - return videobuf_streamoff(&dev->empress_tsq); -} - -static int empress_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7134_dev *dev = file->private_data; - int err; - - /* count == 0 is abused in saa6752hs.c, so that special - case is handled here explicitly. */ - if (ctrls->count == 0) - return 0; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - err = saa_call_empress(dev, core, s_ext_ctrls, ctrls); - ts_init_encoder(dev); - - return err; -} - -static int empress_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *ctrls) -{ - struct saa7134_dev *dev = file->private_data; - - if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return saa_call_empress(dev, core, g_ext_ctrls, ctrls); -} - -static int empress_g_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct saa7134_dev *dev = file->private_data; - - return saa7134_g_ctrl_internal(dev, NULL, c); -} - -static int empress_s_ctrl(struct file *file, void *priv, - struct v4l2_control *c) -{ - struct saa7134_dev *dev = file->private_data; - - return saa7134_s_ctrl_internal(dev, NULL, c); -} - -static int empress_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - /* Must be sorted from low to high control ID! */ - static const u32 user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_HFLIP, - 0 - }; - - /* Must be sorted from low to high control ID! */ - static const u32 mpeg_ctrls[] = { - V4L2_CID_MPEG_CLASS, - V4L2_CID_MPEG_STREAM_TYPE, - V4L2_CID_MPEG_STREAM_PID_PMT, - V4L2_CID_MPEG_STREAM_PID_AUDIO, - V4L2_CID_MPEG_STREAM_PID_VIDEO, - V4L2_CID_MPEG_STREAM_PID_PCR, - V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ, - V4L2_CID_MPEG_AUDIO_ENCODING, - V4L2_CID_MPEG_AUDIO_L2_BITRATE, - V4L2_CID_MPEG_VIDEO_ENCODING, - V4L2_CID_MPEG_VIDEO_ASPECT, - V4L2_CID_MPEG_VIDEO_BITRATE_MODE, - V4L2_CID_MPEG_VIDEO_BITRATE, - V4L2_CID_MPEG_VIDEO_BITRATE_PEAK, - 0 - }; - static const u32 *ctrl_classes[] = { - user_ctrls, - mpeg_ctrls, - NULL - }; - struct saa7134_dev *dev = file->private_data; - - c->id = v4l2_ctrl_next(ctrl_classes, c->id); - if (c->id == 0) - return -EINVAL; - if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS) - return v4l2_ctrl_query_fill(c, 0, 0, 0, 0); - if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) - return saa7134_queryctrl(file, priv, c); - return saa_call_empress(dev, core, queryctrl, c); -} - -static int empress_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *c) -{ - struct saa7134_dev *dev = file->private_data; - - if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return saa_call_empress(dev, core, querymenu, c); -} - -static int empress_s_std(struct file *file, void *priv, v4l2_std_id id) -{ - struct saa7134_dev *dev = file->private_data; - - return saa7134_s_std_internal(dev, NULL, id); -} - -static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct saa7134_dev *dev = file->private_data; - - *id = dev->tvnorm->id; - return 0; -} - static const struct v4l2_file_operations ts_fops = { .owner = THIS_MODULE, @@ -450,28 +242,29 @@ static const struct v4l2_file_operations ts_fops = }; static const struct v4l2_ioctl_ops ts_ioctl_ops = { - .vidioc_querycap = empress_querycap, + .vidioc_querycap = saa7134_querycap, .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, .vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap, - .vidioc_reqbufs = empress_reqbufs, - .vidioc_querybuf = empress_querybuf, - .vidioc_qbuf = empress_qbuf, - .vidioc_dqbuf = empress_dqbuf, - .vidioc_streamon = empress_streamon, - .vidioc_streamoff = empress_streamoff, - .vidioc_s_ext_ctrls = empress_s_ext_ctrls, - .vidioc_g_ext_ctrls = empress_g_ext_ctrls, - .vidioc_enum_input = empress_enum_input, - .vidioc_g_input = empress_g_input, - .vidioc_s_input = empress_s_input, - .vidioc_queryctrl = empress_queryctrl, - .vidioc_querymenu = empress_querymenu, - .vidioc_g_ctrl = empress_g_ctrl, - .vidioc_s_ctrl = empress_s_ctrl, - .vidioc_s_std = empress_s_std, - .vidioc_g_std = empress_g_std, + .vidioc_reqbufs = saa7134_reqbufs, + .vidioc_querybuf = saa7134_querybuf, + .vidioc_qbuf = saa7134_qbuf, + .vidioc_dqbuf = saa7134_dqbuf, + .vidioc_streamon = saa7134_streamon, + .vidioc_streamoff = saa7134_streamoff, + .vidioc_g_frequency = saa7134_g_frequency, + .vidioc_s_frequency = saa7134_s_frequency, + .vidioc_g_tuner = saa7134_g_tuner, + .vidioc_s_tuner = saa7134_s_tuner, + .vidioc_enum_input = saa7134_enum_input, + .vidioc_g_input = saa7134_g_input, + .vidioc_s_input = saa7134_s_input, + .vidioc_s_std = saa7134_s_std, + .vidioc_g_std = saa7134_g_std, + .vidioc_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; /* ----------------------------------------------------------- */ @@ -501,9 +294,26 @@ static void empress_signal_change(struct saa7134_dev *dev) schedule_work(&dev->empress_workqueue); } +static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl) +{ + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_HUE: + case V4L2_CID_CONTRAST: + case V4L2_CID_SATURATION: + case V4L2_CID_AUDIO_MUTE: + case V4L2_CID_AUDIO_VOLUME: + case V4L2_CID_PRIVATE_INVERT: + case V4L2_CID_PRIVATE_AUTOMUTE: + return true; + default: + return false; + } +} static int empress_init(struct saa7134_dev *dev) { + struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler; int err; dprintk("%s: %s\n",dev->name,__func__); @@ -516,6 +326,16 @@ static int empress_init(struct saa7134_dev *dev) snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name), "%s empress (%s)", dev->name, saa7134_boards[dev->board].name); + set_bit(V4L2_FL_USE_FH_PRIO, &dev->empress_dev->flags); + v4l2_ctrl_handler_init(hdl, 21); + v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter); + if (dev->empress_sd) + v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL); + if (hdl->error) { + video_device_release(dev->empress_dev); + return hdl->error; + } + dev->empress_dev->ctrl_handler = hdl; INIT_WORK(&dev->empress_workqueue, empress_signal_update); @@ -551,6 +371,7 @@ static int empress_fini(struct saa7134_dev *dev) return 0; flush_work(&dev->empress_workqueue); video_unregister_device(dev->empress_dev); + v4l2_ctrl_handler_free(&dev->empress_ctrl_handler); dev->empress_dev = NULL; return 0; } |