• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
34 static struct most_aim aim_info;
35 
36 struct 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 
55 struct 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 
62 static struct list_head video_devices = LIST_HEAD_INIT(video_devices);
63 static struct spinlock list_lock;
64 
data_ready(struct most_video_dev * mdev)65 static inline bool data_ready(struct most_video_dev *mdev)
66 {
67 	return !list_empty(&mdev->pending_mbos);
68 }
69 
get_top_mbo(struct most_video_dev * mdev)70 static 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 
aim_vdev_open(struct file * filp)75 static 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 	v4l2_info(&mdev->v4l2_dev, "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 		v4l2_err(&mdev->v4l2_dev, "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 		v4l2_err(&mdev->v4l2_dev, "most_start_channel() failed\n");
110 		goto err_rm;
111 	}
112 
113 	return 0;
114 
115 err_rm:
116 	v4l2_fh_del(&fh->fh);
117 	v4l2_fh_exit(&fh->fh);
118 
119 err_dec:
120 	atomic_dec(&mdev->access_ref);
121 	kfree(fh);
122 	return ret;
123 }
124 
aim_vdev_close(struct file * filp)125 static 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 	v4l2_info(&mdev->v4l2_dev, "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_irq(&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_irq(&mdev->list_lock);
147 		most_put_mbo(mbo);
148 		spin_lock_irq(&mdev->list_lock);
149 	}
150 	spin_unlock_irq(&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 
aim_vdev_read(struct file * filp,char __user * buf,size_t count,loff_t * pos)162 static 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 			v4l2_err(&mdev->v4l2_dev, "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_irq(&mdev->list_lock);
204 			list_del(&mbo->list);
205 			spin_unlock_irq(&mdev->list_lock);
206 			most_put_mbo(mbo);
207 		}
208 	}
209 	return ret;
210 }
211 
aim_vdev_poll(struct file * filp,poll_table * wait)212 static 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 
aim_set_format_struct(struct v4l2_format * f)227 static 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 
aim_set_format(struct most_video_dev * mdev,unsigned int cmd,struct v4l2_format * format)239 static 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 
vidioc_querycap(struct file * file,void * priv,struct v4l2_capability * cap)253 static 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 	v4l2_info(&mdev->v4l2_dev, "vidioc_querycap()\n");
260 
261 	strlcpy(cap->driver, "v4l2_most_aim", sizeof(cap->driver));
262 	strlcpy(cap->card, "MOST", 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 
vidioc_enum_fmt_vid_cap(struct file * file,void * priv,struct v4l2_fmtdesc * f)273 static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
274 				   struct v4l2_fmtdesc *f)
275 {
276 	struct aim_fh *fh = priv;
277 	struct most_video_dev *mdev = fh->mdev;
278 
279 	v4l2_info(&mdev->v4l2_dev, "vidioc_enum_fmt_vid_cap() %d\n", f->index);
280 
281 	if (f->index)
282 		return -EINVAL;
283 
284 	strcpy(f->description, "MPEG");
285 	f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
286 	f->flags = V4L2_FMT_FLAG_COMPRESSED;
287 	f->pixelformat = V4L2_PIX_FMT_MPEG;
288 
289 	return 0;
290 }
291 
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)292 static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
293 				struct v4l2_format *f)
294 {
295 	struct aim_fh *fh = priv;
296 	struct most_video_dev *mdev = fh->mdev;
297 
298 	v4l2_info(&mdev->v4l2_dev, "vidioc_g_fmt_vid_cap()\n");
299 
300 	aim_set_format_struct(f);
301 	return 0;
302 }
303 
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)304 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
305 				  struct v4l2_format *f)
306 {
307 	struct aim_fh *fh = priv;
308 	struct most_video_dev *mdev = fh->mdev;
309 
310 	return aim_set_format(mdev, VIDIOC_TRY_FMT, f);
311 }
312 
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)313 static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
314 				struct v4l2_format *f)
315 {
316 	struct aim_fh *fh = priv;
317 	struct most_video_dev *mdev = fh->mdev;
318 
319 	return aim_set_format(mdev, VIDIOC_S_FMT, f);
320 }
321 
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * norm)322 static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
323 {
324 	struct aim_fh *fh = priv;
325 	struct most_video_dev *mdev = fh->mdev;
326 
327 	v4l2_info(&mdev->v4l2_dev, "vidioc_g_std()\n");
328 
329 	*norm = V4L2_STD_UNKNOWN;
330 	return 0;
331 }
332 
vidioc_enum_input(struct file * file,void * priv,struct v4l2_input * input)333 static int vidioc_enum_input(struct file *file, void *priv,
334 			     struct v4l2_input *input)
335 {
336 	struct aim_fh *fh = priv;
337 	struct most_video_dev *mdev = fh->mdev;
338 
339 	if (input->index >= V4L2_AIM_MAX_INPUT)
340 		return -EINVAL;
341 
342 	strcpy(input->name, "MOST Video");
343 	input->type |= V4L2_INPUT_TYPE_CAMERA;
344 	input->audioset = 0;
345 
346 	input->std = mdev->vdev->tvnorms;
347 
348 	return 0;
349 }
350 
vidioc_g_input(struct file * file,void * priv,unsigned int * i)351 static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
352 {
353 	struct aim_fh *fh = priv;
354 	struct most_video_dev *mdev = fh->mdev;
355 	*i = mdev->ctrl_input;
356 	return 0;
357 }
358 
vidioc_s_input(struct file * file,void * priv,unsigned int index)359 static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
360 {
361 	struct aim_fh *fh = priv;
362 	struct most_video_dev *mdev = fh->mdev;
363 
364 	v4l2_info(&mdev->v4l2_dev, "vidioc_s_input(%d)\n", index);
365 
366 	if (index >= V4L2_AIM_MAX_INPUT)
367 		return -EINVAL;
368 	mdev->ctrl_input = index;
369 	return 0;
370 }
371 
372 static const struct v4l2_file_operations aim_fops = {
373 	.owner      = THIS_MODULE,
374 	.open       = aim_vdev_open,
375 	.release    = aim_vdev_close,
376 	.read       = aim_vdev_read,
377 	.poll       = aim_vdev_poll,
378 	.unlocked_ioctl = video_ioctl2,
379 };
380 
381 static const struct v4l2_ioctl_ops video_ioctl_ops = {
382 	.vidioc_querycap            = vidioc_querycap,
383 	.vidioc_enum_fmt_vid_cap    = vidioc_enum_fmt_vid_cap,
384 	.vidioc_g_fmt_vid_cap       = vidioc_g_fmt_vid_cap,
385 	.vidioc_try_fmt_vid_cap     = vidioc_try_fmt_vid_cap,
386 	.vidioc_s_fmt_vid_cap       = vidioc_s_fmt_vid_cap,
387 	.vidioc_g_std               = vidioc_g_std,
388 	.vidioc_enum_input          = vidioc_enum_input,
389 	.vidioc_g_input             = vidioc_g_input,
390 	.vidioc_s_input             = vidioc_s_input,
391 };
392 
393 static const struct video_device aim_videodev_template = {
394 	.fops = &aim_fops,
395 	.release = video_device_release,
396 	.ioctl_ops = &video_ioctl_ops,
397 	.tvnorms = V4L2_STD_UNKNOWN,
398 };
399 
400 /**************************************************************************/
401 
get_aim_dev(struct most_interface * iface,int channel_idx)402 static struct most_video_dev *get_aim_dev(
403 	struct most_interface *iface, int channel_idx)
404 {
405 	struct most_video_dev *mdev;
406 	unsigned long flags;
407 
408 	spin_lock_irqsave(&list_lock, flags);
409 	list_for_each_entry(mdev, &video_devices, list) {
410 		if (mdev->iface == iface && mdev->ch_idx == channel_idx) {
411 			spin_unlock_irqrestore(&list_lock, flags);
412 			return mdev;
413 		}
414 	}
415 	spin_unlock_irqrestore(&list_lock, flags);
416 	return NULL;
417 }
418 
aim_rx_data(struct mbo * mbo)419 static int aim_rx_data(struct mbo *mbo)
420 {
421 	unsigned long flags;
422 	struct most_video_dev *mdev =
423 		get_aim_dev(mbo->ifp, mbo->hdm_channel_id);
424 
425 	if (!mdev)
426 		return -EIO;
427 
428 	spin_lock_irqsave(&mdev->list_lock, flags);
429 	if (unlikely(mdev->mute)) {
430 		spin_unlock_irqrestore(&mdev->list_lock, flags);
431 		return -EIO;
432 	}
433 
434 	list_add_tail(&mbo->list, &mdev->pending_mbos);
435 	spin_unlock_irqrestore(&mdev->list_lock, flags);
436 	wake_up_interruptible(&mdev->wait_data);
437 	return 0;
438 }
439 
aim_register_videodev(struct most_video_dev * mdev)440 static int aim_register_videodev(struct most_video_dev *mdev)
441 {
442 	int ret;
443 
444 	v4l2_info(&mdev->v4l2_dev, "aim_register_videodev()\n");
445 
446 	init_waitqueue_head(&mdev->wait_data);
447 
448 	/* allocate and fill v4l2 video struct */
449 	mdev->vdev = video_device_alloc();
450 	if (!mdev->vdev)
451 		return -ENOMEM;
452 
453 	/* Fill the video capture device struct */
454 	*mdev->vdev = aim_videodev_template;
455 	mdev->vdev->v4l2_dev = &mdev->v4l2_dev;
456 	mdev->vdev->lock = &mdev->lock;
457 	snprintf(mdev->vdev->name, sizeof(mdev->vdev->name), "MOST: %s",
458 		 mdev->v4l2_dev.name);
459 
460 	/* Register the v4l2 device */
461 	video_set_drvdata(mdev->vdev, mdev);
462 	ret = video_register_device(mdev->vdev, VFL_TYPE_GRABBER, -1);
463 	if (ret) {
464 		v4l2_err(&mdev->v4l2_dev, "video_register_device failed (%d)\n",
465 			 ret);
466 		video_device_release(mdev->vdev);
467 	}
468 
469 	return ret;
470 }
471 
aim_unregister_videodev(struct most_video_dev * mdev)472 static void aim_unregister_videodev(struct most_video_dev *mdev)
473 {
474 	v4l2_info(&mdev->v4l2_dev, "aim_unregister_videodev()\n");
475 
476 	video_unregister_device(mdev->vdev);
477 }
478 
aim_v4l2_dev_release(struct v4l2_device * v4l2_dev)479 static void aim_v4l2_dev_release(struct v4l2_device *v4l2_dev)
480 {
481 	struct most_video_dev *mdev =
482 		container_of(v4l2_dev, struct most_video_dev, v4l2_dev);
483 
484 	v4l2_device_unregister(v4l2_dev);
485 	kfree(mdev);
486 }
487 
aim_probe_channel(struct most_interface * iface,int channel_idx,struct most_channel_config * ccfg,struct kobject * parent,char * name)488 static int aim_probe_channel(struct most_interface *iface, int channel_idx,
489 			     struct most_channel_config *ccfg,
490 			     struct kobject *parent, char *name)
491 {
492 	int ret;
493 	struct most_video_dev *mdev = get_aim_dev(iface, channel_idx);
494 
495 	pr_info("aim_probe_channel(%s)\n", name);
496 
497 	if (mdev) {
498 		pr_err("channel already linked\n");
499 		return -EEXIST;
500 	}
501 
502 	if (ccfg->direction != MOST_CH_RX) {
503 		pr_err("wrong direction, expect rx\n");
504 		return -EINVAL;
505 	}
506 
507 	if (ccfg->data_type != MOST_CH_SYNC &&
508 	    ccfg->data_type != MOST_CH_ISOC) {
509 		pr_err("wrong channel type, expect sync or isoc\n");
510 		return -EINVAL;
511 	}
512 
513 	mdev = kzalloc(sizeof(*mdev), GFP_KERNEL);
514 	if (!mdev)
515 		return -ENOMEM;
516 
517 	mutex_init(&mdev->lock);
518 	atomic_set(&mdev->access_ref, -1);
519 	spin_lock_init(&mdev->list_lock);
520 	INIT_LIST_HEAD(&mdev->pending_mbos);
521 	mdev->iface = iface;
522 	mdev->ch_idx = channel_idx;
523 	mdev->v4l2_dev.release = aim_v4l2_dev_release;
524 
525 	/* Create the v4l2_device */
526 	strlcpy(mdev->v4l2_dev.name, name, sizeof(mdev->v4l2_dev.name));
527 	ret = v4l2_device_register(NULL, &mdev->v4l2_dev);
528 	if (ret) {
529 		pr_err("v4l2_device_register() failed\n");
530 		kfree(mdev);
531 		return ret;
532 	}
533 
534 	ret = aim_register_videodev(mdev);
535 	if (ret)
536 		goto err_unreg;
537 
538 	spin_lock_irq(&list_lock);
539 	list_add(&mdev->list, &video_devices);
540 	spin_unlock_irq(&list_lock);
541 	v4l2_info(&mdev->v4l2_dev, "aim_probe_channel() done\n");
542 	return 0;
543 
544 err_unreg:
545 	v4l2_device_disconnect(&mdev->v4l2_dev);
546 	v4l2_device_put(&mdev->v4l2_dev);
547 	return ret;
548 }
549 
aim_disconnect_channel(struct most_interface * iface,int channel_idx)550 static int aim_disconnect_channel(struct most_interface *iface,
551 				  int channel_idx)
552 {
553 	struct most_video_dev *mdev = get_aim_dev(iface, channel_idx);
554 
555 	if (!mdev) {
556 		pr_err("no such channel is linked\n");
557 		return -ENOENT;
558 	}
559 
560 	v4l2_info(&mdev->v4l2_dev, "aim_disconnect_channel()\n");
561 
562 	spin_lock_irq(&list_lock);
563 	list_del(&mdev->list);
564 	spin_unlock_irq(&list_lock);
565 
566 	aim_unregister_videodev(mdev);
567 	v4l2_device_disconnect(&mdev->v4l2_dev);
568 	v4l2_device_put(&mdev->v4l2_dev);
569 	return 0;
570 }
571 
572 static struct most_aim aim_info = {
573 	.name = "v4l",
574 	.probe_channel = aim_probe_channel,
575 	.disconnect_channel = aim_disconnect_channel,
576 	.rx_completion = aim_rx_data,
577 };
578 
aim_init(void)579 static int __init aim_init(void)
580 {
581 	spin_lock_init(&list_lock);
582 	return most_register_aim(&aim_info);
583 }
584 
aim_exit(void)585 static void __exit aim_exit(void)
586 {
587 	struct most_video_dev *mdev, *tmp;
588 
589 	/*
590 	 * As the mostcore currently doesn't call disconnect_channel()
591 	 * for linked channels while we call most_deregister_aim()
592 	 * we simulate this call here.
593 	 * This must be fixed in core.
594 	 */
595 	spin_lock_irq(&list_lock);
596 	list_for_each_entry_safe(mdev, tmp, &video_devices, list) {
597 		list_del(&mdev->list);
598 		spin_unlock_irq(&list_lock);
599 
600 		aim_unregister_videodev(mdev);
601 		v4l2_device_disconnect(&mdev->v4l2_dev);
602 		v4l2_device_put(&mdev->v4l2_dev);
603 		spin_lock_irq(&list_lock);
604 	}
605 	spin_unlock_irq(&list_lock);
606 
607 	most_deregister_aim(&aim_info);
608 	BUG_ON(!list_empty(&video_devices));
609 }
610 
611 module_init(aim_init);
612 module_exit(aim_exit);
613 
614 MODULE_DESCRIPTION("V4L2 Application Interface Module for MostCore");
615 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
616 MODULE_LICENSE("GPL");
617