root/drivers/staging/most/video/video.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. data_ready
  2. get_top_mbo
  3. comp_vdev_open
  4. comp_vdev_close
  5. comp_vdev_read
  6. comp_vdev_poll
  7. comp_set_format_struct
  8. comp_set_format
  9. vidioc_querycap
  10. vidioc_enum_fmt_vid_cap
  11. vidioc_g_fmt_vid_cap
  12. vidioc_try_fmt_vid_cap
  13. vidioc_s_fmt_vid_cap
  14. vidioc_g_std
  15. vidioc_enum_input
  16. vidioc_g_input
  17. vidioc_s_input
  18. get_comp_dev
  19. comp_rx_data
  20. comp_register_videodev
  21. comp_unregister_videodev
  22. comp_v4l2_dev_release
  23. comp_probe_channel
  24. comp_disconnect_channel
  25. comp_init
  26. comp_exit

   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 
  28 static struct core_component comp;
  29 
  30 struct 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 
  49 struct 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 
  56 static struct list_head video_devices = LIST_HEAD_INIT(video_devices);
  57 static DEFINE_SPINLOCK(list_lock);
  58 
  59 static inline bool data_ready(struct most_video_dev *mdev)
  60 {
  61         return !list_empty(&mdev->pending_mbos);
  62 }
  63 
  64 static 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 
  69 static 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 
 107 err_rm:
 108         v4l2_fh_del(&fh->fh);
 109         v4l2_fh_exit(&fh->fh);
 110 
 111 err_dec:
 112         atomic_dec(&mdev->access_ref);
 113         kfree(fh);
 114         return ret;
 115 }
 116 
 117 static 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 
 152 static 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 
 202 static __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 
 217 static 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 
 229 static 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 
 243 static 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         return 0;
 254 }
 255 
 256 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 257                                    struct v4l2_fmtdesc *f)
 258 {
 259         if (f->index)
 260                 return -EINVAL;
 261 
 262         strcpy(f->description, "MPEG");
 263         f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 264         f->flags = V4L2_FMT_FLAG_COMPRESSED;
 265         f->pixelformat = V4L2_PIX_FMT_MPEG;
 266 
 267         return 0;
 268 }
 269 
 270 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 271                                 struct v4l2_format *f)
 272 {
 273         comp_set_format_struct(f);
 274         return 0;
 275 }
 276 
 277 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 278                                   struct v4l2_format *f)
 279 {
 280         struct comp_fh *fh = priv;
 281         struct most_video_dev *mdev = fh->mdev;
 282 
 283         return comp_set_format(mdev, VIDIOC_TRY_FMT, f);
 284 }
 285 
 286 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 287                                 struct v4l2_format *f)
 288 {
 289         struct comp_fh *fh = priv;
 290         struct most_video_dev *mdev = fh->mdev;
 291 
 292         return comp_set_format(mdev, VIDIOC_S_FMT, f);
 293 }
 294 
 295 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
 296 {
 297         *norm = V4L2_STD_UNKNOWN;
 298         return 0;
 299 }
 300 
 301 static int vidioc_enum_input(struct file *file, void *priv,
 302                              struct v4l2_input *input)
 303 {
 304         struct comp_fh *fh = priv;
 305         struct most_video_dev *mdev = fh->mdev;
 306 
 307         if (input->index >= V4L2_CMP_MAX_INPUT)
 308                 return -EINVAL;
 309 
 310         strcpy(input->name, "MOST Video");
 311         input->type |= V4L2_INPUT_TYPE_CAMERA;
 312         input->audioset = 0;
 313 
 314         input->std = mdev->vdev->tvnorms;
 315 
 316         return 0;
 317 }
 318 
 319 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
 320 {
 321         struct comp_fh *fh = priv;
 322         struct most_video_dev *mdev = fh->mdev;
 323         *i = mdev->ctrl_input;
 324         return 0;
 325 }
 326 
 327 static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
 328 {
 329         struct comp_fh *fh = priv;
 330         struct most_video_dev *mdev = fh->mdev;
 331 
 332         if (index >= V4L2_CMP_MAX_INPUT)
 333                 return -EINVAL;
 334         mdev->ctrl_input = index;
 335         return 0;
 336 }
 337 
 338 static const struct v4l2_file_operations comp_fops = {
 339         .owner      = THIS_MODULE,
 340         .open       = comp_vdev_open,
 341         .release    = comp_vdev_close,
 342         .read       = comp_vdev_read,
 343         .poll       = comp_vdev_poll,
 344         .unlocked_ioctl = video_ioctl2,
 345 };
 346 
 347 static const struct v4l2_ioctl_ops video_ioctl_ops = {
 348         .vidioc_querycap            = vidioc_querycap,
 349         .vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
 350         .vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
 351         .vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
 352         .vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
 353         .vidioc_g_std               = vidioc_g_std,
 354         .vidioc_enum_input          = vidioc_enum_input,
 355         .vidioc_g_input             = vidioc_g_input,
 356         .vidioc_s_input             = vidioc_s_input,
 357 };
 358 
 359 static const struct video_device comp_videodev_template = {
 360         .fops = &comp_fops,
 361         .release = video_device_release,
 362         .ioctl_ops = &video_ioctl_ops,
 363         .tvnorms = V4L2_STD_UNKNOWN,
 364         .device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE,
 365 };
 366 
 367 /**************************************************************************/
 368 
 369 static struct most_video_dev *get_comp_dev(
 370         struct most_interface *iface, int channel_idx)
 371 {
 372         struct most_video_dev *mdev;
 373         unsigned long flags;
 374 
 375         spin_lock_irqsave(&list_lock, flags);
 376         list_for_each_entry(mdev, &video_devices, list) {
 377                 if (mdev->iface == iface && mdev->ch_idx == channel_idx) {
 378                         spin_unlock_irqrestore(&list_lock, flags);
 379                         return mdev;
 380                 }
 381         }
 382         spin_unlock_irqrestore(&list_lock, flags);
 383         return NULL;
 384 }
 385 
 386 static int comp_rx_data(struct mbo *mbo)
 387 {
 388         unsigned long flags;
 389         struct most_video_dev *mdev =
 390                 get_comp_dev(mbo->ifp, mbo->hdm_channel_id);
 391 
 392         if (!mdev)
 393                 return -EIO;
 394 
 395         spin_lock_irqsave(&mdev->list_lock, flags);
 396         if (unlikely(mdev->mute)) {
 397                 spin_unlock_irqrestore(&mdev->list_lock, flags);
 398                 return -EIO;
 399         }
 400 
 401         list_add_tail(&mbo->list, &mdev->pending_mbos);
 402         spin_unlock_irqrestore(&mdev->list_lock, flags);
 403         wake_up_interruptible(&mdev->wait_data);
 404         return 0;
 405 }
 406 
 407 static int comp_register_videodev(struct most_video_dev *mdev)
 408 {
 409         int ret;
 410 
 411         init_waitqueue_head(&mdev->wait_data);
 412 
 413         /* allocate and fill v4l2 video struct */
 414         mdev->vdev = video_device_alloc();
 415         if (!mdev->vdev)
 416                 return -ENOMEM;
 417 
 418         /* Fill the video capture device struct */
 419         *mdev->vdev = comp_videodev_template;
 420         mdev->vdev->v4l2_dev = &mdev->v4l2_dev;
 421         mdev->vdev->lock = &mdev->lock;
 422         snprintf(mdev->vdev->name, sizeof(mdev->vdev->name), "MOST: %s",
 423                  mdev->v4l2_dev.name);
 424 
 425         /* Register the v4l2 device */
 426         video_set_drvdata(mdev->vdev, mdev);
 427         ret = video_register_device(mdev->vdev, VFL_TYPE_GRABBER, -1);
 428         if (ret) {
 429                 v4l2_err(&mdev->v4l2_dev, "video_register_device failed (%d)\n",
 430                          ret);
 431                 video_device_release(mdev->vdev);
 432         }
 433 
 434         return ret;
 435 }
 436 
 437 static void comp_unregister_videodev(struct most_video_dev *mdev)
 438 {
 439         video_unregister_device(mdev->vdev);
 440 }
 441 
 442 static void comp_v4l2_dev_release(struct v4l2_device *v4l2_dev)
 443 {
 444         struct most_video_dev *mdev =
 445                 container_of(v4l2_dev, struct most_video_dev, v4l2_dev);
 446 
 447         v4l2_device_unregister(v4l2_dev);
 448         kfree(mdev);
 449 }
 450 
 451 static int comp_probe_channel(struct most_interface *iface, int channel_idx,
 452                               struct most_channel_config *ccfg, char *name,
 453                               char *args)
 454 {
 455         int ret;
 456         struct most_video_dev *mdev = get_comp_dev(iface, channel_idx);
 457 
 458         if (mdev) {
 459                 pr_err("channel already linked\n");
 460                 return -EEXIST;
 461         }
 462 
 463         if (ccfg->direction != MOST_CH_RX) {
 464                 pr_err("wrong direction, expect rx\n");
 465                 return -EINVAL;
 466         }
 467 
 468         if (ccfg->data_type != MOST_CH_SYNC &&
 469             ccfg->data_type != MOST_CH_ISOC) {
 470                 pr_err("wrong channel type, expect sync or isoc\n");
 471                 return -EINVAL;
 472         }
 473 
 474         mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
 475         if (!mdev)
 476                 return -ENOMEM;
 477 
 478         mutex_init(&mdev->lock);
 479         atomic_set(&mdev->access_ref, -1);
 480         spin_lock_init(&mdev->list_lock);
 481         INIT_LIST_HEAD(&mdev->pending_mbos);
 482         mdev->iface = iface;
 483         mdev->ch_idx = channel_idx;
 484         mdev->v4l2_dev.release = comp_v4l2_dev_release;
 485 
 486         /* Create the v4l2_device */
 487         strlcpy(mdev->v4l2_dev.name, name, sizeof(mdev->v4l2_dev.name));
 488         ret = v4l2_device_register(NULL, &mdev->v4l2_dev);
 489         if (ret) {
 490                 pr_err("v4l2_device_register() failed\n");
 491                 kfree(mdev);
 492                 return ret;
 493         }
 494 
 495         ret = comp_register_videodev(mdev);
 496         if (ret)
 497                 goto err_unreg;
 498 
 499         spin_lock_irq(&list_lock);
 500         list_add(&mdev->list, &video_devices);
 501         spin_unlock_irq(&list_lock);
 502         return 0;
 503 
 504 err_unreg:
 505         v4l2_device_disconnect(&mdev->v4l2_dev);
 506         v4l2_device_put(&mdev->v4l2_dev);
 507         return ret;
 508 }
 509 
 510 static int comp_disconnect_channel(struct most_interface *iface,
 511                                    int channel_idx)
 512 {
 513         struct most_video_dev *mdev = get_comp_dev(iface, channel_idx);
 514 
 515         if (!mdev) {
 516                 pr_err("no such channel is linked\n");
 517                 return -ENOENT;
 518         }
 519 
 520         spin_lock_irq(&list_lock);
 521         list_del(&mdev->list);
 522         spin_unlock_irq(&list_lock);
 523 
 524         comp_unregister_videodev(mdev);
 525         v4l2_device_disconnect(&mdev->v4l2_dev);
 526         v4l2_device_put(&mdev->v4l2_dev);
 527         return 0;
 528 }
 529 
 530 static struct core_component comp = {
 531         .name = "video",
 532         .probe_channel = comp_probe_channel,
 533         .disconnect_channel = comp_disconnect_channel,
 534         .rx_completion = comp_rx_data,
 535 };
 536 
 537 static int __init comp_init(void)
 538 {
 539         int err;
 540 
 541         err = most_register_component(&comp);
 542         if (err)
 543                 return err;
 544         err = most_register_configfs_subsys(&comp);
 545         if (err) {
 546                 most_deregister_component(&comp);
 547                 return err;
 548         }
 549         return 0;
 550 }
 551 
 552 static void __exit comp_exit(void)
 553 {
 554         struct most_video_dev *mdev, *tmp;
 555 
 556         /*
 557          * As the mostcore currently doesn't call disconnect_channel()
 558          * for linked channels while we call most_deregister_component()
 559          * we simulate this call here.
 560          * This must be fixed in core.
 561          */
 562         spin_lock_irq(&list_lock);
 563         list_for_each_entry_safe(mdev, tmp, &video_devices, list) {
 564                 list_del(&mdev->list);
 565                 spin_unlock_irq(&list_lock);
 566 
 567                 comp_unregister_videodev(mdev);
 568                 v4l2_device_disconnect(&mdev->v4l2_dev);
 569                 v4l2_device_put(&mdev->v4l2_dev);
 570                 spin_lock_irq(&list_lock);
 571         }
 572         spin_unlock_irq(&list_lock);
 573 
 574         most_deregister_configfs_subsys(&comp);
 575         most_deregister_component(&comp);
 576         BUG_ON(!list_empty(&video_devices));
 577 }
 578 
 579 module_init(comp_init);
 580 module_exit(comp_exit);
 581 
 582 MODULE_DESCRIPTION("V4L2 Component Module for Mostcore");
 583 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
 584 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */