linux/drivers/staging/most/video/video.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * video.c - V4L2 component for Mostcore
   4 *
   5 * Copyright (C) 2015, Microchip Technology Germany II GmbH & Co. KG
   6 */
   7
   8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   9
  10#include <linux/module.h>
  11#include <linux/slab.h>
  12#include <linux/init.h>
  13#include <linux/device.h>
  14#include <linux/suspend.h>
  15#include <linux/videodev2.h>
  16#include <linux/mutex.h>
  17#include <media/v4l2-common.h>
  18#include <media/v4l2-ioctl.h>
  19#include <media/v4l2-event.h>
  20#include <media/v4l2-device.h>
  21#include <media/v4l2-ctrls.h>
  22#include <media/v4l2-fh.h>
  23
  24#include "most/core.h"
  25
  26#define V4L2_CMP_MAX_INPUT  1
  27
  28static struct core_component comp;
  29
  30struct most_video_dev {
  31        struct most_interface *iface;
  32        int ch_idx;
  33        struct list_head list;
  34        bool mute;
  35
  36        struct list_head pending_mbos;
  37        spinlock_t list_lock;
  38
  39        struct v4l2_device v4l2_dev;
  40        atomic_t access_ref;
  41        struct video_device *vdev;
  42        unsigned int ctrl_input;
  43
  44        struct mutex lock;
  45
  46        wait_queue_head_t wait_data;
  47};
  48
  49struct comp_fh {
  50        /* must be the first field of this struct! */
  51        struct v4l2_fh fh;
  52        struct most_video_dev *mdev;
  53        u32 offs;
  54};
  55
  56static struct list_head video_devices = LIST_HEAD_INIT(video_devices);
  57static struct spinlock list_lock;
  58
  59static inline bool data_ready(struct most_video_dev *mdev)
  60{
  61        return !list_empty(&mdev->pending_mbos);
  62}
  63
  64static inline struct mbo *get_top_mbo(struct most_video_dev *mdev)
  65{
  66        return list_first_entry(&mdev->pending_mbos, struct mbo, list);
  67}
  68
  69static int comp_vdev_open(struct file *filp)
  70{
  71        int ret;
  72        struct video_device *vdev = video_devdata(filp);
  73        struct most_video_dev *mdev = video_drvdata(filp);
  74        struct comp_fh *fh;
  75
  76        switch (vdev->vfl_type) {
  77        case VFL_TYPE_GRABBER:
  78                break;
  79        default:
  80                return -EINVAL;
  81        }
  82
  83        fh = kzalloc(sizeof(*fh), GFP_KERNEL);
  84        if (!fh)
  85                return -ENOMEM;
  86
  87        if (!atomic_inc_and_test(&mdev->access_ref)) {
  88                v4l2_err(&mdev->v4l2_dev, "too many clients\n");
  89                ret = -EBUSY;
  90                goto err_dec;
  91        }
  92
  93        fh->mdev = mdev;
  94        v4l2_fh_init(&fh->fh, vdev);
  95        filp->private_data = fh;
  96
  97        v4l2_fh_add(&fh->fh);
  98
  99        ret = most_start_channel(mdev->iface, mdev->ch_idx, &comp);
 100        if (ret) {
 101                v4l2_err(&mdev->v4l2_dev, "most_start_channel() failed\n");
 102                goto err_rm;
 103        }
 104
 105        return 0;
 106
 107err_rm:
 108        v4l2_fh_del(&fh->fh);
 109        v4l2_fh_exit(&fh->fh);
 110
 111err_dec:
 112        atomic_dec(&mdev->access_ref);
 113        kfree(fh);
 114        return ret;
 115}
 116
 117static int comp_vdev_close(struct file *filp)
 118{
 119        struct comp_fh *fh = filp->private_data;
 120        struct most_video_dev *mdev = fh->mdev;
 121        struct mbo *mbo, *tmp;
 122
 123        /*
 124         * We need to put MBOs back before we call most_stop_channel()
 125         * to deallocate MBOs.
 126         * From the other hand mostcore still calling rx_completion()
 127         * to deliver MBOs until most_stop_channel() is called.
 128         * Use mute to work around this issue.
 129         * This must be implemented in core.
 130         */
 131
 132        spin_lock_irq(&mdev->list_lock);
 133        mdev->mute = true;
 134        list_for_each_entry_safe(mbo, tmp, &mdev->pending_mbos, list) {
 135                list_del(&mbo->list);
 136                spin_unlock_irq(&mdev->list_lock);
 137                most_put_mbo(mbo);
 138                spin_lock_irq(&mdev->list_lock);
 139        }
 140        spin_unlock_irq(&mdev->list_lock);
 141        most_stop_channel(mdev->iface, mdev->ch_idx, &comp);
 142        mdev->mute = false;
 143
 144        v4l2_fh_del(&fh->fh);
 145        v4l2_fh_exit(&fh->fh);
 146
 147        atomic_dec(&mdev->access_ref);
 148        kfree(fh);
 149        return 0;
 150}
 151
 152static ssize_t comp_vdev_read(struct file *filp, char __user *buf,
 153                              size_t count, loff_t *pos)
 154{
 155        struct comp_fh *fh = filp->private_data;
 156        struct most_video_dev *mdev = fh->mdev;
 157        int ret = 0;
 158
 159        if (*pos)
 160                return -ESPIPE;
 161
 162        if (!mdev)
 163                return -ENODEV;
 164
 165        /* wait for the first buffer */
 166        if (!(filp->f_flags & O_NONBLOCK)) {
 167                if (wait_event_interruptible(mdev->wait_data, data_ready(mdev)))
 168                        return -ERESTARTSYS;
 169        }
 170
 171        if (!data_ready(mdev))
 172                return -EAGAIN;
 173
 174        while (count > 0 && data_ready(mdev)) {
 175                struct mbo *const mbo = get_top_mbo(mdev);
 176                int const rem = mbo->processed_length - fh->offs;
 177                int const cnt = rem < count ? rem : count;
 178
 179                if (copy_to_user(buf, mbo->virt_address + fh->offs, cnt)) {
 180                        v4l2_err(&mdev->v4l2_dev, "read: copy_to_user failed\n");
 181                        if (!ret)
 182                                ret = -EFAULT;
 183                        return ret;
 184                }
 185
 186                fh->offs += cnt;
 187                count -= cnt;
 188                buf += cnt;
 189                ret += cnt;
 190
 191                if (cnt >= rem) {
 192                        fh->offs = 0;
 193                        spin_lock_irq(&mdev->list_lock);
 194                        list_del(&mbo->list);
 195                        spin_unlock_irq(&mdev->list_lock);
 196                        most_put_mbo(mbo);
 197                }
 198        }
 199        return ret;
 200}
 201
 202static __poll_t comp_vdev_poll(struct file *filp, poll_table *wait)
 203{
 204        struct comp_fh *fh = filp->private_data;
 205        struct most_video_dev *mdev = fh->mdev;
 206        __poll_t mask = 0;
 207
 208        /* only wait if no data is available */
 209        if (!data_ready(mdev))
 210                poll_wait(filp, &mdev->wait_data, wait);
 211        if (data_ready(mdev))
 212                mask |= EPOLLIN | EPOLLRDNORM;
 213
 214        return mask;
 215}
 216
 217static void comp_set_format_struct(struct v4l2_format *f)
 218{
 219        f->fmt.pix.width = 8;
 220        f->fmt.pix.height = 8;
 221        f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
 222        f->fmt.pix.bytesperline = 0;
 223        f->fmt.pix.sizeimage = 188 * 2;
 224        f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
 225        f->fmt.pix.field = V4L2_FIELD_NONE;
 226        f->fmt.pix.priv = 0;
 227}
 228
 229static int comp_set_format(struct most_video_dev *mdev, unsigned int cmd,
 230                           struct v4l2_format *format)
 231{
 232        if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_MPEG)
 233                return -EINVAL;
 234
 235        if (cmd == VIDIOC_TRY_FMT)
 236                return 0;
 237
 238        comp_set_format_struct(format);
 239
 240        return 0;
 241}
 242
 243static int vidioc_querycap(struct file *file, void *priv,
 244                           struct v4l2_capability *cap)
 245{
 246        struct comp_fh *fh = priv;
 247        struct most_video_dev *mdev = fh->mdev;
 248
 249        strlcpy(cap->driver, "v4l2_component", sizeof(cap->driver));
 250        strlcpy(cap->card, "MOST", sizeof(cap->card));
 251        snprintf(cap->bus_info, sizeof(cap->bus_info),
 252                 "%s", mdev->iface->description);
 253
 254        cap->capabilities =
 255                V4L2_CAP_READWRITE |
 256                V4L2_CAP_TUNER |
 257                V4L2_CAP_VIDEO_CAPTURE;
 258        return 0;
 259}
 260
 261static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 262                                   struct v4l2_fmtdesc *f)
 263{
 264        if (f->index)
 265                return -EINVAL;
 266
 267        strcpy(f->description, "MPEG");
 268        f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 269        f->flags = V4L2_FMT_FLAG_COMPRESSED;
 270        f->pixelformat = V4L2_PIX_FMT_MPEG;
 271
 272        return 0;
 273}
 274
 275static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 276                                struct v4l2_format *f)
 277{
 278        comp_set_format_struct(f);
 279        return 0;
 280}
 281
 282static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 283                                  struct v4l2_format *f)
 284{
 285        struct comp_fh *fh = priv;
 286        struct most_video_dev *mdev = fh->mdev;
 287
 288        return comp_set_format(mdev, VIDIOC_TRY_FMT, f);
 289}
 290
 291static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 292                                struct v4l2_format *f)
 293{
 294        struct comp_fh *fh = priv;
 295        struct most_video_dev *mdev = fh->mdev;
 296
 297        return comp_set_format(mdev, VIDIOC_S_FMT, f);
 298}
 299
 300static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
 301{
 302        *norm = V4L2_STD_UNKNOWN;
 303        return 0;
 304}
 305
 306static int vidioc_enum_input(struct file *file, void *priv,
 307                             struct v4l2_input *input)
 308{
 309        struct comp_fh *fh = priv;
 310        struct most_video_dev *mdev = fh->mdev;
 311
 312        if (input->index >= V4L2_CMP_MAX_INPUT)
 313                return -EINVAL;
 314
 315        strcpy(input->name, "MOST Video");
 316        input->type |= V4L2_INPUT_TYPE_CAMERA;
 317        input->audioset = 0;
 318
 319        input->std = mdev->vdev->tvnorms;
 320
 321        return 0;
 322}
 323
 324static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 325{
 326        struct comp_fh *fh = priv;
 327        struct most_video_dev *mdev = fh->mdev;
 328        *i = mdev->ctrl_input;
 329        return 0;
 330}
 331
 332static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
 333{
 334        struct comp_fh *fh = priv;
 335        struct most_video_dev *mdev = fh->mdev;
 336
 337        if (index >= V4L2_CMP_MAX_INPUT)
 338                return -EINVAL;
 339        mdev->ctrl_input = index;
 340        return 0;
 341}
 342
 343static const struct v4l2_file_operations comp_fops = {
 344        .owner      = THIS_MODULE,
 345        .open       = comp_vdev_open,
 346        .release    = comp_vdev_close,
 347        .read       = comp_vdev_read,
 348        .poll       = comp_vdev_poll,
 349        .unlocked_ioctl = video_ioctl2,
 350};
 351
 352static const struct v4l2_ioctl_ops video_ioctl_ops = {
 353        .vidioc_querycap            = vidioc_querycap,
 354        .vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
 355        .vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
 356        .vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
 357        .vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
 358        .vidioc_g_std               = vidioc_g_std,
 359        .vidioc_enum_input          = vidioc_enum_input,
 360        .vidioc_g_input             = vidioc_g_input,
 361        .vidioc_s_input             = vidioc_s_input,
 362};
 363
 364static const struct video_device comp_videodev_template = {
 365        .fops = &comp_fops,
 366        .release = video_device_release,
 367        .ioctl_ops = &video_ioctl_ops,
 368        .tvnorms = V4L2_STD_UNKNOWN,
 369};
 370
 371/**************************************************************************/
 372
 373static struct most_video_dev *get_comp_dev(
 374        struct most_interface *iface, int channel_idx)
 375{
 376        struct most_video_dev *mdev;
 377        unsigned long flags;
 378
 379        spin_lock_irqsave(&list_lock, flags);
 380        list_for_each_entry(mdev, &video_devices, list) {
 381                if (mdev->iface == iface && mdev->ch_idx == channel_idx) {
 382                        spin_unlock_irqrestore(&list_lock, flags);
 383                        return mdev;
 384                }
 385        }
 386        spin_unlock_irqrestore(&list_lock, flags);
 387        return NULL;
 388}
 389
 390static int comp_rx_data(struct mbo *mbo)
 391{
 392        unsigned long flags;
 393        struct most_video_dev *mdev =
 394                get_comp_dev(mbo->ifp, mbo->hdm_channel_id);
 395
 396        if (!mdev)
 397                return -EIO;
 398
 399        spin_lock_irqsave(&mdev->list_lock, flags);
 400        if (unlikely(mdev->mute)) {
 401                spin_unlock_irqrestore(&mdev->list_lock, flags);
 402                return -EIO;
 403        }
 404
 405        list_add_tail(&mbo->list, &mdev->pending_mbos);
 406        spin_unlock_irqrestore(&mdev->list_lock, flags);
 407        wake_up_interruptible(&mdev->wait_data);
 408        return 0;
 409}
 410
 411static int comp_register_videodev(struct most_video_dev *mdev)
 412{
 413        int ret;
 414
 415        init_waitqueue_head(&mdev->wait_data);
 416
 417        /* allocate and fill v4l2 video struct */
 418        mdev->vdev = video_device_alloc();
 419        if (!mdev->vdev)
 420                return -ENOMEM;
 421
 422        /* Fill the video capture device struct */
 423        *mdev->vdev = comp_videodev_template;
 424        mdev->vdev->v4l2_dev = &mdev->v4l2_dev;
 425        mdev->vdev->lock = &mdev->lock;
 426        snprintf(mdev->vdev->name, sizeof(mdev->vdev->name), "MOST: %s",
 427                 mdev->v4l2_dev.name);
 428
 429        /* Register the v4l2 device */
 430        video_set_drvdata(mdev->vdev, mdev);
 431        ret = video_register_device(mdev->vdev, VFL_TYPE_GRABBER, -1);
 432        if (ret) {
 433                v4l2_err(&mdev->v4l2_dev, "video_register_device failed (%d)\n",
 434                         ret);
 435                video_device_release(mdev->vdev);
 436        }
 437
 438        return ret;
 439}
 440
 441static void comp_unregister_videodev(struct most_video_dev *mdev)
 442{
 443        video_unregister_device(mdev->vdev);
 444}
 445
 446static void comp_v4l2_dev_release(struct v4l2_device *v4l2_dev)
 447{
 448        struct most_video_dev *mdev =
 449                container_of(v4l2_dev, struct most_video_dev, v4l2_dev);
 450
 451        v4l2_device_unregister(v4l2_dev);
 452        kfree(mdev);
 453}
 454
 455static int comp_probe_channel(struct most_interface *iface, int channel_idx,
 456                              struct most_channel_config *ccfg, char *name)
 457{
 458        int ret;
 459        struct most_video_dev *mdev = get_comp_dev(iface, channel_idx);
 460
 461        if (mdev) {
 462                pr_err("channel already linked\n");
 463                return -EEXIST;
 464        }
 465
 466        if (ccfg->direction != MOST_CH_RX) {
 467                pr_err("wrong direction, expect rx\n");
 468                return -EINVAL;
 469        }
 470
 471        if (ccfg->data_type != MOST_CH_SYNC &&
 472            ccfg->data_type != MOST_CH_ISOC) {
 473                pr_err("wrong channel type, expect sync or isoc\n");
 474                return -EINVAL;
 475        }
 476
 477        mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
 478        if (!mdev)
 479                return -ENOMEM;
 480
 481        mutex_init(&mdev->lock);
 482        atomic_set(&mdev->access_ref, -1);
 483        spin_lock_init(&mdev->list_lock);
 484        INIT_LIST_HEAD(&mdev->pending_mbos);
 485        mdev->iface = iface;
 486        mdev->ch_idx = channel_idx;
 487        mdev->v4l2_dev.release = comp_v4l2_dev_release;
 488
 489        /* Create the v4l2_device */
 490        strlcpy(mdev->v4l2_dev.name, name, sizeof(mdev->v4l2_dev.name));
 491        ret = v4l2_device_register(NULL, &mdev->v4l2_dev);
 492        if (ret) {
 493                pr_err("v4l2_device_register() failed\n");
 494                kfree(mdev);
 495                return ret;
 496        }
 497
 498        ret = comp_register_videodev(mdev);
 499        if (ret)
 500                goto err_unreg;
 501
 502        spin_lock_irq(&list_lock);
 503        list_add(&mdev->list, &video_devices);
 504        spin_unlock_irq(&list_lock);
 505        return 0;
 506
 507err_unreg:
 508        v4l2_device_disconnect(&mdev->v4l2_dev);
 509        v4l2_device_put(&mdev->v4l2_dev);
 510        return ret;
 511}
 512
 513static int comp_disconnect_channel(struct most_interface *iface,
 514                                   int channel_idx)
 515{
 516        struct most_video_dev *mdev = get_comp_dev(iface, channel_idx);
 517
 518        if (!mdev) {
 519                pr_err("no such channel is linked\n");
 520                return -ENOENT;
 521        }
 522
 523        spin_lock_irq(&list_lock);
 524        list_del(&mdev->list);
 525        spin_unlock_irq(&list_lock);
 526
 527        comp_unregister_videodev(mdev);
 528        v4l2_device_disconnect(&mdev->v4l2_dev);
 529        v4l2_device_put(&mdev->v4l2_dev);
 530        return 0;
 531}
 532
 533static struct core_component comp_info = {
 534        .name = "video",
 535        .probe_channel = comp_probe_channel,
 536        .disconnect_channel = comp_disconnect_channel,
 537        .rx_completion = comp_rx_data,
 538};
 539
 540static int __init comp_init(void)
 541{
 542        spin_lock_init(&list_lock);
 543        return most_register_component(&comp);
 544}
 545
 546static void __exit comp_exit(void)
 547{
 548        struct most_video_dev *mdev, *tmp;
 549
 550        /*
 551         * As the mostcore currently doesn't call disconnect_channel()
 552         * for linked channels while we call most_deregister_component()
 553         * we simulate this call here.
 554         * This must be fixed in core.
 555         */
 556        spin_lock_irq(&list_lock);
 557        list_for_each_entry_safe(mdev, tmp, &video_devices, list) {
 558                list_del(&mdev->list);
 559                spin_unlock_irq(&list_lock);
 560
 561                comp_unregister_videodev(mdev);
 562                v4l2_device_disconnect(&mdev->v4l2_dev);
 563                v4l2_device_put(&mdev->v4l2_dev);
 564                spin_lock_irq(&list_lock);
 565        }
 566        spin_unlock_irq(&list_lock);
 567
 568        most_deregister_component(&comp_info);
 569        BUG_ON(!list_empty(&video_devices));
 570}
 571
 572module_init(comp_init);
 573module_exit(comp_exit);
 574
 575MODULE_DESCRIPTION("V4L2 Component Module for Mostcore");
 576MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
 577MODULE_LICENSE("GPL");
 578