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