• 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 	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 
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 	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 
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 			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 
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 	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 
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 	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 
vidioc_g_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)289 static 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 
vidioc_try_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)298 static 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 
vidioc_s_fmt_vid_cap(struct file * file,void * priv,struct v4l2_format * f)307 static 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 
vidioc_g_std(struct file * file,void * priv,v4l2_std_id * norm)316 static 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 
vidioc_enum_input(struct file * file,void * priv,struct v4l2_input * input)324 static 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 
vidioc_g_input(struct file * file,void * priv,unsigned int * i)342 static 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 
vidioc_s_input(struct file * file,void * priv,unsigned int index)350 static 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 
363 static 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 
372 static 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 
384 static 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 
get_aim_dev(struct most_interface * iface,int channel_idx)393 static 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 
aim_rx_data(struct mbo * mbo)409 static 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 
aim_register_videodev(struct most_video_dev * mdev)429 static 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 
460 err_vbi_dev:
461 	video_device_release(mdev->vdev);
462 	return ret;
463 }
464 
aim_unregister_videodev(struct most_video_dev * mdev)465 static 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 
aim_v4l2_dev_release(struct v4l2_device * v4l2_dev)472 static 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 
aim_probe_channel(struct most_interface * iface,int channel_idx,struct most_channel_config * ccfg,struct kobject * parent,char * name)481 static 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 
537 err_unreg:
538 	v4l2_device_disconnect(&mdev->v4l2_dev);
539 	v4l2_device_put(&mdev->v4l2_dev);
540 	return ret;
541 }
542 
aim_disconnect_channel(struct most_interface * iface,int channel_idx)543 static 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 
565 static 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 
aim_init(void)572 static int __init aim_init(void)
573 {
574 	spin_lock_init(&list_lock);
575 	return most_register_aim(&aim_info);
576 }
577 
aim_exit(void)578 static 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 
604 module_init(aim_init);
605 module_exit(aim_exit);
606 
607 MODULE_DESCRIPTION("V4L2 Application Interface Module for MostCore");
608 MODULE_AUTHOR("Andrey Shvetsov <andrey.shvetsov@k2l.de>");
609 MODULE_LICENSE("GPL");
610