2018-03-03 23:43:14 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
|
|
|
//
|
|
|
|
// em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
|
|
|
|
// video capture devices
|
|
|
|
//
|
|
|
|
// Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
|
|
|
|
// Markus Rechberger <mrechberger@gmail.com>
|
MAINTAINERS & files: Canonize the e-mails I use at files
From now on, I'll start using my @kernel.org as my development e-mail.
As such, let's remove the entries that point to the old
mchehab@s-opensource.com at MAINTAINERS file.
For the files written with a copyright with mchehab@s-opensource,
let's keep Samsung on their names, using mchehab+samsung@kernel.org,
in order to keep pointing to my employer, with sponsors the work.
For the files written before I join Samsung (on July, 4 2013),
let's just use mchehab@kernel.org.
For bug reports, we can simply point to just kernel.org, as
this will reach my mchehab+samsung inbox anyway.
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Brian Warner <brian.warner@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-04-25 17:34:48 +08:00
|
|
|
// Mauro Carvalho Chehab <mchehab@kernel.org>
|
2018-03-03 23:43:14 +08:00
|
|
|
// Sascha Sommer <saschasommer@freenet.de>
|
|
|
|
// Copyright (C) 2012 Frank Schäfer <fschaefer.oss@googlemail.com>
|
|
|
|
//
|
|
|
|
// Some parts based on SN9C10x PC Camera Controllers GPL driver made
|
|
|
|
// by Luca Risolia <luca.risolia@studio.unibo.it>
|
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation; either version 2 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2016-10-12 18:26:47 +08:00
|
|
|
#include "em28xx.h"
|
|
|
|
|
2005-11-09 13:37:07 +08:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kernel.h>
|
2006-01-24 03:11:08 +08:00
|
|
|
#include <linux/bitmap.h>
|
2005-11-09 13:37:07 +08:00
|
|
|
#include <linux/usb.h>
|
|
|
|
#include <linux/i2c.h>
|
2007-11-01 12:16:09 +08:00
|
|
|
#include <linux/mm.h>
|
2006-01-15 17:52:23 +08:00
|
|
|
#include <linux/mutex.h>
|
include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files. percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.
percpu.h -> slab.h dependency is about to be removed. Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability. As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.
http://userweb.kernel.org/~tj/misc/slabh-sweep.py
The script does the followings.
* Scan files for gfp and slab usages and update includes such that
only the necessary includes are there. ie. if only gfp is used,
gfp.h, if slab is used, slab.h.
* When the script inserts a new include, it looks at the include
blocks and try to put the new include such that its order conforms
to its surrounding. It's put in the include block which contains
core kernel includes, in the same order that the rest are ordered -
alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
doesn't seem to be any matching order.
* If the script can't find a place to put a new include (mostly
because the file doesn't have fitting include block), it prints out
an error message indicating which .h file needs to be added to the
file.
The conversion was done in the following steps.
1. The initial automatic conversion of all .c files updated slightly
over 4000 files, deleting around 700 includes and adding ~480 gfp.h
and ~3000 slab.h inclusions. The script emitted errors for ~400
files.
2. Each error was manually checked. Some didn't need the inclusion,
some needed manual addition while adding it to implementation .h or
embedding .c file was more appropriate for others. This step added
inclusions to around 150 files.
3. The script was run again and the output was compared to the edits
from #2 to make sure no file was left behind.
4. Several build tests were done and a couple of problems were fixed.
e.g. lib/decompress_*.c used malloc/free() wrappers around slab
APIs requiring slab.h to be added manually.
5. The script was run on all .h files but without automatically
editing them as sprinkling gfp.h and slab.h inclusions around .h
files could easily lead to inclusion dependency hell. Most gfp.h
inclusion directives were ignored as stuff from gfp.h was usually
wildly available and often used in preprocessor macros. Each
slab.h inclusion directive was examined and added manually as
necessary.
6. percpu.h was updated not to include slab.h.
7. Build test were done on the following configurations and failures
were fixed. CONFIG_GCOV_KERNEL was turned off for all tests (as my
distributed build env didn't work with gcov compiles) and a few
more options had to be turned off depending on archs to make things
build (like ipr on powerpc/64 which failed due to missing writeq).
* x86 and x86_64 UP and SMP allmodconfig and a custom test config.
* powerpc and powerpc64 SMP allmodconfig
* sparc and sparc64 SMP allmodconfig
* ia64 SMP allmodconfig
* s390 SMP allmodconfig
* alpha SMP allmodconfig
* um on x86_64 SMP allmodconfig
8. percpu.h modifications were reverted so that it could be applied as
a separate patch and serve as bisection point.
Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.
Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-24 16:04:11 +08:00
|
|
|
#include <linux/slab.h>
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
#include "em28xx-v4l.h"
|
2006-01-10 01:25:14 +08:00
|
|
|
#include <media/v4l2-common.h>
|
2008-07-20 19:12:02 +08:00
|
|
|
#include <media/v4l2-ioctl.h>
|
2012-09-07 17:10:12 +08:00
|
|
|
#include <media/v4l2-event.h>
|
2015-11-14 05:40:07 +08:00
|
|
|
#include <media/drv-intf/msp3400.h>
|
V4L/DVB (7060): em28xx: remove has_tuner
has_tuner flag doesn't make much sense, since tuner_type=TUNER_ABSENT
means the same thing.
Having two ways to say that a tuner is not present is
not nice, since it may lead to bad setups. In fact, with the previous
code, if a device were using has_tuner=0, but the user forces a tuner,
with modprobe option tuner=type, the modprobe option won't work.
Also, tveeprom returns TUNER_ABSENT, when tuner is unknown or absent.
So, with the previous logic, in this case, the driver should set
has_tuner=0, or has_tuner=1 otherwise.
Instead of adding several additional tests and setups, better just to
remove .has_tuner.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-01-24 17:59:20 +08:00
|
|
|
#include <media/tuner.h>
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2005-11-09 13:38:25 +08:00
|
|
|
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
|
|
|
|
"Markus Rechberger <mrechberger@gmail.com>, " \
|
MAINTAINERS & files: Canonize the e-mails I use at files
From now on, I'll start using my @kernel.org as my development e-mail.
As such, let's remove the entries that point to the old
mchehab@s-opensource.com at MAINTAINERS file.
For the files written with a copyright with mchehab@s-opensource,
let's keep Samsung on their names, using mchehab+samsung@kernel.org,
in order to keep pointing to my employer, with sponsors the work.
For the files written before I join Samsung (on July, 4 2013),
let's just use mchehab@kernel.org.
For bug reports, we can simply point to just kernel.org, as
this will reach my mchehab+samsung inbox anyway.
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Brian Warner <brian.warner@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-04-25 17:34:48 +08:00
|
|
|
"Mauro Carvalho Chehab <mchehab@kernel.org>, " \
|
2005-11-09 13:38:25 +08:00
|
|
|
"Sascha Sommer <saschasommer@freenet.de>"
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2013-12-23 02:28:26 +08:00
|
|
|
static unsigned int isoc_debug;
|
|
|
|
module_param(isoc_debug, int, 0644);
|
|
|
|
MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
|
|
|
|
|
|
|
|
static unsigned int disable_vbi;
|
|
|
|
module_param(disable_vbi, int, 0644);
|
|
|
|
MODULE_PARM_DESC(disable_vbi, "disable vbi support");
|
|
|
|
|
|
|
|
static int alt;
|
|
|
|
module_param(alt, int, 0644);
|
|
|
|
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
|
|
|
|
|
2016-10-20 18:42:03 +08:00
|
|
|
#define em28xx_videodbg(fmt, arg...) do { \
|
|
|
|
if (video_debug) \
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_printk(KERN_DEBUG, &dev->intf->dev, \
|
2016-10-20 18:42:03 +08:00
|
|
|
"video: %s: " fmt, __func__, ## arg); \
|
|
|
|
} while (0)
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2016-10-12 18:32:23 +08:00
|
|
|
#define em28xx_isocdbg(fmt, arg...) do {\
|
|
|
|
if (isoc_debug) \
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_printk(KERN_DEBUG, &dev->intf->dev, \
|
2016-10-20 18:42:03 +08:00
|
|
|
"isoc: %s: " fmt, __func__, ## arg); \
|
|
|
|
} while (0)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2005-11-09 13:37:07 +08:00
|
|
|
MODULE_AUTHOR(DRIVER_AUTHOR);
|
2013-12-27 22:14:59 +08:00
|
|
|
MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
|
2018-03-03 23:43:14 +08:00
|
|
|
MODULE_LICENSE("GPL v2");
|
[media] Stop using linux/version.h on most video drivers
All the modified drivers didn't have any version increment since
Jan, 1 2011. Several of them didn't have any version increment
for a long time, even having new features and important bug fixes
happening.
As we're now filling the QUERYCAP version with the current Kernel
Release, we don't need to maintain a per-driver version control
anymore. So, let's just use the default.
In order to preserve the Kernel module version history, a
KERNEL_VERSION() macro were added to all modified drivers, and
the extraver number were incremented.
I opted to preserve the per-driver version control to a few
pwc, pvrusb2, s2255, s5p-fimc and sh_vou.
A few drivers are still using the legacy way to handle ioctl's.
So, we can't do such change on them, otherwise, they'll break.
Those are: uvc, et61x251 and sn9c102.
The rationale is that the per-driver version control seems to be
actively maintained on those.
Yet, I think that the better for them would be to just use the
default version numbering, instead of doing that by themselves.
While here, removed a few uneeded include linux/version.h
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-06-25 01:45:49 +08:00
|
|
|
MODULE_VERSION(EM28XX_VERSION);
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2013-03-27 00:38:38 +08:00
|
|
|
#define EM25XX_FRMDATAHDR_BYTE1 0x02
|
|
|
|
#define EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE 0x20
|
|
|
|
#define EM25XX_FRMDATAHDR_BYTE2_FRAME_END 0x02
|
|
|
|
#define EM25XX_FRMDATAHDR_BYTE2_FRAME_ID 0x01
|
|
|
|
#define EM25XX_FRMDATAHDR_BYTE2_MASK (EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE | \
|
|
|
|
EM25XX_FRMDATAHDR_BYTE2_FRAME_END | \
|
|
|
|
EM25XX_FRMDATAHDR_BYTE2_FRAME_ID)
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
|
|
|
|
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
|
|
|
|
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
|
2008-01-06 04:22:01 +08:00
|
|
|
|
2006-01-24 03:11:08 +08:00
|
|
|
module_param_array(video_nr, int, NULL, 0444);
|
|
|
|
module_param_array(vbi_nr, int, NULL, 0444);
|
2008-01-06 04:22:01 +08:00
|
|
|
module_param_array(radio_nr, int, NULL, 0444);
|
|
|
|
MODULE_PARM_DESC(video_nr, "video device numbers");
|
|
|
|
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
|
|
|
|
MODULE_PARM_DESC(radio_nr, "radio device numbers");
|
2005-11-09 13:37:24 +08:00
|
|
|
|
2008-04-23 01:41:48 +08:00
|
|
|
static unsigned int video_debug;
|
2008-04-18 08:41:10 +08:00
|
|
|
module_param(video_debug, int, 0644);
|
|
|
|
MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2008-12-20 20:06:37 +08:00
|
|
|
/* supported video standards */
|
|
|
|
static struct em28xx_fmt format[] = {
|
|
|
|
{
|
2009-07-03 13:54:18 +08:00
|
|
|
.name = "16 bpp YUY2, 4:2:2, packed",
|
2008-12-20 20:06:37 +08:00
|
|
|
.fourcc = V4L2_PIX_FMT_YUYV,
|
|
|
|
.depth = 16,
|
2008-12-30 10:34:37 +08:00
|
|
|
.reg = EM28XX_OUTFMT_YUV422_Y0UY1V,
|
2009-06-30 19:36:17 +08:00
|
|
|
}, {
|
2009-07-03 13:54:18 +08:00
|
|
|
.name = "16 bpp RGB 565, LE",
|
2009-06-30 19:36:17 +08:00
|
|
|
.fourcc = V4L2_PIX_FMT_RGB565,
|
|
|
|
.depth = 16,
|
2009-07-03 13:54:18 +08:00
|
|
|
.reg = EM28XX_OUTFMT_RGB_16_656,
|
2017-04-15 18:05:04 +08:00
|
|
|
}, {
|
|
|
|
.name = "8 bpp Bayer RGRG..GBGB",
|
|
|
|
.fourcc = V4L2_PIX_FMT_SRGGB8,
|
|
|
|
.depth = 8,
|
|
|
|
.reg = EM28XX_OUTFMT_RGB_8_RGRG,
|
2009-07-03 13:54:18 +08:00
|
|
|
}, {
|
|
|
|
.name = "8 bpp Bayer BGBG..GRGR",
|
|
|
|
.fourcc = V4L2_PIX_FMT_SBGGR8,
|
|
|
|
.depth = 8,
|
|
|
|
.reg = EM28XX_OUTFMT_RGB_8_BGBG,
|
|
|
|
}, {
|
|
|
|
.name = "8 bpp Bayer GRGR..BGBG",
|
|
|
|
.fourcc = V4L2_PIX_FMT_SGRBG8,
|
|
|
|
.depth = 8,
|
|
|
|
.reg = EM28XX_OUTFMT_RGB_8_GRGR,
|
|
|
|
}, {
|
|
|
|
.name = "8 bpp Bayer GBGB..RGRG",
|
|
|
|
.fourcc = V4L2_PIX_FMT_SGBRG8,
|
|
|
|
.depth = 8,
|
|
|
|
.reg = EM28XX_OUTFMT_RGB_8_GBGB,
|
|
|
|
}, {
|
|
|
|
.name = "12 bpp YUV411",
|
|
|
|
.fourcc = V4L2_PIX_FMT_YUV411P,
|
|
|
|
.depth = 12,
|
|
|
|
.reg = EM28XX_OUTFMT_YUV411,
|
2008-12-20 20:06:37 +08:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2014-03-22 21:01:03 +08:00
|
|
|
/*FIXME: maxw should be dependent of alt mode */
|
|
|
|
static inline unsigned int norm_maxw(struct em28xx *dev)
|
|
|
|
{
|
2014-03-25 03:33:19 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2014-03-25 03:33:19 +08:00
|
|
|
return v4l2->sensor_xres;
|
2014-03-22 21:01:03 +08:00
|
|
|
|
|
|
|
if (dev->board.max_range_640_480)
|
|
|
|
return 640;
|
|
|
|
|
|
|
|
return 720;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int norm_maxh(struct em28xx *dev)
|
|
|
|
{
|
2014-03-25 03:33:16 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2014-03-25 03:33:19 +08:00
|
|
|
return v4l2->sensor_yres;
|
2014-03-22 21:01:03 +08:00
|
|
|
|
|
|
|
if (dev->board.max_range_640_480)
|
|
|
|
return 480;
|
|
|
|
|
2014-03-25 03:33:16 +08:00
|
|
|
return (v4l2->norm & V4L2_STD_625_50) ? 576 : 480;
|
2014-03-22 21:01:03 +08:00
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_vbi_supported(struct em28xx *dev)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
|
|
|
/* Modprobe option to manually disable */
|
|
|
|
if (disable_vbi == 1)
|
|
|
|
return 0;
|
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2013-12-23 02:28:26 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* FIXME: check subdevices for VBI support */
|
|
|
|
|
|
|
|
if (dev->chip_id == CHIP_ID_EM2860 ||
|
|
|
|
dev->chip_id == CHIP_ID_EM2883)
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
/* Version of em28xx that does not support VBI */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* em28xx_wake_i2c()
|
|
|
|
* configure i2c attached devices
|
|
|
|
*/
|
2013-12-23 00:27:02 +08:00
|
|
|
static void em28xx_wake_i2c(struct em28xx *dev)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
2014-03-25 03:33:09 +08:00
|
|
|
struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
|
2014-11-28 19:34:15 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, core, reset, 0);
|
|
|
|
v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
|
2014-11-28 19:34:15 +08:00
|
|
|
INPUT(dev->ctl_input)->vmux, 0, 0);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_colorlevels_set_default(struct em28xx *dev)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
|
|
|
em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
|
|
|
|
|
|
|
|
em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
|
|
|
|
return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
|
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_set_outfmt(struct em28xx *dev)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
u8 fmt, vinctrl;
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2013-12-23 02:28:26 +08:00
|
|
|
|
2014-03-25 03:33:17 +08:00
|
|
|
fmt = v4l2->format->reg;
|
2013-12-23 02:28:26 +08:00
|
|
|
if (!dev->is_em25xx)
|
|
|
|
fmt |= 0x20;
|
|
|
|
/*
|
|
|
|
* NOTE: it's not clear if this is really needed !
|
|
|
|
* The datasheets say bit 5 is a reserved bit and devices seem to work
|
|
|
|
* fine without it. But the Windows driver sets it for em2710/50+em28xx
|
|
|
|
* devices and we've always been setting it, too.
|
|
|
|
*
|
|
|
|
* em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
|
|
|
|
* it's likely used for an additional (compressed ?) format there.
|
|
|
|
*/
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-03-25 03:33:15 +08:00
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, v4l2->vinmode);
|
2013-12-23 02:28:26 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2014-03-25 03:33:15 +08:00
|
|
|
vinctrl = v4l2->vinctl;
|
2013-12-23 02:28:26 +08:00
|
|
|
if (em28xx_vbi_supported(dev) == 1) {
|
|
|
|
vinctrl |= EM28XX_VINCTRL_VBI_RAW;
|
|
|
|
em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
|
2018-03-04 03:49:09 +08:00
|
|
|
em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH,
|
|
|
|
v4l2->vbi_width / 4);
|
2014-03-25 03:33:14 +08:00
|
|
|
em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height);
|
2014-03-25 03:33:16 +08:00
|
|
|
if (v4l2->norm & V4L2_STD_525_60) {
|
2013-12-23 02:28:26 +08:00
|
|
|
/* NTSC */
|
|
|
|
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
|
2014-03-25 03:33:16 +08:00
|
|
|
} else if (v4l2->norm & V4L2_STD_625_50) {
|
2013-12-23 02:28:26 +08:00
|
|
|
/* PAL */
|
|
|
|
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
|
|
|
|
u8 ymin, u8 ymax)
|
|
|
|
{
|
|
|
|
em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
|
|
|
|
xmin, ymin, xmax, ymax);
|
|
|
|
|
|
|
|
em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
|
|
|
|
em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
|
|
|
|
em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
|
|
|
|
return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
|
2014-11-28 19:34:15 +08:00
|
|
|
u16 width, u16 height)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
|
|
|
u8 cwidth = width >> 2;
|
|
|
|
u8 cheight = height >> 2;
|
|
|
|
u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
|
|
|
|
/* NOTE: size limit: 2047x1023 = 2MPix */
|
|
|
|
|
|
|
|
em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
|
2014-11-28 19:34:15 +08:00
|
|
|
hstart, vstart,
|
2013-12-23 02:28:26 +08:00
|
|
|
((overflow & 2) << 9 | cwidth << 2),
|
|
|
|
((overflow & 1) << 10 | cheight << 2));
|
|
|
|
|
|
|
|
em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
|
|
|
|
em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
|
|
|
|
em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
|
|
|
|
em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
|
|
|
|
em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
|
|
|
|
|
|
|
|
/* FIXME: function/meaning of these registers ? */
|
|
|
|
/* FIXME: align width+height to multiples of 4 ?! */
|
|
|
|
if (dev->is_em25xx) {
|
|
|
|
em28xx_write_reg(dev, 0x34, width >> 4);
|
|
|
|
em28xx_write_reg(dev, 0x35, height >> 4);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
|
|
|
|
{
|
2014-03-25 03:28:36 +08:00
|
|
|
u8 mode = 0x00;
|
2013-12-23 02:28:26 +08:00
|
|
|
/* the em2800 scaler only supports scaling down to 50% */
|
|
|
|
|
|
|
|
if (dev->board.is_em2800) {
|
|
|
|
mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
|
|
|
|
} else {
|
|
|
|
u8 buf[2];
|
|
|
|
|
|
|
|
buf[0] = h;
|
|
|
|
buf[1] = h >> 8;
|
|
|
|
em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
|
|
|
|
|
|
|
|
buf[0] = v;
|
|
|
|
buf[1] = v >> 8;
|
|
|
|
em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* it seems that both H and V scalers must be active
|
|
|
|
* to work correctly
|
|
|
|
*/
|
2013-12-23 02:28:26 +08:00
|
|
|
mode = (h || v) ? 0x30 : 0x00;
|
|
|
|
}
|
2014-03-25 03:28:36 +08:00
|
|
|
return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* FIXME: this only function read values from dev */
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_resolution_set(struct em28xx *dev)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
int width = norm_maxw(dev);
|
|
|
|
int height = norm_maxh(dev);
|
2013-12-23 02:28:26 +08:00
|
|
|
|
|
|
|
/* Properly setup VBI */
|
2014-03-25 03:33:14 +08:00
|
|
|
v4l2->vbi_width = 720;
|
2014-03-25 03:33:16 +08:00
|
|
|
if (v4l2->norm & V4L2_STD_525_60)
|
2014-03-25 03:33:14 +08:00
|
|
|
v4l2->vbi_height = 12;
|
2013-12-23 02:28:26 +08:00
|
|
|
else
|
2014-03-25 03:33:14 +08:00
|
|
|
v4l2->vbi_height = 18;
|
2013-12-23 02:28:26 +08:00
|
|
|
|
|
|
|
em28xx_set_outfmt(dev);
|
|
|
|
|
|
|
|
em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* If we don't set the start position to 2 in VBI mode, we end up
|
|
|
|
* with line 20/21 being YUYV encoded instead of being in 8-bit
|
|
|
|
* greyscale. The core of the issue is that line 21 (and line 23 for
|
|
|
|
* PAL WSS) are inside of active video region, and as a result they
|
|
|
|
* get the pixelformatting associated with that area. So by cropping
|
|
|
|
* it out, we end up with the same format as the rest of the VBI
|
|
|
|
* region
|
|
|
|
*/
|
2013-12-23 02:28:26 +08:00
|
|
|
if (em28xx_vbi_supported(dev) == 1)
|
|
|
|
em28xx_capture_area_set(dev, 0, 2, width, height);
|
|
|
|
else
|
|
|
|
em28xx_capture_area_set(dev, 0, 0, width, height);
|
|
|
|
|
2014-03-25 03:33:14 +08:00
|
|
|
return em28xx_scaler_set(dev, v4l2->hscale, v4l2->vscale);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Set USB alternate setting for analog video */
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_set_alternate(struct em28xx *dev)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2016-12-08 00:34:22 +08:00
|
|
|
struct usb_device *udev = interface_to_usbdev(dev->intf);
|
2018-03-04 03:49:09 +08:00
|
|
|
int err;
|
2013-12-23 02:28:26 +08:00
|
|
|
int i;
|
2014-03-25 03:33:14 +08:00
|
|
|
unsigned int min_pkt_size = v4l2->width * 2 + 4;
|
2013-12-23 02:28:26 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTE: for isoc transfers, only alt settings > 0 are allowed
|
|
|
|
* bulk transfers seem to work only with alt=0 !
|
|
|
|
*/
|
2013-12-23 02:28:26 +08:00
|
|
|
dev->alt = 0;
|
2018-03-04 03:49:09 +08:00
|
|
|
if (alt > 0 && alt < dev->num_alt) {
|
2013-12-23 02:28:26 +08:00
|
|
|
em28xx_videodbg("alternate forced to %d\n", dev->alt);
|
|
|
|
dev->alt = alt;
|
|
|
|
goto set_alt;
|
|
|
|
}
|
|
|
|
if (dev->analog_xfer_bulk)
|
|
|
|
goto set_alt;
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* When image size is bigger than a certain value,
|
|
|
|
* the frame size should be increased, otherwise, only
|
|
|
|
* green screen will be received.
|
2013-12-23 02:28:26 +08:00
|
|
|
*/
|
2014-03-25 03:33:14 +08:00
|
|
|
if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2)
|
2013-12-23 02:28:26 +08:00
|
|
|
min_pkt_size *= 2;
|
|
|
|
|
|
|
|
for (i = 0; i < dev->num_alt; i++) {
|
|
|
|
/* stop when the selected alt setting offers enough bandwidth */
|
|
|
|
if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
|
|
|
|
dev->alt = i;
|
|
|
|
break;
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* otherwise make sure that we end up with the maximum
|
|
|
|
* bandwidth because the min_pkt_size equation might be wrong.
|
|
|
|
*
|
|
|
|
*/
|
2013-12-23 02:28:26 +08:00
|
|
|
} else if (dev->alt_max_pkt_size_isoc[i] >
|
|
|
|
dev->alt_max_pkt_size_isoc[dev->alt])
|
|
|
|
dev->alt = i;
|
|
|
|
}
|
|
|
|
|
|
|
|
set_alt:
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTE: for bulk transfers, we need to call usb_set_interface()
|
2013-12-23 02:28:26 +08:00
|
|
|
* even if the previous settings were the same. Otherwise streaming
|
2018-03-04 03:49:09 +08:00
|
|
|
* fails with all urbs having status = -EOVERFLOW !
|
|
|
|
*/
|
2013-12-23 02:28:26 +08:00
|
|
|
if (dev->analog_xfer_bulk) {
|
|
|
|
dev->max_pkt_size = 512; /* USB 2.0 spec */
|
|
|
|
dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
|
|
|
|
} else { /* isoc */
|
|
|
|
em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
|
2014-11-28 19:34:15 +08:00
|
|
|
min_pkt_size, dev->alt);
|
2013-12-23 02:28:26 +08:00
|
|
|
dev->max_pkt_size =
|
|
|
|
dev->alt_max_pkt_size_isoc[dev->alt];
|
|
|
|
dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
|
|
|
|
}
|
|
|
|
em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
|
2014-11-28 19:34:15 +08:00
|
|
|
dev->alt, dev->max_pkt_size);
|
2018-03-04 03:49:09 +08:00
|
|
|
err = usb_set_interface(udev, dev->ifnum, dev->alt);
|
|
|
|
if (err < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"cannot change alternate number to %d (error=%i)\n",
|
2018-03-04 03:49:09 +08:00
|
|
|
dev->alt, err);
|
|
|
|
return err;
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* DMA and thread functions
|
|
|
|
*/
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
|
|
|
/*
|
2012-12-08 22:31:25 +08:00
|
|
|
* Finish the current buffer
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
*/
|
2012-12-08 22:31:25 +08:00
|
|
|
static inline void finish_buffer(struct em28xx *dev,
|
|
|
|
struct em28xx_buffer *buf)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
2013-01-05 03:16:24 +08:00
|
|
|
em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
|
|
|
|
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
buf->vb.sequence = dev->v4l2->field_count++;
|
2014-08-09 17:37:21 +08:00
|
|
|
if (dev->v4l2->progressive)
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
buf->vb.field = V4L2_FIELD_NONE;
|
2014-08-09 17:37:21 +08:00
|
|
|
else
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
buf->vb.field = V4L2_FIELD_INTERLACED;
|
2015-11-03 18:16:37 +08:00
|
|
|
buf->vb.vb2_buf.timestamp = ktime_get_ns();
|
2013-01-05 03:16:24 +08:00
|
|
|
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-12-08 22:31:32 +08:00
|
|
|
* Copy picture data from USB buffer to videobuf buffer
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
*/
|
|
|
|
static void em28xx_copy_video(struct em28xx *dev,
|
|
|
|
struct em28xx_buffer *buf,
|
2012-12-08 22:31:32 +08:00
|
|
|
unsigned char *usb_buf,
|
2012-12-08 22:31:29 +08:00
|
|
|
unsigned long len)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
2014-03-25 03:33:18 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
void *fieldstart, *startwrite, *startread;
|
2008-04-14 01:41:23 +08:00
|
|
|
int linesdone, currlinedone, offset, lencopy, remain;
|
2014-03-25 03:33:18 +08:00
|
|
|
int bytesperline = v4l2->width << 1;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
if (buf->pos + len > buf->length)
|
|
|
|
len = buf->length - buf->pos;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2012-12-08 22:31:32 +08:00
|
|
|
startread = usb_buf;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
remain = len;
|
|
|
|
|
2014-03-25 03:33:18 +08:00
|
|
|
if (v4l2->progressive || buf->top_field)
|
2012-12-08 22:31:32 +08:00
|
|
|
fieldstart = buf->vb_buf;
|
2012-11-09 01:11:33 +08:00
|
|
|
else /* interlaced mode, even nr. of lines */
|
2012-12-08 22:31:32 +08:00
|
|
|
fieldstart = buf->vb_buf + bytesperline;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2012-12-08 22:31:27 +08:00
|
|
|
linesdone = buf->pos / bytesperline;
|
|
|
|
currlinedone = buf->pos % bytesperline;
|
2009-08-08 14:14:55 +08:00
|
|
|
|
2014-03-25 03:33:18 +08:00
|
|
|
if (v4l2->progressive)
|
2009-08-08 14:14:55 +08:00
|
|
|
offset = linesdone * bytesperline + currlinedone;
|
|
|
|
else
|
|
|
|
offset = linesdone * bytesperline * 2 + currlinedone;
|
|
|
|
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
startwrite = fieldstart + offset;
|
2008-04-14 02:11:08 +08:00
|
|
|
lencopy = bytesperline - currlinedone;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
lencopy = lencopy > remain ? remain : lencopy;
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
|
2014-09-25 07:36:07 +08:00
|
|
|
em28xx_isocdbg("Overflow of %zu bytes past buffer end (1)\n",
|
2014-11-28 19:34:15 +08:00
|
|
|
((char *)startwrite + lencopy) -
|
2013-01-05 03:16:24 +08:00
|
|
|
((char *)buf->vb_buf + buf->length));
|
|
|
|
remain = (char *)buf->vb_buf + buf->length -
|
2012-12-08 22:31:32 +08:00
|
|
|
(char *)startwrite;
|
2009-02-11 10:28:24 +08:00
|
|
|
lencopy = remain;
|
2008-04-14 01:38:47 +08:00
|
|
|
}
|
2008-04-14 01:56:02 +08:00
|
|
|
if (lencopy <= 0)
|
|
|
|
return;
|
2008-04-14 01:38:47 +08:00
|
|
|
memcpy(startwrite, startread, lencopy);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
|
|
|
remain -= lencopy;
|
|
|
|
|
|
|
|
while (remain > 0) {
|
2014-03-25 03:33:18 +08:00
|
|
|
if (v4l2->progressive)
|
2012-11-09 01:11:33 +08:00
|
|
|
startwrite += lencopy;
|
|
|
|
else
|
|
|
|
startwrite += lencopy + bytesperline;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
startread += lencopy;
|
2008-04-14 02:11:08 +08:00
|
|
|
if (bytesperline > remain)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
lencopy = remain;
|
|
|
|
else
|
2008-04-14 02:11:08 +08:00
|
|
|
lencopy = bytesperline;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2012-12-08 22:31:32 +08:00
|
|
|
if ((char *)startwrite + lencopy > (char *)buf->vb_buf +
|
2013-01-05 03:16:24 +08:00
|
|
|
buf->length) {
|
2016-10-12 18:05:48 +08:00
|
|
|
em28xx_isocdbg("Overflow of %zu bytes past buffer end(2)\n",
|
2008-04-14 01:41:23 +08:00
|
|
|
((char *)startwrite + lencopy) -
|
2013-01-05 03:16:24 +08:00
|
|
|
((char *)buf->vb_buf + buf->length));
|
2018-03-04 03:49:09 +08:00
|
|
|
remain = (char *)buf->vb_buf + buf->length -
|
|
|
|
(char *)startwrite;
|
|
|
|
lencopy = remain;
|
2008-04-14 01:38:47 +08:00
|
|
|
}
|
2008-04-14 01:41:23 +08:00
|
|
|
if (lencopy <= 0)
|
|
|
|
break;
|
2008-04-14 01:38:47 +08:00
|
|
|
|
|
|
|
memcpy(startwrite, startread, lencopy);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
|
|
|
remain -= lencopy;
|
|
|
|
}
|
|
|
|
|
2012-12-08 22:31:27 +08:00
|
|
|
buf->pos += len;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
}
|
|
|
|
|
2012-12-08 22:31:32 +08:00
|
|
|
/*
|
|
|
|
* Copy VBI data from USB buffer to videobuf buffer
|
|
|
|
*/
|
2009-09-01 12:54:54 +08:00
|
|
|
static void em28xx_copy_vbi(struct em28xx *dev,
|
2012-12-08 22:31:27 +08:00
|
|
|
struct em28xx_buffer *buf,
|
2012-12-08 22:31:32 +08:00
|
|
|
unsigned char *usb_buf,
|
2012-12-08 22:31:29 +08:00
|
|
|
unsigned long len)
|
2009-09-01 12:54:54 +08:00
|
|
|
{
|
2012-12-08 22:31:32 +08:00
|
|
|
unsigned int offset;
|
2009-09-01 12:54:54 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
if (buf->pos + len > buf->length)
|
|
|
|
len = buf->length - buf->pos;
|
2009-09-01 12:54:54 +08:00
|
|
|
|
2012-12-08 22:31:27 +08:00
|
|
|
offset = buf->pos;
|
2009-09-01 12:54:54 +08:00
|
|
|
/* Make sure the bottom field populates the second half of the frame */
|
2012-12-08 22:31:32 +08:00
|
|
|
if (buf->top_field == 0)
|
2014-03-25 03:33:14 +08:00
|
|
|
offset += dev->v4l2->vbi_width * dev->v4l2->vbi_height;
|
2009-09-01 12:54:54 +08:00
|
|
|
|
2012-12-08 22:31:32 +08:00
|
|
|
memcpy(buf->vb_buf + offset, usb_buf, len);
|
2012-12-08 22:31:27 +08:00
|
|
|
buf->pos += len;
|
2009-09-01 12:54:54 +08:00
|
|
|
}
|
|
|
|
|
2008-04-14 01:41:23 +08:00
|
|
|
static inline void print_err_status(struct em28xx *dev,
|
2014-11-28 19:34:15 +08:00
|
|
|
int packet, int status)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
|
|
|
char *errmsg = "Unknown";
|
|
|
|
|
2008-04-14 01:41:23 +08:00
|
|
|
switch (status) {
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
case -ENOENT:
|
2017-11-02 18:11:53 +08:00
|
|
|
errmsg = "unlinked synchronously";
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
break;
|
|
|
|
case -ECONNRESET:
|
2017-11-02 18:11:53 +08:00
|
|
|
errmsg = "unlinked asynchronously";
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
break;
|
|
|
|
case -ENOSR:
|
|
|
|
errmsg = "Buffer error (overrun)";
|
|
|
|
break;
|
|
|
|
case -EPIPE:
|
|
|
|
errmsg = "Stalled (device not responding)";
|
|
|
|
break;
|
|
|
|
case -EOVERFLOW:
|
|
|
|
errmsg = "Babble (bad cable?)";
|
|
|
|
break;
|
|
|
|
case -EPROTO:
|
|
|
|
errmsg = "Bit-stuff error (bad cable?)";
|
|
|
|
break;
|
|
|
|
case -EILSEQ:
|
|
|
|
errmsg = "CRC/Timeout (could be anything)";
|
|
|
|
break;
|
|
|
|
case -ETIME:
|
|
|
|
errmsg = "Device does not respond";
|
|
|
|
break;
|
|
|
|
}
|
2008-04-14 01:41:23 +08:00
|
|
|
if (packet < 0) {
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
|
|
|
|
} else {
|
|
|
|
em28xx_isocdbg("URB packet %d, status %d [%s].\n",
|
|
|
|
packet, status, errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2012-12-08 22:31:24 +08:00
|
|
|
* get the next available buffer from dma queue
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
*/
|
2012-12-08 22:31:24 +08:00
|
|
|
static inline struct em28xx_buffer *get_next_buf(struct em28xx *dev,
|
|
|
|
struct em28xx_dmaqueue *dma_q)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
2012-12-08 22:31:24 +08:00
|
|
|
struct em28xx_buffer *buf;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2008-04-14 02:08:55 +08:00
|
|
|
if (list_empty(&dma_q->active)) {
|
|
|
|
em28xx_isocdbg("No active queue to serve\n");
|
2012-12-08 22:31:24 +08:00
|
|
|
return NULL;
|
2009-09-01 12:54:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the next buffer */
|
2013-01-05 03:16:24 +08:00
|
|
|
buf = list_entry(dma_q->active.next, struct em28xx_buffer, list);
|
2011-03-31 09:57:33 +08:00
|
|
|
/* Cleans up buffer - Useful for testing for frame/URB loss */
|
2013-01-05 03:16:24 +08:00
|
|
|
list_del(&buf->list);
|
2012-12-08 22:31:27 +08:00
|
|
|
buf->pos = 0;
|
2013-01-05 03:16:24 +08:00
|
|
|
buf->vb_buf = buf->mem;
|
2008-04-14 02:06:52 +08:00
|
|
|
|
2012-12-08 22:31:24 +08:00
|
|
|
return buf;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
}
|
|
|
|
|
2012-12-08 22:31:30 +08:00
|
|
|
/*
|
|
|
|
* Finish the current buffer if completed and prepare for the next field
|
|
|
|
*/
|
|
|
|
static struct em28xx_buffer *
|
|
|
|
finish_field_prepare_next(struct em28xx *dev,
|
|
|
|
struct em28xx_buffer *buf,
|
|
|
|
struct em28xx_dmaqueue *dma_q)
|
|
|
|
{
|
2014-03-25 03:33:18 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
|
2014-03-25 03:33:20 +08:00
|
|
|
if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */
|
2018-03-04 03:49:09 +08:00
|
|
|
if (buf)
|
2012-12-08 22:31:30 +08:00
|
|
|
finish_buffer(dev, buf);
|
|
|
|
buf = get_next_buf(dev, dma_q);
|
|
|
|
}
|
2018-03-04 03:49:09 +08:00
|
|
|
if (buf) {
|
2014-03-25 03:33:20 +08:00
|
|
|
buf->top_field = v4l2->top_field;
|
2012-12-08 22:31:30 +08:00
|
|
|
buf->pos = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2012-12-08 22:31:31 +08:00
|
|
|
/*
|
|
|
|
* Process data packet according to the em2710/em2750/em28xx frame data format
|
|
|
|
*/
|
|
|
|
static inline void process_frame_data_em28xx(struct em28xx *dev,
|
|
|
|
unsigned char *data_pkt,
|
|
|
|
unsigned int data_len)
|
2009-09-01 12:19:46 +08:00
|
|
|
{
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2012-12-08 22:31:31 +08:00
|
|
|
struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
|
|
|
|
struct em28xx_buffer *vbi_buf = dev->usb_ctl.vbi_buf;
|
2009-09-01 12:19:46 +08:00
|
|
|
struct em28xx_dmaqueue *dma_q = &dev->vidq;
|
2009-09-01 12:54:54 +08:00
|
|
|
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
|
2012-12-08 22:31:31 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* capture type 0 = vbi start
|
|
|
|
* capture type 1 = vbi in progress
|
|
|
|
* capture type 2 = video start
|
|
|
|
* capture type 3 = video in progress
|
|
|
|
*/
|
2012-12-08 22:31:31 +08:00
|
|
|
if (data_len >= 4) {
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTE: Headers are always 4 bytes and
|
|
|
|
* never split across packets
|
|
|
|
*/
|
2012-12-08 22:31:31 +08:00
|
|
|
if (data_pkt[0] == 0x88 && data_pkt[1] == 0x88 &&
|
|
|
|
data_pkt[2] == 0x88 && data_pkt[3] == 0x88) {
|
|
|
|
/* Continuation */
|
|
|
|
data_pkt += 4;
|
|
|
|
data_len -= 4;
|
|
|
|
} else if (data_pkt[0] == 0x33 && data_pkt[1] == 0x95) {
|
|
|
|
/* Field start (VBI mode) */
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->capture_type = 0;
|
|
|
|
v4l2->vbi_read = 0;
|
2012-12-08 22:31:31 +08:00
|
|
|
em28xx_isocdbg("VBI START HEADER !!!\n");
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->top_field = !(data_pkt[2] & 1);
|
2012-12-08 22:31:31 +08:00
|
|
|
data_pkt += 4;
|
|
|
|
data_len -= 4;
|
|
|
|
} else if (data_pkt[0] == 0x22 && data_pkt[1] == 0x5a) {
|
|
|
|
/* Field start (VBI disabled) */
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->capture_type = 2;
|
2012-12-08 22:31:31 +08:00
|
|
|
em28xx_isocdbg("VIDEO START HEADER !!!\n");
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->top_field = !(data_pkt[2] & 1);
|
2012-12-08 22:31:31 +08:00
|
|
|
data_pkt += 4;
|
|
|
|
data_len -= 4;
|
|
|
|
}
|
|
|
|
}
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTE: With bulk transfers, intermediate data packets
|
|
|
|
* have no continuation header
|
|
|
|
*/
|
2012-12-08 22:31:31 +08:00
|
|
|
|
2014-03-25 03:33:20 +08:00
|
|
|
if (v4l2->capture_type == 0) {
|
2012-12-08 22:31:31 +08:00
|
|
|
vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q);
|
|
|
|
dev->usb_ctl.vbi_buf = vbi_buf;
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->capture_type = 1;
|
2012-12-08 22:31:31 +08:00
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:20 +08:00
|
|
|
if (v4l2->capture_type == 1) {
|
2014-03-25 03:33:14 +08:00
|
|
|
int vbi_size = v4l2->vbi_width * v4l2->vbi_height;
|
2014-03-25 03:33:20 +08:00
|
|
|
int vbi_data_len = ((v4l2->vbi_read + data_len) > vbi_size) ?
|
|
|
|
(vbi_size - v4l2->vbi_read) : data_len;
|
2012-12-08 22:31:31 +08:00
|
|
|
|
|
|
|
/* Copy VBI data */
|
2018-03-04 03:49:09 +08:00
|
|
|
if (vbi_buf)
|
2012-12-08 22:31:31 +08:00
|
|
|
em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len);
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->vbi_read += vbi_data_len;
|
2012-12-08 22:31:31 +08:00
|
|
|
|
|
|
|
if (vbi_data_len < data_len) {
|
|
|
|
/* Continue with copying video data */
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->capture_type = 2;
|
2012-12-08 22:31:31 +08:00
|
|
|
data_pkt += vbi_data_len;
|
|
|
|
data_len -= vbi_data_len;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:20 +08:00
|
|
|
if (v4l2->capture_type == 2) {
|
2012-12-08 22:31:31 +08:00
|
|
|
buf = finish_field_prepare_next(dev, buf, dma_q);
|
|
|
|
dev->usb_ctl.vid_buf = buf;
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->capture_type = 3;
|
2012-12-08 22:31:31 +08:00
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (v4l2->capture_type == 3 && buf && data_len > 0)
|
2012-12-08 22:31:31 +08:00
|
|
|
em28xx_copy_video(dev, buf, data_pkt, data_len);
|
|
|
|
}
|
|
|
|
|
2013-03-27 00:38:38 +08:00
|
|
|
/*
|
|
|
|
* Process data packet according to the em25xx/em276x/7x/8x frame data format
|
|
|
|
*/
|
|
|
|
static inline void process_frame_data_em25xx(struct em28xx *dev,
|
|
|
|
unsigned char *data_pkt,
|
|
|
|
unsigned int data_len)
|
|
|
|
{
|
|
|
|
struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
|
|
|
|
struct em28xx_dmaqueue *dmaq = &dev->vidq;
|
2014-03-25 03:33:20 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2014-09-04 02:06:13 +08:00
|
|
|
bool frame_end = false;
|
2013-03-27 00:38:38 +08:00
|
|
|
|
|
|
|
/* Check for header */
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTE: at least with bulk transfers, only the first packet
|
|
|
|
* has a header and has always set the FRAME_END bit
|
|
|
|
*/
|
2013-03-27 00:38:38 +08:00
|
|
|
if (data_len >= 2) { /* em25xx header is only 2 bytes long */
|
|
|
|
if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) &&
|
|
|
|
((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) {
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->top_field = !(data_pkt[1] &
|
2013-03-27 00:38:38 +08:00
|
|
|
EM25XX_FRMDATAHDR_BYTE2_FRAME_ID);
|
|
|
|
frame_end = data_pkt[1] &
|
|
|
|
EM25XX_FRMDATAHDR_BYTE2_FRAME_END;
|
|
|
|
data_pkt += 2;
|
|
|
|
data_len -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finish field and prepare next (BULK only) */
|
|
|
|
if (dev->analog_xfer_bulk && frame_end) {
|
|
|
|
buf = finish_field_prepare_next(dev, buf, dmaq);
|
|
|
|
dev->usb_ctl.vid_buf = buf;
|
|
|
|
}
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTE: in ISOC mode when a new frame starts and buf==NULL,
|
2013-03-27 00:38:38 +08:00
|
|
|
* we COULD already prepare a buffer here to avoid skipping the
|
|
|
|
* first frame.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy data */
|
2018-03-04 03:49:09 +08:00
|
|
|
if (buf && data_len > 0)
|
2013-03-27 00:38:38 +08:00
|
|
|
em28xx_copy_video(dev, buf, data_pkt, data_len);
|
|
|
|
|
|
|
|
/* Finish frame (ISOC only) => avoids lag of 1 frame */
|
|
|
|
if (!dev->analog_xfer_bulk && frame_end) {
|
|
|
|
buf = finish_field_prepare_next(dev, buf, dmaq);
|
|
|
|
dev->usb_ctl.vid_buf = buf;
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* NOTES:
|
|
|
|
*
|
|
|
|
* 1) Tested with USB bulk transfers only !
|
2013-03-27 00:38:38 +08:00
|
|
|
* The wording in the datasheet suggests that isoc might work different.
|
|
|
|
* The current code assumes that with isoc transfers each packet has a
|
|
|
|
* header like with the other em28xx devices.
|
2018-03-04 03:49:09 +08:00
|
|
|
*
|
|
|
|
* 2) Support for interlaced mode is pure theory. It has not been
|
|
|
|
* tested and it is unknown if these devices actually support it.
|
2013-03-27 00:38:38 +08:00
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2012-12-08 22:31:31 +08:00
|
|
|
/* Processes and copies the URB data content (video and VBI data) */
|
|
|
|
static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
|
|
|
|
{
|
|
|
|
int xfer_bulk, num_packets, i;
|
|
|
|
unsigned char *usb_data_pkt;
|
|
|
|
unsigned int usb_data_len;
|
2009-09-01 12:19:46 +08:00
|
|
|
|
|
|
|
if (!dev)
|
|
|
|
return 0;
|
|
|
|
|
2012-12-28 06:02:43 +08:00
|
|
|
if (dev->disconnected)
|
2009-09-01 12:19:46 +08:00
|
|
|
return 0;
|
|
|
|
|
2012-11-09 01:11:44 +08:00
|
|
|
if (urb->status < 0)
|
2009-09-01 12:19:46 +08:00
|
|
|
print_err_status(dev, -1, urb->status);
|
|
|
|
|
2012-11-09 01:11:46 +08:00
|
|
|
xfer_bulk = usb_pipebulk(urb->pipe);
|
|
|
|
|
|
|
|
if (xfer_bulk) /* bulk */
|
|
|
|
num_packets = 1;
|
|
|
|
else /* isoc */
|
|
|
|
num_packets = urb->number_of_packets;
|
2009-09-01 12:19:46 +08:00
|
|
|
|
2012-11-09 01:11:46 +08:00
|
|
|
for (i = 0; i < num_packets; i++) {
|
|
|
|
if (xfer_bulk) { /* bulk */
|
2012-12-08 22:31:31 +08:00
|
|
|
usb_data_len = urb->actual_length;
|
2012-11-09 01:11:46 +08:00
|
|
|
|
2012-12-08 22:31:31 +08:00
|
|
|
usb_data_pkt = urb->transfer_buffer;
|
2012-11-09 01:11:46 +08:00
|
|
|
} else { /* isoc */
|
|
|
|
if (urb->iso_frame_desc[i].status < 0) {
|
|
|
|
print_err_status(dev, i,
|
|
|
|
urb->iso_frame_desc[i].status);
|
|
|
|
if (urb->iso_frame_desc[i].status != -EPROTO)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-12-08 22:31:31 +08:00
|
|
|
usb_data_len = urb->iso_frame_desc[i].actual_length;
|
|
|
|
if (usb_data_len > dev->max_pkt_size) {
|
2012-11-09 01:11:46 +08:00
|
|
|
em28xx_isocdbg("packet bigger than packet size");
|
2009-09-01 12:19:46 +08:00
|
|
|
continue;
|
2012-11-09 01:11:46 +08:00
|
|
|
}
|
2009-09-01 12:19:46 +08:00
|
|
|
|
2012-12-08 22:31:31 +08:00
|
|
|
usb_data_pkt = urb->transfer_buffer +
|
|
|
|
urb->iso_frame_desc[i].offset;
|
2009-09-01 12:19:46 +08:00
|
|
|
}
|
2012-11-09 01:11:46 +08:00
|
|
|
|
2012-12-08 22:31:31 +08:00
|
|
|
if (usb_data_len == 0) {
|
2012-11-09 01:11:46 +08:00
|
|
|
/* NOTE: happens very often with isoc transfers */
|
|
|
|
/* em28xx_usbdbg("packet %d is empty",i); - spammy */
|
2009-09-01 12:19:46 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2013-03-27 00:38:38 +08:00
|
|
|
if (dev->is_em25xx)
|
|
|
|
process_frame_data_em25xx(dev,
|
|
|
|
usb_data_pkt, usb_data_len);
|
|
|
|
else
|
|
|
|
process_frame_data_em28xx(dev,
|
|
|
|
usb_data_pkt, usb_data_len);
|
2009-09-01 12:19:46 +08:00
|
|
|
}
|
2012-12-08 22:31:31 +08:00
|
|
|
return 1;
|
2009-09-01 12:19:46 +08:00
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
static int get_resource(enum v4l2_buf_type f_type)
|
2013-01-05 03:16:24 +08:00
|
|
|
{
|
|
|
|
switch (f_type) {
|
|
|
|
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
|
|
|
|
return EM28XX_RESOURCE_VIDEO;
|
|
|
|
case V4L2_BUF_TYPE_VBI_CAPTURE:
|
|
|
|
return EM28XX_RESOURCE_VBI;
|
|
|
|
default:
|
2018-03-04 03:49:09 +08:00
|
|
|
WARN_ON(1);
|
|
|
|
return -1; /* Indicate that device is busy */
|
2013-01-05 03:16:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Usage lock check functions */
|
|
|
|
static int res_get(struct em28xx *dev, enum v4l2_buf_type f_type)
|
|
|
|
{
|
2018-03-04 03:49:09 +08:00
|
|
|
int res_type = get_resource(f_type);
|
2013-01-05 03:16:24 +08:00
|
|
|
|
|
|
|
/* is it free? */
|
|
|
|
if (dev->resources & res_type) {
|
|
|
|
/* no, someone else uses it */
|
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* it's free, grab it */
|
|
|
|
dev->resources |= res_type;
|
|
|
|
em28xx_videodbg("res: get %d\n", res_type);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void res_free(struct em28xx *dev, enum v4l2_buf_type f_type)
|
|
|
|
{
|
2018-03-04 03:49:09 +08:00
|
|
|
int res_type = get_resource(f_type);
|
2013-01-05 03:16:24 +08:00
|
|
|
|
|
|
|
dev->resources &= ~res_type;
|
|
|
|
em28xx_videodbg("res: put %d\n", res_type);
|
|
|
|
}
|
|
|
|
|
2016-01-27 17:07:24 +08:00
|
|
|
static void em28xx_v4l2_media_release(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_EM28XX_INPUT; i++) {
|
|
|
|
if (!INPUT(i)->type)
|
|
|
|
return;
|
|
|
|
media_device_unregister_entity(&dev->input_ent[i]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Media Controller helper functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int em28xx_enable_analog_tuner(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
|
|
|
struct media_device *mdev = dev->media_dev;
|
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
struct media_entity *source;
|
|
|
|
struct media_link *link, *found_link = NULL;
|
|
|
|
int ret, active_links = 0;
|
|
|
|
|
|
|
|
if (!mdev || !v4l2->decoder)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This will find the tuner that is connected into the decoder.
|
|
|
|
* Technically, this is not 100% correct, as the device may be
|
|
|
|
* using an analog input instead of the tuner. However, as we can't
|
|
|
|
* do DVB streaming while the DMA engine is being used for V4L2,
|
|
|
|
* this should be enough for the actual needs.
|
|
|
|
*/
|
|
|
|
list_for_each_entry(link, &v4l2->decoder->links, list) {
|
|
|
|
if (link->sink->entity == v4l2->decoder) {
|
|
|
|
found_link = link;
|
|
|
|
if (link->flags & MEDIA_LNK_FL_ENABLED)
|
|
|
|
active_links++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (active_links == 1 || !found_link)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
source = found_link->source->entity;
|
|
|
|
list_for_each_entry(link, &source->links, list) {
|
|
|
|
struct media_entity *sink;
|
|
|
|
int flags = 0;
|
|
|
|
|
|
|
|
sink = link->sink->entity;
|
|
|
|
|
|
|
|
if (sink == v4l2->decoder)
|
|
|
|
flags = MEDIA_LNK_FL_ENABLED;
|
|
|
|
|
|
|
|
ret = media_entity_setup_link(link, flags);
|
|
|
|
if (ret) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"Couldn't change link %s->%s to %s. Error %d\n",
|
|
|
|
source->name, sink->name,
|
|
|
|
flags ? "enabled" : "disabled",
|
|
|
|
ret);
|
2016-01-27 17:07:24 +08:00
|
|
|
return ret;
|
2018-03-04 03:49:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
em28xx_videodbg("link %s->%s was %s\n",
|
|
|
|
source->name, sink->name,
|
|
|
|
flags ? "ENABLED" : "disabled");
|
2016-01-27 17:07:24 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char * const iname[] = {
|
|
|
|
[EM28XX_VMUX_COMPOSITE] = "Composite",
|
|
|
|
[EM28XX_VMUX_SVIDEO] = "S-Video",
|
|
|
|
[EM28XX_VMUX_TELEVISION] = "Television",
|
|
|
|
[EM28XX_RADIO] = "Radio",
|
|
|
|
};
|
|
|
|
|
|
|
|
static void em28xx_v4l2_create_entities(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_MEDIA_CONTROLLER)
|
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
/* Initialize Video, VBI and Radio pads */
|
|
|
|
v4l2->video_pad.flags = MEDIA_PAD_FL_SINK;
|
|
|
|
ret = media_entity_pads_init(&v4l2->vdev.entity, 1, &v4l2->video_pad);
|
|
|
|
if (ret < 0)
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"failed to initialize video media entity!\n");
|
2016-01-27 17:07:24 +08:00
|
|
|
|
|
|
|
if (em28xx_vbi_supported(dev)) {
|
|
|
|
v4l2->vbi_pad.flags = MEDIA_PAD_FL_SINK;
|
|
|
|
ret = media_entity_pads_init(&v4l2->vbi_dev.entity, 1,
|
|
|
|
&v4l2->vbi_pad);
|
|
|
|
if (ret < 0)
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"failed to initialize vbi media entity!\n");
|
2016-01-27 17:07:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Webcams don't have input connectors */
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2016-01-27 17:07:24 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
/* Create entities for each input connector */
|
|
|
|
for (i = 0; i < MAX_EM28XX_INPUT; i++) {
|
|
|
|
struct media_entity *ent = &dev->input_ent[i];
|
|
|
|
|
|
|
|
if (!INPUT(i)->type)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ent->name = iname[INPUT(i)->type];
|
|
|
|
ent->flags = MEDIA_ENT_FL_CONNECTOR;
|
|
|
|
dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
|
|
|
|
|
|
|
|
switch (INPUT(i)->type) {
|
|
|
|
case EM28XX_VMUX_COMPOSITE:
|
|
|
|
ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
|
|
|
|
break;
|
|
|
|
case EM28XX_VMUX_SVIDEO:
|
|
|
|
ent->function = MEDIA_ENT_F_CONN_SVIDEO;
|
|
|
|
break;
|
|
|
|
default: /* EM28XX_VMUX_TELEVISION or EM28XX_RADIO */
|
2016-02-12 03:17:30 +08:00
|
|
|
if (dev->tuner_type != TUNER_ABSENT)
|
|
|
|
ent->function = MEDIA_ENT_F_CONN_RF;
|
2016-01-27 17:07:24 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
|
|
|
|
if (ret < 0)
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"failed to initialize input pad[%d]!\n", i);
|
2016-01-27 17:07:24 +08:00
|
|
|
|
|
|
|
ret = media_device_register_entity(dev->media_dev, ent);
|
|
|
|
if (ret < 0)
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"failed to register input entity %d!\n", i);
|
2016-01-27 17:07:24 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* Videobuf2 operations
|
|
|
|
*/
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2015-10-28 10:50:37 +08:00
|
|
|
static int queue_setup(struct vb2_queue *vq,
|
2013-01-05 03:16:24 +08:00
|
|
|
unsigned int *nbuffers, unsigned int *nplanes,
|
2016-04-15 20:15:05 +08:00
|
|
|
unsigned int sizes[], struct device *alloc_devs[])
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx *dev = vb2_get_drv_priv(vq);
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2015-10-28 10:50:37 +08:00
|
|
|
unsigned long size =
|
2014-03-25 03:33:17 +08:00
|
|
|
(v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2015-10-28 10:50:37 +08:00
|
|
|
if (*nplanes)
|
|
|
|
return sizes[0] < size ? -EINVAL : 0;
|
2013-01-05 03:16:24 +08:00
|
|
|
*nplanes = 1;
|
|
|
|
sizes[0] = size;
|
2016-01-27 17:07:24 +08:00
|
|
|
|
|
|
|
em28xx_enable_analog_tuner(dev);
|
|
|
|
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
static int
|
|
|
|
buffer_prepare(struct vb2_buffer *vb)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2013-01-05 03:16:24 +08:00
|
|
|
unsigned long size;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
em28xx_videodbg("%s, field=%d\n", __func__, vbuf->field);
|
2008-04-14 02:09:36 +08:00
|
|
|
|
2014-03-25 03:33:17 +08:00
|
|
|
size = (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
|
2008-04-14 02:09:36 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
if (vb2_plane_size(vb, 0) < size) {
|
|
|
|
em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n",
|
|
|
|
__func__, vb2_plane_size(vb, 0), size);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
vb2_set_plane_payload(vb, 0, size);
|
2013-01-05 03:16:24 +08:00
|
|
|
|
|
|
|
return 0;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
}
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx *dev = vb2_get_drv_priv(vq);
|
2014-03-25 03:33:20 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2013-01-05 03:16:24 +08:00
|
|
|
struct v4l2_frequency f;
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
struct v4l2_fh *owner;
|
2013-01-05 03:16:24 +08:00
|
|
|
int rc = 0;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
em28xx_videodbg("%s\n", __func__);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* Make sure streaming is not already in progress for this type
|
|
|
|
* of filehandle (e.g. video, vbi)
|
|
|
|
*/
|
2013-01-05 03:16:24 +08:00
|
|
|
rc = res_get(dev, vq->type);
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2014-05-12 04:59:04 +08:00
|
|
|
if (v4l2->streaming_users == 0) {
|
2013-01-05 03:16:24 +08:00
|
|
|
/* First active streaming user, so allocate all the URBs */
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
/* Allocate the USB bandwidth */
|
|
|
|
em28xx_set_alternate(dev);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* Needed, since GPIO might have disabled power of
|
|
|
|
* some i2c device
|
|
|
|
*/
|
2013-01-05 03:16:24 +08:00
|
|
|
em28xx_wake_i2c(dev);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2->capture_type = -1;
|
2012-11-25 17:37:37 +08:00
|
|
|
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
|
|
|
|
dev->analog_xfer_bulk,
|
|
|
|
EM28XX_NUM_BUFS,
|
|
|
|
dev->max_pkt_size,
|
|
|
|
dev->packet_multiplier,
|
|
|
|
em28xx_urb_data_copy);
|
2008-04-14 01:41:23 +08:00
|
|
|
if (rc < 0)
|
2013-10-11 02:31:53 +08:00
|
|
|
return rc;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
/*
|
|
|
|
* djh: it's not clear whether this code is still needed. I'm
|
|
|
|
* leaving it in here for now entirely out of concern for
|
|
|
|
* backward compatibility (the old code did it)
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Ask tuner to go to analog or radio mode */
|
|
|
|
memset(&f, 0, sizeof(f));
|
2014-03-25 03:33:22 +08:00
|
|
|
f.frequency = v4l2->frequency;
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
owner = (struct v4l2_fh *)vq->owner;
|
|
|
|
if (owner && owner->vdev->vfl_type == VFL_TYPE_RADIO)
|
2013-01-05 03:16:24 +08:00
|
|
|
f.type = V4L2_TUNER_RADIO;
|
|
|
|
else
|
|
|
|
f.type = V4L2_TUNER_ANALOG_TV;
|
2014-03-25 03:33:20 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev,
|
2014-03-25 03:33:09 +08:00
|
|
|
0, tuner, s_frequency, &f);
|
2016-01-26 16:59:39 +08:00
|
|
|
|
|
|
|
/* Enable video stream at TV decoder */
|
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_stream, 1);
|
2013-01-05 03:16:24 +08:00
|
|
|
}
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2014-05-12 04:59:04 +08:00
|
|
|
v4l2->streaming_users++;
|
2013-10-11 02:31:53 +08:00
|
|
|
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2014-04-17 13:47:21 +08:00
|
|
|
static void em28xx_stop_streaming(struct vb2_queue *vq)
|
2013-01-05 03:16:24 +08:00
|
|
|
{
|
|
|
|
struct em28xx *dev = vb2_get_drv_priv(vq);
|
2014-05-12 04:59:04 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx_dmaqueue *vidq = &dev->vidq;
|
|
|
|
unsigned long flags = 0;
|
|
|
|
|
|
|
|
em28xx_videodbg("%s\n", __func__);
|
|
|
|
|
|
|
|
res_free(dev, vq->type);
|
|
|
|
|
2014-05-12 04:59:04 +08:00
|
|
|
if (v4l2->streaming_users-- == 1) {
|
2016-01-26 16:59:39 +08:00
|
|
|
/* Disable video stream at TV decoder */
|
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_stream, 0);
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
/* Last active user, so shutdown all the URBS */
|
|
|
|
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (dev->usb_ctl.vid_buf) {
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
vb2_buffer_done(&dev->usb_ctl.vid_buf->vb.vb2_buf,
|
|
|
|
VB2_BUF_STATE_ERROR);
|
2014-08-09 17:37:20 +08:00
|
|
|
dev->usb_ctl.vid_buf = NULL;
|
|
|
|
}
|
2013-01-05 03:16:24 +08:00
|
|
|
while (!list_empty(&vidq->active)) {
|
|
|
|
struct em28xx_buffer *buf;
|
2014-11-28 19:34:15 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
|
|
|
|
list_del(&buf->list);
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
|
2013-01-05 03:16:24 +08:00
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
|
|
|
}
|
|
|
|
|
2014-04-17 13:47:21 +08:00
|
|
|
void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx *dev = vb2_get_drv_priv(vq);
|
2014-05-12 04:59:04 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx_dmaqueue *vbiq = &dev->vbiq;
|
|
|
|
unsigned long flags = 0;
|
|
|
|
|
|
|
|
em28xx_videodbg("%s\n", __func__);
|
|
|
|
|
|
|
|
res_free(dev, vq->type);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2014-05-12 04:59:04 +08:00
|
|
|
if (v4l2->streaming_users-- == 1) {
|
2016-01-26 16:59:39 +08:00
|
|
|
/* Disable video stream at TV decoder */
|
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_stream, 0);
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
/* Last active user, so shutdown all the URBS */
|
|
|
|
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
|
|
|
|
}
|
|
|
|
|
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (dev->usb_ctl.vbi_buf) {
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
vb2_buffer_done(&dev->usb_ctl.vbi_buf->vb.vb2_buf,
|
|
|
|
VB2_BUF_STATE_ERROR);
|
2014-08-09 17:37:20 +08:00
|
|
|
dev->usb_ctl.vbi_buf = NULL;
|
|
|
|
}
|
2013-01-05 03:16:24 +08:00
|
|
|
while (!list_empty(&vbiq->active)) {
|
|
|
|
struct em28xx_buffer *buf;
|
2014-11-28 19:34:15 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
|
|
|
|
list_del(&buf->list);
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
|
2013-01-05 03:16:24 +08:00
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
}
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
static void
|
|
|
|
buffer_queue(struct vb2_buffer *vb)
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
{
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
|
[media] media: videobuf2: Restructure vb2_buffer
Remove v4l2 stuff - v4l2_buf, v4l2_plane - from struct vb2_buffer.
Add new member variables - bytesused, length, offset, userptr, fd,
data_offset - to struct vb2_plane in order to cover all information
of v4l2_plane.
struct vb2_plane {
<snip>
unsigned int bytesused;
unsigned int length;
union {
unsigned int offset;
unsigned long userptr;
int fd;
} m;
unsigned int data_offset;
}
Replace v4l2_buf with new member variables - index, type, memory - which
are common fields for buffer management.
struct vb2_buffer {
<snip>
unsigned int index;
unsigned int type;
unsigned int memory;
unsigned int num_planes;
struct vb2_plane planes[VIDEO_MAX_PLANES];
<snip>
};
v4l2 specific fields - flags, field, timestamp, timecode,
sequence - are moved to vb2_v4l2_buffer in videobuf2-v4l2.c
struct vb2_v4l2_buffer {
struct vb2_buffer vb2_buf;
__u32 flags;
__u32 field;
struct timeval timestamp;
struct v4l2_timecode timecode;
__u32 sequence;
};
Signed-off-by: Junghak Sung <jh1009.sung@samsung.com>
Signed-off-by: Geunyoung Kim <nenggun.kim@samsung.com>
Acked-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Acked-by: Inki Dae <inki.dae@samsung.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
2015-09-22 21:30:30 +08:00
|
|
|
struct em28xx_buffer *buf =
|
|
|
|
container_of(vbuf, struct em28xx_buffer, vb);
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx_dmaqueue *vidq = &dev->vidq;
|
|
|
|
unsigned long flags = 0;
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
em28xx_videodbg("%s\n", __func__);
|
|
|
|
buf->mem = vb2_plane_vaddr(vb, 0);
|
|
|
|
buf->length = vb2_plane_size(vb, 0);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
|
|
list_add_tail(&buf->list, &vidq->active);
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
}
|
|
|
|
|
2016-09-09 07:59:01 +08:00
|
|
|
static const struct vb2_ops em28xx_video_qops = {
|
2013-01-05 03:16:24 +08:00
|
|
|
.queue_setup = queue_setup,
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
.buf_prepare = buffer_prepare,
|
|
|
|
.buf_queue = buffer_queue,
|
2013-01-05 03:16:24 +08:00
|
|
|
.start_streaming = em28xx_start_analog_streaming,
|
|
|
|
.stop_streaming = em28xx_stop_streaming,
|
|
|
|
.wait_prepare = vb2_ops_wait_prepare,
|
|
|
|
.wait_finish = vb2_ops_wait_finish,
|
V4L/DVB (7540): em28xx: convert to use videobuf-vmalloc
The usage of videobuf-vmalloc allows to cleanup em28xx logic.
Also, it reduced its size by about 5.42% on i386 arch (and about 7.5% on x86_64):
39113 4876 40 44029 abfd old/em28xx.ko
36731 4868 40 41639 a2a7 /home/v4l/master/v4l/em28xx.ko
Also, the preliminary tests, made on a single core 1.5 MHz Centrino showed
that CPU usage reduced from 42%-75% to 28%-33% (reports from "top") command.
A test with time command presented an even better result:
This is the performance tests I did, running code_example to get 1,000 frames
@29.995 Hz (about 35 seconds of stream), tested on a i386 machine, running at
1,5GHz:
The old driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:34.21: 8.22s User time, 25.16s Kernel time, 97% CPU used
The videobuf-based driver:
$ time -f "%E: %Us User time, %Ss Kernel time, %P CPU used" ./capture_example
0:35.36: 0.01s User time, 0.05s Kernel time, 0% CPU used
Conclusion:
The time consumption to receive the stream where reduced from about 33.38
seconds to 0.05 seconds.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-04-14 01:37:52 +08:00
|
|
|
};
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_vb2_setup(struct em28xx *dev)
|
2013-01-05 03:16:24 +08:00
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct vb2_queue *q;
|
2014-03-25 03:33:13 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2013-01-05 03:16:24 +08:00
|
|
|
|
|
|
|
/* Setup Videobuf2 for Video capture */
|
2014-03-25 03:33:13 +08:00
|
|
|
q = &v4l2->vb_vidq;
|
2013-01-05 03:16:24 +08:00
|
|
|
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
2013-01-06 10:34:22 +08:00
|
|
|
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
|
2014-02-26 06:12:19 +08:00
|
|
|
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
2013-01-05 03:16:24 +08:00
|
|
|
q->drv_priv = dev;
|
|
|
|
q->buf_struct_size = sizeof(struct em28xx_buffer);
|
|
|
|
q->ops = &em28xx_video_qops;
|
|
|
|
q->mem_ops = &vb2_vmalloc_memops;
|
|
|
|
|
|
|
|
rc = vb2_queue_init(q);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* Setup Videobuf2 for VBI capture */
|
2014-03-25 03:33:13 +08:00
|
|
|
q = &v4l2->vb_vbiq;
|
2013-01-05 03:16:24 +08:00
|
|
|
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
|
|
|
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
|
2014-02-26 06:12:19 +08:00
|
|
|
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
2013-01-05 03:16:24 +08:00
|
|
|
q->drv_priv = dev;
|
|
|
|
q->buf_struct_size = sizeof(struct em28xx_buffer);
|
|
|
|
q->ops = &em28xx_vbi_qops;
|
|
|
|
q->mem_ops = &vb2_vmalloc_memops;
|
|
|
|
|
|
|
|
rc = vb2_queue_init(q);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* v4l2 interface
|
|
|
|
*/
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2005-11-09 13:38:43 +08:00
|
|
|
static void video_mux(struct em28xx *dev, int index)
|
|
|
|
{
|
2014-03-25 03:33:09 +08:00
|
|
|
struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
|
2014-11-28 19:34:15 +08:00
|
|
|
|
2005-11-09 13:38:43 +08:00
|
|
|
dev->ctl_input = index;
|
|
|
|
dev->ctl_ainput = INPUT(index)->amux;
|
2008-11-20 23:40:51 +08:00
|
|
|
dev->ctl_aoutput = INPUT(index)->aout;
|
2005-11-09 13:38:43 +08:00
|
|
|
|
2008-11-21 00:39:39 +08:00
|
|
|
if (!dev->ctl_aoutput)
|
|
|
|
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
|
2014-11-28 19:34:15 +08:00
|
|
|
INPUT(index)->vmux, 0, 0);
|
2005-11-09 13:38:43 +08:00
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->has_msp34xx) {
|
2008-04-18 08:41:10 +08:00
|
|
|
if (dev->i2s_speed) {
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, audio,
|
2014-11-28 19:34:15 +08:00
|
|
|
s_i2s_clock_freq, dev->i2s_speed);
|
2008-04-18 08:41:10 +08:00
|
|
|
}
|
2006-03-19 23:35:57 +08:00
|
|
|
/* Note: this is msp3400 specific */
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
|
2014-11-28 19:34:15 +08:00
|
|
|
dev->ctl_ainput,
|
|
|
|
MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
|
2005-11-09 13:38:43 +08:00
|
|
|
}
|
2008-01-05 20:53:54 +08:00
|
|
|
|
2009-03-04 19:27:52 +08:00
|
|
|
if (dev->board.adecoder != EM28XX_NOADECODER) {
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
|
2014-11-28 19:34:15 +08:00
|
|
|
dev->ctl_ainput, dev->ctl_aoutput, 0);
|
2009-03-04 19:27:52 +08:00
|
|
|
}
|
|
|
|
|
2008-02-07 05:34:13 +08:00
|
|
|
em28xx_audio_analog_set(dev);
|
2005-11-09 13:38:43 +08:00
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
|
2009-07-19 21:45:49 +08:00
|
|
|
{
|
2012-09-07 16:43:59 +08:00
|
|
|
struct em28xx *dev = priv;
|
2009-07-19 21:45:49 +08:00
|
|
|
|
2012-09-07 16:43:59 +08:00
|
|
|
/*
|
|
|
|
* In the case of non-AC97 volume controls, we still need
|
|
|
|
* to do some setups at em28xx, in order to mute/unmute
|
|
|
|
* and to adjust audio volume. However, the value ranges
|
|
|
|
* should be checked by the corresponding V4L subdriver.
|
|
|
|
*/
|
2007-11-12 00:17:17 +08:00
|
|
|
switch (ctrl->id) {
|
|
|
|
case V4L2_CID_AUDIO_MUTE:
|
2012-09-07 16:43:59 +08:00
|
|
|
dev->mute = ctrl->val;
|
|
|
|
em28xx_audio_analog_set(dev);
|
|
|
|
break;
|
2007-11-12 00:17:17 +08:00
|
|
|
case V4L2_CID_AUDIO_VOLUME:
|
2012-09-07 16:43:59 +08:00
|
|
|
dev->volume = ctrl->val;
|
|
|
|
em28xx_audio_analog_set(dev);
|
|
|
|
break;
|
2005-11-09 13:37:07 +08:00
|
|
|
}
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2012-09-07 16:43:59 +08:00
|
|
|
static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2014-03-25 03:33:10 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 =
|
|
|
|
container_of(ctrl->handler, struct em28xx_v4l2, ctrl_handler);
|
|
|
|
struct em28xx *dev = v4l2->dev;
|
2013-02-16 01:38:32 +08:00
|
|
|
int ret = -EINVAL;
|
2009-07-19 21:45:49 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
switch (ctrl->id) {
|
|
|
|
case V4L2_CID_AUDIO_MUTE:
|
2012-09-07 16:43:59 +08:00
|
|
|
dev->mute = ctrl->val;
|
2013-02-16 01:38:32 +08:00
|
|
|
ret = em28xx_audio_analog_set(dev);
|
2009-07-19 21:45:49 +08:00
|
|
|
break;
|
2007-11-12 00:17:17 +08:00
|
|
|
case V4L2_CID_AUDIO_VOLUME:
|
2012-09-07 16:43:59 +08:00
|
|
|
dev->volume = ctrl->val;
|
2013-02-16 01:38:32 +08:00
|
|
|
ret = em28xx_audio_analog_set(dev);
|
|
|
|
break;
|
|
|
|
case V4L2_CID_CONTRAST:
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R20_YGAIN, ctrl->val);
|
|
|
|
break;
|
|
|
|
case V4L2_CID_BRIGHTNESS:
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R21_YOFFSET, ctrl->val);
|
|
|
|
break;
|
|
|
|
case V4L2_CID_SATURATION:
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R22_UVGAIN, ctrl->val);
|
|
|
|
break;
|
|
|
|
case V4L2_CID_BLUE_BALANCE:
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R23_UOFFSET, ctrl->val);
|
|
|
|
break;
|
|
|
|
case V4L2_CID_RED_BALANCE:
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R24_VOFFSET, ctrl->val);
|
|
|
|
break;
|
|
|
|
case V4L2_CID_SHARPNESS:
|
|
|
|
ret = em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, ctrl->val);
|
2009-07-19 21:45:49 +08:00
|
|
|
break;
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2009-07-19 21:45:49 +08:00
|
|
|
|
2013-02-16 01:38:32 +08:00
|
|
|
return (ret < 0) ? ret : 0;
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2014-01-07 23:50:47 +08:00
|
|
|
static const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
|
2012-09-07 16:43:59 +08:00
|
|
|
.s_ctrl = em28xx_s_ctrl,
|
|
|
|
};
|
|
|
|
|
2013-02-11 03:05:12 +08:00
|
|
|
static void size_to_scale(struct em28xx *dev,
|
2014-11-28 19:34:15 +08:00
|
|
|
unsigned int width, unsigned int height,
|
2007-11-12 00:17:17 +08:00
|
|
|
unsigned int *hscale, unsigned int *vscale)
|
|
|
|
{
|
2009-07-14 07:15:02 +08:00
|
|
|
unsigned int maxw = norm_maxw(dev);
|
|
|
|
unsigned int maxh = norm_maxh(dev);
|
2007-11-12 00:17:17 +08:00
|
|
|
|
|
|
|
*hscale = (((unsigned long)maxw) << 12) / width - 4096L;
|
2013-02-11 03:05:11 +08:00
|
|
|
if (*hscale > EM28XX_HVSCALE_MAX)
|
|
|
|
*hscale = EM28XX_HVSCALE_MAX;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
|
|
|
*vscale = (((unsigned long)maxh) << 12) / height - 4096L;
|
2013-02-11 03:05:11 +08:00
|
|
|
if (*vscale > EM28XX_HVSCALE_MAX)
|
|
|
|
*vscale = EM28XX_HVSCALE_MAX;
|
2005-11-09 13:37:07 +08:00
|
|
|
}
|
|
|
|
|
2013-02-11 03:05:13 +08:00
|
|
|
static void scale_to_size(struct em28xx *dev,
|
|
|
|
unsigned int hscale, unsigned int vscale,
|
|
|
|
unsigned int *width, unsigned int *height)
|
|
|
|
{
|
|
|
|
unsigned int maxw = norm_maxw(dev);
|
|
|
|
unsigned int maxh = norm_maxh(dev);
|
|
|
|
|
|
|
|
*width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
|
|
|
|
*height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
|
2016-01-30 00:05:11 +08:00
|
|
|
|
|
|
|
/* Don't let width or height to be zero */
|
|
|
|
if (*width < 1)
|
|
|
|
*width = 1;
|
|
|
|
if (*height < 1)
|
|
|
|
*height = 1;
|
2013-02-11 03:05:13 +08:00
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* IOCTL vidioc handling
|
|
|
|
*/
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2008-05-28 23:16:41 +08:00
|
|
|
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_format *f)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2014-03-25 03:33:14 +08:00
|
|
|
f->fmt.pix.width = v4l2->width;
|
|
|
|
f->fmt.pix.height = v4l2->height;
|
2014-03-25 03:33:17 +08:00
|
|
|
f->fmt.pix.pixelformat = v4l2->format->fourcc;
|
|
|
|
f->fmt.pix.bytesperline = (v4l2->width * v4l2->format->depth + 7) >> 3;
|
2014-03-25 03:33:14 +08:00
|
|
|
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * v4l2->height;
|
2007-11-12 00:17:17 +08:00
|
|
|
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
|
2014-03-25 03:33:18 +08:00
|
|
|
if (v4l2->progressive)
|
2009-08-08 14:14:55 +08:00
|
|
|
f->fmt.pix.field = V4L2_FIELD_NONE;
|
|
|
|
else
|
2014-03-25 03:33:18 +08:00
|
|
|
f->fmt.pix.field = v4l2->interlaced_fieldmode ?
|
2007-11-12 00:17:17 +08:00
|
|
|
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
|
|
|
|
return 0;
|
2005-11-09 13:37:07 +08:00
|
|
|
}
|
|
|
|
|
2008-12-20 20:06:37 +08:00
|
|
|
static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(format); i++)
|
|
|
|
if (format[i].fourcc == fourcc)
|
|
|
|
return &format[i];
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2008-05-28 23:16:41 +08:00
|
|
|
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_format *f)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:18 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2009-05-31 08:45:46 +08:00
|
|
|
unsigned int width = f->fmt.pix.width;
|
|
|
|
unsigned int height = f->fmt.pix.height;
|
2007-11-12 00:17:17 +08:00
|
|
|
unsigned int maxw = norm_maxw(dev);
|
|
|
|
unsigned int maxh = norm_maxh(dev);
|
|
|
|
unsigned int hscale, vscale;
|
2008-12-20 20:06:37 +08:00
|
|
|
struct em28xx_fmt *fmt;
|
|
|
|
|
|
|
|
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
|
|
|
|
if (!fmt) {
|
|
|
|
em28xx_videodbg("Fourcc format (%08x) invalid.\n",
|
|
|
|
f->fmt.pix.pixelformat);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2009-07-14 07:15:02 +08:00
|
|
|
if (dev->board.is_em2800) {
|
2007-11-12 00:17:17 +08:00
|
|
|
/* the em2800 can only scale down to 50% */
|
2009-05-31 08:45:46 +08:00
|
|
|
height = height > (3 * maxh / 4) ? maxh : maxh / 2;
|
|
|
|
width = width > (3 * maxw / 4) ? maxw : maxw / 2;
|
2013-01-05 03:16:24 +08:00
|
|
|
/*
|
|
|
|
* MaxPacketSize for em2800 is too small to capture at full
|
|
|
|
* resolution use half of maxw as the scaler can only scale
|
|
|
|
* to 50%
|
|
|
|
*/
|
2012-01-09 03:54:28 +08:00
|
|
|
if (width == maxw && height == maxh)
|
|
|
|
width /= 2;
|
2009-05-31 08:45:46 +08:00
|
|
|
} else {
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* width must even because of the YUYV format
|
|
|
|
* height must be even because of interlacing
|
|
|
|
*/
|
2009-09-15 11:18:06 +08:00
|
|
|
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh,
|
|
|
|
1, 0);
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2016-01-30 00:05:11 +08:00
|
|
|
/* Avoid division by zero at size_to_scale */
|
|
|
|
if (width < 1)
|
|
|
|
width = 1;
|
|
|
|
if (height < 1)
|
|
|
|
height = 1;
|
2007-11-11 12:08:26 +08:00
|
|
|
|
2013-02-11 03:05:12 +08:00
|
|
|
size_to_scale(dev, width, height, &hscale, &vscale);
|
2013-03-30 16:31:42 +08:00
|
|
|
scale_to_size(dev, hscale, vscale, &width, &height);
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
f->fmt.pix.width = width;
|
|
|
|
f->fmt.pix.height = height;
|
2008-12-20 20:06:37 +08:00
|
|
|
f->fmt.pix.pixelformat = fmt->fourcc;
|
2013-02-06 19:14:47 +08:00
|
|
|
f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
|
2008-12-20 20:06:37 +08:00
|
|
|
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
|
2007-11-12 00:17:17 +08:00
|
|
|
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
2014-03-25 03:33:18 +08:00
|
|
|
if (v4l2->progressive)
|
2009-08-08 14:14:55 +08:00
|
|
|
f->fmt.pix.field = V4L2_FIELD_NONE;
|
|
|
|
else
|
2014-03-25 03:33:18 +08:00
|
|
|
f->fmt.pix.field = v4l2->interlaced_fieldmode ?
|
2009-08-08 14:14:55 +08:00
|
|
|
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
|
2013-07-17 06:06:46 +08:00
|
|
|
f->fmt.pix.priv = 0;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-07-03 04:34:04 +08:00
|
|
|
static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
|
2018-03-04 03:49:09 +08:00
|
|
|
unsigned int width, unsigned int height)
|
2009-07-03 04:34:04 +08:00
|
|
|
{
|
|
|
|
struct em28xx_fmt *fmt;
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2009-07-03 04:34:04 +08:00
|
|
|
|
|
|
|
fmt = format_by_fourcc(fourcc);
|
|
|
|
if (!fmt)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2014-03-25 03:33:17 +08:00
|
|
|
v4l2->format = fmt;
|
2014-03-25 03:33:14 +08:00
|
|
|
v4l2->width = width;
|
|
|
|
v4l2->height = height;
|
2009-07-03 04:34:04 +08:00
|
|
|
|
|
|
|
/* set new image size */
|
2014-03-25 03:33:14 +08:00
|
|
|
size_to_scale(dev, v4l2->width, v4l2->height,
|
2014-11-28 19:34:15 +08:00
|
|
|
&v4l2->hscale, &v4l2->vscale);
|
2009-07-03 04:34:04 +08:00
|
|
|
|
|
|
|
em28xx_resolution_set(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-05-28 23:16:41 +08:00
|
|
|
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_format *f)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2013-01-05 03:16:24 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-05-12 04:59:04 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2014-09-20 00:02:12 +08:00
|
|
|
if (vb2_is_busy(&v4l2->vb_vidq))
|
2013-01-05 03:16:24 +08:00
|
|
|
return -EBUSY;
|
2007-11-11 12:08:26 +08:00
|
|
|
|
2008-12-17 09:04:56 +08:00
|
|
|
vidioc_try_fmt_vid_cap(file, priv, f);
|
|
|
|
|
2010-09-26 18:34:45 +08:00
|
|
|
return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
|
2009-07-03 04:34:04 +08:00
|
|
|
f->fmt.pix.width, f->fmt.pix.height);
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
|
|
|
|
2009-09-11 11:40:18 +08:00
|
|
|
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2009-09-11 11:40:18 +08:00
|
|
|
|
2014-03-25 03:33:16 +08:00
|
|
|
*norm = dev->v4l2->norm;
|
2009-09-11 11:40:18 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-10-04 20:53:00 +08:00
|
|
|
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2011-10-04 20:53:00 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, video, querystd, norm);
|
2011-10-04 20:53:00 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-15 17:10:40 +08:00
|
|
|
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2007-11-12 00:17:17 +08:00
|
|
|
struct v4l2_format f;
|
|
|
|
|
2014-03-25 03:33:16 +08:00
|
|
|
if (norm == v4l2->norm)
|
2012-09-07 18:31:54 +08:00
|
|
|
return 0;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2014-05-12 04:59:04 +08:00
|
|
|
if (v4l2->streaming_users > 0)
|
2012-09-07 18:31:54 +08:00
|
|
|
return -EBUSY;
|
|
|
|
|
2014-03-25 03:33:16 +08:00
|
|
|
v4l2->norm = norm;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
/* Adjusts width/height, if needed */
|
2012-09-07 18:31:54 +08:00
|
|
|
f.fmt.pix.width = 720;
|
2013-03-15 17:10:40 +08:00
|
|
|
f.fmt.pix.height = (norm & V4L2_STD_525_60) ? 480 : 576;
|
2008-05-28 23:16:41 +08:00
|
|
|
vidioc_try_fmt_vid_cap(file, priv, &f);
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
/* set new image size */
|
2014-03-25 03:33:14 +08:00
|
|
|
v4l2->width = f.fmt.pix.width;
|
|
|
|
v4l2->height = f.fmt.pix.height;
|
|
|
|
size_to_scale(dev, v4l2->width, v4l2->height,
|
2014-11-28 19:34:15 +08:00
|
|
|
&v4l2->hscale, &v4l2->vscale);
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
em28xx_resolution_set(dev);
|
2014-04-29 03:53:01 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2007-11-11 12:13:49 +08:00
|
|
|
|
2009-08-07 08:53:59 +08:00
|
|
|
static int vidioc_g_parm(struct file *file, void *priv,
|
|
|
|
struct v4l2_streamparm *p)
|
|
|
|
{
|
2018-01-22 17:00:45 +08:00
|
|
|
struct v4l2_subdev_frame_interval ival = { 0 };
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:16 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2009-08-07 08:53:59 +08:00
|
|
|
int rc = 0;
|
|
|
|
|
2018-01-22 17:00:45 +08:00
|
|
|
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
|
|
|
p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2012-09-07 17:16:03 +08:00
|
|
|
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
|
2018-01-22 17:00:45 +08:00
|
|
|
p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam) {
|
2014-03-25 03:33:16 +08:00
|
|
|
rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
|
2018-01-22 17:00:45 +08:00
|
|
|
video, g_frame_interval, &ival);
|
|
|
|
if (!rc)
|
|
|
|
p->parm.capture.timeperframe = ival.interval;
|
|
|
|
} else {
|
2014-03-25 03:33:16 +08:00
|
|
|
v4l2_video_std_frame_period(v4l2->norm,
|
2014-11-28 19:34:15 +08:00
|
|
|
&p->parm.capture.timeperframe);
|
2018-01-22 17:00:45 +08:00
|
|
|
}
|
2009-08-07 08:53:59 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_parm(struct file *file, void *priv,
|
|
|
|
struct v4l2_streamparm *p)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2018-01-22 17:00:45 +08:00
|
|
|
struct v4l2_subdev_frame_interval ival = {
|
|
|
|
0,
|
|
|
|
p->parm.capture.timeperframe
|
|
|
|
};
|
|
|
|
int rc = 0;
|
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (!dev->is_webcam)
|
2018-01-22 17:00:45 +08:00
|
|
|
return -ENOTTY;
|
2009-08-07 08:53:59 +08:00
|
|
|
|
2018-01-22 17:00:45 +08:00
|
|
|
if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
|
|
|
|
p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
memset(&p->parm, 0, sizeof(p->parm));
|
2012-09-07 17:16:03 +08:00
|
|
|
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
|
2018-01-22 17:00:45 +08:00
|
|
|
p->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
|
|
|
|
rc = v4l2_device_call_until_err(&dev->v4l2->v4l2_dev, 0,
|
|
|
|
video, s_frame_interval, &ival);
|
|
|
|
if (!rc)
|
|
|
|
p->parm.capture.timeperframe = ival.interval;
|
|
|
|
return rc;
|
2009-08-07 08:53:59 +08:00
|
|
|
}
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
static int vidioc_enum_input(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_input *i)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2007-11-12 00:17:17 +08:00
|
|
|
unsigned int n;
|
2018-09-15 01:13:15 +08:00
|
|
|
int j;
|
2007-11-11 12:13:49 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
n = i->index;
|
|
|
|
if (n >= MAX_EM28XX_INPUT)
|
|
|
|
return -EINVAL;
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!INPUT(n)->type)
|
2007-11-12 00:17:17 +08:00
|
|
|
return -EINVAL;
|
2007-11-11 12:13:49 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
i->type = V4L2_INPUT_TYPE_CAMERA;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(i->name, iname[INPUT(n)->type], sizeof(i->name));
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (INPUT(n)->type == EM28XX_VMUX_TELEVISION)
|
2007-11-12 00:17:17 +08:00
|
|
|
i->type = V4L2_INPUT_TYPE_TUNER;
|
|
|
|
|
2015-03-10 00:34:06 +08:00
|
|
|
i->std = dev->v4l2->vdev.tvnorms;
|
2012-09-07 18:31:54 +08:00
|
|
|
/* webcams do not have the STD API */
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2012-09-07 18:31:54 +08:00
|
|
|
i->capabilities = 0;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
/* Dynamically generates an audioset bitmask */
|
|
|
|
i->audioset = 0;
|
|
|
|
for (j = 0; j < MAX_EM28XX_INPUT; j++)
|
|
|
|
if (dev->amux_map[j] != EM28XX_AMUX_UNUSED)
|
|
|
|
i->audioset |= 1 << j;
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
2005-11-09 13:37:07 +08:00
|
|
|
}
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
*i = dev->ctl_input;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2007-11-12 00:17:17 +08:00
|
|
|
|
|
|
|
if (i >= MAX_EM28XX_INPUT)
|
|
|
|
return -EINVAL;
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!INPUT(i)->type)
|
2007-11-12 00:17:17 +08:00
|
|
|
return -EINVAL;
|
2007-11-11 12:08:26 +08:00
|
|
|
|
2012-03-24 05:09:34 +08:00
|
|
|
video_mux(dev, i);
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
static int em28xx_fill_audio_input(struct em28xx *dev,
|
|
|
|
const char *s,
|
|
|
|
struct v4l2_audio *a,
|
|
|
|
unsigned int index)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2018-09-15 01:13:15 +08:00
|
|
|
unsigned int idx = dev->amux_map[index];
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
/*
|
|
|
|
* With msp3400, almost all mappings use the default (amux = 0).
|
|
|
|
* The only one may use a different value is WinTV USB2, where it
|
|
|
|
* can also be SCART1 input.
|
|
|
|
* As it is very doubtful that we would see new boards with msp3400,
|
|
|
|
* let's just reuse the existing switch.
|
|
|
|
*/
|
|
|
|
if (dev->has_msp34xx && idx != EM28XX_AMUX_UNUSED)
|
|
|
|
idx = EM28XX_AMUX_LINE_IN;
|
|
|
|
|
|
|
|
switch (idx) {
|
2008-11-20 23:40:51 +08:00
|
|
|
case EM28XX_AMUX_VIDEO:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Television", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_LINE_IN:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Line In", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_VIDEO2:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Television alt", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_PHONE:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Phone", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_MIC:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Mic", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_CD:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "CD", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_AUX:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Aux", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
|
|
|
case EM28XX_AMUX_PCM_OUT:
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "PCM", sizeof(a->name));
|
2008-11-20 23:40:51 +08:00
|
|
|
break;
|
2018-09-15 01:13:15 +08:00
|
|
|
case EM28XX_AMUX_UNUSED:
|
2008-11-20 23:40:51 +08:00
|
|
|
default:
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2018-09-15 01:13:15 +08:00
|
|
|
a->index = index;
|
2007-11-12 00:17:17 +08:00
|
|
|
a->capability = V4L2_AUDCAP_STEREO;
|
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
em28xx_videodbg("%s: audio input index %d is '%s'\n",
|
|
|
|
s, a->index, a->name);
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = video_drvdata(file);
|
|
|
|
|
|
|
|
if (a->index >= MAX_EM28XX_INPUT)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
return em28xx_fill_audio_input(dev, __func__, a, a->index);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = video_drvdata(file);
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < MAX_EM28XX_INPUT; i++)
|
|
|
|
if (dev->ctl_ainput == dev->amux_map[i])
|
|
|
|
return em28xx_fill_audio_input(dev, __func__, a, i);
|
|
|
|
|
|
|
|
/* Should never happen! */
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
static int vidioc_s_audio(struct file *file, void *priv,
|
|
|
|
const struct v4l2_audio *a)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2018-09-15 01:13:15 +08:00
|
|
|
int idx, i;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2009-01-08 09:49:25 +08:00
|
|
|
if (a->index >= MAX_EM28XX_INPUT)
|
|
|
|
return -EINVAL;
|
2018-09-15 01:13:15 +08:00
|
|
|
|
|
|
|
idx = dev->amux_map[a->index];
|
|
|
|
|
|
|
|
if (idx == EM28XX_AMUX_UNUSED)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
dev->ctl_ainput = idx;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: This is wrong, as different inputs at em28xx_cards
|
|
|
|
* may have different audio outputs. So, the right thing
|
|
|
|
* to do is to implement VIDIOC_G_AUDOUT/VIDIOC_S_AUDOUT.
|
|
|
|
* With the current board definitions, this would work fine,
|
|
|
|
* as, currently, all boards fit.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < MAX_EM28XX_INPUT; i++)
|
|
|
|
if (idx == dev->amux_map[i])
|
|
|
|
break;
|
|
|
|
if (i == MAX_EM28XX_INPUT)
|
2009-01-08 09:49:25 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
dev->ctl_aoutput = INPUT(i)->aout;
|
2008-11-21 00:39:39 +08:00
|
|
|
|
|
|
|
if (!dev->ctl_aoutput)
|
|
|
|
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
|
2008-12-17 09:04:56 +08:00
|
|
|
|
2018-09-15 01:13:15 +08:00
|
|
|
em28xx_videodbg("%s: set audio input to %d\n", __func__,
|
|
|
|
dev->ctl_ainput);
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_g_tuner(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_tuner *t)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (t->index != 0)
|
2007-11-12 00:17:17 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(t->name, "Tuner", sizeof(t->name));
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
2005-11-09 13:37:07 +08:00
|
|
|
}
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
static int vidioc_s_tuner(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
const struct v4l2_tuner *t)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (t->index != 0)
|
2007-11-12 00:17:17 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
2005-11-09 13:37:07 +08:00
|
|
|
}
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
static int vidioc_g_frequency(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_frequency *f)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:22 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (f->tuner != 0)
|
2012-09-06 21:07:25 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-03-25 03:33:22 +08:00
|
|
|
f->frequency = v4l2->frequency;
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_frequency(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
const struct v4l2_frequency *f)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-03-25 03:33:09 +08:00
|
|
|
struct v4l2_frequency new_freq = *f;
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:09 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (f->tuner != 0)
|
2007-11-12 00:17:17 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f);
|
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, g_frequency, &new_freq);
|
2014-03-25 03:33:22 +08:00
|
|
|
v4l2->frequency = new_freq.frequency;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2013-03-27 19:04:23 +08:00
|
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
2013-04-06 17:16:58 +08:00
|
|
|
static int vidioc_g_chip_info(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_dbg_chip_info *chip)
|
2013-03-18 23:21:53 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2013-03-18 23:21:53 +08:00
|
|
|
|
|
|
|
if (chip->match.addr > 1)
|
|
|
|
return -EINVAL;
|
|
|
|
if (chip->match.addr == 1)
|
2018-09-10 20:19:14 +08:00
|
|
|
strscpy(chip->name, "ac97", sizeof(chip->name));
|
2013-03-18 23:21:53 +08:00
|
|
|
else
|
2018-09-10 20:19:14 +08:00
|
|
|
strscpy(chip->name,
|
2014-03-25 03:33:09 +08:00
|
|
|
dev->v4l2->v4l2_dev.name, sizeof(chip->name));
|
2013-03-18 23:21:53 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-08 00:39:19 +08:00
|
|
|
static int em28xx_reg_len(int reg)
|
|
|
|
{
|
|
|
|
switch (reg) {
|
|
|
|
case EM28XX_R40_AC97LSB:
|
|
|
|
case EM28XX_R30_HSCALELOW:
|
|
|
|
case EM28XX_R32_VSCALELOW:
|
|
|
|
return 2;
|
|
|
|
default:
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
2008-12-23 07:58:41 +08:00
|
|
|
|
2008-02-06 20:00:41 +08:00
|
|
|
static int vidioc_g_register(struct file *file, void *priv,
|
2008-12-30 18:14:19 +08:00
|
|
|
struct v4l2_dbg_register *reg)
|
2008-02-06 20:00:41 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2008-02-06 20:00:41 +08:00
|
|
|
int ret;
|
|
|
|
|
2013-05-29 17:59:35 +08:00
|
|
|
if (reg->match.addr > 1)
|
|
|
|
return -EINVAL;
|
|
|
|
if (reg->match.addr) {
|
2008-12-23 00:18:27 +08:00
|
|
|
ret = em28xx_read_ac97(dev, reg->reg);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
reg->val = ret;
|
2008-12-30 18:14:19 +08:00
|
|
|
reg->size = 1;
|
2008-12-23 00:18:27 +08:00
|
|
|
return 0;
|
2008-12-23 07:58:41 +08:00
|
|
|
}
|
2008-02-06 20:00:41 +08:00
|
|
|
|
2008-12-23 07:58:41 +08:00
|
|
|
/* Match host */
|
2008-12-30 18:14:19 +08:00
|
|
|
reg->size = em28xx_reg_len(reg->reg);
|
|
|
|
if (reg->size == 1) {
|
2008-02-06 20:00:41 +08:00
|
|
|
ret = em28xx_read_reg(dev, reg->reg);
|
2008-12-17 09:04:56 +08:00
|
|
|
|
2008-02-06 20:00:41 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
reg->val = ret;
|
|
|
|
} else {
|
2008-12-30 18:14:19 +08:00
|
|
|
__le16 val = 0;
|
2014-11-28 19:34:15 +08:00
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
|
2008-02-06 20:00:41 +08:00
|
|
|
reg->reg, (char *)&val, 2);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
2008-12-30 18:14:19 +08:00
|
|
|
reg->val = le16_to_cpu(val);
|
2008-02-06 20:00:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_register(struct file *file, void *priv,
|
2013-03-24 19:28:46 +08:00
|
|
|
const struct v4l2_dbg_register *reg)
|
2008-02-06 20:00:41 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2008-12-30 18:14:19 +08:00
|
|
|
__le16 buf;
|
2008-02-06 20:00:41 +08:00
|
|
|
|
2013-05-29 17:59:35 +08:00
|
|
|
if (reg->match.addr > 1)
|
2013-03-18 23:21:53 +08:00
|
|
|
return -EINVAL;
|
2013-05-29 17:59:35 +08:00
|
|
|
if (reg->match.addr)
|
|
|
|
return em28xx_write_ac97(dev, reg->reg, reg->val);
|
2008-12-23 00:18:27 +08:00
|
|
|
|
2008-12-23 07:58:41 +08:00
|
|
|
/* Match host */
|
2008-12-30 18:14:19 +08:00
|
|
|
buf = cpu_to_le16(reg->val);
|
2008-02-06 20:00:41 +08:00
|
|
|
|
2010-09-26 18:34:45 +08:00
|
|
|
return em28xx_write_regs(dev, reg->reg, (char *)&buf,
|
2008-12-17 09:04:56 +08:00
|
|
|
em28xx_reg_len(reg->reg));
|
2008-02-06 20:00:41 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
static int vidioc_querycap(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_capability *cap)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-03-25 03:33:12 +08:00
|
|
|
struct video_device *vdev = video_devdata(file);
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:12 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2016-12-08 00:34:22 +08:00
|
|
|
struct usb_device *udev = interface_to_usbdev(dev->intf);
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-09-10 20:19:14 +08:00
|
|
|
strscpy(cap->driver, "em28xx", sizeof(cap->driver));
|
|
|
|
strscpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
|
2016-12-08 00:34:22 +08:00
|
|
|
usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info));
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2012-09-06 18:31:04 +08:00
|
|
|
if (vdev->vfl_type == VFL_TYPE_GRABBER)
|
|
|
|
cap->device_caps = V4L2_CAP_READWRITE |
|
|
|
|
V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
|
|
|
|
else if (vdev->vfl_type == VFL_TYPE_RADIO)
|
|
|
|
cap->device_caps = V4L2_CAP_RADIO;
|
|
|
|
else
|
2012-09-07 19:45:10 +08:00
|
|
|
cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
|
2009-09-11 11:08:44 +08:00
|
|
|
|
2014-09-13 16:52:21 +08:00
|
|
|
if (dev->int_audio_type != EM28XX_INT_AUDIO_NONE)
|
2012-09-06 18:31:04 +08:00
|
|
|
cap->device_caps |= V4L2_CAP_AUDIO;
|
2009-08-05 06:52:37 +08:00
|
|
|
|
V4L/DVB (7060): em28xx: remove has_tuner
has_tuner flag doesn't make much sense, since tuner_type=TUNER_ABSENT
means the same thing.
Having two ways to say that a tuner is not present is
not nice, since it may lead to bad setups. In fact, with the previous
code, if a device were using has_tuner=0, but the user forces a tuner,
with modprobe option tuner=type, the modprobe option won't work.
Also, tveeprom returns TUNER_ABSENT, when tuner is unknown or absent.
So, with the previous logic, in this case, the driver should set
has_tuner=0, or has_tuner=1 otherwise.
Instead of adding several additional tests and setups, better just to
remove .has_tuner.
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
2008-01-24 17:59:20 +08:00
|
|
|
if (dev->tuner_type != TUNER_ABSENT)
|
2012-09-06 18:31:04 +08:00
|
|
|
cap->device_caps |= V4L2_CAP_TUNER;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
cap->capabilities = cap->device_caps |
|
|
|
|
V4L2_CAP_DEVICE_CAPS | V4L2_CAP_READWRITE |
|
|
|
|
V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
|
2015-03-10 00:34:06 +08:00
|
|
|
if (video_is_registered(&v4l2->vbi_dev))
|
2012-09-07 19:45:10 +08:00
|
|
|
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
|
2015-03-10 00:34:06 +08:00
|
|
|
if (video_is_registered(&v4l2->radio_dev))
|
2012-09-06 18:31:04 +08:00
|
|
|
cap->capabilities |= V4L2_CAP_RADIO;
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
2006-01-10 01:25:14 +08:00
|
|
|
}
|
|
|
|
|
2008-05-28 23:16:41 +08:00
|
|
|
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
|
2014-11-28 19:34:15 +08:00
|
|
|
struct v4l2_fmtdesc *f)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2008-12-20 20:06:37 +08:00
|
|
|
if (unlikely(f->index >= ARRAY_SIZE(format)))
|
2006-01-10 01:25:14 +08:00
|
|
|
return -EINVAL;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
2018-09-10 20:19:14 +08:00
|
|
|
strscpy(f->description, format[f->index].name, sizeof(f->description));
|
2008-12-20 20:06:37 +08:00
|
|
|
f->pixelformat = format[f->index].fourcc;
|
2007-11-12 00:17:17 +08:00
|
|
|
|
|
|
|
return 0;
|
2006-01-10 01:25:14 +08:00
|
|
|
}
|
|
|
|
|
2011-10-16 23:52:43 +08:00
|
|
|
static int vidioc_enum_framesizes(struct file *file, void *priv,
|
|
|
|
struct v4l2_frmsizeenum *fsize)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2011-10-16 23:52:43 +08:00
|
|
|
struct em28xx_fmt *fmt;
|
|
|
|
unsigned int maxw = norm_maxw(dev);
|
|
|
|
unsigned int maxh = norm_maxh(dev);
|
|
|
|
|
|
|
|
fmt = format_by_fourcc(fsize->pixel_format);
|
|
|
|
if (!fmt) {
|
|
|
|
em28xx_videodbg("Fourcc format (%08x) invalid.\n",
|
|
|
|
fsize->pixel_format);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->board.is_em2800) {
|
|
|
|
if (fsize->index > 1)
|
|
|
|
return -EINVAL;
|
|
|
|
fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
|
|
|
|
fsize->discrete.width = maxw / (1 + fsize->index);
|
|
|
|
fsize->discrete.height = maxh / (1 + fsize->index);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fsize->index != 0)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* Report a continuous range */
|
|
|
|
fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
|
2013-02-11 03:05:14 +08:00
|
|
|
scale_to_size(dev, EM28XX_HVSCALE_MAX, EM28XX_HVSCALE_MAX,
|
|
|
|
&fsize->stepwise.min_width, &fsize->stepwise.min_height);
|
|
|
|
if (fsize->stepwise.min_width < 48)
|
|
|
|
fsize->stepwise.min_width = 48;
|
|
|
|
if (fsize->stepwise.min_height < 38)
|
|
|
|
fsize->stepwise.min_height = 38;
|
2011-10-16 23:52:43 +08:00
|
|
|
fsize->stepwise.max_width = maxw;
|
|
|
|
fsize->stepwise.max_height = maxh;
|
|
|
|
fsize->stepwise.step_width = 1;
|
|
|
|
fsize->stepwise.step_height = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-01 12:54:54 +08:00
|
|
|
/* RAW VBI ioctls */
|
|
|
|
|
|
|
|
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
|
|
|
|
struct v4l2_format *format)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2014-03-25 03:33:14 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2009-11-25 10:17:25 +08:00
|
|
|
|
2014-03-25 03:33:14 +08:00
|
|
|
format->fmt.vbi.samples_per_line = v4l2->vbi_width;
|
2009-09-01 12:54:54 +08:00
|
|
|
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
|
|
|
format->fmt.vbi.offset = 0;
|
|
|
|
format->fmt.vbi.flags = 0;
|
2009-11-25 10:17:25 +08:00
|
|
|
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
|
2014-03-25 03:33:14 +08:00
|
|
|
format->fmt.vbi.count[0] = v4l2->vbi_height;
|
|
|
|
format->fmt.vbi.count[1] = v4l2->vbi_height;
|
2012-09-07 19:51:32 +08:00
|
|
|
memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
|
2009-09-01 12:54:54 +08:00
|
|
|
|
|
|
|
/* Varies by video standard (NTSC, PAL, etc.) */
|
2014-03-25 03:33:16 +08:00
|
|
|
if (v4l2->norm & V4L2_STD_525_60) {
|
2009-11-25 10:17:25 +08:00
|
|
|
/* NTSC */
|
|
|
|
format->fmt.vbi.start[0] = 10;
|
|
|
|
format->fmt.vbi.start[1] = 273;
|
2014-03-25 03:33:16 +08:00
|
|
|
} else if (v4l2->norm & V4L2_STD_625_50) {
|
2009-11-25 10:17:25 +08:00
|
|
|
/* PAL */
|
|
|
|
format->fmt.vbi.start[0] = 6;
|
|
|
|
format->fmt.vbi.start[1] = 318;
|
|
|
|
}
|
2009-09-01 12:54:54 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* RADIO ESPECIFIC IOCTLS
|
|
|
|
*/
|
2008-01-06 04:22:01 +08:00
|
|
|
|
|
|
|
static int radio_g_tuner(struct file *file, void *priv,
|
|
|
|
struct v4l2_tuner *t)
|
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2008-01-06 04:22:01 +08:00
|
|
|
|
|
|
|
if (unlikely(t->index > 0))
|
|
|
|
return -EINVAL;
|
|
|
|
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(t->name, "Radio", sizeof(t->name));
|
2008-01-06 04:22:01 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
|
2008-12-17 09:04:56 +08:00
|
|
|
|
2008-01-06 04:22:01 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int radio_s_tuner(struct file *file, void *priv,
|
2013-03-15 17:10:06 +08:00
|
|
|
const struct v4l2_tuner *t)
|
2008-01-06 04:22:01 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(file);
|
2008-01-06 04:22:01 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (t->index != 0)
|
2008-01-06 04:22:01 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
|
2008-01-06 04:22:01 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
/*
|
|
|
|
* em28xx_free_v4l2() - Free struct em28xx_v4l2
|
|
|
|
*
|
|
|
|
* @ref: struct kref for struct em28xx_v4l2
|
|
|
|
*
|
|
|
|
* Called when all users of struct em28xx_v4l2 are gone
|
|
|
|
*/
|
2014-05-24 01:29:44 +08:00
|
|
|
static void em28xx_free_v4l2(struct kref *ref)
|
2014-03-25 03:33:09 +08:00
|
|
|
{
|
|
|
|
struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref);
|
|
|
|
|
2014-03-25 03:33:10 +08:00
|
|
|
v4l2->dev->v4l2 = NULL;
|
2014-03-25 03:33:09 +08:00
|
|
|
kfree(v4l2);
|
|
|
|
}
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
/*
|
|
|
|
* em28xx_v4l2_open()
|
|
|
|
* inits the device and starts isoc transfer
|
|
|
|
*/
|
2008-12-30 17:58:20 +08:00
|
|
|
static int em28xx_v4l2_open(struct file *filp)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2009-12-10 21:44:04 +08:00
|
|
|
struct video_device *vdev = video_devdata(filp);
|
|
|
|
struct em28xx *dev = video_drvdata(filp);
|
2014-03-25 03:33:09 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2009-12-10 21:44:04 +08:00
|
|
|
enum v4l2_buf_type fh_type = 0;
|
2014-07-26 01:48:57 +08:00
|
|
|
int ret;
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2009-12-10 21:44:04 +08:00
|
|
|
switch (vdev->vfl_type) {
|
|
|
|
case VFL_TYPE_GRABBER:
|
|
|
|
fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
break;
|
|
|
|
case VFL_TYPE_VBI:
|
|
|
|
fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
|
|
|
break;
|
2014-01-13 00:24:18 +08:00
|
|
|
case VFL_TYPE_RADIO:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return -EINVAL;
|
2009-12-10 21:44:04 +08:00
|
|
|
}
|
2008-11-20 21:30:26 +08:00
|
|
|
|
2014-09-19 04:55:45 +08:00
|
|
|
em28xx_videodbg("open dev=%s type=%s users=%d\n",
|
|
|
|
video_device_node_name(vdev), v4l2_type_names[fh_type],
|
|
|
|
v4l2->users);
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2012-06-23 19:12:47 +08:00
|
|
|
if (mutex_lock_interruptible(&dev->lock))
|
|
|
|
return -ERESTARTSYS;
|
2014-07-26 01:48:57 +08:00
|
|
|
|
|
|
|
ret = v4l2_fh_open(filp);
|
|
|
|
if (ret) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"%s: v4l2_fh_open() returned error %d\n",
|
2016-10-12 18:32:23 +08:00
|
|
|
__func__, ret);
|
2012-06-23 19:12:47 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2014-07-26 01:48:57 +08:00
|
|
|
return ret;
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2006-01-24 03:11:09 +08:00
|
|
|
|
2014-09-19 04:55:45 +08:00
|
|
|
if (v4l2->users == 0) {
|
2008-04-18 08:48:00 +08:00
|
|
|
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2014-01-13 00:24:18 +08:00
|
|
|
if (vdev->vfl_type != VFL_TYPE_RADIO)
|
|
|
|
em28xx_resolution_set(dev);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Needed, since GPIO might have disabled power
|
|
|
|
* of some i2c devices
|
2008-04-18 08:48:00 +08:00
|
|
|
*/
|
2008-12-29 09:18:14 +08:00
|
|
|
em28xx_wake_i2c(dev);
|
2006-01-24 03:11:08 +08:00
|
|
|
}
|
2013-01-05 03:16:24 +08:00
|
|
|
|
|
|
|
if (vdev->vfl_type == VFL_TYPE_RADIO) {
|
2008-01-06 04:22:01 +08:00
|
|
|
em28xx_videodbg("video_open: setting radio device\n");
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio);
|
2008-01-06 04:22:01 +08:00
|
|
|
}
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_get(&dev->ref);
|
2014-03-25 03:33:09 +08:00
|
|
|
kref_get(&v4l2->ref);
|
2014-09-19 04:55:45 +08:00
|
|
|
v4l2->users++;
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2012-06-23 19:12:47 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2008-04-18 08:48:00 +08:00
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
return 0;
|
2006-01-24 03:11:08 +08:00
|
|
|
}
|
2006-01-24 03:11:08 +08:00
|
|
|
|
2005-11-09 13:37:07 +08:00
|
|
|
/*
|
2013-12-23 00:27:02 +08:00
|
|
|
* em28xx_v4l2_fini()
|
2007-11-12 00:17:17 +08:00
|
|
|
* unregisters the v4l2,i2c and usb devices
|
|
|
|
* called when the device gets disconected or at module unload
|
2018-03-04 03:49:09 +08:00
|
|
|
*/
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_v4l2_fini(struct em28xx *dev)
|
2005-11-09 13:37:07 +08:00
|
|
|
{
|
2014-03-25 03:33:09 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
|
2014-01-06 16:27:47 +08:00
|
|
|
if (dev->is_audio_only) {
|
|
|
|
/* Shouldn't initialize IR for this interface */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
if (!dev->has_video) {
|
|
|
|
/* This device does not support the v4l2 extension */
|
|
|
|
return 0;
|
|
|
|
}
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!v4l2)
|
2014-03-25 03:33:09 +08:00
|
|
|
return 0;
|
|
|
|
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "Closing video extension\n");
|
2014-01-13 06:22:07 +08:00
|
|
|
|
[media] em28xx: push mutex down to extensions on .fini callback
Avoid circular mutex lock by pushing the dev->lock to the .fini
callback on each extension.
As em28xx-dvb, em28xx-alsa and em28xx-rc have their own data
structures, and don't touch at the common structure during .fini,
only em28xx-v4l needs to be locked.
[ 90.994317] ======================================================
[ 90.994356] [ INFO: possible circular locking dependency detected ]
[ 90.994395] 3.13.0-rc1+ #24 Not tainted
[ 90.994427] -------------------------------------------------------
[ 90.994458] khubd/54 is trying to acquire lock:
[ 90.994490] (&card->controls_rwsem){++++.+}, at: [<ffffffffa0177b08>] snd_ctl_dev_free+0x28/0x60 [snd]
[ 90.994656]
[ 90.994656] but task is already holding lock:
[ 90.994688] (&dev->lock){+.+.+.}, at: [<ffffffffa040db81>] em28xx_close_extension+0x31/0x90 [em28xx]
[ 90.994843]
[ 90.994843] which lock already depends on the new lock.
[ 90.994843]
[ 90.994874]
[ 90.994874] the existing dependency chain (in reverse order) is:
[ 90.994905]
-> #1 (&dev->lock){+.+.+.}:
[ 90.995057] [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
[ 90.995121] [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
[ 90.995182] [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
[ 90.995245] [<ffffffffa0422cca>] em28xx_vol_put_mute+0x1ba/0x1d0 [em28xx_alsa]
[ 90.995309] [<ffffffffa017813d>] snd_ctl_elem_write+0xfd/0x140 [snd]
[ 90.995376] [<ffffffffa01791c2>] snd_ctl_ioctl+0xe2/0x810 [snd]
[ 90.995442] [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[ 90.995504] [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[ 90.995568] [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[ 90.995630]
-> #0 (&card->controls_rwsem){++++.+}:
[ 90.995780] [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
[ 90.995841] [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
[ 90.995901] [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
[ 90.995962] [<ffffffff816a762b>] down_write+0x3b/0xa0
[ 90.996022] [<ffffffffa0177b08>] snd_ctl_dev_free+0x28/0x60 [snd]
[ 90.996088] [<ffffffffa017a255>] snd_device_free+0x65/0x140 [snd]
[ 90.996154] [<ffffffffa017a751>] snd_device_free_all+0x61/0xa0 [snd]
[ 90.996219] [<ffffffffa0173af4>] snd_card_do_free+0x14/0x130 [snd]
[ 90.996283] [<ffffffffa0173f14>] snd_card_free+0x84/0x90 [snd]
[ 90.996349] [<ffffffffa0423397>] em28xx_audio_fini+0x97/0xb0 [em28xx_alsa]
[ 90.996411] [<ffffffffa040dba6>] em28xx_close_extension+0x56/0x90 [em28xx]
[ 90.996475] [<ffffffffa040f639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
[ 90.996539] [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
[ 90.996620] [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
[ 90.996682] [<ffffffff814292a5>] device_release_driver+0x25/0x40
[ 90.996742] [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
[ 90.996801] [<ffffffff81425536>] device_del+0x136/0x1d0
[ 90.996863] [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
[ 90.996923] [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
[ 90.996984] [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
[ 90.997044] [<ffffffff814967c3>] hub_events+0x313/0x9b0
[ 90.997105] [<ffffffff81496e95>] hub_thread+0x35/0x170
[ 90.997165] [<ffffffff8108ea2f>] kthread+0xff/0x120
[ 90.997226] [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
[ 90.997287]
[ 90.997287] other info that might help us debug this:
[ 90.997287]
[ 90.997318] Possible unsafe locking scenario:
[ 90.997318]
[ 90.997348] CPU0 CPU1
[ 90.997378] ---- ----
[ 90.997408] lock(&dev->lock);
[ 90.997497] lock(&card->controls_rwsem);
[ 90.997607] lock(&dev->lock);
[ 90.997697] lock(&card->controls_rwsem);
[ 90.997786]
[ 90.997786] *** DEADLOCK ***
[ 90.997786]
[ 90.997817] 5 locks held by khubd/54:
[ 90.997847] #0: (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
[ 90.998025] #1: (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
[ 90.998204] #2: (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
[ 90.998383] #3: (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa040db77>] em28xx_close_extension+0x27/0x90 [em28xx]
[ 90.998567] #4: (&dev->lock){+.+.+.}, at: [<ffffffffa040db81>] em28xx_close_extension+0x31/0x90 [em28xx]
Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Tested-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-13 13:53:44 +08:00
|
|
|
mutex_lock(&dev->lock);
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_disconnect(&v4l2->v4l2_dev);
|
2014-01-13 00:24:21 +08:00
|
|
|
|
2014-01-13 00:24:20 +08:00
|
|
|
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
|
|
|
|
|
2016-01-27 17:07:24 +08:00
|
|
|
em28xx_v4l2_media_release(dev);
|
|
|
|
|
2015-03-10 00:34:06 +08:00
|
|
|
if (video_is_registered(&v4l2->radio_dev)) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
|
2018-03-04 03:49:09 +08:00
|
|
|
video_device_node_name(&v4l2->radio_dev));
|
2015-03-10 00:34:06 +08:00
|
|
|
video_unregister_device(&v4l2->radio_dev);
|
2008-01-06 04:22:01 +08:00
|
|
|
}
|
2015-03-10 00:34:06 +08:00
|
|
|
if (video_is_registered(&v4l2->vbi_dev)) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
|
2018-03-04 03:49:09 +08:00
|
|
|
video_device_node_name(&v4l2->vbi_dev));
|
2015-03-10 00:34:06 +08:00
|
|
|
video_unregister_device(&v4l2->vbi_dev);
|
2008-01-06 04:22:01 +08:00
|
|
|
}
|
2015-03-10 00:34:06 +08:00
|
|
|
if (video_is_registered(&v4l2->vdev)) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n",
|
2018-03-04 03:49:09 +08:00
|
|
|
video_device_node_name(&v4l2->vdev));
|
2015-03-10 00:34:06 +08:00
|
|
|
video_unregister_device(&v4l2->vdev);
|
2008-01-06 04:22:01 +08:00
|
|
|
}
|
2013-12-23 00:27:02 +08:00
|
|
|
|
2014-03-25 03:33:10 +08:00
|
|
|
v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_unregister(&v4l2->v4l2_dev);
|
2014-01-18 01:45:30 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
kref_put(&v4l2->ref, em28xx_free_v4l2);
|
|
|
|
|
[media] em28xx: push mutex down to extensions on .fini callback
Avoid circular mutex lock by pushing the dev->lock to the .fini
callback on each extension.
As em28xx-dvb, em28xx-alsa and em28xx-rc have their own data
structures, and don't touch at the common structure during .fini,
only em28xx-v4l needs to be locked.
[ 90.994317] ======================================================
[ 90.994356] [ INFO: possible circular locking dependency detected ]
[ 90.994395] 3.13.0-rc1+ #24 Not tainted
[ 90.994427] -------------------------------------------------------
[ 90.994458] khubd/54 is trying to acquire lock:
[ 90.994490] (&card->controls_rwsem){++++.+}, at: [<ffffffffa0177b08>] snd_ctl_dev_free+0x28/0x60 [snd]
[ 90.994656]
[ 90.994656] but task is already holding lock:
[ 90.994688] (&dev->lock){+.+.+.}, at: [<ffffffffa040db81>] em28xx_close_extension+0x31/0x90 [em28xx]
[ 90.994843]
[ 90.994843] which lock already depends on the new lock.
[ 90.994843]
[ 90.994874]
[ 90.994874] the existing dependency chain (in reverse order) is:
[ 90.994905]
-> #1 (&dev->lock){+.+.+.}:
[ 90.995057] [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
[ 90.995121] [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
[ 90.995182] [<ffffffff816a5b6c>] mutex_lock_nested+0x5c/0x3c0
[ 90.995245] [<ffffffffa0422cca>] em28xx_vol_put_mute+0x1ba/0x1d0 [em28xx_alsa]
[ 90.995309] [<ffffffffa017813d>] snd_ctl_elem_write+0xfd/0x140 [snd]
[ 90.995376] [<ffffffffa01791c2>] snd_ctl_ioctl+0xe2/0x810 [snd]
[ 90.995442] [<ffffffff811db8b0>] do_vfs_ioctl+0x300/0x520
[ 90.995504] [<ffffffff811dbb51>] SyS_ioctl+0x81/0xa0
[ 90.995568] [<ffffffff816b1929>] system_call_fastpath+0x16/0x1b
[ 90.995630]
-> #0 (&card->controls_rwsem){++++.+}:
[ 90.995780] [<ffffffff810b7a47>] check_prevs_add+0x947/0x950
[ 90.995841] [<ffffffff810b8fa3>] __lock_acquire+0xb43/0x1330
[ 90.995901] [<ffffffff810b9f82>] lock_acquire+0xa2/0x120
[ 90.995962] [<ffffffff816a762b>] down_write+0x3b/0xa0
[ 90.996022] [<ffffffffa0177b08>] snd_ctl_dev_free+0x28/0x60 [snd]
[ 90.996088] [<ffffffffa017a255>] snd_device_free+0x65/0x140 [snd]
[ 90.996154] [<ffffffffa017a751>] snd_device_free_all+0x61/0xa0 [snd]
[ 90.996219] [<ffffffffa0173af4>] snd_card_do_free+0x14/0x130 [snd]
[ 90.996283] [<ffffffffa0173f14>] snd_card_free+0x84/0x90 [snd]
[ 90.996349] [<ffffffffa0423397>] em28xx_audio_fini+0x97/0xb0 [em28xx_alsa]
[ 90.996411] [<ffffffffa040dba6>] em28xx_close_extension+0x56/0x90 [em28xx]
[ 90.996475] [<ffffffffa040f639>] em28xx_usb_disconnect+0x79/0x90 [em28xx]
[ 90.996539] [<ffffffff814a06e7>] usb_unbind_interface+0x67/0x1d0
[ 90.996620] [<ffffffff8142920f>] __device_release_driver+0x7f/0xf0
[ 90.996682] [<ffffffff814292a5>] device_release_driver+0x25/0x40
[ 90.996742] [<ffffffff81428b0c>] bus_remove_device+0x11c/0x1a0
[ 90.996801] [<ffffffff81425536>] device_del+0x136/0x1d0
[ 90.996863] [<ffffffff8149e0c0>] usb_disable_device+0xb0/0x290
[ 90.996923] [<ffffffff814930c5>] usb_disconnect+0xb5/0x1d0
[ 90.996984] [<ffffffff81495ab6>] hub_port_connect_change+0xd6/0xad0
[ 90.997044] [<ffffffff814967c3>] hub_events+0x313/0x9b0
[ 90.997105] [<ffffffff81496e95>] hub_thread+0x35/0x170
[ 90.997165] [<ffffffff8108ea2f>] kthread+0xff/0x120
[ 90.997226] [<ffffffff816b187c>] ret_from_fork+0x7c/0xb0
[ 90.997287]
[ 90.997287] other info that might help us debug this:
[ 90.997287]
[ 90.997318] Possible unsafe locking scenario:
[ 90.997318]
[ 90.997348] CPU0 CPU1
[ 90.997378] ---- ----
[ 90.997408] lock(&dev->lock);
[ 90.997497] lock(&card->controls_rwsem);
[ 90.997607] lock(&dev->lock);
[ 90.997697] lock(&card->controls_rwsem);
[ 90.997786]
[ 90.997786] *** DEADLOCK ***
[ 90.997786]
[ 90.997817] 5 locks held by khubd/54:
[ 90.997847] #0: (&__lockdep_no_validate__){......}, at: [<ffffffff81496564>] hub_events+0xb4/0x9b0
[ 90.998025] #1: (&__lockdep_no_validate__){......}, at: [<ffffffff81493076>] usb_disconnect+0x66/0x1d0
[ 90.998204] #2: (&__lockdep_no_validate__){......}, at: [<ffffffff8142929d>] device_release_driver+0x1d/0x40
[ 90.998383] #3: (em28xx_devlist_mutex){+.+.+.}, at: [<ffffffffa040db77>] em28xx_close_extension+0x27/0x90 [em28xx]
[ 90.998567] #4: (&dev->lock){+.+.+.}, at: [<ffffffffa040db81>] em28xx_close_extension+0x31/0x90 [em28xx]
Reviewed-by: Frank Schäfer <fschaefer.oss@googlemail.com>
Tested-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-13 13:53:44 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2014-03-25 03:33:09 +08:00
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_put(&dev->ref, em28xx_free_device);
|
2014-01-13 00:24:21 +08:00
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
return 0;
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2014-02-22 08:50:17 +08:00
|
|
|
static int em28xx_v4l2_suspend(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
if (dev->is_audio_only)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!dev->has_video)
|
|
|
|
return 0;
|
|
|
|
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "Suspending video extension\n");
|
2014-02-22 08:50:17 +08:00
|
|
|
em28xx_stop_urbs(dev);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_v4l2_resume(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
if (dev->is_audio_only)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!dev->has_video)
|
|
|
|
return 0;
|
|
|
|
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "Resuming video extension\n");
|
2014-02-22 08:50:17 +08:00
|
|
|
/* what do we do here */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
/*
|
|
|
|
* em28xx_v4l2_close()
|
2008-04-18 08:41:10 +08:00
|
|
|
* stops streaming and deallocates all resources allocated by the v4l2
|
|
|
|
* calls and ioctls
|
2007-11-12 00:17:17 +08:00
|
|
|
*/
|
2008-12-30 17:58:20 +08:00
|
|
|
static int em28xx_v4l2_close(struct file *filp)
|
2007-11-12 00:17:17 +08:00
|
|
|
{
|
2014-07-26 01:48:56 +08:00
|
|
|
struct em28xx *dev = video_drvdata(filp);
|
2014-03-25 03:33:09 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
2016-12-08 00:34:22 +08:00
|
|
|
struct usb_device *udev = interface_to_usbdev(dev->intf);
|
2018-03-04 03:49:09 +08:00
|
|
|
int err;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2014-09-19 04:55:45 +08:00
|
|
|
em28xx_videodbg("users=%d\n", v4l2->users);
|
2009-09-03 11:23:27 +08:00
|
|
|
|
2014-09-19 04:55:45 +08:00
|
|
|
vb2_fop_release(filp);
|
|
|
|
mutex_lock(&dev->lock);
|
2014-07-26 01:48:58 +08:00
|
|
|
|
2014-09-19 04:55:45 +08:00
|
|
|
if (v4l2->users == 1) {
|
2014-03-05 22:21:07 +08:00
|
|
|
/* No sense to try to write to the device */
|
|
|
|
if (dev->disconnected)
|
2013-12-23 00:27:02 +08:00
|
|
|
goto exit;
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2008-12-05 21:39:12 +08:00
|
|
|
/* Save some power by putting tuner to sleep */
|
media: add tuner standby op, use where needed
The v4l2_subdev core s_power op was used for two different things: power on/off
sensors or video decoders/encoders and to put a tuner in standby (and only the
tuner!). There is no 'tuner wakeup' op, that's done automatically when the tuner
is accessed.
The danger with calling (s_power, 0) to put a tuner into standby is that it is
usually broadcast for all subdevs. So a video receiver subdev that supports
s_power will also be powered off, and since there is no corresponding (s_power, 1)
they will never be powered on again.
In addition, this is specifically meant for tuners only since they draw the most
current.
This patch adds a new tuner op called 'standby' and replaces all calls to
(core, s_power, 0) by (tuner, standby). This prevents confusion between the two
uses of s_power. Note that there is no overlap: bridge drivers either just want
to put the tuner into standby, or they deal with powering on/off sensors. Never
both.
This also makes it easier to replace s_power for the remaining bridge drivers
with some PM code later.
Whether we want something cleaner for tuners in the future is a separate topic.
There is a lot of legacy code surrounding tuners, and I am very hesitant about
making changes there.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2018-02-21 15:49:25 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby);
|
2008-12-05 21:39:12 +08:00
|
|
|
|
2008-04-14 01:38:47 +08:00
|
|
|
/* do this before setting alternate! */
|
2008-11-27 20:10:40 +08:00
|
|
|
em28xx_set_mode(dev, EM28XX_SUSPEND);
|
2008-04-14 01:38:47 +08:00
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
/* set alternate 0 */
|
|
|
|
dev->alt = 0;
|
|
|
|
em28xx_videodbg("setting alternate 0\n");
|
2018-03-04 03:49:09 +08:00
|
|
|
err = usb_set_interface(udev, 0, 0);
|
|
|
|
if (err < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"cannot change alternate number to 0 (error=%i)\n",
|
2018-03-04 03:49:09 +08:00
|
|
|
err);
|
2007-11-12 00:17:17 +08:00
|
|
|
}
|
2006-01-24 03:11:09 +08:00
|
|
|
}
|
2009-09-01 12:54:54 +08:00
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
exit:
|
2014-09-19 04:55:45 +08:00
|
|
|
v4l2->users--;
|
2014-03-25 03:33:09 +08:00
|
|
|
kref_put(&v4l2->ref, em28xx_free_v4l2);
|
2012-06-23 19:12:47 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_put(&dev->ref, em28xx_free_device);
|
|
|
|
|
2007-11-12 00:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2008-12-30 17:58:20 +08:00
|
|
|
static const struct v4l2_file_operations em28xx_v4l_fops = {
|
2007-11-12 00:17:17 +08:00
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.open = em28xx_v4l2_open,
|
|
|
|
.release = em28xx_v4l2_close,
|
2013-01-05 03:16:24 +08:00
|
|
|
.read = vb2_fop_read,
|
|
|
|
.poll = vb2_fop_poll,
|
|
|
|
.mmap = vb2_fop_mmap,
|
2010-09-26 18:34:45 +08:00
|
|
|
.unlocked_ioctl = video_ioctl2,
|
2007-11-12 00:17:17 +08:00
|
|
|
};
|
2006-01-10 01:24:58 +08:00
|
|
|
|
2008-07-21 13:57:38 +08:00
|
|
|
static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
2007-11-12 00:17:17 +08:00
|
|
|
.vidioc_querycap = vidioc_querycap,
|
2008-05-28 23:16:41 +08:00
|
|
|
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
|
|
|
|
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
|
|
|
|
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
|
|
|
|
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
|
2009-09-01 12:54:54 +08:00
|
|
|
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
2012-09-07 19:51:32 +08:00
|
|
|
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
2013-02-08 00:39:16 +08:00
|
|
|
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
2011-10-16 23:52:43 +08:00
|
|
|
.vidioc_enum_framesizes = vidioc_enum_framesizes,
|
2018-09-15 01:13:15 +08:00
|
|
|
.vidioc_enumaudio = vidioc_enumaudio,
|
2007-11-12 00:17:17 +08:00
|
|
|
.vidioc_g_audio = vidioc_g_audio,
|
|
|
|
.vidioc_s_audio = vidioc_s_audio,
|
|
|
|
|
2013-01-05 03:16:24 +08:00
|
|
|
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
|
|
|
.vidioc_create_bufs = vb2_ioctl_create_bufs,
|
|
|
|
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
|
|
|
|
.vidioc_querybuf = vb2_ioctl_querybuf,
|
|
|
|
.vidioc_qbuf = vb2_ioctl_qbuf,
|
|
|
|
.vidioc_dqbuf = vb2_ioctl_dqbuf,
|
|
|
|
|
2009-09-11 11:40:18 +08:00
|
|
|
.vidioc_g_std = vidioc_g_std,
|
2011-10-04 20:53:00 +08:00
|
|
|
.vidioc_querystd = vidioc_querystd,
|
2007-11-12 00:17:17 +08:00
|
|
|
.vidioc_s_std = vidioc_s_std,
|
2009-08-07 08:53:59 +08:00
|
|
|
.vidioc_g_parm = vidioc_g_parm,
|
|
|
|
.vidioc_s_parm = vidioc_s_parm,
|
2007-11-12 00:17:17 +08:00
|
|
|
.vidioc_enum_input = vidioc_enum_input,
|
|
|
|
.vidioc_g_input = vidioc_g_input,
|
|
|
|
.vidioc_s_input = vidioc_s_input,
|
2013-01-05 03:16:24 +08:00
|
|
|
.vidioc_streamon = vb2_ioctl_streamon,
|
|
|
|
.vidioc_streamoff = vb2_ioctl_streamoff,
|
2007-11-12 00:17:17 +08:00
|
|
|
.vidioc_g_tuner = vidioc_g_tuner,
|
|
|
|
.vidioc_s_tuner = vidioc_s_tuner,
|
|
|
|
.vidioc_g_frequency = vidioc_g_frequency,
|
|
|
|
.vidioc_s_frequency = vidioc_s_frequency,
|
2012-09-07 17:10:12 +08:00
|
|
|
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
|
|
|
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
2008-02-06 20:00:41 +08:00
|
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
2013-04-06 17:16:58 +08:00
|
|
|
.vidioc_g_chip_info = vidioc_g_chip_info,
|
2008-02-06 20:00:41 +08:00
|
|
|
.vidioc_g_register = vidioc_g_register,
|
|
|
|
.vidioc_s_register = vidioc_s_register,
|
|
|
|
#endif
|
2008-07-21 13:57:38 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct video_device em28xx_video_template = {
|
2014-01-13 00:24:25 +08:00
|
|
|
.fops = &em28xx_v4l_fops,
|
|
|
|
.ioctl_ops = &video_ioctl_ops,
|
2015-03-10 00:34:06 +08:00
|
|
|
.release = video_device_release_empty,
|
2014-01-13 00:24:25 +08:00
|
|
|
.tvnorms = V4L2_STD_ALL,
|
2005-11-09 13:37:07 +08:00
|
|
|
};
|
|
|
|
|
2008-12-30 17:58:20 +08:00
|
|
|
static const struct v4l2_file_operations radio_fops = {
|
2008-07-21 13:57:38 +08:00
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.open = em28xx_v4l2_open,
|
|
|
|
.release = em28xx_v4l2_close,
|
2010-12-18 20:59:51 +08:00
|
|
|
.unlocked_ioctl = video_ioctl2,
|
2008-07-21 13:57:38 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
|
2012-09-06 18:31:04 +08:00
|
|
|
.vidioc_querycap = vidioc_querycap,
|
2008-01-06 04:22:01 +08:00
|
|
|
.vidioc_g_tuner = radio_g_tuner,
|
|
|
|
.vidioc_s_tuner = radio_s_tuner,
|
|
|
|
.vidioc_g_frequency = vidioc_g_frequency,
|
|
|
|
.vidioc_s_frequency = vidioc_s_frequency,
|
2012-09-07 17:10:12 +08:00
|
|
|
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
|
|
|
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
2008-02-06 20:00:41 +08:00
|
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
2013-04-16 19:06:30 +08:00
|
|
|
.vidioc_g_chip_info = vidioc_g_chip_info,
|
2008-02-06 20:00:41 +08:00
|
|
|
.vidioc_g_register = vidioc_g_register,
|
|
|
|
.vidioc_s_register = vidioc_s_register,
|
|
|
|
#endif
|
2008-01-06 04:22:01 +08:00
|
|
|
};
|
|
|
|
|
2008-07-21 13:57:38 +08:00
|
|
|
static struct video_device em28xx_radio_template = {
|
2014-01-13 00:24:25 +08:00
|
|
|
.fops = &radio_fops,
|
|
|
|
.ioctl_ops = &radio_ioctl_ops,
|
2015-03-10 00:34:06 +08:00
|
|
|
.release = video_device_release_empty,
|
2008-07-21 13:57:38 +08:00
|
|
|
};
|
|
|
|
|
2013-12-23 00:16:49 +08:00
|
|
|
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
|
|
|
|
static unsigned short saa711x_addrs[] = {
|
|
|
|
0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
|
|
|
|
0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
|
|
|
|
I2C_CLIENT_END };
|
|
|
|
|
|
|
|
static unsigned short tvp5150_addrs[] = {
|
|
|
|
0xb8 >> 1,
|
|
|
|
0xba >> 1,
|
|
|
|
I2C_CLIENT_END
|
|
|
|
};
|
|
|
|
|
|
|
|
static unsigned short msp3400_addrs[] = {
|
|
|
|
0x80 >> 1,
|
|
|
|
0x88 >> 1,
|
|
|
|
I2C_CLIENT_END
|
|
|
|
};
|
|
|
|
|
2008-04-18 08:41:10 +08:00
|
|
|
/******************************** usb interface ******************************/
|
2005-11-09 13:37:07 +08:00
|
|
|
|
2015-03-10 00:34:06 +08:00
|
|
|
static void em28xx_vdev_init(struct em28xx *dev,
|
|
|
|
struct video_device *vfd,
|
|
|
|
const struct video_device *template,
|
|
|
|
const char *type_name)
|
2008-01-06 04:22:01 +08:00
|
|
|
{
|
2009-04-01 04:10:58 +08:00
|
|
|
*vfd = *template;
|
2014-03-25 03:33:09 +08:00
|
|
|
vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
|
2010-09-26 18:34:45 +08:00
|
|
|
vfd->lock = &dev->lock;
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2012-09-07 18:31:54 +08:00
|
|
|
vfd->tvnorms = 0;
|
2008-01-06 04:22:01 +08:00
|
|
|
|
|
|
|
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_name(&dev->intf->dev), type_name);
|
2008-01-06 04:22:01 +08:00
|
|
|
|
2009-12-10 21:44:04 +08:00
|
|
|
video_set_drvdata(vfd, dev);
|
2008-01-06 04:22:01 +08:00
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:24 +08:00
|
|
|
static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr)
|
2013-12-23 02:28:26 +08:00
|
|
|
{
|
2014-03-25 03:33:22 +08:00
|
|
|
struct em28xx_v4l2 *v4l2 = dev->v4l2;
|
|
|
|
struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
|
|
|
|
struct tuner_setup tun_setup;
|
|
|
|
struct v4l2_frequency f;
|
2013-12-23 02:28:26 +08:00
|
|
|
|
|
|
|
memset(&tun_setup, 0, sizeof(tun_setup));
|
|
|
|
|
|
|
|
tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
|
|
|
|
tun_setup.tuner_callback = em28xx_tuner_callback;
|
|
|
|
|
|
|
|
if (dev->board.radio.type) {
|
|
|
|
tun_setup.type = dev->board.radio.type;
|
|
|
|
tun_setup.addr = dev->board.radio_addr;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev,
|
|
|
|
0, tuner, s_type_addr, &tun_setup);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
if (dev->tuner_type != TUNER_ABSENT && dev->tuner_type) {
|
2013-12-23 02:28:26 +08:00
|
|
|
tun_setup.type = dev->tuner_type;
|
2014-03-25 03:33:24 +08:00
|
|
|
tun_setup.addr = tuner_addr;
|
2013-12-23 02:28:26 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev,
|
|
|
|
0, tuner, s_type_addr, &tun_setup);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:23 +08:00
|
|
|
if (dev->board.tda9887_conf) {
|
2013-12-23 02:28:26 +08:00
|
|
|
struct v4l2_priv_tun_config tda9887_cfg;
|
|
|
|
|
|
|
|
tda9887_cfg.tuner = TUNER_TDA9887;
|
2014-03-25 03:33:23 +08:00
|
|
|
tda9887_cfg.priv = &dev->board.tda9887_conf;
|
2013-12-23 02:28:26 +08:00
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev,
|
|
|
|
0, tuner, s_config, &tda9887_cfg);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->tuner_type == TUNER_XC2028) {
|
|
|
|
struct v4l2_priv_tun_config xc2028_cfg;
|
|
|
|
struct xc2028_ctrl ctl;
|
|
|
|
|
|
|
|
memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
|
|
|
|
memset(&ctl, 0, sizeof(ctl));
|
|
|
|
|
|
|
|
em28xx_setup_xc3028(dev, &ctl);
|
|
|
|
|
|
|
|
xc2028_cfg.tuner = TUNER_XC2028;
|
|
|
|
xc2028_cfg.priv = &ctl;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* configure tuner */
|
|
|
|
f.tuner = 0;
|
|
|
|
f.type = V4L2_TUNER_ANALOG_TV;
|
|
|
|
f.frequency = 9076; /* just a magic number */
|
2014-03-25 03:33:22 +08:00
|
|
|
v4l2->frequency = f.frequency;
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_call_all(v4l2_dev, 0, tuner, s_frequency, &f);
|
2013-12-23 02:28:26 +08:00
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
static int em28xx_v4l2_init(struct em28xx *dev)
|
2008-12-29 09:18:14 +08:00
|
|
|
{
|
2012-09-07 16:43:59 +08:00
|
|
|
u8 val;
|
2008-12-29 09:26:36 +08:00
|
|
|
int ret;
|
2012-01-09 03:54:28 +08:00
|
|
|
unsigned int maxw;
|
2014-03-25 03:33:10 +08:00
|
|
|
struct v4l2_ctrl_handler *hdl;
|
2014-03-25 03:33:09 +08:00
|
|
|
struct em28xx_v4l2 *v4l2;
|
2013-12-23 00:16:49 +08:00
|
|
|
|
2014-01-06 16:27:47 +08:00
|
|
|
if (dev->is_audio_only) {
|
|
|
|
/* Shouldn't initialize IR for this interface */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
if (!dev->has_video) {
|
2013-12-23 00:16:49 +08:00
|
|
|
/* This device does not support the v4l2 extension */
|
|
|
|
return 0;
|
|
|
|
}
|
2008-12-29 09:26:36 +08:00
|
|
|
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev, "Registering V4L2 extension\n");
|
2008-12-29 09:18:14 +08:00
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
mutex_lock(&dev->lock);
|
|
|
|
|
2018-03-04 03:49:09 +08:00
|
|
|
v4l2 = kzalloc(sizeof(*v4l2), GFP_KERNEL);
|
2016-10-12 18:26:47 +08:00
|
|
|
if (!v4l2) {
|
2014-03-25 03:33:09 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
kref_init(&v4l2->ref);
|
2014-03-25 03:33:10 +08:00
|
|
|
v4l2->dev = dev;
|
2014-03-25 03:33:09 +08:00
|
|
|
dev->v4l2 = v4l2;
|
|
|
|
|
2016-01-27 17:07:24 +08:00
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
|
|
|
v4l2->v4l2_dev.mdev = dev->media_dev;
|
|
|
|
#endif
|
2016-12-07 23:48:10 +08:00
|
|
|
ret = v4l2_device_register(&dev->intf->dev, &v4l2->v4l2_dev);
|
2013-12-23 00:16:49 +08:00
|
|
|
if (ret < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"Call to v4l2_device_register() failed!\n");
|
2013-12-23 00:16:49 +08:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:10 +08:00
|
|
|
hdl = &v4l2->ctrl_handler;
|
2013-12-23 00:16:49 +08:00
|
|
|
v4l2_ctrl_handler_init(hdl, 8);
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2->v4l2_dev.ctrl_handler = hdl;
|
2013-12-23 00:16:49 +08:00
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam)
|
2014-09-04 02:06:13 +08:00
|
|
|
v4l2->progressive = true;
|
2014-03-25 03:33:18 +08:00
|
|
|
|
2013-12-23 00:16:49 +08:00
|
|
|
/*
|
|
|
|
* Default format, used for tvp5150 or saa711x output formats
|
|
|
|
*/
|
2017-04-15 18:05:03 +08:00
|
|
|
v4l2->vinmode = EM28XX_VINMODE_YUV422_CbYCrY;
|
2014-03-25 03:33:15 +08:00
|
|
|
v4l2->vinctl = EM28XX_VINCTRL_INTERLACED |
|
|
|
|
EM28XX_VINCTRL_CCIR656_ENABLE;
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
/* request some modules */
|
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->has_msp34xx)
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"msp3400", 0, msp3400_addrs);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
if (dev->board.decoder == EM28XX_SAA711X)
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"saa7115_auto", 0, saa711x_addrs);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
if (dev->board.decoder == EM28XX_TVP5150)
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"tvp5150", 0, tvp5150_addrs);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
if (dev->board.adecoder == EM28XX_TVAUDIO)
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"tvaudio", dev->board.tvaudio_addr, NULL);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
/* Initialize tuner and camera */
|
|
|
|
|
|
|
|
if (dev->board.tuner_type != TUNER_ABSENT) {
|
2014-03-25 03:33:24 +08:00
|
|
|
unsigned short tuner_addr = dev->board.tuner_addr;
|
2014-03-25 03:33:23 +08:00
|
|
|
int has_demod = (dev->board.tda9887_conf & TDA9887_PRESENT);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
if (dev->board.radio.type)
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
2014-11-28 19:34:15 +08:00
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"tuner", dev->board.radio_addr,
|
|
|
|
NULL);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
if (has_demod)
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
2014-11-28 19:34:15 +08:00
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"tuner", 0,
|
|
|
|
v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
|
2014-03-25 03:33:24 +08:00
|
|
|
if (tuner_addr == 0) {
|
2013-12-23 00:16:49 +08:00
|
|
|
enum v4l2_i2c_tuner_type type =
|
|
|
|
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
|
|
|
|
struct v4l2_subdev *sd;
|
|
|
|
|
2014-03-25 03:33:09 +08:00
|
|
|
sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
2014-11-28 19:34:15 +08:00
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
|
|
|
"tuner", 0,
|
|
|
|
v4l2_i2c_tuner_addrs(type));
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
if (sd)
|
2014-03-25 03:33:24 +08:00
|
|
|
tuner_addr = v4l2_i2c_subdev_addr(sd);
|
2013-12-23 00:16:49 +08:00
|
|
|
} else {
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
|
|
|
|
&dev->i2c_adap[dev->def_i2c_bus],
|
2014-03-25 03:33:24 +08:00
|
|
|
"tuner", tuner_addr, NULL);
|
2013-12-23 00:16:49 +08:00
|
|
|
}
|
2014-03-25 03:33:24 +08:00
|
|
|
|
|
|
|
em28xx_tuner_setup(dev, tuner_addr);
|
2013-12-23 00:16:49 +08:00
|
|
|
}
|
|
|
|
|
2014-01-18 01:45:32 +08:00
|
|
|
if (dev->em28xx_sensor != EM28XX_NOSENSOR)
|
|
|
|
em28xx_init_camera(dev);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
/* Configure audio */
|
|
|
|
ret = em28xx_audio_setup(dev);
|
|
|
|
if (ret < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"%s: Error while setting audio - error [%d]!\n",
|
|
|
|
__func__, ret);
|
2013-12-23 00:16:49 +08:00
|
|
|
goto unregister_dev;
|
|
|
|
}
|
|
|
|
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
|
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2014-11-28 19:34:15 +08:00
|
|
|
V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
|
2013-12-23 00:16:49 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2014-11-28 19:34:15 +08:00
|
|
|
V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
|
2013-12-23 00:16:49 +08:00
|
|
|
} else {
|
|
|
|
/* install the em28xx notify callback */
|
|
|
|
v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
|
2014-11-28 19:34:15 +08:00
|
|
|
em28xx_ctrl_notify, dev);
|
2013-12-23 00:16:49 +08:00
|
|
|
v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
|
2014-11-28 19:34:15 +08:00
|
|
|
em28xx_ctrl_notify, dev);
|
2013-12-23 00:16:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* wake i2c devices */
|
|
|
|
em28xx_wake_i2c(dev);
|
|
|
|
|
|
|
|
/* init video dma queues */
|
|
|
|
INIT_LIST_HEAD(&dev->vidq.active);
|
|
|
|
INIT_LIST_HEAD(&dev->vbiq.active);
|
|
|
|
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->has_msp34xx) {
|
2013-12-23 00:16:49 +08:00
|
|
|
/* Send a reset to other chips via gpio */
|
|
|
|
ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
|
|
|
|
if (ret < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
|
|
|
|
__func__, ret);
|
2013-12-23 00:16:49 +08:00
|
|
|
goto unregister_dev;
|
|
|
|
}
|
2018-03-04 03:49:09 +08:00
|
|
|
usleep_range(10000, 11000);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
|
|
|
|
if (ret < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
|
|
|
|
__func__, ret);
|
2013-12-23 00:16:49 +08:00
|
|
|
goto unregister_dev;
|
|
|
|
}
|
2018-03-04 03:49:09 +08:00
|
|
|
usleep_range(10000, 11000);
|
2013-12-23 00:16:49 +08:00
|
|
|
}
|
|
|
|
|
2009-01-08 09:49:25 +08:00
|
|
|
/* set default norm */
|
2014-03-25 03:33:16 +08:00
|
|
|
v4l2->norm = V4L2_STD_PAL;
|
2014-04-29 03:53:01 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
|
2014-03-25 03:33:18 +08:00
|
|
|
v4l2->interlaced_fieldmode = EM28XX_INTERLACED_DEFAULT;
|
2009-01-08 09:49:25 +08:00
|
|
|
|
2008-12-29 09:18:14 +08:00
|
|
|
/* Analog specific initialization */
|
2014-03-25 03:33:17 +08:00
|
|
|
v4l2->format = &format[0];
|
2012-01-09 03:54:28 +08:00
|
|
|
|
|
|
|
maxw = norm_maxw(dev);
|
2018-03-04 03:49:09 +08:00
|
|
|
/*
|
|
|
|
* MaxPacketSize for em2800 is too small to capture at full resolution
|
|
|
|
* use half of maxw as the scaler can only scale to 50%
|
|
|
|
*/
|
2013-01-05 03:16:24 +08:00
|
|
|
if (dev->board.is_em2800)
|
|
|
|
maxw /= 2;
|
2012-01-09 03:54:28 +08:00
|
|
|
|
2009-07-03 04:34:04 +08:00
|
|
|
em28xx_set_video_format(dev, format[0].fourcc,
|
2012-01-09 03:54:28 +08:00
|
|
|
maxw, norm_maxh(dev));
|
2009-07-03 04:34:04 +08:00
|
|
|
|
2012-03-24 05:09:34 +08:00
|
|
|
video_mux(dev, 0);
|
2009-01-08 09:49:25 +08:00
|
|
|
|
|
|
|
/* Audio defaults */
|
|
|
|
dev->mute = 1;
|
|
|
|
dev->volume = 0x1f;
|
2008-12-29 09:18:14 +08:00
|
|
|
|
|
|
|
/* em28xx_write_reg(dev, EM28XX_R0E_AUDIOSRC, 0xc0); audio register */
|
2009-02-11 10:28:24 +08:00
|
|
|
val = (u8)em28xx_read_reg(dev, EM28XX_R0F_XCLK);
|
|
|
|
em28xx_write_reg(dev, EM28XX_R0F_XCLK,
|
|
|
|
(EM28XX_XCLK_AUDIO_UNMUTE | val));
|
2008-12-29 09:18:14 +08:00
|
|
|
|
|
|
|
em28xx_set_outfmt(dev);
|
|
|
|
|
2013-02-16 01:38:32 +08:00
|
|
|
/* Add image controls */
|
2018-03-04 03:49:09 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* NOTE: at this point, the subdevices are already registered, so
|
|
|
|
* bridge controls are only added/enabled when no subdevice provides
|
|
|
|
* them
|
|
|
|
*/
|
|
|
|
if (!v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST))
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2013-02-16 01:38:32 +08:00
|
|
|
V4L2_CID_CONTRAST,
|
|
|
|
0, 0x1f, 1, CONTRAST_DEFAULT);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS))
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2013-02-16 01:38:32 +08:00
|
|
|
V4L2_CID_BRIGHTNESS,
|
|
|
|
-0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!v4l2_ctrl_find(hdl, V4L2_CID_SATURATION))
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2013-02-16 01:38:32 +08:00
|
|
|
V4L2_CID_SATURATION,
|
|
|
|
0, 0x1f, 1, SATURATION_DEFAULT);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE))
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2013-02-16 01:38:32 +08:00
|
|
|
V4L2_CID_BLUE_BALANCE,
|
|
|
|
-0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE))
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2013-02-16 01:38:32 +08:00
|
|
|
V4L2_CID_RED_BALANCE,
|
|
|
|
-0x30, 0x30, 1, RED_BALANCE_DEFAULT);
|
2018-03-04 03:49:09 +08:00
|
|
|
if (!v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS))
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
|
2013-02-16 01:38:32 +08:00
|
|
|
V4L2_CID_SHARPNESS,
|
|
|
|
0, 0x0f, 1, SHARPNESS_DEFAULT);
|
|
|
|
|
|
|
|
/* Reset image controls */
|
|
|
|
em28xx_colorlevels_set_default(dev);
|
2014-03-25 03:33:08 +08:00
|
|
|
v4l2_ctrl_handler_setup(hdl);
|
|
|
|
ret = hdl->error;
|
2013-12-23 00:16:49 +08:00
|
|
|
if (ret)
|
|
|
|
goto unregister_dev;
|
2013-02-16 01:38:32 +08:00
|
|
|
|
2008-11-20 21:30:26 +08:00
|
|
|
/* allocate and fill video video_device struct */
|
2015-03-10 00:34:06 +08:00
|
|
|
em28xx_vdev_init(dev, &v4l2->vdev, &em28xx_video_template, "video");
|
2014-03-25 03:33:13 +08:00
|
|
|
mutex_init(&v4l2->vb_queue_lock);
|
|
|
|
mutex_init(&v4l2->vb_vbi_queue_lock);
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2->vdev.queue = &v4l2->vb_vidq;
|
|
|
|
v4l2->vdev.queue->lock = &v4l2->vb_queue_lock;
|
2008-11-20 21:30:26 +08:00
|
|
|
|
2013-02-08 00:39:09 +08:00
|
|
|
/* disable inapplicable ioctls */
|
2018-03-01 23:08:42 +08:00
|
|
|
if (dev->is_webcam) {
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_QUERYSTD);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_STD);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_STD);
|
2013-02-08 00:39:12 +08:00
|
|
|
} else {
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_PARM);
|
2013-02-08 00:39:09 +08:00
|
|
|
}
|
2013-02-08 00:39:10 +08:00
|
|
|
if (dev->tuner_type == TUNER_ABSENT) {
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_TUNER);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_TUNER);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_FREQUENCY);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_FREQUENCY);
|
2013-02-08 00:39:10 +08:00
|
|
|
}
|
2014-09-13 16:52:21 +08:00
|
|
|
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_G_AUDIO);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vdev, VIDIOC_S_AUDIO);
|
2013-02-08 00:39:11 +08:00
|
|
|
}
|
2013-02-08 00:39:09 +08:00
|
|
|
|
2008-11-20 21:30:26 +08:00
|
|
|
/* register v4l2 video video_device */
|
2015-03-10 00:34:06 +08:00
|
|
|
ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER,
|
2014-11-28 19:34:15 +08:00
|
|
|
video_nr[dev->devno]);
|
2008-11-20 21:30:26 +08:00
|
|
|
if (ret) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"unable to register video device (error=%i).\n", ret);
|
2013-12-23 00:16:49 +08:00
|
|
|
goto unregister_dev;
|
2008-11-20 21:30:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate and fill vbi video_device struct */
|
2009-09-11 11:01:06 +08:00
|
|
|
if (em28xx_vbi_supported(dev) == 1) {
|
2015-03-10 00:34:06 +08:00
|
|
|
em28xx_vdev_init(dev, &v4l2->vbi_dev, &em28xx_video_template,
|
2018-03-04 03:49:09 +08:00
|
|
|
"vbi");
|
2008-11-20 21:30:26 +08:00
|
|
|
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2->vbi_dev.queue = &v4l2->vb_vbiq;
|
|
|
|
v4l2->vbi_dev.queue->lock = &v4l2->vb_vbi_queue_lock;
|
2013-01-05 03:16:24 +08:00
|
|
|
|
2013-02-08 00:39:10 +08:00
|
|
|
/* disable inapplicable ioctls */
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_PARM);
|
2013-02-08 00:39:10 +08:00
|
|
|
if (dev->tuner_type == TUNER_ABSENT) {
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_TUNER);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_TUNER);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
|
2013-02-08 00:39:10 +08:00
|
|
|
}
|
2014-09-13 16:52:21 +08:00
|
|
|
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE) {
|
2015-03-10 00:34:06 +08:00
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_G_AUDIO);
|
|
|
|
v4l2_disable_ioctl(&v4l2->vbi_dev, VIDIOC_S_AUDIO);
|
2013-02-08 00:39:11 +08:00
|
|
|
}
|
2013-02-08 00:39:10 +08:00
|
|
|
|
2009-09-11 11:01:06 +08:00
|
|
|
/* register v4l2 vbi video_device */
|
2015-03-10 00:34:06 +08:00
|
|
|
ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI,
|
2009-09-11 11:01:06 +08:00
|
|
|
vbi_nr[dev->devno]);
|
|
|
|
if (ret < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"unable to register vbi device\n");
|
2013-12-23 00:16:49 +08:00
|
|
|
goto unregister_dev;
|
2009-09-11 11:01:06 +08:00
|
|
|
}
|
2008-11-20 21:30:26 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
|
2015-03-10 00:34:06 +08:00
|
|
|
em28xx_vdev_init(dev, &v4l2->radio_dev, &em28xx_radio_template,
|
2018-03-04 03:49:09 +08:00
|
|
|
"radio");
|
2015-03-10 00:34:06 +08:00
|
|
|
ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO,
|
2008-11-20 21:30:26 +08:00
|
|
|
radio_nr[dev->devno]);
|
|
|
|
if (ret < 0) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"can't register radio device\n");
|
2013-12-23 00:16:49 +08:00
|
|
|
goto unregister_dev;
|
2008-11-20 21:30:26 +08:00
|
|
|
}
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"Registered radio device as %s\n",
|
|
|
|
video_device_node_name(&v4l2->radio_dev));
|
2008-11-20 21:30:26 +08:00
|
|
|
}
|
|
|
|
|
2016-01-27 17:07:24 +08:00
|
|
|
/* Init entities at the Media Controller */
|
|
|
|
em28xx_v4l2_create_entities(dev);
|
|
|
|
|
2016-02-26 19:53:22 +08:00
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
2016-02-05 17:08:25 +08:00
|
|
|
ret = v4l2_mc_create_media_graph(dev->media_dev);
|
2016-01-27 17:07:24 +08:00
|
|
|
if (ret) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_err(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"failed to create media graph\n");
|
2016-01-27 17:07:24 +08:00
|
|
|
em28xx_v4l2_media_release(dev);
|
|
|
|
goto unregister_dev;
|
|
|
|
}
|
2016-02-26 19:53:22 +08:00
|
|
|
#endif
|
2016-01-27 17:07:24 +08:00
|
|
|
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"V4L2 video device registered as %s\n",
|
|
|
|
video_device_node_name(&v4l2->vdev));
|
2009-09-11 11:01:06 +08:00
|
|
|
|
2015-03-10 00:34:06 +08:00
|
|
|
if (video_is_registered(&v4l2->vbi_dev))
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"V4L2 VBI device registered as %s\n",
|
|
|
|
video_device_node_name(&v4l2->vbi_dev));
|
2008-11-20 21:30:26 +08:00
|
|
|
|
2013-12-23 00:16:49 +08:00
|
|
|
/* Save some power by putting tuner to sleep */
|
media: add tuner standby op, use where needed
The v4l2_subdev core s_power op was used for two different things: power on/off
sensors or video decoders/encoders and to put a tuner in standby (and only the
tuner!). There is no 'tuner wakeup' op, that's done automatically when the tuner
is accessed.
The danger with calling (s_power, 0) to put a tuner into standby is that it is
usually broadcast for all subdevs. So a video receiver subdev that supports
s_power will also be powered off, and since there is no corresponding (s_power, 1)
they will never be powered on again.
In addition, this is specifically meant for tuners only since they draw the most
current.
This patch adds a new tuner op called 'standby' and replaces all calls to
(core, s_power, 0) by (tuner, standby). This prevents confusion between the two
uses of s_power. Note that there is no overlap: bridge drivers either just want
to put the tuner into standby, or they deal with powering on/off sensors. Never
both.
This also makes it easier to replace s_power for the remaining bridge drivers
with some PM code later.
Whether we want something cleaner for tuners in the future is a separate topic.
There is a lot of legacy code surrounding tuners, and I am very hesitant about
making changes there.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2018-02-21 15:49:25 +08:00
|
|
|
v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, standby);
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
/* initialize videobuf2 stuff */
|
|
|
|
em28xx_vb2_setup(dev);
|
|
|
|
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"V4L2 extension successfully initialized\n");
|
2013-12-26 23:41:03 +08:00
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_get(&dev->ref);
|
|
|
|
|
2013-12-23 00:27:02 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2008-11-20 21:30:26 +08:00
|
|
|
return 0;
|
2013-12-23 00:16:49 +08:00
|
|
|
|
|
|
|
unregister_dev:
|
2016-01-29 23:08:19 +08:00
|
|
|
if (video_is_registered(&v4l2->radio_dev)) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"V4L2 device %s deregistered\n",
|
|
|
|
video_device_node_name(&v4l2->radio_dev));
|
2016-01-29 23:08:19 +08:00
|
|
|
video_unregister_device(&v4l2->radio_dev);
|
|
|
|
}
|
|
|
|
if (video_is_registered(&v4l2->vbi_dev)) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"V4L2 device %s deregistered\n",
|
|
|
|
video_device_node_name(&v4l2->vbi_dev));
|
2016-01-29 23:08:19 +08:00
|
|
|
video_unregister_device(&v4l2->vbi_dev);
|
|
|
|
}
|
|
|
|
if (video_is_registered(&v4l2->vdev)) {
|
2016-12-07 23:48:10 +08:00
|
|
|
dev_info(&dev->intf->dev,
|
2016-10-20 18:42:03 +08:00
|
|
|
"V4L2 device %s deregistered\n",
|
|
|
|
video_device_node_name(&v4l2->vdev));
|
2016-01-29 23:08:19 +08:00
|
|
|
video_unregister_device(&v4l2->vdev);
|
|
|
|
}
|
|
|
|
|
2014-03-25 03:33:10 +08:00
|
|
|
v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
|
2014-03-25 03:33:09 +08:00
|
|
|
v4l2_device_unregister(&v4l2->v4l2_dev);
|
2013-12-23 00:16:49 +08:00
|
|
|
err:
|
2014-03-25 03:33:09 +08:00
|
|
|
dev->v4l2 = NULL;
|
|
|
|
kref_put(&v4l2->ref, em28xx_free_v4l2);
|
2013-12-23 00:27:02 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2013-12-23 00:16:49 +08:00
|
|
|
return ret;
|
2008-11-20 21:30:26 +08:00
|
|
|
}
|
2013-12-23 00:27:02 +08:00
|
|
|
|
|
|
|
static struct em28xx_ops v4l2_ops = {
|
|
|
|
.id = EM28XX_V4L2,
|
|
|
|
.name = "Em28xx v4l2 Extension",
|
|
|
|
.init = em28xx_v4l2_init,
|
|
|
|
.fini = em28xx_v4l2_fini,
|
2014-02-22 08:50:17 +08:00
|
|
|
.suspend = em28xx_v4l2_suspend,
|
|
|
|
.resume = em28xx_v4l2_resume,
|
2013-12-23 00:27:02 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init em28xx_video_register(void)
|
|
|
|
{
|
|
|
|
return em28xx_register_extension(&v4l2_ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit em28xx_video_unregister(void)
|
|
|
|
{
|
|
|
|
em28xx_unregister_extension(&v4l2_ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(em28xx_video_register);
|
|
|
|
module_exit(em28xx_video_unregister);
|