2009-03-11 14:00:40 +08:00
|
|
|
/*
|
|
|
|
* Auvitek AU0828 USB Bridge (Analog video support)
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009 Devin Heitmueller <dheitmueller@linuxtv.org>
|
|
|
|
* Copyright (C) 2005-2008 Auvitek International, Ltd.
|
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Developer Notes:
|
|
|
|
*
|
|
|
|
* The hardware scaler supported is unimplemented
|
|
|
|
* AC97 audio support is unimplemented (only i2s audio mode)
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-08-10 08:47:17 +08:00
|
|
|
#include "au0828.h"
|
2016-02-12 07:41:28 +08:00
|
|
|
#include "au8522.h"
|
2014-08-10 08:47:17 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
#include <linux/module.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>
|
2009-03-11 14:00:40 +08:00
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <media/v4l2-common.h>
|
2016-03-02 21:11:41 +08:00
|
|
|
#include <media/v4l2-mc.h>
|
2009-03-11 14:00:40 +08:00
|
|
|
#include <media/v4l2-ioctl.h>
|
2013-02-15 20:14:00 +08:00
|
|
|
#include <media/v4l2-event.h>
|
2009-03-11 14:00:40 +08:00
|
|
|
#include <media/tuner.h>
|
|
|
|
#include "au0828-reg.h"
|
|
|
|
|
|
|
|
static DEFINE_MUTEX(au0828_sysfs_lock);
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------
|
|
|
|
Videobuf operations
|
|
|
|
------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
static unsigned int isoc_debug;
|
|
|
|
module_param(isoc_debug, int, 0644);
|
|
|
|
MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
|
|
|
|
|
|
|
|
#define au0828_isocdbg(fmt, arg...) \
|
|
|
|
do {\
|
|
|
|
if (isoc_debug) { \
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("au0828 %s :"fmt, \
|
2009-03-11 14:00:40 +08:00
|
|
|
__func__ , ##arg); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
2013-03-12 03:10:33 +08:00
|
|
|
static inline void i2c_gate_ctrl(struct au0828_dev *dev, int val)
|
|
|
|
{
|
|
|
|
if (dev->dvb.frontend && dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl)
|
|
|
|
dev->dvb.frontend->ops.analog_ops.i2c_gate_ctrl(dev->dvb.frontend, val);
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
static inline void print_err_status(struct au0828_dev *dev,
|
|
|
|
int packet, int status)
|
|
|
|
{
|
|
|
|
char *errmsg = "Unknown";
|
|
|
|
|
|
|
|
switch (status) {
|
|
|
|
case -ENOENT:
|
2017-11-02 18:11:53 +08:00
|
|
|
errmsg = "unlinked synchronously";
|
2009-03-11 14:00:40 +08:00
|
|
|
break;
|
|
|
|
case -ECONNRESET:
|
2017-11-02 18:11:53 +08:00
|
|
|
errmsg = "unlinked asynchronously";
|
2009-03-11 14:00:40 +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;
|
|
|
|
}
|
|
|
|
if (packet < 0) {
|
|
|
|
au0828_isocdbg("URB status %d [%s].\n", status, errmsg);
|
|
|
|
} else {
|
|
|
|
au0828_isocdbg("URB packet %d, status %d [%s].\n",
|
|
|
|
packet, status, errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_dev(struct au0828_dev *dev)
|
|
|
|
{
|
2016-03-22 20:21:57 +08:00
|
|
|
if (test_bit(DEV_DISCONNECTED, &dev->dev_state)) {
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("v4l2 ioctl: device not present\n");
|
2009-03-11 14:00:40 +08:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
if (test_bit(DEV_MISCONFIGURED, &dev->dev_state)) {
|
|
|
|
pr_info("v4l2 ioctl: device is misconfigured; close and open it again\n");
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* IRQ callback, called by URB callback
|
|
|
|
*/
|
|
|
|
static void au0828_irq_callback(struct urb *urb)
|
|
|
|
{
|
|
|
|
struct au0828_dmaqueue *dma_q = urb->context;
|
|
|
|
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
|
2010-10-10 01:43:53 +08:00
|
|
|
unsigned long flags = 0;
|
2012-05-14 21:17:35 +08:00
|
|
|
int i;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
switch (urb->status) {
|
|
|
|
case 0: /* success */
|
|
|
|
case -ETIMEDOUT: /* NAK */
|
|
|
|
break;
|
|
|
|
case -ECONNRESET: /* kill */
|
|
|
|
case -ENOENT:
|
|
|
|
case -ESHUTDOWN:
|
|
|
|
au0828_isocdbg("au0828_irq_callback called: status kill\n");
|
|
|
|
return;
|
|
|
|
default: /* unknown error */
|
2018-08-03 22:35:58 +08:00
|
|
|
au0828_isocdbg("urb completion error %d.\n", urb->status);
|
2009-03-11 14:00:40 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy data from URB */
|
2010-10-10 01:43:53 +08:00
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
2012-05-14 21:17:35 +08:00
|
|
|
dev->isoc_ctl.isoc_copy(dev, urb);
|
2010-10-10 01:43:53 +08:00
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
/* Reset urb buffers */
|
|
|
|
for (i = 0; i < urb->number_of_packets; i++) {
|
|
|
|
urb->iso_frame_desc[i].status = 0;
|
|
|
|
urb->iso_frame_desc[i].actual_length = 0;
|
|
|
|
}
|
|
|
|
urb->status = 0;
|
|
|
|
|
|
|
|
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
|
|
|
|
if (urb->status) {
|
|
|
|
au0828_isocdbg("urb resubmit failed (error=%i)\n",
|
|
|
|
urb->status);
|
|
|
|
}
|
2014-08-10 08:47:14 +08:00
|
|
|
dev->stream_state = STREAM_ON;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Stop and Deallocate URBs
|
|
|
|
*/
|
2012-10-28 01:00:30 +08:00
|
|
|
static void au0828_uninit_isoc(struct au0828_dev *dev)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
|
|
|
struct urb *urb;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
au0828_isocdbg("au0828: called au0828_uninit_isoc\n");
|
|
|
|
|
|
|
|
dev->isoc_ctl.nfields = -1;
|
|
|
|
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
|
|
|
|
urb = dev->isoc_ctl.urb[i];
|
|
|
|
if (urb) {
|
|
|
|
if (!irqs_disabled())
|
|
|
|
usb_kill_urb(urb);
|
|
|
|
else
|
|
|
|
usb_unlink_urb(urb);
|
|
|
|
|
|
|
|
if (dev->isoc_ctl.transfer_buffer[i]) {
|
2010-04-12 19:17:25 +08:00
|
|
|
usb_free_coherent(dev->usbdev,
|
2009-03-11 14:00:40 +08:00
|
|
|
urb->transfer_buffer_length,
|
|
|
|
dev->isoc_ctl.transfer_buffer[i],
|
|
|
|
urb->transfer_dma);
|
|
|
|
}
|
|
|
|
usb_free_urb(urb);
|
|
|
|
dev->isoc_ctl.urb[i] = NULL;
|
|
|
|
}
|
|
|
|
dev->isoc_ctl.transfer_buffer[i] = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(dev->isoc_ctl.urb);
|
|
|
|
kfree(dev->isoc_ctl.transfer_buffer);
|
|
|
|
|
|
|
|
dev->isoc_ctl.urb = NULL;
|
|
|
|
dev->isoc_ctl.transfer_buffer = NULL;
|
|
|
|
dev->isoc_ctl.num_bufs = 0;
|
2014-08-10 08:47:14 +08:00
|
|
|
|
|
|
|
dev->stream_state = STREAM_OFF;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate URBs and start IRQ
|
|
|
|
*/
|
2012-10-28 01:00:30 +08:00
|
|
|
static int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
|
|
|
|
int num_bufs, int max_pkt_size,
|
|
|
|
int (*isoc_copy) (struct au0828_dev *dev, struct urb *urb))
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
|
|
|
struct au0828_dmaqueue *dma_q = &dev->vidq;
|
|
|
|
int i;
|
|
|
|
int sb_size, pipe;
|
|
|
|
struct urb *urb;
|
|
|
|
int j, k;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
|
|
|
|
|
|
|
|
dev->isoc_ctl.isoc_copy = isoc_copy;
|
|
|
|
dev->isoc_ctl.num_bufs = num_bufs;
|
|
|
|
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:03:40 +08:00
|
|
|
dev->isoc_ctl.urb = kcalloc(num_bufs, sizeof(void *), GFP_KERNEL);
|
2009-03-11 14:00:40 +08:00
|
|
|
if (!dev->isoc_ctl.urb) {
|
|
|
|
au0828_isocdbg("cannot alloc memory for usb buffers\n");
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
treewide: kzalloc() -> kcalloc()
The kzalloc() function has a 2-factor argument form, kcalloc(). This
patch replaces cases of:
kzalloc(a * b, gfp)
with:
kcalloc(a * b, gfp)
as well as handling cases of:
kzalloc(a * b * c, gfp)
with:
kzalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kzalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kzalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kzalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kzalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kzalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kzalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kzalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kzalloc
+ kcalloc
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kzalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kzalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kzalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kzalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kzalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kzalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kzalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kzalloc(sizeof(THING) * C2, ...)
|
kzalloc(sizeof(TYPE) * C2, ...)
|
kzalloc(C1 * C2 * C3, ...)
|
kzalloc(C1 * C2, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * E2
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kzalloc
+ kcalloc
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-13 05:03:40 +08:00
|
|
|
dev->isoc_ctl.transfer_buffer = kcalloc(num_bufs, sizeof(void *),
|
|
|
|
GFP_KERNEL);
|
2009-03-11 14:00:40 +08:00
|
|
|
if (!dev->isoc_ctl.transfer_buffer) {
|
|
|
|
au0828_isocdbg("cannot allocate memory for usb transfer\n");
|
|
|
|
kfree(dev->isoc_ctl.urb);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->isoc_ctl.max_pkt_size = max_pkt_size;
|
|
|
|
dev->isoc_ctl.buf = NULL;
|
|
|
|
|
|
|
|
sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
|
|
|
|
|
|
|
|
/* allocate urbs and transfer buffers */
|
|
|
|
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
|
|
|
|
urb = usb_alloc_urb(max_packets, GFP_KERNEL);
|
|
|
|
if (!urb) {
|
|
|
|
au0828_uninit_isoc(dev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
dev->isoc_ctl.urb[i] = urb;
|
|
|
|
|
2010-04-12 19:17:25 +08:00
|
|
|
dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev,
|
2009-03-11 14:00:40 +08:00
|
|
|
sb_size, GFP_KERNEL, &urb->transfer_dma);
|
|
|
|
if (!dev->isoc_ctl.transfer_buffer[i]) {
|
[media] au0828: don't break long lines
Due to the 80-cols restrictions, and latter due to checkpatch
warnings, several strings were broken into multiple lines. This
is not considered a good practice anymore, as it makes harder
to grep for strings at the source code.
As we're right now fixing other drivers due to KERN_CONT, we need
to be able to identify what printk strings don't end with a "\n".
It is a way easier to detect those if we don't break long lines.
So, join those continuation lines.
The patch was generated via the script below, and manually
adjusted if needed.
</script>
use Text::Tabs;
while (<>) {
if ($next ne "") {
$c=$_;
if ($c =~ /^\s+\"(.*)/) {
$c2=$1;
$next =~ s/\"\n$//;
$n = expand($next);
$funpos = index($n, '(');
$pos = index($c2, '",');
if ($funpos && $pos > 0) {
$s1 = substr $c2, 0, $pos + 2;
$s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2;
$s2 =~ s/^\s+//;
$s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne "");
print unexpand("$next$s1\n");
print unexpand("$s2\n") if ($s2 ne "");
} else {
print "$next$c2\n";
}
$next="";
next;
} else {
print $next;
}
$next="";
} else {
if (m/\"$/) {
if (!m/\\n\"$/) {
$next=$_;
next;
}
}
}
print $_;
}
</script>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
2016-10-19 03:44:13 +08:00
|
|
|
printk("unable to allocate %i bytes for transfer buffer %i%s\n",
|
2009-03-11 14:00:40 +08:00
|
|
|
sb_size, i,
|
|
|
|
in_interrupt() ? " while in int" : "");
|
|
|
|
au0828_uninit_isoc(dev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
|
|
|
|
|
|
|
|
pipe = usb_rcvisocpipe(dev->usbdev,
|
|
|
|
dev->isoc_in_endpointaddr),
|
|
|
|
|
|
|
|
usb_fill_int_urb(urb, dev->usbdev, pipe,
|
|
|
|
dev->isoc_ctl.transfer_buffer[i], sb_size,
|
|
|
|
au0828_irq_callback, dma_q, 1);
|
|
|
|
|
|
|
|
urb->number_of_packets = max_packets;
|
2009-03-23 10:42:26 +08:00
|
|
|
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
k = 0;
|
|
|
|
for (j = 0; j < max_packets; j++) {
|
|
|
|
urb->iso_frame_desc[j].offset = k;
|
|
|
|
urb->iso_frame_desc[j].length =
|
|
|
|
dev->isoc_ctl.max_pkt_size;
|
|
|
|
k += dev->isoc_ctl.max_pkt_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* submit urbs and enables IRQ */
|
|
|
|
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
|
|
|
|
rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
|
|
|
|
if (rc) {
|
|
|
|
au0828_isocdbg("submit of urb %i failed (error=%i)\n",
|
|
|
|
i, rc);
|
|
|
|
au0828_uninit_isoc(dev);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Announces that a buffer were filled and request the next
|
|
|
|
*/
|
|
|
|
static inline void buffer_filled(struct au0828_dev *dev,
|
2015-02-24 21:00:29 +08:00
|
|
|
struct au0828_dmaqueue *dma_q,
|
|
|
|
struct au0828_buffer *buf)
|
2009-03-11 14:00:40 +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 *vb = &buf->vb;
|
|
|
|
struct vb2_queue *q = vb->vb2_buf.vb2_queue;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
/* Advice that buffer was filled */
|
2015-01-30 00:41:32 +08:00
|
|
|
au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
|
2010-05-30 04:18:45 +08:00
|
|
|
|
2015-02-24 21:00:29 +08:00
|
|
|
if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
[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
|
|
|
vb->sequence = dev->frame_count++;
|
2015-02-24 21:00:29 +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
|
|
|
vb->sequence = dev->vbi_frame_count++;
|
2015-02-24 21:00:29 +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
|
|
|
vb->field = V4L2_FIELD_INTERLACED;
|
2015-11-03 18:16:37 +08:00
|
|
|
vb->vb2_buf.timestamp = ktime_get_ns();
|
[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(&vb->vb2_buf, VB2_BUF_STATE_DONE);
|
2010-05-30 04:18:45 +08:00
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
/*
|
|
|
|
* Identify the buffer header type and properly handles
|
|
|
|
*/
|
|
|
|
static void au0828_copy_video(struct au0828_dev *dev,
|
|
|
|
struct au0828_dmaqueue *dma_q,
|
|
|
|
struct au0828_buffer *buf,
|
|
|
|
unsigned char *p,
|
|
|
|
unsigned char *outp, unsigned long len)
|
|
|
|
{
|
|
|
|
void *fieldstart, *startwrite, *startread;
|
|
|
|
int linesdone, currlinedone, offset, lencopy, remain;
|
|
|
|
int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
if (len == 0)
|
|
|
|
return;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (dma_q->pos + len > buf->length)
|
|
|
|
len = buf->length - dma_q->pos;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
startread = p;
|
|
|
|
remain = len;
|
|
|
|
|
|
|
|
/* Interlaces frame */
|
|
|
|
if (buf->top_field)
|
|
|
|
fieldstart = outp;
|
|
|
|
else
|
|
|
|
fieldstart = outp + bytesperline;
|
|
|
|
|
|
|
|
linesdone = dma_q->pos / bytesperline;
|
|
|
|
currlinedone = dma_q->pos % bytesperline;
|
|
|
|
offset = linesdone * bytesperline * 2 + currlinedone;
|
|
|
|
startwrite = fieldstart + offset;
|
|
|
|
lencopy = bytesperline - currlinedone;
|
|
|
|
lencopy = lencopy > remain ? remain : lencopy;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if ((char *)startwrite + lencopy > (char *)outp + buf->length) {
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
|
|
|
|
((char *)startwrite + lencopy) -
|
2015-01-30 00:41:32 +08:00
|
|
|
((char *)outp + buf->length));
|
|
|
|
remain = (char *)outp + buf->length - (char *)startwrite;
|
2009-03-11 14:00:40 +08:00
|
|
|
lencopy = remain;
|
|
|
|
}
|
|
|
|
if (lencopy <= 0)
|
|
|
|
return;
|
|
|
|
memcpy(startwrite, startread, lencopy);
|
|
|
|
|
|
|
|
remain -= lencopy;
|
|
|
|
|
|
|
|
while (remain > 0) {
|
|
|
|
startwrite += lencopy + bytesperline;
|
|
|
|
startread += lencopy;
|
|
|
|
if (bytesperline > remain)
|
|
|
|
lencopy = remain;
|
|
|
|
else
|
|
|
|
lencopy = bytesperline;
|
|
|
|
|
|
|
|
if ((char *)startwrite + lencopy > (char *)outp +
|
2015-01-30 00:41:32 +08:00
|
|
|
buf->length) {
|
2009-03-16 05:48:52 +08:00
|
|
|
au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
|
2009-03-11 14:00:40 +08:00
|
|
|
((char *)startwrite + lencopy) -
|
2015-01-30 00:41:32 +08:00
|
|
|
((char *)outp + buf->length));
|
|
|
|
lencopy = remain = (char *)outp + buf->length -
|
2009-03-11 14:00:40 +08:00
|
|
|
(char *)startwrite;
|
|
|
|
}
|
|
|
|
if (lencopy <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
memcpy(startwrite, startread, lencopy);
|
|
|
|
|
|
|
|
remain -= lencopy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (offset > 1440) {
|
|
|
|
/* We have enough data to check for greenscreen */
|
2009-03-16 05:48:52 +08:00
|
|
|
if (outp[0] < 0x60 && outp[1440] < 0x60)
|
2009-03-11 14:00:40 +08:00
|
|
|
dev->greenscreen_detected = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
dma_q->pos += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* video-buf generic routine to get the next available buffer
|
|
|
|
*/
|
|
|
|
static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
|
|
|
|
struct au0828_buffer **buf)
|
|
|
|
{
|
|
|
|
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
|
|
|
|
|
|
|
|
if (list_empty(&dma_q->active)) {
|
|
|
|
au0828_isocdbg("No active queue to serve\n");
|
|
|
|
dev->isoc_ctl.buf = NULL;
|
|
|
|
*buf = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the next buffer */
|
2015-01-30 00:41:32 +08:00
|
|
|
*buf = list_entry(dma_q->active.next, struct au0828_buffer, list);
|
|
|
|
/* Cleans up buffer - Useful for testing for frame/URB loss */
|
|
|
|
list_del(&(*buf)->list);
|
|
|
|
dma_q->pos = 0;
|
|
|
|
(*buf)->vb_buf = (*buf)->mem;
|
2009-03-11 14:00:40 +08:00
|
|
|
dev->isoc_ctl.buf = *buf;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
static void au0828_copy_vbi(struct au0828_dev *dev,
|
|
|
|
struct au0828_dmaqueue *dma_q,
|
|
|
|
struct au0828_buffer *buf,
|
|
|
|
unsigned char *p,
|
|
|
|
unsigned char *outp, unsigned long len)
|
|
|
|
{
|
|
|
|
unsigned char *startwrite, *startread;
|
2010-07-23 18:09:20 +08:00
|
|
|
int bytesperline;
|
2010-05-30 04:18:45 +08:00
|
|
|
int i, j = 0;
|
|
|
|
|
|
|
|
if (dev == NULL) {
|
|
|
|
au0828_isocdbg("dev is null\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dma_q == NULL) {
|
|
|
|
au0828_isocdbg("dma_q is null\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (buf == NULL)
|
|
|
|
return;
|
|
|
|
if (p == NULL) {
|
|
|
|
au0828_isocdbg("p is null\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (outp == NULL) {
|
|
|
|
au0828_isocdbg("outp is null\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-07-23 18:09:20 +08:00
|
|
|
bytesperline = dev->vbi_width;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (dma_q->pos + len > buf->length)
|
|
|
|
len = buf->length - dma_q->pos;
|
2010-05-30 04:18:45 +08:00
|
|
|
|
|
|
|
startread = p;
|
|
|
|
startwrite = outp + (dma_q->pos / 2);
|
|
|
|
|
|
|
|
/* Make sure the bottom field populates the second half of the frame */
|
|
|
|
if (buf->top_field == 0)
|
|
|
|
startwrite += bytesperline * dev->vbi_height;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i += 2)
|
|
|
|
startwrite[j++] = startread[i+1];
|
|
|
|
|
|
|
|
dma_q->pos += len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* video-buf generic routine to get the next available VBI buffer
|
|
|
|
*/
|
|
|
|
static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
|
|
|
|
struct au0828_buffer **buf)
|
|
|
|
{
|
|
|
|
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
|
|
|
|
|
|
|
|
if (list_empty(&dma_q->active)) {
|
|
|
|
au0828_isocdbg("No active queue to serve\n");
|
|
|
|
dev->isoc_ctl.vbi_buf = NULL;
|
|
|
|
*buf = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get the next buffer */
|
2015-01-30 00:41:32 +08:00
|
|
|
*buf = list_entry(dma_q->active.next, struct au0828_buffer, list);
|
2011-03-31 09:57:33 +08:00
|
|
|
/* Cleans up buffer - Useful for testing for frame/URB loss */
|
2015-01-30 00:41:32 +08:00
|
|
|
list_del(&(*buf)->list);
|
|
|
|
dma_q->pos = 0;
|
|
|
|
(*buf)->vb_buf = (*buf)->mem;
|
2010-05-30 04:18:45 +08:00
|
|
|
dev->isoc_ctl.vbi_buf = *buf;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
/*
|
|
|
|
* Controls the isoc copy of each urb packet
|
|
|
|
*/
|
|
|
|
static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
|
|
|
|
{
|
|
|
|
struct au0828_buffer *buf;
|
2010-05-30 04:18:45 +08:00
|
|
|
struct au0828_buffer *vbi_buf;
|
2009-03-11 14:00:40 +08:00
|
|
|
struct au0828_dmaqueue *dma_q = urb->context;
|
2010-05-30 04:18:45 +08:00
|
|
|
struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq;
|
2009-03-11 14:00:40 +08:00
|
|
|
unsigned char *outp = NULL;
|
2010-05-30 04:18:45 +08:00
|
|
|
unsigned char *vbioutp = NULL;
|
2009-03-11 14:00:40 +08:00
|
|
|
int i, len = 0, rc = 1;
|
|
|
|
unsigned char *p;
|
|
|
|
unsigned char fbyte;
|
2010-05-30 04:18:45 +08:00
|
|
|
unsigned int vbi_field_size;
|
|
|
|
unsigned int remain, lencopy;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
if (!dev)
|
|
|
|
return 0;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
if (test_bit(DEV_DISCONNECTED, &dev->dev_state) ||
|
|
|
|
test_bit(DEV_MISCONFIGURED, &dev->dev_state))
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (urb->status < 0) {
|
|
|
|
print_err_status(dev, -1, urb->status);
|
|
|
|
if (urb->status == -ENOENT)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
buf = dev->isoc_ctl.buf;
|
|
|
|
if (buf != NULL)
|
[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
|
|
|
outp = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
vbi_buf = dev->isoc_ctl.vbi_buf;
|
|
|
|
if (vbi_buf != NULL)
|
[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
|
|
|
vbioutp = vb2_plane_vaddr(&vbi_buf->vb.vb2_buf, 0);
|
2010-05-30 04:18:45 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
for (i = 0; i < urb->number_of_packets; i++) {
|
|
|
|
int status = urb->iso_frame_desc[i].status;
|
|
|
|
|
|
|
|
if (status < 0) {
|
|
|
|
print_err_status(dev, i, status);
|
|
|
|
if (urb->iso_frame_desc[i].status != -EPROTO)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (urb->iso_frame_desc[i].actual_length <= 0)
|
2009-03-11 14:00:40 +08:00
|
|
|
continue;
|
2009-03-16 05:48:52 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
if (urb->iso_frame_desc[i].actual_length >
|
|
|
|
dev->max_pkt_size) {
|
|
|
|
au0828_isocdbg("packet bigger than packet size");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
|
|
|
|
fbyte = p[0];
|
|
|
|
len = urb->iso_frame_desc[i].actual_length - 4;
|
|
|
|
p += 4;
|
|
|
|
|
|
|
|
if (fbyte & 0x80) {
|
|
|
|
len -= 4;
|
|
|
|
p += 4;
|
|
|
|
au0828_isocdbg("Video frame %s\n",
|
|
|
|
(fbyte & 0x40) ? "odd" : "even");
|
2010-07-06 00:05:16 +08:00
|
|
|
if (fbyte & 0x40) {
|
2010-05-30 04:18:45 +08:00
|
|
|
/* VBI */
|
|
|
|
if (vbi_buf != NULL)
|
2015-02-24 21:00:29 +08:00
|
|
|
buffer_filled(dev, vbi_dma_q, vbi_buf);
|
2010-05-30 04:18:45 +08:00
|
|
|
vbi_get_next_buf(vbi_dma_q, &vbi_buf);
|
|
|
|
if (vbi_buf == NULL)
|
|
|
|
vbioutp = NULL;
|
|
|
|
else
|
2015-01-30 00:41:32 +08:00
|
|
|
vbioutp = vb2_plane_vaddr(
|
[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
|
|
|
&vbi_buf->vb.vb2_buf, 0);
|
2010-05-30 04:18:45 +08:00
|
|
|
|
|
|
|
/* Video */
|
2009-03-11 14:00:40 +08:00
|
|
|
if (buf != NULL)
|
|
|
|
buffer_filled(dev, dma_q, buf);
|
|
|
|
get_next_buf(dma_q, &buf);
|
2009-03-16 05:48:52 +08:00
|
|
|
if (buf == NULL)
|
2009-03-11 14:00:40 +08:00
|
|
|
outp = NULL;
|
2009-03-16 05:48:52 +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
|
|
|
outp = vb2_plane_vaddr(
|
|
|
|
&buf->vb.vb2_buf, 0);
|
2010-10-10 01:43:53 +08:00
|
|
|
|
|
|
|
/* As long as isoc traffic is arriving, keep
|
|
|
|
resetting the timer */
|
|
|
|
if (dev->vid_timeout_running)
|
|
|
|
mod_timer(&dev->vid_timeout,
|
|
|
|
jiffies + (HZ / 10));
|
|
|
|
if (dev->vbi_timeout_running)
|
|
|
|
mod_timer(&dev->vbi_timeout,
|
|
|
|
jiffies + (HZ / 10));
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (buf != NULL) {
|
2009-03-16 05:48:52 +08:00
|
|
|
if (fbyte & 0x40)
|
2009-03-11 14:00:40 +08:00
|
|
|
buf->top_field = 1;
|
2009-03-16 05:48:52 +08:00
|
|
|
else
|
2009-03-11 14:00:40 +08:00
|
|
|
buf->top_field = 0;
|
|
|
|
}
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
if (vbi_buf != NULL) {
|
|
|
|
if (fbyte & 0x40)
|
|
|
|
vbi_buf->top_field = 1;
|
|
|
|
else
|
|
|
|
vbi_buf->top_field = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->vbi_read = 0;
|
|
|
|
vbi_dma_q->pos = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
dma_q->pos = 0;
|
|
|
|
}
|
2010-05-30 04:18:45 +08:00
|
|
|
|
|
|
|
vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
|
|
|
|
if (dev->vbi_read < vbi_field_size) {
|
|
|
|
remain = vbi_field_size - dev->vbi_read;
|
|
|
|
if (len < remain)
|
|
|
|
lencopy = len;
|
|
|
|
else
|
|
|
|
lencopy = remain;
|
|
|
|
|
|
|
|
if (vbi_buf != NULL)
|
|
|
|
au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
|
|
|
|
vbioutp, len);
|
|
|
|
|
|
|
|
len -= lencopy;
|
|
|
|
p += lencopy;
|
|
|
|
dev->vbi_read += lencopy;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->vbi_read >= vbi_field_size && buf != NULL)
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_copy_video(dev, dma_q, buf, p, outp, len);
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2016-02-10 01:53:39 +08:00
|
|
|
void au0828_usb_v4l2_media_release(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
|
|
|
if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
|
|
|
|
return;
|
|
|
|
media_device_unregister_entity(&dev->input_ent[i]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void au0828_usb_v4l2_release(struct v4l2_device *v4l2_dev)
|
|
|
|
{
|
|
|
|
struct au0828_dev *dev =
|
|
|
|
container_of(v4l2_dev, struct au0828_dev, v4l2_dev);
|
|
|
|
|
|
|
|
v4l2_ctrl_handler_free(&dev->v4l2_ctrl_hdl);
|
|
|
|
v4l2_device_unregister(&dev->v4l2_dev);
|
|
|
|
au0828_usb_v4l2_media_release(dev);
|
|
|
|
au0828_usb_release(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
int au0828_v4l2_device_register(struct usb_interface *interface,
|
|
|
|
struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* Create the v4l2_device */
|
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
|
|
|
dev->v4l2_dev.mdev = dev->media_dev;
|
|
|
|
#endif
|
|
|
|
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
|
|
|
|
if (retval) {
|
|
|
|
pr_err("%s() v4l2_device_register failed\n",
|
|
|
|
__func__);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->v4l2_dev.release = au0828_usb_v4l2_release;
|
|
|
|
|
|
|
|
/* This control handler will inherit the controls from au8522 */
|
|
|
|
retval = v4l2_ctrl_handler_init(&dev->v4l2_ctrl_hdl, 4);
|
|
|
|
if (retval) {
|
|
|
|
pr_err("%s() v4l2_ctrl_handler_init failed\n",
|
|
|
|
__func__);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
dev->v4l2_dev.ctrl_handler = &dev->v4l2_ctrl_hdl;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-10-28 10:50:37 +08:00
|
|
|
static int queue_setup(struct vb2_queue *vq,
|
2015-01-30 00:41:32 +08:00
|
|
|
unsigned int *nbuffers, unsigned int *nplanes,
|
2016-04-15 20:15:05 +08:00
|
|
|
unsigned int sizes[], struct device *alloc_devs[])
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = vb2_get_drv_priv(vq);
|
2015-10-28 10:50:37 +08:00
|
|
|
unsigned long size = dev->height * dev->bytesperline;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-10-28 10:50:37 +08:00
|
|
|
if (*nplanes)
|
|
|
|
return sizes[0] < size ? -EINVAL : 0;
|
2015-01-30 00:41:32 +08:00
|
|
|
*nplanes = 1;
|
|
|
|
sizes[0] = size;
|
|
|
|
return 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2015-01-30 00:41:32 +08:00
|
|
|
buffer_prepare(struct vb2_buffer *vb)
|
2009-03-11 14:00:40 +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);
|
|
|
|
struct au0828_buffer *buf = container_of(vbuf,
|
|
|
|
struct au0828_buffer, vb);
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
buf->length = dev->height * dev->bytesperline;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (vb2_plane_size(vb, 0) < buf->length) {
|
|
|
|
pr_err("%s data will not fit into plane (%lu < %lu)\n",
|
|
|
|
__func__, vb2_plane_size(vb, 0), buf->length);
|
2009-03-11 14:00:40 +08:00
|
|
|
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(&buf->vb.vb2_buf, 0, buf->length);
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-01-30 00:41:32 +08:00
|
|
|
buffer_queue(struct vb2_buffer *vb)
|
2009-03-11 14:00:40 +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);
|
|
|
|
struct au0828_buffer *buf = container_of(vbuf,
|
2009-03-11 14:00:40 +08:00
|
|
|
struct au0828_buffer,
|
|
|
|
vb);
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
|
2009-03-11 14:00:40 +08:00
|
|
|
struct au0828_dmaqueue *vidq = &dev->vidq;
|
2015-01-30 00:41:32 +08:00
|
|
|
unsigned long flags = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
buf->mem = vb2_plane_vaddr(vb, 0);
|
|
|
|
buf->length = vb2_plane_size(vb, 0);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
|
|
list_add_tail(&buf->list, &vidq->active);
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int au0828_i2s_init(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
/* Enable i2s mode */
|
|
|
|
au0828_writereg(dev, AU0828_AUDIOCTRL_50C, 0x01);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Auvitek au0828 analog stream enable
|
|
|
|
*/
|
2012-10-28 01:00:30 +08:00
|
|
|
static int au0828_analog_stream_enable(struct au0828_dev *d)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2014-06-09 00:54:57 +08:00
|
|
|
struct usb_interface *iface;
|
2014-06-09 00:54:58 +08:00
|
|
|
int ret, h, w;
|
2014-06-09 00:54:57 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
dprintk(1, "au0828_analog_stream_enable called\n");
|
2014-06-09 00:54:57 +08:00
|
|
|
|
|
|
|
iface = usb_ifnum_to_if(d->usbdev, 0);
|
|
|
|
if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) {
|
|
|
|
dprintk(1, "Changing intf#0 to alt 5\n");
|
|
|
|
/* set au0828 interface0 to AS5 here again */
|
|
|
|
ret = usb_set_interface(d->usbdev, 0, 5);
|
|
|
|
if (ret < 0) {
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("Au0828 can't set alt setting to 5!\n");
|
2014-06-09 00:54:57 +08:00
|
|
|
return -EBUSY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-09 00:54:58 +08:00
|
|
|
h = d->height / 2 + 2;
|
|
|
|
w = d->width * 2;
|
2014-06-09 00:54:57 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
|
|
|
|
au0828_writereg(d, 0x106, 0x00);
|
|
|
|
/* set x position */
|
|
|
|
au0828_writereg(d, 0x110, 0x00);
|
|
|
|
au0828_writereg(d, 0x111, 0x00);
|
2014-06-09 00:54:58 +08:00
|
|
|
au0828_writereg(d, 0x114, w & 0xff);
|
|
|
|
au0828_writereg(d, 0x115, w >> 8);
|
2009-03-11 14:00:40 +08:00
|
|
|
/* set y position */
|
2010-05-30 04:18:45 +08:00
|
|
|
au0828_writereg(d, 0x112, 0x00);
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_writereg(d, 0x113, 0x00);
|
2014-06-09 00:54:58 +08:00
|
|
|
au0828_writereg(d, 0x116, h & 0xff);
|
|
|
|
au0828_writereg(d, 0x117, h >> 8);
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
static int au0828_analog_stream_disable(struct au0828_dev *d)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
|
|
|
dprintk(1, "au0828_analog_stream_disable called\n");
|
|
|
|
au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-10-28 01:00:30 +08:00
|
|
|
static void au0828_analog_stream_reset(struct au0828_dev *dev)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
|
|
|
dprintk(1, "au0828_analog_stream_reset called\n");
|
|
|
|
au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0);
|
|
|
|
mdelay(30);
|
|
|
|
au0828_writereg(dev, AU0828_SENSORCTRL_100, 0xb3);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some operations needs to stop current streaming
|
|
|
|
*/
|
|
|
|
static int au0828_stream_interrupt(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
dev->stream_state = STREAM_INTERRUPT;
|
2016-03-22 20:21:57 +08:00
|
|
|
if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
|
2009-03-11 14:00:40 +08:00
|
|
|
return -ENODEV;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
int au0828_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = vb2_get_drv_priv(vq);
|
|
|
|
int rc = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "au0828_start_analog_streaming called %d\n",
|
|
|
|
dev->streaming_users);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
|
|
|
dev->frame_count = 0;
|
|
|
|
else
|
|
|
|
dev->vbi_frame_count = 0;
|
|
|
|
|
|
|
|
if (dev->streaming_users == 0) {
|
|
|
|
/* If we were doing ac97 instead of i2s, it would go here...*/
|
|
|
|
au0828_i2s_init(dev);
|
|
|
|
rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
|
|
|
|
AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
|
|
|
|
au0828_isoc_copy);
|
|
|
|
if (rc < 0) {
|
|
|
|
pr_info("au0828_init_isoc failed\n");
|
|
|
|
return rc;
|
|
|
|
}
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
|
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, video,
|
|
|
|
s_stream, 1);
|
|
|
|
dev->vid_timeout_running = 1;
|
|
|
|
mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
|
|
|
|
} else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
|
|
|
|
dev->vbi_timeout_running = 1;
|
|
|
|
mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
dev->streaming_users++;
|
|
|
|
return rc;
|
|
|
|
}
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
static void au0828_stop_streaming(struct vb2_queue *vq)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = vb2_get_drv_priv(vq);
|
|
|
|
struct au0828_dmaqueue *vidq = &dev->vidq;
|
|
|
|
unsigned long flags = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (dev->streaming_users-- == 1)
|
|
|
|
au0828_uninit_isoc(dev);
|
|
|
|
|
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
|
|
|
|
dev->vid_timeout_running = 0;
|
|
|
|
del_timer_sync(&dev->vid_timeout);
|
|
|
|
|
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
|
|
if (dev->isoc_ctl.buf != NULL) {
|
[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->isoc_ctl.buf->vb.vb2_buf,
|
|
|
|
VB2_BUF_STATE_ERROR);
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->isoc_ctl.buf = NULL;
|
2010-05-30 04:18:45 +08:00
|
|
|
}
|
2015-01-30 00:41:32 +08:00
|
|
|
while (!list_empty(&vidq->active)) {
|
|
|
|
struct au0828_buffer *buf;
|
2012-08-07 09:46:58 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
buf = list_entry(vidq->active.next, struct au0828_buffer, 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);
|
2015-01-30 00:41:32 +08:00
|
|
|
list_del(&buf->list);
|
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
2010-05-30 04:18:45 +08:00
|
|
|
}
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
void au0828_stop_vbi_streaming(struct vb2_queue *vq)
|
2010-05-30 04:18:45 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = vb2_get_drv_priv(vq);
|
|
|
|
struct au0828_dmaqueue *vbiq = &dev->vbiq;
|
|
|
|
unsigned long flags = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "au0828_stop_vbi_streaming called %d\n",
|
|
|
|
dev->streaming_users);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (dev->streaming_users-- == 1)
|
|
|
|
au0828_uninit_isoc(dev);
|
2010-05-30 04:18:45 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
|
|
|
if (dev->isoc_ctl.vbi_buf != NULL) {
|
[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->isoc_ctl.vbi_buf->vb.vb2_buf,
|
2015-01-30 00:41:32 +08:00
|
|
|
VB2_BUF_STATE_ERROR);
|
|
|
|
dev->isoc_ctl.vbi_buf = NULL;
|
|
|
|
}
|
|
|
|
while (!list_empty(&vbiq->active)) {
|
|
|
|
struct au0828_buffer *buf;
|
|
|
|
|
|
|
|
buf = list_entry(vbiq->active.next, struct au0828_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);
|
2015-01-30 00:41:32 +08:00
|
|
|
}
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->vbi_timeout_running = 0;
|
|
|
|
del_timer_sync(&dev->vbi_timeout);
|
2010-05-30 04:18:45 +08:00
|
|
|
}
|
|
|
|
|
2016-09-09 07:59:01 +08:00
|
|
|
static const struct vb2_ops au0828_video_qops = {
|
2015-01-30 00:41:32 +08:00
|
|
|
.queue_setup = queue_setup,
|
|
|
|
.buf_prepare = buffer_prepare,
|
|
|
|
.buf_queue = buffer_queue,
|
|
|
|
.start_streaming = au0828_start_analog_streaming,
|
|
|
|
.stop_streaming = au0828_stop_streaming,
|
|
|
|
.wait_prepare = vb2_ops_wait_prepare,
|
|
|
|
.wait_finish = vb2_ops_wait_finish,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------
|
|
|
|
V4L2 interface
|
|
|
|
------------------------------------------------------------------*/
|
|
|
|
/*
|
|
|
|
* au0828_analog_unregister
|
|
|
|
* unregister v4l2 devices
|
|
|
|
*/
|
2016-02-10 01:53:39 +08:00
|
|
|
int au0828_analog_unregister(struct au0828_dev *dev)
|
2010-05-30 04:18:45 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "au0828_analog_unregister called\n");
|
2016-02-10 01:53:39 +08:00
|
|
|
|
|
|
|
/* No analog TV */
|
|
|
|
if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
|
|
|
|
return 0;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
mutex_lock(&au0828_sysfs_lock);
|
2015-02-27 06:33:13 +08:00
|
|
|
video_unregister_device(&dev->vdev);
|
|
|
|
video_unregister_device(&dev->vbi_dev);
|
2015-01-30 00:41:32 +08:00
|
|
|
mutex_unlock(&au0828_sysfs_lock);
|
2016-02-10 01:53:39 +08:00
|
|
|
|
|
|
|
v4l2_device_disconnect(&dev->v4l2_dev);
|
|
|
|
v4l2_device_put(&dev->v4l2_dev);
|
|
|
|
|
|
|
|
return 1;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
2010-09-02 09:03:43 +08:00
|
|
|
/* This function ensures that video frames continue to be delivered even if
|
|
|
|
the ITU-656 input isn't receiving any data (thereby preventing applications
|
|
|
|
such as tvtime from hanging) */
|
treewide: setup_timer() -> timer_setup()
This converts all remaining cases of the old setup_timer() API into using
timer_setup(), where the callback argument is the structure already
holding the struct timer_list. These should have no behavioral changes,
since they just change which pointer is passed into the callback with
the same available pointers after conversion. It handles the following
examples, in addition to some other variations.
Casting from unsigned long:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
setup_timer(&ptr->my_timer, my_callback, ptr);
and forced object casts:
void my_callback(struct something *ptr)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
become:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
Direct function assignments:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
ptr->my_timer.function = my_callback;
have a temporary cast added, along with converting the args:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
And finally, callbacks without a data assignment:
void my_callback(unsigned long data)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, 0);
have their argument renamed to verify they're unused during conversion:
void my_callback(struct timer_list *unused)
{
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
The conversion is done with the following Coccinelle script:
spatch --very-quiet --all-includes --include-headers \
-I ./arch/x86/include -I ./arch/x86/include/generated \
-I ./include -I ./arch/x86/include/uapi \
-I ./arch/x86/include/generated/uapi -I ./include/uapi \
-I ./include/generated/uapi --include ./include/linux/kconfig.h \
--dir . \
--cocci-file ~/src/data/timer_setup.cocci
@fix_address_of@
expression e;
@@
setup_timer(
-&(e)
+&e
, ...)
// Update any raw setup_timer() usages that have a NULL callback, but
// would otherwise match change_timer_function_usage, since the latter
// will update all function assignments done in the face of a NULL
// function initialization in setup_timer().
@change_timer_function_usage_NULL@
expression _E;
identifier _timer;
type _cast_data;
@@
(
-setup_timer(&_E->_timer, NULL, _E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E->_timer, NULL, (_cast_data)_E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, &_E);
+timer_setup(&_E._timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, (_cast_data)&_E);
+timer_setup(&_E._timer, NULL, 0);
)
@change_timer_function_usage@
expression _E;
identifier _timer;
struct timer_list _stl;
identifier _callback;
type _cast_func, _cast_data;
@@
(
-setup_timer(&_E->_timer, _callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
_E->_timer@_stl.function = _callback;
|
_E->_timer@_stl.function = &_callback;
|
_E->_timer@_stl.function = (_cast_func)_callback;
|
_E->_timer@_stl.function = (_cast_func)&_callback;
|
_E._timer@_stl.function = _callback;
|
_E._timer@_stl.function = &_callback;
|
_E._timer@_stl.function = (_cast_func)_callback;
|
_E._timer@_stl.function = (_cast_func)&_callback;
)
// callback(unsigned long arg)
@change_callback_handle_cast
depends on change_timer_function_usage@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
identifier _handle;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
(
... when != _origarg
_handletype *_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
)
}
// callback(unsigned long arg) without existing variable
@change_callback_handle_cast_no_arg
depends on change_timer_function_usage &&
!change_callback_handle_cast@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
+ _handletype *_origarg = from_timer(_origarg, t, _timer);
+
... when != _origarg
- (_handletype *)_origarg
+ _origarg
... when != _origarg
}
// Avoid already converted callbacks.
@match_callback_converted
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier t;
@@
void _callback(struct timer_list *t)
{ ... }
// callback(struct something *handle)
@change_callback_handle_arg
depends on change_timer_function_usage &&
!match_callback_converted &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
@@
void _callback(
-_handletype *_handle
+struct timer_list *t
)
{
+ _handletype *_handle = from_timer(_handle, t, _timer);
...
}
// If change_callback_handle_arg ran on an empty function, remove
// the added handler.
@unchange_callback_handle_arg
depends on change_timer_function_usage &&
change_callback_handle_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
identifier t;
@@
void _callback(struct timer_list *t)
{
- _handletype *_handle = from_timer(_handle, t, _timer);
}
// We only want to refactor the setup_timer() data argument if we've found
// the matching callback. This undoes changes in change_timer_function_usage.
@unchange_timer_function_usage
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg &&
!change_callback_handle_arg@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type change_timer_function_usage._cast_data;
@@
(
-timer_setup(&_E->_timer, _callback, 0);
+setup_timer(&_E->_timer, _callback, (_cast_data)_E);
|
-timer_setup(&_E._timer, _callback, 0);
+setup_timer(&_E._timer, _callback, (_cast_data)&_E);
)
// If we fixed a callback from a .function assignment, fix the
// assignment cast now.
@change_timer_function_assignment
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_func;
typedef TIMER_FUNC_TYPE;
@@
(
_E->_timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-&_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
)
// Sometimes timer functions are called directly. Replace matched args.
@change_timer_function_calls
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression _E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_data;
@@
_callback(
(
-(_cast_data)_E
+&_E->_timer
|
-(_cast_data)&_E
+&_E._timer
|
-_E
+&_E->_timer
)
)
// If a timer has been configured without a data argument, it can be
// converted without regard to the callback argument, since it is unused.
@match_timer_function_unused_data@
expression _E;
identifier _timer;
identifier _callback;
@@
(
-setup_timer(&_E->_timer, _callback, 0);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0L);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0UL);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0L);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0UL);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0L);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0UL);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0L);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0UL);
+timer_setup(_timer, _callback, 0);
)
@change_callback_unused_data
depends on match_timer_function_unused_data@
identifier match_timer_function_unused_data._callback;
type _origtype;
identifier _origarg;
@@
void _callback(
-_origtype _origarg
+struct timer_list *unused
)
{
... when != _origarg
}
Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 05:43:17 +08:00
|
|
|
static void au0828_vid_buffer_timeout(struct timer_list *t)
|
2010-09-02 09:03:43 +08:00
|
|
|
{
|
treewide: setup_timer() -> timer_setup()
This converts all remaining cases of the old setup_timer() API into using
timer_setup(), where the callback argument is the structure already
holding the struct timer_list. These should have no behavioral changes,
since they just change which pointer is passed into the callback with
the same available pointers after conversion. It handles the following
examples, in addition to some other variations.
Casting from unsigned long:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
setup_timer(&ptr->my_timer, my_callback, ptr);
and forced object casts:
void my_callback(struct something *ptr)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
become:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
Direct function assignments:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
ptr->my_timer.function = my_callback;
have a temporary cast added, along with converting the args:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
And finally, callbacks without a data assignment:
void my_callback(unsigned long data)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, 0);
have their argument renamed to verify they're unused during conversion:
void my_callback(struct timer_list *unused)
{
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
The conversion is done with the following Coccinelle script:
spatch --very-quiet --all-includes --include-headers \
-I ./arch/x86/include -I ./arch/x86/include/generated \
-I ./include -I ./arch/x86/include/uapi \
-I ./arch/x86/include/generated/uapi -I ./include/uapi \
-I ./include/generated/uapi --include ./include/linux/kconfig.h \
--dir . \
--cocci-file ~/src/data/timer_setup.cocci
@fix_address_of@
expression e;
@@
setup_timer(
-&(e)
+&e
, ...)
// Update any raw setup_timer() usages that have a NULL callback, but
// would otherwise match change_timer_function_usage, since the latter
// will update all function assignments done in the face of a NULL
// function initialization in setup_timer().
@change_timer_function_usage_NULL@
expression _E;
identifier _timer;
type _cast_data;
@@
(
-setup_timer(&_E->_timer, NULL, _E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E->_timer, NULL, (_cast_data)_E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, &_E);
+timer_setup(&_E._timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, (_cast_data)&_E);
+timer_setup(&_E._timer, NULL, 0);
)
@change_timer_function_usage@
expression _E;
identifier _timer;
struct timer_list _stl;
identifier _callback;
type _cast_func, _cast_data;
@@
(
-setup_timer(&_E->_timer, _callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
_E->_timer@_stl.function = _callback;
|
_E->_timer@_stl.function = &_callback;
|
_E->_timer@_stl.function = (_cast_func)_callback;
|
_E->_timer@_stl.function = (_cast_func)&_callback;
|
_E._timer@_stl.function = _callback;
|
_E._timer@_stl.function = &_callback;
|
_E._timer@_stl.function = (_cast_func)_callback;
|
_E._timer@_stl.function = (_cast_func)&_callback;
)
// callback(unsigned long arg)
@change_callback_handle_cast
depends on change_timer_function_usage@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
identifier _handle;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
(
... when != _origarg
_handletype *_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
)
}
// callback(unsigned long arg) without existing variable
@change_callback_handle_cast_no_arg
depends on change_timer_function_usage &&
!change_callback_handle_cast@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
+ _handletype *_origarg = from_timer(_origarg, t, _timer);
+
... when != _origarg
- (_handletype *)_origarg
+ _origarg
... when != _origarg
}
// Avoid already converted callbacks.
@match_callback_converted
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier t;
@@
void _callback(struct timer_list *t)
{ ... }
// callback(struct something *handle)
@change_callback_handle_arg
depends on change_timer_function_usage &&
!match_callback_converted &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
@@
void _callback(
-_handletype *_handle
+struct timer_list *t
)
{
+ _handletype *_handle = from_timer(_handle, t, _timer);
...
}
// If change_callback_handle_arg ran on an empty function, remove
// the added handler.
@unchange_callback_handle_arg
depends on change_timer_function_usage &&
change_callback_handle_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
identifier t;
@@
void _callback(struct timer_list *t)
{
- _handletype *_handle = from_timer(_handle, t, _timer);
}
// We only want to refactor the setup_timer() data argument if we've found
// the matching callback. This undoes changes in change_timer_function_usage.
@unchange_timer_function_usage
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg &&
!change_callback_handle_arg@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type change_timer_function_usage._cast_data;
@@
(
-timer_setup(&_E->_timer, _callback, 0);
+setup_timer(&_E->_timer, _callback, (_cast_data)_E);
|
-timer_setup(&_E._timer, _callback, 0);
+setup_timer(&_E._timer, _callback, (_cast_data)&_E);
)
// If we fixed a callback from a .function assignment, fix the
// assignment cast now.
@change_timer_function_assignment
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_func;
typedef TIMER_FUNC_TYPE;
@@
(
_E->_timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-&_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
)
// Sometimes timer functions are called directly. Replace matched args.
@change_timer_function_calls
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression _E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_data;
@@
_callback(
(
-(_cast_data)_E
+&_E->_timer
|
-(_cast_data)&_E
+&_E._timer
|
-_E
+&_E->_timer
)
)
// If a timer has been configured without a data argument, it can be
// converted without regard to the callback argument, since it is unused.
@match_timer_function_unused_data@
expression _E;
identifier _timer;
identifier _callback;
@@
(
-setup_timer(&_E->_timer, _callback, 0);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0L);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0UL);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0L);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0UL);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0L);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0UL);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0L);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0UL);
+timer_setup(_timer, _callback, 0);
)
@change_callback_unused_data
depends on match_timer_function_unused_data@
identifier match_timer_function_unused_data._callback;
type _origtype;
identifier _origarg;
@@
void _callback(
-_origtype _origarg
+struct timer_list *unused
)
{
... when != _origarg
}
Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 05:43:17 +08:00
|
|
|
struct au0828_dev *dev = from_timer(dev, t, vid_timeout);
|
2010-09-02 09:03:43 +08:00
|
|
|
struct au0828_dmaqueue *dma_q = &dev->vidq;
|
|
|
|
struct au0828_buffer *buf;
|
|
|
|
unsigned char *vid_data;
|
2010-10-10 01:43:53 +08:00
|
|
|
unsigned long flags = 0;
|
2010-09-02 09:03:43 +08:00
|
|
|
|
2010-10-10 01:43:53 +08:00
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
2010-09-02 09:03:43 +08:00
|
|
|
|
|
|
|
buf = dev->isoc_ctl.buf;
|
|
|
|
if (buf != NULL) {
|
[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
|
|
|
vid_data = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
|
2015-01-30 00:41:32 +08:00
|
|
|
memset(vid_data, 0x00, buf->length); /* Blank green frame */
|
2010-09-02 09:03:43 +08:00
|
|
|
buffer_filled(dev, dma_q, buf);
|
|
|
|
}
|
2010-10-10 01:43:53 +08:00
|
|
|
get_next_buf(dma_q, &buf);
|
|
|
|
|
|
|
|
if (dev->vid_timeout_running == 1)
|
|
|
|
mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
|
2010-09-02 09:03:43 +08:00
|
|
|
|
2010-10-10 01:43:53 +08:00
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
2010-09-02 09:03:43 +08:00
|
|
|
}
|
|
|
|
|
treewide: setup_timer() -> timer_setup()
This converts all remaining cases of the old setup_timer() API into using
timer_setup(), where the callback argument is the structure already
holding the struct timer_list. These should have no behavioral changes,
since they just change which pointer is passed into the callback with
the same available pointers after conversion. It handles the following
examples, in addition to some other variations.
Casting from unsigned long:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
setup_timer(&ptr->my_timer, my_callback, ptr);
and forced object casts:
void my_callback(struct something *ptr)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
become:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
Direct function assignments:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
ptr->my_timer.function = my_callback;
have a temporary cast added, along with converting the args:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
And finally, callbacks without a data assignment:
void my_callback(unsigned long data)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, 0);
have their argument renamed to verify they're unused during conversion:
void my_callback(struct timer_list *unused)
{
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
The conversion is done with the following Coccinelle script:
spatch --very-quiet --all-includes --include-headers \
-I ./arch/x86/include -I ./arch/x86/include/generated \
-I ./include -I ./arch/x86/include/uapi \
-I ./arch/x86/include/generated/uapi -I ./include/uapi \
-I ./include/generated/uapi --include ./include/linux/kconfig.h \
--dir . \
--cocci-file ~/src/data/timer_setup.cocci
@fix_address_of@
expression e;
@@
setup_timer(
-&(e)
+&e
, ...)
// Update any raw setup_timer() usages that have a NULL callback, but
// would otherwise match change_timer_function_usage, since the latter
// will update all function assignments done in the face of a NULL
// function initialization in setup_timer().
@change_timer_function_usage_NULL@
expression _E;
identifier _timer;
type _cast_data;
@@
(
-setup_timer(&_E->_timer, NULL, _E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E->_timer, NULL, (_cast_data)_E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, &_E);
+timer_setup(&_E._timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, (_cast_data)&_E);
+timer_setup(&_E._timer, NULL, 0);
)
@change_timer_function_usage@
expression _E;
identifier _timer;
struct timer_list _stl;
identifier _callback;
type _cast_func, _cast_data;
@@
(
-setup_timer(&_E->_timer, _callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
_E->_timer@_stl.function = _callback;
|
_E->_timer@_stl.function = &_callback;
|
_E->_timer@_stl.function = (_cast_func)_callback;
|
_E->_timer@_stl.function = (_cast_func)&_callback;
|
_E._timer@_stl.function = _callback;
|
_E._timer@_stl.function = &_callback;
|
_E._timer@_stl.function = (_cast_func)_callback;
|
_E._timer@_stl.function = (_cast_func)&_callback;
)
// callback(unsigned long arg)
@change_callback_handle_cast
depends on change_timer_function_usage@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
identifier _handle;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
(
... when != _origarg
_handletype *_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
)
}
// callback(unsigned long arg) without existing variable
@change_callback_handle_cast_no_arg
depends on change_timer_function_usage &&
!change_callback_handle_cast@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
+ _handletype *_origarg = from_timer(_origarg, t, _timer);
+
... when != _origarg
- (_handletype *)_origarg
+ _origarg
... when != _origarg
}
// Avoid already converted callbacks.
@match_callback_converted
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier t;
@@
void _callback(struct timer_list *t)
{ ... }
// callback(struct something *handle)
@change_callback_handle_arg
depends on change_timer_function_usage &&
!match_callback_converted &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
@@
void _callback(
-_handletype *_handle
+struct timer_list *t
)
{
+ _handletype *_handle = from_timer(_handle, t, _timer);
...
}
// If change_callback_handle_arg ran on an empty function, remove
// the added handler.
@unchange_callback_handle_arg
depends on change_timer_function_usage &&
change_callback_handle_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
identifier t;
@@
void _callback(struct timer_list *t)
{
- _handletype *_handle = from_timer(_handle, t, _timer);
}
// We only want to refactor the setup_timer() data argument if we've found
// the matching callback. This undoes changes in change_timer_function_usage.
@unchange_timer_function_usage
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg &&
!change_callback_handle_arg@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type change_timer_function_usage._cast_data;
@@
(
-timer_setup(&_E->_timer, _callback, 0);
+setup_timer(&_E->_timer, _callback, (_cast_data)_E);
|
-timer_setup(&_E._timer, _callback, 0);
+setup_timer(&_E._timer, _callback, (_cast_data)&_E);
)
// If we fixed a callback from a .function assignment, fix the
// assignment cast now.
@change_timer_function_assignment
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_func;
typedef TIMER_FUNC_TYPE;
@@
(
_E->_timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-&_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
)
// Sometimes timer functions are called directly. Replace matched args.
@change_timer_function_calls
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression _E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_data;
@@
_callback(
(
-(_cast_data)_E
+&_E->_timer
|
-(_cast_data)&_E
+&_E._timer
|
-_E
+&_E->_timer
)
)
// If a timer has been configured without a data argument, it can be
// converted without regard to the callback argument, since it is unused.
@match_timer_function_unused_data@
expression _E;
identifier _timer;
identifier _callback;
@@
(
-setup_timer(&_E->_timer, _callback, 0);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0L);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0UL);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0L);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0UL);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0L);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0UL);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0L);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0UL);
+timer_setup(_timer, _callback, 0);
)
@change_callback_unused_data
depends on match_timer_function_unused_data@
identifier match_timer_function_unused_data._callback;
type _origtype;
identifier _origarg;
@@
void _callback(
-_origtype _origarg
+struct timer_list *unused
)
{
... when != _origarg
}
Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 05:43:17 +08:00
|
|
|
static void au0828_vbi_buffer_timeout(struct timer_list *t)
|
2010-09-02 09:03:43 +08:00
|
|
|
{
|
treewide: setup_timer() -> timer_setup()
This converts all remaining cases of the old setup_timer() API into using
timer_setup(), where the callback argument is the structure already
holding the struct timer_list. These should have no behavioral changes,
since they just change which pointer is passed into the callback with
the same available pointers after conversion. It handles the following
examples, in addition to some other variations.
Casting from unsigned long:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
setup_timer(&ptr->my_timer, my_callback, ptr);
and forced object casts:
void my_callback(struct something *ptr)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
become:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
Direct function assignments:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
ptr->my_timer.function = my_callback;
have a temporary cast added, along with converting the args:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
And finally, callbacks without a data assignment:
void my_callback(unsigned long data)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, 0);
have their argument renamed to verify they're unused during conversion:
void my_callback(struct timer_list *unused)
{
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
The conversion is done with the following Coccinelle script:
spatch --very-quiet --all-includes --include-headers \
-I ./arch/x86/include -I ./arch/x86/include/generated \
-I ./include -I ./arch/x86/include/uapi \
-I ./arch/x86/include/generated/uapi -I ./include/uapi \
-I ./include/generated/uapi --include ./include/linux/kconfig.h \
--dir . \
--cocci-file ~/src/data/timer_setup.cocci
@fix_address_of@
expression e;
@@
setup_timer(
-&(e)
+&e
, ...)
// Update any raw setup_timer() usages that have a NULL callback, but
// would otherwise match change_timer_function_usage, since the latter
// will update all function assignments done in the face of a NULL
// function initialization in setup_timer().
@change_timer_function_usage_NULL@
expression _E;
identifier _timer;
type _cast_data;
@@
(
-setup_timer(&_E->_timer, NULL, _E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E->_timer, NULL, (_cast_data)_E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, &_E);
+timer_setup(&_E._timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, (_cast_data)&_E);
+timer_setup(&_E._timer, NULL, 0);
)
@change_timer_function_usage@
expression _E;
identifier _timer;
struct timer_list _stl;
identifier _callback;
type _cast_func, _cast_data;
@@
(
-setup_timer(&_E->_timer, _callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
_E->_timer@_stl.function = _callback;
|
_E->_timer@_stl.function = &_callback;
|
_E->_timer@_stl.function = (_cast_func)_callback;
|
_E->_timer@_stl.function = (_cast_func)&_callback;
|
_E._timer@_stl.function = _callback;
|
_E._timer@_stl.function = &_callback;
|
_E._timer@_stl.function = (_cast_func)_callback;
|
_E._timer@_stl.function = (_cast_func)&_callback;
)
// callback(unsigned long arg)
@change_callback_handle_cast
depends on change_timer_function_usage@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
identifier _handle;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
(
... when != _origarg
_handletype *_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
)
}
// callback(unsigned long arg) without existing variable
@change_callback_handle_cast_no_arg
depends on change_timer_function_usage &&
!change_callback_handle_cast@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
+ _handletype *_origarg = from_timer(_origarg, t, _timer);
+
... when != _origarg
- (_handletype *)_origarg
+ _origarg
... when != _origarg
}
// Avoid already converted callbacks.
@match_callback_converted
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier t;
@@
void _callback(struct timer_list *t)
{ ... }
// callback(struct something *handle)
@change_callback_handle_arg
depends on change_timer_function_usage &&
!match_callback_converted &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
@@
void _callback(
-_handletype *_handle
+struct timer_list *t
)
{
+ _handletype *_handle = from_timer(_handle, t, _timer);
...
}
// If change_callback_handle_arg ran on an empty function, remove
// the added handler.
@unchange_callback_handle_arg
depends on change_timer_function_usage &&
change_callback_handle_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
identifier t;
@@
void _callback(struct timer_list *t)
{
- _handletype *_handle = from_timer(_handle, t, _timer);
}
// We only want to refactor the setup_timer() data argument if we've found
// the matching callback. This undoes changes in change_timer_function_usage.
@unchange_timer_function_usage
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg &&
!change_callback_handle_arg@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type change_timer_function_usage._cast_data;
@@
(
-timer_setup(&_E->_timer, _callback, 0);
+setup_timer(&_E->_timer, _callback, (_cast_data)_E);
|
-timer_setup(&_E._timer, _callback, 0);
+setup_timer(&_E._timer, _callback, (_cast_data)&_E);
)
// If we fixed a callback from a .function assignment, fix the
// assignment cast now.
@change_timer_function_assignment
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_func;
typedef TIMER_FUNC_TYPE;
@@
(
_E->_timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-&_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
)
// Sometimes timer functions are called directly. Replace matched args.
@change_timer_function_calls
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression _E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_data;
@@
_callback(
(
-(_cast_data)_E
+&_E->_timer
|
-(_cast_data)&_E
+&_E._timer
|
-_E
+&_E->_timer
)
)
// If a timer has been configured without a data argument, it can be
// converted without regard to the callback argument, since it is unused.
@match_timer_function_unused_data@
expression _E;
identifier _timer;
identifier _callback;
@@
(
-setup_timer(&_E->_timer, _callback, 0);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0L);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0UL);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0L);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0UL);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0L);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0UL);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0L);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0UL);
+timer_setup(_timer, _callback, 0);
)
@change_callback_unused_data
depends on match_timer_function_unused_data@
identifier match_timer_function_unused_data._callback;
type _origtype;
identifier _origarg;
@@
void _callback(
-_origtype _origarg
+struct timer_list *unused
)
{
... when != _origarg
}
Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 05:43:17 +08:00
|
|
|
struct au0828_dev *dev = from_timer(dev, t, vbi_timeout);
|
2010-09-02 09:03:43 +08:00
|
|
|
struct au0828_dmaqueue *dma_q = &dev->vbiq;
|
|
|
|
struct au0828_buffer *buf;
|
|
|
|
unsigned char *vbi_data;
|
2010-10-10 01:43:53 +08:00
|
|
|
unsigned long flags = 0;
|
2010-09-02 09:03:43 +08:00
|
|
|
|
2010-10-10 01:43:53 +08:00
|
|
|
spin_lock_irqsave(&dev->slock, flags);
|
2010-09-02 09:03:43 +08:00
|
|
|
|
|
|
|
buf = dev->isoc_ctl.vbi_buf;
|
|
|
|
if (buf != NULL) {
|
[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
|
|
|
vbi_data = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
|
2015-01-30 00:41:32 +08:00
|
|
|
memset(vbi_data, 0x00, buf->length);
|
2015-02-24 21:00:29 +08:00
|
|
|
buffer_filled(dev, dma_q, buf);
|
2010-09-02 09:03:43 +08:00
|
|
|
}
|
2010-10-10 01:43:53 +08:00
|
|
|
vbi_get_next_buf(dma_q, &buf);
|
2010-09-02 09:03:43 +08:00
|
|
|
|
2010-10-10 01:43:53 +08:00
|
|
|
if (dev->vbi_timeout_running == 1)
|
|
|
|
mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
|
|
|
|
spin_unlock_irqrestore(&dev->slock, flags);
|
2010-09-02 09:03:43 +08:00
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
static int au0828_v4l2_open(struct file *filp)
|
|
|
|
{
|
2009-12-10 21:44:04 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(filp);
|
2015-01-30 00:41:32 +08:00
|
|
|
int ret;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1,
|
2016-03-22 20:21:57 +08:00
|
|
|
"%s called std_set %d dev_state %ld stream users %d users %d\n",
|
2015-01-30 00:41:32 +08:00
|
|
|
__func__, dev->std_set_in_tuner_core, dev->dev_state,
|
|
|
|
dev->streaming_users, dev->users);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (mutex_lock_interruptible(&dev->lock))
|
2013-03-12 03:22:13 +08:00
|
|
|
return -ERESTARTSYS;
|
2015-01-30 00:41:32 +08:00
|
|
|
|
|
|
|
ret = v4l2_fh_open(filp);
|
|
|
|
if (ret) {
|
|
|
|
au0828_isocdbg("%s: v4l2_fh_open() returned error %d\n",
|
|
|
|
__func__, ret);
|
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return ret;
|
2013-03-12 03:22:13 +08:00
|
|
|
}
|
2015-01-30 00:41:32 +08:00
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
if (dev->users == 0) {
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_analog_stream_enable(dev);
|
|
|
|
au0828_analog_stream_reset(dev);
|
|
|
|
dev->stream_state = STREAM_OFF;
|
2016-03-22 20:21:57 +08:00
|
|
|
set_bit(DEV_INITIALIZED, &dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
dev->users++;
|
2013-03-12 03:22:13 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2009-03-11 14:00:40 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int au0828_v4l2_close(struct file *filp)
|
|
|
|
{
|
|
|
|
int ret;
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(filp);
|
|
|
|
struct video_device *vdev = video_devdata(filp);
|
|
|
|
|
|
|
|
dprintk(1,
|
2016-03-22 20:21:57 +08:00
|
|
|
"%s called std_set %d dev_state %ld stream users %d users %d\n",
|
2015-01-30 00:41:32 +08:00
|
|
|
__func__, dev->std_set_in_tuner_core, dev->dev_state,
|
|
|
|
dev->streaming_users, dev->users);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
mutex_lock(&dev->lock);
|
2015-01-30 00:41:32 +08:00
|
|
|
if (vdev->vfl_type == VFL_TYPE_GRABBER && dev->vid_timeout_running) {
|
2010-10-10 01:43:53 +08:00
|
|
|
/* Cancel timeout thread in case they didn't call streamoff */
|
|
|
|
dev->vid_timeout_running = 0;
|
|
|
|
del_timer_sync(&dev->vid_timeout);
|
2015-01-30 00:41:32 +08:00
|
|
|
} else if (vdev->vfl_type == VFL_TYPE_VBI &&
|
|
|
|
dev->vbi_timeout_running) {
|
2010-10-10 01:43:53 +08:00
|
|
|
/* Cancel timeout thread in case they didn't call streamoff */
|
|
|
|
dev->vbi_timeout_running = 0;
|
|
|
|
del_timer_sync(&dev->vbi_timeout);
|
2010-05-30 04:18:45 +08:00
|
|
|
}
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
if (test_bit(DEV_DISCONNECTED, &dev->dev_state))
|
2015-01-30 00:41:32 +08:00
|
|
|
goto end;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (dev->users == 1) {
|
2016-02-12 07:41:37 +08:00
|
|
|
/*
|
|
|
|
* Avoid putting tuner in sleep if DVB or ALSA are
|
|
|
|
* streaming.
|
|
|
|
*
|
|
|
|
* On most USB devices like au0828 the tuner can
|
|
|
|
* be safely put in sleep stare here if ALSA isn't
|
|
|
|
* streaming. Exceptions are some very old USB tuner
|
|
|
|
* models such as em28xx-based WinTV USB2 which have
|
|
|
|
* a separate audio output jack. The devices that have
|
|
|
|
* a separate audio output jack have analog tuners,
|
|
|
|
* like Philips FM1236. Those devices are always on,
|
|
|
|
* so the s_power callback are silently ignored.
|
|
|
|
* So, the current logic here does the following:
|
|
|
|
* Disable (put tuner to sleep) when
|
|
|
|
* - ALSA and DVB aren't not streaming;
|
|
|
|
* - the last V4L2 file handler is closed.
|
|
|
|
*
|
|
|
|
* FIXME:
|
|
|
|
*
|
|
|
|
* Additionally, this logic could be improved to
|
|
|
|
* disable the media source if the above conditions
|
|
|
|
* are met and if the device:
|
|
|
|
* - doesn't have a separate audio out plug (or
|
|
|
|
* - doesn't use a silicon tuner like xc2028/3028/4000/5000).
|
|
|
|
*
|
|
|
|
* Once this additional logic is in place, a callback
|
|
|
|
* is needed to enable the media source and power on
|
|
|
|
* the tuner, for radio to work.
|
|
|
|
*/
|
|
|
|
ret = v4l_enable_media_source(vdev);
|
|
|
|
if (ret == 0)
|
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(&dev->v4l2_dev, 0, tuner,
|
|
|
|
standby);
|
2013-03-12 03:22:13 +08:00
|
|
|
dev->std_set_in_tuner_core = 0;
|
2009-05-07 07:54:00 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
/* When close the device, set the usb intf0 into alt0 to free
|
|
|
|
USB bandwidth */
|
|
|
|
ret = usb_set_interface(dev->usbdev, 0, 0);
|
2009-03-16 05:48:52 +08:00
|
|
|
if (ret < 0)
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("Au0828 can't set alternate to 0!\n");
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
2015-01-30 00:41:32 +08:00
|
|
|
end:
|
|
|
|
_vb2_fop_release(filp, NULL);
|
2009-03-11 14:00:40 +08:00
|
|
|
dev->users--;
|
2015-01-30 00:41:32 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
/* Must be called with dev->lock held */
|
|
|
|
static void au0828_init_tuner(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
struct v4l2_frequency f = {
|
|
|
|
.frequency = dev->ctrl_freq,
|
|
|
|
.type = V4L2_TUNER_ANALOG_TV,
|
|
|
|
};
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
if (dev->std_set_in_tuner_core)
|
|
|
|
return;
|
|
|
|
dev->std_set_in_tuner_core = 1;
|
|
|
|
i2c_gate_ctrl(dev, 1);
|
|
|
|
/* If we've never sent the standard in tuner core, do so now.
|
|
|
|
We don't do this at device probe because we don't want to
|
|
|
|
incur the cost of a firmware load */
|
2014-04-29 03:53:01 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->std);
|
2013-03-12 03:22:13 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
|
|
|
|
i2c_gate_ctrl(dev, 0);
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
|
|
|
|
struct v4l2_format *format)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int width = format->fmt.pix.width;
|
|
|
|
int height = format->fmt.pix.height;
|
|
|
|
|
|
|
|
/* If they are demanding a format other than the one we support,
|
|
|
|
bail out (tvtime asks for UYVY and then retries with YUYV) */
|
2009-03-16 05:48:52 +08:00
|
|
|
if (format->fmt.pix.pixelformat != V4L2_PIX_FMT_UYVY)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
/* format->fmt.pix.width only support 720 and height 480 */
|
2009-03-16 05:48:52 +08:00
|
|
|
if (width != 720)
|
2009-03-11 14:00:40 +08:00
|
|
|
width = 720;
|
2009-03-16 05:48:52 +08:00
|
|
|
if (height != 480)
|
2009-03-11 14:00:40 +08:00
|
|
|
height = 480;
|
|
|
|
|
|
|
|
format->fmt.pix.width = width;
|
|
|
|
format->fmt.pix.height = height;
|
|
|
|
format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
|
|
|
|
format->fmt.pix.bytesperline = width * 2;
|
|
|
|
format->fmt.pix.sizeimage = width * height * 2;
|
|
|
|
format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
|
|
|
format->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
2013-03-12 04:48:34 +08:00
|
|
|
format->fmt.pix.priv = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (cmd == VIDIOC_TRY_FMT)
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* maybe set new image format, driver current only support 720*480 */
|
|
|
|
dev->width = width;
|
|
|
|
dev->height = height;
|
|
|
|
dev->frame_size = width * height * 2;
|
|
|
|
dev->field_size = width * height;
|
|
|
|
dev->bytesperline = width * 2;
|
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (dev->stream_state == STREAM_ON) {
|
2009-03-11 14:00:40 +08:00
|
|
|
dprintk(1, "VIDIOC_SET_FMT: interrupting stream!\n");
|
2009-03-16 05:48:52 +08:00
|
|
|
ret = au0828_stream_interrupt(dev);
|
|
|
|
if (ret != 0) {
|
2009-03-11 14:00:40 +08:00
|
|
|
dprintk(1, "error interrupting video stream!\n");
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
au0828_analog_stream_enable(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_querycap(struct file *file, void *priv,
|
|
|
|
struct v4l2_capability *cap)
|
|
|
|
{
|
2013-02-15 19:11:04 +08:00
|
|
|
struct video_device *vdev = video_devdata(file);
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2018-09-10 20:19:14 +08:00
|
|
|
strscpy(cap->driver, "au0828", sizeof(cap->driver));
|
|
|
|
strscpy(cap->card, dev->board.name, sizeof(cap->card));
|
2013-02-15 19:11:04 +08:00
|
|
|
usb_make_path(dev->usbdev, cap->bus_info, sizeof(cap->bus_info));
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2013-02-15 19:11:04 +08:00
|
|
|
/* set the device capabilities */
|
|
|
|
cap->device_caps = V4L2_CAP_AUDIO |
|
2009-03-11 14:00:40 +08:00
|
|
|
V4L2_CAP_READWRITE |
|
|
|
|
V4L2_CAP_STREAMING |
|
|
|
|
V4L2_CAP_TUNER;
|
2013-02-15 19:11:04 +08:00
|
|
|
if (vdev->vfl_type == VFL_TYPE_GRABBER)
|
|
|
|
cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
|
|
|
|
else
|
|
|
|
cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
|
|
|
|
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
|
|
|
|
V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
|
|
|
|
struct v4l2_fmtdesc *f)
|
|
|
|
{
|
2009-03-16 05:48:52 +08:00
|
|
|
if (f->index)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "%s called\n", __func__);
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(f->description, "Packed YUV2", sizeof(f->description));
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
f->flags = 0;
|
|
|
|
f->pixelformat = V4L2_PIX_FMT_UYVY;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
|
|
|
|
struct v4l2_format *f)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
f->fmt.pix.width = dev->width;
|
|
|
|
f->fmt.pix.height = dev->height;
|
|
|
|
f->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
|
|
|
|
f->fmt.pix.bytesperline = dev->bytesperline;
|
|
|
|
f->fmt.pix.sizeimage = dev->frame_size;
|
|
|
|
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; /* NTSC/PAL */
|
|
|
|
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
2013-03-12 04:48:34 +08:00
|
|
|
f->fmt.pix.priv = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
|
|
|
|
struct v4l2_format *f)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
|
|
|
|
struct v4l2_format *f)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2009-03-11 14:00:40 +08:00
|
|
|
int rc;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
rc = check_dev(dev);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
if (vb2_is_busy(&dev->vb_vidq)) {
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("%s queue busy\n", __func__);
|
2009-03-11 14:00:40 +08:00
|
|
|
rc = -EBUSY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
|
2009-03-11 14:00:40 +08:00
|
|
|
out:
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-03-15 17:10:40 +08:00
|
|
|
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
|
|
|
if (norm == dev->std)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (dev->streaming_users > 0)
|
|
|
|
return -EBUSY;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
dev->std = norm;
|
|
|
|
|
|
|
|
au0828_init_tuner(dev);
|
|
|
|
|
2013-03-12 03:10:33 +08:00
|
|
|
i2c_gate_ctrl(dev, 1);
|
2012-08-07 09:47:12 +08:00
|
|
|
|
2014-06-09 00:54:56 +08:00
|
|
|
/*
|
|
|
|
* FIXME: when we support something other than 60Hz standards,
|
|
|
|
* we are going to have to make the au0828 bridge adjust the size
|
|
|
|
* of its capture buffer, which is currently hardcoded at 720x480
|
|
|
|
*/
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2014-04-29 03:53:01 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm);
|
2012-08-07 09:47:12 +08:00
|
|
|
|
2013-03-12 03:10:33 +08:00
|
|
|
i2c_gate_ctrl(dev, 0);
|
2012-08-07 09:47:12 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-02-15 20:22:37 +08:00
|
|
|
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2013-02-15 20:22:37 +08:00
|
|
|
|
|
|
|
*norm = dev->std;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
static int vidioc_enum_input(struct file *file, void *priv,
|
|
|
|
struct v4l2_input *input)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2009-03-11 14:00:40 +08:00
|
|
|
unsigned int tmp;
|
|
|
|
|
|
|
|
static const char *inames[] = {
|
2009-03-16 04:48:26 +08:00
|
|
|
[AU0828_VMUX_UNDEFINED] = "Undefined",
|
2009-03-11 14:00:40 +08:00
|
|
|
[AU0828_VMUX_COMPOSITE] = "Composite",
|
|
|
|
[AU0828_VMUX_SVIDEO] = "S-Video",
|
|
|
|
[AU0828_VMUX_CABLE] = "Cable TV",
|
|
|
|
[AU0828_VMUX_TELEVISION] = "Television",
|
|
|
|
[AU0828_VMUX_DVB] = "DVB",
|
|
|
|
};
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
tmp = input->index;
|
|
|
|
|
2010-03-28 19:21:18 +08:00
|
|
|
if (tmp >= AU0828_MAX_INPUT)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
2009-03-16 05:48:52 +08:00
|
|
|
if (AUVI_INPUT(tmp).type == 0)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
input->index = tmp;
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(input->name, inames[AUVI_INPUT(tmp).type], sizeof(input->name));
|
2009-03-16 05:48:52 +08:00
|
|
|
if ((AUVI_INPUT(tmp).type == AU0828_VMUX_TELEVISION) ||
|
2013-02-15 19:41:24 +08:00
|
|
|
(AUVI_INPUT(tmp).type == AU0828_VMUX_CABLE)) {
|
2009-03-11 14:00:40 +08:00
|
|
|
input->type |= V4L2_INPUT_TYPE_TUNER;
|
2013-02-15 19:41:24 +08:00
|
|
|
input->audioset = 1;
|
|
|
|
} else {
|
2009-03-11 14:00:40 +08:00
|
|
|
input->type |= V4L2_INPUT_TYPE_CAMERA;
|
2013-02-15 19:41:24 +08:00
|
|
|
input->audioset = 2;
|
|
|
|
}
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-02-27 06:33:13 +08:00
|
|
|
input->std = dev->vdev.tvnorms;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
*i = dev->ctrl_input;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-12 03:18:31 +08:00
|
|
|
static void au0828_s_input(struct au0828_dev *dev, int index)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
switch (AUVI_INPUT(index).type) {
|
2009-03-11 14:00:40 +08:00
|
|
|
case AU0828_VMUX_SVIDEO:
|
|
|
|
dev->input_type = AU0828_VMUX_SVIDEO;
|
2013-02-15 19:41:24 +08:00
|
|
|
dev->ctrl_ainput = 1;
|
2009-03-11 14:00:40 +08:00
|
|
|
break;
|
|
|
|
case AU0828_VMUX_COMPOSITE:
|
|
|
|
dev->input_type = AU0828_VMUX_COMPOSITE;
|
2013-02-15 19:41:24 +08:00
|
|
|
dev->ctrl_ainput = 1;
|
2009-03-11 14:00:40 +08:00
|
|
|
break;
|
|
|
|
case AU0828_VMUX_TELEVISION:
|
|
|
|
dev->input_type = AU0828_VMUX_TELEVISION;
|
2013-02-15 19:41:24 +08:00
|
|
|
dev->ctrl_ainput = 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
break;
|
|
|
|
default:
|
2013-03-12 03:18:31 +08:00
|
|
|
dprintk(1, "unknown input type set [%d]\n",
|
2009-03-16 04:43:13 +08:00
|
|
|
AUVI_INPUT(index).type);
|
2016-02-13 07:18:03 +08:00
|
|
|
return;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
2016-02-13 07:18:03 +08:00
|
|
|
dev->ctrl_input = index;
|
|
|
|
|
2009-04-02 22:26:22 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
|
|
|
|
AUVI_INPUT(index).vmux, 0, 0);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
|
|
|
int enable = 0;
|
2009-03-16 05:48:52 +08:00
|
|
|
if (AUVI_INPUT(i).audio_setup == NULL)
|
2009-03-11 14:00:40 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (i == index)
|
|
|
|
enable = 1;
|
|
|
|
else
|
|
|
|
enable = 0;
|
|
|
|
if (enable) {
|
2009-03-11 14:00:47 +08:00
|
|
|
(AUVI_INPUT(i).audio_setup)(dev, enable);
|
2009-03-11 14:00:40 +08:00
|
|
|
} else {
|
|
|
|
/* Make sure we leave it turned on if some
|
|
|
|
other input is routed to this callback */
|
2009-03-11 14:00:47 +08:00
|
|
|
if ((AUVI_INPUT(i).audio_setup) !=
|
|
|
|
((AUVI_INPUT(index).audio_setup))) {
|
|
|
|
(AUVI_INPUT(i).audio_setup)(dev, enable);
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-02 22:26:22 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
|
|
|
|
AUVI_INPUT(index).amux, 0, 0);
|
2013-03-12 03:18:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2016-02-19 08:28:48 +08:00
|
|
|
struct video_device *vfd = video_devdata(file);
|
2013-03-12 03:18:31 +08:00
|
|
|
|
|
|
|
dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
|
|
|
|
index);
|
|
|
|
if (index >= AU0828_MAX_INPUT)
|
|
|
|
return -EINVAL;
|
|
|
|
if (AUVI_INPUT(index).type == 0)
|
|
|
|
return -EINVAL;
|
2016-02-13 07:18:03 +08:00
|
|
|
|
|
|
|
if (dev->ctrl_input == index)
|
|
|
|
return 0;
|
|
|
|
|
2013-03-12 03:18:31 +08:00
|
|
|
au0828_s_input(dev, index);
|
2016-02-19 08:28:48 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Input has been changed. Disable the media source
|
|
|
|
* associated with the old input and enable source
|
|
|
|
* for the newly set input
|
|
|
|
*/
|
|
|
|
v4l_disable_media_source(vfd);
|
|
|
|
return v4l_enable_media_source(vfd);
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
2013-02-15 19:41:24 +08:00
|
|
|
static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
|
|
|
|
{
|
|
|
|
if (a->index > 1)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "%s called\n", __func__);
|
|
|
|
|
2013-02-15 19:41:24 +08:00
|
|
|
if (a->index == 0)
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Television", sizeof(a->name));
|
2013-02-15 19:41:24 +08:00
|
|
|
else
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Line in", sizeof(a->name));
|
2013-02-15 19:41:24 +08:00
|
|
|
|
|
|
|
a->capability = V4L2_AUDCAP_STEREO;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2013-02-15 19:41:24 +08:00
|
|
|
a->index = dev->ctrl_ainput;
|
|
|
|
if (a->index == 0)
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Television", sizeof(a->name));
|
2009-03-11 14:00:40 +08:00
|
|
|
else
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(a->name, "Line in", sizeof(a->name));
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
a->capability = V4L2_AUDCAP_STEREO;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-09-04 22:59:31 +08:00
|
|
|
static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2013-02-15 19:41:24 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (a->index != dev->ctrl_ainput)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
2015-01-30 00:41:32 +08:00
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2016-02-12 07:41:37 +08:00
|
|
|
struct video_device *vfd = video_devdata(file);
|
|
|
|
int ret;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (t->index != 0)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-02-12 07:41:37 +08:00
|
|
|
ret = v4l_enable_media_source(vfd);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(t->name, "Auvitek tuner", sizeof(t->name));
|
2013-03-12 03:22:13 +08:00
|
|
|
|
|
|
|
au0828_init_tuner(dev);
|
|
|
|
i2c_gate_ctrl(dev, 1);
|
2009-03-16 07:01:53 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
|
2013-03-12 03:22:13 +08:00
|
|
|
i2c_gate_ctrl(dev, 0);
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_tuner(struct file *file, void *priv,
|
2013-03-15 17:10:06 +08:00
|
|
|
const struct v4l2_tuner *t)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (t->index != 0)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
au0828_init_tuner(dev);
|
2013-03-12 03:10:33 +08:00
|
|
|
i2c_gate_ctrl(dev, 1);
|
2009-03-16 07:01:53 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
|
2013-03-12 03:10:33 +08:00
|
|
|
i2c_gate_ctrl(dev, 0);
|
2012-08-07 09:47:12 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
dprintk(1, "VIDIOC_S_TUNER: signal = %x, afc = %x\n", t->signal,
|
|
|
|
t->afc);
|
2012-08-07 09:47:12 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_g_frequency(struct file *file, void *priv,
|
|
|
|
struct v4l2_frequency *freq)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2009-03-16 04:38:47 +08:00
|
|
|
|
2013-03-23 00:32:20 +08:00
|
|
|
if (freq->tuner != 0)
|
|
|
|
return -EINVAL;
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
freq->frequency = dev->ctrl_freq;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_frequency(struct file *file, void *priv,
|
2013-03-19 15:09:26 +08:00
|
|
|
const struct v4l2_frequency *freq)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2013-03-23 00:32:20 +08:00
|
|
|
struct v4l2_frequency new_freq = *freq;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (freq->tuner != 0)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2013-03-12 03:22:13 +08:00
|
|
|
au0828_init_tuner(dev);
|
2013-03-12 03:10:33 +08:00
|
|
|
i2c_gate_ctrl(dev, 1);
|
2012-08-07 09:47:02 +08:00
|
|
|
|
2009-03-16 07:01:53 +08:00
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, freq);
|
2013-03-23 00:32:20 +08:00
|
|
|
/* Get the actual set (and possibly clamped) frequency */
|
|
|
|
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
|
|
|
|
dev->ctrl_freq = new_freq.frequency;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2013-03-12 03:10:33 +08:00
|
|
|
i2c_gate_ctrl(dev, 0);
|
2012-08-07 09:47:02 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
au0828_analog_stream_reset(dev);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
|
|
|
|
/* RAW VBI ioctls */
|
|
|
|
|
|
|
|
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
|
|
|
|
struct v4l2_format *format)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2010-05-30 04:18:45 +08:00
|
|
|
|
|
|
|
format->fmt.vbi.samples_per_line = dev->vbi_width;
|
|
|
|
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
|
|
|
format->fmt.vbi.offset = 0;
|
|
|
|
format->fmt.vbi.flags = 0;
|
|
|
|
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
|
|
|
|
|
|
|
|
format->fmt.vbi.count[0] = dev->vbi_height;
|
|
|
|
format->fmt.vbi.count[1] = dev->vbi_height;
|
|
|
|
format->fmt.vbi.start[0] = 21;
|
|
|
|
format->fmt.vbi.start[1] = 284;
|
2013-03-12 04:48:34 +08:00
|
|
|
memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
|
2010-05-30 04:18:45 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
static int vidioc_cropcap(struct file *file, void *priv,
|
|
|
|
struct v4l2_cropcap *cc)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
2009-03-11 14:00:40 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
cc->bounds.left = 0;
|
|
|
|
cc->bounds.top = 0;
|
|
|
|
cc->bounds.width = dev->width;
|
|
|
|
cc->bounds.height = dev->height;
|
|
|
|
|
|
|
|
cc->defrect = cc->bounds;
|
|
|
|
|
|
|
|
cc->pixelaspect.numerator = 54;
|
|
|
|
cc->pixelaspect.denominator = 59;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-03-20 06:26:23 +08:00
|
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
2009-03-11 14:00:40 +08:00
|
|
|
static int vidioc_g_register(struct file *file, void *priv,
|
|
|
|
struct v4l2_dbg_register *reg)
|
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2012-08-07 09:46:54 +08:00
|
|
|
reg->val = au0828_read(dev, reg->reg);
|
2013-05-29 18:00:03 +08:00
|
|
|
reg->size = 1;
|
2012-08-07 09:46:54 +08:00
|
|
|
return 0;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int vidioc_s_register(struct file *file, void *priv,
|
2013-03-24 19:28:46 +08:00
|
|
|
const struct v4l2_dbg_register *reg)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
2015-01-30 00:41:32 +08:00
|
|
|
struct au0828_dev *dev = video_drvdata(file);
|
|
|
|
|
2016-03-22 20:21:57 +08:00
|
|
|
dprintk(1, "%s called std_set %d dev_state %ld\n", __func__,
|
2015-01-30 00:41:32 +08:00
|
|
|
dev->std_set_in_tuner_core, dev->dev_state);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2012-08-07 09:46:54 +08:00
|
|
|
return au0828_writereg(dev, reg->reg, reg->val);
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
2009-03-20 06:26:23 +08:00
|
|
|
#endif
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2013-02-15 20:14:00 +08:00
|
|
|
static int vidioc_log_status(struct file *file, void *fh)
|
|
|
|
{
|
|
|
|
struct video_device *vdev = video_devdata(file);
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
dprintk(1, "%s called\n", __func__);
|
|
|
|
|
2013-02-15 20:14:00 +08:00
|
|
|
v4l2_ctrl_log_status(file, fh);
|
|
|
|
v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-10 08:47:15 +08:00
|
|
|
void au0828_v4l2_suspend(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
struct urb *urb;
|
|
|
|
int i;
|
|
|
|
|
2014-08-10 08:47:18 +08:00
|
|
|
pr_info("stopping V4L2\n");
|
|
|
|
|
2014-08-10 08:47:15 +08:00
|
|
|
if (dev->stream_state == STREAM_ON) {
|
2014-08-10 08:47:18 +08:00
|
|
|
pr_info("stopping V4L2 active URBs\n");
|
2014-08-10 08:47:15 +08:00
|
|
|
au0828_analog_stream_disable(dev);
|
|
|
|
/* stop urbs */
|
|
|
|
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
|
|
|
|
urb = dev->isoc_ctl.urb[i];
|
|
|
|
if (urb) {
|
|
|
|
if (!irqs_disabled())
|
|
|
|
usb_kill_urb(urb);
|
|
|
|
else
|
|
|
|
usb_unlink_urb(urb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->vid_timeout_running)
|
|
|
|
del_timer_sync(&dev->vid_timeout);
|
|
|
|
if (dev->vbi_timeout_running)
|
|
|
|
del_timer_sync(&dev->vbi_timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
void au0828_v4l2_resume(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
int i, rc;
|
|
|
|
|
2014-08-10 08:47:18 +08:00
|
|
|
pr_info("restarting V4L2\n");
|
|
|
|
|
2014-08-10 08:47:15 +08:00
|
|
|
if (dev->stream_state == STREAM_ON) {
|
|
|
|
au0828_stream_interrupt(dev);
|
|
|
|
au0828_init_tuner(dev);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dev->vid_timeout_running)
|
|
|
|
mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
|
|
|
|
if (dev->vbi_timeout_running)
|
|
|
|
mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
|
|
|
|
|
|
|
|
/* If we were doing ac97 instead of i2s, it would go here...*/
|
|
|
|
au0828_i2s_init(dev);
|
|
|
|
|
|
|
|
au0828_analog_stream_enable(dev);
|
|
|
|
|
|
|
|
if (!(dev->stream_state == STREAM_ON)) {
|
|
|
|
au0828_analog_stream_reset(dev);
|
|
|
|
/* submit urbs */
|
|
|
|
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
|
|
|
|
rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
|
|
|
|
if (rc) {
|
|
|
|
au0828_isocdbg("submit of urb %i failed (error=%i)\n",
|
|
|
|
i, rc);
|
|
|
|
au0828_uninit_isoc(dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-29 14:55:23 +08:00
|
|
|
static const struct v4l2_file_operations au0828_v4l_fops = {
|
2009-03-11 14:00:40 +08:00
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.open = au0828_v4l2_open,
|
|
|
|
.release = au0828_v4l2_close,
|
2015-01-30 00:41:32 +08:00
|
|
|
.read = vb2_fop_read,
|
|
|
|
.poll = vb2_fop_poll,
|
|
|
|
.mmap = vb2_fop_mmap,
|
2012-08-07 09:46:58 +08:00
|
|
|
.unlocked_ioctl = video_ioctl2,
|
2009-03-11 14:00:40 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct v4l2_ioctl_ops video_ioctl_ops = {
|
|
|
|
.vidioc_querycap = vidioc_querycap,
|
|
|
|
.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-03-11 14:00:55 +08:00
|
|
|
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
2013-03-12 04:48:34 +08:00
|
|
|
.vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
2010-05-30 04:18:45 +08:00
|
|
|
.vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
|
2013-02-15 19:41:24 +08:00
|
|
|
.vidioc_enumaudio = vidioc_enumaudio,
|
2009-03-11 14:00:40 +08:00
|
|
|
.vidioc_g_audio = vidioc_g_audio,
|
|
|
|
.vidioc_s_audio = vidioc_s_audio,
|
|
|
|
.vidioc_cropcap = vidioc_cropcap,
|
2015-01-30 00:41:32 +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,
|
|
|
|
.vidioc_expbuf = vb2_ioctl_expbuf,
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
.vidioc_s_std = vidioc_s_std,
|
2013-02-15 20:22:37 +08:00
|
|
|
.vidioc_g_std = vidioc_g_std,
|
2009-03-11 14:00:40 +08:00
|
|
|
.vidioc_enum_input = vidioc_enum_input,
|
|
|
|
.vidioc_g_input = vidioc_g_input,
|
|
|
|
.vidioc_s_input = vidioc_s_input,
|
2015-01-30 00:41:32 +08:00
|
|
|
|
|
|
|
.vidioc_streamon = vb2_ioctl_streamon,
|
|
|
|
.vidioc_streamoff = vb2_ioctl_streamoff,
|
|
|
|
|
2009-03-11 14:00:40 +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,
|
|
|
|
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
|
|
|
.vidioc_g_register = vidioc_g_register,
|
|
|
|
.vidioc_s_register = vidioc_s_register,
|
|
|
|
#endif
|
2013-02-15 20:14:00 +08:00
|
|
|
.vidioc_log_status = vidioc_log_status,
|
|
|
|
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
|
|
|
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
2009-03-11 14:00:40 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const struct video_device au0828_video_template = {
|
|
|
|
.fops = &au0828_v4l_fops,
|
2015-02-27 06:33:13 +08:00
|
|
|
.release = video_device_release_empty,
|
2018-01-05 02:08:56 +08:00
|
|
|
.ioctl_ops = &video_ioctl_ops,
|
2014-06-09 00:54:56 +08:00
|
|
|
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
|
2009-03-11 14:00:40 +08:00
|
|
|
};
|
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
static int au0828_vb2_setup(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct vb2_queue *q;
|
|
|
|
|
|
|
|
/* Setup Videobuf2 for Video capture */
|
|
|
|
q = &dev->vb_vidq;
|
|
|
|
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
|
|
|
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
|
|
|
|
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
|
|
|
q->drv_priv = dev;
|
|
|
|
q->buf_struct_size = sizeof(struct au0828_buffer);
|
|
|
|
q->ops = &au0828_video_qops;
|
|
|
|
q->mem_ops = &vb2_vmalloc_memops;
|
|
|
|
|
|
|
|
rc = vb2_queue_init(q);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* Setup Videobuf2 for VBI capture */
|
|
|
|
q = &dev->vb_vbiq;
|
|
|
|
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
|
|
|
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
|
|
|
|
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
|
|
|
q->drv_priv = dev;
|
|
|
|
q->buf_struct_size = sizeof(struct au0828_buffer);
|
|
|
|
q->ops = &au0828_vbi_qops;
|
|
|
|
q->mem_ops = &vb2_vmalloc_memops;
|
|
|
|
|
|
|
|
rc = vb2_queue_init(q);
|
|
|
|
if (rc < 0)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-08-31 22:43:09 +08:00
|
|
|
static void au0828_analog_create_entities(struct au0828_dev *dev)
|
|
|
|
{
|
|
|
|
#if defined(CONFIG_MEDIA_CONTROLLER)
|
|
|
|
static const char * const inames[] = {
|
|
|
|
[AU0828_VMUX_COMPOSITE] = "Composite",
|
|
|
|
[AU0828_VMUX_SVIDEO] = "S-Video",
|
|
|
|
[AU0828_VMUX_CABLE] = "Cable TV",
|
|
|
|
[AU0828_VMUX_TELEVISION] = "Television",
|
|
|
|
[AU0828_VMUX_DVB] = "DVB",
|
|
|
|
};
|
|
|
|
int ret, i;
|
|
|
|
|
|
|
|
/* Initialize Video and VBI pads */
|
|
|
|
dev->video_pad.flags = MEDIA_PAD_FL_SINK;
|
2015-12-11 17:44:40 +08:00
|
|
|
ret = media_entity_pads_init(&dev->vdev.entity, 1, &dev->video_pad);
|
2015-08-31 22:43:09 +08:00
|
|
|
if (ret < 0)
|
|
|
|
pr_err("failed to initialize video media entity!\n");
|
|
|
|
|
|
|
|
dev->vbi_pad.flags = MEDIA_PAD_FL_SINK;
|
2015-12-11 17:44:40 +08:00
|
|
|
ret = media_entity_pads_init(&dev->vbi_dev.entity, 1, &dev->vbi_pad);
|
2015-08-31 22:43:09 +08:00
|
|
|
if (ret < 0)
|
|
|
|
pr_err("failed to initialize vbi media entity!\n");
|
|
|
|
|
|
|
|
/* Create entities for each input connector */
|
|
|
|
for (i = 0; i < AU0828_MAX_INPUT; i++) {
|
|
|
|
struct media_entity *ent = &dev->input_ent[i];
|
|
|
|
|
|
|
|
if (AUVI_INPUT(i).type == AU0828_VMUX_UNDEFINED)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ent->name = inames[AUVI_INPUT(i).type];
|
|
|
|
ent->flags = MEDIA_ENT_FL_CONNECTOR;
|
|
|
|
dev->input_pad[i].flags = MEDIA_PAD_FL_SOURCE;
|
|
|
|
|
|
|
|
switch (AUVI_INPUT(i).type) {
|
|
|
|
case AU0828_VMUX_COMPOSITE:
|
2015-12-11 03:25:41 +08:00
|
|
|
ent->function = MEDIA_ENT_F_CONN_COMPOSITE;
|
2015-08-31 22:43:09 +08:00
|
|
|
break;
|
|
|
|
case AU0828_VMUX_SVIDEO:
|
2015-12-11 03:25:41 +08:00
|
|
|
ent->function = MEDIA_ENT_F_CONN_SVIDEO;
|
2015-08-31 22:43:09 +08:00
|
|
|
break;
|
|
|
|
case AU0828_VMUX_CABLE:
|
|
|
|
case AU0828_VMUX_TELEVISION:
|
|
|
|
case AU0828_VMUX_DVB:
|
2016-02-12 19:15:41 +08:00
|
|
|
default: /* Just to shut up a warning */
|
2015-12-11 03:25:41 +08:00
|
|
|
ent->function = MEDIA_ENT_F_CONN_RF;
|
2015-08-31 22:43:09 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-12-11 17:44:40 +08:00
|
|
|
ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]);
|
2015-08-31 22:43:09 +08:00
|
|
|
if (ret < 0)
|
|
|
|
pr_err("failed to initialize input pad[%d]!\n", i);
|
|
|
|
|
|
|
|
ret = media_device_register_entity(dev->media_dev, ent);
|
|
|
|
if (ret < 0)
|
|
|
|
pr_err("failed to register input entity %d!\n", i);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
/**************************************************************************/
|
|
|
|
|
2009-03-11 14:01:00 +08:00
|
|
|
int au0828_analog_register(struct au0828_dev *dev,
|
|
|
|
struct usb_interface *interface)
|
2009-03-11 14:00:40 +08:00
|
|
|
{
|
|
|
|
int retval = -ENOMEM;
|
2009-03-11 14:01:00 +08:00
|
|
|
struct usb_host_interface *iface_desc;
|
|
|
|
struct usb_endpoint_descriptor *endpoint;
|
2012-04-22 18:54:42 +08:00
|
|
|
int i, ret;
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2014-06-09 00:54:58 +08:00
|
|
|
dprintk(1, "au0828_analog_register called for intf#%d!\n",
|
|
|
|
interface->cur_altsetting->desc.bInterfaceNumber);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2016-02-10 01:53:39 +08:00
|
|
|
/* No analog TV */
|
|
|
|
if (AUVI_INPUT(0).type == AU0828_VMUX_UNDEFINED)
|
|
|
|
return 0;
|
|
|
|
|
2009-03-11 14:01:00 +08:00
|
|
|
/* set au0828 usb interface0 to as5 */
|
|
|
|
retval = usb_set_interface(dev->usbdev,
|
2009-03-16 05:48:52 +08:00
|
|
|
interface->cur_altsetting->desc.bInterfaceNumber, 5);
|
2009-03-11 14:01:00 +08:00
|
|
|
if (retval != 0) {
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("Failure setting usb interface0 to as5\n");
|
2009-03-11 14:01:00 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Figure out which endpoint has the isoc interface */
|
|
|
|
iface_desc = interface->cur_altsetting;
|
2009-03-16 05:48:52 +08:00
|
|
|
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
|
2009-03-11 14:01:00 +08:00
|
|
|
endpoint = &iface_desc->endpoint[i].desc;
|
2009-03-16 05:48:52 +08:00
|
|
|
if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
|
|
|
|
== USB_DIR_IN) &&
|
|
|
|
((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
|
|
|
|
== USB_ENDPOINT_XFER_ISOC)) {
|
2009-03-11 14:01:00 +08:00
|
|
|
|
|
|
|
/* we find our isoc in endpoint */
|
|
|
|
u16 tmp = le16_to_cpu(endpoint->wMaxPacketSize);
|
2009-03-16 05:48:52 +08:00
|
|
|
dev->max_pkt_size = (tmp & 0x07ff) *
|
|
|
|
(((tmp & 0x1800) >> 11) + 1);
|
2009-03-11 14:01:00 +08:00
|
|
|
dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
|
2014-06-09 00:54:58 +08:00
|
|
|
dprintk(1,
|
|
|
|
"Found isoc endpoint 0x%02x, max size = %d\n",
|
|
|
|
dev->isoc_in_endpointaddr, dev->max_pkt_size);
|
2009-03-11 14:01:00 +08:00
|
|
|
}
|
|
|
|
}
|
2009-03-16 05:48:52 +08:00
|
|
|
if (!(dev->isoc_in_endpointaddr)) {
|
2014-08-10 08:47:17 +08:00
|
|
|
pr_info("Could not locate isoc endpoint\n");
|
2009-03-11 14:01:00 +08:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
init_waitqueue_head(&dev->open);
|
|
|
|
spin_lock_init(&dev->slock);
|
|
|
|
|
2010-05-30 04:18:45 +08:00
|
|
|
/* init video dma queues */
|
2009-03-11 14:00:40 +08:00
|
|
|
INIT_LIST_HEAD(&dev->vidq.active);
|
2010-05-30 04:18:45 +08:00
|
|
|
INIT_LIST_HEAD(&dev->vbiq.active);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
treewide: setup_timer() -> timer_setup()
This converts all remaining cases of the old setup_timer() API into using
timer_setup(), where the callback argument is the structure already
holding the struct timer_list. These should have no behavioral changes,
since they just change which pointer is passed into the callback with
the same available pointers after conversion. It handles the following
examples, in addition to some other variations.
Casting from unsigned long:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
setup_timer(&ptr->my_timer, my_callback, ptr);
and forced object casts:
void my_callback(struct something *ptr)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, (unsigned long)ptr);
become:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
Direct function assignments:
void my_callback(unsigned long data)
{
struct something *ptr = (struct something *)data;
...
}
...
ptr->my_timer.function = my_callback;
have a temporary cast added, along with converting the args:
void my_callback(struct timer_list *t)
{
struct something *ptr = from_timer(ptr, t, my_timer);
...
}
...
ptr->my_timer.function = (TIMER_FUNC_TYPE)my_callback;
And finally, callbacks without a data assignment:
void my_callback(unsigned long data)
{
...
}
...
setup_timer(&ptr->my_timer, my_callback, 0);
have their argument renamed to verify they're unused during conversion:
void my_callback(struct timer_list *unused)
{
...
}
...
timer_setup(&ptr->my_timer, my_callback, 0);
The conversion is done with the following Coccinelle script:
spatch --very-quiet --all-includes --include-headers \
-I ./arch/x86/include -I ./arch/x86/include/generated \
-I ./include -I ./arch/x86/include/uapi \
-I ./arch/x86/include/generated/uapi -I ./include/uapi \
-I ./include/generated/uapi --include ./include/linux/kconfig.h \
--dir . \
--cocci-file ~/src/data/timer_setup.cocci
@fix_address_of@
expression e;
@@
setup_timer(
-&(e)
+&e
, ...)
// Update any raw setup_timer() usages that have a NULL callback, but
// would otherwise match change_timer_function_usage, since the latter
// will update all function assignments done in the face of a NULL
// function initialization in setup_timer().
@change_timer_function_usage_NULL@
expression _E;
identifier _timer;
type _cast_data;
@@
(
-setup_timer(&_E->_timer, NULL, _E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E->_timer, NULL, (_cast_data)_E);
+timer_setup(&_E->_timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, &_E);
+timer_setup(&_E._timer, NULL, 0);
|
-setup_timer(&_E._timer, NULL, (_cast_data)&_E);
+timer_setup(&_E._timer, NULL, 0);
)
@change_timer_function_usage@
expression _E;
identifier _timer;
struct timer_list _stl;
identifier _callback;
type _cast_func, _cast_data;
@@
(
-setup_timer(&_E->_timer, _callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, &_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, _E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, &_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)_E);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, (_cast_func)&_callback, (_cast_data)&_E);
+timer_setup(&_E._timer, _callback, 0);
|
_E->_timer@_stl.function = _callback;
|
_E->_timer@_stl.function = &_callback;
|
_E->_timer@_stl.function = (_cast_func)_callback;
|
_E->_timer@_stl.function = (_cast_func)&_callback;
|
_E._timer@_stl.function = _callback;
|
_E._timer@_stl.function = &_callback;
|
_E._timer@_stl.function = (_cast_func)_callback;
|
_E._timer@_stl.function = (_cast_func)&_callback;
)
// callback(unsigned long arg)
@change_callback_handle_cast
depends on change_timer_function_usage@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
identifier _handle;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
(
... when != _origarg
_handletype *_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(_handletype *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
|
... when != _origarg
_handletype *_handle;
... when != _handle
_handle =
-(void *)_origarg;
+from_timer(_handle, t, _timer);
... when != _origarg
)
}
// callback(unsigned long arg) without existing variable
@change_callback_handle_cast_no_arg
depends on change_timer_function_usage &&
!change_callback_handle_cast@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _origtype;
identifier _origarg;
type _handletype;
@@
void _callback(
-_origtype _origarg
+struct timer_list *t
)
{
+ _handletype *_origarg = from_timer(_origarg, t, _timer);
+
... when != _origarg
- (_handletype *)_origarg
+ _origarg
... when != _origarg
}
// Avoid already converted callbacks.
@match_callback_converted
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier t;
@@
void _callback(struct timer_list *t)
{ ... }
// callback(struct something *handle)
@change_callback_handle_arg
depends on change_timer_function_usage &&
!match_callback_converted &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
@@
void _callback(
-_handletype *_handle
+struct timer_list *t
)
{
+ _handletype *_handle = from_timer(_handle, t, _timer);
...
}
// If change_callback_handle_arg ran on an empty function, remove
// the added handler.
@unchange_callback_handle_arg
depends on change_timer_function_usage &&
change_callback_handle_arg@
identifier change_timer_function_usage._callback;
identifier change_timer_function_usage._timer;
type _handletype;
identifier _handle;
identifier t;
@@
void _callback(struct timer_list *t)
{
- _handletype *_handle = from_timer(_handle, t, _timer);
}
// We only want to refactor the setup_timer() data argument if we've found
// the matching callback. This undoes changes in change_timer_function_usage.
@unchange_timer_function_usage
depends on change_timer_function_usage &&
!change_callback_handle_cast &&
!change_callback_handle_cast_no_arg &&
!change_callback_handle_arg@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type change_timer_function_usage._cast_data;
@@
(
-timer_setup(&_E->_timer, _callback, 0);
+setup_timer(&_E->_timer, _callback, (_cast_data)_E);
|
-timer_setup(&_E._timer, _callback, 0);
+setup_timer(&_E._timer, _callback, (_cast_data)&_E);
)
// If we fixed a callback from a .function assignment, fix the
// assignment cast now.
@change_timer_function_assignment
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression change_timer_function_usage._E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_func;
typedef TIMER_FUNC_TYPE;
@@
(
_E->_timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E->_timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-&_callback;
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)_callback
+(TIMER_FUNC_TYPE)_callback
;
|
_E._timer.function =
-(_cast_func)&_callback
+(TIMER_FUNC_TYPE)_callback
;
)
// Sometimes timer functions are called directly. Replace matched args.
@change_timer_function_calls
depends on change_timer_function_usage &&
(change_callback_handle_cast ||
change_callback_handle_cast_no_arg ||
change_callback_handle_arg)@
expression _E;
identifier change_timer_function_usage._timer;
identifier change_timer_function_usage._callback;
type _cast_data;
@@
_callback(
(
-(_cast_data)_E
+&_E->_timer
|
-(_cast_data)&_E
+&_E._timer
|
-_E
+&_E->_timer
)
)
// If a timer has been configured without a data argument, it can be
// converted without regard to the callback argument, since it is unused.
@match_timer_function_unused_data@
expression _E;
identifier _timer;
identifier _callback;
@@
(
-setup_timer(&_E->_timer, _callback, 0);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0L);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E->_timer, _callback, 0UL);
+timer_setup(&_E->_timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0L);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_E._timer, _callback, 0UL);
+timer_setup(&_E._timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0L);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(&_timer, _callback, 0UL);
+timer_setup(&_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0L);
+timer_setup(_timer, _callback, 0);
|
-setup_timer(_timer, _callback, 0UL);
+timer_setup(_timer, _callback, 0);
)
@change_callback_unused_data
depends on match_timer_function_unused_data@
identifier match_timer_function_unused_data._callback;
type _origtype;
identifier _origarg;
@@
void _callback(
-_origtype _origarg
+struct timer_list *unused
)
{
... when != _origarg
}
Signed-off-by: Kees Cook <keescook@chromium.org>
2017-10-17 05:43:17 +08:00
|
|
|
timer_setup(&dev->vid_timeout, au0828_vid_buffer_timeout, 0);
|
|
|
|
timer_setup(&dev->vbi_timeout, au0828_vbi_buffer_timeout, 0);
|
2010-10-10 01:43:53 +08:00
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
dev->width = NTSC_STD_W;
|
|
|
|
dev->height = NTSC_STD_H;
|
|
|
|
dev->field_size = dev->width * dev->height;
|
|
|
|
dev->frame_size = dev->field_size << 1;
|
|
|
|
dev->bytesperline = dev->width << 1;
|
2013-03-12 03:12:17 +08:00
|
|
|
dev->vbi_width = 720;
|
|
|
|
dev->vbi_height = 1;
|
2009-03-11 14:00:40 +08:00
|
|
|
dev->ctrl_ainput = 0;
|
2013-03-23 00:32:20 +08:00
|
|
|
dev->ctrl_freq = 960;
|
2013-02-15 20:22:37 +08:00
|
|
|
dev->std = V4L2_STD_NTSC_M;
|
2016-02-13 07:18:03 +08:00
|
|
|
/* Default input is TV Tuner */
|
2013-03-12 03:18:31 +08:00
|
|
|
au0828_s_input(dev, 0);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
mutex_init(&dev->vb_queue_lock);
|
|
|
|
mutex_init(&dev->vb_vbi_queue_lock);
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
/* Fill the video capture device struct */
|
2015-02-27 06:33:13 +08:00
|
|
|
dev->vdev = au0828_video_template;
|
|
|
|
dev->vdev.v4l2_dev = &dev->v4l2_dev;
|
|
|
|
dev->vdev.lock = &dev->lock;
|
|
|
|
dev->vdev.queue = &dev->vb_vidq;
|
|
|
|
dev->vdev.queue->lock = &dev->vb_queue_lock;
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(dev->vdev.name, "au0828a video", sizeof(dev->vdev.name));
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
/* Setup the VBI device */
|
2015-02-27 06:33:13 +08:00
|
|
|
dev->vbi_dev = au0828_video_template;
|
|
|
|
dev->vbi_dev.v4l2_dev = &dev->v4l2_dev;
|
|
|
|
dev->vbi_dev.lock = &dev->lock;
|
|
|
|
dev->vbi_dev.queue = &dev->vb_vbiq;
|
|
|
|
dev->vbi_dev.queue->lock = &dev->vb_vbi_queue_lock;
|
2018-09-11 04:20:42 +08:00
|
|
|
strscpy(dev->vbi_dev.name, "au0828a vbi", sizeof(dev->vbi_dev.name));
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2015-08-31 22:43:09 +08:00
|
|
|
/* Init entities at the Media Controller */
|
|
|
|
au0828_analog_create_entities(dev);
|
2015-06-09 09:20:46 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
/* initialize videobuf2 stuff */
|
|
|
|
retval = au0828_vb2_setup(dev);
|
|
|
|
if (retval != 0) {
|
|
|
|
dprintk(1, "unable to setup videobuf2 queues (error = %d).\n",
|
|
|
|
retval);
|
2015-02-27 06:33:13 +08:00
|
|
|
return -ENODEV;
|
2015-01-30 00:41:32 +08:00
|
|
|
}
|
|
|
|
|
2009-03-11 14:00:40 +08:00
|
|
|
/* Register the v4l2 device */
|
2015-02-27 06:33:13 +08:00
|
|
|
video_set_drvdata(&dev->vdev, dev);
|
|
|
|
retval = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
|
2009-03-16 05:48:52 +08:00
|
|
|
if (retval != 0) {
|
|
|
|
dprintk(1, "unable to register video device (error = %d).\n",
|
|
|
|
retval);
|
2012-04-22 18:54:42 +08:00
|
|
|
ret = -ENODEV;
|
2015-01-30 00:41:32 +08:00
|
|
|
goto err_reg_vdev;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Register the vbi device */
|
2015-02-27 06:33:13 +08:00
|
|
|
video_set_drvdata(&dev->vbi_dev, dev);
|
|
|
|
retval = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, -1);
|
2009-03-16 05:48:52 +08:00
|
|
|
if (retval != 0) {
|
|
|
|
dprintk(1, "unable to register vbi device (error = %d).\n",
|
|
|
|
retval);
|
2012-04-22 18:54:42 +08:00
|
|
|
ret = -ENODEV;
|
2015-01-30 00:41:32 +08:00
|
|
|
goto err_reg_vbi_dev;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
2016-03-02 21:11:41 +08:00
|
|
|
|
|
|
|
#ifdef CONFIG_MEDIA_CONTROLLER
|
|
|
|
retval = v4l2_mc_create_media_graph(dev->media_dev);
|
2016-02-10 01:53:39 +08:00
|
|
|
if (retval) {
|
|
|
|
pr_err("%s() au0282_dev_register failed to create graph\n",
|
|
|
|
__func__);
|
|
|
|
ret = -ENODEV;
|
|
|
|
goto err_reg_vbi_dev;
|
|
|
|
}
|
2016-03-02 21:11:41 +08:00
|
|
|
#endif
|
2009-03-11 14:00:40 +08:00
|
|
|
|
2009-03-16 05:48:52 +08:00
|
|
|
dprintk(1, "%s completed!\n", __func__);
|
2009-03-11 14:00:40 +08:00
|
|
|
|
|
|
|
return 0;
|
2012-04-22 18:54:42 +08:00
|
|
|
|
2015-01-30 00:41:32 +08:00
|
|
|
err_reg_vbi_dev:
|
2015-02-27 06:33:13 +08:00
|
|
|
video_unregister_device(&dev->vdev);
|
2015-01-30 00:41:32 +08:00
|
|
|
err_reg_vdev:
|
|
|
|
vb2_queue_release(&dev->vb_vidq);
|
|
|
|
vb2_queue_release(&dev->vb_vbiq);
|
2012-04-22 18:54:42 +08:00
|
|
|
return ret;
|
2009-03-11 14:00:40 +08:00
|
|
|
}
|
|
|
|
|