diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 19:22:22 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-13 19:22:22 -0800 |
commit | d8c532c40721f7507896d202b8cae3b3642d2b0d (patch) | |
tree | 42b1ce76671eb85324281ed93491432f4523f983 | |
parent | e777d192ffb9f2929d547a2f8a5f65b7db7a9552 (diff) | |
parent | 77c53d0b56264a8fc5844e087ad15fffe20c299d (diff) |
Merge branch 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- Missing MAINTAINERS entries were added for several drivers
- Adds V4L2 support for DMABUF handling, allowing zero-copy buffer
sharing between V4L2 devices and GPU
- Got rid of all warnings when compiling with W=1 on x86
- Add a new driver for Exynos hardware (s3c-camif)
- Several bug fixes, cleanups and driver improvements
* 'v4l_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (243 commits)
[media] omap3isp: Replace cpu_is_omap3630() with ISP revision check
[media] omap3isp: Prepare/unprepare clocks before/after enable/disable
[media] omap3isp: preview: Add support for 8-bit formats at the sink pad
[media] omap3isp: Replace printk with dev_*
[media] omap3isp: Find source pad from external entity
[media] omap3isp: Configure CSI-2 phy based on platform data
[media] omap3isp: Add PHY routing configuration
[media] omap3isp: Add CSI configuration registers from control block to ISP resources
[media] omap3isp: Remove unneeded module memory address definitions
[media] omap3isp: Use monotonic timestamps for statistics buffers
[media] uvcvideo: Fix control value clamping for unsigned integer controls
[media] uvcvideo: Mark first output terminal as default video node
[media] uvcvideo: Add VIDIOC_[GS]_PRIORITY support
[media] uvcvideo: Return -ENOTTY for unsupported ioctls
[media] uvcvideo: Set device_caps in VIDIOC_QUERYCAP
[media] uvcvideo: Don't fail when an unsupported format is requested
[media] uvcvideo: Return -EACCES when trying to access a read/write-only control
[media] uvcvideo: Set error_idx properly for extended controls API failures
[media] rtl28xxu: add NOXON DAB/DAB+ USB dongle rev 2
[media] fc2580: write some registers conditionally
...
314 files changed, 7754 insertions, 1863 deletions
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 4fdf6b562d1..3dd9e78815d 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2586,6 +2586,13 @@ ioctls.</para> <para>Vendor and device specific media bus pixel formats. <xref linkend="v4l2-mbus-vendor-spec-fmts" />.</para> </listitem> + <listitem> + <para>Importing DMABUF file descriptors as a new IO method described + in <xref linkend="dmabuf" />.</para> + </listitem> + <listitem> + <para>Exporting DMABUF files using &VIDIOC-EXPBUF; ioctl.</para> + </listitem> </itemizedlist> </section> diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml index b5d1cbdc558..388a3403265 100644 --- a/Documentation/DocBook/media/v4l/io.xml +++ b/Documentation/DocBook/media/v4l/io.xml @@ -331,7 +331,7 @@ application until one or more buffers can be dequeued. By default outgoing queue. When the <constant>O_NONBLOCK</constant> flag was given to the &func-open; function, <constant>VIDIOC_DQBUF</constant> returns immediately with an &EAGAIN; when no buffer is available. The -&func-select; or &func-poll; function are always available.</para> +&func-select; or &func-poll; functions are always available.</para> <para>To start and stop capturing or output applications call the &VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctl. Note @@ -472,6 +472,165 @@ rest should be evident.</para> </footnote></para> </section> + <section id="dmabuf"> + <title>Streaming I/O (DMA buffer importing)</title> + + <note> + <title>Experimental</title> + <para>This is an <link linkend="experimental"> experimental </link> + interface and may change in the future.</para> + </note> + +<para>The DMABUF framework provides a generic method for sharing buffers +between multiple devices. Device drivers that support DMABUF can export a DMA +buffer to userspace as a file descriptor (known as the exporter role), import a +DMA buffer from userspace using a file descriptor previously exported for a +different or the same device (known as the importer role), or both. This +section describes the DMABUF importer role API in V4L2.</para> + + <para>Refer to <link linked="vidioc-expbuf"> DMABUF exporting </link> for +details about exporting V4L2 buffers as DMABUF file descriptors.</para> + +<para>Input and output devices support the streaming I/O method when the +<constant>V4L2_CAP_STREAMING</constant> flag in the +<structfield>capabilities</structfield> field of &v4l2-capability; returned by +the &VIDIOC-QUERYCAP; ioctl is set. Whether importing DMA buffers through +DMABUF file descriptors is supported is determined by calling the +&VIDIOC-REQBUFS; ioctl with the memory type set to +<constant>V4L2_MEMORY_DMABUF</constant>.</para> + + <para>This I/O method is dedicated to sharing DMA buffers between different +devices, which may be V4L devices or other video-related devices (e.g. DRM). +Buffers (planes) are allocated by a driver on behalf of an application. Next, +these buffers are exported to the application as file descriptors using an API +which is specific for an allocator driver. Only such file descriptor are +exchanged. The descriptors and meta-information are passed in &v4l2-buffer; (or +in &v4l2-plane; in the multi-planar API case). The driver must be switched +into DMABUF I/O mode by calling the &VIDIOC-REQBUFS; with the desired buffer +type.</para> + + <example> + <title>Initiating streaming I/O with DMABUF file descriptors</title> + + <programlisting> +&v4l2-requestbuffers; reqbuf; + +memset(&reqbuf, 0, sizeof (reqbuf)); +reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; +reqbuf.memory = V4L2_MEMORY_DMABUF; +reqbuf.count = 1; + +if (ioctl(fd, &VIDIOC-REQBUFS;, &reqbuf) == -1) { + if (errno == EINVAL) + printf("Video capturing or DMABUF streaming is not supported\n"); + else + perror("VIDIOC_REQBUFS"); + + exit(EXIT_FAILURE); +} + </programlisting> + </example> + + <para>The buffer (plane) file descriptor is passed on the fly with the +&VIDIOC-QBUF; ioctl. In case of multiplanar buffers, every plane can be +associated with a different DMABUF descriptor. Although buffers are commonly +cycled, applications can pass a different DMABUF descriptor at each +<constant>VIDIOC_QBUF</constant> call.</para> + + <example> + <title>Queueing DMABUF using single plane API</title> + + <programlisting> +int buffer_queue(int v4lfd, int index, int dmafd) +{ + &v4l2-buffer; buf; + + memset(&buf, 0, sizeof buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = index; + buf.m.fd = dmafd; + + if (ioctl(v4lfd, &VIDIOC-QBUF;, &buf) == -1) { + perror("VIDIOC_QBUF"); + return -1; + } + + return 0; +} + </programlisting> + </example> + + <example> + <title>Queueing DMABUF using multi plane API</title> + + <programlisting> +int buffer_queue_mp(int v4lfd, int index, int dmafd[], int n_planes) +{ + &v4l2-buffer; buf; + &v4l2-plane; planes[VIDEO_MAX_PLANES]; + int i; + + memset(&buf, 0, sizeof buf); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + buf.memory = V4L2_MEMORY_DMABUF; + buf.index = index; + buf.m.planes = planes; + buf.length = n_planes; + + memset(&planes, 0, sizeof planes); + + for (i = 0; i < n_planes; ++i) + buf.m.planes[i].m.fd = dmafd[i]; + + if (ioctl(v4lfd, &VIDIOC-QBUF;, &buf) == -1) { + perror("VIDIOC_QBUF"); + return -1; + } + + return 0; +} + </programlisting> + </example> + + <para>Captured or displayed buffers are dequeued with the +&VIDIOC-DQBUF; ioctl. The driver can unlock the buffer at any +time between the completion of the DMA and this ioctl. The memory is +also unlocked when &VIDIOC-STREAMOFF; is called, &VIDIOC-REQBUFS;, or +when the device is closed.</para> + + <para>For capturing applications it is customary to enqueue a +number of empty buffers, to start capturing and enter the read loop. +Here the application waits until a filled buffer can be dequeued, and +re-enqueues the buffer when the data is no longer needed. Output +applications fill and enqueue buffers, when enough buffers are stacked +up output is started. In the write loop, when the application +runs out of free buffers it must wait until an empty buffer can be +dequeued and reused. Two methods exist to suspend execution of the +application until one or more buffers can be dequeued. By default +<constant>VIDIOC_DQBUF</constant> blocks when no buffer is in the +outgoing queue. When the <constant>O_NONBLOCK</constant> flag was +given to the &func-open; function, <constant>VIDIOC_DQBUF</constant> +returns immediately with an &EAGAIN; when no buffer is available. The +&func-select; and &func-poll; functions are always available.</para> + + <para>To start and stop capturing or displaying applications call the +&VIDIOC-STREAMON; and &VIDIOC-STREAMOFF; ioctls. Note that +<constant>VIDIOC_STREAMOFF</constant> removes all buffers from both queues and +unlocks all buffers as a side effect. Since there is no notion of doing +anything "now" on a multitasking system, if an application needs to synchronize +with another event it should examine the &v4l2-buffer; +<structfield>timestamp</structfield> of captured buffers, or set the field +before enqueuing buffers for output.</para> + + <para>Drivers implementing DMABUF importing I/O must support the +<constant>VIDIOC_REQBUFS</constant>, <constant>VIDIOC_QBUF</constant>, +<constant>VIDIOC_DQBUF</constant>, <constant>VIDIOC_STREAMON</constant> and +<constant>VIDIOC_STREAMOFF</constant> ioctls, and the +<function>select()</function> and <function>poll()</function> functions.</para> + + </section> + <section id="async"> <title>Asynchronous I/O</title> @@ -673,6 +832,14 @@ memory, set by the application. See <xref linkend="userp" /> for details. <structname>v4l2_buffer</structname> structure.</entry> </row> <row> + <entry></entry> + <entry>int</entry> + <entry><structfield>fd</structfield></entry> + <entry>For the single-plane API and when +<structfield>memory</structfield> is <constant>V4L2_MEMORY_DMABUF</constant> this +is the file descriptor associated with a DMABUF buffer.</entry> + </row> + <row> <entry>__u32</entry> <entry><structfield>length</structfield></entry> <entry></entry> @@ -744,6 +911,15 @@ should set this to 0.</entry> </entry> </row> <row> + <entry></entry> + <entry>int</entry> + <entry><structfield>fd</structfield></entry> + <entry>When the memory type in the containing &v4l2-buffer; is + <constant>V4L2_MEMORY_DMABUF</constant>, this is a file + descriptor associated with a DMABUF buffer, similar to the + <structfield>fd</structfield> field in &v4l2-buffer;.</entry> + </row> + <row> <entry>__u32</entry> <entry><structfield>data_offset</structfield></entry> <entry></entry> @@ -923,7 +1099,7 @@ application. Drivers set or clear this flag when the </row> <row> <entry><constant>V4L2_BUF_FLAG_NO_CACHE_INVALIDATE</constant></entry> - <entry>0x0400</entry> + <entry>0x0800</entry> <entry>Caches do not have to be invalidated for this buffer. Typically applications shall use this flag if the data captured in the buffer is not going to be touched by the CPU, instead the buffer will, probably, be @@ -932,7 +1108,7 @@ passed on to a DMA-capable hardware unit for further processing or output. </row> <row> <entry><constant>V4L2_BUF_FLAG_NO_CACHE_CLEAN</constant></entry> - <entry>0x0800</entry> + <entry>0x1000</entry> <entry>Caches do not have to be cleaned for this buffer. Typically applications shall use this flag for output buffers if the data in this buffer has not been created by the CPU but by some DMA-capable unit, @@ -964,6 +1140,12 @@ pointer</link> I/O.</entry> <entry>3</entry> <entry>[to do]</entry> </row> + <row> + <entry><constant>V4L2_MEMORY_DMABUF</constant></entry> + <entry>4</entry> + <entry>The buffer is used for <link linkend="dmabuf">DMA shared +buffer</link> I/O.</entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml index 10ccde9d16d..4d110b1ad3e 100644 --- a/Documentation/DocBook/media/v4l/v4l2.xml +++ b/Documentation/DocBook/media/v4l/v4l2.xml @@ -543,6 +543,7 @@ and discussions on the V4L mailing list.</revremark> &sub-enuminput; &sub-enumoutput; &sub-enumstd; + &sub-expbuf; &sub-g-audio; &sub-g-audioout; &sub-g-crop; diff --git a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml index a8cda1acacd..cd994367243 100644 --- a/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml +++ b/Documentation/DocBook/media/v4l/vidioc-create-bufs.xml @@ -6,7 +6,8 @@ <refnamediv> <refname>VIDIOC_CREATE_BUFS</refname> - <refpurpose>Create buffers for Memory Mapped or User Pointer I/O</refpurpose> + <refpurpose>Create buffers for Memory Mapped or User Pointer or DMA Buffer + I/O</refpurpose> </refnamediv> <refsynopsisdiv> @@ -55,11 +56,11 @@ </note> <para>This ioctl is used to create buffers for <link linkend="mmap">memory -mapped</link> or <link linkend="userp">user pointer</link> -I/O. It can be used as an alternative or in addition to the -<constant>VIDIOC_REQBUFS</constant> ioctl, when a tighter control over buffers -is required. This ioctl can be called multiple times to create buffers of -different sizes.</para> +mapped</link> or <link linkend="userp">user pointer</link> or <link +linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in +addition to the <constant>VIDIOC_REQBUFS</constant> ioctl, when a tighter +control over buffers is required. This ioctl can be called multiple times to +create buffers of different sizes.</para> <para>To allocate device buffers applications initialize relevant fields of the <structname>v4l2_create_buffers</structname> structure. They set the @@ -109,7 +110,8 @@ information.</para> <entry>__u32</entry> <entry><structfield>memory</structfield></entry> <entry>Applications set this field to -<constant>V4L2_MEMORY_MMAP</constant> or +<constant>V4L2_MEMORY_MMAP</constant>, +<constant>V4L2_MEMORY_DMABUF</constant> or <constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory" /></entry> </row> diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml new file mode 100644 index 00000000000..72dfbd20a80 --- /dev/null +++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml @@ -0,0 +1,212 @@ +<refentry id="vidioc-expbuf"> + + <refmeta> + <refentrytitle>ioctl VIDIOC_EXPBUF</refentrytitle> + &manvol; + </refmeta> + + <refnamediv> + <refname>VIDIOC_EXPBUF</refname> + <refpurpose>Export a buffer as a DMABUF file descriptor.</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <funcsynopsis> + <funcprototype> + <funcdef>int <function>ioctl</function></funcdef> + <paramdef>int <parameter>fd</parameter></paramdef> + <paramdef>int <parameter>request</parameter></paramdef> + <paramdef>struct v4l2_exportbuffer *<parameter>argp</parameter></paramdef> + </funcprototype> + </funcsynopsis> + </refsynopsisdiv> + + <refsect1> + <title>Arguments</title> + + <variablelist> + <varlistentry> + <term><parameter>fd</parameter></term> + <listitem> + <para>&fd;</para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>request</parameter></term> + <listitem> + <para>VIDIOC_EXPBUF</para> + </listitem> + </varlistentry> + <varlistentry> + <term><parameter>argp</parameter></term> + <listitem> + <para></para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> + <title>Description</title> + + <note> + <title>Experimental</title> + <para>This is an <link linkend="experimental"> experimental </link> + interface and may change in the future.</para> + </note> + +<para>This ioctl is an extension to the <link linkend="mmap">memory +mapping</link> I/O method, therefore it is available only for +<constant>V4L2_MEMORY_MMAP</constant> buffers. It can be used to export a +buffer as a DMABUF file at any time after buffers have been allocated with the +&VIDIOC-REQBUFS; ioctl.</para> + +<para> To export a buffer, applications fill &v4l2-exportbuffer;. The +<structfield> type </structfield> field is set to the same buffer type as was +previously used with &v4l2-requestbuffers;<structfield> type </structfield>. +Applications must also set the <structfield> index </structfield> field. Valid +index numbers range from zero to the number of buffers allocated with +&VIDIOC-REQBUFS; (&v4l2-requestbuffers;<structfield> count </structfield>) +minus one. For the multi-planar API, applications set the <structfield> plane +</structfield> field to the index of the plane to be exported. Valid planes +range from zero to the maximal number of valid planes for the currently active +format. For the single-planar API, applications must set <structfield> plane +</structfield> to zero. Additional flags may be posted in the <structfield> +flags </structfield> field. Refer to a manual for open() for details. +Currently only O_CLOEXEC is supported. All other fields must be set to zero. +In the case of multi-planar API, every plane is exported separately using +multiple <constant> VIDIOC_EXPBUF </constant> calls. </para> + +<para> After calling <constant>VIDIOC_EXPBUF</constant> the <structfield> fd +</structfield> field will be set by a driver. This is a DMABUF file +descriptor. The application may pass it to other DMABUF-aware devices. Refer to +<link linkend="dmabuf">DMABUF importing</link> for details about importing +DMABUF files into V4L2 nodes. It is recommended to close a DMABUF file when it +is no longer used to allow the associated memory to be reclaimed. </para> + + </refsect1> + <refsect1> + <section> + <title>Examples</title> + + <example> + <title>Exporting a buffer.</title> + <programlisting> +int buffer_export(int v4lfd, &v4l2-buf-type; bt, int index, int *dmafd) +{ + &v4l2-exportbuffer; expbuf; + + memset(&expbuf, 0, sizeof(expbuf)); + expbuf.type = bt; + expbuf.index = index; + if (ioctl(v4lfd, &VIDIOC-EXPBUF;, &expbuf) == -1) { + perror("VIDIOC_EXPBUF"); + return -1; + } + + *dmafd = expbuf.fd; + + return 0; +} + </programlisting> + </example> + + <example> + <title>Exporting a buffer using the multi-planar API.</title> + <programlisting> +int buffer_export_mp(int v4lfd, &v4l2-buf-type; bt, int index, + int dmafd[], int n_planes) +{ + int i; + + for (i = 0; i < n_planes; ++i) { + &v4l2-exportbuffer; expbuf; + + memset(&expbuf, 0, sizeof(expbuf)); + expbuf.type = bt; + expbuf.index = index; + expbuf.plane = i; + if (ioctl(v4lfd, &VIDIOC-EXPBUF;, &expbuf) == -1) { + perror("VIDIOC_EXPBUF"); + while (i) + close(dmafd[--i]); + return -1; + } + dmafd[i] = expbuf.fd; + } + + return 0; +} + </programlisting> + </example> + </section> + </refsect1> + + <refsect1> + <table pgwide="1" frame="none" id="v4l2-exportbuffer"> + <title>struct <structname>v4l2_exportbuffer</structname></title> + <tgroup cols="3"> + &cs-str; + <tbody valign="top"> + <row> + <entry>__u32</entry> + <entry><structfield>type</structfield></entry> + <entry>Type of the buffer, same as &v4l2-format; +<structfield>type</structfield> or &v4l2-requestbuffers; +<structfield>type</structfield>, set by the application. See <xref +linkend="v4l2-buf-type" /></entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>index</structfield></entry> + <entry>Number of the buffer, set by the application. This field is +only used for <link linkend="mmap">memory mapping</link> I/O and can range from +zero to the number of buffers allocated with the &VIDIOC-REQBUFS; and/or +&VIDIOC-CREATE-BUFS; ioctls. </entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>plane</structfield></entry> + <entry>Index of the plane to be exported when using the +multi-planar API. Otherwise this value must be set to zero. </entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>flags</structfield></entry> + <entry>Flags for the newly created file, currently only <constant> +O_CLOEXEC </constant> is supported, refer to the manual of open() for more +details.</entry> + </row> + <row> + <entry>__s32</entry> + <entry><structfield>fd</structfield></entry> + <entry>The DMABUF file descriptor associated with a buffer. Set by + the driver.</entry> + </row> + <row> + <entry>__u32</entry> + <entry><structfield>reserved[11]</structfield></entry> + <entry>Reserved field for future use. Must be set to zero.</entry> + </row> + </tbody> + </tgroup> + </table> + + </refsect1> + + <refsect1> + &return-value; + <variablelist> + <varlistentry> + <term><errorcode>EINVAL</errorcode></term> + <listitem> + <para>A queue is not in MMAP mode or DMABUF exporting is not +supported or <structfield> flags </structfield> or <structfield> type +</structfield> or <structfield> index </structfield> or <structfield> plane +</structfield> fields are invalid.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + +</refentry> diff --git a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml index 2d37abefce1..3504a7f2f38 100644 --- a/Documentation/DocBook/media/v4l/vidioc-qbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-qbuf.xml @@ -109,6 +109,23 @@ they cannot be swapped out to disk. Buffers remain locked until dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is called, or until the device is closed.</para> + <para>To enqueue a <link linkend="dmabuf">DMABUF</link> buffer applications +set the <structfield>memory</structfield> field to +<constant>V4L2_MEMORY_DMABUF</constant> and the <structfield>m.fd</structfield> +field to a file descriptor associated with a DMABUF buffer. When the +multi-planar API is used the <structfield>m.fd</structfield> fields of the +passed array of &v4l2-plane; have to be used instead. When +<constant>VIDIOC_QBUF</constant> is called with a pointer to this structure the +driver sets the <constant>V4L2_BUF_FLAG_QUEUED</constant> flag and clears the +<constant>V4L2_BUF_FLAG_MAPPED</constant> and +<constant>V4L2_BUF_FLAG_DONE</constant> flags in the +<structfield>flags</structfield> field, or it returns an error code. This +ioctl locks the buffer. Locking a buffer means passing it to a driver for a +hardware access (usually DMA). If an application accesses (reads/writes) a +locked buffer then the result is undefined. Buffers remain locked until +dequeued, until the &VIDIOC-STREAMOFF; or &VIDIOC-REQBUFS; ioctl is called, or +until the device is closed.</para> + <para>Applications call the <constant>VIDIOC_DQBUF</constant> ioctl to dequeue a filled (capturing) or displayed (output) buffer from the driver's outgoing queue. They just set the diff --git a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml index 2b50ef2007f..78a06a9a5ec 100644 --- a/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml +++ b/Documentation/DocBook/media/v4l/vidioc-reqbufs.xml @@ -48,28 +48,30 @@ <refsect1> <title>Description</title> - <para>This ioctl is used to initiate <link linkend="mmap">memory -mapped</link> or <link linkend="userp">user pointer</link> -I/O. Memory mapped buffers are located in device memory and must be -allocated with this ioctl before they can be mapped into the -application's address space. User buffers are allocated by -applications themselves, and this ioctl is merely used to switch the -driver into user pointer I/O mode and to setup some internal structures.</para> +<para>This ioctl is used to initiate <link linkend="mmap">memory mapped</link>, +<link linkend="userp">user pointer</link> or <link +linkend="dmabuf">DMABUF</link> based I/O. Memory mapped buffers are located in +device memory and must be allocated with this ioctl before they can be mapped +into the application's address space. User buffers are allocated by +applications themselves, and this ioctl is merely used to switch the driver +into user pointer I/O mode and to setup some internal structures. +Similarly, DMABUF buffers are allocated by applications through a device +driver, and this ioctl only configures the driver into DMABUF I/O mode without +performing any direct allocation.</para> - <para>To allocate device buffers applications initialize all -fields of the <structname>v4l2_requestbuffers</structname> structure. -They set the <structfield>type</structfield> field to the respective -stream or buffer type, the <structfield>count</structfield> field to -the desired number of buffers, <structfield>memory</structfield> -must be set to the requested I/O method and the <structfield>reserved</structfield> array -must be zeroed. When the ioctl -is called with a pointer to this structure the driver will attempt to allocate -the requested number of buffers and it stores the actual number -allocated in the <structfield>count</structfield> field. It can be -smaller than the number requested, even zero, when the driver runs out -of free memory. A larger number is also possible when the driver requires -more buffers to function correctly. For example video output requires at least two buffers, -one displayed and one filled by the application.</para> + <para>To allocate device buffers applications initialize all fields of the +<structname>v4l2_requestbuffers</structname> structure. They set the +<structfield>type</structfield> field to the respective stream or buffer type, +the <structfield>count</structfield> field to the desired number of buffers, +<structfield>memory</structfield> must be set to the requested I/O method and +the <structfield>reserved</structfield> array must be zeroed. When the ioctl is +called with a pointer to this structure the driver will attempt to allocate the +requested number of buffers and it stores the actual number allocated in the +<structfield>count</structfield> field. It can be smaller than the number +requested, even zero, when the driver runs out of free memory. A larger number +is also possible when the driver requires more buffers to function correctly. +For example video output requires at least two buffers, one displayed and one +filled by the application.</para> <para>When the I/O method is not supported the ioctl returns an &EINVAL;.</para> @@ -102,7 +104,8 @@ as the &v4l2-format; <structfield>type</structfield> field. See <xref <entry>__u32</entry> <entry><structfield>memory</structfield></entry> <entry>Applications set this field to -<constant>V4L2_MEMORY_MMAP</constant> or +<constant>V4L2_MEMORY_MMAP</constant>, +<constant>V4L2_MEMORY_DMABUF</constant> or <constant>V4L2_MEMORY_USERPTR</constant>. See <xref linkend="v4l2-memory" />.</entry> </row> diff --git a/MAINTAINERS b/MAINTAINERS index 63b140583e2..a6be3e864b5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -337,6 +337,13 @@ W: http://wireless.kernel.org/ S: Orphan F: drivers/net/wireless/adm8211.* +ADP1653 FLASH CONTROLLER DRIVER +M: Sakari Ailus <sakari.ailus@iki.fi> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/adp1653.c +F: include/media/adp1653.h + ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501) M: Michael Hennerich <michael.hennerich@analog.com> L: device-drivers-devel@blackfin.uclinux.org @@ -1494,6 +1501,14 @@ F: include/linux/ax25.h F: include/net/ax25.h F: net/ax25/ +AZ6007 DVB DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/usb/dvb-usb-v2/az6007.c + B43 WIRELESS DRIVER M: Stefano Brivio <stefano.brivio@polimi.it> L: linux-wireless@vger.kernel.org @@ -1745,11 +1760,11 @@ F: Documentation/filesystems/btrfs.txt F: fs/btrfs/ BTTV VIDEO4LINUX DRIVER -M: Mauro Carvalho Chehab <mchehab@infradead.org> +M: Mauro Carvalho Chehab <mchehab@redhat.com> L: linux-media@vger.kernel.org W: http://linuxtv.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git -S: Maintained +T: git git://linuxtv.org/media_tree.git +S: Odd fixes F: Documentation/video4linux/bttv/ F: drivers/media/pci/bt8xx/bttv* @@ -1778,7 +1793,7 @@ F: fs/cachefiles/ CAFE CMOS INTEGRATED CAMERA CONTROLLER DRIVER M: Jonathan Corbet <corbet@lwn.net> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: Documentation/video4linux/cafe_ccic F: drivers/media/platform/marvell-ccic/ @@ -2164,12 +2179,22 @@ CX18 VIDEO4LINUX DRIVER M: Andy Walls <awalls@md.metrocast.net> L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git W: http://linuxtv.org W: http://www.ivtvdriver.org/index.php/Cx18 S: Maintained F: Documentation/video4linux/cx18.txt F: drivers/media/pci/cx18/ +F: include/uapi/linux/ivtv* + +CX88 VIDEO4LINUX DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: Documentation/video4linux/cx88/ +F: drivers/media/pci/cx88/ CXD2820R MEDIA DRIVER M: Antti Palosaari <crope@iki.fi> @@ -2856,6 +2881,14 @@ L: netdev@vger.kernel.org S: Maintained F: drivers/net/ethernet/ibm/ehea/ +EM28XX VIDEO4LINUX DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/usb/em28xx/ + EMBEDDED LINUX M: Paul Gortmaker <paul.gortmaker@windriver.com> M: Matt Mackall <mpm@selenic.com> @@ -3054,6 +3087,14 @@ T: git git://git.alsa-project.org/alsa-kernel.git S: Maintained F: sound/firewire/ +FIREWIRE MEDIA DRIVERS (firedtv) +M: Stefan Richter <stefanr@s5r6.in-berlin.de> +L: linux-media@vger.kernel.org +L: linux1394-devel@lists.sourceforge.net +T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +S: Maintained +F: drivers/media/firewire/ + FIREWIRE SBP-2 TARGET M: Chris Boot <bootc@bootc.net> L: linux-scsi@vger.kernel.org @@ -3340,56 +3381,56 @@ F: drivers/net/ethernet/aeroflex/ GSPCA FINEPIX SUBDRIVER M: Frank Zago <frank@zago.net> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/finepix.c GSPCA GL860 SUBDRIVER M: Olivier Lorin <o.lorin@laposte.net> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/gl860/ GSPCA M5602 SUBDRIVER M: Erik Andren <erik.andren@gmail.com> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/m5602/ GSPCA PAC207 SONIXB SUBDRIVER M: Hans de Goede <hdegoede@redhat.com> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/pac207.c GSPCA SN9C20X SUBDRIVER M: Brian Johnson <brijohn@gmail.com> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/sn9c20x.c GSPCA T613 SUBDRIVER M: Leandro Costantino <lcostantino@gmail.com> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/t613.c GSPCA USB WEBCAM DRIVER M: Hans de Goede <hdegoede@redhat.com> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/gspca/ STK1160 USB VIDEO CAPTURE DRIVER M: Ezequiel Garcia <elezegarcia@gmail.com> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/usb/stk1160/ @@ -3787,6 +3828,12 @@ F: net/ieee802154/ F: net/mac802154/ F: drivers/ieee802154/ +IGUANAWORKS USB IR TRANSCEIVER +M: Sean Young <sean@mess.org> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/rc/iguanair.c + IIO SUBSYSTEM AND DRIVERS M: Jonathan Cameron <jic23@cam.ac.uk> L: linux-iio@vger.kernel.org @@ -4172,17 +4219,41 @@ S: Maintained F: Documentation/hwmon/it87 F: drivers/hwmon/it87.c +IT913X MEDIA DRIVER +M: Malcolm Priestley <tvboxspy@gmail.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/usb/dvb-usb-v2/it913x* + +IT913X FE MEDIA DRIVER +M: Malcolm Priestley <tvboxspy@gmail.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/dvb-frontends/it913x-fe* + IVTV VIDEO4LINUX DRIVER M: Andy Walls <awalls@md.metrocast.net> L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers) L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git W: http://www.ivtvdriver.org S: Maintained F: Documentation/video4linux/*.ivtv F: drivers/media/pci/ivtv/ F: include/linux/ivtv* +IX2505V MEDIA DRIVER +M: Malcolm Priestley <tvboxspy@gmail.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/dvb-frontends/ix2505v* + JC42.4 TEMPERATURE SENSOR DRIVER M: Guenter Roeck <linux@roeck-us.net> L: lm-sensors@lm-sensors.org @@ -4628,6 +4699,14 @@ S: Maintained F: Documentation/hwmon/lm90 F: drivers/hwmon/lm90.c +LME2510 MEDIA DRIVER +M: Malcolm Priestley <tvboxspy@gmail.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/usb/dvb-usb-v2/lmedm04* + LOCKDEP AND LOCKSTAT M: Peter Zijlstra <peterz@infradead.org> M: Ingo Molnar <mingo@redhat.com> @@ -4721,6 +4800,14 @@ W: http://www.tazenda.demon.co.uk/phil/linux-hp S: Maintained F: arch/m68k/hp300/ +M88RS2000 MEDIA DRIVER +M: Malcolm Priestley <tvboxspy@gmail.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +S: Maintained +F: drivers/media/dvb-frontends/m88rs2000* + MAC80211 M: Johannes Berg <johannes@sipsolutions.net> L: linux-wireless@vger.kernel.org @@ -4813,12 +4900,12 @@ F: Documentation/hwmon/max6650 F: drivers/hwmon/max6650.c MEDIA INPUT INFRASTRUCTURE (V4L/DVB) -M: Mauro Carvalho Chehab <mchehab@infradead.org> +M: Mauro Carvalho Chehab <mchehab@redhat.com> P: LinuxTV.org Project L: linux-media@vger.kernel.org W: http://linuxtv.org Q: http://patchwork.kernel.org/project/linux-media/list/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: Documentation/dvb/ F: Documentation/video4linux/ @@ -4826,8 +4913,13 @@ F: Documentation/DocBook/media/ F: drivers/media/ F: drivers/staging/media/ F: include/media/ -F: include/linux/dvb/ -F: include/linux/videodev*.h +F: include/uapi/linux/dvb/ +F: include/uapi/linux/videodev2.h +F: include/uapi/linux/media.h +F: include/uapi/linux/v4l2-* +F: include/uapi/linux/meye.h +F: include/uapi/linux/ivtv* +F: include/uapi/linux/uvcvideo.h MEGARAID SCSI DRIVERS M: Neela Syam Kolli <megaraidlinux@lsi.com> @@ -4909,7 +5001,7 @@ W: http://popies.net/meye/ S: Orphan F: Documentation/video4linux/meye.txt F: drivers/media/pci/meye/ -F: include/linux/meye.h +F: include/uapi/linux/meye.h MOTOROLA IMX MMC/SD HOST CONTROLLER INTERFACE DRIVER M: Pavel Pisa <ppisa@pikron.com> @@ -4923,6 +5015,13 @@ S: Maintained F: Documentation/serial/moxa-smartio F: drivers/tty/mxser.* +MR800 AVERMEDIA USB FM RADIO DRIVER +M: Alexey Klimov <klimov.linux@gmail.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/radio/radio-mr800.c + MSI LAPTOP SUPPORT M: "Lee, Chun-Yi" <jlee@novell.com> L: platform-driver-x86@vger.kernel.org @@ -5385,7 +5484,7 @@ F: drivers/char/pcmcia/cm4040_cs.* OMNIVISION OV7670 SENSOR DRIVER M: Jonathan Corbet <corbet@lwn.net> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: drivers/media/i2c/ov7670.c @@ -5934,11 +6033,18 @@ M: Mike Isely <isely@pobox.com> L: pvrusb2@isely.net (subscribers-only) L: linux-media@vger.kernel.org W: http://www.isely.net/pvrusb2/ -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: Documentation/video4linux/README.pvrusb2 F: drivers/media/usb/pvrusb2/ +PWC WEBCAM DRIVER +M: Hans de Goede <hdegoede@redhat.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/usb/pwc/* + PWM SUBSYSTEM M: Thierry Reding <thierry.reding@avionic-design.de> L: linux-kernel@vger.kernel.org @@ -6081,6 +6187,21 @@ S: Maintained F: drivers/video/aty/radeon* F: include/linux/radeonfb.h +RADIOSHARK RADIO DRIVER +M: Hans de Goede <hdegoede@redhat.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/radio/radio-shark.c + +RADIOSHARK2 RADIO DRIVER +M: Hans de Goede <hdegoede@redhat.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/radio/radio-shark2.c +F: drivers/media/radio/radio-tea5777.c + RAGE128 FRAMEBUFFER DISPLAY DRIVER M: Paul Mackerras <paulus@samba.org> L: linux-fbdev@vger.kernel.org @@ -6321,10 +6442,19 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported F: drivers/mmc/host/s3cmci.* +SAA7134 VIDEO4LINUX DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: Documentation/video4linux/saa7134/ +F: drivers/media/pci/saa7134/ + SAA7146 VIDEO4LINUX-2 DRIVER M: Michael Hunold <michael@mihu.de> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git W: http://www.mihu.de/linux/saa7146 S: Maintained F: drivers/media/common/saa7146/ @@ -6359,6 +6489,14 @@ F: drivers/regulator/s5m*.c F: drivers/rtc/rtc-sec.c F: include/linux/mfd/samsung/ +SAMSUNG S3C24XX/S3C64XX SOC SERIES CAMIF DRIVER +M: Sylwester Nawrocki <sylvester.nawrocki@gmail.com> +L: linux-media@vger.kernel.org +L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) +S: Maintained +F: drivers/media/platform/s3c-camif/ +F: include/media/s3c_camif.h + SERIAL DRIVERS M: Alan Cox <alan@linux.intel.com> L: linux-serial@vger.kernel.org @@ -6653,6 +6791,18 @@ S: Supported F: arch/arm/mach-davinci F: drivers/i2c/busses/i2c-davinci.c +TI DAVINCI SERIES MEDIA DRIVER +M: Manjunath Hadli <manjunath.hadli@ti.com> +M: Prabhakar Lad <prabhakar.lad@ti.com> +L: linux-media@vger.kernel.org +L: davinci-linux-open-source@linux.davincidsp.com (moderated for non-subscribers) +W: http://linuxtv.org/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/mhadli/v4l-dvb-davinci_devices.git +S: Supported +F: drivers/media/platform/davinci/ +F: include/media/davinci/ + SIS 190 ETHERNET DRIVER M: Francois Romieu <romieu@fr.zoreil.com> L: netdev@vger.kernel.org @@ -6719,6 +6869,15 @@ M: Nicolas Pitre <nico@fluxnic.net> S: Odd Fixes F: drivers/net/ethernet/smsc/smc91x.* +SMIA AND SMIA++ IMAGE SENSOR DRIVER +M: Sakari Ailus <sakari.ailus@iki.fi> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/smiapp +F: include/media/smiapp.h +F: drivers/media/i2c/smiapp-pll.c +F: drivers/media/i2c/smiapp-pll.h + SMM665 HARDWARE MONITOR DRIVER M: Guenter Roeck <linux@roeck-us.net> L: lm-sensors@lm-sensors.org @@ -6777,7 +6936,7 @@ F: arch/ia64/sn/ SOC-CAMERA V4L2 SUBSYSTEM M: Guennadi Liakhovetski <g.liakhovetski@gmx.de> L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git S: Maintained F: include/media/soc* F: drivers/media/i2c/soc_camera/ @@ -7267,6 +7426,22 @@ T: git git://linuxtv.org/mkrufky/tuners.git S: Maintained F: drivers/media/tuners/tda8290.* +TEA5761 TUNER DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: drivers/media/tuners/tea5761.* + +TEA5767 TUNER DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/tuners/tea5767.* + TEAM DRIVER M: Jiri Pirko <jpirko@redhat.com> L: netdev@vger.kernel.org @@ -7274,6 +7449,12 @@ S: Supported F: drivers/net/team/ F: include/linux/if_team.h +TECHNOTREND USB IR RECEIVER +M: Sean Young <sean@mess.org> +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/rc/ttusbir.c + TEGRA SUPPORT M: Stephen Warren <swarren@wwwdotorg.org> L: linux-tegra@vger.kernel.org @@ -7426,6 +7607,14 @@ S: Maintained F: include/linux/shmem_fs.h F: mm/shmem.c +TM6000 VIDEO4LINUX DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Odd fixes +F: drivers/media/usb/tm6000/ + TPM DEVICE DRIVER M: Kent Yoder <key@linux.vnet.ibm.com> M: Rajiv Andrade <mail@srajiv.net> @@ -7820,7 +8009,7 @@ USB SN9C1xx DRIVER M: Luca Risolia <luca.risolia@studio.unibo.it> L: linux-usb@vger.kernel.org L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git W: http://www.linux-projects.org S: Maintained F: Documentation/video4linux/sn9c102.txt @@ -7856,10 +8045,11 @@ USB VIDEO CLASS M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> L: linux-uvc-devel@lists.sourceforge.net (subscribers-only) L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git W: http://www.ideasonboard.org/uvc/ S: Maintained F: drivers/media/usb/uvc/ +F: include/uapi/linux/uvcvideo.h USB WEBCAM GADGET M: Laurent Pinchart <laurent.pinchart@ideasonboard.com> @@ -7891,7 +8081,7 @@ USB ZR364XX DRIVER M: Antoine Jacquet <royale@zerezo.com> L: linux-usb@vger.kernel.org L: linux-media@vger.kernel.org -T: git git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media.git +T: git git://linuxtv.org/media_tree.git W: http://royale.zerezo.com/zr364xx/ S: Maintained F: Documentation/video4linux/zr364xx.txt @@ -8246,6 +8436,14 @@ L: linux-edac@vger.kernel.org S: Maintained F: arch/x86/kernel/cpu/mcheck/* +XC2028/3028 TUNER DRIVER +M: Mauro Carvalho Chehab <mchehab@redhat.com> +L: linux-media@vger.kernel.org +W: http://linuxtv.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/tuners/tuner-xc2028.* + XEN HYPERVISOR INTERFACE M: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> M: Jeremy Fitzhardinge <jeremy@goop.org> diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index c67a731cfbb..4abb8b5e9bc 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -203,6 +203,16 @@ static struct resource omap3isp_resources[] = { .flags = IORESOURCE_MEM, }, { + .start = OMAP343X_CTRL_BASE + OMAP343X_CONTROL_CSIRXFE, + .end = OMAP343X_CTRL_BASE + OMAP343X_CONTROL_CSIRXFE + 3, + .flags = IORESOURCE_MEM, + }, + { + .start = OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL, + .end = OMAP343X_CTRL_BASE + OMAP3630_CONTROL_CAMERA_PHY_CTRL + 3, + .flags = IORESOURCE_MEM, + }, + { .start = 24 + OMAP_INTC_START, .flags = IORESOURCE_IRQ, } diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c index 113c57a0356..fb7f1d1627d 100644 --- a/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/arch/arm/mach-pxa/pcm990-baseboard.c @@ -26,6 +26,7 @@ #include <linux/i2c/pxa-i2c.h> #include <linux/pwm_backlight.h> +#include <media/mt9v022.h> #include <media/soc_camera.h> #include <linux/platform_data/camera-pxa.h> @@ -468,6 +469,10 @@ static struct i2c_board_info __initdata pcm990_i2c_devices[] = { }, }; +static struct mt9v022_platform_data mt9v022_pdata = { + .y_skip_top = 1, +}; + static struct i2c_board_info pcm990_camera_i2c[] = { { I2C_BOARD_INFO("mt9v022", 0x48), @@ -480,6 +485,7 @@ static struct soc_camera_link iclink[] = { { .bus_id = 0, /* Must match with the camera ID */ .board_info = &pcm990_camera_i2c[0], + .priv = &mt9v022_pdata, .i2c_adapter_id = 0, .query_bus_param = pcm990_camera_query_bus_param, .set_bus_param = pcm990_camera_set_bus_param, diff --git a/drivers/base/dma-mapping.c b/drivers/base/dma-mapping.c index 3fbedc75e7c..0ce39a33b3c 100644 --- a/drivers/base/dma-mapping.c +++ b/drivers/base/dma-mapping.c @@ -218,6 +218,8 @@ void dmam_release_declared_memory(struct device *dev) } EXPORT_SYMBOL(dmam_release_declared_memory); +#endif + /* * Create scatter-list for the already allocated DMA buffer. */ @@ -236,8 +238,6 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, } EXPORT_SYMBOL(dma_common_get_sgtable); -#endif - /* * Create userspace mapping for the DMA-coherent memory. */ diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c index 13ca9191b63..a79e95bb9fb 100644 --- a/drivers/hid/hid-picolcd_cir.c +++ b/drivers/hid/hid-picolcd_cir.c @@ -116,7 +116,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report) rdev->priv = data; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; + rdev->allowed_protos = RC_BIT_ALL; rdev->open = picolcd_cir_open; rdev->close = picolcd_cir_close; rdev->input_name = data->hdev->name; diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 121b0110af3..d2a436ce77f 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -1,3 +1,10 @@ +# Used by common drivers, when they need to ask questions +config MEDIA_COMMON_OPTIONS + bool + +comment "common driver options" + depends on MEDIA_COMMON_OPTIONS + source "drivers/media/common/b2c2/Kconfig" source "drivers/media/common/saa7146/Kconfig" source "drivers/media/common/siano/Kconfig" diff --git a/drivers/media/common/b2c2/Kconfig b/drivers/media/common/b2c2/Kconfig index 1df9e578daa..a8c6cdfaa2f 100644 --- a/drivers/media/common/b2c2/Kconfig +++ b/drivers/media/common/b2c2/Kconfig @@ -17,11 +17,6 @@ config DVB_B2C2_FLEXCOP select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the digital TV receiver chip made by B2C2 Inc. included in - Technisats PCI cards and USB boxes. - - Say Y if you own such a device and want to use it. # Selected via the PCI or USB flexcop drivers config DVB_B2C2_FLEXCOP_DEBUG diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig index 425aeadfb49..68f0f604678 100644 --- a/drivers/media/common/siano/Kconfig +++ b/drivers/media/common/siano/Kconfig @@ -4,14 +4,16 @@ config SMS_SIANO_MDTV tristate - depends on DVB_CORE && RC_CORE && HAS_DMA + depends on DVB_CORE && HAS_DMA + depends on !RC_CORE || RC_CORE depends on SMS_USB_DRV || SMS_SDIO_DRV default y - ---help--- - Choose Y or M here if you have MDTV receiver with a Siano chipset. - - To compile this driver as a module, choose M here - (The module will be called smsmdtv). - Further documentation on this driver can be found on the WWW - at http://www.siano-ms.com/ +config SMS_SIANO_RC + bool "Enable Remote Controller support for Siano devices" + depends on SMS_SIANO_MDTV && RC_CORE + depends on SMS_USB_DRV || SMS_SDIO_DRV + depends on MEDIA_COMMON_OPTIONS + default y + ---help--- + Choose Y to select Remote Controller support for Siano driver. diff --git a/drivers/media/common/siano/Makefile b/drivers/media/common/siano/Makefile index 2a09279e064..81b1e985bea 100644 --- a/drivers/media/common/siano/Makefile +++ b/drivers/media/common/siano/Makefile @@ -1,7 +1,11 @@ -smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o smsir.o +smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o +ifeq ($(CONFIG_SMS_SIANO_RC),y) + smsmdtv-objs += smsir.o +endif + ccflags-y += -Idrivers/media/dvb-core ccflags-y += $(extra-cflags-y) $(extra-cflags-m) diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 9cc55546cc3..1842e64e633 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -1092,7 +1092,7 @@ EXPORT_SYMBOL_GPL(smscore_onresponse); * @return pointer to descriptor on success, NULL on error. */ -struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) +static struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev) { struct smscore_buffer_t *cb = NULL; unsigned long flags; diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c index 37bc5c4b8ad..b8c5cad7853 100644 --- a/drivers/media/common/siano/smsir.c +++ b/drivers/media/common/siano/smsir.c @@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev) dev->priv = coredev; dev->driver_type = RC_DRIVER_IR_RAW; - dev->allowed_protos = RC_TYPE_ALL; + dev->allowed_protos = RC_BIT_ALL; dev->map_name = sms_get_board(board_id)->rc_codes; dev->driver_name = MODULE_NAME; diff --git a/drivers/media/common/siano/smsir.h b/drivers/media/common/siano/smsir.h index ae92b3a8587..69b59b9eee2 100644 --- a/drivers/media/common/siano/smsir.h +++ b/drivers/media/common/siano/smsir.h @@ -46,10 +46,19 @@ struct ir_t { u32 controller; }; +#ifdef CONFIG_SMS_SIANO_RC int sms_ir_init(struct smscore_device_t *coredev); void sms_ir_exit(struct smscore_device_t *coredev); void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len); +#else +inline static int sms_ir_init(struct smscore_device_t *coredev) { + return 0; +} +inline static void sms_ir_exit(struct smscore_device_t *coredev) {}; +inline static void sms_ir_event(struct smscore_device_t *coredev, + const char *buf, int len) {}; +#endif #endif /* __SMS_IR_H__ */ diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 889c9c16c6d..d81dbb22aa8 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -877,7 +877,7 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter); - if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) + if ((unsigned)params->pes_type > DMX_PES_OTHER) return -EINVAL; dmxdevfilter->type = DMXDEV_TYPE_PES; diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h index 02ebe28f830..48c6cf92ab9 100644 --- a/drivers/media/dvb-core/dmxdev.h +++ b/drivers/media/dvb-core/dmxdev.h @@ -26,6 +26,7 @@ #include <linux/types.h> #include <linux/spinlock.h> #include <linux/kernel.h> +#include <linux/time.h> #include <linux/timer.h> #include <linux/wait.h> #include <linux/fs.h> diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 58e0220447c..388c2eb4d74 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -250,6 +250,7 @@ #define USB_PID_TERRATEC_T3 0x10a0 #define USB_PID_TERRATEC_T5 0x10a1 #define USB_PID_NOXON_DAB_STICK 0x00b3 +#define USB_PID_NOXON_DAB_STICK_REV2 0x00e0 #define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e #define USB_PID_PINNACLE_PCTV2000E 0x022c #define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228 diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 7e92793260f..49d95040096 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1029,12 +1029,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { /* Get */ _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1), _DTV_CMD(DTV_API_VERSION, 0, 0), - _DTV_CMD(DTV_CODE_RATE_HP, 0, 0), - _DTV_CMD(DTV_CODE_RATE_LP, 0, 0), - _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), - _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), - _DTV_CMD(DTV_HIERARCHY, 0, 0), - _DTV_CMD(DTV_INTERLEAVING, 0, 0), _DTV_CMD(DTV_ENUM_DELSYS, 0, 0), @@ -1042,13 +1036,11 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0), _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0), - _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0), _DTV_CMD(DTV_ATSCMH_NOG, 0, 0), _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0), _DTV_CMD(DTV_ATSCMH_SGN, 0, 0), _DTV_CMD(DTV_ATSCMH_PRC, 0, 0), _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0), - _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0), _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0), _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0), @@ -1056,8 +1048,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0), _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0), - - _DTV_CMD(DTV_LNA, 0, 0), }; static void dtv_property_dump(struct dvb_frontend *fe, struct dtv_property *tvp) diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c index f2a90f990ce..3d399d9a634 100644 --- a/drivers/media/dvb-frontends/cx22700.c +++ b/drivers/media/dvb-frontends/cx22700.c @@ -139,7 +139,7 @@ static int cx22700_set_tps(struct cx22700_state *state, if (p->code_rate_HP == FEC_4_5 || p->code_rate_LP == FEC_4_5) return -EINVAL; - if (p->guard_interval < GUARD_INTERVAL_1_32 || + if ((int)p->guard_interval < GUARD_INTERVAL_1_32 || p->guard_interval > GUARD_INTERVAL_1_4) return -EINVAL; @@ -152,7 +152,7 @@ static int cx22700_set_tps(struct cx22700_state *state, p->modulation != QAM_64) return -EINVAL; - if (p->hierarchy < HIERARCHY_NONE || + if ((int)p->hierarchy < HIERARCHY_NONE || p->hierarchy > HIERARCHY_4) return -EINVAL; diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index 7e28b4ee7d4..68c88ab58e7 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -338,7 +338,7 @@ static int cx24123_set_fec(struct cx24123_state *state, fe_code_rate_t fec) { u8 nom_reg = cx24123_readreg(state, 0x0e) & ~0x07; - if ((fec < FEC_NONE) || (fec > FEC_AUTO)) + if (((int)fec < FEC_NONE) || (fec > FEC_AUTO)) fec = FEC_AUTO; /* Set the soft decision threshold */ diff --git a/drivers/media/dvb-frontends/dib9000.h b/drivers/media/dvb-frontends/dib9000.h index b5781a48034..de1cc91fd83 100644 --- a/drivers/media/dvb-frontends/dib9000.h +++ b/drivers/media/dvb-frontends/dib9000.h @@ -97,7 +97,7 @@ static inline int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb return -ENODEV; } -int dib9000_remove_slave_frontend(struct dvb_frontend *fe) +static inline int dib9000_remove_slave_frontend(struct dvb_frontend *fe) { printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return -ENODEV; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 6d9853750d2..e71cc60851e 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -1748,7 +1748,8 @@ static int DRX_Stop(struct drxd_state *state) return status; } -int SetOperationMode(struct drxd_state *state, int oMode) +#if 0 /* Currently unused */ +static int SetOperationMode(struct drxd_state *state, int oMode) { int status; @@ -1788,6 +1789,7 @@ int SetOperationMode(struct drxd_state *state, int oMode) state->operation_mode = oMode; return status; } +#endif static int StartDiversity(struct drxd_state *state) { @@ -2612,7 +2614,7 @@ static int CDRXD(struct drxd_state *state, u32 IntermediateFrequency) return 0; } -int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size) +static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size) { int status = 0; u32 driverVersion; @@ -2774,7 +2776,7 @@ int DRXD_init(struct drxd_state *state, const u8 * fw, u32 fw_size) return status; } -int DRXD_status(struct drxd_state *state, u32 * pLockStatus) +static int DRXD_status(struct drxd_state *state, u32 *pLockStatus) { DRX_GetLockStatus(state, pLockStatus); diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index df9abe83f87..c2fc7da0d6b 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -65,16 +65,6 @@ static bool IsQAM(struct drxk_state *state) state->m_OperationMode == OM_QAM_ITU_C; } -bool IsA1WithPatchCode(struct drxk_state *state) -{ - return state->m_DRXK_A1_PATCH_CODE; -} - -bool IsA1WithRomCode(struct drxk_state *state) -{ - return state->m_DRXK_A1_ROM_CODE; -} - #define NOA1ROM 0 #define DRXDAP_FASI_SHORT_FORMAT(addr) (((addr) & 0xFC30FF80) == 0) @@ -189,7 +179,7 @@ static inline u32 MulDiv32(u32 a, u32 b, u32 c) return (u32) tmp64; } -inline u32 Frac28a(u32 a, u32 c) +static inline u32 Frac28a(u32 a, u32 c) { int i = 0; u32 Q1 = 0; @@ -587,7 +577,7 @@ static int write_block(struct drxk_state *state, u32 Address, #define DRXK_MAX_RETRIES_POWERUP 20 #endif -int PowerUpDevice(struct drxk_state *state) +static int PowerUpDevice(struct drxk_state *state) { int status; u8 data = 0; @@ -720,11 +710,6 @@ static int init_state(struct drxk_state *state) state->m_bPowerDown = (ulPowerDown != 0); - state->m_DRXK_A1_PATCH_CODE = false; - state->m_DRXK_A1_ROM_CODE = false; - state->m_DRXK_A2_ROM_CODE = false; - state->m_DRXK_A3_ROM_CODE = false; - state->m_DRXK_A2_PATCH_CODE = false; state->m_DRXK_A3_PATCH_CODE = false; /* Init AGC and PGA parameters */ @@ -921,7 +906,7 @@ static int GetDeviceCapabilities(struct drxk_state *state) status = write16(state, SCU_RAM_GPIO__A, SCU_RAM_GPIO_HW_LOCK_IND_DISABLE); if (status < 0) goto error; - status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA); + status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY); if (status < 0) goto error; status = read16(state, SIO_PDR_OHW_CFG__A, &sioPdrOhwCfg); @@ -1217,7 +1202,7 @@ static int MPEGTSConfigurePins(struct drxk_state *state, bool mpegEnable) goto error; /* MPEG TS pad configuration */ - status = write16(state, SIO_TOP_COMM_KEY__A, 0xFABA); + status = write16(state, SIO_TOP_COMM_KEY__A, SIO_TOP_COMM_KEY_KEY); if (status < 0) goto error; @@ -5461,6 +5446,7 @@ static int QAMDemodulatorCommand(struct drxk_state *state, } else { printk(KERN_WARNING "drxk: Unknown QAM demodulator parameter " "count %d\n", numberOfParameters); + status = -EINVAL; } error: diff --git a/drivers/media/dvb-frontends/drxk_hard.h b/drivers/media/dvb-frontends/drxk_hard.h index 6bb9fc4a7b9..d18a896a983 100644 --- a/drivers/media/dvb-frontends/drxk_hard.h +++ b/drivers/media/dvb-frontends/drxk_hard.h @@ -320,11 +320,7 @@ struct drxk_state { u8 *m_microcode; int m_microcode_length; - bool m_DRXK_A1_PATCH_CODE; - bool m_DRXK_A1_ROM_CODE; - bool m_DRXK_A2_ROM_CODE; - bool m_DRXK_A3_ROM_CODE; - bool m_DRXK_A2_PATCH_CODE; + bool m_DRXK_A3_ROM_CODE; bool m_DRXK_A3_PATCH_CODE; bool m_rfmirror; diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 5b639087ce4..60a529e3833 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -30,7 +30,6 @@ #include "ds3000.h" static int debug; -static int force_fw_upload; #define dprintk(args...) \ do { \ @@ -234,7 +233,6 @@ struct ds3000_state { struct i2c_adapter *i2c; const struct ds3000_config *config; struct dvb_frontend frontend; - u8 skip_fw_load; /* previous uncorrected block counter for DVB-S2 */ u16 prevUCBS2; }; @@ -397,9 +395,6 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) if (ret < 0) return ret; - if (state->skip_fw_load || !force_fw_upload) - return 0; /* Firmware already uploaded, skipping */ - /* Load firmware */ /* request the firmware, this will block until someone uploads it */ printk(KERN_INFO "%s: Waiting for firmware upload (%s)...\n", __func__, @@ -413,9 +408,6 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) return ret; } - /* Make sure we don't recurse back through here during loading */ - state->skip_fw_load = 1; - ret = ds3000_load_firmware(fe, fw); if (ret) printk("%s: Writing firmware to device failed\n", __func__); @@ -425,9 +417,6 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) dprintk("%s: Firmware upload %s\n", __func__, ret == 0 ? "complete" : "failed"); - /* Ensure firmware is always loaded if required */ - state->skip_fw_load = 0; - return ret; } @@ -1309,10 +1298,8 @@ static struct dvb_frontend_ops ds3000_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); -module_param(force_fw_upload, int, 0644); -MODULE_PARM_DESC(force_fw_upload, "Force firmware upload (default:0)"); - MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " "DS3000/TS2020 hardware"); MODULE_AUTHOR("Konstantin Dimitrov"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE); diff --git a/drivers/media/dvb-frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c index 36fcf559e36..ddf866c46f8 100644 --- a/drivers/media/dvb-frontends/l64781.c +++ b/drivers/media/dvb-frontends/l64781.c @@ -180,11 +180,11 @@ static int apply_frontend_param(struct dvb_frontend *fe) p->transmission_mode != TRANSMISSION_MODE_8K) return -EINVAL; - if (p->guard_interval < GUARD_INTERVAL_1_32 || + if ((int)p->guard_interval < GUARD_INTERVAL_1_32 || p->guard_interval > GUARD_INTERVAL_1_4) return -EINVAL; - if (p->hierarchy < HIERARCHY_NONE || + if ((int)p->hierarchy < HIERARCHY_NONE || p->hierarchy > HIERARCHY_4) return -EINVAL; diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index e20bf13aa86..ec388c1d691 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -549,7 +549,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe) || (p->frequency > fe->ops.info.frequency_max)) return -EINVAL; - if ((p->inversion < INVERSION_OFF) + if (((int)p->inversion < INVERSION_OFF) || (p->inversion > INVERSION_ON)) return -EINVAL; @@ -557,7 +557,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe) || (p->symbol_rate > fe->ops.info.symbol_rate_max)) return -EINVAL; - if ((p->fec_inner < FEC_NONE) + if (((int)p->fec_inner < FEC_NONE) || (p->fec_inner > FEC_AUTO)) return -EINVAL; diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index b0f6ec03d1e..362d26d11e8 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -130,7 +130,7 @@ static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val) } /* write single register with mask */ -int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) +static int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) { int ret; u8 tmp; @@ -150,7 +150,7 @@ int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask) } /* read single register with mask */ -int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) +static int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask) { int ret, i; u8 tmp; @@ -256,7 +256,7 @@ static int rtl2830_sleep(struct dvb_frontend *fe) return 0; } -int rtl2830_get_tune_settings(struct dvb_frontend *fe, +static int rtl2830_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) { s->min_delay_ms = 500; diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 80c8e5f1182..73887690b04 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -265,7 +265,7 @@ static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val) return rtl2832_rd_regs(priv, reg, page, val, 1); } -int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val) +static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val) { int ret; @@ -305,7 +305,7 @@ err: } -int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val) +static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val) { int ret, i; u8 len; @@ -510,7 +510,7 @@ static int rtl2832_sleep(struct dvb_frontend *fe) return 0; } -int rtl2832_get_tune_settings(struct dvb_frontend *fe, +static int rtl2832_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s) { struct rtl2832_priv *priv = fe->demodulator_priv; diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index 79e29de87fb..cc278b3d6d5 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -1260,7 +1260,7 @@ static inline void CONVERT32(u32 x, char *str) *str = '\0'; } -int stb0899_get_dev_id(struct stb0899_state *state) +static int stb0899_get_dev_id(struct stb0899_state *state) { u8 chip_id, release; u16 id; diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 2a8aaeb1112..0c8e45949b1 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -879,7 +879,8 @@ static u8 stv0367_readbits(struct stv0367_state *state, u32 label) return val; } -u8 stv0367_getbits(u8 reg, u32 label) +#if 0 /* Currently, unused */ +static u8 stv0367_getbits(u8 reg, u32 label) { u8 mask, pos; @@ -887,7 +888,7 @@ u8 stv0367_getbits(u8 reg, u32 label) return (reg & mask) >> pos; } - +#endif static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable) { struct stv0367_state *state = fe->demodulator_priv; @@ -1263,8 +1264,8 @@ stv0367_ter_signal_type stv0367ter_check_cpamp(struct stv0367_state *state, return CPAMPStatus; } -enum -stv0367_ter_signal_type stv0367ter_lock_algo(struct stv0367_state *state) +static enum stv0367_ter_signal_type +stv0367ter_lock_algo(struct stv0367_state *state) { enum stv0367_ter_signal_type ret_flag; short int wd, tempo; @@ -1528,7 +1529,7 @@ static int stv0367ter_sleep(struct dvb_frontend *fe) return stv0367ter_standby(fe, 1); } -int stv0367ter_init(struct dvb_frontend *fe) +static int stv0367ter_init(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; @@ -2378,9 +2379,9 @@ static u32 stv0367cab_get_adc_freq(struct dvb_frontend *fe, u32 ExtClk_Hz) return ADCClk_Hz; } -enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state, - u32 SymbolRate, - enum stv0367cab_mod QAMSize) +static enum stv0367cab_mod stv0367cab_SetQamSize(struct stv0367_state *state, + u32 SymbolRate, + enum stv0367cab_mod QAMSize) { /* Set QAM size */ stv0367_writebits(state, F367CAB_QAM_MODE, QAMSize); @@ -2762,7 +2763,7 @@ static int stv0367cab_sleep(struct dvb_frontend *fe) return stv0367cab_standby(fe, 1); } -int stv0367cab_init(struct dvb_frontend *fe) +static int stv0367cab_init(struct dvb_frontend *fe) { struct stv0367_state *state = fe->demodulator_priv; struct stv0367cab_state *cab_state = state->cab_state; diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index a83bf680234..16a4bc54dbe 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -96,7 +96,8 @@ static int tda10071_rd_reg(struct tda10071_priv *priv, u8 reg, u8 *val) } /* write single register with mask */ -int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask) +static int tda10071_wr_reg_mask(struct tda10071_priv *priv, + u8 reg, u8 val, u8 mask) { int ret; u8 tmp; @@ -116,7 +117,8 @@ int tda10071_wr_reg_mask(struct tda10071_priv *priv, u8 reg, u8 val, u8 mask) } /* read single register with mask */ -int tda10071_rd_reg_mask(struct tda10071_priv *priv, u8 reg, u8 *val, u8 mask) +static int tda10071_rd_reg_mask(struct tda10071_priv *priv, + u8 reg, u8 *val, u8 mask) { int ret, i; u8 tmp; diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index ad7c72e8f51..d281f77d5c2 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -32,6 +32,7 @@ #include <asm/div64.h> #include "dvb_frontend.h" +#include "tda18271c2dd.h" struct SStandardParam { s32 m_IFFrequency; diff --git a/drivers/media/firewire/firedtv.h b/drivers/media/firewire/firedtv.h index 4fdcd8cb753..c2ba085e0d2 100644 --- a/drivers/media/firewire/firedtv.h +++ b/drivers/media/firewire/firedtv.h @@ -13,6 +13,7 @@ #ifndef _FIREDTV_H #define _FIREDTV_H +#include <linux/time.h> #include <linux/dvb/dmx.h> #include <linux/dvb/frontend.h> #include <linux/list.h> diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index 18a38b38fcb..df163800c8e 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -3,10 +3,10 @@ * * Copyright (C) 2008--2011 Nokia Corporation * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * Contributors: - * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Sakari Ailus <sakari.ailus@iki.fi> * Tuukka Toivonen <tuukkat76@gmail.com> * * This program is free software; you can redistribute it and/or diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c index e1d4c89d714..10c3c1db4cd 100644 --- a/drivers/media/i2c/adv7183.c +++ b/drivers/media/i2c/adv7183.c @@ -681,18 +681,7 @@ static struct i2c_driver adv7183_driver = { .id_table = adv7183_id, }; -static __init int adv7183_init(void) -{ - return i2c_add_driver(&adv7183_driver); -} - -static __exit void adv7183_exit(void) -{ - i2c_del_driver(&adv7183_driver); -} - -module_init(adv7183_init); -module_exit(adv7183_exit); +module_i2c_driver(adv7183_driver); MODULE_DESCRIPTION("Analog Devices ADV7183 video decoder driver"); MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 05f8950f6f9..f47555b1000 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -486,9 +486,19 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) struct i2c_client *client = state->i2c_edid; u8 msgbuf0[1] = { 0 }; u8 msgbuf1[256]; - struct i2c_msg msg[2] = { { client->addr, 0, 1, msgbuf0 }, - { client->addr, 0 | I2C_M_RD, len, msgbuf1 } - }; + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .len = 1, + .buf = msgbuf0 + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = len, + .buf = msgbuf1 + }, + }; if (i2c_transfer(client->adapter, msg, 2) < 0) return -EIO; diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 2cee69e3418..f4149eb4d7b 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -2065,7 +2065,7 @@ static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status, #define DIF_BPF_COEFF3435 (0x38c) #define DIF_BPF_COEFF36 (0x390) -void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) +static void cx23885_dif_setup(struct i2c_client *client, u32 ifHz) { u64 pll_freq; u32 pll_freq_word; diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index 04f192a0398..08ae067b2b6 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -284,7 +284,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) { char *ir_codes = NULL; const char *name = NULL; - u64 rc_type = RC_TYPE_UNKNOWN; + u64 rc_type = RC_BIT_UNKNOWN; struct IR_i2c *ir; struct rc_dev *rc = NULL; struct i2c_adapter *adap = client->adapter; @@ -303,7 +303,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case 0x64: name = "Pixelview"; ir->get_key = get_key_pixelview; - rc_type = RC_TYPE_OTHER; + rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; case 0x18: @@ -311,31 +311,31 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id) case 0x1a: name = "Hauppauge"; ir->get_key = get_key_haup; - rc_type = RC_TYPE_RC5; + rc_type = RC_BIT_RC5; ir_codes = RC_MAP_HAUPPAUGE; break; case 0x30: name = "KNC One"; ir->get_key = get_key_knc1; - rc_type = RC_TYPE_OTHER; + rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_EMPTY; break; case 0x6b: name = "FusionHDTV"; ir->get_key = get_key_fusionhdtv; - rc_type = RC_TYPE_RC5; + rc_type = RC_BIT_RC5; ir_codes = RC_MAP_FUSIONHDTV_MCE; break; case 0x40: name = "AVerMedia Cardbus remote"; ir->get_key = get_key_avermedia_cardbus; - rc_type = RC_TYPE_OTHER; + rc_type = RC_BIT_OTHER; ir_codes = RC_MAP_AVERMEDIA_CARDBUS; break; case 0x71: name = "Hauppauge/Zilog Z8"; ir->get_key = get_key_haup_xvr; - rc_type = RC_TYPE_RC5; + rc_type = RC_BIT_RC5; ir_codes = RC_MAP_HAUPPAUGE; break; } diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c index 49c1b3abb42..2750de63427 100644 --- a/drivers/media/i2c/s5k4ecgx.c +++ b/drivers/media/i2c/s5k4ecgx.c @@ -343,7 +343,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd) } regs_num = le32_to_cpu(get_unaligned_le32(fw->data)); - v4l2_dbg(3, debug, sd, "FW: %s size %d register sets %d\n", + v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n", S5K4ECGX_FIRMWARE, fw->size, regs_num); regs_num++; /* Add header */ diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index a577614bd84..d8d5da7c52d 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -58,7 +58,7 @@ static int bounds_check(struct device *dev, uint32_t val, if (val >= min && val <= max) return 0; - dev_warn(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); + dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); return -EINVAL; } @@ -87,14 +87,14 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll) dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz); } -int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, - struct smiapp_pll *pll) +static int __smiapp_pll_calculate(struct device *dev, + const struct smiapp_pll_limits *limits, + struct smiapp_pll *pll, uint32_t mul, + uint32_t div, uint32_t lane_op_clock_ratio) { uint32_t sys_div; uint32_t best_pix_div = INT_MAX >> 1; uint32_t vt_op_binning_div; - uint32_t lane_op_clock_ratio; - uint32_t mul, div; uint32_t more_mul_min, more_mul_max; uint32_t more_mul_factor; uint32_t min_vt_div, max_vt_div, vt_div; @@ -102,54 +102,6 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, unsigned int i; int rval; - if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) - lane_op_clock_ratio = pll->lanes; - else - lane_op_clock_ratio = 1; - dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio); - - dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal, - pll->binning_vertical); - - /* CSI transfers 2 bits per clock per lane; thus times 2 */ - pll->pll_op_clk_freq_hz = pll->link_freq * 2 - * (pll->lanes / lane_op_clock_ratio); - - /* Figure out limits for pre-pll divider based on extclk */ - dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - limits->max_pre_pll_clk_div = - min_t(uint16_t, limits->max_pre_pll_clk_div, - clk_div_even(pll->ext_clk_freq_hz / - limits->min_pll_ip_freq_hz)); - limits->min_pre_pll_clk_div = - max_t(uint16_t, limits->min_pre_pll_clk_div, - clk_div_even_up( - DIV_ROUND_UP(pll->ext_clk_freq_hz, - limits->max_pll_ip_freq_hz))); - dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - - i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); - mul = div_u64(pll->pll_op_clk_freq_hz, i); - div = pll->ext_clk_freq_hz / i; - dev_dbg(dev, "mul %d / div %d\n", mul, div); - - limits->min_pre_pll_clk_div = - max_t(uint16_t, limits->min_pre_pll_clk_div, - clk_div_even_up( - DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, - limits->max_pll_op_freq_hz))); - dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n", - limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); - - if (limits->min_pre_pll_clk_div > limits->max_pre_pll_clk_div) { - dev_err(dev, "unable to compute pre_pll divisor\n"); - return -EINVAL; - } - - pll->pre_pll_clk_div = limits->min_pre_pll_clk_div; - /* * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be * too high. @@ -162,7 +114,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, more_mul_max); /* Don't go above max pll op frequency. */ more_mul_max = - min_t(int, + min_t(uint32_t, more_mul_max, limits->max_pll_op_freq_hz / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); @@ -170,7 +122,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, more_mul_max); /* Don't go above the division capability of op sys clock divider. */ more_mul_max = min(more_mul_max, - limits->max_op_sys_clk_div * pll->pre_pll_clk_div + limits->op.max_sys_clk_div * pll->pre_pll_clk_div / div); dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n", more_mul_max); @@ -193,14 +145,14 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, more_mul_min); if (more_mul_min > more_mul_max) { - dev_warn(dev, - "unable to compute more_mul_min and more_mul_max"); + dev_dbg(dev, + "unable to compute more_mul_min and more_mul_max\n"); return -EINVAL; } more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor); - more_mul_factor = lcm(more_mul_factor, limits->min_op_sys_clk_div); + more_mul_factor = lcm(more_mul_factor, limits->op.min_sys_clk_div); dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n", more_mul_factor); i = roundup(more_mul_min, more_mul_factor); @@ -209,7 +161,7 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, dev_dbg(dev, "final more_mul: %d\n", i); if (i > more_mul_max) { - dev_warn(dev, "final more_mul is bad, max %d", more_mul_max); + dev_dbg(dev, "final more_mul is bad, max %d\n", more_mul_max); return -EINVAL; } @@ -268,19 +220,19 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, dev_dbg(dev, "min_vt_div: %d\n", min_vt_div); min_vt_div = max(min_vt_div, DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->max_vt_pix_clk_freq_hz)); + limits->vt.max_pix_clk_freq_hz)); dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n", min_vt_div); min_vt_div = max_t(uint32_t, min_vt_div, - limits->min_vt_pix_clk_div - * limits->min_vt_sys_clk_div); + limits->vt.min_pix_clk_div + * limits->vt.min_sys_clk_div); dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div); - max_vt_div = limits->max_vt_sys_clk_div * limits->max_vt_pix_clk_div; + max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; dev_dbg(dev, "max_vt_div: %d\n", max_vt_div); max_vt_div = min(max_vt_div, DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->min_vt_pix_clk_freq_hz)); + limits->vt.min_pix_clk_freq_hz)); dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n", max_vt_div); @@ -288,28 +240,28 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, * Find limitsits for sys_clk_div. Not all values are possible * with all values of pix_clk_div. */ - min_sys_div = limits->min_vt_sys_clk_div; + min_sys_div = limits->vt.min_sys_clk_div; dev_dbg(dev, "min_sys_div: %d\n", min_sys_div); min_sys_div = max(min_sys_div, DIV_ROUND_UP(min_vt_div, - limits->max_vt_pix_clk_div)); + limits->vt.max_pix_clk_div)); dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div); min_sys_div = max(min_sys_div, pll->pll_op_clk_freq_hz - / limits->max_vt_sys_clk_freq_hz); + / limits->vt.max_sys_clk_freq_hz); dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div); min_sys_div = clk_div_even_up(min_sys_div); dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div); - max_sys_div = limits->max_vt_sys_clk_div; + max_sys_div = limits->vt.max_sys_clk_div; dev_dbg(dev, "max_sys_div: %d\n", max_sys_div); max_sys_div = min(max_sys_div, DIV_ROUND_UP(max_vt_div, - limits->min_vt_pix_clk_div)); + limits->vt.min_pix_clk_div)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div); max_sys_div = min(max_sys_div, DIV_ROUND_UP(pll->pll_op_clk_freq_hz, - limits->min_vt_pix_clk_freq_hz)); + limits->vt.min_pix_clk_freq_hz)); dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div); /* @@ -322,15 +274,15 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, for (sys_div = min_sys_div; sys_div <= max_sys_div; sys_div += 2 - (sys_div & 1)) { - int pix_div = DIV_ROUND_UP(vt_div, sys_div); + uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div); - if (pix_div < limits->min_vt_pix_clk_div - || pix_div > limits->max_vt_pix_clk_div) { + if (pix_div < limits->vt.min_pix_clk_div + || pix_div > limits->vt.max_pix_clk_div) { dev_dbg(dev, "pix_div %d too small or too big (%d--%d)\n", pix_div, - limits->min_vt_pix_clk_div, - limits->max_vt_pix_clk_div); + limits->vt.min_pix_clk_div, + limits->vt.max_pix_clk_div); continue; } @@ -354,16 +306,10 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, pll->pixel_rate_csi = pll->op_pix_clk_freq_hz * lane_op_clock_ratio; - print_pll(dev, pll); - - rval = bounds_check(dev, pll->pre_pll_clk_div, - limits->min_pre_pll_clk_div, - limits->max_pre_pll_clk_div, "pre_pll_clk_div"); - if (!rval) - rval = bounds_check( - dev, pll->pll_ip_clk_freq_hz, - limits->min_pll_ip_freq_hz, limits->max_pll_ip_freq_hz, - "pll_ip_clk_freq_hz"); + rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, + limits->min_pll_ip_freq_hz, + limits->max_pll_ip_freq_hz, + "pll_ip_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->pll_multiplier, @@ -377,42 +323,121 @@ int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, if (!rval) rval = bounds_check( dev, pll->op_sys_clk_div, - limits->min_op_sys_clk_div, limits->max_op_sys_clk_div, + limits->op.min_sys_clk_div, limits->op.max_sys_clk_div, "op_sys_clk_div"); if (!rval) rval = bounds_check( dev, pll->op_pix_clk_div, - limits->min_op_pix_clk_div, limits->max_op_pix_clk_div, + limits->op.min_pix_clk_div, limits->op.max_pix_clk_div, "op_pix_clk_div"); if (!rval) rval = bounds_check( dev, pll->op_sys_clk_freq_hz, - limits->min_op_sys_clk_freq_hz, - limits->max_op_sys_clk_freq_hz, + limits->op.min_sys_clk_freq_hz, + limits->op.max_sys_clk_freq_hz, "op_sys_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->op_pix_clk_freq_hz, - limits->min_op_pix_clk_freq_hz, - limits->max_op_pix_clk_freq_hz, + limits->op.min_pix_clk_freq_hz, + limits->op.max_pix_clk_freq_hz, "op_pix_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->vt_sys_clk_freq_hz, - limits->min_vt_sys_clk_freq_hz, - limits->max_vt_sys_clk_freq_hz, + limits->vt.min_sys_clk_freq_hz, + limits->vt.max_sys_clk_freq_hz, "vt_sys_clk_freq_hz"); if (!rval) rval = bounds_check( dev, pll->vt_pix_clk_freq_hz, - limits->min_vt_pix_clk_freq_hz, - limits->max_vt_pix_clk_freq_hz, + limits->vt.min_pix_clk_freq_hz, + limits->vt.max_pix_clk_freq_hz, "vt_pix_clk_freq_hz"); return rval; } + +int smiapp_pll_calculate(struct device *dev, + const struct smiapp_pll_limits *limits, + struct smiapp_pll *pll) +{ + uint16_t min_pre_pll_clk_div; + uint16_t max_pre_pll_clk_div; + uint32_t lane_op_clock_ratio; + uint32_t mul, div; + unsigned int i; + int rval = -EINVAL; + + if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) + lane_op_clock_ratio = pll->csi2.lanes; + else + lane_op_clock_ratio = 1; + dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio); + + dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal, + pll->binning_vertical); + + switch (pll->bus_type) { + case SMIAPP_PLL_BUS_TYPE_CSI2: + /* CSI transfers 2 bits per clock per lane; thus times 2 */ + pll->pll_op_clk_freq_hz = pll->link_freq * 2 + * (pll->csi2.lanes / lane_op_clock_ratio); + break; + case SMIAPP_PLL_BUS_TYPE_PARALLEL: + pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel + / DIV_ROUND_UP(pll->bits_per_pixel, + pll->parallel.bus_width); + break; + default: + return -EINVAL; + } + + /* Figure out limits for pre-pll divider based on extclk */ + dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n", + limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); + max_pre_pll_clk_div = + min_t(uint16_t, limits->max_pre_pll_clk_div, + clk_div_even(pll->ext_clk_freq_hz / + limits->min_pll_ip_freq_hz)); + min_pre_pll_clk_div = + max_t(uint16_t, limits->min_pre_pll_clk_div, + clk_div_even_up( + DIV_ROUND_UP(pll->ext_clk_freq_hz, + limits->max_pll_ip_freq_hz))); + dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); + mul = div_u64(pll->pll_op_clk_freq_hz, i); + div = pll->ext_clk_freq_hz / i; + dev_dbg(dev, "mul %d / div %d\n", mul, div); + + min_pre_pll_clk_div = + max_t(uint16_t, min_pre_pll_clk_div, + clk_div_even_up( + DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, + limits->max_pll_op_freq_hz))); + dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n", + min_pre_pll_clk_div, max_pre_pll_clk_div); + + for (pll->pre_pll_clk_div = min_pre_pll_clk_div; + pll->pre_pll_clk_div <= max_pre_pll_clk_div; + pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { + rval = __smiapp_pll_calculate(dev, limits, pll, mul, div, + lane_op_clock_ratio); + if (rval) + continue; + + print_pll(dev, pll); + return 0; + } + + dev_info(dev, "unable to compute pre_pll divisor\n"); + return rval; +} EXPORT_SYMBOL_GPL(smiapp_pll_calculate); -MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>"); MODULE_DESCRIPTION("Generic SMIA/SMIA++ PLL calculator"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h index cb2d2db5d02..a4a649834a1 100644 --- a/drivers/media/i2c/smiapp-pll.h +++ b/drivers/media/i2c/smiapp-pll.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -27,16 +27,34 @@ #include <linux/device.h> +/* CSI-2 or CCP-2 */ +#define SMIAPP_PLL_BUS_TYPE_CSI2 0x00 +#define SMIAPP_PLL_BUS_TYPE_PARALLEL 0x01 + +/* op pix clock is for all lanes in total normally */ +#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) +#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1) + struct smiapp_pll { - uint8_t lanes; + /* input values */ + uint8_t bus_type; + union { + struct { + uint8_t lanes; + } csi2; + struct { + uint8_t bus_width; + } parallel; + }; + uint8_t flags; uint8_t binning_horizontal; uint8_t binning_vertical; uint8_t scale_m; uint8_t scale_n; uint8_t bits_per_pixel; - uint16_t flags; uint32_t link_freq; + /* output values */ uint16_t pre_pll_clk_div; uint16_t pll_multiplier; uint16_t op_sys_clk_div; @@ -55,6 +73,17 @@ struct smiapp_pll { uint32_t pixel_rate_csi; }; +struct smiapp_pll_branch_limits { + uint16_t min_sys_clk_div; + uint16_t max_sys_clk_div; + uint32_t min_sys_clk_freq_hz; + uint32_t max_sys_clk_freq_hz; + uint16_t min_pix_clk_div; + uint16_t max_pix_clk_div; + uint32_t min_pix_clk_freq_hz; + uint32_t max_pix_clk_freq_hz; +}; + struct smiapp_pll_limits { /* Strict PLL limits */ uint32_t min_ext_clk_freq_hz; @@ -68,36 +97,18 @@ struct smiapp_pll_limits { uint32_t min_pll_op_freq_hz; uint32_t max_pll_op_freq_hz; - uint16_t min_vt_sys_clk_div; - uint16_t max_vt_sys_clk_div; - uint32_t min_vt_sys_clk_freq_hz; - uint32_t max_vt_sys_clk_freq_hz; - uint16_t min_vt_pix_clk_div; - uint16_t max_vt_pix_clk_div; - uint32_t min_vt_pix_clk_freq_hz; - uint32_t max_vt_pix_clk_freq_hz; - - uint16_t min_op_sys_clk_div; - uint16_t max_op_sys_clk_div; - uint32_t min_op_sys_clk_freq_hz; - uint32_t max_op_sys_clk_freq_hz; - uint16_t min_op_pix_clk_div; - uint16_t max_op_pix_clk_div; - uint32_t min_op_pix_clk_freq_hz; - uint32_t max_op_pix_clk_freq_hz; + struct smiapp_pll_branch_limits vt; + struct smiapp_pll_branch_limits op; /* Other relevant limits */ uint32_t min_line_length_pck_bin; uint32_t min_line_length_pck; }; -/* op pix clock is for all lanes in total normally */ -#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) -#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1) - struct device; -int smiapp_pll_calculate(struct device *dev, struct smiapp_pll_limits *limits, +int smiapp_pll_calculate(struct device *dev, + const struct smiapp_pll_limits *limits, struct smiapp_pll *pll); #endif /* SMIAPP_PLL_H */ diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index e08e588ad24..83c7ed7ffcc 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * Based on smiapp driver by Vimarsh Zutshi * Based on jt8ev1.c by Vimarsh Zutshi @@ -252,23 +252,23 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ], .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ], - .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV], - .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV], - .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV], - .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV], - .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ], - .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ], - .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ], - .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ], - - .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV], - .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV], - .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV], - .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV], - .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ], - .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ], - .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ], - .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ], + .op.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV], + .op.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV], + .op.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV], + .op.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV], + .op.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ], + .op.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ], + .op.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ], + .op.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ], + + .vt.min_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV], + .vt.max_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV], + .vt.min_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV], + .vt.max_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV], + .vt.min_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ], + .vt.max_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ], + .vt.min_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ], + .vt.max_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ], .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN], .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK], @@ -276,11 +276,6 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) struct smiapp_pll *pll = &sensor->pll; int rval; - memset(&sensor->pll, 0, sizeof(sensor->pll)); - - pll->lanes = sensor->platform_data->lanes; - pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; - if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) { /* * Fill in operational clock divisors limits from the @@ -288,28 +283,14 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) * requirements regarding them are essentially the * same as on VT ones. */ - lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div; - lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div; - lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div; - lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div; - lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz; - lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz; - lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz; - lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz; - /* Profile 0 sensors have no separate OP clock branch. */ - pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + lim.op = lim.vt; } - if (smiapp_needs_quirk(sensor, - SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE)) - pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; - pll->binning_horizontal = sensor->binning_horizontal; pll->binning_vertical = sensor->binning_vertical; pll->link_freq = sensor->link_freq->qmenu_int[sensor->link_freq->val]; pll->scale_m = sensor->scale_m; - pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; pll->bits_per_pixel = sensor->csi_format->compressed; rval = smiapp_pll_calculate(&client->dev, &lim, pll); @@ -1010,7 +991,7 @@ static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) * do not change, or if you do at least know what you're * doing. :-) * - * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25 + * Sakari Ailus <sakari.ailus@iki.fi> 2010-10-25 * * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl * / EXTCLK freq [Hz]) * flash_strobe_adjustment @@ -2369,6 +2350,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); struct i2c_client *client = v4l2_get_subdevdata(subdev); + struct smiapp_pll *pll = &sensor->pll; struct smiapp_subdev *last = NULL; u32 tmp; unsigned int i; @@ -2635,6 +2617,18 @@ static int smiapp_registered(struct v4l2_subdev *subdev) if (rval < 0) goto out_nvm_release; + /* prepare PLL configuration input values */ + pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; + pll->csi2.lanes = sensor->platform_data->lanes; + pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; + /* Profile 0 sensors have no separate OP clock branch. */ + if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + if (smiapp_needs_quirk(sensor, + SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE)) + pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; + pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; + rval = smiapp_update_mode(sensor); if (rval) { dev_err(&client->dev, "update mode failed\n"); @@ -2893,6 +2887,6 @@ static struct i2c_driver smiapp_i2c_driver = { module_i2c_driver(smiapp_i2c_driver); -MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); +MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>"); MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c index fb2f81ad8c3..847cb235e19 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.c +++ b/drivers/media/i2c/smiapp/smiapp-limits.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h index 9ae765e23ea..343e9c3827f 100644 --- a/drivers/media/i2c/smiapp/smiapp-limits.h +++ b/drivers/media/i2c/smiapp/smiapp-limits.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c index 725cf62836c..bb8c506e0e3 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.c +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h index 86fd3e8bfb0..504a6d80ced 100644 --- a/drivers/media/i2c/smiapp/smiapp-quirk.h +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h index defa7c5adeb..3aa0ca948d8 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h index 54568ca2fe6..b0dcbb8fa5e 100644 --- a/drivers/media/i2c/smiapp/smiapp-reg.h +++ b/drivers/media/i2c/smiapp/smiapp-reg.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index 70e0d8db013..4fac32cfcb3 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h index 7f9013b4797..eefc6c84d5f 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.h +++ b/drivers/media/i2c/smiapp/smiapp-regs.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 4182a695ab5..7cc5aae662f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2010--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c index 333ef178d6f..d40a8858be0 100644 --- a/drivers/media/i2c/soc_camera/mt9v022.c +++ b/drivers/media/i2c/soc_camera/mt9v022.c @@ -15,6 +15,7 @@ #include <linux/log2.h> #include <linux/module.h> +#include <media/mt9v022.h> #include <media/soc_camera.h> #include <media/soc_mediabus.h> #include <media/v4l2-subdev.h> @@ -50,6 +51,7 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_PIXEL_OPERATION_MODE 0x0f #define MT9V022_LED_OUT_CONTROL 0x1b #define MT9V022_ADC_MODE_CONTROL 0x1c +#define MT9V022_REG32 0x20 #define MT9V022_ANALOG_GAIN 0x35 #define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47 #define MT9V022_PIXCLK_FV_LV 0x74 @@ -71,7 +73,15 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); #define MT9V022_COLUMN_SKIP 1 #define MT9V022_ROW_SKIP 4 -#define is_mt9v024(id) (id == 0x1324) +#define MT9V022_HORIZONTAL_BLANKING_MIN 43 +#define MT9V022_HORIZONTAL_BLANKING_MAX 1023 +#define MT9V022_HORIZONTAL_BLANKING_DEF 94 +#define MT9V022_VERTICAL_BLANKING_MIN 2 +#define MT9V022_VERTICAL_BLANKING_MAX 3000 +#define MT9V022_VERTICAL_BLANKING_DEF 45 + +#define is_mt9v022_rev3(id) (id == 0x1313) +#define is_mt9v024(id) (id == 0x1324) /* MT9V022 has only one fixed colorspace per pixelcode */ struct mt9v022_datafmt { @@ -136,6 +146,8 @@ struct mt9v022 { struct v4l2_ctrl *autogain; struct v4l2_ctrl *gain; }; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; struct v4l2_rect rect; /* Sensor window */ const struct mt9v022_datafmt *fmt; const struct mt9v022_datafmt *fmts; @@ -143,6 +155,7 @@ struct mt9v022 { int num_fmts; int model; /* V4L2_IDENT_MT9V022* codes from v4l2-chip-ident.h */ u16 chip_control; + u16 chip_version; unsigned short y_skip_top; /* Lines to skip at the top */ }; @@ -225,12 +238,32 @@ static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable) struct i2c_client *client = v4l2_get_subdevdata(sd); struct mt9v022 *mt9v022 = to_mt9v022(client); - if (enable) + if (enable) { /* Switch to master "normal" mode */ mt9v022->chip_control &= ~0x10; - else + if (is_mt9v022_rev3(mt9v022->chip_version) || + is_mt9v024(mt9v022->chip_version)) { + /* + * Unset snapshot mode specific settings: clear bit 9 + * and bit 2 in reg. 0x20 when in normal mode. + */ + if (reg_clear(client, MT9V022_REG32, 0x204)) + return -EIO; + } + } else { /* Switch to snapshot mode */ mt9v022->chip_control |= 0x10; + if (is_mt9v022_rev3(mt9v022->chip_version) || + is_mt9v024(mt9v022->chip_version)) { + /* + * Required settings for snapshot mode: set bit 9 + * (RST enable) and bit 2 (CR enable) in reg. 0x20 + * See TechNote TN0960 or TN-09-225. + */ + if (reg_set(client, MT9V022_REG32, 0x204)) + return -EIO; + } + } if (reg_write(client, MT9V022_CHIP_CONTROL, mt9v022->chip_control) < 0) return -EIO; @@ -282,11 +315,10 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a) * Default 94, Phytec driver says: * "width + horizontal blank >= 660" */ - ret = reg_write(client, MT9V022_HORIZONTAL_BLANKING, - rect.width > 660 - 43 ? 43 : - 660 - rect.width); + ret = v4l2_ctrl_s_ctrl(mt9v022->hblank, + rect.width > 660 - 43 ? 43 : 660 - rect.width); if (!ret) - ret = reg_write(client, MT9V022_VERTICAL_BLANKING, 45); + ret = v4l2_ctrl_s_ctrl(mt9v022->vblank, 45); if (!ret) ret = reg_write(client, MT9V022_WINDOW_WIDTH, rect.width); if (!ret) @@ -509,6 +541,18 @@ static int mt9v022_g_volatile_ctrl(struct v4l2_ctrl *ctrl) range = exp->maximum - exp->minimum; exp->val = ((data - 1) * range + 239) / 479 + exp->minimum; return 0; + case V4L2_CID_HBLANK: + data = reg_read(client, MT9V022_HORIZONTAL_BLANKING); + if (data < 0) + return -EIO; + ctrl->val = data; + return 0; + case V4L2_CID_VBLANK: + data = reg_read(client, MT9V022_VERTICAL_BLANKING); + if (data < 0) + return -EIO; + ctrl->val = data; + return 0; } return -EINVAL; } @@ -590,6 +634,16 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl) return -EIO; } return 0; + case V4L2_CID_HBLANK: + if (reg_write(client, MT9V022_HORIZONTAL_BLANKING, + ctrl->val) < 0) + return -EIO; + return 0; + case V4L2_CID_VBLANK: + if (reg_write(client, MT9V022_VERTICAL_BLANKING, + ctrl->val) < 0) + return -EIO; + return 0; } return -EINVAL; } @@ -621,6 +675,8 @@ static int mt9v022_video_probe(struct i2c_client *client) goto ei2c; } + mt9v022->chip_version = data; + mt9v022->reg = is_mt9v024(data) ? &mt9v024_register : &mt9v022_register; @@ -819,6 +875,7 @@ static int mt9v022_probe(struct i2c_client *client, struct mt9v022 *mt9v022; struct soc_camera_link *icl = soc_camera_i2c_to_link(client); struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct mt9v022_platform_data *pdata = icl->priv; int ret; if (!icl) { @@ -857,10 +914,21 @@ static int mt9v022_probe(struct i2c_client *client, mt9v022->exposure = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, V4L2_CID_EXPOSURE, 1, 255, 1, 255); + mt9v022->hblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_HBLANK, MT9V022_HORIZONTAL_BLANKING_MIN, + MT9V022_HORIZONTAL_BLANKING_MAX, 1, + MT9V022_HORIZONTAL_BLANKING_DEF); + + mt9v022->vblank = v4l2_ctrl_new_std(&mt9v022->hdl, &mt9v022_ctrl_ops, + V4L2_CID_VBLANK, MT9V022_VERTICAL_BLANKING_MIN, + MT9V022_VERTICAL_BLANKING_MAX, 1, + MT9V022_VERTICAL_BLANKING_DEF); + mt9v022->subdev.ctrl_handler = &mt9v022->hdl; if (mt9v022->hdl.error) { int err = mt9v022->hdl.error; + dev_err(&client->dev, "control initialisation err %d\n", err); kfree(mt9v022); return err; } @@ -871,10 +939,10 @@ static int mt9v022_probe(struct i2c_client *client, mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT; /* - * MT9V022 _really_ corrupts the first read out line. - * TODO: verify on i.MX31 + * On some platforms the first read out line is corrupted. + * Workaround it by skipping if indicated by platform data. */ - mt9v022->y_skip_top = 1; + mt9v022->y_skip_top = pdata ? pdata->y_skip_top : 0; mt9v022->rect.left = MT9V022_COLUMN_SKIP; mt9v022->rect.top = MT9V022_ROW_SKIP; mt9v022->rect.width = MT9V022_MAX_WIDTH; diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c index d2d298b6354..66698a83bda 100644 --- a/drivers/media/i2c/soc_camera/ov2640.c +++ b/drivers/media/i2c/soc_camera/ov2640.c @@ -586,9 +586,20 @@ static const struct regval_list ov2640_format_change_preamble_regs[] = { ENDMARKER, }; -static const struct regval_list ov2640_yuv422_regs[] = { +static const struct regval_list ov2640_yuyv_regs[] = { + { IMAGE_MODE, IMAGE_MODE_YUV422 }, + { 0xd7, 0x03 }, + { 0x33, 0xa0 }, + { 0xe5, 0x1f }, + { 0xe1, 0x67 }, + { RESET, 0x00 }, + { R_BYPASS, R_BYPASS_USE_DSP }, + ENDMARKER, +}; + +static const struct regval_list ov2640_uyvy_regs[] = { { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 }, - { 0xD7, 0x01 }, + { 0xd7, 0x01 }, { 0x33, 0xa0 }, { 0xe1, 0x67 }, { RESET, 0x00 }, @@ -596,7 +607,15 @@ static const struct regval_list ov2640_yuv422_regs[] = { ENDMARKER, }; -static const struct regval_list ov2640_rgb565_regs[] = { +static const struct regval_list ov2640_rgb565_be_regs[] = { + { IMAGE_MODE, IMAGE_MODE_RGB565 }, + { 0xd7, 0x03 }, + { RESET, 0x00 }, + { R_BYPASS, R_BYPASS_USE_DSP }, + ENDMARKER, +}; + +static const struct regval_list ov2640_rgb565_le_regs[] = { { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 }, { 0xd7, 0x03 }, { RESET, 0x00 }, @@ -605,7 +624,9 @@ static const struct regval_list ov2640_rgb565_regs[] = { }; static enum v4l2_mbus_pixelcode ov2640_codes[] = { + V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_MBUS_FMT_RGB565_2X8_LE, }; @@ -787,14 +808,22 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height, /* select format */ priv->cfmt_code = 0; switch (code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: + dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__); + selected_cfmt_regs = ov2640_rgb565_be_regs; + break; case V4L2_MBUS_FMT_RGB565_2X8_LE: - dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__); - selected_cfmt_regs = ov2640_rgb565_regs; + dev_dbg(&client->dev, "%s: Selected cfmt RGB565 LE", __func__); + selected_cfmt_regs = ov2640_rgb565_le_regs; + break; + case V4L2_MBUS_FMT_YUYV8_2X8: + dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__); + selected_cfmt_regs = ov2640_yuyv_regs; break; default: case V4L2_MBUS_FMT_UYVY8_2X8: - dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__); - selected_cfmt_regs = ov2640_yuv422_regs; + dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__); + selected_cfmt_regs = ov2640_uyvy_regs; } /* reset hardware */ @@ -859,10 +888,12 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd, mf->code = priv->cfmt_code; switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: + case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } @@ -879,11 +910,13 @@ static int ov2640_s_fmt(struct v4l2_subdev *sd, switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } @@ -896,21 +929,21 @@ static int ov2640_s_fmt(struct v4l2_subdev *sd, static int ov2640_try_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf) { - const struct ov2640_win_size *win; - /* - * select suitable win + * select suitable win, but don't store it */ - win = ov2640_select_win(&mf->width, &mf->height); + ov2640_select_win(&mf->width, &mf->height); mf->field = V4L2_FIELD_NONE; switch (mf->code) { + case V4L2_MBUS_FMT_RGB565_2X8_BE: case V4L2_MBUS_FMT_RGB565_2X8_LE: mf->colorspace = V4L2_COLORSPACE_SRGB; break; default: mf->code = V4L2_MBUS_FMT_UYVY8_2X8; + case V4L2_MBUS_FMT_YUYV8_2X8: case V4L2_MBUS_FMT_UYVY8_2X8: mf->colorspace = V4L2_COLORSPACE_JPEG; } diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 42ae9dc9c57..f434a19b9bc 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -910,18 +910,7 @@ static struct i2c_driver vs6624_driver = { .id_table = vs6624_id, }; -static __init int vs6624_init(void) -{ - return i2c_add_driver(&vs6624_driver); -} - -static __exit void vs6624_exit(void) -{ - i2c_del_driver(&vs6624_driver); -} - -module_init(vs6624_init); -module_exit(vs6624_exit); +module_i2c_driver(vs6624_driver); MODULE_DESCRIPTION("VS6624 sensor driver"); MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig index fa62475be3b..aa05ad3c1cc 100644 --- a/drivers/media/mmc/siano/Kconfig +++ b/drivers/media/mmc/siano/Kconfig @@ -4,7 +4,8 @@ config SMS_SDIO_DRV tristate "Siano SMS1xxx based MDTV via SDIO interface" - depends on DVB_CORE && RC_CORE && HAS_DMA + depends on DVB_CORE && HAS_DMA depends on MMC + select MEDIA_COMMON_OPTIONS ---help--- Choose if you would like to have Siano's support for SDIO interface diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 56c6c77793d..de6f41f1918 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -200,7 +200,7 @@ static void flush_request_modules(struct bttv *dev) } #else #define request_modules(dev) -#define flush_request_modules(dev) +#define flush_request_modules(dev) do {} while(0) #endif /* CONFIG_MODULES */ @@ -301,11 +301,10 @@ const struct bttv_tvnorm bttv_tvnorms[] = { /* totalwidth */ 1135, /* sqwidth */ 944, /* vdelay */ 0x20, - /* sheight */ 576, - /* videostart0 */ 23) /* bt878 (and bt848?) can capture another line below active video. */ - .cropcap.bounds.height = (576 + 2) + 0x20 - 2, + /* sheight */ (576 + 2) + 0x20 - 2, + /* videostart0 */ 23) },{ .v4l2_id = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, .name = "NTSC", diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index 6d2a98246b6..8e971ff6058 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -197,7 +197,7 @@ err_exit: return ret; } -int cx18_alsa_load(struct cx18 *cx) +static int __init cx18_alsa_load(struct cx18 *cx) { struct v4l2_device *v4l2_dev = &cx->v4l2_dev; struct cx18_stream *s; diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index 7a5b84a86bb..180077c4912 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c @@ -37,6 +37,7 @@ #include "cx18-streams.h" #include "cx18-fileops.h" #include "cx18-alsa.h" +#include "cx18-alsa-pcm.h" static unsigned int pcm_debug; module_param(pcm_debug, int, 0644); diff --git a/drivers/media/pci/cx18/cx18-i2c.c b/drivers/media/pci/cx18/cx18-i2c.c index 51609d5c88c..4908eb7bcf6 100644 --- a/drivers/media/pci/cx18/cx18-i2c.c +++ b/drivers/media/pci/cx18/cx18-i2c.c @@ -98,7 +98,7 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, case CX18_HW_Z8F0811_IR_RX_HAUP: init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; + init_data->type = RC_BIT_RC5; init_data->name = cx->card_name; info.platform_data = init_data; break; diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 72af9b5c2d7..843c62b2f48 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -97,7 +97,7 @@ static struct { }; -void cx18_dma_free(struct videobuf_queue *q, +static void cx18_dma_free(struct videobuf_queue *q, struct cx18_stream *s, struct cx18_videobuf_buffer *buf) { videobuf_waiton(q, &buf->vb, 0, 0); diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 495781ee471..2926f7fadcc 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -263,7 +263,7 @@ static int netup_fpga_op_rw(struct fpga_internal *inter, int addr, } /* flag - mem/io, read - read/write */ -int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, +static int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 flag, u8 read, int addr, u8 val) { @@ -298,31 +298,32 @@ int altera_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, return mem; } -int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr) +static int altera_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr) { return altera_ci_op_cam(en50221, slot, 0, NETUP_CI_FLG_RD, addr, 0); } -int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, - int slot, int addr, u8 data) +static int altera_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data) { return altera_ci_op_cam(en50221, slot, 0, 0, addr, data); } -int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +static int altera_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, + int slot, u8 addr) { return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, NETUP_CI_FLG_RD, addr, 0); } -int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, - u8 addr, u8 data) +static int altera_ci_write_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, + u8 addr, u8 data) { return altera_ci_op_cam(en50221, slot, NETUP_CI_FLG_CTL, 0, addr, data); } -int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +static int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) { struct altera_ci_state *state = en50221->data; struct fpga_internal *inter = state->internal; @@ -365,13 +366,13 @@ int altera_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) return 0; } -int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +static int altera_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) { /* not implemented */ return 0; } -int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) +static int altera_ci_slot_ts_ctl(struct dvb_ca_en50221 *en50221, int slot) { struct altera_ci_state *state = en50221->data; struct fpga_internal *inter = state->internal; @@ -448,8 +449,8 @@ int altera_ci_irq(void *dev) } EXPORT_SYMBOL(altera_ci_irq); -int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, - int open) +static int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open) { struct altera_ci_state *state = en50221->data; @@ -459,7 +460,7 @@ int altera_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, return state->status; } -void altera_hw_filt_release(void *main_dev, int filt_nr) +static void altera_hw_filt_release(void *main_dev, int filt_nr) { struct fpga_inode *temp_int = find_inode(main_dev); struct netup_hw_pid_filter *pid_filt = NULL; @@ -581,7 +582,7 @@ static void altera_toggle_fullts_streaming(struct netup_hw_pid_filter *pid_filt, mutex_unlock(&inter->fpga_mutex); } -int altera_pid_feed_control(void *demux_dev, int filt_nr, +static int altera_pid_feed_control(void *demux_dev, int filt_nr, struct dvb_demux_feed *feed, int onoff) { struct fpga_inode *temp_int = find_dinode(demux_dev); @@ -603,41 +604,41 @@ int altera_pid_feed_control(void *demux_dev, int filt_nr, } EXPORT_SYMBOL(altera_pid_feed_control); -int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) +static int altera_ci_start_feed(struct dvb_demux_feed *feed, int num) { altera_pid_feed_control(feed->demux, num, feed, 1); return 0; } -int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) +static int altera_ci_stop_feed(struct dvb_demux_feed *feed, int num) { altera_pid_feed_control(feed->demux, num, feed, 0); return 0; } -int altera_ci_start_feed_1(struct dvb_demux_feed *feed) +static int altera_ci_start_feed_1(struct dvb_demux_feed *feed) { return altera_ci_start_feed(feed, 1); } -int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) +static int altera_ci_stop_feed_1(struct dvb_demux_feed *feed) { return altera_ci_stop_feed(feed, 1); } -int altera_ci_start_feed_2(struct dvb_demux_feed *feed) +static int altera_ci_start_feed_2(struct dvb_demux_feed *feed) { return altera_ci_start_feed(feed, 2); } -int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) +static int altera_ci_stop_feed_2(struct dvb_demux_feed *feed) { return altera_ci_stop_feed(feed, 2); } -int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) +static int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) { struct netup_hw_pid_filter *pid_filt = NULL; struct fpga_inode *temp_int = find_inode(config->dev); diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 6617774a326..7344849183a 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -24,6 +24,7 @@ */ #include "cx23885.h" +#include "cimax2.h" #include "dvb_ca_en50221.h" /**** Bit definitions for MC417_RWD and MC417_OEN registers *** bits 31-16 @@ -87,7 +88,7 @@ struct netup_ci_state { }; -int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, +static int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, u8 *buf, int len) { int ret; @@ -120,7 +121,7 @@ int netup_read_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, return 0; } -int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, +static int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, u8 *buf, int len) { int ret; @@ -147,7 +148,7 @@ int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, return 0; } -int netup_ci_get_mem(struct cx23885_dev *dev) +static int netup_ci_get_mem(struct cx23885_dev *dev) { int mem; unsigned long timeout = jiffies + msecs_to_jiffies(1); @@ -166,7 +167,7 @@ int netup_ci_get_mem(struct cx23885_dev *dev) return mem & 0xff; } -int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, +static int netup_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 flag, u8 read, int addr, u8 data) { struct netup_ci_state *state = en50221->data; @@ -248,7 +249,8 @@ int netup_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, return netup_ci_op_cam(en50221, slot, 0, 0, addr, data); } -int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, u8 addr) +int netup_ci_read_cam_ctl(struct dvb_ca_en50221 *en50221, int slot, + u8 addr) { return netup_ci_op_cam(en50221, slot, NETUP_CI_CTL, NETUP_CI_RD, addr, 0); @@ -295,7 +297,7 @@ int netup_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) return 0; } -int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) +static int netup_ci_set_irq(struct dvb_ca_en50221 *en50221, u8 irq_mode) { struct netup_ci_state *state = en50221->data; int ret; @@ -399,7 +401,8 @@ int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status) return 1; } -int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, int slot, int open) +int netup_poll_ci_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open) { struct netup_ci_state *state = en50221->data; diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 795169237e7..c6c9bd58f8b 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -45,8 +45,10 @@ #define AUDIO_SRAM_CHANNEL SRAM_CH07 -#define dprintk(level, fmt, arg...) if (audio_debug >= level) \ - printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (audio_debug + 1 > level) \ + printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg); \ +} while(0) #define dprintk_core(level, fmt, arg...) if (audio_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, chip->dev->name , ## arg) diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c index 134ebddd860..e958a01fd55 100644 --- a/drivers/media/pci/cx23885/cx23885-av.c +++ b/drivers/media/pci/cx23885/cx23885-av.c @@ -22,6 +22,7 @@ */ #include "cx23885.h" +#include "cx23885-av.h" void cx23885_av_work_handler(struct work_struct *work) { diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 5acdf954ff6..6277e145f0b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1427,7 +1427,7 @@ void cx23885_ir_fini(struct cx23885_dev *dev) } } -int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) +static int netup_jtag_io(void *device, int tms, int tdi, int read_tdo) { int data; int tdo = 0; diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 697728f0943..065ecd54bda 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -303,7 +303,7 @@ static struct sram_channel cx23887_sram_channels[] = { }, }; -void cx23885_irq_add(struct cx23885_dev *dev, u32 mask) +static void cx23885_irq_add(struct cx23885_dev *dev, u32 mask) { unsigned long flags; spin_lock_irqsave(&dev->pci_irqmask_lock, flags); @@ -1516,8 +1516,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port, buf = list_entry(q->queued.next, struct cx23885_buffer, vb.queue); if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &q->active); + list_move_tail(&buf->vb.queue, &q->active); cx23885_start_dma(port, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; @@ -1528,8 +1527,7 @@ int cx23885_restart_queue(struct cx23885_tsport *port, } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &q->active); + list_move_tail(&buf->vb.queue, &q->active); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 4379d8a6dad..2f5b902e63a 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -659,7 +659,7 @@ static struct mt2063_config terratec_mt2063_config[] = { }, }; -int netup_altera_fpga_rw(void *device, int flag, int data, int read) +static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; unsigned long timeout = jiffies + msecs_to_jiffies(1); diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index 93998f22098..5444cc52600 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -29,6 +29,7 @@ */ #include "cx23885.h" +#include "cx23885-f300.h" #define F300_DATA GPIO_0 #define F300_RESET GPIO_1 diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 2c925f77cf2..4f1055a194b 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -40,6 +40,7 @@ #include <media/v4l2-subdev.h> #include "cx23885.h" +#include "cx23885-input.h" #define MODULE_NAME "cx23885" @@ -270,21 +271,21 @@ int cx23885_input_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1250: /* Integrated CX2388[58] IR controller */ driver_type = RC_DRIVER_IR_RAW; - allowed_protos = RC_TYPE_ALL; + allowed_protos = RC_BIT_ALL; /* The grey Hauppauge RC-5 remote */ rc_map = RC_MAP_HAUPPAUGE; break; case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL: /* Integrated CX23885 IR controller */ driver_type = RC_DRIVER_IR_RAW; - allowed_protos = RC_TYPE_NEC; + allowed_protos = RC_BIT_NEC; /* The grey Terratec remote with orange buttons */ rc_map = RC_MAP_NEC_TERRATEC_CINERGY_XS; break; case CX23885_BOARD_TEVII_S470: /* Integrated CX23885 IR controller */ driver_type = RC_DRIVER_IR_RAW; - allowed_protos = RC_TYPE_ALL; + allowed_protos = RC_BIT_ALL; /* A guess at the remote */ rc_map = RC_MAP_TEVII_NEC; break; diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h index 75ef15d3f52..87dc44e6997 100644 --- a/drivers/media/pci/cx23885/cx23885-input.h +++ b/drivers/media/pci/cx23885/cx23885-input.h @@ -23,7 +23,7 @@ #ifndef _CX23885_INPUT_H_ #define _CX23885_INPUT_H_ -int cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events); +void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events); int cx23885_input_init(struct cx23885_dev *dev); void cx23885_input_fini(struct cx23885_dev *dev); diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index 44812ca7889..ea9a614f3bb 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -22,6 +22,8 @@ */ #include "cx23885.h" +#include "cx23885-ioctl.h" + #include <media/v4l2-chip-ident.h> int cx23885_g_chip_ident(struct file *file, void *fh, diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c index 7125247dd25..bfef1935929 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.c +++ b/drivers/media/pci/cx23885/cx23885-ir.c @@ -24,6 +24,7 @@ #include <media/v4l2-device.h> #include "cx23885.h" +#include "cx23885-ir.h" #include "cx23885-input.h" #define CX23885_IR_RX_FIFO_SERVICE_REQ 0 diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index c2bc39c58f8..c4bd1e95d33 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -29,6 +29,7 @@ #include <media/rc-core.h> #include "cx23885.h" +#include "cx23888-ir.h" static unsigned int ir_888_debug; module_param(ir_888_debug, int, 0644); diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c index f4893e69cd8..0044fef7ca2 100644 --- a/drivers/media/pci/cx23885/netup-init.c +++ b/drivers/media/pci/cx23885/netup-init.c @@ -24,6 +24,7 @@ */ #include "cx23885.h" +#include "netup-init.h" static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val) { diff --git a/drivers/media/pci/cx25821/cx25821-audio-upstream.c b/drivers/media/pci/cx25821/cx25821-audio-upstream.c index 8b2a99975c2..87491ca05ee 100644 --- a/drivers/media/pci/cx25821/cx25821-audio-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-audio-upstream.c @@ -44,7 +44,7 @@ MODULE_LICENSE("GPL"); static int _intr_msk = FLD_AUD_SRC_RISCI1 | FLD_AUD_SRC_OF | FLD_AUD_SRC_SYNC | FLD_AUD_SRC_OPC_ERR; -int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev, +static int cx25821_sram_channel_setup_upstream_audio(struct cx25821_dev *dev, struct sram_channel *ch, unsigned int bpl, u32 risc) { @@ -133,7 +133,7 @@ static __le32 *cx25821_risc_field_upstream_audio(struct cx25821_dev *dev, return rp; } -int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, +static int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, struct pci_dev *pci, unsigned int bpl, unsigned int lines) { @@ -197,7 +197,7 @@ int cx25821_risc_buffer_upstream_audio(struct cx25821_dev *dev, return 0; } -void cx25821_free_memory_audio(struct cx25821_dev *dev) +static void cx25821_free_memory_audio(struct cx25821_dev *dev) { if (dev->_risc_virt_addr) { pci_free_consistent(dev->pci, dev->_audiorisc_size, @@ -256,7 +256,7 @@ void cx25821_free_mem_upstream_audio(struct cx25821_dev *dev) cx25821_free_memory_audio(dev); } -int cx25821_get_audio_data(struct cx25821_dev *dev, +static int cx25821_get_audio_data(struct cx25821_dev *dev, struct sram_channel *sram_ch) { struct file *myfile; @@ -351,7 +351,7 @@ static void cx25821_audioups_handler(struct work_struct *work) sram_channels); } -int cx25821_openfile_audio(struct cx25821_dev *dev, +static int cx25821_openfile_audio(struct cx25821_dev *dev, struct sram_channel *sram_ch) { struct file *myfile; @@ -490,7 +490,7 @@ error: return ret; } -int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, +static int cx25821_audio_upstream_irq(struct cx25821_dev *dev, int chan_num, u32 status) { int i = 0; @@ -634,8 +634,8 @@ static void cx25821_wait_fifo_enable(struct cx25821_dev *dev, } -int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, - struct sram_channel *sram_ch) +static int cx25821_start_audio_dma_upstream(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { u32 tmp = 0; int err = 0; @@ -700,9 +700,7 @@ fail_irq: int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) { struct sram_channel *sram_ch; - int retval = 0; int err = 0; - int str_length = 0; if (dev->_audio_is_running) { pr_warn("Audio Channel is still running so return!\n"); @@ -731,27 +729,29 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) _line_size = AUDIO_LINE_SIZE; if (dev->input_audiofilename) { - str_length = strlen(dev->input_audiofilename); - dev->_audiofilename = kmemdup(dev->input_audiofilename, - str_length + 1, GFP_KERNEL); + dev->_audiofilename = kstrdup(dev->input_audiofilename, + GFP_KERNEL); - if (!dev->_audiofilename) + if (!dev->_audiofilename) { + err = -ENOMEM; goto error; + } /* Default if filename is empty string */ if (strcmp(dev->input_audiofilename, "") == 0) dev->_audiofilename = "/root/audioGOOD.wav"; } else { - str_length = strlen(_defaultAudioName); - dev->_audiofilename = kmemdup(_defaultAudioName, - str_length + 1, GFP_KERNEL); + dev->_audiofilename = kstrdup(_defaultAudioName, + GFP_KERNEL); - if (!dev->_audiofilename) + if (!dev->_audiofilename) { + err = -ENOMEM; goto error; + } } - retval = cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, - _line_size, 0); + cx25821_sram_channel_setup_upstream_audio(dev, sram_ch, + _line_size, 0); dev->audio_upstream_riscbuf_size = AUDIO_RISC_DMA_BUF_SIZE * NUM_AUDIO_PROGS + @@ -759,9 +759,9 @@ int cx25821_audio_upstream_init(struct cx25821_dev *dev, int channel_select) dev->audio_upstream_databuf_size = AUDIO_DATA_BUF_SZ * NUM_AUDIO_PROGS; /* Allocating buffers and prepare RISC program */ - retval = cx25821_audio_upstream_buffer_prepare(dev, sram_ch, + err = cx25821_audio_upstream_buffer_prepare(dev, sram_ch, _line_size); - if (retval < 0) { + if (err < 0) { pr_err("%s: Failed to set up Audio upstream buffers!\n", dev->name); goto error; diff --git a/drivers/media/pci/cx25821/cx25821-biffuncs.h b/drivers/media/pci/cx25821/cx25821-biffuncs.h index 9326a7c729e..937f5a70fb7 100644 --- a/drivers/media/pci/cx25821/cx25821-biffuncs.h +++ b/drivers/media/pci/cx25821/cx25821-biffuncs.h @@ -25,17 +25,17 @@ #define SetBit(Bit) (1 << Bit) -inline u8 getBit(u32 sample, u8 index) +static inline u8 getBit(u32 sample, u8 index) { return (u8) ((sample >> index) & 1); } -inline u32 clearBitAtPos(u32 value, u8 bit) +static inline u32 clearBitAtPos(u32 value, u8 bit) { return value & ~(1 << bit); } -inline u32 setBitAtPos(u32 sample, u8 bit) +static inline u32 setBitAtPos(u32 sample, u8 bit) { sample |= (1 << bit); return sample; diff --git a/drivers/media/pci/cx25821/cx25821-i2c.c b/drivers/media/pci/cx25821/cx25821-i2c.c index 9844549764c..a8dc945bbe1 100644 --- a/drivers/media/pci/cx25821/cx25821-i2c.c +++ b/drivers/media/pci/cx25821/cx25821-i2c.c @@ -329,7 +329,8 @@ int cx25821_i2c_unregister(struct cx25821_i2c *bus) return 0; } -void cx25821_av_clk(struct cx25821_dev *dev, int enable) +#if 0 /* Currently unused */ +static void cx25821_av_clk(struct cx25821_dev *dev, int enable) { /* write 0 to bus 2 addr 0x144 via i2x_xfer() */ char buffer[3]; @@ -351,6 +352,7 @@ void cx25821_av_clk(struct cx25821_dev *dev, int enable) i2c_xfer(&dev->i2c_bus[0].i2c_adap, &msg, 1); } +#endif int cx25821_i2c_read(struct cx25821_i2c *bus, u16 reg_addr, int *value) { diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c index d33fc1a2303..cf2723c7197 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream-ch2.c @@ -123,10 +123,11 @@ static __le32 *cx25821_risc_field_upstream_ch2(struct cx25821_dev *dev, return rp; } -int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, - struct pci_dev *pci, - unsigned int top_offset, unsigned int bpl, - unsigned int lines) +static int cx25821_risc_buffer_upstream_ch2(struct cx25821_dev *dev, + struct pci_dev *pci, + unsigned int top_offset, + unsigned int bpl, + unsigned int lines) { __le32 *rp; int fifo_enable = 0; @@ -255,7 +256,8 @@ void cx25821_free_mem_upstream_ch2(struct cx25821_dev *dev) } } -int cx25821_get_frame_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) +static int cx25821_get_frame_ch2(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { struct file *myfile; int frame_index_temp = dev->_frame_index_ch2; @@ -360,7 +362,8 @@ static void cx25821_vidups_handler_ch2(struct work_struct *work) _channel2_upstream_select].sram_channels); } -int cx25821_openfile_ch2(struct cx25821_dev *dev, struct sram_channel *sram_ch) +static int cx25821_openfile_ch2(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; @@ -507,8 +510,9 @@ error: return ret; } -int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, int chan_num, - u32 status) +static int cx25821_video_upstream_irq_ch2(struct cx25821_dev *dev, + int chan_num, + u32 status) { u32 int_msk_tmp; struct sram_channel *channel = dev->channels[chan_num].sram_channels; @@ -647,8 +651,8 @@ static void cx25821_set_pixelengine_ch2(struct cx25821_dev *dev, cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); } -int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, - struct sram_channel *sram_ch) +static int cx25821_start_video_dma_upstream_ch2(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { u32 tmp = 0; int err = 0; @@ -704,11 +708,9 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, { struct sram_channel *sram_ch; u32 tmp; - int retval = 0; int err = 0; int data_frame_size = 0; int risc_buffer_size = 0; - int str_length = 0; if (dev->_is_running_ch2) { pr_info("Video Channel is still running so return!\n"); @@ -744,20 +746,16 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, risc_buffer_size = dev->_isNTSC_ch2 ? NTSC_RISC_BUF_SIZE : PAL_RISC_BUF_SIZE; - if (dev->input_filename_ch2) { - str_length = strlen(dev->input_filename_ch2); - dev->_filename_ch2 = kmemdup(dev->input_filename_ch2, - str_length + 1, GFP_KERNEL); - - if (!dev->_filename_ch2) - goto error; - } else { - str_length = strlen(dev->_defaultname_ch2); - dev->_filename_ch2 = kmemdup(dev->_defaultname_ch2, - str_length + 1, GFP_KERNEL); + if (dev->input_filename_ch2) + dev->_filename_ch2 = kstrdup(dev->input_filename_ch2, + GFP_KERNEL); + else + dev->_filename_ch2 = kstrdup(dev->_defaultname_ch2, + GFP_KERNEL); - if (!dev->_filename_ch2) - goto error; + if (!dev->_filename_ch2) { + err = -ENOENT; + goto error; } /* Default if filename is empty string */ @@ -773,7 +771,7 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, } } - retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, + err = cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size_ch2, 0); /* setup fifo + format */ @@ -783,9 +781,9 @@ int cx25821_vidupstream_init_ch2(struct cx25821_dev *dev, int channel_select, dev->upstream_databuf_size_ch2 = data_frame_size * 2; /* Allocating buffers and prepare RISC program */ - retval = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, + err = cx25821_upstream_buffer_prepare_ch2(dev, sram_ch, dev->_line_size_ch2); - if (retval < 0) { + if (err < 0) { pr_err("%s: Failed to set up Video upstream buffers!\n", dev->name); goto error; diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 6759fff8eb6..7fc97110d97 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -173,10 +173,10 @@ static __le32 *cx25821_risc_field_upstream(struct cx25821_dev *dev, __le32 * rp, return rp; } -int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, - struct pci_dev *pci, - unsigned int top_offset, - unsigned int bpl, unsigned int lines) +static int cx25821_risc_buffer_upstream(struct cx25821_dev *dev, + struct pci_dev *pci, + unsigned int top_offset, + unsigned int bpl, unsigned int lines) { __le32 *rp; int fifo_enable = 0; @@ -300,7 +300,8 @@ void cx25821_free_mem_upstream_ch1(struct cx25821_dev *dev) } } -int cx25821_get_frame(struct cx25821_dev *dev, struct sram_channel *sram_ch) +static int cx25821_get_frame(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { struct file *myfile; int frame_index_temp = dev->_frame_index; @@ -405,7 +406,8 @@ static void cx25821_vidups_handler(struct work_struct *work) sram_channels); } -int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) +static int cx25821_openfile(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { struct file *myfile; int i = 0, j = 0; @@ -486,8 +488,9 @@ int cx25821_openfile(struct cx25821_dev *dev, struct sram_channel *sram_ch) return 0; } -int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, - struct sram_channel *sram_ch, int bpl) +static int cx25821_upstream_buffer_prepare(struct cx25821_dev *dev, + struct sram_channel *sram_ch, + int bpl) { int ret = 0; dma_addr_t dma_addr; @@ -548,8 +551,8 @@ error: return ret; } -int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, - u32 status) +static int cx25821_video_upstream_irq(struct cx25821_dev *dev, int chan_num, + u32 status) { u32 int_msk_tmp; struct sram_channel *channel = dev->channels[chan_num].sram_channels; @@ -664,8 +667,9 @@ static irqreturn_t cx25821_upstream_irq(int irq, void *dev_id) return IRQ_RETVAL(handled); } -void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch, - int pix_format) +static void cx25821_set_pixelengine(struct cx25821_dev *dev, + struct sram_channel *ch, + int pix_format) { int width = WIDTH_D1; int height = dev->_lines_count; @@ -696,8 +700,8 @@ void cx25821_set_pixelengine(struct cx25821_dev *dev, struct sram_channel *ch, cx_write(ch->vid_cdt_size, VID_CDT_SIZE >> 3); } -int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, - struct sram_channel *sram_ch) +static int cx25821_start_video_dma_upstream(struct cx25821_dev *dev, + struct sram_channel *sram_ch) { u32 tmp = 0; int err = 0; @@ -753,7 +757,6 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, { struct sram_channel *sram_ch; u32 tmp; - int retval = 0; int err = 0; int data_frame_size = 0; int risc_buffer_size = 0; @@ -796,15 +799,19 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->_filename = kmemdup(dev->input_filename, str_length + 1, GFP_KERNEL); - if (!dev->_filename) + if (!dev->_filename) { + err = -ENOENT; goto error; + } } else { str_length = strlen(dev->_defaultname); dev->_filename = kmemdup(dev->_defaultname, str_length + 1, GFP_KERNEL); - if (!dev->_filename) + if (!dev->_filename) { + err = -ENOENT; goto error; + } } /* Default if filename is empty string */ @@ -828,7 +835,7 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->_line_size = (dev->_pixel_format == PIXEL_FRMT_422) ? (WIDTH_D1 * 2) : (WIDTH_D1 * 3) / 2; - retval = cx25821_sram_channel_setup_upstream(dev, sram_ch, + err = cx25821_sram_channel_setup_upstream(dev, sram_ch, dev->_line_size, 0); /* setup fifo + format */ @@ -838,8 +845,8 @@ int cx25821_vidupstream_init_ch1(struct cx25821_dev *dev, int channel_select, dev->upstream_databuf_size = data_frame_size * 2; /* Allocating buffers and prepare RISC program */ - retval = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); - if (retval < 0) { + err = cx25821_upstream_buffer_prepare(dev, sram_ch, dev->_line_size); + if (err < 0) { pr_err("%s: Failed to set up Video upstream buffers!\n", dev->name); goto error; diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c index 0a80245165d..53b16dd7032 100644 --- a/drivers/media/pci/cx25821/cx25821-video.c +++ b/drivers/media/pci/cx25821/cx25821-video.c @@ -291,9 +291,9 @@ int cx25821_start_video_dma(struct cx25821_dev *dev, return 0; } -int cx25821_restart_video_queue(struct cx25821_dev *dev, - struct cx25821_dmaqueue *q, - struct sram_channel *channel) +static int cx25821_restart_video_queue(struct cx25821_dev *dev, + struct cx25821_dmaqueue *q, + struct sram_channel *channel) { struct cx25821_buffer *buf, *prev; struct list_head *item; @@ -342,7 +342,7 @@ int cx25821_restart_video_queue(struct cx25821_dev *dev, } } -void cx25821_vid_timeout(unsigned long data) +static void cx25821_vid_timeout(unsigned long data) { struct cx25821_data *timeout_data = (struct cx25821_data *)data; struct cx25821_dev *dev = timeout_data->dev; diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 3aa6856ead3..d2de1a913e1 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -45,11 +45,15 @@ #include "cx88.h" #include "cx88-reg.h" -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg) - -#define dprintk_core(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg);\ +} while(0) + +#define dprintk_core(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg);\ +} while(0) /**************************************************************************** Data type declarations - Can be moded to a header file later diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 62184eb919e..a6ff8a6f4fc 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -53,9 +53,10 @@ static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg) - +#define dprintk(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg); \ +} while(0) /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index c97b174be3a..19a58754c6e 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -646,22 +646,22 @@ int cx88_reset(struct cx88_core *core) /* ------------------------------------------------------------------ */ -static unsigned int inline norm_swidth(v4l2_std_id norm) +static inline unsigned int norm_swidth(v4l2_std_id norm) { return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; } -static unsigned int inline norm_hdelay(v4l2_std_id norm) +static inline unsigned int norm_hdelay(v4l2_std_id norm) { return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186; } -static unsigned int inline norm_vdelay(v4l2_std_id norm) +static inline unsigned int norm_vdelay(v4l2_std_id norm) { return (norm & V4L2_STD_625_50) ? 0x24 : 0x18; } -static unsigned int inline norm_fsc8(v4l2_std_id norm) +static inline unsigned int norm_fsc8(v4l2_std_id norm) { if (norm & V4L2_STD_PAL_M) return 28604892; // 3.575611 MHz @@ -681,7 +681,7 @@ static unsigned int inline norm_fsc8(v4l2_std_id norm) return 35468950; // 4.43361875 MHz +/- 5 Hz } -static unsigned int inline norm_htotal(v4l2_std_id norm) +static inline unsigned int norm_htotal(v4l2_std_id norm) { unsigned int fsc4=norm_fsc8(norm)/2; @@ -692,7 +692,7 @@ static unsigned int inline norm_htotal(v4l2_std_id norm) ((fsc4+262)/525*1001+15000)/30000; } -static unsigned int inline norm_vbipack(v4l2_std_id norm) +static inline unsigned int norm_vbipack(v4l2_std_id norm) { return (norm & V4L2_STD_625_50) ? 511 : 400; } diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index ebf448c48ca..f29e18c72f4 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -248,7 +248,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) struct cx88_IR *ir; struct rc_dev *dev; char *ir_codes = NULL; - u64 rc_type = RC_TYPE_OTHER; + u64 rc_type = RC_BIT_OTHER; int err = -ENOMEM; u32 hardware_mask = 0; /* For devices with a hardware mask, when * used with a full-code IR table @@ -416,7 +416,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) break; case CX88_BOARD_TWINHAN_VP1027_DVBS: ir_codes = RC_MAP_TWINHAN_VP1027_DVBS; - rc_type = RC_TYPE_NEC; + rc_type = RC_BIT_NEC; ir->sampling = 0xff00; /* address */ break; } @@ -592,7 +592,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) case CX88_BOARD_LEADTEK_PVR2000: addr_list = pvr2000_addr_list; core->init_data.name = "cx88 Leadtek PVR 2000 remote"; - core->init_data.type = RC_TYPE_UNKNOWN; + core->init_data.type = RC_BIT_UNKNOWN; core->init_data.get_key = get_key_pvr2000; core->init_data.ir_codes = RC_MAP_EMPTY; break; @@ -613,7 +613,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) /* Hauppauge XVR */ core->init_data.name = "cx88 Hauppauge XVR remote"; core->init_data.ir_codes = RC_MAP_HAUPPAUGE; - core->init_data.type = RC_TYPE_RC5; + core->init_data.type = RC_BIT_RC5; core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; info.platform_data = &core->init_data; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index d154bc19735..d46b008a46b 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -45,11 +45,15 @@ static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg); \ +} while(0) -#define mpeg_dbg(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg) +#define mpeg_dbg(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg); \ +} while(0) #if defined(CONFIG_MODULES) && defined(MODULE) static void request_module_async(struct work_struct *work) @@ -217,8 +221,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, return 0; buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue); if (NULL == prev) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); + list_move_tail(&buf->vb.queue, &q->active); cx8802_start_dma(dev, q, buf); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; @@ -229,8 +232,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue,&q->active); + list_move_tail(&buf->vb.queue, &q->active); buf->vb.state = VIDEOBUF_ACTIVE; buf->count = q->count++; prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 44ffc8b3d45..ba0dba4a4d2 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -94,13 +94,13 @@ enum cx8802_board_access { /* ----------------------------------------------------------- */ /* tv norms */ -static unsigned int inline norm_maxw(v4l2_std_id norm) +static inline unsigned int norm_maxw(v4l2_std_id norm) { return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; } -static unsigned int inline norm_maxh(v4l2_std_id norm) +static inline unsigned int norm_maxh(v4l2_std_id norm) { return (norm & V4L2_STD_625_50) ? 576 : 480; } diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index a609b3a9b14..f288ffcc4b6 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -736,7 +736,7 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id) return IRQ_HANDLED; } -int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) +static int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) { struct rc_dev *dev; int err = -ENOMEM; @@ -776,7 +776,7 @@ int __devinit dm1105_ir_init(struct dm1105_dev *dm1105) return 0; } -void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105) +static void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105) { rc_unregister_device(dm1105->ir.dev); } @@ -1128,8 +1128,10 @@ static int __devinit dm1105_probe(struct pci_dev *pdev, INIT_WORK(&dev->work, dm1105_dmx_buffer); sprintf(dev->wqn, "%s/%d", dvb_adapter->name, dvb_adapter->num); dev->wq = create_singlethread_workqueue(dev->wqn); - if (!dev->wq) + if (!dev->wq) { + ret = -ENOMEM; goto err_dvb_net; + } ret = request_irq(pdev->irq, dm1105_irq, IRQF_SHARED, DRIVER_NAME, dev); diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c index 8deab1629b3..4a221c69399 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-main.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c @@ -205,7 +205,7 @@ err_exit: return ret; } -int ivtv_alsa_load(struct ivtv *itv) +static int __init ivtv_alsa_load(struct ivtv *itv) { struct v4l2_device *v4l2_dev = &itv->v4l2_dev; struct ivtv_stream *s; diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c index f7022bd58ff..e1863dbf4ed 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c @@ -37,6 +37,7 @@ #include "ivtv-streams.h" #include "ivtv-fileops.h" #include "ivtv-alsa.h" +#include "ivtv-alsa-pcm.h" static unsigned int pcm_debug; module_param(pcm_debug, int, 0644); @@ -69,8 +70,9 @@ static struct snd_pcm_hardware snd_ivtv_hw_capture = { .periods_max = 98, /* 12544, */ }; -void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc, u8 *pcm_data, - size_t num_bytes) +static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc, + u8 *pcm_data, + size_t num_bytes) { struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.h b/drivers/media/pci/ivtv/ivtv-alsa-pcm.h index 5ab18319ea4..23dfe0d1240 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.h +++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.h @@ -21,7 +21,3 @@ */ int __init snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc); - -/* Used by ivtv driver to announce the PCM data to the module */ -void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *card, u8 *pcm_data, - size_t num_bytes); diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index 6ec7705af55..68387d4369d 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -276,7 +276,7 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv) } /* Try to restart the card & restore previous settings */ -int ivtv_firmware_restart(struct ivtv *itv) +static int ivtv_firmware_restart(struct ivtv *itv) { int rc = 0; v4l2_std_id std; diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c index d47f41a0ef6..46e262becb6 100644 --- a/drivers/media/pci/ivtv/ivtv-i2c.c +++ b/drivers/media/pci/ivtv/ivtv-i2c.c @@ -200,21 +200,21 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS; init_data->internal_get_key_func = IR_KBD_GET_KEY_AVERMEDIA_CARDBUS; - init_data->type = RC_TYPE_OTHER; + init_data->type = RC_BIT_OTHER; init_data->name = "AVerMedia AVerTV card"; break; case IVTV_HW_I2C_IR_RX_HAUP_EXT: case IVTV_HW_I2C_IR_RX_HAUP_INT: init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_TYPE_RC5; + init_data->type = RC_BIT_RC5; init_data->name = itv->card_name; break; case IVTV_HW_Z8F0811_IR_RX_HAUP: /* Default to grey remote */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; + init_data->type = RC_BIT_RC5; init_data->name = itv->card_name; break; case IVTV_HW_I2C_IR_RX_ADAPTEC: @@ -222,7 +222,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr) init_data->name = itv->card_name; /* FIXME: The protocol and RC_MAP needs to be corrected */ init_data->ir_codes = RC_MAP_EMPTY; - init_data->type = RC_TYPE_UNKNOWN; + init_data->type = RC_BIT_UNKNOWN; break; } diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c index 949ae230e11..7a8b0d0b612 100644 --- a/drivers/media/pci/ivtv/ivtv-ioctl.c +++ b/drivers/media/pci/ivtv/ivtv-ioctl.c @@ -993,7 +993,7 @@ int ivtv_s_input(struct file *file, void *fh, unsigned int inp) v4l2_std_id std; int i; - if (inp < 0 || inp >= itv->nof_inputs) + if (inp >= itv->nof_inputs) return -EINVAL; if (inp == itv->active_input) { @@ -1168,7 +1168,7 @@ void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id *std) } } -int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) +static int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std) { struct ivtv *itv = fh2id(fh)->itv; diff --git a/drivers/media/pci/mantis/mantis_input.c b/drivers/media/pci/mantis/mantis_input.c index db6d54d3fec..0e5252e5c0e 100644 --- a/drivers/media/pci/mantis/mantis_input.c +++ b/drivers/media/pci/mantis/mantis_input.c @@ -18,6 +18,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#if 0 /* Currently unused */ + #include <media/rc-core.h> #include <linux/pci.h> @@ -150,10 +152,11 @@ out: return err; } -int mantis_exit(struct mantis_pci *mantis) +int mantis_init_exit(struct mantis_pci *mantis) { rc_unregister_device(mantis->rc); rc_map_unregister(&ir_mantis_map); return 0; } +#endif diff --git a/drivers/media/pci/mantis/mantis_uart.c b/drivers/media/pci/mantis/mantis_uart.c index 85e977861b4..a7071921863 100644 --- a/drivers/media/pci/mantis/mantis_uart.c +++ b/drivers/media/pci/mantis/mantis_uart.c @@ -61,7 +61,7 @@ static struct { #define UART_MAX_BUF 16 -int mantis_uart_read(struct mantis_pci *mantis, u8 *data) +static int mantis_uart_read(struct mantis_pci *mantis, u8 *data) { struct mantis_hwconfig *config = mantis->hwconfig; u32 stat = 0, i; diff --git a/drivers/media/pci/mantis/mantis_vp1033.c b/drivers/media/pci/mantis/mantis_vp1033.c index ad013e93ed1..115003e8d19 100644 --- a/drivers/media/pci/mantis/mantis_vp1033.c +++ b/drivers/media/pci/mantis/mantis_vp1033.c @@ -83,7 +83,7 @@ u8 lgtdqcs001f_inittab[] = { #define MANTIS_MODEL_NAME "VP-1033" #define MANTIS_DEV_TYPE "DVB-S/DSS" -int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) +static int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct mantis_pci *mantis = fe->dvb->priv; @@ -115,8 +115,8 @@ int lgtdqcs001f_tuner_set(struct dvb_frontend *fe) return 0; } -int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) +static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe, + u32 srate, u32 ratio) { u8 aclk = 0; u8 bclk = 0; diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index e5a76da8608..ae7d32027bf 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -1945,7 +1945,7 @@ static struct pci_driver meye_driver = { static int __init meye_init(void) { gbuffers = max(2, min((int)gbuffers, MEYE_MAX_BUFNBRS)); - if (gbufsize < 0 || gbufsize > MEYE_MAX_BUFSIZE) + if (gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; gbufsize = PAGE_ALIGN(gbufsize); printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " diff --git a/drivers/media/pci/ngene/ngene-cards.c b/drivers/media/pci/ngene/ngene-cards.c index 96a13ed197d..b38bce52956 100644 --- a/drivers/media/pci/ngene/ngene-cards.c +++ b/drivers/media/pci/ngene/ngene-cards.c @@ -425,8 +425,10 @@ static int ReadEEProm(struct i2c_adapter *adapter, status = i2c_read_eeprom(adapter, 0x50, Addr, data, Length); if (!status) { *pLength = EETag[2]; +#if 0 if (Length < EETag[2]) - ; /*status=STATUS_BUFFER_OVERFLOW; */ + status = STATUS_BUFFER_OVERFLOW; +#endif } } return status; diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c index c8e0d5b99d4..8eeec4f50cc 100644 --- a/drivers/media/pci/ngene/ngene-core.c +++ b/drivers/media/pci/ngene/ngene-core.c @@ -752,8 +752,8 @@ void set_transfer(struct ngene_channel *chan, int state) if (chan->mode & NGENE_IO_TSIN) chan->pBufferExchange = tsin_exchange; spin_unlock_irq(&chan->state_lock); - } else - ;/* printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", + } + /* else printk(KERN_INFO DEVICE_NAME ": lock=%08x\n", ngreadl(0x9310)); */ ret = ngene_command_stream_control(dev, chan->number, @@ -1691,7 +1691,8 @@ int __devinit ngene_probe(struct pci_dev *pci_dev, dev->i2c_current_bus = -1; /* Register DVB adapters and devices for both channels */ - if (init_channels(dev) < 0) + stat = init_channels(dev); + if (stat < 0) goto fail2; return 0; diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index f2b37e05b96..8976d0e6581 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -944,8 +944,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* board config */ dev->board = pci_id->driver_data; - if (card[dev->nr] >= 0 && - card[dev->nr] < saa7134_bcount) + if ((unsigned)card[dev->nr] < saa7134_bcount) dev->board = card[dev->nr]; if (SAA7134_BOARD_UNKNOWN == dev->board) must_configure_manually(0); diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index 0f78f5e537e..e761262f747 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -990,7 +990,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev) dev->init_data.name = "BeholdTV"; dev->init_data.get_key = get_key_beholdm6xx; dev->init_data.ir_codes = RC_MAP_BEHOLD; - dev->init_data.type = RC_TYPE_NEC; + dev->init_data.type = RC_BIT_NEC; info.addr = 0x2d; break; case SAA7134_BOARD_AVERMEDIA_CARDBUS_501: diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c index 4a77124ee70..3abf52711e1 100644 --- a/drivers/media/pci/saa7134/saa7134-video.c +++ b/drivers/media/pci/saa7134/saa7134-video.c @@ -2511,7 +2511,7 @@ int saa7134_video_init1(struct saa7134_dev *dev) /* sanitycheck insmod options */ if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) gbuffers = 2; - if (gbufsize < 0 || gbufsize > gbufsize_max) + if (gbufsize > gbufsize_max) gbufsize = gbufsize_max; gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; diff --git a/drivers/media/pci/saa7164/saa7164-api.c b/drivers/media/pci/saa7164/saa7164-api.c index eff7135cf0e..e042963d377 100644 --- a/drivers/media/pci/saa7164/saa7164-api.c +++ b/drivers/media/pci/saa7164/saa7164-api.c @@ -165,7 +165,7 @@ int saa7164_api_set_vbi_format(struct saa7164_port *port) return ret; } -int saa7164_api_set_gop_size(struct saa7164_port *port) +static int saa7164_api_set_gop_size(struct saa7164_port *port) { struct saa7164_dev *dev = port->dev; struct tmComResEncVideoGopStructure gs; @@ -619,7 +619,7 @@ int saa7164_api_get_videomux(struct saa7164_port *port) return ret; } -int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) +static int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val) { struct saa7164_dev *dev = port->dev; @@ -822,8 +822,8 @@ int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen) ®[0], 128, buf); } -int saa7164_api_configure_port_vbi(struct saa7164_dev *dev, - struct saa7164_port *port) +static int saa7164_api_configure_port_vbi(struct saa7164_dev *dev, + struct saa7164_port *port) { struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc; @@ -858,9 +858,10 @@ int saa7164_api_configure_port_vbi(struct saa7164_dev *dev, return 0; } -int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, - struct saa7164_port *port, - struct tmComResTSFormatDescrHeader *tsfmt) +static int +saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, + struct saa7164_port *port, + struct tmComResTSFormatDescrHeader *tsfmt) { dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex); dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset); @@ -892,9 +893,10 @@ int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev, return 0; } -int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, - struct saa7164_port *port, - struct tmComResPSFormatDescrHeader *fmt) +static int +saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, + struct saa7164_port *port, + struct tmComResPSFormatDescrHeader *fmt) { dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex); dprintk(DBGLVL_API, " wPacketLength= 0x%x\n", fmt->wPacketLength); @@ -925,7 +927,7 @@ int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev, return 0; } -int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) +static int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len) { struct saa7164_port *tsport = NULL; struct saa7164_port *encport = NULL; @@ -1486,7 +1488,7 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen, return ret == SAA_OK ? 0 : -EIO; } -int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, +static int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid, u8 pin, u8 state) { int ret; diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c index a7f58a99875..5f6f3094c44 100644 --- a/drivers/media/pci/saa7164/saa7164-bus.c +++ b/drivers/media/pci/saa7164/saa7164-bus.c @@ -81,7 +81,7 @@ void saa7164_bus_dump(struct saa7164_dev *dev) } /* Intensionally throw a BUG() if the state of the message bus looks corrupt */ -void saa7164_bus_verify(struct saa7164_dev *dev) +static void saa7164_bus_verify(struct saa7164_dev *dev) { struct tmComResBusInfo *b = &dev->bus; int bug = 0; @@ -106,8 +106,8 @@ void saa7164_bus_verify(struct saa7164_dev *dev) } } -void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m, - void *buf) +static void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo *m, + void *buf) { dprintk(DBGLVL_BUS, "Dumping msg structure:\n"); dprintk(DBGLVL_BUS, " .id = %d\n", m->id); diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index 62fac7f9d04..cfabcbacc33 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c @@ -23,7 +23,7 @@ #include "saa7164.h" -int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev) +static int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev) { int i, ret = -1; @@ -42,7 +42,7 @@ int saa7164_cmd_alloc_seqno(struct saa7164_dev *dev) return ret; } -void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno) +static void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno) { mutex_lock(&dev->lock); if ((dev->cmds[seqno].inuse == 1) && @@ -54,7 +54,7 @@ void saa7164_cmd_free_seqno(struct saa7164_dev *dev, u8 seqno) mutex_unlock(&dev->lock); } -void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno) +static void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno) { mutex_lock(&dev->lock); if ((dev->cmds[seqno].inuse == 1) && @@ -64,7 +64,7 @@ void saa7164_cmd_timeout_seqno(struct saa7164_dev *dev, u8 seqno) mutex_unlock(&dev->lock); } -u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno) +static u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno) { int ret = 0; @@ -132,7 +132,7 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev) /* Commands to the f/w get marshelled to/from this code then onto the PCI * -bus/c running buffer. */ -int saa7164_cmd_dequeue(struct saa7164_dev *dev) +static int saa7164_cmd_dequeue(struct saa7164_dev *dev) { int loop = 1; int ret; @@ -186,8 +186,8 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev) return SAA_OK; } -int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg, - void *buf) +static int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg, + void *buf) { struct tmComResBusInfo *bus = &dev->bus; u8 cmd_sent; @@ -259,7 +259,7 @@ out: /* Wait for a signal event, without holding a mutex. Either return TIMEOUT if * the event never occurred, or SAA_OK if it was signaled during the wait. */ -int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) +static int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) { wait_queue_head_t *q = NULL; int ret = SAA_BUS_TIMEOUT; diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 2c9ad878bef..063047f5676 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -410,7 +410,7 @@ static void saa7164_work_enchandler(struct work_struct *w) } else rp = (port->last_svc_rp + 1) % 8; - if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) { + if (rp > (port->hwcfg.buffercount - 1)) { printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp); break; } @@ -486,7 +486,7 @@ static void saa7164_work_vbihandler(struct work_struct *w) } else rp = (port->last_svc_rp + 1) % 8; - if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) { + if (rp > (port->hwcfg.buffercount - 1)) { printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp); break; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index a9ed686ad08..994018e2d0d 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -1101,7 +1101,8 @@ static int fops_release(struct file *file) return 0; } -struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) +static struct +saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port) { struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; @@ -1287,8 +1288,8 @@ static const struct v4l2_file_operations mpeg_fops = { .unlocked_ioctl = video_ioctl2, }; -int saa7164_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) +static int saa7164_g_chip_ident(struct file *file, void *fh, + struct v4l2_dbg_chip_ident *chip) { struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; struct saa7164_dev *dev = port->dev; @@ -1297,8 +1298,8 @@ int saa7164_g_chip_ident(struct file *file, void *fh, return 0; } -int saa7164_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) +static int saa7164_g_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) { struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; struct saa7164_dev *dev = port->dev; @@ -1310,8 +1311,8 @@ int saa7164_g_register(struct file *file, void *fh, return 0; } -int saa7164_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) +static int saa7164_s_register(struct file *file, void *fh, + struct v4l2_dbg_register *reg) { struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port; struct saa7164_dev *dev = port->dev; diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index a266bf0169e..86763203d61 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -37,7 +37,7 @@ struct fw_header { u32 version; }; -int saa7164_dl_wait_ack(struct saa7164_dev *dev, u32 reg) +static int saa7164_dl_wait_ack(struct saa7164_dev *dev, u32 reg) { u32 timeout = SAA_DEVICE_TIMEOUT; while ((saa7164_readl(reg) & 0x01) == 0) { @@ -53,7 +53,7 @@ int saa7164_dl_wait_ack(struct saa7164_dev *dev, u32 reg) return 0; } -int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg) +static int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg) { u32 timeout = SAA_DEVICE_TIMEOUT; while (saa7164_readl(reg) & 0x01) { @@ -71,8 +71,8 @@ int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg) /* TODO: move dlflags into dev-> and change to write/readl/b */ /* TODO: Excessive levels of debug */ -int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize, - u32 dlflags, u8 *dst, u32 dstsize) +static int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize, + u32 dlflags, u8 *dst, u32 dstsize) { u32 reg, timeout, offset; u8 *srcbuf = NULL; diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index d8e6c8f1407..b4532299c0e 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -984,7 +984,8 @@ out: return ret; } -int saa7164_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) +static int saa7164_vbi_fmt(struct file *file, void *priv, + struct v4l2_format *f) { /* ntsc */ f->fmt.vbi.samples_per_line = 1600; @@ -1047,7 +1048,8 @@ static int fops_release(struct file *file) return 0; } -struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) +static struct +saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port) { struct saa7164_user_buffer *ubuf = NULL; struct saa7164_dev *dev = port->dev; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 88b3b2d6cc0..a378662b1dc 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -6,6 +6,7 @@ #include <linux/netdevice.h> #include <linux/i2c.h> #include <linux/input.h> +#include <linux/time.h> #include <linux/dvb/video.h> #include <linux/dvb/audio.h> diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 12ddb53c58d..1f8b1bb0bf9 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -1477,8 +1477,8 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio if (saa7113_init(budget_av) == 0) { budget_av->has_saa7113 = 1; - - if (0 != saa7146_vv_init(dev, &vv_data)) { + err = saa7146_vv_init(dev, &vv_data); + if (err != 0) { /* fixme: proper cleanup here */ ERR("cannot init vv subsystem\n"); return err; diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 181c7686e41..3dcfea612c4 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -109,6 +109,18 @@ config VIDEO_OMAP3_DEBUG ---help--- Enable debug messages on OMAP 3 camera controller driver. +config VIDEO_S3C_CAMIF + tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on (PLAT_S3C64XX || PLAT_S3C24XX) && PM_RUNTIME + select VIDEOBUF2_DMA_CONTIG + ---help--- + This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera + host interface (CAMIF). + + To compile this driver as a module, choose M here: the module + will be called s3c-camif. + source "drivers/media/platform/soc_camera/Kconfig" source "drivers/media/platform/s5p-fimc/Kconfig" source "drivers/media/platform/s5p-tv/Kconfig" diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index baaa55026c8..4817d280217 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_VIDEO_CODA) += coda.o obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o +obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index cb2eb26850b..ec476ef5b70 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -1050,19 +1050,7 @@ static struct platform_driver bcap_driver = { .probe = bcap_probe, .remove = __devexit_p(bcap_remove), }; - -static __init int bcap_init(void) -{ - return platform_driver_register(&bcap_driver); -} - -static __exit void bcap_exit(void) -{ - platform_driver_unregister(&bcap_driver); -} - -module_init(bcap_init); -module_exit(bcap_exit); +module_platform_driver(bcap_driver); MODULE_DESCRIPTION("Analog Devices blackfin video capture driver"); MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>"); diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c index cd04ae252c3..7b8b547f2d5 100644 --- a/drivers/media/platform/coda.c +++ b/drivers/media/platform/coda.c @@ -1540,7 +1540,7 @@ static irqreturn_t coda_irq_handler(int irq, void *data) u32 wr_ptr, start_ptr; struct coda_ctx *ctx; - __cancel_delayed_work(&dev->timeout); + cancel_delayed_work(&dev->timeout); /* read status register to attend the IRQ */ coda_read(dev, CODA_REG_BIT_INT_STATUS); @@ -1877,7 +1877,7 @@ static const struct coda_devtype coda_devdata[] = { static struct platform_device_id coda_platform_ids[] = { { .name = "coda-imx27", .driver_data = CODA_IMX27 }, - { .name = "coda-imx53", .driver_data = CODA_7541 }, + { .name = "coda-imx53", .driver_data = CODA_IMX53 }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, coda_platform_ids); diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig index 78e26d24f63..3c56037c82f 100644 --- a/drivers/media/platform/davinci/Kconfig +++ b/drivers/media/platform/davinci/Kconfig @@ -101,7 +101,7 @@ config VIDEO_DM644X_VPBE tristate "DM644X VPBE HW module" depends on ARCH_DAVINCI_DM644x select VIDEO_VPSS_SYSTEM - select VIDEOBUF_DMA_CONTIG + select VIDEOBUF2_DMA_CONTIG help Enables VPBE modules used for display on a DM644x SoC. diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index ce0e4131c06..030950dcfb1 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -1003,7 +1003,7 @@ static int __devinit dm355_ccdc_probe(struct platform_device *pdev) status = PTR_ERR(ccdc_cfg.mclk); goto fail_nomap; } - if (clk_enable(ccdc_cfg.mclk)) { + if (clk_prepare_enable(ccdc_cfg.mclk)) { status = -ENODEV; goto fail_mclk; } @@ -1014,7 +1014,7 @@ static int __devinit dm355_ccdc_probe(struct platform_device *pdev) status = PTR_ERR(ccdc_cfg.sclk); goto fail_mclk; } - if (clk_enable(ccdc_cfg.sclk)) { + if (clk_prepare_enable(ccdc_cfg.sclk)) { status = -ENODEV; goto fail_sclk; } @@ -1034,8 +1034,10 @@ static int __devinit dm355_ccdc_probe(struct platform_device *pdev) printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; fail_sclk: + clk_disable_unprepare(ccdc_cfg.sclk); clk_put(ccdc_cfg.sclk); fail_mclk: + clk_disable_unprepare(ccdc_cfg.mclk); clk_put(ccdc_cfg.mclk); fail_nomap: iounmap(ccdc_cfg.base_addr); @@ -1050,6 +1052,8 @@ static int dm355_ccdc_remove(struct platform_device *pdev) { struct resource *res; + clk_disable_unprepare(ccdc_cfg.sclk); + clk_disable_unprepare(ccdc_cfg.mclk); clk_put(ccdc_cfg.mclk); clk_put(ccdc_cfg.sclk); iounmap(ccdc_cfg.base_addr); diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index ee7942b1996..0215ab6ebc9 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -994,7 +994,7 @@ static int __devinit dm644x_ccdc_probe(struct platform_device *pdev) status = PTR_ERR(ccdc_cfg.mclk); goto fail_nomap; } - if (clk_enable(ccdc_cfg.mclk)) { + if (clk_prepare_enable(ccdc_cfg.mclk)) { status = -ENODEV; goto fail_mclk; } @@ -1005,7 +1005,7 @@ static int __devinit dm644x_ccdc_probe(struct platform_device *pdev) status = PTR_ERR(ccdc_cfg.sclk); goto fail_mclk; } - if (clk_enable(ccdc_cfg.sclk)) { + if (clk_prepare_enable(ccdc_cfg.sclk)) { status = -ENODEV; goto fail_sclk; } @@ -1013,8 +1013,10 @@ static int __devinit dm644x_ccdc_probe(struct platform_device *pdev) printk(KERN_NOTICE "%s is registered with vpfe.\n", ccdc_hw_dev.name); return 0; fail_sclk: + clk_disable_unprepare(ccdc_cfg.sclk); clk_put(ccdc_cfg.sclk); fail_mclk: + clk_disable_unprepare(ccdc_cfg.mclk); clk_put(ccdc_cfg.mclk); fail_nomap: iounmap(ccdc_cfg.base_addr); @@ -1029,6 +1031,8 @@ static int dm644x_ccdc_remove(struct platform_device *pdev) { struct resource *res; + clk_disable_unprepare(ccdc_cfg.mclk); + clk_disable_unprepare(ccdc_cfg.sclk); clk_put(ccdc_cfg.mclk); clk_put(ccdc_cfg.sclk); iounmap(ccdc_cfg.base_addr); @@ -1046,8 +1050,8 @@ static int dm644x_ccdc_suspend(struct device *dev) /* Disable CCDC */ ccdc_enable(0); /* Disable both master and slave clock */ - clk_disable(ccdc_cfg.mclk); - clk_disable(ccdc_cfg.sclk); + clk_disable_unprepare(ccdc_cfg.mclk); + clk_disable_unprepare(ccdc_cfg.sclk); return 0; } @@ -1055,8 +1059,8 @@ static int dm644x_ccdc_suspend(struct device *dev) static int dm644x_ccdc_resume(struct device *dev) { /* Enable both master and slave clock */ - clk_enable(ccdc_cfg.mclk); - clk_enable(ccdc_cfg.sclk); + clk_prepare_enable(ccdc_cfg.mclk); + clk_prepare_enable(ccdc_cfg.sclk); /* Restore CCDC context */ ccdc_restore_context(); diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index b99d5423e3a..2c26c3e1837 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -1053,7 +1053,7 @@ static int __devinit isif_probe(struct platform_device *pdev) status = PTR_ERR(isif_cfg.mclk); goto fail_mclk; } - if (clk_enable(isif_cfg.mclk)) { + if (clk_prepare_enable(isif_cfg.mclk)) { status = -ENODEV; goto fail_mclk; } @@ -1125,6 +1125,7 @@ fail_nobase_res: i--; } fail_mclk: + clk_disable_unprepare(isif_cfg.mclk); clk_put(isif_cfg.mclk); vpfe_unregister_ccdc_device(&isif_hw_dev); return status; @@ -1145,6 +1146,8 @@ static int isif_remove(struct platform_device *pdev) i++; } vpfe_unregister_ccdc_device(&isif_hw_dev); + clk_disable_unprepare(isif_cfg.mclk); + clk_put(isif_cfg.mclk); return 0; } diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 69d7a58c92c..7f5cf9b347b 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -612,7 +612,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) ret = PTR_ERR(vpbe_dev->dac_clk); goto fail_mutex_unlock; } - if (clk_enable(vpbe_dev->dac_clk)) { + if (clk_prepare_enable(vpbe_dev->dac_clk)) { ret = -ENODEV; goto fail_mutex_unlock; } @@ -759,8 +759,10 @@ fail_kfree_encoders: fail_dev_unregister: v4l2_device_unregister(&vpbe_dev->v4l2_dev); fail_clk_put: - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + clk_disable_unprepare(vpbe_dev->dac_clk); clk_put(vpbe_dev->dac_clk); + } fail_mutex_unlock: mutex_unlock(&vpbe_dev->lock); return ret; @@ -777,8 +779,10 @@ fail_mutex_unlock: static void vpbe_deinitialize(struct device *dev, struct vpbe_device *vpbe_dev) { v4l2_device_unregister(&vpbe_dev->v4l2_dev); - if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) + if (strcmp(vpbe_dev->cfg->module_name, "dm644x-vpbe-display") != 0) { + clk_disable_unprepare(vpbe_dev->dac_clk); clk_put(vpbe_dev->dac_clk); + } kfree(vpbe_dev->amp); kfree(vpbe_dev->encoders); diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c index 161c77650e2..2bfde7958fe 100644 --- a/drivers/media/platform/davinci/vpbe_display.c +++ b/drivers/media/platform/davinci/vpbe_display.c @@ -47,6 +47,9 @@ static int debug; module_param(debug, int, 0644); +static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, + struct vpbe_layer *layer); + static int venc_is_second_field(struct vpbe_display *disp_dev) { struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev; @@ -73,10 +76,11 @@ static void vpbe_isr_even_field(struct vpbe_display *disp_obj, if (layer->cur_frm == layer->next_frm) return; ktime_get_ts(&timevalue); - layer->cur_frm->ts.tv_sec = timevalue.tv_sec; - layer->cur_frm->ts.tv_usec = timevalue.tv_nsec / NSEC_PER_USEC; - layer->cur_frm->state = VIDEOBUF_DONE; - wake_up_interruptible(&layer->cur_frm->done); + layer->cur_frm->vb.v4l2_buf.timestamp.tv_sec = + timevalue.tv_sec; + layer->cur_frm->vb.v4l2_buf.timestamp.tv_usec = + timevalue.tv_nsec / NSEC_PER_USEC; + vb2_buffer_done(&layer->cur_frm->vb, VB2_BUF_STATE_DONE); /* Make cur_frm pointing to next_frm */ layer->cur_frm = layer->next_frm; } @@ -99,16 +103,14 @@ static void vpbe_isr_odd_field(struct vpbe_display *disp_obj, * otherwise hold on current frame * Get next from the buffer queue */ - layer->next_frm = list_entry( - layer->dma_queue.next, - struct videobuf_buffer, - queue); + layer->next_frm = list_entry(layer->dma_queue.next, + struct vpbe_disp_buffer, list); /* Remove that from the buffer queue */ - list_del(&layer->next_frm->queue); + list_del(&layer->next_frm->list); spin_unlock(&disp_obj->dma_queue_lock); /* Mark state of the frame to active */ - layer->next_frm->state = VIDEOBUF_ACTIVE; - addr = videobuf_to_dma_contig(layer->next_frm); + layer->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; + addr = vb2_dma_contig_plane_dma_addr(&layer->next_frm->vb, 0); osd_device->ops.start_layer(osd_device, layer->layer_info.id, addr, @@ -199,39 +201,29 @@ static irqreturn_t venc_isr(int irq, void *arg) /* * vpbe_buffer_prepare() - * This is the callback function called from videobuf_qbuf() function + * This is the callback function called from vb2_qbuf() function * the buffer is prepared and user space virtual address is converted into * physical address */ -static int vpbe_buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int vpbe_buffer_prepare(struct vb2_buffer *vb) { - struct vpbe_fh *fh = q->priv_data; + struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_queue *q = vb->vb2_queue; struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; unsigned long addr; - int ret; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_prepare\n"); - /* If buffer is not initialized, initialize it */ - if (VIDEOBUF_NEEDS_INIT == vb->state) { - vb->width = layer->pix_fmt.width; - vb->height = layer->pix_fmt.height; - vb->size = layer->pix_fmt.sizeimage; - vb->field = field; - - ret = videobuf_iolock(q, vb, NULL); - if (ret < 0) { - v4l2_err(&vpbe_dev->v4l2_dev, "Failed to map \ - user address\n"); + if (vb->state != VB2_BUF_STATE_ACTIVE && + vb->state != VB2_BUF_STATE_PREPARED) { + vb2_set_plane_payload(vb, 0, layer->pix_fmt.sizeimage); + if (vb2_plane_vaddr(vb, 0) && + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) return -EINVAL; - } - - addr = videobuf_to_dma_contig(vb); + addr = vb2_dma_contig_plane_dma_addr(vb, 0); if (q->streaming) { if (!IS_ALIGNED(addr, 8)) { v4l2_err(&vpbe_dev->v4l2_dev, @@ -240,7 +232,6 @@ static int vpbe_buffer_prepare(struct videobuf_queue *q, return -EINVAL; } } - vb->state = VIDEOBUF_PREPARED; } return 0; } @@ -249,22 +240,26 @@ static int vpbe_buffer_prepare(struct videobuf_queue *q, * vpbe_buffer_setup() * This function allocates memory for the buffers */ -static int vpbe_buffer_setup(struct videobuf_queue *q, - unsigned int *count, - unsigned int *size) +static int +vpbe_buffer_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) + { /* Get the file handle object and layer object */ - struct vpbe_fh *fh = q->priv_data; + struct vpbe_fh *fh = vb2_get_drv_priv(vq); struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n"); - *size = layer->pix_fmt.sizeimage; - /* Store number of buffers allocated in numbuffer member */ - if (*count < VPBE_DEFAULT_NUM_BUFS) - *count = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS; + if (*nbuffers < VPBE_DEFAULT_NUM_BUFS) + *nbuffers = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS; + + *nplanes = 1; + sizes[0] = layer->pix_fmt.sizeimage; + alloc_ctxs[0] = layer->alloc_ctx; return 0; } @@ -273,11 +268,12 @@ static int vpbe_buffer_setup(struct videobuf_queue *q, * vpbe_buffer_queue() * This function adds the buffer to DMA queue */ -static void vpbe_buffer_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpbe_buffer_queue(struct vb2_buffer *vb) { /* Get the file handle object and layer object */ - struct vpbe_fh *fh = q->priv_data; + struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); + struct vpbe_disp_buffer *buf = container_of(vb, + struct vpbe_disp_buffer, vb); struct vpbe_layer *layer = fh->layer; struct vpbe_display *disp = fh->disp_dev; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; @@ -288,39 +284,125 @@ static void vpbe_buffer_queue(struct videobuf_queue *q, /* add the buffer to the DMA queue */ spin_lock_irqsave(&disp->dma_queue_lock, flags); - list_add_tail(&vb->queue, &layer->dma_queue); + list_add_tail(&buf->list, &layer->dma_queue); spin_unlock_irqrestore(&disp->dma_queue_lock, flags); - /* Change state of the buffer */ - vb->state = VIDEOBUF_QUEUED; } /* - * vpbe_buffer_release() - * This function is called from the videobuf layer to free memory allocated to + * vpbe_buf_cleanup() + * This function is called from the vb2 layer to free memory allocated to * the buffers */ -static void vpbe_buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void vpbe_buf_cleanup(struct vb2_buffer *vb) { /* Get the file handle object and layer object */ - struct vpbe_fh *fh = q->priv_data; + struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue); struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + struct vpbe_disp_buffer *buf = container_of(vb, + struct vpbe_disp_buffer, vb); + unsigned long flags; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, - "vpbe_buffer_release\n"); + "vpbe_buf_cleanup\n"); + + spin_lock_irqsave(&layer->irqlock, flags); + if (vb->state == VB2_BUF_STATE_ACTIVE) + list_del_init(&buf->list); + spin_unlock_irqrestore(&layer->irqlock, flags); +} + +static void vpbe_wait_prepare(struct vb2_queue *vq) +{ + struct vpbe_fh *fh = vb2_get_drv_priv(vq); + struct vpbe_layer *layer = fh->layer; + + mutex_unlock(&layer->opslock); +} + +static void vpbe_wait_finish(struct vb2_queue *vq) +{ + struct vpbe_fh *fh = vb2_get_drv_priv(vq); + struct vpbe_layer *layer = fh->layer; + + mutex_lock(&layer->opslock); +} + +static int vpbe_buffer_init(struct vb2_buffer *vb) +{ + struct vpbe_disp_buffer *buf = container_of(vb, + struct vpbe_disp_buffer, vb); + + INIT_LIST_HEAD(&buf->list); + return 0; +} + +static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vpbe_fh *fh = vb2_get_drv_priv(vq); + struct vpbe_layer *layer = fh->layer; + struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + int ret; + + /* If buffer queue is empty, return error */ + if (list_empty(&layer->dma_queue)) { + v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); + return -EINVAL; + } + /* Get the next frame from the buffer queue */ + layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, + struct vpbe_disp_buffer, list); + /* Remove buffer from the buffer queue */ + list_del(&layer->cur_frm->list); + /* Mark state of the current frame to active */ + layer->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; + /* Initialize field_id and started member */ + layer->field_id = 0; + + /* Set parameters in OSD and VENC */ + ret = vpbe_set_osd_display_params(fh->disp_dev, layer); + if (ret < 0) + return ret; - if (V4L2_MEMORY_USERPTR != layer->memory) - videobuf_dma_contig_free(q, vb); + /* + * if request format is yuv420 semiplanar, need to + * enable both video windows + */ + layer->started = 1; + layer->layer_first_int = 1; + + return ret; +} + +static int vpbe_stop_streaming(struct vb2_queue *vq) +{ + struct vpbe_fh *fh = vb2_get_drv_priv(vq); + struct vpbe_layer *layer = fh->layer; + + if (!vb2_is_streaming(vq)) + return 0; + + /* release all active buffers */ + while (!list_empty(&layer->dma_queue)) { + layer->next_frm = list_entry(layer->dma_queue.next, + struct vpbe_disp_buffer, list); + list_del(&layer->next_frm->list); + vb2_buffer_done(&layer->next_frm->vb, VB2_BUF_STATE_ERROR); + } - vb->state = VIDEOBUF_NEEDS_INIT; + return 0; } -static struct videobuf_queue_ops video_qops = { - .buf_setup = vpbe_buffer_setup, +static struct vb2_ops video_qops = { + .queue_setup = vpbe_buffer_queue_setup, + .wait_prepare = vpbe_wait_prepare, + .wait_finish = vpbe_wait_finish, + .buf_init = vpbe_buffer_init, .buf_prepare = vpbe_buffer_prepare, + .start_streaming = vpbe_start_streaming, + .stop_streaming = vpbe_stop_streaming, + .buf_cleanup = vpbe_buf_cleanup, .buf_queue = vpbe_buffer_queue, - .buf_release = vpbe_buffer_release, }; static @@ -345,7 +427,7 @@ static int vpbe_set_osd_display_params(struct vpbe_display *disp_dev, unsigned long addr; int ret; - addr = videobuf_to_dma_contig(layer->cur_frm); + addr = vb2_dma_contig_plane_dma_addr(&layer->cur_frm->vb, 0); /* Set address in the display registers */ osd_device->ops.start_layer(osd_device, layer->layer_info.id, @@ -620,9 +702,12 @@ static int vpbe_display_querycap(struct file *file, void *priv, struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; cap->version = VPBE_DISPLAY_VERSION_CODE; - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; - strlcpy(cap->driver, VPBE_DISPLAY_DRIVER, sizeof(cap->driver)); - strlcpy(cap->bus_info, "platform", sizeof(cap->bus_info)); + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + snprintf(cap->driver, sizeof(cap->driver), "%s", + dev_name(vpbe_dev->pdev)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(vpbe_dev->pdev)); strlcpy(cap->card, vpbe_dev->cfg->module_name, sizeof(cap->card)); return 0; @@ -1161,7 +1246,7 @@ static int vpbe_display_streamoff(struct file *file, void *priv, osd_device->ops.disable_layer(osd_device, layer->layer_info.id); layer->started = 0; - ret = videobuf_streamoff(&layer->buffer_queue); + ret = vb2_streamoff(&layer->buffer_queue, buf_type); return ret; } @@ -1199,46 +1284,15 @@ static int vpbe_display_streamon(struct file *file, void *priv, } /* - * Call videobuf_streamon to start streaming + * Call vb2_streamon to start streaming * in videobuf */ - ret = videobuf_streamon(&layer->buffer_queue); + ret = vb2_streamon(&layer->buffer_queue, buf_type); if (ret) { v4l2_err(&vpbe_dev->v4l2_dev, - "error in videobuf_streamon\n"); + "error in vb2_streamon\n"); return ret; } - /* If buffer queue is empty, return error */ - if (list_empty(&layer->dma_queue)) { - v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n"); - goto streamoff; - } - /* Get the next frame from the buffer queue */ - layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next, - struct videobuf_buffer, queue); - /* Remove buffer from the buffer queue */ - list_del(&layer->cur_frm->queue); - /* Mark state of the current frame to active */ - layer->cur_frm->state = VIDEOBUF_ACTIVE; - /* Initialize field_id and started member */ - layer->field_id = 0; - - /* Set parameters in OSD and VENC */ - ret = vpbe_set_osd_display_params(disp_dev, layer); - if (ret < 0) - goto streamoff; - - /* - * if request format is yuv420 semiplanar, need to - * enable both video windows - */ - layer->started = 1; - - layer->layer_first_int = 1; - - return ret; -streamoff: - ret = videobuf_streamoff(&layer->buffer_queue); return ret; } @@ -1265,10 +1319,10 @@ static int vpbe_display_dqbuf(struct file *file, void *priv, } if (file->f_flags & O_NONBLOCK) /* Call videobuf_dqbuf for non blocking mode */ - ret = videobuf_dqbuf(&layer->buffer_queue, buf, 1); + ret = vb2_dqbuf(&layer->buffer_queue, buf, 1); else /* Call videobuf_dqbuf for blocking mode */ - ret = videobuf_dqbuf(&layer->buffer_queue, buf, 0); + ret = vb2_dqbuf(&layer->buffer_queue, buf, 0); return ret; } @@ -1295,7 +1349,7 @@ static int vpbe_display_qbuf(struct file *file, void *priv, return -EACCES; } - return videobuf_qbuf(&layer->buffer_queue, p); + return vb2_qbuf(&layer->buffer_queue, p); } static int vpbe_display_querybuf(struct file *file, void *priv, @@ -1304,7 +1358,6 @@ static int vpbe_display_querybuf(struct file *file, void *priv, struct vpbe_fh *fh = file->private_data; struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; - int ret; v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_QUERYBUF, layer id = %d\n", @@ -1314,11 +1367,8 @@ static int vpbe_display_querybuf(struct file *file, void *priv, v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n"); return -EINVAL; } - - /* Call videobuf_querybuf to get information */ - ret = videobuf_querybuf(&layer->buffer_queue, buf); - - return ret; + /* Call vb2_querybuf to get information */ + return vb2_querybuf(&layer->buffer_queue, buf); } static int vpbe_display_reqbufs(struct file *file, void *priv, @@ -1327,8 +1377,8 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, struct vpbe_fh *fh = file->private_data; struct vpbe_layer *layer = fh->layer; struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev; + struct vb2_queue *q; int ret; - v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n"); if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) { @@ -1342,15 +1392,26 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, return -EBUSY; } /* Initialize videobuf queue as per the buffer type */ - videobuf_queue_dma_contig_init(&layer->buffer_queue, - &video_qops, - vpbe_dev->pdev, - &layer->irqlock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - layer->pix_fmt.field, - sizeof(struct videobuf_buffer), - fh, NULL); + layer->alloc_ctx = vb2_dma_contig_init_ctx(vpbe_dev->pdev); + if (!layer->alloc_ctx) { + v4l2_err(&vpbe_dev->v4l2_dev, "Failed to get the context\n"); + return -EINVAL; + } + q = &layer->buffer_queue; + memset(q, 0, sizeof(*q)); + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->drv_priv = fh; + q->ops = &video_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct vpbe_disp_buffer); + ret = vb2_queue_init(q); + if (ret) { + v4l2_err(&vpbe_dev->v4l2_dev, "vb2_queue_init() failed\n"); + vb2_dma_contig_cleanup_ctx(layer->alloc_ctx); + return ret; + } /* Set io allowed member of file handle to TRUE */ fh->io_allowed = 1; /* Increment io usrs member of layer object to 1 */ @@ -1360,9 +1421,7 @@ static int vpbe_display_reqbufs(struct file *file, void *priv, /* Initialize buffer queue */ INIT_LIST_HEAD(&layer->dma_queue); /* Allocate buffers */ - ret = videobuf_reqbufs(&layer->buffer_queue, req_buf); - - return ret; + return vb2_reqbufs(q, req_buf); } /* @@ -1381,7 +1440,7 @@ static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma) if (mutex_lock_interruptible(&layer->opslock)) return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&layer->buffer_queue, vma); + ret = vb2_mmap(&layer->buffer_queue, vma); mutex_unlock(&layer->opslock); return ret; } @@ -1398,7 +1457,7 @@ static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait) v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n"); if (layer->started) { mutex_lock(&layer->opslock); - err = videobuf_poll_stream(filep, &layer->buffer_queue, wait); + err = vb2_poll(&layer->buffer_queue, filep, wait); mutex_unlock(&layer->opslock); } return err; @@ -1488,8 +1547,8 @@ static int vpbe_display_release(struct file *file) layer->layer_info.id); layer->started = 0; /* Free buffers allocated */ - videobuf_queue_cancel(&layer->buffer_queue); - videobuf_mmap_free(&layer->buffer_queue); + vb2_queue_release(&layer->buffer_queue); + vb2_dma_contig_cleanup_ctx(&layer->buffer_queue); } /* Decrement layer usrs counter */ diff --git a/drivers/media/platform/davinci/vpbe_osd.c b/drivers/media/platform/davinci/vpbe_osd.c index bba299dbf39..707f243f810 100644 --- a/drivers/media/platform/davinci/vpbe_osd.c +++ b/drivers/media/platform/davinci/vpbe_osd.c @@ -62,7 +62,7 @@ static inline u32 osd_set(struct osd_state *sd, u32 mask, u32 offset) { struct osd_state *osd = sd; - u32 addr = osd->osd_base + offset; + void __iomem *addr = osd->osd_base + offset; u32 val = readl(addr) | mask; writel(val, addr); @@ -74,7 +74,7 @@ static inline u32 osd_clear(struct osd_state *sd, u32 mask, u32 offset) { struct osd_state *osd = sd; - u32 addr = osd->osd_base + offset; + void __iomem *addr = osd->osd_base + offset; u32 val = readl(addr) & ~mask; writel(val, addr); @@ -87,7 +87,7 @@ static inline u32 osd_modify(struct osd_state *sd, u32 mask, u32 val, { struct osd_state *osd = sd; - u32 addr = osd->osd_base + offset; + void __iomem *addr = osd->osd_base + offset; u32 new_val = (readl(addr) & ~mask) | (val & mask); writel(new_val, addr); @@ -1559,8 +1559,7 @@ static int osd_probe(struct platform_device *pdev) ret = -ENODEV; goto free_mem; } - osd->osd_base = (unsigned long)ioremap_nocache(res->start, - osd->osd_size); + osd->osd_base = ioremap_nocache(res->start, osd->osd_size); if (!osd->osd_base) { dev_err(osd->dev, "Unable to map the OSD region\n"); ret = -ENODEV; diff --git a/drivers/media/platform/davinci/vpif.c b/drivers/media/platform/davinci/vpif.c index cff3c0ab501..0d6cc8e4deb 100644 --- a/drivers/media/platform/davinci/vpif.c +++ b/drivers/media/platform/davinci/vpif.c @@ -444,7 +444,7 @@ static int __devinit vpif_probe(struct platform_device *pdev) status = PTR_ERR(vpif_clk); goto clk_fail; } - clk_enable(vpif_clk); + clk_prepare_enable(vpif_clk); spin_lock_init(&vpif_lock); dev_info(&pdev->dev, "vpif probe success\n"); @@ -460,7 +460,7 @@ fail: static int __devexit vpif_remove(struct platform_device *pdev) { if (vpif_clk) { - clk_disable(vpif_clk); + clk_disable_unprepare(vpif_clk); clk_put(vpif_clk); } @@ -472,13 +472,13 @@ static int __devexit vpif_remove(struct platform_device *pdev) #ifdef CONFIG_PM static int vpif_suspend(struct device *dev) { - clk_disable(vpif_clk); + clk_disable_unprepare(vpif_clk); return 0; } static int vpif_resume(struct device *dev) { - clk_enable(vpif_clk); + clk_prepare_enable(vpif_clk); return 0; } diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index fcabc023885..a409ccefb38 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -201,13 +201,16 @@ static void vpif_buffer_queue(struct vb2_buffer *vb) struct vpif_cap_buffer *buf = container_of(vb, struct vpif_cap_buffer, vb); struct common_obj *common; + unsigned long flags; common = &ch->common[VPIF_VIDEO_INDEX]; vpif_dbg(2, debug, "vpif_buffer_queue\n"); + spin_lock_irqsave(&common->irqlock, flags); /* add the buffer to the DMA queue */ list_add_tail(&buf->list, &common->dma_queue); + spin_unlock_irqrestore(&common->irqlock, flags); } /** @@ -278,10 +281,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct vpif_params *vpif = &ch->vpifparams; unsigned long addr = 0; + unsigned long flags; int ret; - /* If buffer queue is empty, return error */ + /* If buffer queue is empty, return error */ + spin_lock_irqsave(&common->irqlock, flags); if (list_empty(&common->dma_queue)) { + spin_unlock_irqrestore(&common->irqlock, flags); vpif_dbg(1, debug, "buffer queue is empty\n"); return -EIO; } @@ -291,6 +297,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) struct vpif_cap_buffer, list); /* Remove buffer from the buffer queue */ list_del(&common->cur_frm->list); + spin_unlock_irqrestore(&common->irqlock, flags); /* Mark state of the current frame to active */ common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; /* Initialize field_id and started member */ @@ -362,6 +369,7 @@ static int vpif_stop_streaming(struct vb2_queue *vq) struct vpif_fh *fh = vb2_get_drv_priv(vq); struct channel_obj *ch = fh->channel; struct common_obj *common; + unsigned long flags; if (!vb2_is_streaming(vq)) return 0; @@ -369,12 +377,14 @@ static int vpif_stop_streaming(struct vb2_queue *vq) common = &ch->common[VPIF_VIDEO_INDEX]; /* release all active buffers */ + spin_lock_irqsave(&common->irqlock, flags); while (!list_empty(&common->dma_queue)) { common->next_frm = list_entry(common->dma_queue.next, struct vpif_cap_buffer, list); list_del(&common->next_frm->list); vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); } + spin_unlock_irqrestore(&common->irqlock, flags); return 0; } @@ -420,10 +430,12 @@ static void vpif_schedule_next_buffer(struct common_obj *common) { unsigned long addr = 0; + spin_lock(&common->irqlock); common->next_frm = list_entry(common->dma_queue.next, struct vpif_cap_buffer, list); /* Remove that buffer from the buffer queue */ list_del(&common->next_frm->list); + spin_unlock(&common->irqlock); common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; addr = vb2_dma_contig_plane_dma_addr(&common->next_frm->vb, 0); @@ -468,8 +480,12 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) /* Check the field format */ if (1 == ch->vpifparams.std_info.frm_fmt) { /* Progressive mode */ - if (list_empty(&common->dma_queue)) + spin_lock(&common->irqlock); + if (list_empty(&common->dma_queue)) { + spin_unlock(&common->irqlock); continue; + } + spin_unlock(&common->irqlock); if (!channel_first_int[i][channel_id]) vpif_process_buffer_complete(common); @@ -513,9 +529,13 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) vpif_process_buffer_complete(common); } else if (1 == fid) { /* odd field */ + spin_lock(&common->irqlock); if (list_empty(&common->dma_queue) || - (common->cur_frm != common->next_frm)) + (common->cur_frm != common->next_frm)) { + spin_unlock(&common->irqlock); continue; + } + spin_unlock(&common->irqlock); vpif_schedule_next_buffer(common); } @@ -1004,9 +1024,9 @@ static int vpif_reqbufs(struct file *file, void *priv, /* Initialize videobuf2 queue as per the buffer type */ common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); - if (!common->alloc_ctx) { + if (IS_ERR(common->alloc_ctx)) { vpif_err("Failed to get the context\n"); - return -EINVAL; + return PTR_ERR(common->alloc_ctx); } q = &common->buffer_queue; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -1715,7 +1735,7 @@ vpif_enum_dv_timings(struct file *file, void *priv, int ret; ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); - if (ret == -ENOIOCTLCMD && ret == -ENODEV) + if (ret == -ENOIOCTLCMD || ret == -ENODEV) return -EINVAL; return ret; } @@ -1735,7 +1755,7 @@ vpif_query_dv_timings(struct file *file, void *priv, int ret; ret = v4l2_subdev_call(ch->sd, video, query_dv_timings, timings); - if (ret == -ENOIOCTLCMD && ret == -ENODEV) + if (ret == -ENOIOCTLCMD || ret == -ENODEV) return -ENODATA; return ret; } diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index b716fbd4241..9f2b603be9c 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -177,11 +177,14 @@ static void vpif_buffer_queue(struct vb2_buffer *vb) struct vpif_disp_buffer, vb); struct channel_obj *ch = fh->channel; struct common_obj *common; + unsigned long flags; common = &ch->common[VPIF_VIDEO_INDEX]; /* add the buffer to the DMA queue */ + spin_lock_irqsave(&common->irqlock, flags); list_add_tail(&buf->list, &common->dma_queue); + spin_unlock_irqrestore(&common->irqlock, flags); } /* @@ -246,10 +249,13 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX]; struct vpif_params *vpif = &ch->vpifparams; unsigned long addr = 0; + unsigned long flags; int ret; /* If buffer queue is empty, return error */ + spin_lock_irqsave(&common->irqlock, flags); if (list_empty(&common->dma_queue)) { + spin_unlock_irqrestore(&common->irqlock, flags); vpif_err("buffer queue is empty\n"); return -EIO; } @@ -260,6 +266,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count) struct vpif_disp_buffer, list); list_del(&common->cur_frm->list); + spin_unlock_irqrestore(&common->irqlock, flags); /* Mark state of the current frame to active */ common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE; @@ -330,6 +337,7 @@ static int vpif_stop_streaming(struct vb2_queue *vq) struct vpif_fh *fh = vb2_get_drv_priv(vq); struct channel_obj *ch = fh->channel; struct common_obj *common; + unsigned long flags; if (!vb2_is_streaming(vq)) return 0; @@ -337,12 +345,14 @@ static int vpif_stop_streaming(struct vb2_queue *vq) common = &ch->common[VPIF_VIDEO_INDEX]; /* release all active buffers */ + spin_lock_irqsave(&common->irqlock, flags); while (!list_empty(&common->dma_queue)) { common->next_frm = list_entry(common->dma_queue.next, struct vpif_disp_buffer, list); list_del(&common->next_frm->list); vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR); } + spin_unlock_irqrestore(&common->irqlock, flags); return 0; } @@ -363,11 +373,13 @@ static void process_progressive_mode(struct common_obj *common) { unsigned long addr = 0; + spin_lock(&common->irqlock); /* Get the next buffer from buffer queue */ common->next_frm = list_entry(common->dma_queue.next, struct vpif_disp_buffer, list); /* Remove that buffer from the buffer queue */ list_del(&common->next_frm->list); + spin_unlock(&common->irqlock); /* Mark status of the buffer as active */ common->next_frm->vb.state = VB2_BUF_STATE_ACTIVE; @@ -398,16 +410,18 @@ static void process_interlaced_mode(int fid, struct common_obj *common) common->cur_frm = common->next_frm; } else if (1 == fid) { /* odd field */ + spin_lock(&common->irqlock); if (list_empty(&common->dma_queue) || (common->cur_frm != common->next_frm)) { + spin_unlock(&common->irqlock); return; } + spin_unlock(&common->irqlock); /* one field is displayed configure the next * frame if it is available else hold on current * frame */ /* Get next from the buffer queue */ process_progressive_mode(common); - } } @@ -437,8 +451,12 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) continue; if (1 == ch->vpifparams.std_info.frm_fmt) { - if (list_empty(&common->dma_queue)) + spin_lock(&common->irqlock); + if (list_empty(&common->dma_queue)) { + spin_unlock(&common->irqlock); continue; + } + spin_unlock(&common->irqlock); /* Progressive mode */ if (!channel_first_int[i][channel_id]) { @@ -972,9 +990,9 @@ static int vpif_reqbufs(struct file *file, void *priv, } /* Initialize videobuf2 queue as per the buffer type */ common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev); - if (!common->alloc_ctx) { + if (IS_ERR(common->alloc_ctx)) { vpif_err("Failed to get the context\n"); - return -EINVAL; + return PTR_ERR(common->alloc_ctx); } q = &common->buffer_queue; q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; @@ -1380,7 +1398,7 @@ vpif_enum_dv_timings(struct file *file, void *priv, int ret; ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings); - if (ret == -ENOIOCTLCMD && ret == -ENODEV) + if (ret == -ENOIOCTLCMD || ret == -ENODEV) return -EINVAL; return ret; } diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 19cbb12a12a..cc7b218d047 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -982,7 +982,7 @@ static void *gsc_get_drv_data(struct platform_device *pdev) match = of_match_node(of_match_ptr(exynos_gsc_match), pdev->dev.of_node); if (match) - driver_data = match->data; + driver_data = (struct gsc_driverdata *)match->data; } else { driver_data = (struct gsc_driverdata *) platform_get_device_id(pdev)->driver_data; diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index c065d040ed9..c267c57c76f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -122,7 +122,7 @@ static void gsc_m2m_device_run(void *priv) struct gsc_ctx *ctx = priv; struct gsc_dev *gsc; unsigned long flags; - u32 ret; + int ret; bool is_set = false; if (WARN(!ctx, "null hardware context\n")) diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c index 31ac4dc6924..a8ddb0cacab 100644 --- a/drivers/media/platform/fsl-viu.c +++ b/drivers/media/platform/fsl-viu.c @@ -352,8 +352,7 @@ static int restart_video_queue(struct viu_dmaqueue *vidq) return 0; buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue); if (prev == NULL) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->active); + list_move_tail(&buf->vb.queue, &vidq->active); dprintk(1, "Restarting video dma\n"); viu_stop_dma(vidq->dev); @@ -367,8 +366,7 @@ static int restart_video_queue(struct viu_dmaqueue *vidq) } else if (prev->vb.width == buf->vb.width && prev->vb.height == buf->vb.height && prev->fmt == buf->fmt) { - list_del(&buf->vb.queue); - list_add_tail(&buf->vb.queue, &vidq->active); + list_move_tail(&buf->vb.queue, &vidq->active); buf->vb.state = VIDEOBUF_ACTIVE; dprintk(2, "[%p/%d] restart_queue - move to active\n", buf, buf->vb.i); diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c index 45164c4f845..05c560f2ef0 100644 --- a/drivers/media/platform/m2m-deinterlace.c +++ b/drivers/media/platform/m2m-deinterlace.c @@ -218,15 +218,14 @@ static void dma_callback(void *data) static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, int do_callback) { - struct deinterlace_q_data *s_q_data, *d_q_data; + struct deinterlace_q_data *s_q_data; struct vb2_buffer *src_buf, *dst_buf; struct deinterlace_dev *pcdev = ctx->dev; struct dma_chan *chan = pcdev->dma_chan; struct dma_device *dmadev = chan->device; struct dma_async_tx_descriptor *tx; unsigned int s_width, s_height; - unsigned int d_width, d_height; - unsigned int d_size, s_size; + unsigned int s_size; dma_addr_t p_in, p_out; enum dma_ctrl_flags flags; @@ -238,11 +237,6 @@ static void deinterlace_issue_dma(struct deinterlace_ctx *ctx, int op, s_height = s_q_data->height; s_size = s_width * s_height; - d_q_data = get_q_data(V4L2_BUF_TYPE_VIDEO_CAPTURE); - d_width = d_q_data->width; - d_height = d_q_data->height; - d_size = d_width * d_height; - p_in = (dma_addr_t)vb2_dma_contig_plane_dma_addr(src_buf, 0); p_out = (dma_addr_t)vb2_dma_contig_plane_dma_addr(dst_buf, 0); if (!p_in || !p_out) { @@ -1108,17 +1102,5 @@ static struct platform_driver deinterlace_pdrv = { .owner = THIS_MODULE, }, }; - -static void __exit deinterlace_exit(void) -{ - platform_driver_unregister(&deinterlace_pdrv); -} - -static int __init deinterlace_init(void) -{ - return platform_driver_register(&deinterlace_pdrv); -} - -module_init(deinterlace_init); -module_exit(deinterlace_exit); +module_platform_driver(deinterlace_pdrv); diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c index 2e2121e9813..7487d7208de 100644 --- a/drivers/media/platform/mem2mem_testdev.c +++ b/drivers/media/platform/mem2mem_testdev.c @@ -839,7 +839,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); src_vq->ops = &m2mtest_qops; @@ -850,7 +850,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); dst_vq->ops = &m2mtest_qops; diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index bfa65079fc3..6b155d7be8e 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -1013,16 +1013,4 @@ static struct platform_driver emmaprp_pdrv = { .owner = THIS_MODULE, }, }; - -static void __exit emmaprp_exit(void) -{ - platform_driver_unregister(&emmaprp_pdrv); -} - -static int __init emmaprp_init(void) -{ - return platform_driver_register(&emmaprp_pdrv); -} - -module_init(emmaprp_init); -module_exit(emmaprp_exit); +module_platform_driver(emmaprp_pdrv); diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index 99350401596..202d1b4b9be 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -1174,13 +1174,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *fh, /* set default crop and win */ omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win); - /* Save the changes in the overlay strcuture */ - ret = omapvid_init(vout, 0); - if (ret) { - v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode\n"); - goto s_fmt_vid_out_exit; - } - ret = 0; s_fmt_vid_out_exit: @@ -1684,20 +1677,6 @@ static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) omap_dispc_register_isr(omap_vout_isr, vout, mask); - for (j = 0; j < ovid->num_overlays; j++) { - struct omap_overlay *ovl = ovid->overlays[j]; - - if (ovl->get_device(ovl)) { - struct omap_overlay_info info; - ovl->get_overlay_info(ovl, &info); - info.paddr = addr; - if (ovl->set_overlay_info(ovl, &info)) { - ret = -EINVAL; - goto streamon_err1; - } - } - } - /* First save the configuration in ovelray structure */ ret = omapvid_init(vout, addr); if (ret) @@ -2094,11 +2073,12 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) } video_set_drvdata(vfd, vout); - /* Configure the overlay structure */ - ret = omapvid_init(vid_dev->vouts[k], 0); - if (!ret) - goto success; + dev_info(&pdev->dev, ": registered and initialized" + " video device %d\n", vfd->minor); + if (k == (pdev->num_resources - 1)) + return 0; + continue; error2: if (vout->vid_info.rotation_type == VOUT_ROT_VRFB) omap_vout_release_vrfb(vout); @@ -2108,12 +2088,6 @@ error1: error: kfree(vout); return ret; - -success: - dev_info(&pdev->dev, ": registered and initialized" - " video device %d\n", vfd->minor); - if (k == (pdev->num_resources - 1)) - return 0; } return -ENODEV; diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 7f182f0ff3d..a9f6de5b69d 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -103,7 +103,8 @@ static const struct isp_res_mapping isp_res_maps[] = { 1 << OMAP3_ISP_IOMEM_RESZ | 1 << OMAP3_ISP_IOMEM_SBL | 1 << OMAP3_ISP_IOMEM_CSI2A_REGS1 | - 1 << OMAP3_ISP_IOMEM_CSIPHY2, + 1 << OMAP3_ISP_IOMEM_CSIPHY2 | + 1 << OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, }, { .isp_rev = ISP_REVISION_15_0, @@ -120,7 +121,8 @@ static const struct isp_res_mapping isp_res_maps[] = { 1 << OMAP3_ISP_IOMEM_CSI2A_REGS2 | 1 << OMAP3_ISP_IOMEM_CSI2C_REGS1 | 1 << OMAP3_ISP_IOMEM_CSIPHY1 | - 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2, + 1 << OMAP3_ISP_IOMEM_CSI2C_REGS2 | + 1 << OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, }, }; @@ -1331,7 +1333,8 @@ void omap3isp_subclk_disable(struct isp_device *isp, * isp_enable_clocks - Enable ISP clocks * @isp: OMAP3 ISP device * - * Return 0 if successful, or clk_enable return value if any of tthem fails. + * Return 0 if successful, or clk_prepare_enable return value if any of them + * fails. */ static int isp_enable_clocks(struct isp_device *isp) { @@ -1348,14 +1351,11 @@ static int isp_enable_clocks(struct isp_device *isp) * has to be twice of what is set on OMAP3430 to get * the required value for cam_mclk */ - if (cpu_is_omap3630()) - divisor = 1; - else - divisor = 2; + divisor = isp->revision == ISP_REVISION_15_0 ? 1 : 2; - r = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); + r = clk_prepare_enable(isp->clock[ISP_CLK_CAM_ICK]); if (r) { - dev_err(isp->dev, "clk_enable cam_ick failed\n"); + dev_err(isp->dev, "failed to enable cam_ick clock\n"); goto out_clk_enable_ick; } r = clk_set_rate(isp->clock[ISP_CLK_DPLL4_M5_CK], @@ -1364,9 +1364,9 @@ static int isp_enable_clocks(struct isp_device *isp) dev_err(isp->dev, "clk_set_rate for dpll4_m5_ck failed\n"); goto out_clk_enable_mclk; } - r = clk_enable(isp->clock[ISP_CLK_CAM_MCLK]); + r = clk_prepare_enable(isp->clock[ISP_CLK_CAM_MCLK]); if (r) { - dev_err(isp->dev, "clk_enable cam_mclk failed\n"); + dev_err(isp->dev, "failed to enable cam_mclk clock\n"); goto out_clk_enable_mclk; } rate = clk_get_rate(isp->clock[ISP_CLK_CAM_MCLK]); @@ -1374,17 +1374,17 @@ static int isp_enable_clocks(struct isp_device *isp) dev_warn(isp->dev, "unexpected cam_mclk rate:\n" " expected : %d\n" " actual : %ld\n", CM_CAM_MCLK_HZ, rate); - r = clk_enable(isp->clock[ISP_CLK_CSI2_FCK]); + r = clk_prepare_enable(isp->clock[ISP_CLK_CSI2_FCK]); if (r) { - dev_err(isp->dev, "clk_enable csi2_fck failed\n"); + dev_err(isp->dev, "failed to enable csi2_fck clock\n"); goto out_clk_enable_csi2_fclk; } return 0; out_clk_enable_csi2_fclk: - clk_disable(isp->clock[ISP_CLK_CAM_MCLK]); + clk_disable_unprepare(isp->clock[ISP_CLK_CAM_MCLK]); out_clk_enable_mclk: - clk_disable(isp->clock[ISP_CLK_CAM_ICK]); + clk_disable_unprepare(isp->clock[ISP_CLK_CAM_ICK]); out_clk_enable_ick: return r; } @@ -1395,9 +1395,9 @@ out_clk_enable_ick: */ static void isp_disable_clocks(struct isp_device *isp) { - clk_disable(isp->clock[ISP_CLK_CAM_ICK]); - clk_disable(isp->clock[ISP_CLK_CAM_MCLK]); - clk_disable(isp->clock[ISP_CLK_CSI2_FCK]); + clk_disable_unprepare(isp->clock[ISP_CLK_CAM_ICK]); + clk_disable_unprepare(isp->clock[ISP_CLK_CAM_MCLK]); + clk_disable_unprepare(isp->clock[ISP_CLK_CSI2_FCK]); } static const char *isp_clocks[] = { @@ -1678,7 +1678,7 @@ isp_register_subdev_group(struct isp_device *isp, adapter = i2c_get_adapter(board_info->i2c_adapter_id); if (adapter == NULL) { - printk(KERN_ERR "%s: Unable to get I2C adapter %d for " + dev_err(isp->dev, "%s: Unable to get I2C adapter %d for " "device %s\n", __func__, board_info->i2c_adapter_id, board_info->board_info->type); @@ -1688,7 +1688,7 @@ isp_register_subdev_group(struct isp_device *isp, subdev = v4l2_i2c_new_subdev_board(&isp->v4l2_dev, adapter, board_info->board_info, NULL); if (subdev == NULL) { - printk(KERN_ERR "%s: Unable to register subdev %s\n", + dev_err(isp->dev, "%s: Unable to register subdev %s\n", __func__, board_info->board_info->type); continue; } @@ -1713,7 +1713,7 @@ static int isp_register_entities(struct isp_device *isp) isp->media_dev.link_notify = isp_pipeline_link_notify; ret = media_device_register(&isp->media_dev); if (ret < 0) { - printk(KERN_ERR "%s: Media device registration failed (%d)\n", + dev_err(isp->dev, "%s: Media device registration failed (%d)\n", __func__, ret); return ret; } @@ -1721,7 +1721,7 @@ static int isp_register_entities(struct isp_device *isp) isp->v4l2_dev.mdev = &isp->media_dev; ret = v4l2_device_register(isp->dev, &isp->v4l2_dev); if (ret < 0) { - printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n", + dev_err(isp->dev, "%s: V4L2 device registration failed (%d)\n", __func__, ret); goto done; } @@ -1766,6 +1766,7 @@ static int isp_register_entities(struct isp_device *isp) struct media_entity *input; unsigned int flags; unsigned int pad; + unsigned int i; sensor = isp_register_subdev_group(isp, subdevs->subdevs); if (sensor == NULL) @@ -1807,13 +1808,25 @@ static int isp_register_entities(struct isp_device *isp) break; default: - printk(KERN_ERR "%s: invalid interface type %u\n", - __func__, subdevs->interface); + dev_err(isp->dev, "%s: invalid interface type %u\n", + __func__, subdevs->interface); + ret = -EINVAL; + goto done; + } + + for (i = 0; i < sensor->entity.num_pads; i++) { + if (sensor->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE) + break; + } + if (i == sensor->entity.num_pads) { + dev_err(isp->dev, + "%s: no source pad in external entity\n", + __func__); ret = -EINVAL; goto done; } - ret = media_entity_create_link(&sensor->entity, 0, input, pad, + ret = media_entity_create_link(&sensor->entity, i, input, pad, flags); if (ret < 0) goto done; @@ -2096,7 +2109,11 @@ static int __devinit isp_probe(struct platform_device *pdev) isp->isp_csiphy1.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY1"); isp->isp_csiphy2.vdd = regulator_get(&pdev->dev, "VDD_CSIPHY2"); - /* Clocks */ + /* Clocks + * + * The ISP clock tree is revision-dependent. We thus need to enable ICLK + * manually to read the revision before calling __omap3isp_get(). + */ ret = isp_map_mem_resource(pdev, isp, OMAP3_ISP_IOMEM_MAIN); if (ret < 0) goto error; @@ -2105,6 +2122,16 @@ static int __devinit isp_probe(struct platform_device *pdev) if (ret < 0) goto error; + ret = clk_enable(isp->clock[ISP_CLK_CAM_ICK]); + if (ret < 0) + goto error; + + isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); + dev_info(isp->dev, "Revision %d.%d found\n", + (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); + + clk_disable(isp->clock[ISP_CLK_CAM_ICK]); + if (__omap3isp_get(isp, false) == NULL) { ret = -ENODEV; goto error; @@ -2115,10 +2142,6 @@ static int __devinit isp_probe(struct platform_device *pdev) goto error_isp; /* Memory resources */ - isp->revision = isp_reg_readl(isp, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION); - dev_info(isp->dev, "Revision %d.%d found\n", - (isp->revision & 0xf0) >> 4, isp->revision & 0x0f); - for (m = 0; m < ARRAY_SIZE(isp_res_maps); m++) if (isp->revision == isp_res_maps[m].isp_rev) break; diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h index 8d6866942b8..517d348ce32 100644 --- a/drivers/media/platform/omap3isp/isp.h +++ b/drivers/media/platform/omap3isp/isp.h @@ -70,6 +70,8 @@ enum isp_mem_resources { OMAP3_ISP_IOMEM_CSI2C_REGS1, OMAP3_ISP_IOMEM_CSIPHY1, OMAP3_ISP_IOMEM_CSI2C_REGS2, + OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, + OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, OMAP3_ISP_IOMEM_LAST }; @@ -125,9 +127,6 @@ struct isp_reg { struct isp_platform_callback { u32 (*set_xclk)(struct isp_device *isp, u32 xclk, u8 xclksel); - int (*csiphy_config)(struct isp_csiphy *phy, - struct isp_csiphy_dphy_cfg *dphy, - struct isp_csiphy_lanes_cfg *lanes); }; /* diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index 6a3ff792af7..783f4b05b15 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -517,7 +517,7 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) } while (soft_reset_retries < 5); if (soft_reset_retries == 5) { - printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n"); + dev_err(isp->dev, "CSI2: Soft reset try count exceeded!\n"); return -EBUSY; } @@ -535,8 +535,8 @@ int omap3isp_csi2_reset(struct isp_csi2_device *csi2) } while (--i > 0); if (i == 0) { - printk(KERN_ERR - "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); + dev_err(isp->dev, + "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n"); return -EBUSY; } diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index 348f67ebbbc..3d56b33f85e 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -32,34 +32,92 @@ #include "ispreg.h" #include "ispcsiphy.h" -/* - * csiphy_lanes_config - Configuration of CSIPHY lanes. - * - * Updates HW configuration. - * Called with phy->mutex taken. - */ -static void csiphy_lanes_config(struct isp_csiphy *phy) +static void csiphy_routing_cfg_3630(struct isp_csiphy *phy, u32 iface, + bool ccp2_strobe) { - unsigned int i; - u32 reg; + u32 reg = isp_reg_readl( + phy->isp, OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0); + u32 shift, mode; + + switch (iface) { + case ISP_INTERFACE_CCP2B_PHY1: + reg &= ~OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2; + shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT; + break; + case ISP_INTERFACE_CSI2C_PHY1: + shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT; + mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY; + break; + case ISP_INTERFACE_CCP2B_PHY2: + reg |= OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2; + shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT; + break; + case ISP_INTERFACE_CSI2A_PHY2: + shift = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT; + mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY; + break; + } - reg = isp_reg_readl(phy->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); + /* Select data/clock or data/strobe mode for CCP2 */ + switch (iface) { + case ISP_INTERFACE_CCP2B_PHY1: + case ISP_INTERFACE_CCP2B_PHY2: + if (ccp2_strobe) + mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_STROBE; + else + mode = OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_CLOCK; + } - for (i = 0; i < phy->num_data_lanes; i++) { - reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | - ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); - reg |= (phy->lanes.data[i].pol << - ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); - reg |= (phy->lanes.data[i].pos << - ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); + reg &= ~(OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK << shift); + reg |= mode << shift; + + isp_reg_writel(phy->isp, reg, + OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL, 0); +} + +static void csiphy_routing_cfg_3430(struct isp_csiphy *phy, u32 iface, bool on, + bool ccp2_strobe) +{ + u32 csirxfe = OMAP343X_CONTROL_CSIRXFE_PWRDNZ + | OMAP343X_CONTROL_CSIRXFE_RESET; + + /* Only the CCP2B on PHY1 is configurable. */ + if (iface != ISP_INTERFACE_CCP2B_PHY1) + return; + + if (!on) { + isp_reg_writel(phy->isp, 0, + OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0); + return; } - reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | - ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); - reg |= phy->lanes.clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; - reg |= phy->lanes.clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; + if (ccp2_strobe) + csirxfe |= OMAP343X_CONTROL_CSIRXFE_SELFORM; - isp_reg_writel(phy->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); + isp_reg_writel(phy->isp, csirxfe, + OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE, 0); +} + +/* + * Configure OMAP 3 CSI PHY routing. + * @phy: relevant phy device + * @iface: ISP_INTERFACE_* + * @on: power on or off + * @ccp2_strobe: false: data/clock, true: data/strobe + * + * Note that the underlying routing configuration registers are part of the + * control (SCM) register space and part of the CORE power domain on both 3430 + * and 3630, so they will not hold their contents in off-mode. This isn't an + * issue since the MPU power domain is forced on whilst the ISP is in use. + */ +static void csiphy_routing_cfg(struct isp_csiphy *phy, u32 iface, bool on, + bool ccp2_strobe) +{ + if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_3630_CONTROL_CAMERA_PHY_CTRL] + && on) + return csiphy_routing_cfg_3630(phy, iface, ccp2_strobe); + if (phy->isp->mmio_base[OMAP3_ISP_IOMEM_343X_CONTROL_CSIRXFE]) + return csiphy_routing_cfg_3430(phy, iface, on, ccp2_strobe); } /* @@ -99,7 +157,7 @@ static int csiphy_set_power(struct isp_csiphy *phy, u32 power) } while ((reg != power >> 2) && (retry_count < 100)); if (retry_count == 100) { - printk(KERN_ERR "CSI2 CIO set power failed!\n"); + dev_err(phy->isp->dev, "CSI2 CIO set power failed!\n"); return -EBUSY; } @@ -107,43 +165,28 @@ static int csiphy_set_power(struct isp_csiphy *phy, u32 power) } /* - * csiphy_dphy_config - Configure CSI2 D-PHY parameters. - * - * Called with phy->mutex taken. + * TCLK values are OK at their reset values */ -static void csiphy_dphy_config(struct isp_csiphy *phy) -{ - u32 reg; - - /* Set up ISPCSIPHY_REG0 */ - reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG0); - - reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | - ISPCSIPHY_REG0_THS_SETTLE_MASK); - reg |= phy->dphy.ths_term << ISPCSIPHY_REG0_THS_TERM_SHIFT; - reg |= phy->dphy.ths_settle << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; - - isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); - - /* Set up ISPCSIPHY_REG1 */ - reg = isp_reg_readl(phy->isp, phy->phy_regs, ISPCSIPHY_REG1); - - reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | - ISPCSIPHY_REG1_TCLK_MISS_MASK | - ISPCSIPHY_REG1_TCLK_SETTLE_MASK); - reg |= phy->dphy.tclk_term << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; - reg |= phy->dphy.tclk_miss << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; - reg |= phy->dphy.tclk_settle << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; - - isp_reg_writel(phy->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); -} +#define TCLK_TERM 0 +#define TCLK_MISS 1 +#define TCLK_SETTLE 14 -static int csiphy_config(struct isp_csiphy *phy, - struct isp_csiphy_dphy_cfg *dphy, - struct isp_csiphy_lanes_cfg *lanes) +static int omap3isp_csiphy_config(struct isp_csiphy *phy) { + struct isp_csi2_device *csi2 = phy->csi2; + struct isp_pipeline *pipe = to_isp_pipeline(&csi2->subdev.entity); + struct isp_v4l2_subdevs_group *subdevs = pipe->external->host_priv; + struct isp_csiphy_lanes_cfg *lanes; + int csi2_ddrclk_khz; unsigned int used_lanes = 0; unsigned int i; + u32 reg; + + if (subdevs->interface == ISP_INTERFACE_CCP2B_PHY1 + || subdevs->interface == ISP_INTERFACE_CCP2B_PHY2) + lanes = &subdevs->bus.ccp2.lanecfg; + else + lanes = &subdevs->bus.csi2.lanecfg; /* Clock and data lanes verification */ for (i = 0; i < phy->num_data_lanes; i++) { @@ -162,10 +205,61 @@ static int csiphy_config(struct isp_csiphy *phy, if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos)) return -EINVAL; - mutex_lock(&phy->mutex); - phy->dphy = *dphy; - phy->lanes = *lanes; - mutex_unlock(&phy->mutex); + /* + * The PHY configuration is lost in off mode, that's not an + * issue since the MPU power domain is forced on whilst the + * ISP is in use. + */ + csiphy_routing_cfg(phy, subdevs->interface, true, + subdevs->bus.ccp2.phy_layer); + + /* DPHY timing configuration */ + /* CSI-2 is DDR and we only count used lanes. */ + csi2_ddrclk_khz = pipe->external_rate / 1000 + / (2 * hweight32(used_lanes)) * pipe->external_width; + + reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG0); + + reg &= ~(ISPCSIPHY_REG0_THS_TERM_MASK | + ISPCSIPHY_REG0_THS_SETTLE_MASK); + /* THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1. */ + reg |= (DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1) + << ISPCSIPHY_REG0_THS_TERM_SHIFT; + /* THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3. */ + reg |= (DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3) + << ISPCSIPHY_REG0_THS_SETTLE_SHIFT; + + isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG0); + + reg = isp_reg_readl(csi2->isp, phy->phy_regs, ISPCSIPHY_REG1); + + reg &= ~(ISPCSIPHY_REG1_TCLK_TERM_MASK | + ISPCSIPHY_REG1_TCLK_MISS_MASK | + ISPCSIPHY_REG1_TCLK_SETTLE_MASK); + reg |= TCLK_TERM << ISPCSIPHY_REG1_TCLK_TERM_SHIFT; + reg |= TCLK_MISS << ISPCSIPHY_REG1_TCLK_MISS_SHIFT; + reg |= TCLK_SETTLE << ISPCSIPHY_REG1_TCLK_SETTLE_SHIFT; + + isp_reg_writel(csi2->isp, reg, phy->phy_regs, ISPCSIPHY_REG1); + + /* DPHY lane configuration */ + reg = isp_reg_readl(csi2->isp, phy->cfg_regs, ISPCSI2_PHY_CFG); + + for (i = 0; i < phy->num_data_lanes; i++) { + reg &= ~(ISPCSI2_PHY_CFG_DATA_POL_MASK(i + 1) | + ISPCSI2_PHY_CFG_DATA_POSITION_MASK(i + 1)); + reg |= (lanes->data[i].pol << + ISPCSI2_PHY_CFG_DATA_POL_SHIFT(i + 1)); + reg |= (lanes->data[i].pos << + ISPCSI2_PHY_CFG_DATA_POSITION_SHIFT(i + 1)); + } + + reg &= ~(ISPCSI2_PHY_CFG_CLOCK_POL_MASK | + ISPCSI2_PHY_CFG_CLOCK_POSITION_MASK); + reg |= lanes->clk.pol << ISPCSI2_PHY_CFG_CLOCK_POL_SHIFT; + reg |= lanes->clk.pos << ISPCSI2_PHY_CFG_CLOCK_POSITION_SHIFT; + + isp_reg_writel(csi2->isp, reg, phy->cfg_regs, ISPCSI2_PHY_CFG); return 0; } @@ -190,8 +284,9 @@ int omap3isp_csiphy_acquire(struct isp_csiphy *phy) if (rval < 0) goto done; - csiphy_dphy_config(phy); - csiphy_lanes_config(phy); + rval = omap3isp_csiphy_config(phy); + if (rval < 0) + goto done; rval = csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_ON); if (rval) { @@ -211,6 +306,14 @@ void omap3isp_csiphy_release(struct isp_csiphy *phy) { mutex_lock(&phy->mutex); if (phy->phy_in_use) { + struct isp_csi2_device *csi2 = phy->csi2; + struct isp_pipeline *pipe = + to_isp_pipeline(&csi2->subdev.entity); + struct isp_v4l2_subdevs_group *subdevs = + pipe->external->host_priv; + + csiphy_routing_cfg(phy, subdevs->interface, false, + subdevs->bus.ccp2.phy_layer); csiphy_power_autoswitch_enable(phy, false); csiphy_set_power(phy, ISPCSI2_PHY_CFG_PWR_CMD_OFF); regulator_disable(phy->vdd); @@ -227,8 +330,6 @@ int omap3isp_csiphy_init(struct isp_device *isp) struct isp_csiphy *phy1 = &isp->isp_csiphy1; struct isp_csiphy *phy2 = &isp->isp_csiphy2; - isp->platform_cb.csiphy_config = csiphy_config; - phy2->isp = isp; phy2->csi2 = &isp->isp_csi2a; phy2->num_data_lanes = ISP_CSIPHY2_NUM_DATA_LANES; diff --git a/drivers/media/platform/omap3isp/ispcsiphy.h b/drivers/media/platform/omap3isp/ispcsiphy.h index e93a661e65d..14551fd7769 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.h +++ b/drivers/media/platform/omap3isp/ispcsiphy.h @@ -32,14 +32,6 @@ struct isp_csi2_device; struct regulator; -struct isp_csiphy_dphy_cfg { - u8 ths_term; - u8 ths_settle; - u8 tclk_term; - unsigned tclk_miss:1; - u8 tclk_settle; -}; - struct isp_csiphy { struct isp_device *isp; struct mutex mutex; /* serialize csiphy configuration */ @@ -52,8 +44,6 @@ struct isp_csiphy { unsigned int phy_regs; u8 num_data_lanes; /* number of CSI2 Data Lanes supported */ - struct isp_csiphy_lanes_cfg lanes; - struct isp_csiphy_dphy_cfg dphy; }; int omap3isp_csiphy_acquire(struct isp_csiphy *phy); diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index e7f9c4292cc..2d759c56f37 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -74,11 +74,14 @@ static void hist_reset_mem(struct ispstat *hist) static void hist_dma_config(struct ispstat *hist) { + struct isp_device *isp = hist->isp; + hist->dma_config.data_type = OMAP_DMA_DATA_TYPE_S32; hist->dma_config.sync_mode = OMAP_DMA_SYNC_ELEMENT; hist->dma_config.frame_count = 1; hist->dma_config.src_amode = OMAP_DMA_AMODE_CONSTANT; - hist->dma_config.src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA; + hist->dma_config.src_start = isp->mmio_base_phys[OMAP3_ISP_IOMEM_HIST] + + ISPHIST_DATA; hist->dma_config.dst_amode = OMAP_DMA_AMODE_POST_INC; hist->dma_config.src_or_dst_synch = OMAP_DMA_SRC_SYNC; } @@ -479,6 +482,8 @@ int omap3isp_hist_init(struct isp_device *isp) return -ENOMEM; memset(hist, 0, sizeof(*hist)); + hist->isp = isp; + if (HIST_CONFIG_DMA) ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST", hist_dma_cb, hist, &hist->dma_ch); @@ -496,7 +501,6 @@ int omap3isp_hist_init(struct isp_device *isp) hist->ops = &hist_ops; hist->priv = hist_cfg; hist->event_type = V4L2_EVENT_OMAP3ISP_HIST; - hist->isp = isp; ret = omap3isp_stat_init(hist, "histogram", &hist_subdev_ops); if (ret) { diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c index 1ae1c0909ed..691b92a3c3e 100644 --- a/drivers/media/platform/omap3isp/isppreview.c +++ b/drivers/media/platform/omap3isp/isppreview.c @@ -200,10 +200,10 @@ static void preview_enable_invalaw(struct isp_prev_device *prev, bool enable) if (enable) isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW); + ISPPRV_PCR_INVALAW); else isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, - ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW); + ISPPRV_PCR_INVALAW); } /* @@ -1014,7 +1014,7 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) /* * preview_config_input_format - Configure the input format * @prev: The preview engine - * @format: Format on the preview engine sink pad + * @info: Sink pad format information * * Enable and configure CFA interpolation for Bayer formats and disable it for * greyscale formats. @@ -1025,22 +1025,29 @@ static void preview_config_averager(struct isp_prev_device *prev, u8 average) * reordered to support non-GRBG Bayer patterns. */ static void preview_config_input_format(struct isp_prev_device *prev, - const struct v4l2_mbus_framefmt *format) + const struct isp_format_info *info) { struct isp_device *isp = to_isp_device(prev); struct prev_params *params; - switch (format->code) { - case V4L2_MBUS_FMT_SGRBG10_1X10: + if (info->width == 8) + isp_reg_set(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_WIDTH); + else + isp_reg_clr(isp, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, + ISPPRV_PCR_WIDTH); + + switch (info->flavor) { + case V4L2_MBUS_FMT_SGRBG8_1X8: prev->params.cfa_order = 0; break; - case V4L2_MBUS_FMT_SRGGB10_1X10: + case V4L2_MBUS_FMT_SRGGB8_1X8: prev->params.cfa_order = 1; break; - case V4L2_MBUS_FMT_SBGGR10_1X10: + case V4L2_MBUS_FMT_SBGGR8_1X8: prev->params.cfa_order = 2; break; - case V4L2_MBUS_FMT_SGBRG10_1X10: + case V4L2_MBUS_FMT_SGBRG8_1X8: prev->params.cfa_order = 3; break; default: @@ -1081,7 +1088,8 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active) unsigned int elv = prev->crop.top + prev->crop.height - 1; u32 features; - if (format->code != V4L2_MBUS_FMT_Y10_1X10) { + if (format->code != V4L2_MBUS_FMT_Y8_1X8 && + format->code != V4L2_MBUS_FMT_Y10_1X10) { sph -= 2; eph += 2; slv -= 2; @@ -1389,6 +1397,7 @@ static unsigned int preview_max_out_width(struct isp_prev_device *prev) static void preview_configure(struct isp_prev_device *prev) { struct isp_device *isp = to_isp_device(prev); + const struct isp_format_info *info; struct v4l2_mbus_framefmt *format; unsigned long flags; u32 update; @@ -1402,17 +1411,18 @@ static void preview_configure(struct isp_prev_device *prev) /* PREV_PAD_SINK */ format = &prev->formats[PREV_PAD_SINK]; + info = omap3isp_video_format_info(format->code); preview_adjust_bandwidth(prev); - preview_config_input_format(prev, format); + preview_config_input_format(prev, info); preview_config_input_size(prev, active); if (prev->input == PREVIEW_INPUT_CCDC) preview_config_inlineoffset(prev, 0); else - preview_config_inlineoffset(prev, - ALIGN(format->width, 0x20) * 2); + preview_config_inlineoffset(prev, ALIGN(format->width, 0x20) * + info->bpp); preview_setup_hw(prev, update, active); @@ -1709,6 +1719,11 @@ __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh, /* previewer format descriptions */ static const unsigned int preview_input_fmts[] = { + V4L2_MBUS_FMT_Y8_1X8, + V4L2_MBUS_FMT_SGRBG8_1X8, + V4L2_MBUS_FMT_SRGGB8_1X8, + V4L2_MBUS_FMT_SBGGR8_1X8, + V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10, diff --git a/drivers/media/platform/omap3isp/ispreg.h b/drivers/media/platform/omap3isp/ispreg.h index e2c57f334c5..b7d90e6fb01 100644 --- a/drivers/media/platform/omap3isp/ispreg.h +++ b/drivers/media/platform/omap3isp/ispreg.h @@ -29,83 +29,6 @@ #define CM_CAM_MCLK_HZ 172800000 /* Hz */ -/* ISP Submodules offset */ - -#define L4_34XX_BASE 0x48000000 -#define OMAP3430_ISP_BASE (L4_34XX_BASE + 0xBC000) - -#define OMAP3ISP_REG_BASE OMAP3430_ISP_BASE -#define OMAP3ISP_REG(offset) (OMAP3ISP_REG_BASE + (offset)) - -#define OMAP3ISP_CCP2_REG_OFFSET 0x0400 -#define OMAP3ISP_CCP2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CCP2_REG_OFFSET) -#define OMAP3ISP_CCP2_REG(offset) (OMAP3ISP_CCP2_REG_BASE + (offset)) - -#define OMAP3ISP_CCDC_REG_OFFSET 0x0600 -#define OMAP3ISP_CCDC_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CCDC_REG_OFFSET) -#define OMAP3ISP_CCDC_REG(offset) (OMAP3ISP_CCDC_REG_BASE + (offset)) - -#define OMAP3ISP_HIST_REG_OFFSET 0x0A00 -#define OMAP3ISP_HIST_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_HIST_REG_OFFSET) -#define OMAP3ISP_HIST_REG(offset) (OMAP3ISP_HIST_REG_BASE + (offset)) - -#define OMAP3ISP_H3A_REG_OFFSET 0x0C00 -#define OMAP3ISP_H3A_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_H3A_REG_OFFSET) -#define OMAP3ISP_H3A_REG(offset) (OMAP3ISP_H3A_REG_BASE + (offset)) - -#define OMAP3ISP_PREV_REG_OFFSET 0x0E00 -#define OMAP3ISP_PREV_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_PREV_REG_OFFSET) -#define OMAP3ISP_PREV_REG(offset) (OMAP3ISP_PREV_REG_BASE + (offset)) - -#define OMAP3ISP_RESZ_REG_OFFSET 0x1000 -#define OMAP3ISP_RESZ_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_RESZ_REG_OFFSET) -#define OMAP3ISP_RESZ_REG(offset) (OMAP3ISP_RESZ_REG_BASE + (offset)) - -#define OMAP3ISP_SBL_REG_OFFSET 0x1200 -#define OMAP3ISP_SBL_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_SBL_REG_OFFSET) -#define OMAP3ISP_SBL_REG(offset) (OMAP3ISP_SBL_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2A_REGS1_REG_OFFSET 0x1800 -#define OMAP3ISP_CSI2A_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2A_REGS1_REG_OFFSET) -#define OMAP3ISP_CSI2A_REGS1_REG(offset) \ - (OMAP3ISP_CSI2A_REGS1_REG_BASE + (offset)) - -#define OMAP3ISP_CSIPHY2_REG_OFFSET 0x1970 -#define OMAP3ISP_CSIPHY2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSIPHY2_REG_OFFSET) -#define OMAP3ISP_CSIPHY2_REG(offset) (OMAP3ISP_CSIPHY2_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2A_REGS2_REG_OFFSET 0x19C0 -#define OMAP3ISP_CSI2A_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2A_REGS2_REG_OFFSET) -#define OMAP3ISP_CSI2A_REGS2_REG(offset) \ - (OMAP3ISP_CSI2A_REGS2_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2C_REGS1_REG_OFFSET 0x1C00 -#define OMAP3ISP_CSI2C_REGS1_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2C_REGS1_REG_OFFSET) -#define OMAP3ISP_CSI2C_REGS1_REG(offset) \ - (OMAP3ISP_CSI2C_REGS1_REG_BASE + (offset)) - -#define OMAP3ISP_CSIPHY1_REG_OFFSET 0x1D70 -#define OMAP3ISP_CSIPHY1_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSIPHY1_REG_OFFSET) -#define OMAP3ISP_CSIPHY1_REG(offset) (OMAP3ISP_CSIPHY1_REG_BASE + (offset)) - -#define OMAP3ISP_CSI2C_REGS2_REG_OFFSET 0x1DC0 -#define OMAP3ISP_CSI2C_REGS2_REG_BASE (OMAP3ISP_REG_BASE + \ - OMAP3ISP_CSI2C_REGS2_REG_OFFSET) -#define OMAP3ISP_CSI2C_REGS2_REG(offset) \ - (OMAP3ISP_CSI2C_REGS2_REG_BASE + (offset)) - /* ISP module register offset */ #define ISP_REVISION (0x000) @@ -1583,4 +1506,26 @@ #define ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_MASK \ (0x7fffff << ISPCSIPHY_REG2_CCP2_SYNC_PATTERN_SHIFT) +/* ----------------------------------------------------------------------------- + * CONTROL registers for CSI-2 phy routing + */ + +/* OMAP343X_CONTROL_CSIRXFE */ +#define OMAP343X_CONTROL_CSIRXFE_CSIB_INV (1 << 7) +#define OMAP343X_CONTROL_CSIRXFE_RESENABLE (1 << 8) +#define OMAP343X_CONTROL_CSIRXFE_SELFORM (1 << 10) +#define OMAP343X_CONTROL_CSIRXFE_PWRDNZ (1 << 12) +#define OMAP343X_CONTROL_CSIRXFE_RESET (1 << 13) + +/* OMAP3630_CONTROL_CAMERA_PHY_CTRL */ +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY1_SHIFT 2 +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_PHY2_SHIFT 0 +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_DPHY 0x0 +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_STROBE 0x1 +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_CCP2_DATA_CLOCK 0x2 +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_GPI 0x3 +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CAMMODE_MASK 0x3 +/* CCP2B: set to receive data from PHY2 instead of PHY1 */ +#define OMAP3630_CONTROL_CAMERA_PHY_CTRL_CSI1_RX_SEL_PHY2 (1 << 4) + #endif /* OMAP3_ISP_REG_H */ diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index e7939869bda..61e17f9bd8b 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -257,7 +257,7 @@ static int isp_stat_buf_queue(struct ispstat *stat) if (!stat->active_buf) return STAT_NO_BUF; - do_gettimeofday(&stat->active_buf->ts); + ktime_get_ts(&stat->active_buf->ts); stat->active_buf->buf_size = stat->buf_size; if (isp_stat_buf_check_magic(stat, stat->active_buf)) { @@ -537,7 +537,8 @@ int omap3isp_stat_request_statistics(struct ispstat *stat, return PTR_ERR(buf); } - data->ts = buf->ts; + data->ts.tv_sec = buf->ts.tv_sec; + data->ts.tv_usec = buf->ts.tv_nsec / NSEC_PER_USEC; data->config_counter = buf->config_counter; data->frame_number = buf->frame_number; data->buf_size = buf->buf_size; diff --git a/drivers/media/platform/omap3isp/ispstat.h b/drivers/media/platform/omap3isp/ispstat.h index fd15094de34..9a047c929b9 100644 --- a/drivers/media/platform/omap3isp/ispstat.h +++ b/drivers/media/platform/omap3isp/ispstat.h @@ -50,7 +50,7 @@ struct ispstat_buffer { struct iovm_struct *iovm; void *virt_addr; dma_addr_t dma_addr; - struct timeval ts; + struct timespec ts; u32 buf_size; u32 frame_number; u16 config_counter; diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c index 3311d6bb345..e0d73a64218 100644 --- a/drivers/media/platform/omap3isp/ispvideo.c +++ b/drivers/media/platform/omap3isp/ispvideo.c @@ -1392,7 +1392,8 @@ int omap3isp_video_register(struct isp_video *video, struct v4l2_device *vdev) ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1); if (ret < 0) - printk(KERN_ERR "%s: could not register video device (%d)\n", + dev_err(video->isp->dev, + "%s: could not register video device (%d)\n", __func__, ret); return ret; diff --git a/drivers/media/platform/s3c-camif/Makefile b/drivers/media/platform/s3c-camif/Makefile new file mode 100644 index 00000000000..50bf8c59b99 --- /dev/null +++ b/drivers/media/platform/s3c-camif/Makefile @@ -0,0 +1,5 @@ +# Makefile for s3c244x/s3c64xx CAMIF driver + +s3c-camif-objs := camif-core.o camif-capture.o camif-regs.o + +obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif.o diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c new file mode 100644 index 00000000000..a55793c3d81 --- /dev/null +++ b/drivers/media/platform/s3c-camif/camif-capture.c @@ -0,0 +1,1672 @@ +/* + * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver + * + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> + * + * Based on drivers/media/platform/s5p-fimc, + * Copyright (C) 2010 - 2012 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include <linux/bug.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/ratelimit.h> +#include <linux/slab.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#include <media/media-device.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "camif-core.h" +#include "camif-regs.h" + +static int debug; +module_param(debug, int, 0644); + +/* Locking: called with vp->camif->slock spinlock held */ +static void camif_cfg_video_path(struct camif_vp *vp) +{ + WARN_ON(s3c_camif_get_scaler_config(vp, &vp->scaler)); + camif_hw_set_scaler(vp); + camif_hw_set_flip(vp); + camif_hw_set_target_format(vp); + camif_hw_set_output_dma(vp); +} + +static void camif_prepare_dma_offset(struct camif_vp *vp) +{ + struct camif_frame *f = &vp->out_frame; + + f->dma_offset.initial = f->rect.top * f->f_width + f->rect.left; + f->dma_offset.line = f->f_width - (f->rect.left + f->rect.width); + + pr_debug("dma_offset: initial: %d, line: %d\n", + f->dma_offset.initial, f->dma_offset.line); +} + +/* Locking: called with camif->slock spinlock held */ +static int s3c_camif_hw_init(struct camif_dev *camif, struct camif_vp *vp) +{ + const struct s3c_camif_variant *variant = camif->variant; + + if (camif->sensor.sd == NULL || vp->out_fmt == NULL) + return -EINVAL; + + if (variant->ip_revision == S3C244X_CAMIF_IP_REV) + camif_hw_clear_fifo_overflow(vp); + camif_hw_set_camera_bus(camif); + camif_hw_set_source_format(camif); + camif_hw_set_camera_crop(camif); + camif_hw_set_test_pattern(camif, camif->test_pattern); + if (variant->has_img_effect) + camif_hw_set_effect(camif, camif->colorfx, + camif->colorfx_cb, camif->colorfx_cr); + if (variant->ip_revision == S3C6410_CAMIF_IP_REV) + camif_hw_set_input_path(vp); + camif_cfg_video_path(vp); + vp->state &= ~ST_VP_CONFIG; + + return 0; +} + +/* + * Initialize the video path, only up from the scaler stage. The camera + * input interface set up is skipped. This is useful to enable one of the + * video paths when the other is already running. + * Locking: called with camif->slock spinlock held. + */ +static int s3c_camif_hw_vp_init(struct camif_dev *camif, struct camif_vp *vp) +{ + unsigned int ip_rev = camif->variant->ip_revision; + + if (vp->out_fmt == NULL) + return -EINVAL; + + camif_prepare_dma_offset(vp); + if (ip_rev == S3C244X_CAMIF_IP_REV) + camif_hw_clear_fifo_overflow(vp); + camif_cfg_video_path(vp); + vp->state &= ~ST_VP_CONFIG; + return 0; +} + +static int sensor_set_power(struct camif_dev *camif, int on) +{ + struct cam_sensor *sensor = &camif->sensor; + int err = 0; + + if (!on == camif->sensor.power_count) + err = v4l2_subdev_call(sensor->sd, core, s_power, on); + if (!err) + sensor->power_count += on ? 1 : -1; + + pr_debug("on: %d, power_count: %d, err: %d\n", + on, sensor->power_count, err); + + return err; +} + +static int sensor_set_streaming(struct camif_dev *camif, int on) +{ + struct cam_sensor *sensor = &camif->sensor; + int err = 0; + + if (!on == camif->sensor.stream_count) + err = v4l2_subdev_call(sensor->sd, video, s_stream, on); + if (!err) + sensor->stream_count += on ? 1 : -1; + + pr_debug("on: %d, stream_count: %d, err: %d\n", + on, sensor->stream_count, err); + + return err; +} + +/* + * Reinitialize the driver so it is ready to start streaming again. + * Return any buffers to vb2, perform CAMIF software reset and + * turn off streaming at the data pipeline (sensor) if required. + */ +static int camif_reinitialize(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + struct camif_buffer *buf; + unsigned long flags; + bool streaming; + + spin_lock_irqsave(&camif->slock, flags); + streaming = vp->state & ST_VP_SENSOR_STREAMING; + + vp->state &= ~(ST_VP_PENDING | ST_VP_RUNNING | ST_VP_OFF | + ST_VP_ABORTING | ST_VP_STREAMING | + ST_VP_SENSOR_STREAMING | ST_VP_LASTIRQ); + + /* Release unused buffers */ + while (!list_empty(&vp->pending_buf_q)) { + buf = camif_pending_queue_pop(vp); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + while (!list_empty(&vp->active_buf_q)) { + buf = camif_active_queue_pop(vp); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + + spin_unlock_irqrestore(&camif->slock, flags); + + if (!streaming) + return 0; + + return sensor_set_streaming(camif, 0); +} + +static bool s3c_vp_active(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + unsigned long flags; + bool ret; + + spin_lock_irqsave(&camif->slock, flags); + ret = (vp->state & ST_VP_RUNNING) || (vp->state & ST_VP_PENDING); + spin_unlock_irqrestore(&camif->slock, flags); + + return ret; +} + +static bool camif_is_streaming(struct camif_dev *camif) +{ + unsigned long flags; + bool status; + + spin_lock_irqsave(&camif->slock, flags); + status = camif->stream_count > 0; + spin_unlock_irqrestore(&camif->slock, flags); + + return status; +} + +static int camif_stop_capture(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + unsigned long flags; + int ret; + + if (!s3c_vp_active(vp)) + return 0; + + spin_lock_irqsave(&camif->slock, flags); + vp->state &= ~(ST_VP_OFF | ST_VP_LASTIRQ); + vp->state |= ST_VP_ABORTING; + spin_unlock_irqrestore(&camif->slock, flags); + + ret = wait_event_timeout(vp->irq_queue, + !(vp->state & ST_VP_ABORTING), + msecs_to_jiffies(CAMIF_STOP_TIMEOUT)); + + spin_lock_irqsave(&camif->slock, flags); + + if (ret == 0 && !(vp->state & ST_VP_OFF)) { + /* Timed out, forcibly stop capture */ + vp->state &= ~(ST_VP_OFF | ST_VP_ABORTING | + ST_VP_LASTIRQ); + + camif_hw_disable_capture(vp); + camif_hw_enable_scaler(vp, false); + } + + spin_unlock_irqrestore(&camif->slock, flags); + + return camif_reinitialize(vp); +} + +static int camif_prepare_addr(struct camif_vp *vp, struct vb2_buffer *vb, + struct camif_addr *paddr) +{ + struct camif_frame *frame = &vp->out_frame; + u32 pix_size; + + if (vb == NULL || frame == NULL) + return -EINVAL; + + pix_size = frame->rect.width * frame->rect.height; + + pr_debug("colplanes: %d, pix_size: %u\n", + vp->out_fmt->colplanes, pix_size); + + paddr->y = vb2_dma_contig_plane_dma_addr(vb, 0); + + switch (vp->out_fmt->colplanes) { + case 1: + paddr->cb = 0; + paddr->cr = 0; + break; + case 2: + /* decompose Y into Y/Cb */ + paddr->cb = (u32)(paddr->y + pix_size); + paddr->cr = 0; + break; + case 3: + paddr->cb = (u32)(paddr->y + pix_size); + /* decompose Y into Y/Cb/Cr */ + if (vp->out_fmt->color == IMG_FMT_YCBCR422P) + paddr->cr = (u32)(paddr->cb + (pix_size >> 1)); + else /* 420 */ + paddr->cr = (u32)(paddr->cb + (pix_size >> 2)); + + if (vp->out_fmt->color == IMG_FMT_YCRCB420) + swap(paddr->cb, paddr->cr); + break; + default: + return -EINVAL; + } + + pr_debug("DMA address: y: %#x cb: %#x cr: %#x\n", + paddr->y, paddr->cb, paddr->cr); + + return 0; +} + +irqreturn_t s3c_camif_irq_handler(int irq, void *priv) +{ + struct camif_vp *vp = priv; + struct camif_dev *camif = vp->camif; + unsigned int ip_rev = camif->variant->ip_revision; + unsigned int status; + + spin_lock(&camif->slock); + + if (ip_rev == S3C6410_CAMIF_IP_REV) + camif_hw_clear_pending_irq(vp); + + status = camif_hw_get_status(vp); + + if (ip_rev == S3C244X_CAMIF_IP_REV && (status & CISTATUS_OVF_MASK)) { + camif_hw_clear_fifo_overflow(vp); + goto unlock; + } + + if (vp->state & ST_VP_ABORTING) { + if (vp->state & ST_VP_OFF) { + /* Last IRQ */ + vp->state &= ~(ST_VP_OFF | ST_VP_ABORTING | + ST_VP_LASTIRQ); + wake_up(&vp->irq_queue); + goto unlock; + } else if (vp->state & ST_VP_LASTIRQ) { + camif_hw_disable_capture(vp); + camif_hw_enable_scaler(vp, false); + camif_hw_set_lastirq(vp, false); + vp->state |= ST_VP_OFF; + } else { + /* Disable capture, enable last IRQ */ + camif_hw_set_lastirq(vp, true); + vp->state |= ST_VP_LASTIRQ; + } + } + + if (!list_empty(&vp->pending_buf_q) && (vp->state & ST_VP_RUNNING) && + !list_empty(&vp->active_buf_q)) { + unsigned int index; + struct camif_buffer *vbuf; + struct timeval *tv; + struct timespec ts; + /* + * Get previous DMA write buffer index: + * 0 => DMA buffer 0, 2; + * 1 => DMA buffer 1, 3. + */ + index = (CISTATUS_FRAMECNT(status) + 2) & 1; + + ktime_get_ts(&ts); + vbuf = camif_active_queue_peek(vp, index); + + if (!WARN_ON(vbuf == NULL)) { + /* Dequeue a filled buffer */ + tv = &vbuf->vb.v4l2_buf.timestamp; + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC; + vbuf->vb.v4l2_buf.sequence = vp->frame_sequence++; + vb2_buffer_done(&vbuf->vb, VB2_BUF_STATE_DONE); + + /* Set up an empty buffer at the DMA engine */ + vbuf = camif_pending_queue_pop(vp); + vbuf->index = index; + camif_hw_set_output_addr(vp, &vbuf->paddr, index); + camif_hw_set_output_addr(vp, &vbuf->paddr, index + 2); + + /* Scheduled in H/W, add to the queue */ + camif_active_queue_add(vp, vbuf); + } + } else if (!(vp->state & ST_VP_ABORTING) && + (vp->state & ST_VP_PENDING)) { + vp->state |= ST_VP_RUNNING; + } + + if (vp->state & ST_VP_CONFIG) { + camif_prepare_dma_offset(vp); + camif_hw_set_camera_crop(camif); + camif_hw_set_scaler(vp); + camif_hw_set_flip(vp); + camif_hw_set_test_pattern(camif, camif->test_pattern); + if (camif->variant->has_img_effect) + camif_hw_set_effect(camif, camif->colorfx, + camif->colorfx_cb, camif->colorfx_cr); + vp->state &= ~ST_VP_CONFIG; + } +unlock: + spin_unlock(&camif->slock); + return IRQ_HANDLED; +} + +static int start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct camif_vp *vp = vb2_get_drv_priv(vq); + struct camif_dev *camif = vp->camif; + unsigned long flags; + int ret; + + /* + * We assume the codec capture path is always activated + * first, before the preview path starts streaming. + * This is required to avoid internal FIFO overflow and + * a need for CAMIF software reset. + */ + spin_lock_irqsave(&camif->slock, flags); + + if (camif->stream_count == 0) { + camif_hw_reset(camif); + ret = s3c_camif_hw_init(camif, vp); + } else { + ret = s3c_camif_hw_vp_init(camif, vp); + } + spin_unlock_irqrestore(&camif->slock, flags); + + if (ret < 0) { + camif_reinitialize(vp); + return ret; + } + + spin_lock_irqsave(&camif->slock, flags); + vp->frame_sequence = 0; + vp->state |= ST_VP_PENDING; + + if (!list_empty(&vp->pending_buf_q) && + (!(vp->state & ST_VP_STREAMING) || + !(vp->state & ST_VP_SENSOR_STREAMING))) { + + camif_hw_enable_scaler(vp, vp->scaler.enable); + camif_hw_enable_capture(vp); + vp->state |= ST_VP_STREAMING; + + if (!(vp->state & ST_VP_SENSOR_STREAMING)) { + vp->state |= ST_VP_SENSOR_STREAMING; + spin_unlock_irqrestore(&camif->slock, flags); + ret = sensor_set_streaming(camif, 1); + if (ret) + v4l2_err(&vp->vdev, "Sensor s_stream failed\n"); + if (debug) + camif_hw_dump_regs(camif, __func__); + + return ret; + } + } + + spin_unlock_irqrestore(&camif->slock, flags); + return 0; +} + +static int stop_streaming(struct vb2_queue *vq) +{ + struct camif_vp *vp = vb2_get_drv_priv(vq); + return camif_stop_capture(vp); +} + +static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *allocators[]) +{ + const struct v4l2_pix_format *pix = NULL; + struct camif_vp *vp = vb2_get_drv_priv(vq); + struct camif_dev *camif = vp->camif; + struct camif_frame *frame = &vp->out_frame; + const struct camif_fmt *fmt = vp->out_fmt; + unsigned int size; + + if (pfmt) { + pix = &pfmt->fmt.pix; + fmt = s3c_camif_find_format(vp, &pix->pixelformat, -1); + size = (pix->width * pix->height * fmt->depth) / 8; + } else { + size = (frame->f_width * frame->f_height * fmt->depth) / 8; + } + + if (fmt == NULL) + return -EINVAL; + *num_planes = 1; + + if (pix) + sizes[0] = max(size, pix->sizeimage); + else + sizes[0] = size; + allocators[0] = camif->alloc_ctx; + + pr_debug("size: %u\n", sizes[0]); + return 0; +} + +static int buffer_prepare(struct vb2_buffer *vb) +{ + struct camif_vp *vp = vb2_get_drv_priv(vb->vb2_queue); + + if (vp->out_fmt == NULL) + return -EINVAL; + + if (vb2_plane_size(vb, 0) < vp->payload) { + v4l2_err(&vp->vdev, "buffer too small: %lu, required: %u\n", + vb2_plane_size(vb, 0), vp->payload); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, vp->payload); + + return 0; +} + +static void buffer_queue(struct vb2_buffer *vb) +{ + struct camif_buffer *buf = container_of(vb, struct camif_buffer, vb); + struct camif_vp *vp = vb2_get_drv_priv(vb->vb2_queue); + struct camif_dev *camif = vp->camif; + unsigned long flags; + + spin_lock_irqsave(&camif->slock, flags); + WARN_ON(camif_prepare_addr(vp, &buf->vb, &buf->paddr)); + + if (!(vp->state & ST_VP_STREAMING) && vp->active_buffers < 2) { + /* Schedule an empty buffer in H/W */ + buf->index = vp->buf_index; + + camif_hw_set_output_addr(vp, &buf->paddr, buf->index); + camif_hw_set_output_addr(vp, &buf->paddr, buf->index + 2); + + camif_active_queue_add(vp, buf); + vp->buf_index = !vp->buf_index; + } else { + camif_pending_queue_add(vp, buf); + } + + if (vb2_is_streaming(&vp->vb_queue) && !list_empty(&vp->pending_buf_q) + && !(vp->state & ST_VP_STREAMING)) { + + vp->state |= ST_VP_STREAMING; + camif_hw_enable_scaler(vp, vp->scaler.enable); + camif_hw_enable_capture(vp); + spin_unlock_irqrestore(&camif->slock, flags); + + if (!(vp->state & ST_VP_SENSOR_STREAMING)) { + if (sensor_set_streaming(camif, 1) == 0) + vp->state |= ST_VP_SENSOR_STREAMING; + else + v4l2_err(&vp->vdev, "Sensor s_stream failed\n"); + + if (debug) + camif_hw_dump_regs(camif, __func__); + } + return; + } + spin_unlock_irqrestore(&camif->slock, flags); +} + +static void camif_lock(struct vb2_queue *vq) +{ + struct camif_vp *vp = vb2_get_drv_priv(vq); + mutex_lock(&vp->camif->lock); +} + +static void camif_unlock(struct vb2_queue *vq) +{ + struct camif_vp *vp = vb2_get_drv_priv(vq); + mutex_unlock(&vp->camif->lock); +} + +static const struct vb2_ops s3c_camif_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_queue = buffer_queue, + .wait_prepare = camif_unlock, + .wait_finish = camif_lock, + .start_streaming = start_streaming, + .stop_streaming = stop_streaming, +}; + +static int s3c_camif_open(struct file *file) +{ + struct camif_vp *vp = video_drvdata(file); + struct camif_dev *camif = vp->camif; + int ret; + + pr_debug("[vp%d] state: %#x, owner: %p, pid: %d\n", vp->id, + vp->state, vp->owner, task_pid_nr(current)); + + if (mutex_lock_interruptible(&camif->lock)) + return -ERESTARTSYS; + + ret = v4l2_fh_open(file); + if (ret < 0) + goto unlock; + + ret = pm_runtime_get_sync(camif->dev); + if (ret < 0) + goto err_pm; + + ret = sensor_set_power(camif, 1); + if (!ret) + goto unlock; + + pm_runtime_put(camif->dev); +err_pm: + v4l2_fh_release(file); +unlock: + mutex_unlock(&camif->lock); + return ret; +} + +static int s3c_camif_close(struct file *file) +{ + struct camif_vp *vp = video_drvdata(file); + struct camif_dev *camif = vp->camif; + int ret; + + pr_debug("[vp%d] state: %#x, owner: %p, pid: %d\n", vp->id, + vp->state, vp->owner, task_pid_nr(current)); + + mutex_lock(&camif->lock); + + if (vp->owner == file->private_data) { + camif_stop_capture(vp); + vb2_queue_release(&vp->vb_queue); + vp->owner = NULL; + } + + sensor_set_power(camif, 0); + + pm_runtime_put(camif->dev); + ret = v4l2_fh_release(file); + + mutex_unlock(&camif->lock); + return ret; +} + +static unsigned int s3c_camif_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct camif_vp *vp = video_drvdata(file); + struct camif_dev *camif = vp->camif; + int ret; + + mutex_lock(&camif->lock); + if (vp->owner && vp->owner != file->private_data) + ret = -EBUSY; + else + ret = vb2_poll(&vp->vb_queue, file, wait); + + mutex_unlock(&camif->lock); + return ret; +} + +static int s3c_camif_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct camif_vp *vp = video_drvdata(file); + int ret; + + if (vp->owner && vp->owner != file->private_data) + ret = -EBUSY; + else + ret = vb2_mmap(&vp->vb_queue, vma); + + return ret; +} + +static const struct v4l2_file_operations s3c_camif_fops = { + .owner = THIS_MODULE, + .open = s3c_camif_open, + .release = s3c_camif_close, + .poll = s3c_camif_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = s3c_camif_mmap, +}; + +/* + * Video node IOCTLs + */ + +static int s3c_camif_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct camif_vp *vp = video_drvdata(file); + + strlcpy(cap->driver, S3C_CAMIF_DRIVER_NAME, sizeof(cap->driver)); + strlcpy(cap->card, S3C_CAMIF_DRIVER_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s.%d", + dev_name(vp->camif->dev), vp->id); + + cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int s3c_camif_vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *input) +{ + struct camif_vp *vp = video_drvdata(file); + struct v4l2_subdev *sensor = vp->camif->sensor.sd; + + if (input->index || sensor == NULL) + return -EINVAL; + + input->type = V4L2_INPUT_TYPE_CAMERA; + strlcpy(input->name, sensor->name, sizeof(input->name)); + return 0; +} + +static int s3c_camif_vidioc_s_input(struct file *file, void *priv, + unsigned int i) +{ + return i == 0 ? 0 : -EINVAL; +} + +static int s3c_camif_vidioc_g_input(struct file *file, void *priv, + unsigned int *i) +{ + *i = 0; + return 0; +} + +static int s3c_camif_vidioc_enum_fmt(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct camif_vp *vp = video_drvdata(file); + const struct camif_fmt *fmt; + + fmt = s3c_camif_find_format(vp, NULL, f->index); + if (!fmt) + return -EINVAL; + + strlcpy(f->description, fmt->name, sizeof(f->description)); + f->pixelformat = fmt->fourcc; + + pr_debug("fmt(%d): %s\n", f->index, f->description); + return 0; +} + +static int s3c_camif_vidioc_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct camif_vp *vp = video_drvdata(file); + struct v4l2_pix_format *pix = &f->fmt.pix; + struct camif_frame *frame = &vp->out_frame; + const struct camif_fmt *fmt = vp->out_fmt; + + pix->bytesperline = frame->f_width * fmt->ybpp; + pix->sizeimage = vp->payload; + + pix->pixelformat = fmt->fourcc; + pix->width = frame->f_width; + pix->height = frame->f_height; + pix->field = V4L2_FIELD_NONE; + pix->colorspace = V4L2_COLORSPACE_JPEG; + + return 0; +} + +static int __camif_video_try_format(struct camif_vp *vp, + struct v4l2_pix_format *pix, + const struct camif_fmt **ffmt) +{ + struct camif_dev *camif = vp->camif; + struct v4l2_rect *crop = &camif->camif_crop; + unsigned int wmin, hmin, sc_hrmax, sc_vrmax; + const struct vp_pix_limits *pix_lim; + const struct camif_fmt *fmt; + + fmt = s3c_camif_find_format(vp, &pix->pixelformat, 0); + + if (WARN_ON(fmt == NULL)) + return -EINVAL; + + if (ffmt) + *ffmt = fmt; + + pix_lim = &camif->variant->vp_pix_limits[vp->id]; + + pr_debug("fmt: %ux%u, crop: %ux%u, bytesperline: %u\n", + pix->width, pix->height, crop->width, crop->height, + pix->bytesperline); + /* + * Calculate minimum width and height according to the configured + * camera input interface crop rectangle and the resizer's capabilities. + */ + sc_hrmax = min(SCALER_MAX_RATIO, 1 << (ffs(crop->width) - 3)); + sc_vrmax = min(SCALER_MAX_RATIO, 1 << (ffs(crop->height) - 1)); + + wmin = max_t(u32, pix_lim->min_out_width, crop->width / sc_hrmax); + wmin = round_up(wmin, pix_lim->out_width_align); + hmin = max_t(u32, 8, crop->height / sc_vrmax); + hmin = round_up(hmin, 8); + + v4l_bound_align_image(&pix->width, wmin, pix_lim->max_sc_out_width, + ffs(pix_lim->out_width_align) - 1, + &pix->height, hmin, pix_lim->max_height, 0, 0); + + pix->bytesperline = pix->width * fmt->ybpp; + pix->sizeimage = (pix->width * pix->height * fmt->depth) / 8; + pix->pixelformat = fmt->fourcc; + pix->colorspace = V4L2_COLORSPACE_JPEG; + pix->field = V4L2_FIELD_NONE; + + pr_debug("%ux%u, wmin: %d, hmin: %d, sc_hrmax: %d, sc_vrmax: %d\n", + pix->width, pix->height, wmin, hmin, sc_hrmax, sc_vrmax); + + return 0; +} + +static int s3c_camif_vidioc_try_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct camif_vp *vp = video_drvdata(file); + return __camif_video_try_format(vp, &f->fmt.pix, NULL); +} + +static int s3c_camif_vidioc_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format *pix = &f->fmt.pix; + struct camif_vp *vp = video_drvdata(file); + struct camif_frame *out_frame = &vp->out_frame; + const struct camif_fmt *fmt = NULL; + int ret; + + pr_debug("[vp%d]\n", vp->id); + + if (vb2_is_busy(&vp->vb_queue)) + return -EBUSY; + + ret = __camif_video_try_format(vp, &f->fmt.pix, &fmt); + if (ret < 0) + return ret; + + vp->out_fmt = fmt; + vp->payload = pix->sizeimage; + out_frame->f_width = pix->width; + out_frame->f_height = pix->height; + + /* Reset composition rectangle */ + out_frame->rect.width = pix->width; + out_frame->rect.height = pix->height; + out_frame->rect.left = 0; + out_frame->rect.top = 0; + + if (vp->owner == NULL) + vp->owner = priv; + + pr_debug("%ux%u. payload: %u. fmt: %s. %d %d. sizeimage: %d. bpl: %d\n", + out_frame->f_width, out_frame->f_height, vp->payload, fmt->name, + pix->width * pix->height * fmt->depth, fmt->depth, + pix->sizeimage, pix->bytesperline); + + return 0; +} + +/* Only check pixel formats at the sensor and the camif subdev pads */ +static int camif_pipeline_validate(struct camif_dev *camif) +{ + struct v4l2_subdev_format src_fmt; + struct media_pad *pad; + int ret; + + /* Retrieve format at the sensor subdev source pad */ + pad = media_entity_remote_source(&camif->pads[0]); + if (!pad || media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV) + return -EPIPE; + + src_fmt.pad = pad->index; + src_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(camif->sensor.sd, pad, get_fmt, NULL, &src_fmt); + if (ret < 0 && ret != -ENOIOCTLCMD) + return -EPIPE; + + if (src_fmt.format.width != camif->mbus_fmt.width || + src_fmt.format.height != camif->mbus_fmt.height || + src_fmt.format.code != camif->mbus_fmt.code) + return -EPIPE; + + return 0; +} + +static int s3c_camif_streamon(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct camif_vp *vp = video_drvdata(file); + struct camif_dev *camif = vp->camif; + struct media_entity *sensor = &camif->sensor.sd->entity; + int ret; + + pr_debug("[vp%d]\n", vp->id); + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (vp->owner && vp->owner != priv) + return -EBUSY; + + if (s3c_vp_active(vp)) + return 0; + + ret = media_entity_pipeline_start(sensor, camif->m_pipeline); + if (ret < 0) + return ret; + + ret = camif_pipeline_validate(camif); + if (ret < 0) { + media_entity_pipeline_stop(sensor); + return ret; + } + + return vb2_streamon(&vp->vb_queue, type); +} + +static int s3c_camif_streamoff(struct file *file, void *priv, + enum v4l2_buf_type type) +{ + struct camif_vp *vp = video_drvdata(file); + struct camif_dev *camif = vp->camif; + int ret; + + pr_debug("[vp%d]\n", vp->id); + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (vp->owner && vp->owner != priv) + return -EBUSY; + + ret = vb2_streamoff(&vp->vb_queue, type); + if (ret == 0) + media_entity_pipeline_stop(&camif->sensor.sd->entity); + return ret; +} + +static int s3c_camif_reqbufs(struct file *file, void *priv, + struct v4l2_requestbuffers *rb) +{ + struct camif_vp *vp = video_drvdata(file); + int ret; + + pr_debug("[vp%d] rb count: %d, owner: %p, priv: %p\n", + vp->id, rb->count, vp->owner, priv); + + if (vp->owner && vp->owner != priv) + return -EBUSY; + + if (rb->count) + rb->count = max_t(u32, CAMIF_REQ_BUFS_MIN, rb->count); + else + vp->owner = NULL; + + ret = vb2_reqbufs(&vp->vb_queue, rb); + if (!ret) { + vp->reqbufs_count = rb->count; + if (vp->owner == NULL && rb->count > 0) + vp->owner = priv; + } + + return ret; +} + +static int s3c_camif_querybuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct camif_vp *vp = video_drvdata(file); + return vb2_querybuf(&vp->vb_queue, buf); +} + +static int s3c_camif_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct camif_vp *vp = video_drvdata(file); + + pr_debug("[vp%d]\n", vp->id); + + if (vp->owner && vp->owner != priv) + return -EBUSY; + + return vb2_qbuf(&vp->vb_queue, buf); +} + +static int s3c_camif_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct camif_vp *vp = video_drvdata(file); + + pr_debug("[vp%d] sequence: %d\n", vp->id, vp->frame_sequence); + + if (vp->owner && vp->owner != priv) + return -EBUSY; + + return vb2_dqbuf(&vp->vb_queue, buf, file->f_flags & O_NONBLOCK); +} + +static int s3c_camif_create_bufs(struct file *file, void *priv, + struct v4l2_create_buffers *create) +{ + struct camif_vp *vp = video_drvdata(file); + int ret; + + if (vp->owner && vp->owner != priv) + return -EBUSY; + + create->count = max_t(u32, 1, create->count); + ret = vb2_create_bufs(&vp->vb_queue, create); + + if (!ret && vp->owner == NULL) + vp->owner = priv; + + return ret; +} + +static int s3c_camif_prepare_buf(struct file *file, void *priv, + struct v4l2_buffer *b) +{ + struct camif_vp *vp = video_drvdata(file); + return vb2_prepare_buf(&vp->vb_queue, b); +} + +static int s3c_camif_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct camif_vp *vp = video_drvdata(file); + + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = vp->out_frame.f_width; + sel->r.height = vp->out_frame.f_height; + return 0; + + case V4L2_SEL_TGT_COMPOSE: + sel->r = vp->out_frame.rect; + return 0; + } + + return -EINVAL; +} + +static void __camif_try_compose(struct camif_dev *camif, struct camif_vp *vp, + struct v4l2_rect *r) +{ + /* s3c244x doesn't support composition */ + if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV) { + *r = vp->out_frame.rect; + return; + } + + /* TODO: s3c64xx */ +} + +static int s3c_camif_s_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct camif_vp *vp = video_drvdata(file); + struct camif_dev *camif = vp->camif; + struct v4l2_rect rect = sel->r; + unsigned long flags; + + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + sel->target != V4L2_SEL_TGT_COMPOSE) + return -EINVAL; + + __camif_try_compose(camif, vp, &rect); + + sel->r = rect; + spin_lock_irqsave(&camif->slock, flags); + vp->out_frame.rect = rect; + vp->state |= ST_VP_CONFIG; + spin_unlock_irqrestore(&camif->slock, flags); + + pr_debug("type: %#x, target: %#x, flags: %#x, (%d,%d)/%dx%d\n", + sel->type, sel->target, sel->flags, + sel->r.left, sel->r.top, sel->r.width, sel->r.height); + + return 0; +} + +static const struct v4l2_ioctl_ops s3c_camif_ioctl_ops = { + .vidioc_querycap = s3c_camif_vidioc_querycap, + .vidioc_enum_input = s3c_camif_vidioc_enum_input, + .vidioc_g_input = s3c_camif_vidioc_g_input, + .vidioc_s_input = s3c_camif_vidioc_s_input, + .vidioc_enum_fmt_vid_cap = s3c_camif_vidioc_enum_fmt, + .vidioc_try_fmt_vid_cap = s3c_camif_vidioc_try_fmt, + .vidioc_s_fmt_vid_cap = s3c_camif_vidioc_s_fmt, + .vidioc_g_fmt_vid_cap = s3c_camif_vidioc_g_fmt, + .vidioc_g_selection = s3c_camif_g_selection, + .vidioc_s_selection = s3c_camif_s_selection, + .vidioc_reqbufs = s3c_camif_reqbufs, + .vidioc_querybuf = s3c_camif_querybuf, + .vidioc_prepare_buf = s3c_camif_prepare_buf, + .vidioc_create_bufs = s3c_camif_create_bufs, + .vidioc_qbuf = s3c_camif_qbuf, + .vidioc_dqbuf = s3c_camif_dqbuf, + .vidioc_streamon = s3c_camif_streamon, + .vidioc_streamoff = s3c_camif_streamoff, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +/* + * Video node controls + */ +static int s3c_camif_video_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct camif_vp *vp = ctrl->priv; + struct camif_dev *camif = vp->camif; + unsigned long flags; + + pr_debug("[vp%d] ctrl: %s, value: %d\n", vp->id, + ctrl->name, ctrl->val); + + spin_lock_irqsave(&camif->slock, flags); + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + vp->hflip = ctrl->val; + break; + + case V4L2_CID_VFLIP: + vp->vflip = ctrl->val; + break; + } + + vp->state |= ST_VP_CONFIG; + spin_unlock_irqrestore(&camif->slock, flags); + return 0; +} + +/* Codec and preview video node control ops */ +static const struct v4l2_ctrl_ops s3c_camif_video_ctrl_ops = { + .s_ctrl = s3c_camif_video_s_ctrl, +}; + +int s3c_camif_register_video_node(struct camif_dev *camif, int idx) +{ + struct camif_vp *vp = &camif->vp[idx]; + struct vb2_queue *q = &vp->vb_queue; + struct video_device *vfd = &vp->vdev; + struct v4l2_ctrl *ctrl; + int ret; + + memset(vfd, 0, sizeof(*vfd)); + snprintf(vfd->name, sizeof(vfd->name), "camif-%s", + vp->id == 0 ? "codec" : "preview"); + + vfd->fops = &s3c_camif_fops; + vfd->ioctl_ops = &s3c_camif_ioctl_ops; + vfd->v4l2_dev = &camif->v4l2_dev; + vfd->minor = -1; + vfd->release = video_device_release_empty; + vfd->lock = &camif->lock; + vp->reqbufs_count = 0; + + INIT_LIST_HEAD(&vp->pending_buf_q); + INIT_LIST_HEAD(&vp->active_buf_q); + + memset(q, 0, sizeof(*q)); + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR; + q->ops = &s3c_camif_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->buf_struct_size = sizeof(struct camif_buffer); + q->drv_priv = vp; + + ret = vb2_queue_init(q); + if (ret) + goto err_vd_rel; + + vp->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_init(&vfd->entity, 1, &vp->pad, 0); + if (ret) + goto err_vd_rel; + + video_set_drvdata(vfd, vp); + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); + + v4l2_ctrl_handler_init(&vp->ctrl_handler, 1); + ctrl = v4l2_ctrl_new_std(&vp->ctrl_handler, &s3c_camif_video_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + if (ctrl) + ctrl->priv = vp; + ctrl = v4l2_ctrl_new_std(&vp->ctrl_handler, &s3c_camif_video_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + if (ctrl) + ctrl->priv = vp; + + ret = vp->ctrl_handler.error; + if (ret < 0) + goto err_me_cleanup; + + vfd->ctrl_handler = &vp->ctrl_handler; + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1); + if (ret) + goto err_ctrlh_free; + + v4l2_info(&camif->v4l2_dev, "registered %s as /dev/%s\n", + vfd->name, video_device_node_name(vfd)); + return 0; + +err_ctrlh_free: + v4l2_ctrl_handler_free(&vp->ctrl_handler); +err_me_cleanup: + media_entity_cleanup(&vfd->entity); +err_vd_rel: + video_device_release(vfd); + return ret; +} + +void s3c_camif_unregister_video_node(struct camif_dev *camif, int idx) +{ + struct video_device *vfd = &camif->vp[idx].vdev; + + if (video_is_registered(vfd)) { + video_unregister_device(vfd); + media_entity_cleanup(&vfd->entity); + v4l2_ctrl_handler_free(vfd->ctrl_handler); + } +} + +/* Media bus pixel formats supported at the camif input */ +static const enum v4l2_mbus_pixelcode camif_mbus_formats[] = { + V4L2_MBUS_FMT_YUYV8_2X8, + V4L2_MBUS_FMT_YVYU8_2X8, + V4L2_MBUS_FMT_UYVY8_2X8, + V4L2_MBUS_FMT_VYUY8_2X8, +}; + +/* + * Camera input interface subdev operations + */ + +static int s3c_camif_subdev_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index >= ARRAY_SIZE(camif_mbus_formats)) + return -EINVAL; + + code->code = camif_mbus_formats[code->index]; + return 0; +} + +static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct camif_dev *camif = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &fmt->format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *mf; + return 0; + } + + mutex_lock(&camif->lock); + + switch (fmt->pad) { + case CAMIF_SD_PAD_SINK: + /* full camera input pixel size */ + *mf = camif->mbus_fmt; + break; + + case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P: + /* crop rectangle at camera interface input */ + mf->width = camif->camif_crop.width; + mf->height = camif->camif_crop.height; + mf->code = camif->mbus_fmt.code; + break; + } + + mutex_unlock(&camif->lock); + mf->colorspace = V4L2_COLORSPACE_JPEG; + return 0; +} + +static void __camif_subdev_try_format(struct camif_dev *camif, + struct v4l2_mbus_framefmt *mf, int pad) +{ + const struct s3c_camif_variant *variant = camif->variant; + const struct vp_pix_limits *pix_lim; + int i = ARRAY_SIZE(camif_mbus_formats); + + /* FIXME: constraints against codec or preview path ? */ + pix_lim = &variant->vp_pix_limits[VP_CODEC]; + + while (i-- >= 0) + if (camif_mbus_formats[i] == mf->code) + break; + + mf->code = camif_mbus_formats[i]; + + if (pad == CAMIF_SD_PAD_SINK) { + v4l_bound_align_image(&mf->width, 8, CAMIF_MAX_PIX_WIDTH, + ffs(pix_lim->out_width_align) - 1, + &mf->height, 8, CAMIF_MAX_PIX_HEIGHT, 0, + 0); + } else { + struct v4l2_rect *crop = &camif->camif_crop; + v4l_bound_align_image(&mf->width, 8, crop->width, + ffs(pix_lim->out_width_align) - 1, + &mf->height, 8, crop->height, + 0, 0); + } + + v4l2_dbg(1, debug, &camif->subdev, "%ux%u\n", mf->width, mf->height); +} + +static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_format *fmt) +{ + struct camif_dev *camif = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf = &fmt->format; + struct v4l2_rect *crop = &camif->camif_crop; + int i; + + v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %ux%u\n", + fmt->pad, mf->code, mf->width, mf->height); + + mf->colorspace = V4L2_COLORSPACE_JPEG; + mutex_lock(&camif->lock); + + /* + * No pixel format change at the camera input is allowed + * while streaming. + */ + if (vb2_is_busy(&camif->vp[VP_CODEC].vb_queue) || + vb2_is_busy(&camif->vp[VP_PREVIEW].vb_queue)) { + mutex_unlock(&camif->lock); + return -EBUSY; + } + + __camif_subdev_try_format(camif, mf, fmt->pad); + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + mf = v4l2_subdev_get_try_format(fh, fmt->pad); + *mf = fmt->format; + mutex_unlock(&camif->lock); + return 0; + } + + switch (fmt->pad) { + case CAMIF_SD_PAD_SINK: + camif->mbus_fmt = *mf; + /* Reset sink crop rectangle. */ + crop->width = mf->width; + crop->height = mf->height; + crop->left = 0; + crop->top = 0; + /* + * Reset source format (the camif's crop rectangle) + * and the video output resolution. + */ + for (i = 0; i < CAMIF_VP_NUM; i++) { + struct camif_frame *frame = &camif->vp[i].out_frame; + frame->rect = *crop; + frame->f_width = mf->width; + frame->f_height = mf->height; + } + break; + + case CAMIF_SD_PAD_SOURCE_C...CAMIF_SD_PAD_SOURCE_P: + /* Pixel format can be only changed on the sink pad. */ + mf->code = camif->mbus_fmt.code; + mf->width = crop->width; + mf->height = crop->height; + break; + } + + mutex_unlock(&camif->lock); + return 0; +} + +static int s3c_camif_subdev_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct camif_dev *camif = v4l2_get_subdevdata(sd); + struct v4l2_rect *crop = &camif->camif_crop; + struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt; + + if ((sel->target != V4L2_SEL_TGT_CROP && + sel->target != V4L2_SEL_TGT_CROP_BOUNDS) || + sel->pad != CAMIF_SD_PAD_SINK) + return -EINVAL; + + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad); + return 0; + } + + mutex_lock(&camif->lock); + + if (sel->target == V4L2_SEL_TGT_CROP) { + sel->r = *crop; + } else { /* crop bounds */ + sel->r.width = mf->width; + sel->r.height = mf->height; + sel->r.left = 0; + sel->r.top = 0; + } + + mutex_unlock(&camif->lock); + + v4l2_dbg(1, debug, sd, "%s: crop: (%d,%d) %dx%d, size: %ux%u\n", + __func__, crop->left, crop->top, crop->width, + crop->height, mf->width, mf->height); + + return 0; +} + +static void __camif_try_crop(struct camif_dev *camif, struct v4l2_rect *r) +{ + struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt; + const struct camif_pix_limits *pix_lim = &camif->variant->pix_limits; + unsigned int left = 2 * r->left; + unsigned int top = 2 * r->top; + + /* + * Following constraints must be met: + * - r->width + 2 * r->left = mf->width; + * - r->height + 2 * r->top = mf->height; + * - crop rectangle size and position must be aligned + * to 8 or 2 pixels, depending on SoC version. + */ + v4l_bound_align_image(&r->width, 0, mf->width, + ffs(pix_lim->win_hor_offset_align) - 1, + &r->height, 0, mf->height, 1, 0); + + v4l_bound_align_image(&left, 0, mf->width - r->width, + ffs(pix_lim->win_hor_offset_align), + &top, 0, mf->height - r->height, 2, 0); + + r->left = left / 2; + r->top = top / 2; + r->width = mf->width - left; + r->height = mf->height - top; + /* + * Make sure we either downscale or upscale both the pixel + * width and height. Just return current crop rectangle if + * this scaler constraint is not met. + */ + if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV && + camif_is_streaming(camif)) { + unsigned int i; + + for (i = 0; i < CAMIF_VP_NUM; i++) { + struct v4l2_rect *or = &camif->vp[i].out_frame.rect; + if ((or->width > r->width) == (or->height > r->height)) + continue; + *r = camif->camif_crop; + pr_debug("Width/height scaling direction limitation\n"); + break; + } + } + + v4l2_dbg(1, debug, &camif->v4l2_dev, "crop: (%d,%d)/%dx%d, fmt: %ux%u\n", + r->left, r->top, r->width, r->height, mf->width, mf->height); +} + +static int s3c_camif_subdev_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_fh *fh, + struct v4l2_subdev_selection *sel) +{ + struct camif_dev *camif = v4l2_get_subdevdata(sd); + struct v4l2_rect *crop = &camif->camif_crop; + struct camif_scaler scaler; + + if (sel->target != V4L2_SEL_TGT_CROP || sel->pad != CAMIF_SD_PAD_SINK) + return -EINVAL; + + mutex_lock(&camif->lock); + __camif_try_crop(camif, &sel->r); + + if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_get_try_crop(fh, sel->pad) = sel->r; + } else { + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&camif->slock, flags); + *crop = sel->r; + + for (i = 0; i < CAMIF_VP_NUM; i++) { + struct camif_vp *vp = &camif->vp[i]; + scaler = vp->scaler; + if (s3c_camif_get_scaler_config(vp, &scaler)) + continue; + vp->scaler = scaler; + vp->state |= ST_VP_CONFIG; + } + + spin_unlock_irqrestore(&camif->slock, flags); + } + mutex_unlock(&camif->lock); + + v4l2_dbg(1, debug, sd, "%s: (%d,%d) %dx%d, f_w: %u, f_h: %u\n", + __func__, crop->left, crop->top, crop->width, crop->height, + camif->mbus_fmt.width, camif->mbus_fmt.height); + + return 0; +} + +static const struct v4l2_subdev_pad_ops s3c_camif_subdev_pad_ops = { + .enum_mbus_code = s3c_camif_subdev_enum_mbus_code, + .get_selection = s3c_camif_subdev_get_selection, + .set_selection = s3c_camif_subdev_set_selection, + .get_fmt = s3c_camif_subdev_get_fmt, + .set_fmt = s3c_camif_subdev_set_fmt, +}; + +static struct v4l2_subdev_ops s3c_camif_subdev_ops = { + .pad = &s3c_camif_subdev_pad_ops, +}; + +static int s3c_camif_subdev_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct camif_dev *camif = container_of(ctrl->handler, struct camif_dev, + ctrl_handler); + unsigned long flags; + + spin_lock_irqsave(&camif->slock, flags); + + switch (ctrl->id) { + case V4L2_CID_COLORFX: + camif->colorfx = camif->ctrl_colorfx->val; + /* Set Cb, Cr */ + switch (ctrl->val) { + case V4L2_COLORFX_SEPIA: + camif->colorfx_cb = 115; + camif->colorfx_cr = 145; + break; + case V4L2_COLORFX_SET_CBCR: + camif->colorfx_cb = camif->ctrl_colorfx_cbcr->val >> 8; + camif->colorfx_cr = camif->ctrl_colorfx_cbcr->val & 0xff; + break; + default: + /* for V4L2_COLORFX_BW and others */ + camif->colorfx_cb = 128; + camif->colorfx_cr = 128; + } + break; + case V4L2_CID_TEST_PATTERN: + camif->test_pattern = camif->ctrl_test_pattern->val; + break; + default: + WARN_ON(1); + } + + camif->vp[VP_CODEC].state |= ST_VP_CONFIG; + camif->vp[VP_PREVIEW].state |= ST_VP_CONFIG; + spin_unlock_irqrestore(&camif->slock, flags); + + return 0; +} + +static const struct v4l2_ctrl_ops s3c_camif_subdev_ctrl_ops = { + .s_ctrl = s3c_camif_subdev_s_ctrl, +}; + +static const char * const s3c_camif_test_pattern_menu[] = { + "Disabled", + "Color bars", + "Horizontal increment", + "Vertical increment", +}; + +int s3c_camif_create_subdev(struct camif_dev *camif) +{ + struct v4l2_ctrl_handler *handler = &camif->ctrl_handler; + struct v4l2_subdev *sd = &camif->subdev; + int ret; + + v4l2_subdev_init(sd, &s3c_camif_subdev_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + strlcpy(sd->name, "S3C-CAMIF", sizeof(sd->name)); + + camif->pads[CAMIF_SD_PAD_SINK].flags = MEDIA_PAD_FL_SINK; + camif->pads[CAMIF_SD_PAD_SOURCE_C].flags = MEDIA_PAD_FL_SOURCE; + camif->pads[CAMIF_SD_PAD_SOURCE_P].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_init(&sd->entity, CAMIF_SD_PADS_NUM, + camif->pads, 0); + if (ret) + return ret; + + v4l2_ctrl_handler_init(handler, 3); + camif->ctrl_test_pattern = v4l2_ctrl_new_std_menu_items(handler, + &s3c_camif_subdev_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(s3c_camif_test_pattern_menu) - 1, 0, 0, + s3c_camif_test_pattern_menu); + + camif->ctrl_colorfx = v4l2_ctrl_new_std_menu(handler, + &s3c_camif_subdev_ctrl_ops, + V4L2_CID_COLORFX, V4L2_COLORFX_SET_CBCR, + ~0x981f, V4L2_COLORFX_NONE); + + camif->ctrl_colorfx_cbcr = v4l2_ctrl_new_std(handler, + &s3c_camif_subdev_ctrl_ops, + V4L2_CID_COLORFX_CBCR, 0, 0xffff, 1, 0); + if (handler->error) { + v4l2_ctrl_handler_free(handler); + media_entity_cleanup(&sd->entity); + return handler->error; + } + + v4l2_ctrl_auto_cluster(2, &camif->ctrl_colorfx, + V4L2_COLORFX_SET_CBCR, false); + if (!camif->variant->has_img_effect) { + camif->ctrl_colorfx->flags |= V4L2_CTRL_FLAG_DISABLED; + camif->ctrl_colorfx_cbcr->flags |= V4L2_CTRL_FLAG_DISABLED; + } + sd->ctrl_handler = handler; + v4l2_set_subdevdata(sd, camif); + + return 0; +} + +void s3c_camif_unregister_subdev(struct camif_dev *camif) +{ + struct v4l2_subdev *sd = &camif->subdev; + + /* Return if not registered */ + if (v4l2_get_subdevdata(sd) == NULL) + return; + + v4l2_device_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(&camif->ctrl_handler); + v4l2_set_subdevdata(sd, NULL); +} + +int s3c_camif_set_defaults(struct camif_dev *camif) +{ + unsigned int ip_rev = camif->variant->ip_revision; + int i; + + for (i = 0; i < CAMIF_VP_NUM; i++) { + struct camif_vp *vp = &camif->vp[i]; + struct camif_frame *f = &vp->out_frame; + + vp->camif = camif; + vp->id = i; + vp->offset = camif->variant->vp_offset; + + if (ip_rev == S3C244X_CAMIF_IP_REV) + vp->fmt_flags = i ? FMT_FL_S3C24XX_PREVIEW : + FMT_FL_S3C24XX_CODEC; + else + vp->fmt_flags = FMT_FL_S3C64XX; + + vp->out_fmt = s3c_camif_find_format(vp, NULL, 0); + BUG_ON(vp->out_fmt == NULL); + + memset(f, 0, sizeof(*f)); + f->f_width = CAMIF_DEF_WIDTH; + f->f_height = CAMIF_DEF_HEIGHT; + f->rect.width = CAMIF_DEF_WIDTH; + f->rect.height = CAMIF_DEF_HEIGHT; + + /* Scaler is always enabled */ + vp->scaler.enable = 1; + + vp->payload = (f->f_width * f->f_height * + vp->out_fmt->depth) / 8; + } + + memset(&camif->mbus_fmt, 0, sizeof(camif->mbus_fmt)); + camif->mbus_fmt.width = CAMIF_DEF_WIDTH; + camif->mbus_fmt.height = CAMIF_DEF_HEIGHT; + camif->mbus_fmt.code = camif_mbus_formats[0]; + + memset(&camif->camif_crop, 0, sizeof(camif->camif_crop)); + camif->camif_crop.width = CAMIF_DEF_WIDTH; + camif->camif_crop.height = CAMIF_DEF_HEIGHT; + + return 0; +} diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c new file mode 100644 index 00000000000..0dd65376c06 --- /dev/null +++ b/drivers/media/platform/s3c-camif/camif-core.c @@ -0,0 +1,662 @@ +/* + * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver + * + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> + * + * 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. + */ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include <linux/bug.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gpio.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/list.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <media/media-device.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-ioctl.h> +#include <media/videobuf2-core.h> +#include <media/videobuf2-dma-contig.h> + +#include "camif-core.h" + +static char *camif_clocks[CLK_MAX_NUM] = { + /* HCLK CAMIF clock */ + [CLK_GATE] = "camif", + /* CAMIF / external camera sensor master clock */ + [CLK_CAM] = "camera", +}; + +static const struct camif_fmt camif_formats[] = { + { + .name = "YUV 4:2:2 planar, Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV422P, + .depth = 16, + .ybpp = 1, + .color = IMG_FMT_YCBCR422P, + .colplanes = 3, + .flags = FMT_FL_S3C24XX_CODEC | + FMT_FL_S3C64XX, + }, { + .name = "YUV 4:2:0 planar, Y/Cb/Cr", + .fourcc = V4L2_PIX_FMT_YUV420, + .depth = 12, + .ybpp = 1, + .color = IMG_FMT_YCBCR420, + .colplanes = 3, + .flags = FMT_FL_S3C24XX_CODEC | + FMT_FL_S3C64XX, + }, { + .name = "YVU 4:2:0 planar, Y/Cr/Cb", + .fourcc = V4L2_PIX_FMT_YVU420, + .depth = 12, + .ybpp = 1, + .color = IMG_FMT_YCRCB420, + .colplanes = 3, + .flags = FMT_FL_S3C24XX_CODEC | + FMT_FL_S3C64XX, + }, { + .name = "RGB565, 16 bpp", + .fourcc = V4L2_PIX_FMT_RGB565X, + .depth = 16, + .ybpp = 2, + .color = IMG_FMT_RGB565, + .colplanes = 1, + .flags = FMT_FL_S3C24XX_PREVIEW | + FMT_FL_S3C64XX, + }, { + .name = "XRGB8888, 32 bpp", + .fourcc = V4L2_PIX_FMT_RGB32, + .depth = 32, + .ybpp = 4, + .color = IMG_FMT_XRGB8888, + .colplanes = 1, + .flags = FMT_FL_S3C24XX_PREVIEW | + FMT_FL_S3C64XX, + }, { + .name = "BGR666", + .fourcc = V4L2_PIX_FMT_BGR666, + .depth = 32, + .ybpp = 4, + .color = IMG_FMT_RGB666, + .colplanes = 1, + .flags = FMT_FL_S3C64XX, + } +}; + +/** + * s3c_camif_find_format() - lookup camif color format by fourcc or an index + * @pixelformat: fourcc to match, ignored if null + * @index: index to the camif_formats array, ignored if negative + */ +const struct camif_fmt *s3c_camif_find_format(struct camif_vp *vp, + const u32 *pixelformat, + int index) +{ + const struct camif_fmt *fmt, *def_fmt = NULL; + unsigned int i; + int id = 0; + + if (index >= (int)ARRAY_SIZE(camif_formats)) + return NULL; + + for (i = 0; i < ARRAY_SIZE(camif_formats); ++i) { + fmt = &camif_formats[i]; + if (vp && !(vp->fmt_flags & fmt->flags)) + continue; + if (pixelformat && fmt->fourcc == *pixelformat) + return fmt; + if (index == id) + def_fmt = fmt; + id++; + } + return def_fmt; +} + +static int camif_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift) +{ + unsigned int sh = 6; + + if (src >= 64 * tar) + return -EINVAL; + + while (sh--) { + unsigned int tmp = 1 << sh; + if (src >= tar * tmp) { + *shift = sh, *ratio = tmp; + return 0; + } + } + *shift = 0, *ratio = 1; + return 0; +} + +int s3c_camif_get_scaler_config(struct camif_vp *vp, + struct camif_scaler *scaler) +{ + struct v4l2_rect *camif_crop = &vp->camif->camif_crop; + int source_x = camif_crop->width; + int source_y = camif_crop->height; + int target_x = vp->out_frame.rect.width; + int target_y = vp->out_frame.rect.height; + int ret; + + if (vp->rotation == 90 || vp->rotation == 270) + swap(target_x, target_y); + + ret = camif_get_scaler_factor(source_x, target_x, &scaler->pre_h_ratio, + &scaler->h_shift); + if (ret < 0) + return ret; + + ret = camif_get_scaler_factor(source_y, target_y, &scaler->pre_v_ratio, + &scaler->v_shift); + if (ret < 0) + return ret; + + scaler->pre_dst_width = source_x / scaler->pre_h_ratio; + scaler->pre_dst_height = source_y / scaler->pre_v_ratio; + + scaler->main_h_ratio = (source_x << 8) / (target_x << scaler->h_shift); + scaler->main_v_ratio = (source_y << 8) / (target_y << scaler->v_shift); + + scaler->scaleup_h = (target_x >= source_x); + scaler->scaleup_v = (target_y >= source_y); + + scaler->copy = 0; + + pr_debug("H: ratio: %u, shift: %u. V: ratio: %u, shift: %u.\n", + scaler->pre_h_ratio, scaler->h_shift, + scaler->pre_v_ratio, scaler->v_shift); + + pr_debug("Source: %dx%d, Target: %dx%d, scaleup_h/v: %d/%d\n", + source_x, source_y, target_x, target_y, + scaler->scaleup_h, scaler->scaleup_v); + + return 0; +} + +static int camif_register_sensor(struct camif_dev *camif) +{ + struct s3c_camif_sensor_info *sensor = &camif->pdata.sensor; + struct v4l2_device *v4l2_dev = &camif->v4l2_dev; + struct i2c_adapter *adapter; + struct v4l2_subdev_format format; + struct v4l2_subdev *sd; + int ret; + + camif->sensor.sd = NULL; + + if (sensor->i2c_board_info.addr == 0) + return -EINVAL; + + adapter = i2c_get_adapter(sensor->i2c_bus_num); + if (adapter == NULL) { + v4l2_warn(v4l2_dev, "failed to get I2C adapter %d\n", + sensor->i2c_bus_num); + return -EPROBE_DEFER; + } + + sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter, + &sensor->i2c_board_info, NULL); + if (sd == NULL) { + i2c_put_adapter(adapter); + v4l2_warn(v4l2_dev, "failed to acquire subdev %s\n", + sensor->i2c_board_info.type); + return -EPROBE_DEFER; + } + camif->sensor.sd = sd; + + v4l2_info(v4l2_dev, "registered sensor subdevice %s\n", sd->name); + + /* Get initial pixel format and set it at the camif sink pad */ + format.pad = 0; + format.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format); + + if (ret < 0) + return 0; + + format.pad = CAMIF_SD_PAD_SINK; + v4l2_subdev_call(&camif->subdev, pad, set_fmt, NULL, &format); + + v4l2_info(sd, "Initial format from sensor: %dx%d, %#x\n", + format.format.width, format.format.height, + format.format.code); + return 0; +} + +static void camif_unregister_sensor(struct camif_dev *camif) +{ + struct v4l2_subdev *sd = camif->sensor.sd; + struct i2c_client *client = sd ? v4l2_get_subdevdata(sd) : NULL; + struct i2c_adapter *adapter; + + if (client == NULL) + return; + + adapter = client->adapter; + v4l2_device_unregister_subdev(sd); + camif->sensor.sd = NULL; + i2c_unregister_device(client); + if (adapter) + i2c_put_adapter(adapter); +} + +static int camif_create_media_links(struct camif_dev *camif) +{ + int i, ret; + + ret = media_entity_create_link(&camif->sensor.sd->entity, 0, + &camif->subdev.entity, CAMIF_SD_PAD_SINK, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) + return ret; + + for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) { + ret = media_entity_create_link(&camif->subdev.entity, i, + &camif->vp[i - 1].vdev.entity, 0, + MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + } + + return ret; +} + +static int camif_register_video_nodes(struct camif_dev *camif) +{ + int ret = s3c_camif_register_video_node(camif, VP_CODEC); + if (ret < 0) + return ret; + + return s3c_camif_register_video_node(camif, VP_PREVIEW); +} + +static void camif_unregister_video_nodes(struct camif_dev *camif) +{ + s3c_camif_unregister_video_node(camif, VP_CODEC); + s3c_camif_unregister_video_node(camif, VP_PREVIEW); +} + +static void camif_unregister_media_entities(struct camif_dev *camif) +{ + camif_unregister_video_nodes(camif); + camif_unregister_sensor(camif); + s3c_camif_unregister_subdev(camif); +} + +/* + * Media device + */ +static int camif_media_dev_register(struct camif_dev *camif) +{ + struct media_device *md = &camif->media_dev; + struct v4l2_device *v4l2_dev = &camif->v4l2_dev; + unsigned int ip_rev = camif->variant->ip_revision; + int ret; + + memset(md, 0, sizeof(*md)); + snprintf(md->model, sizeof(md->model), "SAMSUNG S3C%s CAMIF", + ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X"); + strlcpy(md->bus_info, "platform", sizeof(md->bus_info)); + md->hw_revision = ip_rev; + md->driver_version = KERNEL_VERSION(1, 0, 0); + + md->dev = camif->dev; + + strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name)); + v4l2_dev->mdev = md; + + ret = v4l2_device_register(camif->dev, v4l2_dev); + if (ret < 0) + return ret; + + ret = media_device_register(md); + if (ret < 0) + v4l2_device_unregister(v4l2_dev); + + return ret; +} + +static void camif_clk_put(struct camif_dev *camif) +{ + int i; + + for (i = 0; i < CLK_MAX_NUM; i++) { + if (IS_ERR_OR_NULL(camif->clock[i])) + continue; + clk_unprepare(camif->clock[i]); + clk_put(camif->clock[i]); + } +} + +static int camif_clk_get(struct camif_dev *camif) +{ + int ret, i; + + for (i = 0; i < CLK_MAX_NUM; i++) { + camif->clock[i] = clk_get(camif->dev, camif_clocks[i]); + if (IS_ERR(camif->clock[i])) { + ret = PTR_ERR(camif->clock[i]); + goto err; + } + ret = clk_prepare(camif->clock[i]); + if (ret < 0) { + clk_put(camif->clock[i]); + camif->clock[i] = NULL; + goto err; + } + } + return 0; +err: + camif_clk_put(camif); + dev_err(camif->dev, "failed to get clock: %s\n", + camif_clocks[i]); + return ret; +} + +/* + * The CAMIF device has two relatively independent data processing paths + * that can source data from memory or the common camera input frontend. + * Register interrupts for each data processing path (camif_vp). + */ +static int camif_request_irqs(struct platform_device *pdev, + struct camif_dev *camif) +{ + int irq, ret, i; + + for (i = 0; i < CAMIF_VP_NUM; i++) { + struct camif_vp *vp = &camif->vp[i]; + + init_waitqueue_head(&vp->irq_queue); + + irq = platform_get_irq(pdev, i); + if (irq <= 0) { + dev_err(&pdev->dev, "failed to get IRQ %d\n", i); + return -ENXIO; + } + + ret = devm_request_irq(&pdev->dev, irq, s3c_camif_irq_handler, + 0, dev_name(&pdev->dev), vp); + if (ret < 0) { + dev_err(&pdev->dev, "failed to install IRQ: %d\n", ret); + break; + } + } + + return ret; +} + +static int s3c_camif_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct s3c_camif_plat_data *pdata = dev->platform_data; + struct s3c_camif_drvdata *drvdata; + struct camif_dev *camif; + struct resource *mres; + int ret = 0; + + camif = devm_kzalloc(dev, sizeof(*camif), GFP_KERNEL); + if (!camif) + return -ENOMEM; + + spin_lock_init(&camif->slock); + mutex_init(&camif->lock); + + camif->dev = dev; + + if (!pdata || !pdata->gpio_get || !pdata->gpio_put) { + dev_err(dev, "wrong platform data\n"); + return -EINVAL; + } + + camif->pdata = *pdata; + drvdata = (void *)platform_get_device_id(pdev)->driver_data; + camif->variant = drvdata->variant; + + mres = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + camif->io_base = devm_request_and_ioremap(dev, mres); + if (!camif->io_base) { + dev_err(dev, "failed to obtain I/O memory\n"); + return -ENOENT; + } + + ret = camif_request_irqs(pdev, camif); + if (ret < 0) + return ret; + + ret = pdata->gpio_get(); + if (ret < 0) + return ret; + + ret = s3c_camif_create_subdev(camif); + if (ret < 0) + goto err_sd; + + ret = camif_clk_get(camif); + if (ret < 0) + goto err_clk; + + platform_set_drvdata(pdev, camif); + clk_set_rate(camif->clock[CLK_CAM], + camif->pdata.sensor.clock_frequency); + + dev_info(dev, "sensor clock frequency: %lu\n", + clk_get_rate(camif->clock[CLK_CAM])); + /* + * Set initial pixel format, resolution and crop rectangle. + * Must be done before a sensor subdev is registered as some + * settings are overrode with values from sensor subdev. + */ + s3c_camif_set_defaults(camif); + + pm_runtime_enable(dev); + + ret = pm_runtime_get_sync(dev); + if (ret < 0) + goto err_pm; + + /* Initialize contiguous memory allocator */ + camif->alloc_ctx = vb2_dma_contig_init_ctx(dev); + if (IS_ERR(camif->alloc_ctx)) { + ret = PTR_ERR(camif->alloc_ctx); + goto err_alloc; + } + + ret = camif_media_dev_register(camif); + if (ret < 0) + goto err_mdev; + + ret = camif_register_sensor(camif); + if (ret < 0) + goto err_sens; + + ret = v4l2_device_register_subdev(&camif->v4l2_dev, &camif->subdev); + if (ret < 0) + goto err_sens; + + mutex_lock(&camif->media_dev.graph_mutex); + + ret = v4l2_device_register_subdev_nodes(&camif->v4l2_dev); + if (ret < 0) + goto err_unlock; + + ret = camif_register_video_nodes(camif); + if (ret < 0) + goto err_unlock; + + ret = camif_create_media_links(camif); + if (ret < 0) + goto err_unlock; + + mutex_unlock(&camif->media_dev.graph_mutex); + pm_runtime_put(dev); + return 0; + +err_unlock: + mutex_unlock(&camif->media_dev.graph_mutex); +err_sens: + v4l2_device_unregister(&camif->v4l2_dev); + media_device_unregister(&camif->media_dev); + camif_unregister_media_entities(camif); +err_mdev: + vb2_dma_contig_cleanup_ctx(camif->alloc_ctx); +err_alloc: + pm_runtime_put(dev); + pm_runtime_disable(dev); +err_pm: + camif_clk_put(camif); +err_clk: + s3c_camif_unregister_subdev(camif); +err_sd: + pdata->gpio_put(); + return ret; +} + +static int __devexit s3c_camif_remove(struct platform_device *pdev) +{ + struct camif_dev *camif = platform_get_drvdata(pdev); + struct s3c_camif_plat_data *pdata = &camif->pdata; + + media_device_unregister(&camif->media_dev); + camif_unregister_media_entities(camif); + v4l2_device_unregister(&camif->v4l2_dev); + + pm_runtime_disable(&pdev->dev); + camif_clk_put(camif); + pdata->gpio_put(); + + return 0; +} + +static int s3c_camif_runtime_resume(struct device *dev) +{ + struct camif_dev *camif = dev_get_drvdata(dev); + + clk_enable(camif->clock[CLK_GATE]); + /* null op on s3c244x */ + clk_enable(camif->clock[CLK_CAM]); + return 0; +} + +static int s3c_camif_runtime_suspend(struct device *dev) +{ + struct camif_dev *camif = dev_get_drvdata(dev); + + /* null op on s3c244x */ + clk_disable(camif->clock[CLK_CAM]); + + clk_disable(camif->clock[CLK_GATE]); + return 0; +} + +static const struct s3c_camif_variant s3c244x_camif_variant = { + .vp_pix_limits = { + [VP_CODEC] = { + .max_out_width = 4096, + .max_sc_out_width = 2048, + .out_width_align = 16, + .min_out_width = 16, + .max_height = 4096, + }, + [VP_PREVIEW] = { + .max_out_width = 640, + .max_sc_out_width = 640, + .out_width_align = 16, + .min_out_width = 16, + .max_height = 480, + } + }, + .pix_limits = { + .win_hor_offset_align = 8, + }, + .ip_revision = S3C244X_CAMIF_IP_REV, +}; + +static struct s3c_camif_drvdata s3c244x_camif_drvdata = { + .variant = &s3c244x_camif_variant, + .bus_clk_freq = 24000000UL, +}; + +static const struct s3c_camif_variant s3c6410_camif_variant = { + .vp_pix_limits = { + [VP_CODEC] = { + .max_out_width = 4096, + .max_sc_out_width = 2048, + .out_width_align = 16, + .min_out_width = 16, + .max_height = 4096, + }, + [VP_PREVIEW] = { + .max_out_width = 4096, + .max_sc_out_width = 720, + .out_width_align = 16, + .min_out_width = 16, + .max_height = 4096, + } + }, + .pix_limits = { + .win_hor_offset_align = 8, + }, + .ip_revision = S3C6410_CAMIF_IP_REV, + .has_img_effect = 1, + .vp_offset = 0x20, +}; + +static struct s3c_camif_drvdata s3c6410_camif_drvdata = { + .variant = &s3c6410_camif_variant, + .bus_clk_freq = 133000000UL, +}; + +static struct platform_device_id s3c_camif_driver_ids[] = { + { + .name = "s3c2440-camif", + .driver_data = (unsigned long)&s3c244x_camif_drvdata, + }, { + .name = "s3c6410-camif", + .driver_data = (unsigned long)&s3c6410_camif_drvdata, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(platform, s3c_camif_driver_ids); + +static const struct dev_pm_ops s3c_camif_pm_ops = { + .runtime_suspend = s3c_camif_runtime_suspend, + .runtime_resume = s3c_camif_runtime_resume, +}; + +static struct platform_driver s3c_camif_driver = { + .probe = s3c_camif_probe, + .remove = __devexit_p(s3c_camif_remove), + .id_table = s3c_camif_driver_ids, + .driver = { + .name = S3C_CAMIF_DRIVER_NAME, + .owner = THIS_MODULE, + .pm = &s3c_camif_pm_ops, + } +}; + +module_platform_driver(s3c_camif_driver); + +MODULE_AUTHOR("Sylwester Nawrocki <sylvester.nawrocki@gmail.com>"); +MODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>"); +MODULE_DESCRIPTION("S3C24XX/S3C64XX SoC camera interface driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/s3c-camif/camif-core.h b/drivers/media/platform/s3c-camif/camif-core.h new file mode 100644 index 00000000000..261134baa65 --- /dev/null +++ b/drivers/media/platform/s3c-camif/camif-core.h @@ -0,0 +1,393 @@ +/* + * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver + * + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef CAMIF_CORE_H_ +#define CAMIF_CORE_H_ + +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/platform_device.h> +#include <linux/sched.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/videodev2.h> + +#include <media/media-entity.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-dev.h> +#include <media/v4l2-device.h> +#include <media/v4l2-mediabus.h> +#include <media/videobuf2-core.h> +#include <media/s3c_camif.h> + +#define S3C_CAMIF_DRIVER_NAME "s3c-camif" +#define CAMIF_REQ_BUFS_MIN 3 +#define CAMIF_MAX_OUT_BUFS 4 +#define CAMIF_MAX_PIX_WIDTH 4096 +#define CAMIF_MAX_PIX_HEIGHT 4096 +#define SCALER_MAX_RATIO 64 +#define CAMIF_DEF_WIDTH 640 +#define CAMIF_DEF_HEIGHT 480 +#define CAMIF_STOP_TIMEOUT 1500 /* ms */ + +#define S3C244X_CAMIF_IP_REV 0x20 /* 2.0 */ +#define S3C2450_CAMIF_IP_REV 0x30 /* 3.0 - not implemented, not tested */ +#define S3C6400_CAMIF_IP_REV 0x31 /* 3.1 - not implemented, not tested */ +#define S3C6410_CAMIF_IP_REV 0x32 /* 3.2 */ + +/* struct camif_vp::state */ + +#define ST_VP_PENDING (1 << 0) +#define ST_VP_RUNNING (1 << 1) +#define ST_VP_STREAMING (1 << 2) +#define ST_VP_SENSOR_STREAMING (1 << 3) + +#define ST_VP_ABORTING (1 << 4) +#define ST_VP_OFF (1 << 5) +#define ST_VP_LASTIRQ (1 << 6) + +#define ST_VP_CONFIG (1 << 8) + +#define CAMIF_SD_PAD_SINK 0 +#define CAMIF_SD_PAD_SOURCE_C 1 +#define CAMIF_SD_PAD_SOURCE_P 2 +#define CAMIF_SD_PADS_NUM 3 + +enum img_fmt { + IMG_FMT_RGB565 = 0x0010, + IMG_FMT_RGB666, + IMG_FMT_XRGB8888, + IMG_FMT_YCBCR420 = 0x0020, + IMG_FMT_YCRCB420, + IMG_FMT_YCBCR422P, + IMG_FMT_YCBYCR422 = 0x0040, + IMG_FMT_YCRYCB422, + IMG_FMT_CBYCRY422, + IMG_FMT_CRYCBY422, +}; + +#define img_fmt_is_rgb(x) ((x) & 0x10) +#define img_fmt_is_ycbcr(x) ((x) & 0x60) + +/* Possible values for struct camif_fmt::flags */ +#define FMT_FL_S3C24XX_CODEC (1 << 0) +#define FMT_FL_S3C24XX_PREVIEW (1 << 1) +#define FMT_FL_S3C64XX (1 << 2) + +/** + * struct camif_fmt - pixel format description + * @fourcc: fourcc code for this format, 0 if not applicable + * @color: a corresponding enum img_fmt + * @colplanes: number of physically contiguous data planes + * @flags: indicate for which SoCs revisions this format is valid + * @depth: bits per pixel (total) + * @ybpp: number of luminance bytes per pixel + */ +struct camif_fmt { + char *name; + u32 fourcc; + u32 color; + u16 colplanes; + u16 flags; + u8 depth; + u8 ybpp; +}; + +/** + * struct camif_dma_offset - pixel offset information for DMA + * @initial: offset (in pixels) to first pixel + * @line: offset (in pixels) from end of line to start of next line + */ +struct camif_dma_offset { + int initial; + int line; +}; + +/** + * struct camif_frame - source/target frame properties + * @f_width: full pixel width + * @f_height: full pixel height + * @rect: crop/composition rectangle + * @dma_offset: DMA offset configuration + */ +struct camif_frame { + u16 f_width; + u16 f_height; + struct v4l2_rect rect; + struct camif_dma_offset dma_offset; +}; + +/* CAMIF clocks enumeration */ +enum { + CLK_GATE, + CLK_CAM, + CLK_MAX_NUM, +}; + +struct vp_pix_limits { + u16 max_out_width; + u16 max_sc_out_width; + u16 out_width_align; + u16 max_height; + u8 min_out_width; + u16 out_hor_offset_align; +}; + +struct camif_pix_limits { + u16 win_hor_offset_align; +}; + +/** + * struct s3c_camif_variant - CAMIF variant structure + * @vp_pix_limits: pixel limits for the codec and preview paths + * @camif_pix_limits: pixel limits for the camera input interface + * @ip_revision: the CAMIF IP revision: 0x20 for s3c244x, 0x32 for s3c6410 + */ +struct s3c_camif_variant { + struct vp_pix_limits vp_pix_limits[2]; + struct camif_pix_limits pix_limits; + u8 ip_revision; + u8 has_img_effect; + unsigned int vp_offset; +}; + +struct s3c_camif_drvdata { + const struct s3c_camif_variant *variant; + unsigned long bus_clk_freq; +}; + +struct camif_scaler { + u8 scaleup_h; + u8 scaleup_v; + u8 copy; + u8 enable; + u32 h_shift; + u32 v_shift; + u32 pre_h_ratio; + u32 pre_v_ratio; + u32 pre_dst_width; + u32 pre_dst_height; + u32 main_h_ratio; + u32 main_v_ratio; +}; + +struct camif_dev; + +/** + * struct camif_vp - CAMIF data processing path structure (codec/preview) + * @irq_queue: interrupt handling waitqueue + * @irq: interrupt number for this data path + * @camif: pointer to the camif structure + * @pad: media pad for the video node + * @vdev video device + * @ctrl_handler: video node controls handler + * @owner: file handle that own the streaming + * @pending_buf_q: pending (empty) buffers queue head + * @active_buf_q: active (being written) buffers queue head + * @active_buffers: counter of buffer set up at the DMA engine + * @buf_index: identifier of a last empty buffer set up in H/W + * @frame_sequence: image frame sequence counter + * @reqbufs_count: the number of buffers requested + * @scaler: the scaler structure + * @out_fmt: pixel format at this video path output + * @payload: the output data frame payload size + * @out_frame: the output pixel resolution + * @state: the video path's state + * @fmt_flags: flags determining supported pixel formats + * @id: CAMIF id, 0 - codec, 1 - preview + * @rotation: current image rotation value + * @hflip: apply horizontal flip if set + * @vflip: apply vertical flip if set + */ +struct camif_vp { + wait_queue_head_t irq_queue; + int irq; + struct camif_dev *camif; + struct media_pad pad; + struct video_device vdev; + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_fh *owner; + struct vb2_queue vb_queue; + struct list_head pending_buf_q; + struct list_head active_buf_q; + unsigned int active_buffers; + unsigned int buf_index; + unsigned int frame_sequence; + unsigned int reqbufs_count; + struct camif_scaler scaler; + const struct camif_fmt *out_fmt; + unsigned int payload; + struct camif_frame out_frame; + unsigned int state; + u16 fmt_flags; + u8 id; + u8 rotation; + u8 hflip; + u8 vflip; + unsigned int offset; +}; + +/* Video processing path enumeration */ +#define VP_CODEC 0 +#define VP_PREVIEW 1 +#define CAMIF_VP_NUM 2 + +/** + * struct camif_dev - the CAMIF driver private data structure + * @media_dev: top-level media device structure + * @v4l2_dev: root v4l2_device + * @subdev: camera interface ("catchcam") subdev + * @mbus_fmt: camera input media bus format + * @camif_crop: camera input interface crop rectangle + * @pads: the camif subdev's media pads + * @stream_count: the camera interface streaming reference counter + * @sensor: image sensor data structure + * @m_pipeline: video entity pipeline description + * @ctrl_handler: v4l2 control handler (owned by @subdev) + * @test_pattern: test pattern controls + * @vp: video path (DMA) description (codec/preview) + * @alloc_ctx: memory buffer allocator context + * @variant: variant information for this device + * @dev: pointer to the CAMIF device struct + * @pdata: a copy of the driver's platform data + * @clock: clocks required for the CAMIF operation + * @lock: mutex protecting this data structure + * @slock: spinlock protecting CAMIF registers + * @io_base: start address of the mmaped CAMIF registers + */ +struct camif_dev { + struct media_device media_dev; + struct v4l2_device v4l2_dev; + struct v4l2_subdev subdev; + struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_rect camif_crop; + struct media_pad pads[CAMIF_SD_PADS_NUM]; + int stream_count; + + struct cam_sensor { + struct v4l2_subdev *sd; + short power_count; + short stream_count; + } sensor; + struct media_pipeline *m_pipeline; + + struct v4l2_ctrl_handler ctrl_handler; + struct v4l2_ctrl *ctrl_test_pattern; + struct { + struct v4l2_ctrl *ctrl_colorfx; + struct v4l2_ctrl *ctrl_colorfx_cbcr; + }; + u8 test_pattern; + u8 colorfx; + u8 colorfx_cb; + u8 colorfx_cr; + + struct camif_vp vp[CAMIF_VP_NUM]; + struct vb2_alloc_ctx *alloc_ctx; + + const struct s3c_camif_variant *variant; + struct device *dev; + struct s3c_camif_plat_data pdata; + struct clk *clock[CLK_MAX_NUM]; + struct mutex lock; + spinlock_t slock; + void __iomem *io_base; +}; + +/** + * struct camif_addr - Y/Cb/Cr DMA start address structure + * @y: luminance plane dma address + * @cb: Cb plane dma address + * @cr: Cr plane dma address + */ +struct camif_addr { + dma_addr_t y; + dma_addr_t cb; + dma_addr_t cr; +}; + +/** + * struct camif_buffer - the camif video buffer structure + * @vb: vb2 buffer + * @list: list head for the buffers queue + * @paddr: DMA start addresses + * @index: an identifier of this buffer at the DMA engine + */ +struct camif_buffer { + struct vb2_buffer vb; + struct list_head list; + struct camif_addr paddr; + unsigned int index; +}; + +const struct camif_fmt *s3c_camif_find_format(struct camif_vp *vp, + const u32 *pixelformat, int index); +int s3c_camif_register_video_node(struct camif_dev *camif, int idx); +void s3c_camif_unregister_video_node(struct camif_dev *camif, int idx); +irqreturn_t s3c_camif_irq_handler(int irq, void *priv); +int s3c_camif_create_subdev(struct camif_dev *camif); +void s3c_camif_unregister_subdev(struct camif_dev *camif); +int s3c_camif_set_defaults(struct camif_dev *camif); +int s3c_camif_get_scaler_config(struct camif_vp *vp, + struct camif_scaler *scaler); + +static inline void camif_active_queue_add(struct camif_vp *vp, + struct camif_buffer *buf) +{ + list_add_tail(&buf->list, &vp->active_buf_q); + vp->active_buffers++; +} + +static inline struct camif_buffer *camif_active_queue_pop( + struct camif_vp *vp) +{ + struct camif_buffer *buf = list_first_entry(&vp->active_buf_q, + struct camif_buffer, list); + list_del(&buf->list); + vp->active_buffers--; + return buf; +} + +static inline struct camif_buffer *camif_active_queue_peek( + struct camif_vp *vp, int index) +{ + struct camif_buffer *tmp, *buf; + + if (WARN_ON(list_empty(&vp->active_buf_q))) + return NULL; + + list_for_each_entry_safe(buf, tmp, &vp->active_buf_q, list) { + if (buf->index == index) { + list_del(&buf->list); + vp->active_buffers--; + return buf; + } + } + + return NULL; +} + +static inline void camif_pending_queue_add(struct camif_vp *vp, + struct camif_buffer *buf) +{ + list_add_tail(&buf->list, &vp->pending_buf_q); +} + +static inline struct camif_buffer *camif_pending_queue_pop( + struct camif_vp *vp) +{ + struct camif_buffer *buf = list_first_entry(&vp->pending_buf_q, + struct camif_buffer, list); + list_del(&buf->list); + return buf; +} + +#endif /* CAMIF_CORE_H_ */ diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c new file mode 100644 index 00000000000..1a3b4fc05ec --- /dev/null +++ b/drivers/media/platform/s3c-camif/camif-regs.c @@ -0,0 +1,606 @@ +/* + * Samsung s3c24xx/s3c64xx SoC CAMIF driver + * + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ +#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__ + +#include <linux/delay.h> +#include "camif-regs.h" + +#define camif_write(_camif, _off, _val) writel(_val, (_camif)->io_base + (_off)) +#define camif_read(_camif, _off) readl((_camif)->io_base + (_off)) + +void camif_hw_reset(struct camif_dev *camif) +{ + u32 cfg; + + cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT); + cfg |= CISRCFMT_ITU601_8BIT; + camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg); + + /* S/W reset */ + cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL); + cfg |= CIGCTRL_SWRST; + if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) + cfg |= CIGCTRL_IRQ_LEVEL; + camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg); + udelay(10); + + cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL); + cfg &= ~CIGCTRL_SWRST; + camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg); + udelay(10); +} + +void camif_hw_clear_pending_irq(struct camif_vp *vp) +{ + u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_CIGCTRL); + cfg |= CIGCTRL_IRQ_CLR(vp->id); + camif_write(vp->camif, S3C_CAMIF_REG_CIGCTRL, cfg); +} + +/* + * Sets video test pattern (off, color bar, horizontal or vertical gradient). + * External sensor pixel clock must be active for the test pattern to work. + */ +void camif_hw_set_test_pattern(struct camif_dev *camif, unsigned int pattern) +{ + u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL); + cfg &= ~CIGCTRL_TESTPATTERN_MASK; + cfg |= (pattern << 27); + camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg); +} + +void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect, + unsigned int cr, unsigned int cb) +{ + static const struct v4l2_control colorfx[] = { + { V4L2_COLORFX_NONE, CIIMGEFF_FIN_BYPASS }, + { V4L2_COLORFX_BW, CIIMGEFF_FIN_ARBITRARY }, + { V4L2_COLORFX_SEPIA, CIIMGEFF_FIN_ARBITRARY }, + { V4L2_COLORFX_NEGATIVE, CIIMGEFF_FIN_NEGATIVE }, + { V4L2_COLORFX_ART_FREEZE, CIIMGEFF_FIN_ARTFREEZE }, + { V4L2_COLORFX_EMBOSS, CIIMGEFF_FIN_EMBOSSING }, + { V4L2_COLORFX_SILHOUETTE, CIIMGEFF_FIN_SILHOUETTE }, + { V4L2_COLORFX_SET_CBCR, CIIMGEFF_FIN_ARBITRARY }, + }; + unsigned int i, cfg; + + for (i = 0; i < ARRAY_SIZE(colorfx); i++) + if (colorfx[i].id == effect) + break; + + if (i == ARRAY_SIZE(colorfx)) + return; + + cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset)); + /* Set effect */ + cfg &= ~CIIMGEFF_FIN_MASK; + cfg |= colorfx[i].value; + /* Set both paths */ + if (camif->variant->ip_revision >= S3C6400_CAMIF_IP_REV) { + if (effect == V4L2_COLORFX_NONE) + cfg &= ~CIIMGEFF_IE_ENABLE_MASK; + else + cfg |= CIIMGEFF_IE_ENABLE_MASK; + } + cfg &= ~CIIMGEFF_PAT_CBCR_MASK; + cfg |= cr | (cb << 13); + camif_write(camif, S3C_CAMIF_REG_CIIMGEFF(camif->vp->offset), cfg); +} + +static const u32 src_pixfmt_map[8][2] = { + { V4L2_MBUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR }, + { V4L2_MBUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB }, + { V4L2_MBUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY }, + { V4L2_MBUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY }, +}; + +/* Set camera input pixel format and resolution */ +void camif_hw_set_source_format(struct camif_dev *camif) +{ + struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt; + unsigned int i = ARRAY_SIZE(src_pixfmt_map); + u32 cfg; + + while (i-- >= 0) { + if (src_pixfmt_map[i][0] == mf->code) + break; + } + + if (i == 0 && src_pixfmt_map[i][0] != mf->code) { + dev_err(camif->dev, + "Unsupported pixel code, falling back to %#08x\n", + src_pixfmt_map[i][0]); + } + + cfg = camif_read(camif, S3C_CAMIF_REG_CISRCFMT); + cfg &= ~(CISRCFMT_ORDER422_MASK | CISRCFMT_SIZE_CAM_MASK); + cfg |= (mf->width << 16) | mf->height; + cfg |= src_pixfmt_map[i][1]; + camif_write(camif, S3C_CAMIF_REG_CISRCFMT, cfg); +} + +/* Set the camera host input window offsets (cropping) */ +void camif_hw_set_camera_crop(struct camif_dev *camif) +{ + struct v4l2_mbus_framefmt *mf = &camif->mbus_fmt; + struct v4l2_rect *crop = &camif->camif_crop; + u32 hoff2, voff2; + u32 cfg; + + /* Note: s3c244x requirement: left = f_width - rect.width / 2 */ + cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST); + cfg &= ~(CIWDOFST_OFST_MASK | CIWDOFST_WINOFSEN); + cfg |= (crop->left << 16) | crop->top; + if (crop->left != 0 || crop->top != 0) + cfg |= CIWDOFST_WINOFSEN; + camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg); + + if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) { + hoff2 = mf->width - crop->width - crop->left; + voff2 = mf->height - crop->height - crop->top; + cfg = (hoff2 << 16) | voff2; + camif_write(camif, S3C_CAMIF_REG_CIWDOFST2, cfg); + } +} + +void camif_hw_clear_fifo_overflow(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + u32 cfg; + + cfg = camif_read(camif, S3C_CAMIF_REG_CIWDOFST); + if (vp->id == 0) + cfg |= (CIWDOFST_CLROVCOFIY | CIWDOFST_CLROVCOFICB | + CIWDOFST_CLROVCOFICR); + else + cfg |= (/* CIWDOFST_CLROVPRFIY | */ CIWDOFST_CLROVPRFICB | + CIWDOFST_CLROVPRFICR); + camif_write(camif, S3C_CAMIF_REG_CIWDOFST, cfg); +} + +/* Set video bus signals polarity */ +void camif_hw_set_camera_bus(struct camif_dev *camif) +{ + unsigned int flags = camif->pdata.sensor.flags; + + u32 cfg = camif_read(camif, S3C_CAMIF_REG_CIGCTRL); + + cfg &= ~(CIGCTRL_INVPOLPCLK | CIGCTRL_INVPOLVSYNC | + CIGCTRL_INVPOLHREF | CIGCTRL_INVPOLFIELD); + + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) + cfg |= CIGCTRL_INVPOLPCLK; + + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW) + cfg |= CIGCTRL_INVPOLVSYNC; + /* + * HREF is normally high during frame active data + * transmission and low during horizontal synchronization + * period. Thus HREF active high means HSYNC active low. + */ + if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + cfg |= CIGCTRL_INVPOLHREF; /* HREF active low */ + + if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) { + if (flags & V4L2_MBUS_FIELD_EVEN_LOW) + cfg |= CIGCTRL_INVPOLFIELD; + cfg |= CIGCTRL_FIELDMODE; + } + + pr_debug("Setting CIGCTRL to: %#x\n", cfg); + + camif_write(camif, S3C_CAMIF_REG_CIGCTRL, cfg); +} + +void camif_hw_set_output_addr(struct camif_vp *vp, + struct camif_addr *paddr, int i) +{ + struct camif_dev *camif = vp->camif; + + camif_write(camif, S3C_CAMIF_REG_CIYSA(vp->id, i), paddr->y); + if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV + || vp->id == VP_CODEC) { + camif_write(camif, S3C_CAMIF_REG_CICBSA(vp->id, i), + paddr->cb); + camif_write(camif, S3C_CAMIF_REG_CICRSA(vp->id, i), + paddr->cr); + } + + pr_debug("dst_buf[%d]: %#X, cb: %#X, cr: %#X\n", + i, paddr->y, paddr->cb, paddr->cr); +} + +static void camif_hw_set_out_dma_size(struct camif_vp *vp) +{ + struct camif_frame *frame = &vp->out_frame; + u32 cfg; + + cfg = camif_read(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset)); + cfg &= ~CITRGFMT_TARGETSIZE_MASK; + cfg |= (frame->f_width << 16) | frame->f_height; + camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg); +} + +static void camif_get_dma_burst(u32 width, u32 ybpp, u32 *mburst, u32 *rburst) +{ + unsigned int nwords = width * ybpp / 4; + unsigned int div, rem; + + if (WARN_ON(width < 8 || (width * ybpp) & 7)) + return; + + for (div = 16; div >= 2; div /= 2) { + if (nwords < div) + continue; + + rem = nwords & (div - 1); + if (rem == 0) { + *mburst = div; + *rburst = div; + break; + } + if (rem == div / 2 || rem == div / 4) { + *mburst = div; + *rburst = rem; + break; + } + } +} + +void camif_hw_set_output_dma(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + struct camif_frame *frame = &vp->out_frame; + const struct camif_fmt *fmt = vp->out_fmt; + unsigned int ymburst = 0, yrburst = 0; + u32 cfg; + + camif_hw_set_out_dma_size(vp); + + if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) { + struct camif_dma_offset *offset = &frame->dma_offset; + /* Set the input dma offsets. */ + cfg = S3C_CISS_OFFS_INITIAL(offset->initial); + cfg |= S3C_CISS_OFFS_LINE(offset->line); + camif_write(camif, S3C_CAMIF_REG_CISSY(vp->id), cfg); + camif_write(camif, S3C_CAMIF_REG_CISSCB(vp->id), cfg); + camif_write(camif, S3C_CAMIF_REG_CISSCR(vp->id), cfg); + } + + /* Configure DMA burst values */ + camif_get_dma_burst(frame->rect.width, fmt->ybpp, &ymburst, &yrburst); + + cfg = camif_read(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset)); + cfg &= ~CICTRL_BURST_MASK; + + cfg |= CICTRL_YBURST1(ymburst) | CICTRL_YBURST2(yrburst); + cfg |= CICTRL_CBURST1(ymburst / 2) | CICTRL_CBURST2(yrburst / 2); + + camif_write(camif, S3C_CAMIF_REG_CICTRL(vp->id, vp->offset), cfg); + + pr_debug("ymburst: %u, yrburst: %u\n", ymburst, yrburst); +} + +void camif_hw_set_input_path(struct camif_vp *vp) +{ + u32 cfg = camif_read(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id)); + cfg &= ~MSCTRL_SEL_DMA_CAM; + camif_write(vp->camif, S3C_CAMIF_REG_MSCTRL(vp->id), cfg); +} + +void camif_hw_set_target_format(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + struct camif_frame *frame = &vp->out_frame; + u32 cfg; + + pr_debug("fw: %d, fh: %d color: %d\n", frame->f_width, + frame->f_height, vp->out_fmt->color); + + cfg = camif_read(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset)); + cfg &= ~CITRGFMT_TARGETSIZE_MASK; + + if (camif->variant->ip_revision == S3C244X_CAMIF_IP_REV) { + /* We currently support only YCbCr 4:2:2 at the camera input */ + cfg |= CITRGFMT_IN422; + cfg &= ~CITRGFMT_OUT422; + if (vp->out_fmt->color == IMG_FMT_YCBCR422P) + cfg |= CITRGFMT_OUT422; + } else { + cfg &= ~CITRGFMT_OUTFORMAT_MASK; + switch (vp->out_fmt->color) { + case IMG_FMT_RGB565...IMG_FMT_XRGB8888: + cfg |= CITRGFMT_OUTFORMAT_RGB; + break; + case IMG_FMT_YCBCR420...IMG_FMT_YCRCB420: + cfg |= CITRGFMT_OUTFORMAT_YCBCR420; + break; + case IMG_FMT_YCBCR422P: + cfg |= CITRGFMT_OUTFORMAT_YCBCR422; + break; + case IMG_FMT_YCBYCR422...IMG_FMT_CRYCBY422: + cfg |= CITRGFMT_OUTFORMAT_YCBCR422I; + break; + } + } + + /* Rotation is only supported by s3c64xx */ + if (vp->rotation == 90 || vp->rotation == 270) + cfg |= (frame->f_height << 16) | frame->f_width; + else + cfg |= (frame->f_width << 16) | frame->f_height; + camif_write(camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg); + + /* Target area, output pixel width * height */ + cfg = camif_read(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset)); + cfg &= ~CITAREA_MASK; + cfg |= (frame->f_width * frame->f_height); + camif_write(camif, S3C_CAMIF_REG_CITAREA(vp->id, vp->offset), cfg); +} + +void camif_hw_set_flip(struct camif_vp *vp) +{ + u32 cfg = camif_read(vp->camif, + S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset)); + + cfg &= ~CITRGFMT_FLIP_MASK; + + if (vp->hflip) + cfg |= CITRGFMT_FLIP_Y_MIRROR; + if (vp->vflip) + cfg |= CITRGFMT_FLIP_X_MIRROR; + + camif_write(vp->camif, S3C_CAMIF_REG_CITRGFMT(vp->id, vp->offset), cfg); +} + +static void camif_hw_set_prescaler(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + struct camif_scaler *sc = &vp->scaler; + u32 cfg, shfactor, addr; + + addr = S3C_CAMIF_REG_CISCPRERATIO(vp->id, vp->offset); + + shfactor = 10 - (sc->h_shift + sc->v_shift); + cfg = shfactor << 28; + + cfg |= (sc->pre_h_ratio << 16) | sc->pre_v_ratio; + camif_write(camif, addr, cfg); + + cfg = (sc->pre_dst_width << 16) | sc->pre_dst_height; + camif_write(camif, S3C_CAMIF_REG_CISCPREDST(vp->id, vp->offset), cfg); +} + +void camif_s3c244x_hw_set_scaler(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + struct camif_scaler *scaler = &vp->scaler; + unsigned int color = vp->out_fmt->color; + u32 cfg; + + camif_hw_set_prescaler(vp); + + cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset)); + + cfg &= ~(CISCCTRL_SCALEUP_MASK | CISCCTRL_SCALERBYPASS | + CISCCTRL_MAIN_RATIO_MASK | CIPRSCCTRL_RGB_FORMAT_24BIT); + + if (scaler->enable) { + if (scaler->scaleup_h) { + if (vp->id == VP_CODEC) + cfg |= CISCCTRL_SCALEUP_H; + else + cfg |= CIPRSCCTRL_SCALEUP_H; + } + if (scaler->scaleup_v) { + if (vp->id == VP_CODEC) + cfg |= CISCCTRL_SCALEUP_V; + else + cfg |= CIPRSCCTRL_SCALEUP_V; + } + } else { + if (vp->id == VP_CODEC) + cfg |= CISCCTRL_SCALERBYPASS; + } + + cfg |= ((scaler->main_h_ratio & 0x1ff) << 16); + cfg |= scaler->main_v_ratio & 0x1ff; + + if (vp->id == VP_PREVIEW) { + if (color == IMG_FMT_XRGB8888) + cfg |= CIPRSCCTRL_RGB_FORMAT_24BIT; + cfg |= CIPRSCCTRL_SAMPLE; + } + + camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg); + + pr_debug("main: h_ratio: %#x, v_ratio: %#x", + scaler->main_h_ratio, scaler->main_v_ratio); +} + +void camif_s3c64xx_hw_set_scaler(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + struct camif_scaler *scaler = &vp->scaler; + unsigned int color = vp->out_fmt->color; + u32 cfg; + + camif_hw_set_prescaler(vp); + + cfg = camif_read(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset)); + + cfg &= ~(CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE + | CISCCTRL_SCALEUP_H | CISCCTRL_SCALEUP_V + | CISCCTRL_SCALERBYPASS | CISCCTRL_ONE2ONE + | CISCCTRL_INRGB_FMT_MASK | CISCCTRL_OUTRGB_FMT_MASK + | CISCCTRL_INTERLACE | CISCCTRL_EXTRGB_EXTENSION + | CISCCTRL_MAIN_RATIO_MASK); + + cfg |= (CISCCTRL_CSCR2Y_WIDE | CISCCTRL_CSCY2R_WIDE); + + if (!scaler->enable) { + cfg |= CISCCTRL_SCALERBYPASS; + } else { + if (scaler->scaleup_h) + cfg |= CISCCTRL_SCALEUP_H; + if (scaler->scaleup_v) + cfg |= CISCCTRL_SCALEUP_V; + if (scaler->copy) + cfg |= CISCCTRL_ONE2ONE; + } + + switch (color) { + case IMG_FMT_RGB666: + cfg |= CISCCTRL_OUTRGB_FMT_RGB666; + break; + case IMG_FMT_XRGB8888: + cfg |= CISCCTRL_OUTRGB_FMT_RGB888; + break; + } + + cfg |= (scaler->main_h_ratio & 0x1ff) << 16; + cfg |= scaler->main_v_ratio & 0x1ff; + + camif_write(camif, S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset), cfg); + + pr_debug("main: h_ratio: %#x, v_ratio: %#x", + scaler->main_h_ratio, scaler->main_v_ratio); +} + +void camif_hw_set_scaler(struct camif_vp *vp) +{ + unsigned int ip_rev = vp->camif->variant->ip_revision; + + if (ip_rev == S3C244X_CAMIF_IP_REV) + camif_s3c244x_hw_set_scaler(vp); + else + camif_s3c64xx_hw_set_scaler(vp); +} + +void camif_hw_enable_scaler(struct camif_vp *vp, bool on) +{ + u32 addr = S3C_CAMIF_REG_CISCCTRL(vp->id, vp->offset); + u32 cfg; + + cfg = camif_read(vp->camif, addr); + if (on) + cfg |= CISCCTRL_SCALERSTART; + else + cfg &= ~CISCCTRL_SCALERSTART; + camif_write(vp->camif, addr, cfg); +} + +void camif_hw_set_lastirq(struct camif_vp *vp, int enable) +{ + u32 addr = S3C_CAMIF_REG_CICTRL(vp->id, vp->offset); + u32 cfg; + + cfg = camif_read(vp->camif, addr); + if (enable) + cfg |= CICTRL_LASTIRQ_ENABLE; + else + cfg &= ~CICTRL_LASTIRQ_ENABLE; + camif_write(vp->camif, addr, cfg); +} + +void camif_hw_enable_capture(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + u32 cfg; + + cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset)); + camif->stream_count++; + + if (camif->variant->ip_revision == S3C6410_CAMIF_IP_REV) + cfg |= CIIMGCPT_CPT_FREN_ENABLE(vp->id); + + if (vp->scaler.enable) + cfg |= CIIMGCPT_IMGCPTEN_SC(vp->id); + + if (camif->stream_count == 1) + cfg |= CIIMGCPT_IMGCPTEN; + + camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg); + + pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n", + cfg, camif->stream_count); +} + +void camif_hw_disable_capture(struct camif_vp *vp) +{ + struct camif_dev *camif = vp->camif; + u32 cfg; + + cfg = camif_read(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset)); + cfg &= ~CIIMGCPT_IMGCPTEN_SC(vp->id); + + if (WARN_ON(--(camif->stream_count) < 0)) + camif->stream_count = 0; + + if (camif->stream_count == 0) + cfg &= ~CIIMGCPT_IMGCPTEN; + + pr_debug("CIIMGCPT: %#x, camif->stream_count: %d\n", + cfg, camif->stream_count); + + camif_write(camif, S3C_CAMIF_REG_CIIMGCPT(vp->offset), cfg); +} + +void camif_hw_dump_regs(struct camif_dev *camif, const char *label) +{ + struct { + u32 offset; + const char * const name; + } registers[] = { + { S3C_CAMIF_REG_CISRCFMT, "CISRCFMT" }, + { S3C_CAMIF_REG_CIWDOFST, "CIWDOFST" }, + { S3C_CAMIF_REG_CIGCTRL, "CIGCTRL" }, + { S3C_CAMIF_REG_CIWDOFST2, "CIWDOFST2" }, + { S3C_CAMIF_REG_CIYSA(0, 0), "CICOYSA0" }, + { S3C_CAMIF_REG_CICBSA(0, 0), "CICOCBSA0" }, + { S3C_CAMIF_REG_CICRSA(0, 0), "CICOCRSA0" }, + { S3C_CAMIF_REG_CIYSA(0, 1), "CICOYSA1" }, + { S3C_CAMIF_REG_CICBSA(0, 1), "CICOCBSA1" }, + { S3C_CAMIF_REG_CICRSA(0, 1), "CICOCRSA1" }, + { S3C_CAMIF_REG_CIYSA(0, 2), "CICOYSA2" }, + { S3C_CAMIF_REG_CICBSA(0, 2), "CICOCBSA2" }, + { S3C_CAMIF_REG_CICRSA(0, 2), "CICOCRSA2" }, + { S3C_CAMIF_REG_CIYSA(0, 3), "CICOYSA3" }, + { S3C_CAMIF_REG_CICBSA(0, 3), "CICOCBSA3" }, + { S3C_CAMIF_REG_CICRSA(0, 3), "CICOCRSA3" }, + { S3C_CAMIF_REG_CIYSA(1, 0), "CIPRYSA0" }, + { S3C_CAMIF_REG_CIYSA(1, 1), "CIPRYSA1" }, + { S3C_CAMIF_REG_CIYSA(1, 2), "CIPRYSA2" }, + { S3C_CAMIF_REG_CIYSA(1, 3), "CIPRYSA3" }, + { S3C_CAMIF_REG_CITRGFMT(0, 0), "CICOTRGFMT" }, + { S3C_CAMIF_REG_CITRGFMT(1, 0), "CIPRTRGFMT" }, + { S3C_CAMIF_REG_CICTRL(0, 0), "CICOCTRL" }, + { S3C_CAMIF_REG_CICTRL(1, 0), "CIPRCTRL" }, + { S3C_CAMIF_REG_CISCPREDST(0, 0), "CICOSCPREDST" }, + { S3C_CAMIF_REG_CISCPREDST(1, 0), "CIPRSCPREDST" }, + { S3C_CAMIF_REG_CISCPRERATIO(0, 0), "CICOSCPRERATIO" }, + { S3C_CAMIF_REG_CISCPRERATIO(1, 0), "CIPRSCPRERATIO" }, + { S3C_CAMIF_REG_CISCCTRL(0, 0), "CICOSCCTRL" }, + { S3C_CAMIF_REG_CISCCTRL(1, 0), "CIPRSCCTRL" }, + { S3C_CAMIF_REG_CITAREA(0, 0), "CICOTAREA" }, + { S3C_CAMIF_REG_CITAREA(1, 0), "CIPRTAREA" }, + { S3C_CAMIF_REG_CISTATUS(0, 0), "CICOSTATUS" }, + { S3C_CAMIF_REG_CISTATUS(1, 0), "CIPRSTATUS" }, + { S3C_CAMIF_REG_CIIMGCPT(0), "CIIMGCPT" }, + }; + u32 i; + + pr_info("--- %s ---\n", label); + for (i = 0; i < ARRAY_SIZE(registers); i++) { + u32 cfg = readl(camif->io_base + registers[i].offset); + printk(KERN_INFO "%s:\t0x%08x\n", registers[i].name, cfg); + } +} diff --git a/drivers/media/platform/s3c-camif/camif-regs.h b/drivers/media/platform/s3c-camif/camif-regs.h new file mode 100644 index 00000000000..af2d472ea1d --- /dev/null +++ b/drivers/media/platform/s3c-camif/camif-regs.h @@ -0,0 +1,269 @@ +/* + * Register definition file for s3c24xx/s3c64xx SoC CAMIF driver + * + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef CAMIF_REGS_H_ +#define CAMIF_REGS_H_ + +#include "camif-core.h" +#include <media/s3c_camif.h> + +/* + * The id argument indicates the processing path: + * id = 0 - codec (FIMC C), 1 - preview (FIMC P). + */ + +/* Camera input format */ +#define S3C_CAMIF_REG_CISRCFMT 0x00 +#define CISRCFMT_ITU601_8BIT (1 << 31) +#define CISRCFMT_ITU656_8BIT (0 << 31) +#define CISRCFMT_ORDER422_YCBYCR (0 << 14) +#define CISRCFMT_ORDER422_YCRYCB (1 << 14) +#define CISRCFMT_ORDER422_CBYCRY (2 << 14) +#define CISRCFMT_ORDER422_CRYCBY (3 << 14) +#define CISRCFMT_ORDER422_MASK (3 << 14) +#define CISRCFMT_SIZE_CAM_MASK (0x1fff << 16 | 0x1fff) + +/* Window offset */ +#define S3C_CAMIF_REG_CIWDOFST 0x04 +#define CIWDOFST_WINOFSEN (1 << 31) +#define CIWDOFST_CLROVCOFIY (1 << 30) +#define CIWDOFST_CLROVRLB_PR (1 << 28) +/* #define CIWDOFST_CLROVPRFIY (1 << 27) */ +#define CIWDOFST_CLROVCOFICB (1 << 15) +#define CIWDOFST_CLROVCOFICR (1 << 14) +#define CIWDOFST_CLROVPRFICB (1 << 13) +#define CIWDOFST_CLROVPRFICR (1 << 12) +#define CIWDOFST_OFST_MASK (0x7ff << 16 | 0x7ff) + +/* Window offset 2 */ +#define S3C_CAMIF_REG_CIWDOFST2 0x14 +#define CIWDOFST2_OFST2_MASK (0xfff << 16 | 0xfff) + +/* Global control */ +#define S3C_CAMIF_REG_CIGCTRL 0x08 +#define CIGCTRL_SWRST (1 << 31) +#define CIGCTRL_CAMRST (1 << 30) +#define CIGCTRL_TESTPATTERN_NORMAL (0 << 27) +#define CIGCTRL_TESTPATTERN_COLOR_BAR (1 << 27) +#define CIGCTRL_TESTPATTERN_HOR_INC (2 << 27) +#define CIGCTRL_TESTPATTERN_VER_INC (3 << 27) +#define CIGCTRL_TESTPATTERN_MASK (3 << 27) +#define CIGCTRL_INVPOLPCLK (1 << 26) +#define CIGCTRL_INVPOLVSYNC (1 << 25) +#define CIGCTRL_INVPOLHREF (1 << 24) +#define CIGCTRL_IRQ_OVFEN (1 << 22) +#define CIGCTRL_HREF_MASK (1 << 21) +#define CIGCTRL_IRQ_LEVEL (1 << 20) +/* IRQ_CLR_C, IRQ_CLR_P */ +#define CIGCTRL_IRQ_CLR(id) (1 << (19 - (id))) +#define CIGCTRL_FIELDMODE (1 << 2) +#define CIGCTRL_INVPOLFIELD (1 << 1) +#define CIGCTRL_CAM_INTERLACE (1 << 0) + +/* Y DMA output frame start address. n = 0..3. */ +#define S3C_CAMIF_REG_CIYSA(id, n) (0x18 + (id) * 0x54 + (n) * 4) +/* Cb plane output DMA start address. n = 0..3. Only codec path. */ +#define S3C_CAMIF_REG_CICBSA(id, n) (0x28 + (id) * 0x54 + (n) * 4) +/* Cr plane output DMA start address. n = 0..3. Only codec path. */ +#define S3C_CAMIF_REG_CICRSA(id, n) (0x38 + (id) * 0x54 + (n) * 4) + +/* CICOTRGFMT, CIPRTRGFMT - Target format */ +#define S3C_CAMIF_REG_CITRGFMT(id, _offs) (0x48 + (id) * (0x34 + (_offs))) +#define CITRGFMT_IN422 (1 << 31) /* only for s3c24xx */ +#define CITRGFMT_OUT422 (1 << 30) /* only for s3c24xx */ +#define CITRGFMT_OUTFORMAT_YCBCR420 (0 << 29) /* only for s3c6410 */ +#define CITRGFMT_OUTFORMAT_YCBCR422 (1 << 29) /* only for s3c6410 */ +#define CITRGFMT_OUTFORMAT_YCBCR422I (2 << 29) /* only for s3c6410 */ +#define CITRGFMT_OUTFORMAT_RGB (3 << 29) /* only for s3c6410 */ +#define CITRGFMT_OUTFORMAT_MASK (3 << 29) /* only for s3c6410 */ +#define CITRGFMT_TARGETHSIZE(x) ((x) << 16) +#define CITRGFMT_FLIP_NORMAL (0 << 14) +#define CITRGFMT_FLIP_X_MIRROR (1 << 14) +#define CITRGFMT_FLIP_Y_MIRROR (2 << 14) +#define CITRGFMT_FLIP_180 (3 << 14) +#define CITRGFMT_FLIP_MASK (3 << 14) +/* Preview path only */ +#define CITRGFMT_ROT90_PR (1 << 13) +#define CITRGFMT_TARGETVSIZE(x) ((x) << 0) +#define CITRGFMT_TARGETSIZE_MASK ((0x1fff << 16) | 0x1fff) + +/* CICOCTRL, CIPRCTRL. Output DMA control. */ +#define S3C_CAMIF_REG_CICTRL(id, _offs) (0x4c + (id) * (0x34 + (_offs))) +#define CICTRL_BURST_MASK (0xfffff << 4) +/* xBURSTn - 5-bits width */ +#define CICTRL_YBURST1(x) ((x) << 19) +#define CICTRL_YBURST2(x) ((x) << 14) +#define CICTRL_RGBBURST1(x) ((x) << 19) +#define CICTRL_RGBBURST2(x) ((x) << 14) +#define CICTRL_CBURST1(x) ((x) << 9) +#define CICTRL_CBURST2(x) ((x) << 4) +#define CICTRL_LASTIRQ_ENABLE (1 << 2) +#define CICTRL_ORDER422_MASK (3 << 0) + +/* CICOSCPRERATIO, CIPRSCPRERATIO. Pre-scaler control 1. */ +#define S3C_CAMIF_REG_CISCPRERATIO(id, _offs) (0x50 + (id) * (0x34 + (_offs))) + +/* CICOSCPREDST, CIPRSCPREDST. Pre-scaler control 2. */ +#define S3C_CAMIF_REG_CISCPREDST(id, _offs) (0x54 + (id) * (0x34 + (_offs))) + +/* CICOSCCTRL, CIPRSCCTRL. Main scaler control. */ +#define S3C_CAMIF_REG_CISCCTRL(id, _offs) (0x58 + (id) * (0x34 + (_offs))) +#define CISCCTRL_SCALERBYPASS (1 << 31) +/* s3c244x preview path only, s3c64xx both */ +#define CIPRSCCTRL_SAMPLE (1 << 31) +/* 0 - 16-bit RGB, 1 - 24-bit RGB */ +#define CIPRSCCTRL_RGB_FORMAT_24BIT (1 << 30) /* only for s3c244x */ +#define CIPRSCCTRL_SCALEUP_H (1 << 29) /* only for s3c244x */ +#define CIPRSCCTRL_SCALEUP_V (1 << 28) /* only for s3c244x */ +/* s3c64xx */ +#define CISCCTRL_SCALEUP_H (1 << 30) +#define CISCCTRL_SCALEUP_V (1 << 29) +#define CISCCTRL_SCALEUP_MASK (0x3 << 29) +#define CISCCTRL_CSCR2Y_WIDE (1 << 28) +#define CISCCTRL_CSCY2R_WIDE (1 << 27) +#define CISCCTRL_LCDPATHEN_FIFO (1 << 26) +#define CISCCTRL_INTERLACE (1 << 25) +#define CISCCTRL_SCALERSTART (1 << 15) +#define CISCCTRL_INRGB_FMT_RGB565 (0 << 13) +#define CISCCTRL_INRGB_FMT_RGB666 (1 << 13) +#define CISCCTRL_INRGB_FMT_RGB888 (2 << 13) +#define CISCCTRL_INRGB_FMT_MASK (3 << 13) +#define CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11) +#define CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11) +#define CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11) +#define CISCCTRL_OUTRGB_FMT_MASK (3 << 11) +#define CISCCTRL_EXTRGB_EXTENSION (1 << 10) +#define CISCCTRL_ONE2ONE (1 << 9) +#define CISCCTRL_MAIN_RATIO_MASK (0x1ff << 16 | 0x1ff) + +/* CICOTAREA, CIPRTAREA. Target area for DMA (Hsize x Vsize). */ +#define S3C_CAMIF_REG_CITAREA(id, _offs) (0x5c + (id) * (0x34 + (_offs))) +#define CITAREA_MASK 0xfffffff + +/* Codec (id = 0) or preview (id = 1) path status. */ +#define S3C_CAMIF_REG_CISTATUS(id, _offs) (0x64 + (id) * (0x34 + (_offs))) +#define CISTATUS_OVFIY_STATUS (1 << 31) +#define CISTATUS_OVFICB_STATUS (1 << 30) +#define CISTATUS_OVFICR_STATUS (1 << 29) +#define CISTATUS_OVF_MASK (0x7 << 29) +#define CIPRSTATUS_OVF_MASK (0x3 << 30) +#define CISTATUS_VSYNC_STATUS (1 << 28) +#define CISTATUS_FRAMECNT_MASK (3 << 26) +#define CISTATUS_FRAMECNT(__reg) (((__reg) >> 26) & 0x3) +#define CISTATUS_WINOFSTEN_STATUS (1 << 25) +#define CISTATUS_IMGCPTEN_STATUS (1 << 22) +#define CISTATUS_IMGCPTENSC_STATUS (1 << 21) +#define CISTATUS_VSYNC_A_STATUS (1 << 20) +#define CISTATUS_FRAMEEND_STATUS (1 << 19) /* 17 on s3c64xx */ + +/* Image capture enable */ +#define S3C_CAMIF_REG_CIIMGCPT(_offs) (0xa0 + (_offs)) +#define CIIMGCPT_IMGCPTEN (1 << 31) +#define CIIMGCPT_IMGCPTEN_SC(id) (1 << (30 - (id))) +/* Frame control: 1 - one-shot, 0 - free run */ +#define CIIMGCPT_CPT_FREN_ENABLE(id) (1 << (25 - (id))) +#define CIIMGCPT_CPT_FRMOD_ENABLE (0 << 18) +#define CIIMGCPT_CPT_FRMOD_CNT (1 << 18) + +/* Capture sequence */ +#define S3C_CAMIF_REG_CICPTSEQ 0xc4 + +/* Image effects */ +#define S3C_CAMIF_REG_CIIMGEFF(_offs) (0xb0 + (_offs)) +#define CIIMGEFF_IE_ENABLE(id) (1 << (30 + (id))) +#define CIIMGEFF_IE_ENABLE_MASK (3 << 30) +/* Image effect: 1 - after scaler, 0 - before scaler */ +#define CIIMGEFF_IE_AFTER_SC (1 << 29) +#define CIIMGEFF_FIN_MASK (7 << 26) +#define CIIMGEFF_FIN_BYPASS (0 << 26) +#define CIIMGEFF_FIN_ARBITRARY (1 << 26) +#define CIIMGEFF_FIN_NEGATIVE (2 << 26) +#define CIIMGEFF_FIN_ARTFREEZE (3 << 26) +#define CIIMGEFF_FIN_EMBOSSING (4 << 26) +#define CIIMGEFF_FIN_SILHOUETTE (5 << 26) +#define CIIMGEFF_PAT_CBCR_MASK ((0xff << 13) | 0xff) +#define CIIMGEFF_PAT_CB(x) ((x) << 13) +#define CIIMGEFF_PAT_CR(x) (x) + +/* MSCOY0SA, MSPRY0SA. Y/Cb/Cr frame start address for input DMA. */ +#define S3C_CAMIF_REG_MSY0SA(id) (0xd4 + ((id) * 0x2c)) +#define S3C_CAMIF_REG_MSCB0SA(id) (0xd8 + ((id) * 0x2c)) +#define S3C_CAMIF_REG_MSCR0SA(id) (0xdc + ((id) * 0x2c)) + +/* MSCOY0END, MSCOY0END. Y/Cb/Cr frame end address for input DMA. */ +#define S3C_CAMIF_REG_MSY0END(id) (0xe0 + ((id) * 0x2c)) +#define S3C_CAMIF_REG_MSCB0END(id) (0xe4 + ((id) * 0x2c)) +#define S3C_CAMIF_REG_MSCR0END(id) (0xe8 + ((id) * 0x2c)) + +/* MSPRYOFF, MSPRYOFF. Y/Cb/Cr offset. n: 0 - codec, 1 - preview. */ +#define S3C_CAMIF_REG_MSYOFF(id) (0x118 + ((id) * 0x2c)) +#define S3C_CAMIF_REG_MSCBOFF(id) (0x11c + ((id) * 0x2c)) +#define S3C_CAMIF_REG_MSCROFF(id) (0x120 + ((id) * 0x2c)) + +/* Real input DMA data size. n = 0 - codec, 1 - preview. */ +#define S3C_CAMIF_REG_MSWIDTH(id) (0xf8 + (id) * 0x2c) +#define AUTOLOAD_ENABLE (1 << 31) +#define ADDR_CH_DIS (1 << 30) +#define MSHEIGHT(x) (((x) & 0x3ff) << 16) +#define MSWIDTH(x) ((x) & 0x3ff) + +/* Input DMA control. n = 0 - codec, 1 - preview */ +#define S3C_CAMIF_REG_MSCTRL(id) (0xfc + (id) * 0x2c) +#define MSCTRL_ORDER422_M_YCBYCR (0 << 4) +#define MSCTRL_ORDER422_M_YCRYCB (1 << 4) +#define MSCTRL_ORDER422_M_CBYCRY (2 << 4) +#define MSCTRL_ORDER422_M_CRYCBY (3 << 4) +/* 0 - camera, 1 - DMA */ +#define MSCTRL_SEL_DMA_CAM (1 << 3) +#define MSCTRL_INFORMAT_M_YCBCR420 (0 << 1) +#define MSCTRL_INFORMAT_M_YCBCR422 (1 << 1) +#define MSCTRL_INFORMAT_M_YCBCR422I (2 << 1) +#define MSCTRL_INFORMAT_M_RGB (3 << 1) +#define MSCTRL_ENVID_M (1 << 0) + +/* CICOSCOSY, CIPRSCOSY. Scan line Y/Cb/Cr offset. */ +#define S3C_CAMIF_REG_CISSY(id) (0x12c + (id) * 0x0c) +#define S3C_CAMIF_REG_CISSCB(id) (0x130 + (id) * 0x0c) +#define S3C_CAMIF_REG_CISSCR(id) (0x134 + (id) * 0x0c) +#define S3C_CISS_OFFS_INITIAL(x) ((x) << 16) +#define S3C_CISS_OFFS_LINE(x) ((x) << 0) + +/* ------------------------------------------------------------------ */ + +void camif_hw_reset(struct camif_dev *camif); +void camif_hw_clear_pending_irq(struct camif_vp *vp); +void camif_hw_clear_fifo_overflow(struct camif_vp *vp); +void camif_hw_set_lastirq(struct camif_vp *vp, int enable); +void camif_hw_set_input_path(struct camif_vp *vp); +void camif_hw_enable_scaler(struct camif_vp *vp, bool on); +void camif_hw_enable_capture(struct camif_vp *vp); +void camif_hw_disable_capture(struct camif_vp *vp); +void camif_hw_set_camera_bus(struct camif_dev *camif); +void camif_hw_set_source_format(struct camif_dev *camif); +void camif_hw_set_camera_crop(struct camif_dev *camif); +void camif_hw_set_scaler(struct camif_vp *vp); +void camif_hw_set_flip(struct camif_vp *vp); +void camif_hw_set_output_dma(struct camif_vp *vp); +void camif_hw_set_target_format(struct camif_vp *vp); +void camif_hw_set_test_pattern(struct camif_dev *camif, unsigned int pattern); +void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect, + unsigned int cr, unsigned int cb); +void camif_hw_set_output_addr(struct camif_vp *vp, struct camif_addr *paddr, + int index); +void camif_hw_dump_regs(struct camif_dev *camif, const char *label); + +static inline u32 camif_hw_get_status(struct camif_vp *vp) +{ + return readl(vp->camif->io_base + S3C_CAMIF_REG_CISTATUS(vp->id, + vp->offset)); +} + +#endif /* CAMIF_REGS_H_ */ diff --git a/drivers/media/platform/s5p-fimc/fimc-capture.c b/drivers/media/platform/s5p-fimc/fimc-capture.c index 891ee873c62..fdb6740248a 100644 --- a/drivers/media/platform/s5p-fimc/fimc-capture.c +++ b/drivers/media/platform/s5p-fimc/fimc-capture.c @@ -1230,6 +1230,14 @@ static int fimc_cap_qbuf(struct file *file, void *priv, return vb2_qbuf(&fimc->vid_cap.vbq, buf); } +static int fimc_cap_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct fimc_dev *fimc = video_drvdata(file); + + return vb2_expbuf(&fimc->vid_cap.vbq, eb); +} + static int fimc_cap_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) { @@ -1354,6 +1362,7 @@ static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = { .vidioc_qbuf = fimc_cap_qbuf, .vidioc_dqbuf = fimc_cap_dqbuf, + .vidioc_expbuf = fimc_cap_expbuf, .vidioc_prepare_buf = fimc_cap_prepare_buf, .vidioc_create_bufs = fimc_cap_create_bufs, @@ -1729,7 +1738,7 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, q = &fimc->vid_cap.vbq; memset(q, 0, sizeof(*q)); q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - q->io_modes = VB2_MMAP | VB2_USERPTR; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; q->drv_priv = fimc->vid_cap.ctx; q->ops = &fimc_capture_qops; q->mem_ops = &vb2_dma_contig_memops; diff --git a/drivers/media/platform/s5p-fimc/fimc-m2m.c b/drivers/media/platform/s5p-fimc/fimc-m2m.c index 62afed3162e..1d21da4bd24 100644 --- a/drivers/media/platform/s5p-fimc/fimc-m2m.c +++ b/drivers/media/platform/s5p-fimc/fimc-m2m.c @@ -105,7 +105,7 @@ static void fimc_device_run(void *priv) struct fimc_frame *sf, *df; struct fimc_dev *fimc; unsigned long flags; - u32 ret; + int ret; if (WARN(!ctx, "Null context\n")) return; @@ -439,6 +439,15 @@ static int fimc_m2m_dqbuf(struct file *file, void *fh, return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); } +static int fimc_m2m_expbuf(struct file *file, void *fh, + struct v4l2_exportbuffer *eb) +{ + struct fimc_ctx *ctx = fh_to_ctx(fh); + + return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb); +} + + static int fimc_m2m_streamon(struct file *file, void *fh, enum v4l2_buf_type type) { @@ -607,6 +616,7 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = { .vidioc_querybuf = fimc_m2m_querybuf, .vidioc_qbuf = fimc_m2m_qbuf, .vidioc_dqbuf = fimc_m2m_dqbuf, + .vidioc_expbuf = fimc_m2m_expbuf, .vidioc_streamon = fimc_m2m_streamon, .vidioc_streamoff = fimc_m2m_streamoff, .vidioc_g_crop = fimc_m2m_g_crop, @@ -622,7 +632,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, int ret; src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; src_vq->drv_priv = ctx; src_vq->ops = &fimc_qops; src_vq->mem_ops = &vb2_dma_contig_memops; @@ -633,7 +643,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return ret; dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; dst_vq->drv_priv = ctx; dst_vq->ops = &fimc_qops; dst_vq->mem_ops = &vb2_dma_contig_memops; diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 0531ab70a94..1bd5678cfeb 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c @@ -213,7 +213,7 @@ static int fimc_pipeline_close(struct fimc_pipeline *p) * @pipeline: video pipeline structure * @on: passed as the s_stream call argument */ -int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) +static int fimc_pipeline_s_stream(struct fimc_pipeline *p, bool on) { int i, ret; @@ -547,7 +547,7 @@ static int __fimc_md_create_fimc_sink_links(struct fimc_md *fmd, if (ret) break; - v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]", + v4l2_info(&fmd->v4l2_dev, "created link [%s] %c> [%s]\n", source->name, flags ? '=' : '-', sink->name); if (flags == 0 || sensor == NULL) diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index eb6a70b0f82..6dad9a74f61 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -636,6 +636,19 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return -EINVAL; } +/* Export DMA buffer */ +static int vidioc_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_expbuf(&ctx->vq_src, eb); + if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_expbuf(&ctx->vq_dst, eb); + return -EINVAL; +} + /* Stream on */ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) @@ -813,6 +826,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_dec_ioctl_ops = { .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_expbuf = vidioc_expbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_crop = vidioc_g_crop, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index 2af6d522f4a..f92f6ddd739 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1165,6 +1165,19 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return ret; } +/* Export DMA buffer */ +static int vidioc_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); + + if (eb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + return vb2_expbuf(&ctx->vq_src, eb); + if (eb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return vb2_expbuf(&ctx->vq_dst, eb); + return -EINVAL; +} + /* Stream on */ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type type) @@ -1542,7 +1555,7 @@ int vidioc_encoder_cmd(struct file *file, void *priv, } static int vidioc_subscribe_event(struct v4l2_fh *fh, - struct v4l2_event_subscription *sub) + const struct v4l2_event_subscription *sub) { switch (sub->type) { case V4L2_EVENT_EOS: @@ -1568,6 +1581,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_expbuf = vidioc_expbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_s_parm = vidioc_s_parm, diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 367db755228..2895333866f 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -28,7 +28,7 @@ static struct s5p_mfc_pm *pm; static struct s5p_mfc_dev *p_dev; #ifdef CLK_DEBUG -atomic_t clk_ref; +static atomic_t clk_ref; #endif int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c index 0c1cd895ff6..7379e77bf4e 100644 --- a/drivers/media/platform/s5p-tv/mixer_video.c +++ b/drivers/media/platform/s5p-tv/mixer_video.c @@ -19,7 +19,6 @@ #include <linux/videodev2.h> #include <linux/mm.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/timer.h> #include <media/videobuf2-dma-contig.h> @@ -698,6 +697,15 @@ static int mxr_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) return vb2_dqbuf(&layer->vb_queue, p, file->f_flags & O_NONBLOCK); } +static int mxr_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *eb) +{ + struct mxr_layer *layer = video_drvdata(file); + + mxr_dbg(layer->mdev, "%s:%d\n", __func__, __LINE__); + return vb2_expbuf(&layer->vb_queue, eb); +} + static int mxr_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct mxr_layer *layer = video_drvdata(file); @@ -725,6 +733,7 @@ static const struct v4l2_ioctl_ops mxr_ioctl_ops = { .vidioc_querybuf = mxr_querybuf, .vidioc_qbuf = mxr_qbuf, .vidioc_dqbuf = mxr_dqbuf, + .vidioc_expbuf = mxr_expbuf, /* Streaming control */ .vidioc_streamon = mxr_streamon, .vidioc_streamoff = mxr_streamoff, @@ -1093,7 +1102,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev, layer->vb_queue = (struct vb2_queue) { .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, - .io_modes = VB2_MMAP | VB2_USERPTR, + .io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF, .drv_priv = layer, .buf_struct_size = sizeof(struct mxr_buffer), .ops = &mxr_video_qops, diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig index 9afe1e7bde7..cb6791e62bd 100644 --- a/drivers/media/platform/soc_camera/Kconfig +++ b/drivers/media/platform/soc_camera/Kconfig @@ -19,6 +19,7 @@ config MX1_VIDEO config VIDEO_MX1 tristate "i.MX1/i.MXL CMOS Sensor Interface driver" + depends on BROKEN depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA select FIQ select VIDEOBUF_DMA_CONTIG diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c index d3f0b84e2d7..4e3735679f1 100644 --- a/drivers/media/platform/soc_camera/soc_camera.c +++ b/drivers/media/platform/soc_camera/soc_camera.c @@ -645,11 +645,17 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct soc_camera_device *icd = file->private_data; - int err = -EINVAL; + struct soc_camera_host *ici = to_soc_camera_host(icd->parent); + + dev_dbg(icd->pdev, "read called, buf %p\n", buf); + + if (ici->ops->init_videobuf2 && icd->vb2_vidq.io_modes & VB2_READ) + return vb2_read(&icd->vb2_vidq, buf, count, ppos, + file->f_flags & O_NONBLOCK); dev_err(icd->pdev, "camera device read not implemented\n"); - return err; + return -EINVAL; } static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma) @@ -1048,10 +1054,8 @@ static void scan_add_host(struct soc_camera_host *ici) list_for_each_entry(icd, &devices, list) { if (icd->iface == ici->nr) { - int ret; - icd->parent = ici->v4l2_dev.dev; - ret = soc_camera_probe(icd); + soc_camera_probe(icd); } } diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c index b366b050a3d..0d59b9db83c 100644 --- a/drivers/media/platform/vivi.c +++ b/drivers/media/platform/vivi.c @@ -39,7 +39,6 @@ /* Wake up at about 30 fps */ #define WAKE_NUMERATOR 30 #define WAKE_DENOMINATOR 1001 -#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ #define MAX_WIDTH 1920 #define MAX_HEIGHT 1200 @@ -352,11 +351,6 @@ static void precalculate_bars(struct vivi_dev *dev) } } -#define TSTAMP_MIN_Y 24 -#define TSTAMP_MAX_Y (TSTAMP_MIN_Y + 15) -#define TSTAMP_INPUT_X 10 -#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X) - /* 'odd' is true for pixels 1, 3, 5, etc. and false for pixels 0, 2, 4, etc. */ static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos, bool odd) { @@ -1308,7 +1302,7 @@ static int __init vivi_create_instance(int inst) /* initialize queue */ q = &dev->vb_vidq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vivi_buffer); q->ops = &vivi_video_qops; diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index 12c70e876f5..a739ad492e7 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -82,7 +82,7 @@ static struct radio_isa_card *rtrack_alloc(void) #define AIMS_BIT_VOL_UP (1 << 6) /* active low */ #define AIMS_BIT_VOL_DN (1 << 7) /* active low */ -void rtrack_set_pins(void *handle, u8 pins) +static void rtrack_set_pins(void *handle, u8 pins) { struct radio_isa_card *isa = handle; struct rtrack *rt = container_of(isa, struct rtrack, isa); diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 697a421c994..643d80ac28f 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -645,7 +645,8 @@ static int __init cadet_init(void) set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); video_set_drvdata(&dev->vdev, dev); - if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) + res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); + if (res < 0) goto err_hdl; v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); return 0; diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c index 3c0067de432..84b7b9f4385 100644 --- a/drivers/media/radio/radio-isa.c +++ b/drivers/media/radio/radio-isa.c @@ -191,7 +191,7 @@ static bool radio_isa_valid_io(const struct radio_isa_driver *drv, int io) return false; } -struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv, +static struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv, struct device *pdev) { struct v4l2_device *v4l2_dev; @@ -207,8 +207,9 @@ struct radio_isa_card *radio_isa_alloc(struct radio_isa_driver *drv, return isa; } -int radio_isa_common_probe(struct radio_isa_card *isa, struct device *pdev, - int radio_nr, unsigned region_size) +static int radio_isa_common_probe(struct radio_isa_card *isa, + struct device *pdev, + int radio_nr, unsigned region_size) { const struct radio_isa_driver *drv = isa->drv; const struct radio_isa_ops *ops = drv->ops; @@ -287,7 +288,8 @@ err_dev_reg: return res; } -int radio_isa_common_remove(struct radio_isa_card *isa, unsigned region_size) +static int radio_isa_common_remove(struct radio_isa_card *isa, + unsigned region_size) { const struct radio_isa_ops *ops = isa->drv->ops; diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index 227dcdb54df..c260a2a354b 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -64,7 +64,7 @@ bool pnp_attached; #define FMI_BIT_VOL_SW (1 << 3) #define FMI_BIT_TUN_STRQ (1 << 4) -void fmi_set_pins(void *handle, u8 pins) +static void fmi_set_pins(void *handle, u8 pins) { struct fmi *fmi = handle; u8 bits = FMI_BIT_TUN_STRQ; diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c index d0c90531007..36aec575e0e 100644 --- a/drivers/media/radio/radio-tea5764.c +++ b/drivers/media/radio/radio-tea5764.c @@ -145,7 +145,7 @@ struct tea5764_device { }; /* I2C code related */ -int tea5764_i2c_read(struct tea5764_device *radio) +static int tea5764_i2c_read(struct tea5764_device *radio) { int i; u16 *p = (u16 *) &radio->regs; @@ -165,7 +165,7 @@ int tea5764_i2c_read(struct tea5764_device *radio) return 0; } -int tea5764_i2c_write(struct tea5764_device *radio) +static int tea5764_i2c_write(struct tea5764_device *radio) { struct tea5764_write_regs wr; struct tea5764_regs *r = &radio->regs; diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c index e3079c142c5..bd61b3bd0ca 100644 --- a/drivers/media/radio/si4713-i2c.c +++ b/drivers/media/radio/si4713-i2c.c @@ -1769,7 +1769,7 @@ exit: } /* si4713_ioctl - deal with private ioctls (only rnl for now) */ -long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) +static long si4713_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) { struct si4713_device *sdev = to_si4713_device(sd); struct si4713_rnl *rnl = arg; diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h index d84ad9dad32..aac0f025f76 100644 --- a/drivers/media/radio/wl128x/fmdrv.h +++ b/drivers/media/radio/wl128x/fmdrv.h @@ -60,7 +60,7 @@ #define fmdbg(format, ...) \ printk(KERN_DEBUG "fmdrv: " format, ## __VA_ARGS__) #else /* DEBUG */ -#define fmdbg(format, ...) +#define fmdbg(format, ...) do {} while(0) #endif enum { FM_MODE_OFF, diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index bf867a6b5ea..602ef7ac8c2 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -742,7 +742,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev) if ((meta_data & FM_RDS_STATUS_ERR_MASK) != 0) break; - if (blk_idx < FM_RDS_BLK_IDX_A || blk_idx > FM_RDS_BLK_IDX_D) { + if (blk_idx > FM_RDS_BLK_IDX_D) { fmdbg("Block sequence mismatch\n"); rds->last_blk_idx = -1; break; diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index 3dd9fc097c4..ebf09a3927d 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -305,7 +305,7 @@ int fm_rx_set_volume(struct fmdev *fmdev, u16 vol_to_set) if (fmdev->curr_fmmode != FM_MODE_RX) return -EPERM; - if (vol_to_set < FM_RX_VOLUME_MIN || vol_to_set > FM_RX_VOLUME_MAX) { + if (vol_to_set > FM_RX_VOLUME_MAX) { fmerr("Volume is not within(%d-%d) range\n", FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX); return -EINVAL; diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 49bb356ed14..2d6fb26a017 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -784,7 +784,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote) rdev->priv = ati_remote; rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_TYPE_OTHER; + rdev->allowed_protos = RC_BIT_OTHER; rdev->driver_name = "ati_remote"; rdev->open = ati_remote_rc_open; diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index d05ac15b5de..22231dd4f62 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -329,7 +329,7 @@ static int ene_rx_get_sample_reg(struct ene_device *dev) } /* Sense current received carrier */ -void ene_rx_sense_carrier(struct ene_device *dev) +static void ene_rx_sense_carrier(struct ene_device *dev) { DEFINE_IR_RAW_EVENT(ev); @@ -1003,7 +1003,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL); rdev = rc_allocate_device(); if (!dev || !rdev) - goto error1; + goto failure; /* validate resources */ error = -ENODEV; @@ -1014,10 +1014,10 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) if (!pnp_port_valid(pnp_dev, 0) || pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE) - goto error; + goto failure; if (!pnp_irq_valid(pnp_dev, 0)) - goto error; + goto failure; spin_lock_init(&dev->hw_lock); @@ -1033,7 +1033,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* detect hardware version and features */ error = ene_hw_detect(dev); if (error) - goto error; + goto failure; if (!dev->hw_learning_and_tx_capable && txsim) { dev->hw_learning_and_tx_capable = true; @@ -1046,7 +1046,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) learning_mode_force = false; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; + rdev->allowed_protos = RC_BIT_ALL; rdev->priv = dev; rdev->open = ene_open; rdev->close = ene_close; @@ -1078,30 +1078,27 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id) /* claim the resources */ error = -EBUSY; if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) { - dev->hw_io = -1; - dev->irq = -1; - goto error; + goto failure; } dev->irq = pnp_irq(pnp_dev, 0); if (request_irq(dev->irq, ene_isr, IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) { - dev->irq = -1; - goto error; + goto failure2; } error = rc_register_device(rdev); if (error < 0) - goto error; + goto failure3; pr_notice("driver has been successfully loaded\n"); return 0; -error: - if (dev && dev->irq >= 0) - free_irq(dev->irq, dev); - if (dev && dev->hw_io >= 0) - release_region(dev->hw_io, ENE_IO_SIZE); -error1: + +failure3: + free_irq(dev->irq, dev); +failure2: + release_region(dev->hw_io, ENE_IO_SIZE); +failure: rc_free_device(rdev); kfree(dev); return error; diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index 52fd7696b1b..936c3f79b62 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -541,7 +541,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id /* Set up the rc device */ rdev->priv = fintek; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; + rdev->allowed_protos = RC_BIT_ALL; rdev->open = fintek_open; rdev->close = fintek_close; rdev->input_name = FINTEK_DESCRIPTION; @@ -684,12 +684,12 @@ static struct pnp_driver fintek_driver = { .shutdown = fintek_shutdown, }; -int fintek_init(void) +static int fintek_init(void) { return pnp_register_driver(&fintek_driver); } -void fintek_exit(void) +static void fintek_exit(void) { pnp_unregister_driver(&fintek_driver); } diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c index 04cb272db16..ba1a1eb356c 100644 --- a/drivers/media/rc/gpio-ir-recv.c +++ b/drivers/media/rc/gpio-ir-recv.c @@ -95,7 +95,7 @@ static int __devinit gpio_ir_recv_probe(struct platform_device *pdev) if (pdata->allowed_protos) rcdev->allowed_protos = pdata->allowed_protos; else - rcdev->allowed_protos = RC_TYPE_ALL; + rcdev->allowed_protos = RC_BIT_ALL; rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY; gpio_dev->rcdev = rcdev; diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 51d7057aca0..5a9163da63c 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c @@ -499,7 +499,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf, usb_to_input_id(ir->udev, &rc->input_id); rc->dev.parent = &intf->dev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; + rc->allowed_protos = RC_BIT_ALL; rc->priv = ir; rc->open = iguanair_open; rc->close = iguanair_close; diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 5dd0386604f..8f6a28921ed 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1001,7 +1001,7 @@ static void imon_touch_display_timeout(unsigned long data) * it is not, so we must acquire it prior to calling send_packet, which * requires that the lock is held. */ -static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) +static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) { int retval; struct imon_context *ictx = rc->priv; @@ -1010,31 +1010,27 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) unsigned char ir_proto_packet[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; - if (rc_type && !(rc_type & rc->allowed_protos)) + if (*rc_type && !(*rc_type & rc->allowed_protos)) dev_warn(dev, "Looks like you're trying to use an IR protocol " "this device does not support\n"); - switch (rc_type) { - case RC_TYPE_RC6: + if (*rc_type & RC_BIT_RC6_MCE) { dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); ir_proto_packet[0] = 0x01; - break; - case RC_TYPE_UNKNOWN: - case RC_TYPE_OTHER: + *rc_type = RC_BIT_RC6_MCE; + } else if (*rc_type & RC_BIT_OTHER) { dev_dbg(dev, "Configuring IR receiver for iMON protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - rc_type = RC_TYPE_OTHER; - break; - default: + *rc_type = RC_BIT_OTHER; + } else { dev_warn(dev, "Unsupported IR protocol specified, overriding " "to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ - rc_type = RC_TYPE_OTHER; - break; + *rc_type = RC_BIT_OTHER; } memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet)); @@ -1048,7 +1044,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type) if (retval) goto out; - ictx->rc_type = rc_type; + ictx->rc_type = *rc_type; ictx->pad_mouse = false; out: @@ -1323,7 +1319,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) rel_x = buf[2]; rel_y = buf[3]; - if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { + if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) { if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); @@ -1390,7 +1386,7 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf) buf[0] = 0x01; buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0; - if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) { + if (ictx->rc_type == RC_BIT_OTHER && pad_stabilize) { dir = stabilize((int)rel_x, (int)rel_y, timeout, threshold); if (!dir) { @@ -1511,7 +1507,7 @@ static void imon_incoming_packet(struct imon_context *ictx, kc = imon_panel_key_lookup(scancode); } else { scancode = be32_to_cpu(*((u32 *)buf)); - if (ictx->rc_type == RC_TYPE_RC6) { + if (ictx->rc_type == RC_BIT_RC6_MCE) { ktype = IMON_KEY_IMON; if (buf[0] == 0x80) ktype = IMON_KEY_MCE; @@ -1744,7 +1740,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) { u8 ffdc_cfg_byte = ictx->usb_rx_buf[6]; u8 detected_display_type = IMON_DISPLAY_TYPE_NONE; - u64 allowed_protos = RC_TYPE_OTHER; + u64 allowed_protos = RC_BIT_OTHER; switch (ffdc_cfg_byte) { /* iMON Knob, no display, iMON IR + vol knob */ @@ -1775,13 +1771,13 @@ static void imon_get_ffdc_type(struct imon_context *ictx) case 0x9e: dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; - allowed_protos = RC_TYPE_RC6; + allowed_protos = RC_BIT_RC6_MCE; break; /* iMON LCD, MCE IR */ case 0x9f: dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR"); detected_display_type = IMON_DISPLAY_TYPE_LCD; - allowed_protos = RC_TYPE_RC6; + allowed_protos = RC_BIT_RC6_MCE; break; default: dev_info(ictx->dev, "Unknown 0xffdc device, " @@ -1789,7 +1785,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) detected_display_type = IMON_DISPLAY_TYPE_VFD; /* We don't know which one it is, allow user to set the * RC6 one from userspace if OTHER wasn't correct. */ - allowed_protos |= RC_TYPE_RC6; + allowed_protos |= RC_BIT_RC6_MCE; break; } @@ -1875,7 +1871,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) rdev->priv = ictx; rdev->driver_type = RC_DRIVER_SCANCODE; - rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */ + rdev->allowed_protos = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */ rdev->change_protocol = imon_ir_change_protocol; rdev->driver_name = MOD_NAME; @@ -1893,7 +1889,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx) imon_set_display_type(ictx); - if (ictx->rc_type == RC_TYPE_RC6) + if (ictx->rc_type == RC_BIT_RC6_MCE) rdev->map_name = RC_MAP_IMON_MCE; else rdev->map_name = RC_MAP_IMON_PAD; diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c index 035668e27f6..69edffb9fe9 100644 --- a/drivers/media/rc/ir-jvc-decoder.c +++ b/drivers/media/rc/ir-jvc-decoder.c @@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct jvc_dec *data = &dev->raw->jvc; - if (!(dev->raw->enabled_protocols & RC_TYPE_JVC)) + if (!(dev->raw->enabled_protocols & RC_BIT_JVC)) return 0; if (!is_timing_event(ev)) { @@ -174,7 +174,7 @@ out: } static struct ir_raw_handler jvc_handler = { - .protocols = RC_TYPE_JVC, + .protocols = RC_BIT_JVC, .decode = ir_jvc_decode, }; diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 870c93052fd..9945e5e7f61 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC)) + if (!(dev->raw->enabled_protocols & RC_BIT_LIRC)) return 0; if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) @@ -408,7 +408,7 @@ static int ir_lirc_unregister(struct rc_dev *dev) } static struct ir_raw_handler lirc_handler = { - .protocols = RC_TYPE_LIRC, + .protocols = RC_BIT_LIRC, .decode = ir_lirc_decode, .raw_register = ir_lirc_register, .raw_unregister = ir_lirc_unregister, diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c index 3784ebf80ec..33fafa4cf7c 100644 --- a/drivers/media/rc/ir-mce_kbd-decoder.c +++ b/drivers/media/rc/ir-mce_kbd-decoder.c @@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; unsigned long delay; - if (!(dev->raw->enabled_protocols & RC_TYPE_MCE_KBD)) + if (!(dev->raw->enabled_protocols & RC_BIT_MCE_KBD)) return 0; if (!is_timing_event(ev)) { @@ -422,7 +422,7 @@ static int ir_mce_kbd_unregister(struct rc_dev *dev) } static struct ir_raw_handler mce_kbd_handler = { - .protocols = RC_TYPE_MCE_KBD, + .protocols = RC_BIT_MCE_KBD, .decode = ir_mce_kbd_decode, .raw_register = ir_mce_kbd_register, .raw_unregister = ir_mce_kbd_unregister, diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c index 2ca509e6e16..a47ee363496 100644 --- a/drivers/media/rc/ir-nec-decoder.c +++ b/drivers/media/rc/ir-nec-decoder.c @@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 address, not_address, command, not_command; bool send_32bits = false; - if (!(dev->raw->enabled_protocols & RC_TYPE_NEC)) + if (!(dev->raw->enabled_protocols & RC_BIT_NEC)) return 0; if (!is_timing_event(ev)) { @@ -201,7 +201,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev) } static struct ir_raw_handler nec_handler = { - .protocols = RC_TYPE_NEC, + .protocols = RC_BIT_NEC, .decode = ir_nec_decode, }; diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c index 9ab663a507a..5b4d1ddeac4 100644 --- a/drivers/media/rc/ir-rc5-decoder.c +++ b/drivers/media/rc/ir-rc5-decoder.c @@ -52,8 +52,8 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle; u32 scancode; - if (!(dev->raw->enabled_protocols & RC_TYPE_RC5)) - return 0; + if (!(dev->raw->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X))) + return 0; if (!is_timing_event(ev)) { if (ev.reset) @@ -128,6 +128,10 @@ again: if (data->wanted_bits == RC5X_NBITS) { /* RC5X */ u8 xdata, command, system; + if (!(dev->raw->enabled_protocols & RC_BIT_RC5X)) { + data->state = STATE_INACTIVE; + return 0; + } xdata = (data->bits & 0x0003F) >> 0; command = (data->bits & 0x00FC0) >> 6; system = (data->bits & 0x1F000) >> 12; @@ -141,6 +145,10 @@ again: } else { /* RC5 */ u8 command, system; + if (!(dev->raw->enabled_protocols & RC_BIT_RC5)) { + data->state = STATE_INACTIVE; + return 0; + } command = (data->bits & 0x0003F) >> 0; system = (data->bits & 0x007C0) >> 6; toggle = (data->bits & 0x00800) ? 1 : 0; @@ -164,7 +172,7 @@ out: } static struct ir_raw_handler rc5_handler = { - .protocols = RC_TYPE_RC5, + .protocols = RC_BIT_RC5 | RC_BIT_RC5X, .decode = ir_rc5_decode, }; diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c index ec8d4a2e2c5..fd807a8308d 100644 --- a/drivers/media/rc/ir-rc5-sz-decoder.c +++ b/drivers/media/rc/ir-rc5-sz-decoder.c @@ -48,8 +48,8 @@ static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev) u8 toggle, command, system; u32 scancode; - if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ)) - return 0; + if (!(dev->raw->enabled_protocols & RC_BIT_RC5_SZ)) + return 0; if (!is_timing_event(ev)) { if (ev.reset) @@ -128,7 +128,7 @@ out: } static struct ir_raw_handler rc5_sz_handler = { - .protocols = RC_TYPE_RC5_SZ, + .protocols = RC_BIT_RC5_SZ, .decode = ir_rc5_sz_decode, }; diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c index 4cfdd7fa4bb..e19072ffb36 100644 --- a/drivers/media/rc/ir-rc6-decoder.c +++ b/drivers/media/rc/ir-rc6-decoder.c @@ -89,7 +89,9 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 toggle; - if (!(dev->raw->enabled_protocols & RC_TYPE_RC6)) + if (!(dev->raw->enabled_protocols & + (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | + RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE))) return 0; if (!is_timing_event(ev)) { @@ -271,7 +273,9 @@ out: } static struct ir_raw_handler rc6_handler = { - .protocols = RC_TYPE_RC6, + .protocols = RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | + RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | + RC_BIT_RC6_MCE, .decode = ir_rc6_decode, }; diff --git a/drivers/media/rc/ir-rx51.c b/drivers/media/rc/ir-rx51.c index 82e6c1e282d..9e76c7b40af 100644 --- a/drivers/media/rc/ir-rx51.c +++ b/drivers/media/rc/ir-rx51.c @@ -479,18 +479,7 @@ struct platform_driver lirc_rx51_platform_driver = { .owner = THIS_MODULE, }, }; - -static int __init lirc_rx51_init(void) -{ - return platform_driver_register(&lirc_rx51_platform_driver); -} -module_init(lirc_rx51_init); - -static void __exit lirc_rx51_exit(void) -{ - platform_driver_unregister(&lirc_rx51_platform_driver); -} -module_exit(lirc_rx51_exit); +module_platform_driver(lirc_rx51_platform_driver); MODULE_DESCRIPTION("LIRC TX driver for Nokia RX51"); MODULE_AUTHOR("Nokia Corporation"); diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 7e54ec57bcf..7e69a3b6537 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 address, command, not_command; - if (!(dev->raw->enabled_protocols & RC_TYPE_SANYO)) + if (!(dev->raw->enabled_protocols & RC_BIT_SANYO)) return 0; if (!is_timing_event(ev)) { @@ -179,7 +179,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) } static struct ir_raw_handler sanyo_handler = { - .protocols = RC_TYPE_SANYO, + .protocols = RC_BIT_SANYO, .decode = ir_sanyo_decode, }; diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c index dab98b37621..fb914342cf4 100644 --- a/drivers/media/rc/ir-sony-decoder.c +++ b/drivers/media/rc/ir-sony-decoder.c @@ -45,7 +45,8 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) u32 scancode; u8 device, subdevice, function; - if (!(dev->raw->enabled_protocols & RC_TYPE_SONY)) + if (!(dev->raw->enabled_protocols & + (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20))) return 0; if (!is_timing_event(ev)) { @@ -123,16 +124,28 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev) switch (data->count) { case 12: + if (!(dev->raw->enabled_protocols & RC_BIT_SONY12)) { + data->state = STATE_INACTIVE; + return 0; + } device = bitrev8((data->bits << 3) & 0xF8); subdevice = 0; function = bitrev8((data->bits >> 4) & 0xFE); break; case 15: + if (!(dev->raw->enabled_protocols & RC_BIT_SONY15)) { + data->state = STATE_INACTIVE; + return 0; + } device = bitrev8((data->bits >> 0) & 0xFF); subdevice = 0; function = bitrev8((data->bits >> 7) & 0xFE); break; case 20: + if (!(dev->raw->enabled_protocols & RC_BIT_SONY20)) { + data->state = STATE_INACTIVE; + return 0; + } device = bitrev8((data->bits >> 5) & 0xF8); subdevice = bitrev8((data->bits >> 0) & 0xFF); function = bitrev8((data->bits >> 12) & 0xFE); @@ -157,7 +170,7 @@ out: } static struct ir_raw_handler sony_handler = { - .protocols = RC_TYPE_SONY, + .protocols = RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20, .decode = ir_sony_decode, }; diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 24c77a42fc3..5e5a7f2b818 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -1563,7 +1563,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id /* set up ir-core props */ rdev->priv = itdev; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; + rdev->allowed_protos = RC_BIT_ALL; rdev->open = ite_open; rdev->close = ite_close; rdev->s_idle = ite_s_idle; @@ -1708,12 +1708,12 @@ static struct pnp_driver ite_driver = { .shutdown = ite_shutdown, }; -int ite_init(void) +static int ite_init(void) { return pnp_register_driver(&ite_driver); } -void ite_exit(void) +static void ite_exit(void) { pnp_unregister_driver(&ite_driver); } diff --git a/drivers/media/rc/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c index 124c7228ba8..f0da960560b 100644 --- a/drivers/media/rc/keymaps/rc-imon-mce.c +++ b/drivers/media/rc/keymaps/rc-imon-mce.c @@ -121,7 +121,7 @@ static struct rc_map_list imon_mce_map = { .scan = imon_mce, .size = ARRAY_SIZE(imon_mce), /* its RC6, but w/a hardware decoder */ - .rc_type = RC_TYPE_RC6, + .rc_type = RC_TYPE_RC6_MCE, .name = RC_MAP_IMON_MCE, } }; diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c index 753e43ec787..ef4006fe4de 100644 --- a/drivers/media/rc/keymaps/rc-rc6-mce.c +++ b/drivers/media/rc/keymaps/rc-rc6-mce.c @@ -97,7 +97,7 @@ static struct rc_map_list rc6_mce_map = { .map = { .scan = rc6_mce, .size = ARRAY_SIZE(rc6_mce), - .rc_type = RC_TYPE_RC6, + .rc_type = RC_TYPE_RC6_MCE, .name = RC_MAP_RC6_MCE, } }; diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 850547fe711..b2146cd99fd 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -1205,7 +1205,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir) rc->dev.parent = dev; rc->priv = ir; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; + rc->allowed_protos = RC_BIT_ALL; rc->timeout = MS_TO_NS(100); if (!ir->flags.no_tx) { rc->s_tx_mask = mceusb_set_tx_mask; diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 2ea913a44ae..e4ea89a11ee 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -472,6 +472,7 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); } +#if 0 /* Currently unused */ /* rx carrier detect only works in learning mode, must be called w/nvt_lock */ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) { @@ -504,7 +505,7 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) return carrier; } - +#endif /* * set carrier frequency * @@ -620,7 +621,6 @@ static void nvt_dump_rx_buf(struct nvt_dev *nvt) static void nvt_process_rx_ir_data(struct nvt_dev *nvt) { DEFINE_IR_RAW_EVENT(rawir); - u32 carrier; u8 sample; int i; @@ -629,9 +629,6 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) if (debug) nvt_dump_rx_buf(nvt); - if (nvt->carrier_detect_enabled) - carrier = nvt_rx_carrier_detect(nvt); - nvt_dbg_verbose("Processing buffer of len %d", nvt->pkts); init_ir_raw_event(&rawir); @@ -1045,7 +1042,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* Set up the rc device */ rdev->priv = nvt; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; + rdev->allowed_protos = RC_BIT_ALL; rdev->open = nvt_open; rdev->close = nvt_close; rdev->tx_ir = nvt_tx_ir; @@ -1220,12 +1217,12 @@ static struct pnp_driver nvt_driver = { .shutdown = nvt_shutdown, }; -int nvt_init(void) +static int nvt_init(void) { return pnp_register_driver(&nvt_driver); } -void nvt_exit(void) +static void nvt_exit(void) { pnp_unregister_driver(&nvt_driver); } diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 0d5e0872a2e..7c3674ff5ea 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -103,7 +103,6 @@ struct nvt_dev { /* rx settings */ bool learning_enabled; - bool carrier_detect_enabled; /* track cir wake state */ u8 wake_state; diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c index f9be68132c6..53d02827a47 100644 --- a/drivers/media/rc/rc-loopback.c +++ b/drivers/media/rc/rc-loopback.c @@ -195,7 +195,7 @@ static int __init loop_init(void) rc->map_name = RC_MAP_EMPTY; rc->priv = &loopdev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; + rc->allowed_protos = RC_BIT_ALL; rc->timeout = 100 * 1000 * 1000; /* 100 ms */ rc->min_timeout = 1; rc->max_timeout = UINT_MAX; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index cabc19c1051..601d1ac1c68 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -725,25 +725,36 @@ static struct class ir_input_class = { .devnode = ir_devnode, }; +/* + * These are the protocol textual descriptions that are + * used by the sysfs protocols file. Note that the order + * of the entries is relevant. + */ static struct { u64 type; char *name; } proto_names[] = { - { RC_TYPE_UNKNOWN, "unknown" }, - { RC_TYPE_RC5, "rc-5" }, - { RC_TYPE_NEC, "nec" }, - { RC_TYPE_RC6, "rc-6" }, - { RC_TYPE_JVC, "jvc" }, - { RC_TYPE_SONY, "sony" }, - { RC_TYPE_RC5_SZ, "rc-5-sz" }, - { RC_TYPE_SANYO, "sanyo" }, - { RC_TYPE_MCE_KBD, "mce_kbd" }, - { RC_TYPE_LIRC, "lirc" }, - { RC_TYPE_OTHER, "other" }, + { RC_BIT_NONE, "none" }, + { RC_BIT_OTHER, "other" }, + { RC_BIT_UNKNOWN, "unknown" }, + { RC_BIT_RC5 | + RC_BIT_RC5X, "rc-5" }, + { RC_BIT_NEC, "nec" }, + { RC_BIT_RC6_0 | + RC_BIT_RC6_6A_20 | + RC_BIT_RC6_6A_24 | + RC_BIT_RC6_6A_32 | + RC_BIT_RC6_MCE, "rc-6" }, + { RC_BIT_JVC, "jvc" }, + { RC_BIT_SONY12 | + RC_BIT_SONY15 | + RC_BIT_SONY20, "sony" }, + { RC_BIT_RC5_SZ, "rc-5-sz" }, + { RC_BIT_SANYO, "sanyo" }, + { RC_BIT_MCE_KBD, "mce_kbd" }, + { RC_BIT_LIRC, "lirc" }, }; -#define PROTO_NONE "none" - /** * show_protocols() - shows the current IR protocol(s) * @device: the device descriptor @@ -790,6 +801,9 @@ static ssize_t show_protocols(struct device *device, tmp += sprintf(tmp, "[%s] ", proto_names[i].name); else if (allowed & proto_names[i].type) tmp += sprintf(tmp, "%s ", proto_names[i].name); + + if (allowed & proto_names[i].type) + allowed &= ~proto_names[i].type; } if (tmp != buf) @@ -867,26 +881,20 @@ static ssize_t store_protocols(struct device *device, disable = false; } - if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) { - tmp += sizeof(PROTO_NONE); - mask = 0; - count++; - } else { - for (i = 0; i < ARRAY_SIZE(proto_names); i++) { - if (!strcasecmp(tmp, proto_names[i].name)) { - tmp += strlen(proto_names[i].name); - mask = proto_names[i].type; - break; - } - } - if (i == ARRAY_SIZE(proto_names)) { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - ret = -EINVAL; - goto out; + for (i = 0; i < ARRAY_SIZE(proto_names); i++) { + if (!strcasecmp(tmp, proto_names[i].name)) { + mask = proto_names[i].type; + break; } - count++; } + if (i == ARRAY_SIZE(proto_names)) { + IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + return -EINVAL; + } + + count++; + if (enable) type |= mask; else if (disable) @@ -902,7 +910,7 @@ static ssize_t store_protocols(struct device *device, } if (dev->change_protocol) { - rc = dev->change_protocol(dev, type); + rc = dev->change_protocol(dev, &type); if (rc < 0) { IR_dprintk(1, "Error setting protocols to 0x%llx\n", (long long)type); @@ -1117,7 +1125,8 @@ int rc_register_device(struct rc_dev *dev) } if (dev->change_protocol) { - rc = dev->change_protocol(dev, rc_map->rc_type); + u64 rc_type = (1 << rc_map->rc_type); + rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; } diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 9f5a17bb5ef..a8887aba9fa 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -1082,7 +1082,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->dev.parent = dev; rc->priv = rr3; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; + rc->allowed_protos = RC_BIT_ALL; rc->timeout = US_TO_NS(2750); rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index d6f4bfe0939..c720f12f661 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -322,7 +322,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) rdev->dev.parent = dev; rdev->priv = sz; rdev->driver_type = RC_DRIVER_IR_RAW; - rdev->allowed_protos = RC_TYPE_ALL; + rdev->allowed_protos = RC_BIT_ALL; rdev->driver_name = DRIVER_NAME; rdev->map_name = RC_MAP_STREAMZAP; diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c index fef05235234..f0921b5483e 100644 --- a/drivers/media/rc/ttusbir.c +++ b/drivers/media/rc/ttusbir.c @@ -316,7 +316,7 @@ static int __devinit ttusbir_probe(struct usb_interface *intf, usb_to_input_id(tt->udev, &rc->input_id); rc->dev.parent = &intf->dev; rc->driver_type = RC_DRIVER_IR_RAW; - rc->allowed_protos = RC_TYPE_ALL; + rc->allowed_protos = RC_BIT_ALL; rc->priv = tt; rc->driver_name = DRIVER_NAME; rc->map_name = RC_MAP_TT_1500; diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 7c9b5f33113..7f3c476dde0 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -7,6 +7,7 @@ * with minor modifications. * * Original Author: David Härdeman <david@hardeman.nu> + * Copyright (C) 2012 Sean Young <sean@mess.org> * Copyright (C) 2009 - 2011 David Härdeman <david@hardeman.nu> * * Dedicated to my daughter Matilda, without whose loving attention this @@ -22,9 +23,7 @@ * o IR Receive * o IR Transmit * o Wake-On-CIR functionality - * - * To do: - * o Learning + * o Carrier detection * * 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 @@ -149,6 +148,12 @@ #define WBCIR_REGSEL_MASK 0x20 /* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */ #define WBCIR_REG_ADDR0 0x00 +/* Enable carrier counter */ +#define WBCIR_CNTR_EN 0x01 +/* Reset carrier counter */ +#define WBCIR_CNTR_R 0x02 +/* Invert TX */ +#define WBCIR_IRTX_INV 0x04 /* Valid banks for the SP3 UART */ enum wbcir_bank { @@ -184,7 +189,7 @@ enum wbcir_txstate { }; /* Misc */ -#define WBCIR_NAME "winbond-cir" +#define WBCIR_NAME "Winbond CIR" #define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */ #define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */ #define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */ @@ -207,7 +212,8 @@ struct wbcir_data { /* RX state */ enum wbcir_rxstate rxstate; struct led_trigger *rxtrigger; - struct ir_raw_event rxev; + int carrier_report_enabled; + u32 pulse_duration; /* TX state */ enum wbcir_txstate txstate; @@ -330,6 +336,30 @@ wbcir_to_rc6cells(u8 val) *****************************************************************************/ static void +wbcir_carrier_report(struct wbcir_data *data) +{ + unsigned counter = inb(data->ebase + WBCIR_REG_ECEIR_CNT_LO) | + inb(data->ebase + WBCIR_REG_ECEIR_CNT_HI) << 8; + + if (counter > 0 && counter < 0xffff) { + DEFINE_IR_RAW_EVENT(ev); + + ev.carrier_report = 1; + ev.carrier = DIV_ROUND_CLOSEST(counter * 1000000u, + data->pulse_duration); + + ir_raw_event_store(data->dev, &ev); + } + + /* reset and restart the counter */ + data->pulse_duration = 0; + wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_R, + WBCIR_CNTR_EN | WBCIR_CNTR_R); + wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_EN, + WBCIR_CNTR_EN | WBCIR_CNTR_R); +} + +static void wbcir_idle_rx(struct rc_dev *dev, bool idle) { struct wbcir_data *data = dev->priv; @@ -339,9 +369,16 @@ wbcir_idle_rx(struct rc_dev *dev, bool idle) led_trigger_event(data->rxtrigger, LED_FULL); } - if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE) + if (idle && data->rxstate != WBCIR_RXSTATE_INACTIVE) { + data->rxstate = WBCIR_RXSTATE_INACTIVE; + led_trigger_event(data->rxtrigger, LED_OFF); + + if (data->carrier_report_enabled) + wbcir_carrier_report(data); + /* Tell hardware to go idle by setting RXINACTIVE */ outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR); + } } static void @@ -349,21 +386,22 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device) { u8 irdata; DEFINE_IR_RAW_EVENT(rawir); + unsigned duration; /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */ while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) { irdata = inb(data->sbase + WBCIR_REG_SP3_RXDATA); if (data->rxstate == WBCIR_RXSTATE_ERROR) continue; + + duration = ((irdata & 0x7F) + 1) * 2; rawir.pulse = irdata & 0x80 ? false : true; - rawir.duration = US_TO_NS(((irdata & 0x7F) + 1) * 10); - ir_raw_event_store_with_filter(data->dev, &rawir); - } + rawir.duration = US_TO_NS(duration); - /* Check if we should go idle */ - if (data->dev->idle) { - led_trigger_event(data->rxtrigger, LED_OFF); - data->rxstate = WBCIR_RXSTATE_INACTIVE; + if (rawir.pulse) + data->pulse_duration += duration; + + ir_raw_event_store_with_filter(data->dev, &rawir); } ir_raw_event_handle(data->dev); @@ -492,6 +530,33 @@ wbcir_irq_handler(int irqno, void *cookie) *****************************************************************************/ static int +wbcir_set_carrier_report(struct rc_dev *dev, int enable) +{ + struct wbcir_data *data = dev->priv; + unsigned long flags; + + spin_lock_irqsave(&data->spinlock, flags); + + if (data->carrier_report_enabled == enable) { + spin_unlock_irqrestore(&data->spinlock, flags); + return 0; + } + + data->pulse_duration = 0; + wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, WBCIR_CNTR_R, + WBCIR_CNTR_EN | WBCIR_CNTR_R); + + if (enable && data->dev->idle) + wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CCTL, + WBCIR_CNTR_EN, WBCIR_CNTR_EN | WBCIR_CNTR_R); + + data->carrier_report_enabled = enable; + spin_unlock_irqrestore(&data->spinlock, flags); + + return 0; +} + +static int wbcir_txcarrier(struct rc_dev *dev, u32 carrier) { struct wbcir_data *data = dev->priv; @@ -837,7 +902,7 @@ wbcir_init_hw(struct wbcir_data *data) /* Set IRTX_INV */ if (invert) - outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL); + outb(WBCIR_IRTX_INV, data->ebase + WBCIR_REG_ECEIR_CCTL); else outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL); @@ -866,8 +931,8 @@ wbcir_init_hw(struct wbcir_data *data) /* prescaler 1.0, tx/rx fifo lvl 16 */ outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2); - /* Set baud divisor to sample every 10 us */ - outb(0x0F, data->sbase + WBCIR_REG_SP3_BGDL); + /* Set baud divisor to sample every 2 ns */ + outb(0x03, data->sbase + WBCIR_REG_SP3_BGDL); outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH); /* Set CEIR mode */ @@ -876,9 +941,12 @@ wbcir_init_hw(struct wbcir_data *data) inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */ inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */ - /* Disable RX demod, enable run-length enc/dec, set freq span */ + /* + * Disable RX demod, enable run-length enc/dec, set freq span and + * enable over-sampling + */ wbcir_select_bank(data, WBCIR_BANK_7); - outb(0x90, data->sbase + WBCIR_REG_SP3_RCCFG); + outb(0xd0, data->sbase + WBCIR_REG_SP3_RCCFG); /* Disable timer */ wbcir_select_bank(data, WBCIR_BANK_4); @@ -915,9 +983,8 @@ wbcir_init_hw(struct wbcir_data *data) /* Clear RX state */ data->rxstate = WBCIR_RXSTATE_INACTIVE; - data->rxev.duration = 0; ir_raw_event_reset(data->dev); - ir_raw_event_handle(data->dev); + ir_raw_event_set_idle(data->dev, true); /* Clear TX state */ if (data->txstate == WBCIR_TXSTATE_ACTIVE) { @@ -1007,7 +1074,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) } data->dev->driver_type = RC_DRIVER_IR_RAW; - data->dev->driver_name = WBCIR_NAME; + data->dev->driver_name = DRVNAME; data->dev->input_name = WBCIR_NAME; data->dev->input_phys = "wbcir/cir0"; data->dev->input_id.bustype = BUS_HOST; @@ -1016,13 +1083,15 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) data->dev->input_id.version = WBCIR_ID_CHIP; data->dev->map_name = RC_MAP_RC6_MCE; data->dev->s_idle = wbcir_idle_rx; + data->dev->s_carrier_report = wbcir_set_carrier_report; data->dev->s_tx_mask = wbcir_txmask; data->dev->s_tx_carrier = wbcir_txcarrier; data->dev->tx_ir = wbcir_tx; data->dev->priv = data; data->dev->dev.parent = &device->dev; data->dev->timeout = MS_TO_NS(100); - data->dev->allowed_protos = RC_TYPE_ALL; + data->dev->rx_resolution = US_TO_NS(2); + data->dev->allowed_protos = RC_BIT_ALL; if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) { dev_err(dev, "Region 0x%lx-0x%lx already in use!\n", diff --git a/drivers/media/tuners/fc2580.c b/drivers/media/tuners/fc2580.c index aff39ae457a..81f38aae9c6 100644 --- a/drivers/media/tuners/fc2580.c +++ b/drivers/media/tuners/fc2580.c @@ -35,8 +35,6 @@ * Currently it blind writes bunch of static registers from the * fc2580_freq_regs_lut[] when fc2580_set_params() is called. Add some * logic to reduce unneeded register writes. - * There is also don't-care registers, initialized with value 0xff, and those - * are also written to the chip currently (yes, not wise). */ /* write multiple registers */ @@ -111,6 +109,17 @@ static int fc2580_rd_reg(struct fc2580_priv *priv, u8 reg, u8 *val) return fc2580_rd_regs(priv, reg, val, 1); } +/* write single register conditionally only when value differs from 0xff + * XXX: This is special routine meant only for writing fc2580_freq_regs_lut[] + * values. Do not use for the other purposes. */ +static int fc2580_wr_reg_ff(struct fc2580_priv *priv, u8 reg, u8 val) +{ + if (val == 0xff) + return 0; + else + return fc2580_wr_regs(priv, reg, &val, 1); +} + static int fc2580_set_params(struct dvb_frontend *fe) { struct fc2580_priv *priv = fe->tuner_priv; @@ -213,99 +222,99 @@ static int fc2580_set_params(struct dvb_frontend *fe) if (i == ARRAY_SIZE(fc2580_freq_regs_lut)) goto err; - ret = fc2580_wr_reg(priv, 0x25, fc2580_freq_regs_lut[i].r25_val); + ret = fc2580_wr_reg_ff(priv, 0x25, fc2580_freq_regs_lut[i].r25_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x27, fc2580_freq_regs_lut[i].r27_val); + ret = fc2580_wr_reg_ff(priv, 0x27, fc2580_freq_regs_lut[i].r27_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x28, fc2580_freq_regs_lut[i].r28_val); + ret = fc2580_wr_reg_ff(priv, 0x28, fc2580_freq_regs_lut[i].r28_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x29, fc2580_freq_regs_lut[i].r29_val); + ret = fc2580_wr_reg_ff(priv, 0x29, fc2580_freq_regs_lut[i].r29_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x2b, fc2580_freq_regs_lut[i].r2b_val); + ret = fc2580_wr_reg_ff(priv, 0x2b, fc2580_freq_regs_lut[i].r2b_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x2c, fc2580_freq_regs_lut[i].r2c_val); + ret = fc2580_wr_reg_ff(priv, 0x2c, fc2580_freq_regs_lut[i].r2c_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x2d, fc2580_freq_regs_lut[i].r2d_val); + ret = fc2580_wr_reg_ff(priv, 0x2d, fc2580_freq_regs_lut[i].r2d_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x30, fc2580_freq_regs_lut[i].r30_val); + ret = fc2580_wr_reg_ff(priv, 0x30, fc2580_freq_regs_lut[i].r30_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x44, fc2580_freq_regs_lut[i].r44_val); + ret = fc2580_wr_reg_ff(priv, 0x44, fc2580_freq_regs_lut[i].r44_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x50, fc2580_freq_regs_lut[i].r50_val); + ret = fc2580_wr_reg_ff(priv, 0x50, fc2580_freq_regs_lut[i].r50_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x53, fc2580_freq_regs_lut[i].r53_val); + ret = fc2580_wr_reg_ff(priv, 0x53, fc2580_freq_regs_lut[i].r53_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x5f, fc2580_freq_regs_lut[i].r5f_val); + ret = fc2580_wr_reg_ff(priv, 0x5f, fc2580_freq_regs_lut[i].r5f_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x61, fc2580_freq_regs_lut[i].r61_val); + ret = fc2580_wr_reg_ff(priv, 0x61, fc2580_freq_regs_lut[i].r61_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x62, fc2580_freq_regs_lut[i].r62_val); + ret = fc2580_wr_reg_ff(priv, 0x62, fc2580_freq_regs_lut[i].r62_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x63, fc2580_freq_regs_lut[i].r63_val); + ret = fc2580_wr_reg_ff(priv, 0x63, fc2580_freq_regs_lut[i].r63_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x67, fc2580_freq_regs_lut[i].r67_val); + ret = fc2580_wr_reg_ff(priv, 0x67, fc2580_freq_regs_lut[i].r67_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x68, fc2580_freq_regs_lut[i].r68_val); + ret = fc2580_wr_reg_ff(priv, 0x68, fc2580_freq_regs_lut[i].r68_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x69, fc2580_freq_regs_lut[i].r69_val); + ret = fc2580_wr_reg_ff(priv, 0x69, fc2580_freq_regs_lut[i].r69_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x6a, fc2580_freq_regs_lut[i].r6a_val); + ret = fc2580_wr_reg_ff(priv, 0x6a, fc2580_freq_regs_lut[i].r6a_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x6b, fc2580_freq_regs_lut[i].r6b_val); + ret = fc2580_wr_reg_ff(priv, 0x6b, fc2580_freq_regs_lut[i].r6b_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x6c, fc2580_freq_regs_lut[i].r6c_val); + ret = fc2580_wr_reg_ff(priv, 0x6c, fc2580_freq_regs_lut[i].r6c_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x6d, fc2580_freq_regs_lut[i].r6d_val); + ret = fc2580_wr_reg_ff(priv, 0x6d, fc2580_freq_regs_lut[i].r6d_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x6e, fc2580_freq_regs_lut[i].r6e_val); + ret = fc2580_wr_reg_ff(priv, 0x6e, fc2580_freq_regs_lut[i].r6e_val); if (ret < 0) goto err; - ret = fc2580_wr_reg(priv, 0x6f, fc2580_freq_regs_lut[i].r6f_val); + ret = fc2580_wr_reg_ff(priv, 0x6f, fc2580_freq_regs_lut[i].r6f_val); if (ret < 0) goto err; diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c index ba84936aafd..95ed46f2cd2 100644 --- a/drivers/media/tuners/max2165.c +++ b/drivers/media/tuners/max2165.c @@ -161,7 +161,7 @@ static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) return 0; } -int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) +static int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) { u32 remainder; u32 q, f = 0; diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c index 38966847407..83a6240f64d 100644 --- a/drivers/media/tuners/tua9001.c +++ b/drivers/media/tuners/tua9001.c @@ -136,7 +136,7 @@ static int tua9001_set_params(struct dvb_frontend *fe) { struct tua9001_priv *priv = fe->tuner_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret, i; + int ret = 0, i; u16 val; u32 frequency; struct reg_val data[2]; diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index 4937712278f..5c0fd787cc8 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -934,7 +934,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, int rc = 0, is_retry = 0; u16 hwmodel; v4l2_std_id std0; - u8 hw_major, hw_minor, fw_major, fw_minor; + u8 hw_major = 0, hw_minor = 0, fw_major = 0, fw_minor = 0; dprintk(1, "%s called\n", __func__); diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c index 448361c6a13..0cb7c28dcb1 100644 --- a/drivers/media/usb/au0828/au0828-cards.c +++ b/drivers/media/usb/au0828/au0828-cards.c @@ -25,7 +25,7 @@ #include "media/tuner.h" #include "media/v4l2-common.h" -void hvr950q_cs5340_audio(void *priv, int enable) +static void hvr950q_cs5340_audio(void *priv, int enable) { /* Because the HVR-950q shares an i2s bus between the cs5340 and the au8522, we need to hold cs5340 in reset when using the au8522 */ diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c index b328f6550d0..9a6f15613a3 100644 --- a/drivers/media/usb/au0828/au0828-dvb.c +++ b/drivers/media/usb/au0828/au0828-dvb.c @@ -272,7 +272,6 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) struct au0828_dev *dev = container_of(work, struct au0828_dev, restart_streaming); struct au0828_dvb *dvb = &dev->dvb; - int ret; if (dev->urb_streaming == 0) return; @@ -282,7 +281,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) mutex_lock(&dvb->lock); /* Stop transport */ - ret = stop_urb_transfer(dev); + stop_urb_transfer(dev); au0828_write(dev, 0x608, 0x00); au0828_write(dev, 0x609, 0x00); au0828_write(dev, 0x60a, 0x00); @@ -293,7 +292,7 @@ static void au0828_restart_dvb_streaming(struct work_struct *work) au0828_write(dev, 0x609, 0x72); au0828_write(dev, 0x60a, 0x71); au0828_write(dev, 0x60b, 0x01); - ret = start_urb_transfer(dev); + start_urb_transfer(dev); mutex_unlock(&dvb->lock); } diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 87058557057..45387aab10c 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -158,7 +158,7 @@ static void au0828_irq_callback(struct urb *urb) /* * Stop and Deallocate URBs */ -void au0828_uninit_isoc(struct au0828_dev *dev) +static void au0828_uninit_isoc(struct au0828_dev *dev) { struct urb *urb; int i; @@ -197,9 +197,9 @@ void au0828_uninit_isoc(struct au0828_dev *dev) /* * Allocate URBs and start IRQ */ -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)) +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)) { struct au0828_dmaqueue *dma_q = &dev->vidq; int i; @@ -783,7 +783,7 @@ static int au0828_i2s_init(struct au0828_dev *dev) * Auvitek au0828 analog stream enable * Please set interface0 to AS5 before enable the stream */ -int au0828_analog_stream_enable(struct au0828_dev *d) +static int au0828_analog_stream_enable(struct au0828_dev *d) { dprintk(1, "au0828_analog_stream_enable called\n"); au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00); @@ -810,7 +810,7 @@ int au0828_analog_stream_disable(struct au0828_dev *d) return 0; } -void au0828_analog_stream_reset(struct au0828_dev *dev) +static void au0828_analog_stream_reset(struct au0828_dev *dev) { dprintk(1, "au0828_analog_stream_reset called\n"); au0828_writereg(dev, AU0828_SENSORCTRL_100, 0x0); @@ -913,7 +913,7 @@ static int get_ressource(struct au0828_fh *fh) /* 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) */ -void au0828_vid_buffer_timeout(unsigned long data) +static void au0828_vid_buffer_timeout(unsigned long data) { struct au0828_dev *dev = (struct au0828_dev *) data; struct au0828_dmaqueue *dma_q = &dev->vidq; @@ -937,7 +937,7 @@ void au0828_vid_buffer_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock, flags); } -void au0828_vbi_buffer_timeout(unsigned long data) +static void au0828_vbi_buffer_timeout(unsigned long data) { struct au0828_dev *dev = (struct au0828_dev *) data; struct au0828_dmaqueue *dma_q = &dev->vbiq; diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c index 447148eff95..72220791374 100644 --- a/drivers/media/usb/cx231xx/cx231xx-avcore.c +++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c @@ -1068,12 +1068,12 @@ int cx231xx_unmute_audio(struct cx231xx *dev) } EXPORT_SYMBOL_GPL(cx231xx_unmute_audio); -int stopAudioFirmware(struct cx231xx *dev) +static int stopAudioFirmware(struct cx231xx *dev) { return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x03); } -int restartAudioFirmware(struct cx231xx *dev) +static int restartAudioFirmware(struct cx231xx *dev) { return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x13); } @@ -2631,11 +2631,6 @@ int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type) rc = cx231xx_stop_stream(dev, ep_mask); } - if (dev->mode == CX231XX_ANALOG_MODE) - ;/* do any in Analog mode */ - else - ;/* do any in digital mode */ - return rc; } EXPORT_SYMBOL_GPL(cx231xx_capture_start); diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c index b84ebc54d91..bbed1e40eed 100644 --- a/drivers/media/usb/cx231xx/cx231xx-cards.c +++ b/drivers/media/usb/cx231xx/cx231xx-cards.c @@ -686,7 +686,7 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg) } EXPORT_SYMBOL_GPL(cx231xx_tuner_callback); -void cx231xx_reset_out(struct cx231xx *dev) +static void cx231xx_reset_out(struct cx231xx *dev) { cx231xx_set_gpio_value(dev, CX23417_RESET, 1); msleep(200); @@ -694,11 +694,13 @@ void cx231xx_reset_out(struct cx231xx *dev) msleep(200); cx231xx_set_gpio_value(dev, CX23417_RESET, 1); } -void cx231xx_enable_OSC(struct cx231xx *dev) + +static void cx231xx_enable_OSC(struct cx231xx *dev) { cx231xx_set_gpio_value(dev, CX23417_OSC_EN, 1); } -void cx231xx_sleep_s5h1432(struct cx231xx *dev) + +static void cx231xx_sleep_s5h1432(struct cx231xx *dev) { cx231xx_set_gpio_value(dev, SLEEP_S5H1432, 0); } diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c index 781feed406f..96a5a096539 100644 --- a/drivers/media/usb/cx231xx/cx231xx-i2c.c +++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c @@ -72,8 +72,8 @@ static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus, /* * cx231xx_i2c_send_bytes() */ -int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, - const struct i2c_msg *msg) +static int cx231xx_i2c_send_bytes(struct i2c_adapter *i2c_adap, + const struct i2c_msg *msg) { struct cx231xx_i2c *bus = i2c_adap->algo_data; struct cx231xx *dev = bus->dev; diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c index 96176e9db5a..0f7b4244682 100644 --- a/drivers/media/usb/cx231xx/cx231xx-input.c +++ b/drivers/media/usb/cx231xx/cx231xx-input.c @@ -99,7 +99,7 @@ int cx231xx_ir_init(struct cx231xx *dev) /* The i2c micro-controller only outputs the cmd part of NEC protocol */ dev->init_data.rc_dev->scanmask = 0xff; dev->init_data.rc_dev->driver_name = "cx231xx"; - dev->init_data.type = RC_TYPE_NEC; + dev->init_data.type = RC_BIT_NEC; info.addr = 0x30; /* Load and bind ir-kbd-i2c */ diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 3d7526e28d4..943d9342370 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1306,7 +1306,7 @@ static int af9015_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) if (!rc->map_name) rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; rc->query = af9015_rc_query; rc->interval = 500; diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index ea27eaff4e3..61ae7f9d0b2 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -1023,10 +1023,10 @@ static int af9035_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) switch (tmp) { case 0: /* NEC */ default: - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; break; case 1: /* RC6 */ - rc->allowed_protos = RC_TYPE_RC6; + rc->allowed_protos = RC_BIT_RC6_MCE; break; } diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c index ec540140c81..d05c5b563da 100644 --- a/drivers/media/usb/dvb-usb-v2/anysee.c +++ b/drivers/media/usb/dvb-usb-v2/anysee.c @@ -1048,7 +1048,7 @@ static int anysee_rc_query(struct dvb_usb_device *d) static int anysee_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; rc->query = anysee_rc_query; rc->interval = 250; /* windows driver uses 500ms */ @@ -1170,7 +1170,7 @@ static int anysee_ci_poll_slot_status(struct dvb_ca_en50221 *ci, int slot, struct dvb_usb_device *d = ci->data; struct anysee_state *state = d_to_priv(d); int ret; - u8 tmp; + u8 tmp = 0; ret = anysee_rd_reg_mask(d, REG_IOC, &tmp, 0x40); if (ret) diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c index 54f1221d930..d75dbf27e99 100644 --- a/drivers/media/usb/dvb-usb-v2/az6007.c +++ b/drivers/media/usb/dvb-usb-v2/az6007.c @@ -826,7 +826,7 @@ static int az6007_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { pr_debug("Getting az6007 Remote Control properties\n"); - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; rc->query = az6007_rc_query; rc->interval = 400; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h index bae16a1189d..059291b892b 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h @@ -137,7 +137,7 @@ struct dvb_usb_driver_info { struct dvb_usb_rc { const char *map_name; u64 allowed_protos; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); int (*query) (struct dvb_usb_device *d); unsigned int interval; const enum rc_driver_type driver_type; diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c index ba51f65204d..671b4fa232b 100644 --- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c +++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c @@ -224,7 +224,7 @@ static void dvb_usb_data_complete_raw(struct usb_data_stream *stream, u8 *buf, dvb_dmx_swfilter_raw(&adap->demux, buf, len); } -int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) +static int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) { dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, adap->id); @@ -236,7 +236,7 @@ int dvb_usbv2_adapter_stream_init(struct dvb_usb_adapter *adap) return usb_urb_initv2(&adap->stream, &adap->props->stream); } -int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) +static int dvb_usbv2_adapter_stream_exit(struct dvb_usb_adapter *adap) { dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, adap->id); @@ -368,7 +368,7 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) return dvb_usb_ctrl_feed(dvbdmxfeed, -1); } -int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) +static int dvb_usbv2_adapter_dvb_init(struct dvb_usb_adapter *adap) { int ret; struct dvb_usb_device *d = adap_to_d(adap); @@ -440,7 +440,7 @@ err_dvb_register_adapter: return ret; } -int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) +static int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) { dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, adap->id); @@ -456,7 +456,7 @@ int dvb_usbv2_adapter_dvb_exit(struct dvb_usb_adapter *adap) return 0; } -int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) +static int dvb_usbv2_device_power_ctrl(struct dvb_usb_device *d, int onoff) { int ret; @@ -553,7 +553,7 @@ err: return ret; } -int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) +static int dvb_usbv2_adapter_frontend_init(struct dvb_usb_adapter *adap) { int ret, i, count_registered = 0; struct dvb_usb_device *d = adap_to_d(adap); @@ -622,7 +622,7 @@ err: return ret; } -int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) +static int dvb_usbv2_adapter_frontend_exit(struct dvb_usb_adapter *adap) { int i; dev_dbg(&adap_to_d(adap)->udev->dev, "%s: adap=%d\n", __func__, diff --git a/drivers/media/usb/dvb-usb-v2/it913x.c b/drivers/media/usb/dvb-usb-v2/it913x.c index 695f9106bc5..47204280b8b 100644 --- a/drivers/media/usb/dvb-usb-v2/it913x.c +++ b/drivers/media/usb/dvb-usb-v2/it913x.c @@ -659,13 +659,19 @@ static int it913x_frontend_attach(struct dvb_usb_adapter *adap) it913x_wr_reg(d, DEV_0_DMOD, MP2IF2_SW_RST, 0x1); it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x0f); it913x_wr_reg(d, DEV_0, EP0_TX_NAK, 0x1b); - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f); + if (st->proprietary_ir == false) /* Enable endpoint 3 */ + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x3f); + else + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x2f); it913x_wr_reg(d, DEV_0, EP4_TX_LEN_LSB, ep_size & 0xff); it913x_wr_reg(d, DEV_0, EP4_TX_LEN_MSB, ep_size >> 8); ret = it913x_wr_reg(d, DEV_0, EP4_MAX_PKT, pkt_size); } else if (adap->id == 1 && adap->fe[0]) { - it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f); + if (st->proprietary_ir == false) + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x7f); + else + it913x_wr_reg(d, DEV_0, EP0_TX_EN, 0x6f); it913x_wr_reg(d, DEV_0, EP5_TX_LEN_LSB, ep_size & 0xff); it913x_wr_reg(d, DEV_0, EP5_TX_LEN_MSB, ep_size >> 8); @@ -698,7 +704,7 @@ static int it913x_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) return 0; } - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; rc->query = it913x_rc_query; rc->interval = 250; diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index c41d9d9ec7b..6427ac359f2 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -799,7 +799,7 @@ static const char fw_c_rs2000[] = LME2510_C_RS2000; static const char fw_lg[] = LME2510_LG; static const char fw_s0194[] = LME2510_S0194; -const char *lme_firmware_switch(struct dvb_usb_device *d, int cold) +static const char *lme_firmware_switch(struct dvb_usb_device *d, int cold) { struct lme2510_state *st = d->priv; struct usb_device *udev = d->udev; @@ -1253,7 +1253,7 @@ static int lme2510_get_stream_config(struct dvb_frontend *fe, u8 *ts_type, static int lme2510_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; return 0; } diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c index 093f1acce40..a4c302d0aa3 100644 --- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c +++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c @@ -1197,7 +1197,7 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; rc->query = rtl2831u_rc_query; rc->interval = 400; @@ -1269,7 +1269,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc) { rc->map_name = RC_MAP_EMPTY; - rc->allowed_protos = RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_NEC; rc->query = rtl2832u_rc_query; rc->interval = 400; @@ -1338,6 +1338,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = { &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK, &rtl2832u_props, "NOXON DAB/DAB+ USB dongle", NULL) }, + { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2, + &rtl2832u_props, "NOXON DAB/DAB+ USB dongle (rev 2)", NULL) }, { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0, &rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) }, { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101, diff --git a/drivers/media/usb/dvb-usb-v2/usb_urb.c b/drivers/media/usb/dvb-usb-v2/usb_urb.c index 5989b659037..7346f85f3f2 100644 --- a/drivers/media/usb/dvb-usb-v2/usb_urb.c +++ b/drivers/media/usb/dvb-usb-v2/usb_urb.c @@ -112,7 +112,7 @@ int usb_urb_submitv2(struct usb_data_stream *stream, return 0; } -int usb_urb_free_urbs(struct usb_data_stream *stream) +static int usb_urb_free_urbs(struct usb_data_stream *stream) { int i; @@ -205,7 +205,7 @@ static int usb_urb_alloc_isoc_urbs(struct usb_data_stream *stream) return 0; } -int usb_free_stream_buffers(struct usb_data_stream *stream) +static int usb_free_stream_buffers(struct usb_data_stream *stream) { if (stream->state & USB_STATE_URB_BUF) { while (stream->buf_num) { @@ -223,8 +223,8 @@ int usb_free_stream_buffers(struct usb_data_stream *stream) return 0; } -int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, - unsigned long size) +static int usb_alloc_stream_buffers(struct usb_data_stream *stream, int num, + unsigned long size) { stream->buf_num = 0; stream->buf_size = size; diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c index 5e45ae60542..91e0119e8a8 100644 --- a/drivers/media/usb/dvb-usb/az6027.c +++ b/drivers/media/usb/dvb-usb/az6027.c @@ -298,7 +298,8 @@ struct stb6100_config az6027_stb6100_config = { /* check for mutex FIXME */ -int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +static int az6027_usb_in_op(struct dvb_usb_device *d, u8 req, + u16 value, u16 index, u8 *b, int blen) { int ret = -1; if (mutex_lock_interruptible(&d->usb_mutex)) @@ -1051,10 +1052,10 @@ static struct i2c_algorithm az6027_i2c_algo = { .functionality = az6027_i2c_func, }; -int az6027_identify_state(struct usb_device *udev, - struct dvb_usb_device_properties *props, - struct dvb_usb_device_description **desc, - int *cold) +static int az6027_identify_state(struct usb_device *udev, + struct dvb_usb_device_properties *props, + struct dvb_usb_device_description **desc, + int *cold) { u8 *b; s16 ret; diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h index 7de125c0b36..637b6123f39 100644 --- a/drivers/media/usb/dvb-usb/dib0700.h +++ b/drivers/media/usb/dvb-usb/dib0700.h @@ -64,7 +64,7 @@ extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff); extern struct i2c_algorithm dib0700_i2c_algo; extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props, struct dvb_usb_device_description **desc, int *cold); -extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type); +extern int dib0700_change_protocol(struct rc_dev *dev, u64 *rc_type); extern int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz); extern int dib0700_device_count; diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index ef87229de6a..19b5ed2825d 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -605,7 +605,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return ret; } -int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) +int dib0700_change_protocol(struct rc_dev *rc, u64 *rc_type) { struct dvb_usb_device *d = rc->priv; struct dib0700_state *st = d->priv; @@ -621,17 +621,19 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) st->buf[2] = 0; /* Set the IR mode */ - if (rc_type == RC_TYPE_RC5) + if (*rc_type & RC_BIT_RC5) { new_proto = 1; - else if (rc_type == RC_TYPE_NEC) + *rc_type = RC_BIT_RC5; + } else if (*rc_type & RC_BIT_NEC) { new_proto = 0; - else if (rc_type == RC_TYPE_RC6) { + *rc_type = RC_BIT_NEC; + } else if (*rc_type & RC_BIT_RC6_MCE) { if (st->fw_version < 0x10200) { ret = -EINVAL; goto out; } - new_proto = 2; + *rc_type = RC_BIT_RC6_MCE; } else { ret = -EINVAL; goto out; @@ -645,7 +647,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type) goto out; } - d->props.rc.core.protocol = rc_type; + d->props.rc.core.protocol = *rc_type; out: mutex_unlock(&d->usb_mutex); @@ -707,7 +709,7 @@ static void dib0700_rc_urb_completion(struct urb *purb) purb->actual_length); switch (d->props.rc.core.protocol) { - case RC_TYPE_NEC: + case RC_BIT_NEC: toggle = 0; /* NEC protocol sends repeat code as 0 0 0 FF */ diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 510001da6e8..11798426fa8 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -518,7 +518,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d) d->last_event = 0; switch (d->props.rc.core.protocol) { - case RC_TYPE_NEC: + case RC_BIT_NEC: /* NEC protocol sends repeat code as 0 0 0 FF */ if ((key[3-2] == 0x00) && (key[3-3] == 0x00) && (key[3] == 0xff)) @@ -3658,9 +3658,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3698,9 +3698,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3763,9 +3763,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_interval = DEFAULT_RC_INTERVAL, .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3808,9 +3808,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3890,9 +3890,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3936,9 +3936,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -3987,9 +3987,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4055,9 +4055,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4106,9 +4106,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_NEC_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4177,9 +4177,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4215,9 +4215,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4295,9 +4295,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4341,9 +4341,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_NEC_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4394,9 +4394,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4433,9 +4433,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4472,9 +4472,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4511,9 +4511,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4550,9 +4550,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4589,9 +4589,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4644,9 +4644,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4681,9 +4681,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4721,9 +4721,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4761,9 +4761,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, @@ -4802,9 +4802,9 @@ struct dvb_usb_device_properties dib0700_devices[] = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, .module_name = "dib0700", .rc_query = dib0700_rc_query_old_firmware, - .allowed_protos = RC_TYPE_RC5 | - RC_TYPE_RC6 | - RC_TYPE_NEC, + .allowed_protos = RC_BIT_RC5 | + RC_BIT_RC6_MCE | + RC_BIT_NEC, .change_protocol = dib0700_change_protocol, }, }, diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index aab0f99bc89..ce4c4e3b58b 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -202,7 +202,7 @@ struct dvb_rc { u64 protocol; u64 allowed_protos; enum rc_driver_type driver_type; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); char *module_name; int (*rc_query) (struct dvb_usb_device *d); int rc_interval; diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c index 02e878577c3..d1ddfa13de8 100644 --- a/drivers/media/usb/dvb-usb/pctv452e.c +++ b/drivers/media/usb/dvb-usb/pctv452e.c @@ -927,7 +927,7 @@ static struct dvb_usb_device_properties pctv452e_properties = { .rc.core = { .rc_codes = RC_MAP_DIB0700_RC5_TABLE, - .allowed_protos = RC_TYPE_UNKNOWN, + .allowed_protos = RC_BIT_UNKNOWN, .rc_query = pctv452e_rc_query, .rc_interval = 100, }, @@ -980,7 +980,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = { .rc.core = { .rc_codes = RC_MAP_TT_1500, - .allowed_protos = RC_TYPE_UNKNOWN, + .allowed_protos = RC_BIT_UNKNOWN, .rc_query = pctv452e_rc_query, .rc_interval = 100, }, diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 7a8c8c18590..40832a1aef6 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -732,7 +732,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = { .rc_codes = RC_MAP_TECHNISAT_USB2, .module_name = "technisat-usb2", .rc_query = technisat_usb2_rc_query, - .allowed_protos = RC_TYPE_ALL, + .allowed_protos = RC_BIT_ALL, .driver_type = RC_DRIVER_IR_RAW, } }; diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c index 6a50cdea3bc..bcdac225ebe 100644 --- a/drivers/media/usb/dvb-usb/ttusb2.c +++ b/drivers/media/usb/dvb-usb/ttusb2.c @@ -741,7 +741,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = { .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */ .rc_codes = RC_MAP_TT_1500, .rc_query = tt3650_rc_query, - .allowed_protos = RC_TYPE_UNKNOWN, + .allowed_protos = RC_BIT_UNKNOWN, }, .num_adapters = 1, diff --git a/drivers/media/usb/dvb-usb/vp702x.c b/drivers/media/usb/dvb-usb/vp702x.c index 07c673a6e76..22cf9f96cb9 100644 --- a/drivers/media/usb/dvb-usb/vp702x.c +++ b/drivers/media/usb/dvb-usb/vp702x.c @@ -56,7 +56,7 @@ static int vp702x_usb_in_op_unlocked(struct dvb_usb_device *d, u8 req, } int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) + u16 index, u8 *b, int blen) { int ret; @@ -67,8 +67,8 @@ int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, return ret; } -int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value, - u16 index, u8 *b, int blen) +static int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, + u16 value, u16 index, u8 *b, int blen) { int ret; deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index); @@ -86,7 +86,7 @@ int vp702x_usb_out_op_unlocked(struct dvb_usb_device *d, u8 req, u16 value, return 0; } -int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, +static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) { int ret; diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 16a84f9f46d..619bffbab3b 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -1979,6 +1979,15 @@ struct em28xx_board em28xx_boards[] = { EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ, }, + [EM2884_BOARD_TERRATEC_HTC_USB_XS] = { + .name = "Terratec Cinergy HTC USB XS", + .has_dvb = 1, + .ir_codes = RC_MAP_NEC_TERRATEC_CINERGY_XS, + .tuner_type = TUNER_ABSENT, + .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT | + EM28XX_I2C_CLK_WAIT_ENABLE | + EM28XX_I2C_FREQ_400_KHZ, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); @@ -2057,9 +2066,9 @@ struct usb_device_id em28xx_id_table[] = { { USB_DEVICE(0x0ccd, 0x0043), .driver_info = EM2870_BOARD_TERRATEC_XS }, { USB_DEVICE(0x0ccd, 0x008e), /* Cinergy HTC USB XS Rev. 1 */ - .driver_info = EM2884_BOARD_TERRATEC_H5 }, + .driver_info = EM2884_BOARD_TERRATEC_HTC_USB_XS }, { USB_DEVICE(0x0ccd, 0x00ac), /* Cinergy HTC USB XS Rev. 2 */ - .driver_info = EM2884_BOARD_TERRATEC_H5 }, + .driver_info = EM2884_BOARD_TERRATEC_HTC_USB_XS }, { USB_DEVICE(0x0ccd, 0x10a2), /* H5 Rev. 1 */ .driver_info = EM2884_BOARD_TERRATEC_H5 }, { USB_DEVICE(0x0ccd, 0x10ad), /* H5 Rev. 2 */ @@ -3297,7 +3306,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->num_alt = interface->num_altsetting; - if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) + if ((unsigned)card[nr] < em28xx_bcount) dev->model = card[nr]; /* save our data pointer in this interface device */ diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 13ae821949e..63f2e7070c0 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -331,7 +331,7 @@ static struct drxk_config hauppauge_930c_drxk = { .load_firmware_sync = true, }; -struct drxk_config terratec_htc_stick_drxk = { +static struct drxk_config terratec_htc_stick_drxk = { .adr = 0x29, .single_master = 1, .no_i2c_bridge = 1, @@ -520,7 +520,10 @@ static void terratec_htc_stick_init(struct em28xx *dev) { -1, -1, -1, -1}, }; - /* Init the analog decoder? */ + /* + * Init the analog decoder (not yet supported), but + * it's probably still a good idea. + */ struct { unsigned char r[4]; int len; @@ -547,6 +550,64 @@ static void terratec_htc_stick_init(struct em28xx *dev) em28xx_gpio_set(dev, terratec_htc_stick_end); }; +static void terratec_htc_usb_xs_init(struct em28xx *dev) +{ + int i; + + struct em28xx_reg_seq terratec_htc_usb_xs_init[] = { + {EM28XX_R08_GPIO, 0xff, 0xff, 10}, + {EM2874_R80_GPIO, 0xb2, 0xff, 100}, + {EM2874_R80_GPIO, 0xb2, 0xff, 50}, + {EM2874_R80_GPIO, 0xb6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + struct em28xx_reg_seq terratec_htc_usb_xs_end[] = { + {EM2874_R80_GPIO, 0xa6, 0xff, 100}, + {EM2874_R80_GPIO, 0xa6, 0xff, 50}, + {EM2874_R80_GPIO, 0xe6, 0xff, 100}, + { -1, -1, -1, -1}, + }; + + /* + * Init the analog decoder (not yet supported), but + * it's probably still a good idea. + */ + struct { + unsigned char r[4]; + int len; + } regs[] = { + {{ 0x06, 0x02, 0x00, 0x31 }, 4}, + {{ 0x01, 0x02 }, 2}, + {{ 0x01, 0x02, 0x00, 0xc6 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0xff, 0xaf }, 4}, + {{ 0x01, 0x00, 0x03, 0xa0 }, 4}, + {{ 0x01, 0x00 }, 2}, + {{ 0x01, 0x00, 0x73, 0xaf }, 4}, + {{ 0x04, 0x00 }, 2}, + {{ 0x00, 0x04 }, 2}, + {{ 0x00, 0x04, 0x00, 0x0a }, 4}, + {{ 0x04, 0x14 }, 2}, + {{ 0x04, 0x14, 0x00, 0x00 }, 4}, + }; + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + + em28xx_gpio_set(dev, terratec_htc_usb_xs_init); + + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x40); + msleep(10); + em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, 0x44); + msleep(10); + + dev->i2c_client.addr = 0x82 >> 1; + + for (i = 0; i < ARRAY_SIZE(regs); i++) + i2c_master_send(&dev->i2c_client, regs[i].r, regs[i].len); + + em28xx_gpio_set(dev, terratec_htc_usb_xs_end); +}; + static void pctv_520e_init(struct em28xx *dev) { /* @@ -1155,6 +1216,25 @@ static int em28xx_dvb_init(struct em28xx *dev) goto out_free; } break; + case EM2884_BOARD_TERRATEC_HTC_USB_XS: + terratec_htc_usb_xs_init(dev); + + /* attach demodulator */ + dvb->fe[0] = dvb_attach(drxk_attach, &terratec_htc_stick_drxk, + &dev->i2c_adap); + if (!dvb->fe[0]) { + result = -EINVAL; + goto out_free; + } + + /* Attach the demodulator. */ + if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60, + &dev->i2c_adap, + &em28xx_cxd2820r_tda18271_config)) { + result = -EINVAL; + goto out_free; + } + break; default: em28xx_errdev("/2: The frontend of your DVB/ATSC card" " isn't supported yet\n"); diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 97d36b4f19d..660bf803c9e 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -345,7 +345,7 @@ static void em28xx_ir_stop(struct rc_dev *rc) cancel_delayed_work_sync(&ir->work); } -static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) +static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) { int rc = 0; struct em28xx_IR *ir = rc_dev->priv; @@ -354,14 +354,16 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type) /* Adjust xclk based o IR table for RC5/NEC tables */ - if (rc_type == RC_TYPE_RC5) { + if (*rc_type & RC_BIT_RC5) { dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE; ir->full_code = 1; - } else if (rc_type == RC_TYPE_NEC) { + *rc_type = RC_BIT_RC5; + } else if (*rc_type & RC_BIT_NEC) { dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE; ir_config = EM2874_IR_NEC; ir->full_code = 1; - } else if (rc_type != RC_TYPE_UNKNOWN) + *rc_type = RC_BIT_NEC; + } else if (*rc_type != RC_BIT_UNKNOWN) rc = -EINVAL; em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk, @@ -524,6 +526,7 @@ static int em28xx_ir_init(struct em28xx *dev) struct em28xx_IR *ir; struct rc_dev *rc; int err = -ENOMEM; + u64 rc_type; if (dev->board.ir_codes == NULL) { /* No remote control support */ @@ -546,14 +549,15 @@ static int em28xx_ir_init(struct em28xx *dev) * em2874 supports more protocols. For now, let's just announce * the two protocols that were already tested */ - rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; rc->priv = ir; rc->change_protocol = em28xx_ir_change_protocol; rc->open = em28xx_ir_start; rc->close = em28xx_ir_stop; /* By default, keep protocol field untouched */ - err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN); + rc_type = RC_BIT_UNKNOWN; + err = em28xx_ir_change_protocol(rc, &rc_type); if (err) goto err_out_free; diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 8757523e686..86e90d86da6 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -128,6 +128,7 @@ #define EM2874_BOARD_MAXMEDIA_UB425_TC 84 #define EM2884_BOARD_PCTV_510E 85 #define EM2884_BOARD_PCTV_520E 86 +#define EM2884_BOARD_TERRATEC_HTC_USB_XS 87 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index a2b934146eb..e0a431bb0d4 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -1586,8 +1586,7 @@ static int vidioc_querybuf(struct file *file, void *priv, struct gspca_dev *gspca_dev = video_drvdata(file); struct gspca_frame *frame; - if (v4l2_buf->index < 0 - || v4l2_buf->index >= gspca_dev->nframes) + if (v4l2_buf->index >= gspca_dev->nframes) return -EINVAL; frame = &gspca_dev->frame[v4l2_buf->index]; diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index e3eab82cd4e..352317d7acd 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -32,7 +32,7 @@ do { \ #define D_USBO 0x00 #define D_V4L2 0x0100 #else -#define PDEBUG(level, fmt, ...) +#define PDEBUG(level, fmt, ...) do {} while(0) #endif #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ diff --git a/drivers/media/usb/gspca/jeilinj.c b/drivers/media/usb/gspca/jeilinj.c index b897aa86f31..1ba29fe7fad 100644 --- a/drivers/media/usb/gspca/jeilinj.c +++ b/drivers/media/usb/gspca/jeilinj.c @@ -114,7 +114,7 @@ static void jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command) } /* Responses are one byte only */ -static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) +static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char *response) { int retval; @@ -123,7 +123,7 @@ static void jlj_read1(struct gspca_dev *gspca_dev, unsigned char response) retval = usb_bulk_msg(gspca_dev->dev, usb_rcvbulkpipe(gspca_dev->dev, 0x84), gspca_dev->usb_buf, 1, NULL, 500); - response = gspca_dev->usb_buf[0]; + *response = gspca_dev->usb_buf[0]; if (retval < 0) { pr_err("read command [%02x] error %d\n", gspca_dev->usb_buf[0], retval); @@ -260,7 +260,7 @@ static int jlj_start(struct gspca_dev *gspca_dev) if (start_commands[i].delay) msleep(start_commands[i].delay); if (start_commands[i].ack_wanted) - jlj_read1(gspca_dev, response); + jlj_read1(gspca_dev, &response); } setcamquality(gspca_dev, v4l2_ctrl_g_ctrl(sd->jpegqual)); msleep(2); diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c index cc8ec3f7e8d..c8e1572eb50 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k4aa.c @@ -74,6 +74,12 @@ static DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 2548") } }, { + .ident = "Fujitsu-Siemens Amilo Pi 2530", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 2530") + } + }, { .ident = "MSI GX700", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"), diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index 2d5c6d8343a..4f5869a9808 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -29,14 +29,13 @@ * Register page 0: * * Address Description - * 0x02 Red balance control - * 0x03 Green balance control - * 0x04 Blue balance control - * Valus are inverted (0=max, 255=min). + * 0x01 Red balance control + * 0x02 Green balance control + * 0x03 Blue balance control * The Windows driver uses a quadratic approach to map * the settable values (0-200) on register values: - * min=0x80, default=0x40, max=0x20 - * 0x0f-0x20 Colors, saturation and exposure control + * min=0x20, default=0x40, max=0x80 + * 0x0f-0x20 Color and saturation control * 0xa2-0xab Brightness, contrast and gamma control * 0xb6 Sharpness control (bits 0-4) * @@ -78,12 +77,12 @@ * * Page | Register | Function * -----+------------+--------------------------------------------------- + * 0 | 0x01 | setredbalance() + * 0 | 0x03 | setbluebalance() * 0 | 0x0f..0x20 | setcolors() * 0 | 0xa2..0xab | setbrightcont() * 0 | 0xb6 | setsharpness() - * 0 | 0xc5 | setredbalance() * 0 | 0xc6 | setwhitebalance() - * 0 | 0xc7 | setbluebalance() * 0 | 0xdc | setbrightcont(), setcolors() * 3 | 0x02 | setexposure() * 3 | 0x10, 0x12 | setgain() @@ -99,10 +98,13 @@ /* Include pac common sof detection functions */ #include "pac_common.h" -#define PAC7302_GAIN_DEFAULT 15 -#define PAC7302_GAIN_KNEE 42 -#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */ -#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ +#define PAC7302_RGB_BALANCE_MIN 0 +#define PAC7302_RGB_BALANCE_MAX 200 +#define PAC7302_RGB_BALANCE_DEFAULT 100 +#define PAC7302_GAIN_DEFAULT 15 +#define PAC7302_GAIN_KNEE 42 +#define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */ +#define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, " "Thomas Kaiser thomas@kaiser-linux.li"); @@ -439,12 +441,31 @@ static void setwhitebalance(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0xdc, 0x01); } +static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val) +{ + const unsigned int k = 1000; /* precision factor */ + unsigned int norm; + + /* Normed value [0...k] */ + norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN) + / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN); + /* Qudratic apporach improves control at small (register) values: */ + return 64 * norm * norm / (k*k) + 32 * norm / k + 32; + /* Y = 64*X*X + 32*X + 32 + * => register values 0x20-0x80; Windows driver uses these limits */ + + /* NOTE: for full value range (0x00-0xff) use + * Y = 254*X*X + X + * => 254 * norm * norm / (k*k) + 1 * norm / k */ +} + static void setredbalance(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc5, sd->red_balance->val); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0x01, + rgbbalance_ctrl_to_reg_value(sd->red_balance->val)); reg_w(gspca_dev, 0xdc, 0x01); } @@ -454,7 +475,8 @@ static void setbluebalance(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ - reg_w(gspca_dev, 0xc7, sd->blue_balance->val); + reg_w(gspca_dev, 0x03, + rgbbalance_ctrl_to_reg_value(sd->blue_balance->val)); reg_w(gspca_dev, 0xdc, 0x01); } @@ -643,9 +665,15 @@ static int sd_init_controls(struct gspca_dev *gspca_dev) V4L2_CID_WHITE_BALANCE_TEMPERATURE, 0, 255, 1, 55); sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, - V4L2_CID_RED_BALANCE, 0, 3, 1, 1); + V4L2_CID_RED_BALANCE, + PAC7302_RGB_BALANCE_MIN, + PAC7302_RGB_BALANCE_MAX, + 1, PAC7302_RGB_BALANCE_DEFAULT); sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, - V4L2_CID_BLUE_BALANCE, 0, 3, 1, 1); + V4L2_CID_BLUE_BALANCE, + PAC7302_RGB_BALANCE_MIN, + PAC7302_RGB_BALANCE_MAX, + 1, PAC7302_RGB_BALANCE_DEFAULT); gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_AUTOGAIN, 0, 1, 1, 1); diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index fd1f8d2d3b0..70511d5f953 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -1449,6 +1449,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, #endif + {USB_DEVICE(0x0c45, 0x6027), SB(OV7630, 101)}, /* Genius Eye 310 */ {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, {USB_DEVICE(0x0c45, 0x602a), SB(HV7131D, 102)}, diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index 304f43ef59e..84dc26fe80e 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -401,12 +401,14 @@ static int hdpvr_probe(struct usb_interface *interface, client = hdpvr_register_ir_rx_i2c(dev); if (!client) { v4l2_err(&dev->v4l2_dev, "i2c IR RX device register failed\n"); + retval = -ENODEV; goto reg_fail; } client = hdpvr_register_ir_tx_i2c(dev); if (!client) { v4l2_err(&dev->v4l2_dev, "i2c IR TX device register failed\n"); + retval = -ENODEV; goto reg_fail; } #endif diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index 82e819fa91c..031cf024304 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -55,7 +55,7 @@ struct i2c_client *hdpvr_register_ir_rx_i2c(struct hdpvr_device *dev) /* Our default information for ir-kbd-i2c.c to use */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; + init_data->type = RC_BIT_RC5; init_data->name = "HD-PVR"; init_data->polling_interval = 405; /* ms, duplicated from Windows */ hdpvr_ir_rx_i2c_board_info.platform_data = init_data; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index fb828ba1dbb..299751a8b06 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -3563,9 +3563,9 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw, enum pvr2_v4l_type index,int v) { switch (index) { - case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v; - case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v; - case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v; + case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;break; + case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;break; + case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;break; default: break; } } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 885ce11f222..9ab596c78a4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -581,7 +581,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP; - init_data->type = RC_TYPE_RC5; + init_data->type = RC_BIT_RC5; init_data->name = hdw->hdw_desc->description; init_data->polling_interval = 100; /* ms From ir-kbd-i2c */ /* IR Receiver */ @@ -596,7 +596,7 @@ static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw) case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */ init_data->ir_codes = RC_MAP_HAUPPAUGE; init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; + init_data->type = RC_BIT_RC5; init_data->name = hdw->hdw_desc->description; /* IR Receiver */ info.addr = 0x71; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index db249cad3cd..6930676051e 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -196,7 +196,7 @@ static int pvr2_g_std(struct file *file, void *priv, v4l2_std_id *std) return ret; } -int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std) +static int pvr2_s_std(struct file *file, void *priv, v4l2_std_id *std) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; @@ -365,7 +365,7 @@ static int pvr2_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt) vt->audmode); } -int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) +static int pvr2_s_frequency(struct file *file, void *priv, struct v4l2_frequency *vf) { struct pvr2_v4l2_fh *fh = file->private_data; struct pvr2_hdw *hdw = fh->channel.mc_head->hdw; diff --git a/drivers/media/usb/pwc/pwc-ctrl.c b/drivers/media/usb/pwc/pwc-ctrl.c index 1f506fde97d..3a1618580ed 100644 --- a/drivers/media/usb/pwc/pwc-ctrl.c +++ b/drivers/media/usb/pwc/pwc-ctrl.c @@ -179,6 +179,8 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt, return -EINVAL; if (frames < 4) frames = 4; + else if (size > PSZ_QCIF && frames > 15) + frames = 15; else if (frames > 25) frames = 25; frames = frames2frames[frames]; diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index 42e36bac4d7..5210239cbae 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -155,7 +155,7 @@ static struct video_device pwc_template = { /***************************************************************************/ /* Private functions */ -struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev) +static struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev) { unsigned long flags = 0; struct pwc_frame_buf *buf = NULL; @@ -1000,7 +1000,11 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); pdev->vb_queue.ops = &pwc_vb_queue_ops; pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; - vb2_queue_init(&pdev->vb_queue); + rc = vb2_queue_init(&pdev->vb_queue); + if (rc < 0) { + PWC_ERROR("Oops, could not initialize vb2 queue.\n"); + goto err_free_mem; + } /* Init video_device structure */ memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index 2191f6ddf9e..8ebec0d7bf5 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1651,7 +1651,7 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv, int is_ntsc = 0; #define NUM_FRAME_ENUMS 4 int frm_dec[NUM_FRAME_ENUMS] = {1, 2, 3, 5}; - if (fe->index < 0 || fe->index >= NUM_FRAME_ENUMS) + if (fe->index >= NUM_FRAME_ENUMS) return -EINVAL; switch (fe->width) { case 640: diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig index 3c76e62d820..5afbd9a4b55 100644 --- a/drivers/media/usb/siano/Kconfig +++ b/drivers/media/usb/siano/Kconfig @@ -4,7 +4,8 @@ config SMS_USB_DRV tristate "Siano SMS1xxx based MDTV receiver" - depends on DVB_CORE && RC_CORE && HAS_DMA + depends on DVB_CORE && HAS_DMA + select MEDIA_COMMON_OPTIONS ---help--- Choose if you would like to have Siano's support for USB interface diff --git a/drivers/media/usb/sn9c102/sn9c102_core.c b/drivers/media/usb/sn9c102/sn9c102_core.c index 5bfc8e2f018..73605864fff 100644 --- a/drivers/media/usb/sn9c102/sn9c102_core.c +++ b/drivers/media/usb/sn9c102/sn9c102_core.c @@ -2481,11 +2481,13 @@ sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg) if (frmsize.pixel_format != V4L2_PIX_FMT_SN9C10X && frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) return -EINVAL; + break; case BRIDGE_SN9C105: case BRIDGE_SN9C120: if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG && frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8) return -EINVAL; + break; } frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE; diff --git a/drivers/media/usb/stk1160/stk1160-i2c.c b/drivers/media/usb/stk1160/stk1160-i2c.c index 176ac937306..850cf285ada 100644 --- a/drivers/media/usb/stk1160/stk1160-i2c.c +++ b/drivers/media/usb/stk1160/stk1160-i2c.c @@ -116,7 +116,7 @@ static int stk1160_i2c_read_reg(struct stk1160 *dev, u8 addr, if (rc < 0) return rc; - stk1160_read_reg(dev, STK1160_SBUSR_RD, value); + rc = stk1160_read_reg(dev, STK1160_SBUSR_RD, value); if (rc < 0) return rc; diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 8bdfb027531..fa3671de02a 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -475,7 +475,11 @@ int stk1160_alloc_isoc(struct stk1160 *dev) if (!dev->isoc_ctl.transfer_buffer[i]) { stk1160_err("cannot alloc %d bytes for tx[%d] buffer\n", sb_size, i); - goto free_i_bufs; + + /* Not enough transfer buffers, so just give up */ + if (i < STK1160_MIN_BUFS) + goto free_i_bufs; + goto nomore_tx_bufs; } memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); @@ -506,13 +510,28 @@ int stk1160_alloc_isoc(struct stk1160 *dev) } } - stk1160_dbg("urbs allocated\n"); + stk1160_dbg("%d urbs allocated\n", num_bufs); /* At last we can say we have some buffers */ dev->isoc_ctl.num_bufs = num_bufs; return 0; +nomore_tx_bufs: + /* + * Failed to allocate desired buffer count. However, we may have + * enough to work fine, so we just free the extra urb, + * store the allocated count and keep going, fingers crossed! + */ + usb_free_urb(dev->isoc_ctl.urb[i]); + dev->isoc_ctl.urb[i] = NULL; + + stk1160_warn("%d urbs allocated. Trying to continue...\n", i - 1); + + dev->isoc_ctl.num_bufs = i - 1; + + return 0; + free_i_bufs: /* Save the allocated buffers so far, so we can properly free them */ dev->isoc_ctl.num_bufs = i+1; diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 68c8707d36a..05b05b160e1 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -30,11 +30,12 @@ #define STK1160_VERSION "0.9.5" #define STK1160_VERSION_NUM 0x000905 -/* TODO: Decide on number of packets for each buffer */ +/* Decide on number of packets for each buffer */ #define STK1160_NUM_PACKETS 64 /* Number of buffers for isoc transfers */ -#define STK1160_NUM_BUFS 16 /* TODO */ +#define STK1160_NUM_BUFS 16 +#define STK1160_MIN_BUFS 1 /* TODO: This endpoint address should be retrieved */ #define STK1160_EP_VIDEO 0x82 diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 86a0fc56c33..5d3c032d733 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -54,10 +54,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Jaime Velasco Juan <jsagarribay@gmail.com> and Nicolas VIVIEN"); MODULE_DESCRIPTION("Syntek DC1125 webcam driver"); - -/* bool for webcam LED management */ -int first_init = 1; - /* Some cameras have audio interfaces, we aren't interested in those */ static struct usb_device_id stkwebcam_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x174f, 0xa311, 0xff, 0xff, 0xff) }, @@ -554,6 +550,7 @@ static void stk_free_buffers(struct stk_camera *dev) static int v4l_stk_open(struct file *fp) { + static int first_init = 1; /* webcam LED management */ struct stk_camera *dev; struct video_device *vdev; diff --git a/drivers/media/usb/tlg2300/pd-dvb.c b/drivers/media/usb/tlg2300/pd-dvb.c index 30fcb117e89..ca4994a5190 100644 --- a/drivers/media/usb/tlg2300/pd-dvb.c +++ b/drivers/media/usb/tlg2300/pd-dvb.c @@ -1,6 +1,7 @@ #include "pd-common.h" #include <linux/kernel.h> #include <linux/usb.h> +#include <linux/time.h> #include <linux/dvb/dmx.h> #include <linux/delay.h> #include <linux/gfp.h> diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 1f448ac7a49..3082bfa9b2c 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -888,7 +888,7 @@ static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in) { struct front_face *front = fh; - if (in->index < 0 || in->index >= POSEIDON_INPUTS) + if (in->index >= POSEIDON_INPUTS) return -EINVAL; strcpy(in->name, pd_inputs[in->index].name); in->type = V4L2_INPUT_TYPE_TUNER; @@ -923,7 +923,7 @@ static int vidioc_s_input(struct file *file, void *fh, unsigned int i) struct poseidon *pd = front->pd; s32 ret, cmd_status; - if (i < 0 || i >= POSEIDON_INPUTS) + if (i >= POSEIDON_INPUTS) return -EINVAL; ret = send_set_req(pd, SGNL_SRC_SEL, pd_inputs[i].tlg_src, &cmd_status); diff --git a/drivers/media/usb/tm6000/tm6000-input.c b/drivers/media/usb/tm6000/tm6000-input.c index dffbd4bd47b..8a6bbf1d80e 100644 --- a/drivers/media/usb/tm6000/tm6000-input.c +++ b/drivers/media/usb/tm6000/tm6000-input.c @@ -109,12 +109,12 @@ static int tm6000_ir_config(struct tm6000_IR *ir) */ switch (ir->rc_type) { - case RC_TYPE_NEC: + case RC_BIT_NEC: leader = 900; /* ms */ pulse = 700; /* ms - the actual value would be 562 */ break; default: - case RC_TYPE_RC5: + case RC_BIT_RC5: leader = 900; /* ms - from the NEC decoding */ pulse = 1780; /* ms - The actual value would be 1776 */ break; @@ -122,12 +122,12 @@ static int tm6000_ir_config(struct tm6000_IR *ir) pulse = ir_clock_mhz * pulse; leader = ir_clock_mhz * leader; - if (ir->rc_type == RC_TYPE_NEC) + if (ir->rc_type == RC_BIT_NEC) leader = leader | 0x8000; dprintk(2, "%s: %s, %d MHz, leader = 0x%04x, pulse = 0x%06x \n", __func__, - (ir->rc_type == RC_TYPE_NEC) ? "NEC" : "RC-5", + (ir->rc_type == RC_BIT_NEC) ? "NEC" : "RC-5", ir_clock_mhz, leader, pulse); /* Remote WAKEUP = enable, normal mode, from IR decoder output */ @@ -297,7 +297,7 @@ static void tm6000_ir_stop(struct rc_dev *rc) cancel_delayed_work_sync(&ir->work); } -static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) +static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) { struct tm6000_IR *ir = rc->priv; @@ -306,10 +306,10 @@ static int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) dprintk(2, "%s\n",__func__); - if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) + if ((rc->rc_map.scan) && (*rc_type == RC_BIT_NEC)) ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); - ir->rc_type = rc_type; + ir->rc_type = *rc_type; tm6000_ir_config(ir); /* TODO */ @@ -398,6 +398,7 @@ int tm6000_ir_init(struct tm6000_core *dev) struct tm6000_IR *ir; struct rc_dev *rc; int err = -ENOMEM; + u64 rc_type; if (!enable_ir) return -ENODEV; @@ -421,7 +422,7 @@ int tm6000_ir_init(struct tm6000_core *dev) ir->rc = rc; /* input setup */ - rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC; /* Neded, in order to support NEC remotes with 24 or 32 bits */ rc->scanmask = 0xffff; rc->priv = ir; @@ -444,7 +445,8 @@ int tm6000_ir_init(struct tm6000_core *dev) usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN); + rc_type = RC_BIT_UNKNOWN; + tm6000_ir_change_protocol(rc, &rc_type); rc->input_name = ir->name; rc->input_phys = ir->phys; diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index 4342cd4f5c8..f656fd7a39a 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -1802,6 +1802,7 @@ int tm6000_v4l2_register(struct tm6000_core *dev) if (!dev->radio_dev) { printk(KERN_INFO "%s: can't register radio device\n", dev->name); + ret = -ENXIO; return ret; /* FIXME release resource */ } diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h index 43cf61fe494..8a25876d72c 100644 --- a/drivers/media/usb/usbvision/usbvision.h +++ b/drivers/media/usb/usbvision/usbvision.h @@ -167,7 +167,7 @@ enum { /* This macro restricts an int variable to an inclusive range */ #define RESTRICT_TO_RANGE(v, mi, ma) \ - { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } + { if (((int)v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); } /* * We use macros to do YUV -> RGB conversion because this is diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c index f7061a5ef1d..516a5b188ea 100644 --- a/drivers/media/usb/uvc/uvc_ctrl.c +++ b/drivers/media/usb/uvc/uvc_ctrl.c @@ -927,7 +927,7 @@ static int __uvc_ctrl_get(struct uvc_video_chain *chain, int ret; if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) - return -EINVAL; + return -EACCES; if (!ctrl->loaded) { ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id, @@ -1061,7 +1061,7 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain, ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping); if (ctrl == NULL) { - ret = -EINVAL; + ret = -ENOENT; goto done; } @@ -1099,12 +1099,13 @@ int uvc_query_v4l2_menu(struct uvc_video_chain *chain, return -ERESTARTSYS; ctrl = uvc_find_control(chain, query_menu->id, &mapping); - if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) { - ret = -EINVAL; + if (ctrl == NULL) { + ret = -ENOENT; goto done; } - if (query_menu->index >= mapping->menu_count) { + if (mapping->v4l2_type != V4L2_CTRL_TYPE_MENU || + query_menu->index >= mapping->menu_count) { ret = -EINVAL; goto done; } @@ -1263,7 +1264,7 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems) ctrl = uvc_find_control(handle->chain, sev->id, &mapping); if (ctrl == NULL) { - ret = -EINVAL; + ret = -ENOENT; goto done; } @@ -1414,7 +1415,7 @@ int uvc_ctrl_get(struct uvc_video_chain *chain, ctrl = uvc_find_control(chain, xctrl->id, &mapping); if (ctrl == NULL) - return -EINVAL; + return -ENOENT; return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value); } @@ -1431,8 +1432,10 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, int ret; ctrl = uvc_find_control(chain, xctrl->id, &mapping); - if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0) - return -EINVAL; + if (ctrl == NULL) + return -ENOENT; + if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR)) + return -EACCES; /* Clamp out of range values. */ switch (mapping->v4l2_type) { @@ -1452,8 +1455,12 @@ int uvc_ctrl_set(struct uvc_video_chain *chain, if (step == 0) step = 1; - xctrl->value = min + (xctrl->value - min + step/2) / step * step; - xctrl->value = clamp(xctrl->value, min, max); + xctrl->value = min + ((u32)(xctrl->value - min) + step / 2) + / step * step; + if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED) + xctrl->value = clamp(xctrl->value, min, max); + else + xctrl->value = clamp_t(u32, xctrl->value, min, max); value = xctrl->value; break; diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 5967081747c..5dbefa68b1d 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1562,6 +1562,9 @@ static int uvc_scan_device(struct uvc_device *dev) INIT_LIST_HEAD(&chain->entities); mutex_init(&chain->ctrl_mutex); chain->dev = dev; + v4l2_prio_init(&chain->prio); + + term->flags |= UVC_ENTITY_FLAG_DEFAULT; if (uvc_scan_chain(chain, term) < 0) { kfree(chain); @@ -1722,6 +1725,8 @@ static int uvc_register_video(struct uvc_device *dev, vdev->v4l2_dev = &dev->vdev; vdev->fops = &uvc_fops; vdev->release = uvc_release; + vdev->prio = &stream->chain->prio; + set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags); if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) vdev->vfl_dir = VFL_DIR_TX; strlcpy(vdev->name, dev->name, sizeof vdev->name); @@ -1741,6 +1746,11 @@ static int uvc_register_video(struct uvc_device *dev, return ret; } + if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + stream->chain->caps |= V4L2_CAP_VIDEO_CAPTURE; + else + stream->chain->caps |= V4L2_CAP_VIDEO_OUTPUT; + atomic_inc(&dev->nstreams); return 0; } diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index 29e239911d0..dc56a59ecad 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -93,6 +93,8 @@ static int uvc_mc_init_entity(struct uvc_entity *entity) } else if (entity->vdev != NULL) { ret = media_entity_init(&entity->vdev->entity, entity->num_pads, entity->pads, 0); + if (entity->flags & UVC_ENTITY_FLAG_DEFAULT) + entity->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; } else ret = 0; diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c index 18a91fae6bc..778addc5caf 100644 --- a/drivers/media/usb/uvc/uvc_queue.c +++ b/drivers/media/usb/uvc/uvc_queue.c @@ -128,7 +128,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type, int ret; queue->queue.type = type; - queue->queue.io_modes = VB2_MMAP | VB2_USERPTR; + queue->queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; queue->queue.drv_priv = queue; queue->queue.buf_struct_size = sizeof(struct uvc_buffer); queue->queue.ops = &uvc_queue_qops; diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index f00db3060e0..8e056046bc2 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -165,17 +165,18 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream, fcc[0], fcc[1], fcc[2], fcc[3], fmt->fmt.pix.width, fmt->fmt.pix.height); - /* Check if the hardware supports the requested format. */ + /* Check if the hardware supports the requested format, use the default + * format otherwise. + */ for (i = 0; i < stream->nformats; ++i) { format = &stream->format[i]; if (format->fcc == fmt->fmt.pix.pixelformat) break; } - if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) { - uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n", - fmt->fmt.pix.pixelformat); - return -EINVAL; + if (i == stream->nformats) { + format = stream->def_format; + fmt->fmt.pix.pixelformat = format->fcc; } /* Find the closest image size. The distance between image sizes is @@ -564,15 +565,30 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info)); cap->version = LINUX_VERSION_CODE; + cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING + | chain->caps; if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING; else - cap->capabilities = V4L2_CAP_VIDEO_OUTPUT - | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; break; } + /* Priority */ + case VIDIOC_G_PRIORITY: + *(u32 *)arg = v4l2_prio_max(vdev->prio); + break; + + case VIDIOC_S_PRIORITY: + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + + return v4l2_prio_change(vdev->prio, &handle->vfh.prio, + *(u32 *)arg); + /* Get, Set & Query control */ case VIDIOC_QUERYCTRL: return uvc_query_v4l2_ctrl(chain, arg); @@ -591,8 +607,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_get(chain, &xctrl); uvc_ctrl_rollback(handle); - if (ret >= 0) - ctrl->value = xctrl.value; + if (ret < 0) + return ret == -ENOENT ? -EINVAL : ret; + + ctrl->value = xctrl.value; break; } @@ -601,6 +619,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_control *ctrl = arg; struct v4l2_ext_control xctrl; + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + memset(&xctrl, 0, sizeof xctrl); xctrl.id = ctrl->id; xctrl.value = ctrl->value; @@ -612,7 +634,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_set(chain, &xctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - return ret; + return ret == -ENOENT ? -EINVAL : ret; } ret = uvc_ctrl_commit(handle, &xctrl, 1); if (ret == 0) @@ -637,8 +659,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_get(chain, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - ctrls->error_idx = i; - return ret; + ctrls->error_idx = ret == -ENOENT + ? ctrls->count : i; + return ret == -ENOENT ? -EINVAL : ret; } } ctrls->error_idx = 0; @@ -647,6 +670,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case VIDIOC_S_EXT_CTRLS: + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + /* Fall through */ case VIDIOC_TRY_EXT_CTRLS: { struct v4l2_ext_controls *ctrls = arg; @@ -661,8 +688,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) ret = uvc_ctrl_set(chain, ctrl); if (ret < 0) { uvc_ctrl_rollback(handle); - ctrls->error_idx = i; - return ret; + ctrls->error_idx = (ret == -ENOENT && + cmd == VIDIOC_S_EXT_CTRLS) + ? ctrls->count : i; + return ret == -ENOENT ? -EINVAL : ret; } } @@ -739,6 +768,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { u32 input = *(u32 *)arg + 1; + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; @@ -792,6 +825,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) } case VIDIOC_S_FMT: + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; @@ -894,6 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) return uvc_v4l2_get_streamparm(stream, arg); case VIDIOC_S_PARM: + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; @@ -924,10 +965,14 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_G_CROP: case VIDIOC_S_CROP: - return -EINVAL; + return -ENOTTY; /* Buffers & streaming */ case VIDIOC_REQBUFS: + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + if ((ret = uvc_acquire_privileges(handle)) < 0) return ret; @@ -973,6 +1018,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (*type != stream->type) return -EINVAL; + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + if (!uvc_has_privileges(handle)) return -EBUSY; @@ -991,6 +1040,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) if (*type != stream->type) return -EINVAL; + ret = v4l2_prio_check(vdev->prio, handle->vfh.prio); + if (ret < 0) + return ret; + if (!uvc_has_privileges(handle)) return -EBUSY; @@ -1030,7 +1083,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_ENUMOUTPUT: uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd); - return -EINVAL; + return -ENOTTY; case UVCIOC_CTRL_MAP: return uvc_ioctl_ctrl_map(chain, arg); diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c index 57c3076a462..3394c343201 100644 --- a/drivers/media/usb/uvc/uvc_video.c +++ b/drivers/media/usb/uvc/uvc_video.c @@ -1812,6 +1812,7 @@ int uvc_video_init(struct uvc_streaming *stream) probe->bFormatIndex = format->index; probe->bFrameIndex = frame->bFrameIndex; + stream->def_format = format; stream->cur_format = format; stream->cur_frame = frame; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index af216ec45e3..af505fdd9b3 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -225,10 +225,14 @@ struct uvc_format_desc { * always be accessed with the UVC_ENTITY_* macros and never directly. */ +#define UVC_ENTITY_FLAG_DEFAULT (1 << 0) + struct uvc_entity { struct list_head list; /* Entity as part of a UVC device. */ struct list_head chain; /* Entity as part of a video device * chain. */ + unsigned int flags; + __u8 id; __u16 type; char name[64]; @@ -371,6 +375,9 @@ struct uvc_video_chain { struct uvc_entity *selector; /* Selector unit */ struct mutex ctrl_mutex; /* Protects ctrl.info */ + + struct v4l2_prio_state prio; /* V4L2 priority state */ + u32 caps; /* V4L2 chain-wide caps */ }; struct uvc_stats_frame { @@ -436,6 +443,7 @@ struct uvc_streaming { struct uvc_format *format; struct uvc_streaming_control ctrl; + struct uvc_format *def_format; struct uvc_format *cur_format; struct uvc_frame *cur_frame; /* Protect access to ctrl, cur_format, cur_frame and hardware video diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 9afab35878b..39edd444293 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -1007,8 +1007,7 @@ static void read_pipe_completion(struct urb *purb) return; } - if (purb->actual_length < 0 || - purb->actual_length > pipe_info->transfer_size) { + if (purb->actual_length > pipe_info->transfer_size) { dev_err(&cam->udev->dev, "wrong number of bytes\n"); return; } diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 0c54e19d994..65875c3aba1 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -59,6 +59,7 @@ config VIDEOBUF_DVB # Used by drivers that need Videobuf2 modules config VIDEOBUF2_CORE + select DMA_SHARED_BUFFER tristate config VIDEOBUF2_MEMOPS @@ -68,11 +69,13 @@ config VIDEOBUF2_DMA_CONTIG tristate select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS + select DMA_SHARED_BUFFER config VIDEOBUF2_VMALLOC tristate select VIDEOBUF2_CORE select VIDEOBUF2_MEMOPS + select DMA_SHARED_BUFFER config VIDEOBUF2_DMA_SG tristate diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index f995dd31151..380ddd89fa4 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -837,7 +837,7 @@ bool v4l2_detect_gtf(unsigned frame_height, struct v4l2_dv_timings *fmt) { int pix_clk; - int v_fp, v_bp, h_fp, h_bp, hsync; + int v_fp, v_bp, h_fp, hsync; int frame_width, image_height, image_width; bool default_gtf; int h_blank; @@ -885,7 +885,6 @@ bool v4l2_detect_gtf(unsigned frame_height, hsync = hsync - hsync % GTF_CELL_GRAN; h_fp = h_blank / 2 - hsync; - h_bp = h_blank / 2; fmt->bt.polarities = polarities; fmt->bt.width = image_width; diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index 83ffb6436ba..7157af301b1 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -297,6 +297,7 @@ struct v4l2_plane32 { union { __u32 mem_offset; compat_long_t userptr; + __s32 fd; } m; __u32 data_offset; __u32 reserved[11]; @@ -318,6 +319,7 @@ struct v4l2_buffer32 { __u32 offset; compat_long_t userptr; compat_caddr_t planes; + __s32 fd; } m; __u32 length; __u32 reserved2; @@ -341,6 +343,9 @@ static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, up_pln = compat_ptr(p); if (put_user((unsigned long)up_pln, &up->m.userptr)) return -EFAULT; + } else if (memory == V4L2_MEMORY_DMABUF) { + if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(int))) + return -EFAULT; } else { if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset, sizeof(__u32))) @@ -364,6 +369,11 @@ static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32, if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset, sizeof(__u32))) return -EFAULT; + /* For DMABUF, driver might've set up the fd, so copy it back. */ + if (memory == V4L2_MEMORY_DMABUF) + if (copy_in_user(&up32->m.fd, &up->m.fd, + sizeof(int))) + return -EFAULT; return 0; } @@ -446,6 +456,10 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (get_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; + case V4L2_MEMORY_DMABUF: + if (get_user(kp->m.fd, &up->m.fd)) + return -EFAULT; + break; } } @@ -510,6 +524,10 @@ static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user if (put_user(kp->m.offset, &up->m.offset)) return -EFAULT; break; + case V4L2_MEMORY_DMABUF: + if (put_user(kp->m.fd, &up->m.fd)) + return -EFAULT; + break; } } @@ -1000,6 +1018,7 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg) case VIDIOC_S_FBUF32: case VIDIOC_OVERLAY32: case VIDIOC_QBUF32: + case VIDIOC_EXPBUF: case VIDIOC_DQBUF32: case VIDIOC_STREAMON32: case VIDIOC_STREAMOFF32: diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index a2df842e510..98dcad9c8a3 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -571,6 +571,7 @@ static void determine_valid_ioctls(struct video_device *vdev) SET_VALID_IOCTL(ops, VIDIOC_REQBUFS, vidioc_reqbufs); SET_VALID_IOCTL(ops, VIDIOC_QUERYBUF, vidioc_querybuf); SET_VALID_IOCTL(ops, VIDIOC_QBUF, vidioc_qbuf); + SET_VALID_IOCTL(ops, VIDIOC_EXPBUF, vidioc_expbuf); SET_VALID_IOCTL(ops, VIDIOC_DQBUF, vidioc_dqbuf); SET_VALID_IOCTL(ops, VIDIOC_STREAMON, vidioc_streamon); SET_VALID_IOCTL(ops, VIDIOC_STREAMOFF, vidioc_streamoff); diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 18a040b935a..c7200921815 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -5,7 +5,7 @@ * * Copyright (C) 2009--2010 Nokia Corporation. * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/v4l2-core/v4l2-fh.c b/drivers/media/v4l2-core/v4l2-fh.c index 9e3fc040ea2..e57c002b415 100644 --- a/drivers/media/v4l2-core/v4l2-fh.c +++ b/drivers/media/v4l2-core/v4l2-fh.c @@ -5,7 +5,7 @@ * * Copyright (C) 2009--2010 Nokia Corporation. * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 8f388ff31eb..aa6e7c788db 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -155,6 +155,7 @@ static const char *v4l2_memory_names[] = { [V4L2_MEMORY_MMAP] = "mmap", [V4L2_MEMORY_USERPTR] = "userptr", [V4L2_MEMORY_OVERLAY] = "overlay", + [V4L2_MEMORY_DMABUF] = "dmabuf", }; #define prt_names(a, arr) (((unsigned)(a)) < ARRAY_SIZE(arr) ? arr[a] : "unknown") @@ -453,6 +454,15 @@ static void v4l_print_buffer(const void *arg, bool write_only) tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); } +static void v4l_print_exportbuffer(const void *arg, bool write_only) +{ + const struct v4l2_exportbuffer *p = arg; + + pr_cont("fd=%d, type=%s, index=%u, plane=%u, flags=0x%08x\n", + p->fd, prt_names(p->type, v4l2_type_names), + p->index, p->plane, p->flags); +} + static void v4l_print_create_buffers(const void *arg, bool write_only) { const struct v4l2_create_buffers *p = arg; @@ -1960,6 +1970,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = { IOCTL_INFO_STD(VIDIOC_S_FBUF, vidioc_s_fbuf, v4l_print_framebuffer, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_OVERLAY, v4l_overlay, v4l_print_u32, INFO_FL_PRIO), IOCTL_INFO_FNC(VIDIOC_QBUF, v4l_qbuf, v4l_print_buffer, INFO_FL_QUEUE), + IOCTL_INFO_STD(VIDIOC_EXPBUF, vidioc_expbuf, v4l_print_exportbuffer, INFO_FL_QUEUE | INFO_FL_CLEAR(v4l2_exportbuffer, flags)), IOCTL_INFO_FNC(VIDIOC_DQBUF, v4l_dqbuf, v4l_print_buffer, INFO_FL_QUEUE), IOCTL_INFO_FNC(VIDIOC_STREAMON, v4l_streamon, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), IOCTL_INFO_FNC(VIDIOC_STREAMOFF, v4l_streamoff, v4l_print_buftype, INFO_FL_PRIO | INFO_FL_QUEUE), diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index 3ac83583ad7..438ea45d107 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -369,6 +369,19 @@ int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, EXPORT_SYMBOL_GPL(v4l2_m2m_dqbuf); /** + * v4l2_m2m_expbuf() - export a source or destination buffer, depending on + * the type + */ +int v4l2_m2m_expbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + struct v4l2_exportbuffer *eb) +{ + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(m2m_ctx, eb->type); + return vb2_expbuf(vq, eb); +} +EXPORT_SYMBOL_GPL(v4l2_m2m_expbuf); +/** * v4l2_m2m_streamon() - turn on streaming for a video queue */ int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, @@ -510,12 +523,10 @@ struct v4l2_m2m_dev *v4l2_m2m_init(struct v4l2_m2m_ops *m2m_ops) { struct v4l2_m2m_dev *m2m_dev; - if (!m2m_ops) + if (!m2m_ops || WARN_ON(!m2m_ops->device_run) || + WARN_ON(!m2m_ops->job_abort)) return ERR_PTR(-EINVAL); - BUG_ON(!m2m_ops->device_run); - BUG_ON(!m2m_ops->job_abort); - m2m_dev = kzalloc(sizeof *m2m_dev, GFP_KERNEL); if (!m2m_dev) return ERR_PTR(-ENOMEM); diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index dced41c1d99..996c248dea4 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -412,20 +412,20 @@ static int v4l2_subdev_link_validate_get_format(struct media_pad *pad, struct v4l2_subdev_format *fmt) { - switch (media_entity_type(pad->entity)) { - case MEDIA_ENT_T_V4L2_SUBDEV: + if (media_entity_type(pad->entity) == MEDIA_ENT_T_V4L2_SUBDEV) { + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(pad->entity); + fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE; fmt->pad = pad->index; - return v4l2_subdev_call(media_entity_to_v4l2_subdev( - pad->entity), - pad, get_fmt, NULL, fmt); - default: - WARN(1, "Driver bug! Wrong media entity type %d, entity %s\n", - media_entity_type(pad->entity), pad->entity->name); - /* Fall through */ - case MEDIA_ENT_T_DEVNODE_V4L: - return -EINVAL; + return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt); } + + WARN(pad->entity->type != MEDIA_ENT_T_DEVNODE_V4L, + "Driver bug! Wrong media entity type 0x%08x, entity %s\n", + pad->entity->type, pad->entity->name); + + return -EINVAL; } int v4l2_subdev_link_validate(struct media_link *link) diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index bf7a326b1cd..5449e8aa984 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -335,6 +335,9 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, case V4L2_MEMORY_OVERLAY: b->m.offset = vb->boff; break; + case V4L2_MEMORY_DMABUF: + /* DMABUF is not handled in videobuf framework */ + break; } b->flags = 0; @@ -405,6 +408,7 @@ int __videobuf_mmap_setup(struct videobuf_queue *q, break; case V4L2_MEMORY_USERPTR: case V4L2_MEMORY_OVERLAY: + case V4L2_MEMORY_DMABUF: /* nothing */ break; } diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 432df119af2..9f81be23a81 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -109,6 +109,36 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb) } /** + * __vb2_plane_dmabuf_put() - release memory associated with + * a DMABUF shared plane + */ +static void __vb2_plane_dmabuf_put(struct vb2_queue *q, struct vb2_plane *p) +{ + if (!p->mem_priv) + return; + + if (p->dbuf_mapped) + call_memop(q, unmap_dmabuf, p->mem_priv); + + call_memop(q, detach_dmabuf, p->mem_priv); + dma_buf_put(p->dbuf); + memset(p, 0, sizeof(*p)); +} + +/** + * __vb2_buf_dmabuf_put() - release memory associated with + * a DMABUF shared buffer + */ +static void __vb2_buf_dmabuf_put(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + unsigned int plane; + + for (plane = 0; plane < vb->num_planes; ++plane) + __vb2_plane_dmabuf_put(q, &vb->planes[plane]); +} + +/** * __setup_offsets() - setup unique offsets ("cookies") for every plane in * every buffer on the queue */ @@ -230,6 +260,8 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers) /* Free MMAP buffers or release USERPTR buffers */ if (q->memory == V4L2_MEMORY_MMAP) __vb2_buf_mem_free(vb); + else if (q->memory == V4L2_MEMORY_DMABUF) + __vb2_buf_dmabuf_put(vb); else __vb2_buf_userptr_put(vb); } @@ -362,6 +394,8 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b) b->m.offset = vb->v4l2_planes[0].m.mem_offset; else if (q->memory == V4L2_MEMORY_USERPTR) b->m.userptr = vb->v4l2_planes[0].m.userptr; + else if (q->memory == V4L2_MEMORY_DMABUF) + b->m.fd = vb->v4l2_planes[0].m.fd; } /* @@ -454,13 +488,28 @@ static int __verify_mmap_ops(struct vb2_queue *q) } /** + * __verify_dmabuf_ops() - verify that all memory operations required for + * DMABUF queue type have been provided + */ +static int __verify_dmabuf_ops(struct vb2_queue *q) +{ + if (!(q->io_modes & VB2_DMABUF) || !q->mem_ops->attach_dmabuf || + !q->mem_ops->detach_dmabuf || !q->mem_ops->map_dmabuf || + !q->mem_ops->unmap_dmabuf) + return -EINVAL; + + return 0; +} + +/** * __verify_memory_type() - Check whether the memory type and buffer type * passed to a buffer operation are compatible with the queue. */ static int __verify_memory_type(struct vb2_queue *q, enum v4l2_memory memory, enum v4l2_buf_type type) { - if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR) { + if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR && + memory != V4L2_MEMORY_DMABUF) { dprintk(1, "reqbufs: unsupported memory type\n"); return -EINVAL; } @@ -484,6 +533,11 @@ static int __verify_memory_type(struct vb2_queue *q, return -EINVAL; } + if (memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) { + dprintk(1, "reqbufs: DMABUF for current setup unsupported\n"); + return -EINVAL; + } + /* * Place the busy tests at the end: -EBUSY can be ignored when * create_bufs is called with count == 0, but count == 0 should still @@ -790,6 +844,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) { struct vb2_queue *q = vb->vb2_queue; unsigned long flags; + unsigned int plane; if (vb->state != VB2_BUF_STATE_ACTIVE) return; @@ -800,6 +855,10 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) dprintk(4, "Done processing on buffer %d, state: %d\n", vb->v4l2_buf.index, vb->state); + /* sync buffers */ + for (plane = 0; plane < vb->num_planes; ++plane) + call_memop(q, finish, vb->planes[plane].mem_priv); + /* Add the buffer to the done buffers list */ spin_lock_irqsave(&q->done_lock, flags); vb->state = state; @@ -845,6 +904,16 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b b->m.planes[plane].length; } } + if (b->memory == V4L2_MEMORY_DMABUF) { + for (plane = 0; plane < vb->num_planes; ++plane) { + v4l2_planes[plane].m.fd = + b->m.planes[plane].m.fd; + v4l2_planes[plane].length = + b->m.planes[plane].length; + v4l2_planes[plane].data_offset = + b->m.planes[plane].data_offset; + } + } } else { /* * Single-planar buffers do not use planes array, @@ -859,6 +928,13 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b v4l2_planes[0].m.userptr = b->m.userptr; v4l2_planes[0].length = b->length; } + + if (b->memory == V4L2_MEMORY_DMABUF) { + v4l2_planes[0].m.fd = b->m.fd; + v4l2_planes[0].length = b->length; + v4l2_planes[0].data_offset = 0; + } + } vb->v4l2_buf.field = b->field; @@ -959,14 +1035,121 @@ static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /** + * __qbuf_dmabuf() - handle qbuf of a DMABUF buffer + */ +static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b) +{ + struct v4l2_plane planes[VIDEO_MAX_PLANES]; + struct vb2_queue *q = vb->vb2_queue; + void *mem_priv; + unsigned int plane; + int ret; + int write = !V4L2_TYPE_IS_OUTPUT(q->type); + + /* Verify and copy relevant information provided by the userspace */ + __fill_vb2_buffer(vb, b, planes); + + for (plane = 0; plane < vb->num_planes; ++plane) { + struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd); + + if (IS_ERR_OR_NULL(dbuf)) { + dprintk(1, "qbuf: invalid dmabuf fd for plane %d\n", + plane); + ret = -EINVAL; + goto err; + } + + /* use DMABUF size if length is not provided */ + if (planes[plane].length == 0) + planes[plane].length = dbuf->size; + + if (planes[plane].length < planes[plane].data_offset + + q->plane_sizes[plane]) { + ret = -EINVAL; + goto err; + } + + /* Skip the plane if already verified */ + if (dbuf == vb->planes[plane].dbuf && + vb->v4l2_planes[plane].length == planes[plane].length) { + dma_buf_put(dbuf); + continue; + } + + dprintk(1, "qbuf: buffer for plane %d changed\n", plane); + + /* Release previously acquired memory if present */ + __vb2_plane_dmabuf_put(q, &vb->planes[plane]); + memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane)); + + /* Acquire each plane's memory */ + mem_priv = call_memop(q, attach_dmabuf, q->alloc_ctx[plane], + dbuf, planes[plane].length, write); + if (IS_ERR(mem_priv)) { + dprintk(1, "qbuf: failed to attach dmabuf\n"); + ret = PTR_ERR(mem_priv); + dma_buf_put(dbuf); + goto err; + } + + vb->planes[plane].dbuf = dbuf; + vb->planes[plane].mem_priv = mem_priv; + } + + /* TODO: This pins the buffer(s) with dma_buf_map_attachment()).. but + * really we want to do this just before the DMA, not while queueing + * the buffer(s).. + */ + for (plane = 0; plane < vb->num_planes; ++plane) { + ret = call_memop(q, map_dmabuf, vb->planes[plane].mem_priv); + if (ret) { + dprintk(1, "qbuf: failed to map dmabuf for plane %d\n", + plane); + goto err; + } + vb->planes[plane].dbuf_mapped = 1; + } + + /* + * Call driver-specific initialization on the newly acquired buffer, + * if provided. + */ + ret = call_qop(q, buf_init, vb); + if (ret) { + dprintk(1, "qbuf: buffer initialization failed\n"); + goto err; + } + + /* + * Now that everything is in order, copy relevant information + * provided by userspace. + */ + for (plane = 0; plane < vb->num_planes; ++plane) + vb->v4l2_planes[plane] = planes[plane]; + + return 0; +err: + /* In case of errors, release planes that were already acquired */ + __vb2_buf_dmabuf_put(vb); + + return ret; +} + +/** * __enqueue_in_driver() - enqueue a vb2_buffer in driver for processing */ static void __enqueue_in_driver(struct vb2_buffer *vb) { struct vb2_queue *q = vb->vb2_queue; + unsigned int plane; vb->state = VB2_BUF_STATE_ACTIVE; atomic_inc(&q->queued_count); + + /* sync buffers */ + for (plane = 0; plane < vb->num_planes; ++plane) + call_memop(q, prepare, vb->planes[plane].mem_priv); + q->ops->buf_queue(vb); } @@ -982,6 +1165,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b) case V4L2_MEMORY_USERPTR: ret = __qbuf_userptr(vb, b); break; + case V4L2_MEMORY_DMABUF: + ret = __qbuf_dmabuf(vb, b); + break; default: WARN(1, "Invalid queue type\n"); ret = -EINVAL; @@ -1303,6 +1489,30 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q) EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers); /** + * __vb2_dqbuf() - bring back the buffer to the DEQUEUED state + */ +static void __vb2_dqbuf(struct vb2_buffer *vb) +{ + struct vb2_queue *q = vb->vb2_queue; + unsigned int i; + + /* nothing to do if the buffer is already dequeued */ + if (vb->state == VB2_BUF_STATE_DEQUEUED) + return; + + vb->state = VB2_BUF_STATE_DEQUEUED; + + /* unmap DMABUF buffer */ + if (q->memory == V4L2_MEMORY_DMABUF) + for (i = 0; i < vb->num_planes; ++i) { + if (!vb->planes[i].dbuf_mapped) + continue; + call_memop(q, unmap_dmabuf, vb->planes[i].mem_priv); + vb->planes[i].dbuf_mapped = 0; + } +} + +/** * vb2_dqbuf() - Dequeue a buffer to the userspace * @q: videobuf2 queue * @b: buffer structure passed from userspace to vidioc_dqbuf handler @@ -1363,11 +1573,12 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking) __fill_v4l2_buffer(vb, b); /* Remove from videobuf queue */ list_del(&vb->queued_entry); + /* go back to dequeued state */ + __vb2_dqbuf(vb); dprintk(1, "dqbuf of buffer %d, with state %d\n", vb->v4l2_buf.index, vb->state); - vb->state = VB2_BUF_STATE_DEQUEUED; return 0; } EXPORT_SYMBOL_GPL(vb2_dqbuf); @@ -1406,7 +1617,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q) * Reinitialize all buffers for next use. */ for (i = 0; i < q->num_buffers; ++i) - q->bufs[i]->state = VB2_BUF_STATE_DEQUEUED; + __vb2_dqbuf(q->bufs[i]); } /** @@ -1540,6 +1751,79 @@ static int __find_plane_by_offset(struct vb2_queue *q, unsigned long off, } /** + * vb2_expbuf() - Export a buffer as a file descriptor + * @q: videobuf2 queue + * @eb: export buffer structure passed from userspace to vidioc_expbuf + * handler in driver + * + * The return values from this function are intended to be directly returned + * from vidioc_expbuf handler in driver. + */ +int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb) +{ + struct vb2_buffer *vb = NULL; + struct vb2_plane *vb_plane; + int ret; + struct dma_buf *dbuf; + + if (q->memory != V4L2_MEMORY_MMAP) { + dprintk(1, "Queue is not currently set up for mmap\n"); + return -EINVAL; + } + + if (!q->mem_ops->get_dmabuf) { + dprintk(1, "Queue does not support DMA buffer exporting\n"); + return -EINVAL; + } + + if (eb->flags & ~O_CLOEXEC) { + dprintk(1, "Queue does support only O_CLOEXEC flag\n"); + return -EINVAL; + } + + if (eb->type != q->type) { + dprintk(1, "qbuf: invalid buffer type\n"); + return -EINVAL; + } + + if (eb->index >= q->num_buffers) { + dprintk(1, "buffer index out of range\n"); + return -EINVAL; + } + + vb = q->bufs[eb->index]; + + if (eb->plane >= vb->num_planes) { + dprintk(1, "buffer plane out of range\n"); + return -EINVAL; + } + + vb_plane = &vb->planes[eb->plane]; + + dbuf = call_memop(q, get_dmabuf, vb_plane->mem_priv); + if (IS_ERR_OR_NULL(dbuf)) { + dprintk(1, "Failed to export buffer %d, plane %d\n", + eb->index, eb->plane); + return -EINVAL; + } + + ret = dma_buf_fd(dbuf, eb->flags); + if (ret < 0) { + dprintk(3, "buffer %d, plane %d failed to export (%d)\n", + eb->index, eb->plane, ret); + dma_buf_put(dbuf); + return ret; + } + + dprintk(3, "buffer %d, plane %d exported as %d descriptor\n", + eb->index, eb->plane, ret); + eb->fd = ret; + + return 0; +} +EXPORT_SYMBOL_GPL(vb2_expbuf); + +/** * vb2_mmap() - map video buffers into application address space * @q: videobuf2 queue * @vma: vma passed to the mmap file operation handler in the driver @@ -2245,6 +2529,16 @@ int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) } EXPORT_SYMBOL_GPL(vb2_ioctl_streamoff); +int vb2_ioctl_expbuf(struct file *file, void *priv, struct v4l2_exportbuffer *p) +{ + struct video_device *vdev = video_devdata(file); + + if (vb2_queue_is_busy(vdev, file)) + return -EBUSY; + return vb2_expbuf(vdev->queue, p); +} +EXPORT_SYMBOL_GPL(vb2_ioctl_expbuf); + /* v4l2_file_operations helpers */ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma) diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c index 4b7132660a9..10beaee7f0a 100644 --- a/drivers/media/v4l2-core/videobuf2-dma-contig.c +++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c @@ -10,7 +10,10 @@ * the Free Software Foundation. */ +#include <linux/dma-buf.h> #include <linux/module.h> +#include <linux/scatterlist.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/dma-mapping.h> @@ -23,40 +26,158 @@ struct vb2_dc_conf { }; struct vb2_dc_buf { - struct vb2_dc_conf *conf; + struct device *dev; void *vaddr; - dma_addr_t dma_addr; unsigned long size; - struct vm_area_struct *vma; - atomic_t refcount; + dma_addr_t dma_addr; + enum dma_data_direction dma_dir; + struct sg_table *dma_sgt; + + /* MMAP related */ struct vb2_vmarea_handler handler; + atomic_t refcount; + struct sg_table *sgt_base; + + /* USERPTR related */ + struct vm_area_struct *vma; + + /* DMABUF related */ + struct dma_buf_attachment *db_attach; }; -static void vb2_dma_contig_put(void *buf_priv); +/*********************************************/ +/* scatterlist table functions */ +/*********************************************/ + + +static void vb2_dc_sgt_foreach_page(struct sg_table *sgt, + void (*cb)(struct page *pg)) +{ + struct scatterlist *s; + unsigned int i; + + for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { + struct page *page = sg_page(s); + unsigned int n_pages = PAGE_ALIGN(s->offset + s->length) + >> PAGE_SHIFT; + unsigned int j; + + for (j = 0; j < n_pages; ++j, ++page) + cb(page); + } +} + +static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt) +{ + struct scatterlist *s; + dma_addr_t expected = sg_dma_address(sgt->sgl); + unsigned int i; + unsigned long size = 0; + + for_each_sg(sgt->sgl, s, sgt->nents, i) { + if (sg_dma_address(s) != expected) + break; + expected = sg_dma_address(s) + sg_dma_len(s); + size += sg_dma_len(s); + } + return size; +} + +/*********************************************/ +/* callbacks for all buffers */ +/*********************************************/ + +static void *vb2_dc_cookie(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return &buf->dma_addr; +} + +static void *vb2_dc_vaddr(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return buf->vaddr; +} + +static unsigned int vb2_dc_num_users(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + return atomic_read(&buf->refcount); +} + +static void vb2_dc_prepare(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + struct sg_table *sgt = buf->dma_sgt; + + /* DMABUF exporter will flush the cache for us */ + if (!sgt || buf->db_attach) + return; + + dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); +} + +static void vb2_dc_finish(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + struct sg_table *sgt = buf->dma_sgt; + + /* DMABUF exporter will flush the cache for us */ + if (!sgt || buf->db_attach) + return; + + dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir); +} + +/*********************************************/ +/* callbacks for MMAP buffers */ +/*********************************************/ + +static void vb2_dc_put(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + + if (!atomic_dec_and_test(&buf->refcount)) + return; + + if (buf->sgt_base) { + sg_free_table(buf->sgt_base); + kfree(buf->sgt_base); + } + dma_free_coherent(buf->dev, buf->size, buf->vaddr, buf->dma_addr); + put_device(buf->dev); + kfree(buf); +} -static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) +static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size) { struct vb2_dc_conf *conf = alloc_ctx; + struct device *dev = conf->dev; struct vb2_dc_buf *buf; buf = kzalloc(sizeof *buf, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); - buf->vaddr = dma_alloc_coherent(conf->dev, size, &buf->dma_addr, - GFP_KERNEL); + /* align image size to PAGE_SIZE */ + size = PAGE_ALIGN(size); + + buf->vaddr = dma_alloc_coherent(dev, size, &buf->dma_addr, GFP_KERNEL); if (!buf->vaddr) { - dev_err(conf->dev, "dma_alloc_coherent of size %ld failed\n", - size); + dev_err(dev, "dma_alloc_coherent of size %ld failed\n", size); kfree(buf); return ERR_PTR(-ENOMEM); } - buf->conf = conf; + /* Prevent the device from being released while the buffer is used */ + buf->dev = get_device(dev); buf->size = size; buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_dma_contig_put; + buf->handler.put = vb2_dc_put; buf->handler.arg = buf; atomic_inc(&buf->refcount); @@ -64,100 +185,569 @@ static void *vb2_dma_contig_alloc(void *alloc_ctx, unsigned long size) return buf; } -static void vb2_dma_contig_put(void *buf_priv) +static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma) { struct vb2_dc_buf *buf = buf_priv; + int ret; - if (atomic_dec_and_test(&buf->refcount)) { - dma_free_coherent(buf->conf->dev, buf->size, buf->vaddr, - buf->dma_addr); - kfree(buf); + if (!buf) { + printk(KERN_ERR "No buffer to map\n"); + return -EINVAL; + } + + /* + * dma_mmap_* uses vm_pgoff as in-buffer offset, but we want to + * map whole buffer + */ + vma->vm_pgoff = 0; + + ret = dma_mmap_coherent(buf->dev, vma, buf->vaddr, + buf->dma_addr, buf->size); + + if (ret) { + pr_err("Remapping memory failed, error: %d\n", ret); + return ret; } + + vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; + vma->vm_private_data = &buf->handler; + vma->vm_ops = &vb2_common_vm_ops; + + vma->vm_ops->open(vma); + + pr_debug("%s: mapped dma addr 0x%08lx at 0x%08lx, size %ld\n", + __func__, (unsigned long)buf->dma_addr, vma->vm_start, + buf->size); + + return 0; } -static void *vb2_dma_contig_cookie(void *buf_priv) +/*********************************************/ +/* DMABUF ops for exporters */ +/*********************************************/ + +struct vb2_dc_attachment { + struct sg_table sgt; + enum dma_data_direction dir; +}; + +static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev, + struct dma_buf_attachment *dbuf_attach) { - struct vb2_dc_buf *buf = buf_priv; + struct vb2_dc_attachment *attach; + unsigned int i; + struct scatterlist *rd, *wr; + struct sg_table *sgt; + struct vb2_dc_buf *buf = dbuf->priv; + int ret; - return &buf->dma_addr; + attach = kzalloc(sizeof(*attach), GFP_KERNEL); + if (!attach) + return -ENOMEM; + + sgt = &attach->sgt; + /* Copy the buf->base_sgt scatter list to the attachment, as we can't + * map the same scatter list to multiple attachments at the same time. + */ + ret = sg_alloc_table(sgt, buf->sgt_base->orig_nents, GFP_KERNEL); + if (ret) { + kfree(attach); + return -ENOMEM; + } + + rd = buf->sgt_base->sgl; + wr = sgt->sgl; + for (i = 0; i < sgt->orig_nents; ++i) { + sg_set_page(wr, sg_page(rd), rd->length, rd->offset); + rd = sg_next(rd); + wr = sg_next(wr); + } + + attach->dir = DMA_NONE; + dbuf_attach->priv = attach; + + return 0; } -static void *vb2_dma_contig_vaddr(void *buf_priv) +static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf, + struct dma_buf_attachment *db_attach) { - struct vb2_dc_buf *buf = buf_priv; - if (!buf) - return NULL; + struct vb2_dc_attachment *attach = db_attach->priv; + struct sg_table *sgt; + + if (!attach) + return; + + sgt = &attach->sgt; + + /* release the scatterlist cache */ + if (attach->dir != DMA_NONE) + dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dir); + sg_free_table(sgt); + kfree(attach); + db_attach->priv = NULL; +} + +static struct sg_table *vb2_dc_dmabuf_ops_map( + struct dma_buf_attachment *db_attach, enum dma_data_direction dir) +{ + struct vb2_dc_attachment *attach = db_attach->priv; + /* stealing dmabuf mutex to serialize map/unmap operations */ + struct mutex *lock = &db_attach->dmabuf->lock; + struct sg_table *sgt; + int ret; + + mutex_lock(lock); + + sgt = &attach->sgt; + /* return previously mapped sg table */ + if (attach->dir == dir) { + mutex_unlock(lock); + return sgt; + } + + /* release any previous cache */ + if (attach->dir != DMA_NONE) { + dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, + attach->dir); + attach->dir = DMA_NONE; + } + + /* mapping to the client with new direction */ + ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dir); + if (ret <= 0) { + pr_err("failed to map scatterlist\n"); + mutex_unlock(lock); + return ERR_PTR(-EIO); + } + + attach->dir = dir; + + mutex_unlock(lock); + + return sgt; +} + +static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach, + struct sg_table *sgt, enum dma_data_direction dir) +{ + /* nothing to be done here */ +} + +static void vb2_dc_dmabuf_ops_release(struct dma_buf *dbuf) +{ + /* drop reference obtained in vb2_dc_get_dmabuf */ + vb2_dc_put(dbuf->priv); +} + +static void *vb2_dc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum) +{ + struct vb2_dc_buf *buf = dbuf->priv; + + return buf->vaddr + pgnum * PAGE_SIZE; +} + +static void *vb2_dc_dmabuf_ops_vmap(struct dma_buf *dbuf) +{ + struct vb2_dc_buf *buf = dbuf->priv; return buf->vaddr; } -static unsigned int vb2_dma_contig_num_users(void *buf_priv) +static int vb2_dc_dmabuf_ops_mmap(struct dma_buf *dbuf, + struct vm_area_struct *vma) { - struct vb2_dc_buf *buf = buf_priv; + return vb2_dc_mmap(dbuf->priv, vma); +} - return atomic_read(&buf->refcount); +static struct dma_buf_ops vb2_dc_dmabuf_ops = { + .attach = vb2_dc_dmabuf_ops_attach, + .detach = vb2_dc_dmabuf_ops_detach, + .map_dma_buf = vb2_dc_dmabuf_ops_map, + .unmap_dma_buf = vb2_dc_dmabuf_ops_unmap, + .kmap = vb2_dc_dmabuf_ops_kmap, + .kmap_atomic = vb2_dc_dmabuf_ops_kmap, + .vmap = vb2_dc_dmabuf_ops_vmap, + .mmap = vb2_dc_dmabuf_ops_mmap, + .release = vb2_dc_dmabuf_ops_release, +}; + +static struct sg_table *vb2_dc_get_base_sgt(struct vb2_dc_buf *buf) +{ + int ret; + struct sg_table *sgt; + + sgt = kmalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) { + dev_err(buf->dev, "failed to alloc sg table\n"); + return NULL; + } + + ret = dma_get_sgtable(buf->dev, sgt, buf->vaddr, buf->dma_addr, + buf->size); + if (ret < 0) { + dev_err(buf->dev, "failed to get scatterlist from DMA API\n"); + kfree(sgt); + return NULL; + } + + return sgt; } -static int vb2_dma_contig_mmap(void *buf_priv, struct vm_area_struct *vma) +static struct dma_buf *vb2_dc_get_dmabuf(void *buf_priv) { struct vb2_dc_buf *buf = buf_priv; + struct dma_buf *dbuf; - if (!buf) { - printk(KERN_ERR "No buffer to map\n"); - return -EINVAL; + if (!buf->sgt_base) + buf->sgt_base = vb2_dc_get_base_sgt(buf); + + if (WARN_ON(!buf->sgt_base)) + return NULL; + + dbuf = dma_buf_export(buf, &vb2_dc_dmabuf_ops, buf->size, 0); + if (IS_ERR(dbuf)) + return NULL; + + /* dmabuf keeps reference to vb2 buffer */ + atomic_inc(&buf->refcount); + + return dbuf; +} + +/*********************************************/ +/* callbacks for USERPTR buffers */ +/*********************************************/ + +static inline int vma_is_io(struct vm_area_struct *vma) +{ + return !!(vma->vm_flags & (VM_IO | VM_PFNMAP)); +} + +static int vb2_dc_get_user_pages(unsigned long start, struct page **pages, + int n_pages, struct vm_area_struct *vma, int write) +{ + if (vma_is_io(vma)) { + unsigned int i; + + for (i = 0; i < n_pages; ++i, start += PAGE_SIZE) { + unsigned long pfn; + int ret = follow_pfn(vma, start, &pfn); + + if (ret) { + pr_err("no page for address %lu\n", start); + return ret; + } + pages[i] = pfn_to_page(pfn); + } + } else { + int n; + + n = get_user_pages(current, current->mm, start & PAGE_MASK, + n_pages, write, 1, pages, NULL); + /* negative error means that no page was pinned */ + n = max(n, 0); + if (n != n_pages) { + pr_err("got only %d of %d user pages\n", n, n_pages); + while (n) + put_page(pages[--n]); + return -EFAULT; + } } - return vb2_mmap_pfn_range(vma, buf->dma_addr, buf->size, - &vb2_common_vm_ops, &buf->handler); + return 0; } -static void *vb2_dma_contig_get_userptr(void *alloc_ctx, unsigned long vaddr, - unsigned long size, int write) +static void vb2_dc_put_dirty_page(struct page *page) { + set_page_dirty_lock(page); + put_page(page); +} + +static void vb2_dc_put_userptr(void *buf_priv) +{ + struct vb2_dc_buf *buf = buf_priv; + struct sg_table *sgt = buf->dma_sgt; + + dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); + if (!vma_is_io(buf->vma)) + vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page); + + sg_free_table(sgt); + kfree(sgt); + vb2_put_vma(buf->vma); + kfree(buf); +} + +static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr, + unsigned long size, int write) +{ + struct vb2_dc_conf *conf = alloc_ctx; struct vb2_dc_buf *buf; + unsigned long start; + unsigned long end; + unsigned long offset; + struct page **pages; + int n_pages; + int ret = 0; struct vm_area_struct *vma; - dma_addr_t dma_addr = 0; - int ret; + struct sg_table *sgt; + unsigned long contig_size; + unsigned long dma_align = dma_get_cache_alignment(); + + /* Only cache aligned DMA transfers are reliable */ + if (!IS_ALIGNED(vaddr | size, dma_align)) { + pr_debug("user data must be aligned to %lu bytes\n", dma_align); + return ERR_PTR(-EINVAL); + } + + if (!size) { + pr_debug("size is zero\n"); + return ERR_PTR(-EINVAL); + } buf = kzalloc(sizeof *buf, GFP_KERNEL); if (!buf) return ERR_PTR(-ENOMEM); - ret = vb2_get_contig_userptr(vaddr, size, &vma, &dma_addr); + buf->dev = conf->dev; + buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + + start = vaddr & PAGE_MASK; + offset = vaddr & ~PAGE_MASK; + end = PAGE_ALIGN(vaddr + size); + n_pages = (end - start) >> PAGE_SHIFT; + + pages = kmalloc(n_pages * sizeof(pages[0]), GFP_KERNEL); + if (!pages) { + ret = -ENOMEM; + pr_err("failed to allocate pages table\n"); + goto fail_buf; + } + + /* current->mm->mmap_sem is taken by videobuf2 core */ + vma = find_vma(current->mm, vaddr); + if (!vma) { + pr_err("no vma for address %lu\n", vaddr); + ret = -EFAULT; + goto fail_pages; + } + + if (vma->vm_end < vaddr + size) { + pr_err("vma at %lu is too small for %lu bytes\n", vaddr, size); + ret = -EFAULT; + goto fail_pages; + } + + buf->vma = vb2_get_vma(vma); + if (!buf->vma) { + pr_err("failed to copy vma\n"); + ret = -ENOMEM; + goto fail_pages; + } + + /* extract page list from userspace mapping */ + ret = vb2_dc_get_user_pages(start, pages, n_pages, vma, write); if (ret) { - printk(KERN_ERR "Failed acquiring VMA for vaddr 0x%08lx\n", - vaddr); - kfree(buf); - return ERR_PTR(ret); + pr_err("failed to get user pages\n"); + goto fail_vma; + } + + sgt = kzalloc(sizeof(*sgt), GFP_KERNEL); + if (!sgt) { + pr_err("failed to allocate sg table\n"); + ret = -ENOMEM; + goto fail_get_user_pages; + } + + ret = sg_alloc_table_from_pages(sgt, pages, n_pages, + offset, size, GFP_KERNEL); + if (ret) { + pr_err("failed to initialize sg table\n"); + goto fail_sgt; } + /* pages are no longer needed */ + kfree(pages); + pages = NULL; + + sgt->nents = dma_map_sg(buf->dev, sgt->sgl, sgt->orig_nents, + buf->dma_dir); + if (sgt->nents <= 0) { + pr_err("failed to map scatterlist\n"); + ret = -EIO; + goto fail_sgt_init; + } + + contig_size = vb2_dc_get_contiguous_size(sgt); + if (contig_size < size) { + pr_err("contiguous mapping is too small %lu/%lu\n", + contig_size, size); + ret = -EFAULT; + goto fail_map_sg; + } + + buf->dma_addr = sg_dma_address(sgt->sgl); buf->size = size; - buf->dma_addr = dma_addr; - buf->vma = vma; + buf->dma_sgt = sgt; return buf; + +fail_map_sg: + dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir); + +fail_sgt_init: + if (!vma_is_io(buf->vma)) + vb2_dc_sgt_foreach_page(sgt, put_page); + sg_free_table(sgt); + +fail_sgt: + kfree(sgt); + +fail_get_user_pages: + if (pages && !vma_is_io(buf->vma)) + while (n_pages) + put_page(pages[--n_pages]); + +fail_vma: + vb2_put_vma(buf->vma); + +fail_pages: + kfree(pages); /* kfree is NULL-proof */ + +fail_buf: + kfree(buf); + + return ERR_PTR(ret); } -static void vb2_dma_contig_put_userptr(void *mem_priv) +/*********************************************/ +/* callbacks for DMABUF buffers */ +/*********************************************/ + +static int vb2_dc_map_dmabuf(void *mem_priv) { struct vb2_dc_buf *buf = mem_priv; + struct sg_table *sgt; + unsigned long contig_size; - if (!buf) + if (WARN_ON(!buf->db_attach)) { + pr_err("trying to pin a non attached buffer\n"); + return -EINVAL; + } + + if (WARN_ON(buf->dma_sgt)) { + pr_err("dmabuf buffer is already pinned\n"); + return 0; + } + + /* get the associated scatterlist for this buffer */ + sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir); + if (IS_ERR_OR_NULL(sgt)) { + pr_err("Error getting dmabuf scatterlist\n"); + return -EINVAL; + } + + /* checking if dmabuf is big enough to store contiguous chunk */ + contig_size = vb2_dc_get_contiguous_size(sgt); + if (contig_size < buf->size) { + pr_err("contiguous chunk is too small %lu/%lu b\n", + contig_size, buf->size); + dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + return -EFAULT; + } + + buf->dma_addr = sg_dma_address(sgt->sgl); + buf->dma_sgt = sgt; + + return 0; +} + +static void vb2_dc_unmap_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + struct sg_table *sgt = buf->dma_sgt; + + if (WARN_ON(!buf->db_attach)) { + pr_err("trying to unpin a not attached buffer\n"); return; + } - vb2_put_vma(buf->vma); + if (WARN_ON(!sgt)) { + pr_err("dmabuf buffer is already unpinned\n"); + return; + } + + dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir); + + buf->dma_addr = 0; + buf->dma_sgt = NULL; +} + +static void vb2_dc_detach_dmabuf(void *mem_priv) +{ + struct vb2_dc_buf *buf = mem_priv; + + /* if vb2 works correctly you should never detach mapped buffer */ + if (WARN_ON(buf->dma_addr)) + vb2_dc_unmap_dmabuf(buf); + + /* detach this attachment */ + dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach); kfree(buf); } +static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, + unsigned long size, int write) +{ + struct vb2_dc_conf *conf = alloc_ctx; + struct vb2_dc_buf *buf; + struct dma_buf_attachment *dba; + + if (dbuf->size < size) + return ERR_PTR(-EFAULT); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + buf->dev = conf->dev; + /* create attachment for the dmabuf with the user device */ + dba = dma_buf_attach(dbuf, buf->dev); + if (IS_ERR(dba)) { + pr_err("failed to attach dmabuf\n"); + kfree(buf); + return dba; + } + + buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + buf->size = size; + buf->db_attach = dba; + + return buf; +} + +/*********************************************/ +/* DMA CONTIG exported functions */ +/*********************************************/ + const struct vb2_mem_ops vb2_dma_contig_memops = { - .alloc = vb2_dma_contig_alloc, - .put = vb2_dma_contig_put, - .cookie = vb2_dma_contig_cookie, - .vaddr = vb2_dma_contig_vaddr, - .mmap = vb2_dma_contig_mmap, - .get_userptr = vb2_dma_contig_get_userptr, - .put_userptr = vb2_dma_contig_put_userptr, - .num_users = vb2_dma_contig_num_users, + .alloc = vb2_dc_alloc, + .put = vb2_dc_put, + .get_dmabuf = vb2_dc_get_dmabuf, + .cookie = vb2_dc_cookie, + .vaddr = vb2_dc_vaddr, + .mmap = vb2_dc_mmap, + .get_userptr = vb2_dc_get_userptr, + .put_userptr = vb2_dc_put_userptr, + .prepare = vb2_dc_prepare, + .finish = vb2_dc_finish, + .map_dmabuf = vb2_dc_map_dmabuf, + .unmap_dmabuf = vb2_dc_unmap_dmabuf, + .attach_dmabuf = vb2_dc_attach_dmabuf, + .detach_dmabuf = vb2_dc_detach_dmabuf, + .num_users = vb2_dc_num_users, }; EXPORT_SYMBOL_GPL(vb2_dma_contig_memops); diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c index 051ea3571b2..81c1ad8b2cf 100644 --- a/drivers/media/v4l2-core/videobuf2-memops.c +++ b/drivers/media/v4l2-core/videobuf2-memops.c @@ -137,46 +137,6 @@ int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, EXPORT_SYMBOL_GPL(vb2_get_contig_userptr); /** - * vb2_mmap_pfn_range() - map physical pages to userspace - * @vma: virtual memory region for the mapping - * @paddr: starting physical address of the memory to be mapped - * @size: size of the memory to be mapped - * @vm_ops: vm operations to be assigned to the created area - * @priv: private data to be associated with the area - * - * Returns 0 on success. - */ -int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, - unsigned long size, - const struct vm_operations_struct *vm_ops, - void *priv) -{ - int ret; - - size = min_t(unsigned long, vma->vm_end - vma->vm_start, size); - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - ret = remap_pfn_range(vma, vma->vm_start, paddr >> PAGE_SHIFT, - size, vma->vm_page_prot); - if (ret) { - printk(KERN_ERR "Remapping memory failed, error: %d\n", ret); - return ret; - } - - vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; - vma->vm_private_data = priv; - vma->vm_ops = vm_ops; - - vma->vm_ops->open(vma); - - pr_debug("%s: mapped paddr 0x%08lx at 0x%08lx, size %ld\n", - __func__, paddr, vma->vm_start, size); - - return 0; -} -EXPORT_SYMBOL_GPL(vb2_mmap_pfn_range); - -/** * vb2_common_vm_open() - increase refcount of the vma * @vma: virtual memory region for the mapping * diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index 94efa04d8d5..a47fd4f589a 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -30,6 +30,7 @@ struct vb2_vmalloc_buf { unsigned int n_pages; atomic_t refcount; struct vb2_vmarea_handler handler; + struct dma_buf *dbuf; }; static void vb2_vmalloc_put(void *buf_priv); @@ -207,11 +208,66 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma) return 0; } +/*********************************************/ +/* callbacks for DMABUF buffers */ +/*********************************************/ + +static int vb2_vmalloc_map_dmabuf(void *mem_priv) +{ + struct vb2_vmalloc_buf *buf = mem_priv; + + buf->vaddr = dma_buf_vmap(buf->dbuf); + + return buf->vaddr ? 0 : -EFAULT; +} + +static void vb2_vmalloc_unmap_dmabuf(void *mem_priv) +{ + struct vb2_vmalloc_buf *buf = mem_priv; + + dma_buf_vunmap(buf->dbuf, buf->vaddr); + buf->vaddr = NULL; +} + +static void vb2_vmalloc_detach_dmabuf(void *mem_priv) +{ + struct vb2_vmalloc_buf *buf = mem_priv; + + if (buf->vaddr) + dma_buf_vunmap(buf->dbuf, buf->vaddr); + + kfree(buf); +} + +static void *vb2_vmalloc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf, + unsigned long size, int write) +{ + struct vb2_vmalloc_buf *buf; + + if (dbuf->size < size) + return ERR_PTR(-EFAULT); + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return ERR_PTR(-ENOMEM); + + buf->dbuf = dbuf; + buf->write = write; + buf->size = size; + + return buf; +} + + const struct vb2_mem_ops vb2_vmalloc_memops = { .alloc = vb2_vmalloc_alloc, .put = vb2_vmalloc_put, .get_userptr = vb2_vmalloc_get_userptr, .put_userptr = vb2_vmalloc_put_userptr, + .map_dmabuf = vb2_vmalloc_map_dmabuf, + .unmap_dmabuf = vb2_vmalloc_unmap_dmabuf, + .attach_dmabuf = vb2_vmalloc_attach_dmabuf, + .detach_dmabuf = vb2_vmalloc_detach_dmabuf, .vaddr = vb2_vmalloc_vaddr, .mmap = vb2_vmalloc_mmap, .num_users = vb2_vmalloc_num_users, diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c index 238910373f5..479c643da2f 100644 --- a/drivers/staging/media/dt3155v4l/dt3155v4l.c +++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c @@ -396,7 +396,9 @@ dt3155_open(struct file *filp) pd->q->drv_priv = pd; pd->curr_buf = NULL; pd->field_count = 0; - vb2_queue_init(pd->q); /* cannot fail */ + ret = vb2_queue_init(pd->q); + if (ret < 0) + return ret; INIT_LIST_HEAD(&pd->dmaq); spin_lock_init(&pd->lock); /* disable all irqs, clear all irq flags */ diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/staging/media/go7007/go7007-fw.c index c9a6409edfe..f99c05b454b 100644 --- a/drivers/staging/media/go7007/go7007-fw.c +++ b/drivers/staging/media/go7007/go7007-fw.c @@ -382,8 +382,8 @@ static int gen_mjpeghdr_to_package(struct go7007 *go, __le16 *code, int space) buf = kzalloc(4096, GFP_KERNEL); if (buf == NULL) { - printk(KERN_ERR "go7007: unable to allocate 4096 bytes for " - "firmware construction\n"); + dev_err(go->dev, + "unable to allocate 4096 bytes for firmware construction\n"); return -1; } @@ -652,8 +652,8 @@ static int gen_mpeg1hdr_to_package(struct go7007 *go, buf = kzalloc(5120, GFP_KERNEL); if (buf == NULL) { - printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " - "firmware construction\n"); + dev_err(go->dev, + "unable to allocate 5120 bytes for firmware construction\n"); return -1; } framelen[0] = mpeg1_frame_header(go, buf, 0, 1, PFRAME); @@ -839,8 +839,8 @@ static int gen_mpeg4hdr_to_package(struct go7007 *go, buf = kzalloc(5120, GFP_KERNEL); if (buf == NULL) { - printk(KERN_ERR "go7007: unable to allocate 5120 bytes for " - "firmware construction\n"); + dev_err(go->dev, + "unable to allocate 5120 bytes for firmware construction\n"); return -1; } framelen[0] = mpeg4_frame_header(go, buf, 0, PFRAME); @@ -1545,9 +1545,8 @@ static int do_special(struct go7007 *go, u16 type, __le16 *code, int space, case SPECIAL_MODET: return modet_to_package(go, code, space); } - printk(KERN_ERR - "go7007: firmware file contains unsupported feature %04x\n", - type); + dev_err(go->dev, + "firmware file contains unsupported feature %04x\n", type); return -1; } @@ -1577,15 +1576,16 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) return -1; } if (request_firmware(&fw_entry, go->board_info->firmware, go->dev)) { - printk(KERN_ERR - "go7007: unable to load firmware from file \"%s\"\n", + dev_err(go->dev, + "unable to load firmware from file \"%s\"\n", go->board_info->firmware); return -1; } code = kzalloc(codespace * 2, GFP_KERNEL); if (code == NULL) { - printk(KERN_ERR "go7007: unable to allocate %d bytes for " - "firmware construction\n", codespace * 2); + dev_err(go->dev, + "unable to allocate %d bytes for firmware construction\n", + codespace * 2); goto fw_failed; } src = (__le16 *)fw_entry->data; @@ -1594,9 +1594,9 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) chunk_flags = __le16_to_cpu(src[0]); chunk_len = __le16_to_cpu(src[1]); if (chunk_len + 2 > srclen) { - printk(KERN_ERR "go7007: firmware file \"%s\" " - "appears to be corrupted\n", - go->board_info->firmware); + dev_err(go->dev, + "firmware file \"%s\" appears to be corrupted\n", + go->board_info->firmware); goto fw_failed; } if (chunk_flags & mode_flag) { @@ -1604,17 +1604,15 @@ int go7007_construct_fw_image(struct go7007 *go, u8 **fw, int *fwlen) ret = do_special(go, __le16_to_cpu(src[2]), &code[i], codespace - i, framelen); if (ret < 0) { - printk(KERN_ERR "go7007: insufficient " - "memory for firmware " - "construction\n"); + dev_err(go->dev, + "insufficient memory for firmware construction\n"); goto fw_failed; } i += ret; } else { if (codespace - i < chunk_len) { - printk(KERN_ERR "go7007: insufficient " - "memory for firmware " - "construction\n"); + dev_err(go->dev, + "insufficient memory for firmware construction\n"); goto fw_failed; } memcpy(&code[i], &src[2], chunk_len * 2); diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c index 980371b0274..a78133b67de 100644 --- a/drivers/staging/media/go7007/go7007-v4l2.c +++ b/drivers/staging/media/go7007/go7007-v4l2.c @@ -812,7 +812,7 @@ static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf) return retval; mutex_lock(&gofh->lock); - if (buf->index < 0 || buf->index >= gofh->buf_count) + if (buf->index >= gofh->buf_count) goto unlock_and_return; gobuf = &gofh->bufs[buf->index]; diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c index 014d38410c9..b3974100c6c 100644 --- a/drivers/staging/media/go7007/s2250-board.c +++ b/drivers/staging/media/go7007/s2250-board.c @@ -688,15 +688,4 @@ static struct i2c_driver s2250_driver = { .id_table = s2250_id, }; -static __init int init_s2250(void) -{ - return i2c_add_driver(&s2250_driver); -} - -static __exit void exit_s2250(void) -{ - i2c_del_driver(&s2250_driver); -} - -module_init(init_s2250); -module_exit(exit_s2250); +module_i2c_driver(s2250_driver); diff --git a/drivers/staging/media/go7007/wis-ov7640.c b/drivers/staging/media/go7007/wis-ov7640.c index 6bc9470fecb..9f01657f884 100644 --- a/drivers/staging/media/go7007/wis-ov7640.c +++ b/drivers/staging/media/go7007/wis-ov7640.c @@ -29,8 +29,7 @@ struct wis_ov7640 { int hue; }; -static u8 initial_registers[] = -{ +static u8 initial_registers[] = { 0x12, 0x80, 0x12, 0x54, 0x14, 0x24, @@ -60,12 +59,12 @@ static int wis_ov7640_probe(struct i2c_client *client, client->flags = I2C_CLIENT_SCCB; - printk(KERN_DEBUG + dev_dbg(&client->dev, "wis-ov7640: initializing OV7640 at address %d on %s\n", client->addr, adapter->name); if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR "wis-ov7640: error initializing OV7640\n"); + dev_err(&client->dev, "wis-ov7640: error initializing OV7640\n"); return -ENODEV; } @@ -92,17 +91,6 @@ static struct i2c_driver wis_ov7640_driver = { .id_table = wis_ov7640_id, }; -static int __init wis_ov7640_init(void) -{ - return i2c_add_driver(&wis_ov7640_driver); -} - -static void __exit wis_ov7640_cleanup(void) -{ - i2c_del_driver(&wis_ov7640_driver); -} - -module_init(wis_ov7640_init); -module_exit(wis_ov7640_cleanup); +module_i2c_driver(wis_ov7640_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-saa7113.c b/drivers/staging/media/go7007/wis-saa7113.c index 05e0e108386..8810c1e6e1e 100644 --- a/drivers/staging/media/go7007/wis-saa7113.c +++ b/drivers/staging/media/go7007/wis-saa7113.c @@ -32,8 +32,7 @@ struct wis_saa7113 { int hue; }; -static u8 initial_registers[] = -{ +static u8 initial_registers[] = { 0x01, 0x08, 0x02, 0xc0, 0x03, 0x33, @@ -282,12 +281,12 @@ static int wis_saa7113_probe(struct i2c_client *client, dec->hue = 0; i2c_set_clientdata(client, dec); - printk(KERN_DEBUG + dev_dbg(&client->dev, "wis-saa7113: initializing SAA7113 at address %d on %s\n", client->addr, adapter->name); if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR + dev_err(&client->dev, "wis-saa7113: error initializing SAA7113\n"); kfree(dec); return -ENODEV; @@ -320,17 +319,6 @@ static struct i2c_driver wis_saa7113_driver = { .id_table = wis_saa7113_id, }; -static int __init wis_saa7113_init(void) -{ - return i2c_add_driver(&wis_saa7113_driver); -} - -static void __exit wis_saa7113_cleanup(void) -{ - i2c_del_driver(&wis_saa7113_driver); -} - -module_init(wis_saa7113_init); -module_exit(wis_saa7113_cleanup); +module_i2c_driver(wis_saa7113_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-saa7115.c b/drivers/staging/media/go7007/wis-saa7115.c index 46cff59e28b..fa86acd3fdf 100644 --- a/drivers/staging/media/go7007/wis-saa7115.c +++ b/drivers/staging/media/go7007/wis-saa7115.c @@ -32,8 +32,7 @@ struct wis_saa7115 { int hue; }; -static u8 initial_registers[] = -{ +static u8 initial_registers[] = { 0x01, 0x08, 0x02, 0xc0, 0x03, 0x20, @@ -415,12 +414,12 @@ static int wis_saa7115_probe(struct i2c_client *client, dec->hue = 0; i2c_set_clientdata(client, dec); - printk(KERN_DEBUG + dev_dbg(&client->dev, "wis-saa7115: initializing SAA7115 at address %d on %s\n", client->addr, adapter->name); if (write_regs(client, initial_registers) < 0) { - printk(KERN_ERR + dev_err(&client->dev, "wis-saa7115: error initializing SAA7115\n"); kfree(dec); return -ENODEV; @@ -453,17 +452,6 @@ static struct i2c_driver wis_saa7115_driver = { .id_table = wis_saa7115_id, }; -static int __init wis_saa7115_init(void) -{ - return i2c_add_driver(&wis_saa7115_driver); -} - -static void __exit wis_saa7115_cleanup(void) -{ - i2c_del_driver(&wis_saa7115_driver); -} - -module_init(wis_saa7115_init); -module_exit(wis_saa7115_cleanup); +module_i2c_driver(wis_saa7115_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-sony-tuner.c b/drivers/staging/media/go7007/wis-sony-tuner.c index 8f1b7d4f6a2..1291ab79d2a 100644 --- a/drivers/staging/media/go7007/wis-sony-tuner.c +++ b/drivers/staging/media/go7007/wis-sony-tuner.c @@ -704,17 +704,6 @@ static struct i2c_driver wis_sony_tuner_driver = { .id_table = wis_sony_tuner_id, }; -static int __init wis_sony_tuner_init(void) -{ - return i2c_add_driver(&wis_sony_tuner_driver); -} - -static void __exit wis_sony_tuner_cleanup(void) -{ - i2c_del_driver(&wis_sony_tuner_driver); -} - -module_init(wis_sony_tuner_init); -module_exit(wis_sony_tuner_cleanup); +module_i2c_driver(wis_sony_tuner_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-tw2804.c b/drivers/staging/media/go7007/wis-tw2804.c index 9134f03e3cf..d6410ee01be 100644 --- a/drivers/staging/media/go7007/wis-tw2804.c +++ b/drivers/staging/media/go7007/wis-tw2804.c @@ -341,17 +341,6 @@ static struct i2c_driver wis_tw2804_driver = { .id_table = wis_tw2804_id, }; -static int __init wis_tw2804_init(void) -{ - return i2c_add_driver(&wis_tw2804_driver); -} - -static void __exit wis_tw2804_cleanup(void) -{ - i2c_del_driver(&wis_tw2804_driver); -} - -module_init(wis_tw2804_init); -module_exit(wis_tw2804_cleanup); +module_i2c_driver(wis_tw2804_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-tw9903.c b/drivers/staging/media/go7007/wis-tw9903.c index 9230f4a8052..94071def3bb 100644 --- a/drivers/staging/media/go7007/wis-tw9903.c +++ b/drivers/staging/media/go7007/wis-tw9903.c @@ -325,17 +325,6 @@ static struct i2c_driver wis_tw9903_driver = { .id_table = wis_tw9903_id, }; -static int __init wis_tw9903_init(void) -{ - return i2c_add_driver(&wis_tw9903_driver); -} - -static void __exit wis_tw9903_cleanup(void) -{ - i2c_del_driver(&wis_tw9903_driver); -} - -module_init(wis_tw9903_init); -module_exit(wis_tw9903_cleanup); +module_i2c_driver(wis_tw9903_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/go7007/wis-uda1342.c b/drivers/staging/media/go7007/wis-uda1342.c index 0127be2f3be..05ac798f35f 100644 --- a/drivers/staging/media/go7007/wis-uda1342.c +++ b/drivers/staging/media/go7007/wis-uda1342.c @@ -98,17 +98,6 @@ static struct i2c_driver wis_uda1342_driver = { .id_table = wis_uda1342_id, }; -static int __init wis_uda1342_init(void) -{ - return i2c_add_driver(&wis_uda1342_driver); -} - -static void __exit wis_uda1342_cleanup(void) -{ - i2c_del_driver(&wis_uda1342_driver); -} - -module_init(wis_uda1342_init); -module_exit(wis_uda1342_cleanup); +module_i2c_driver(wis_uda1342_driver); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 71e3bf2937f..b5d0088f310 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -1239,6 +1239,10 @@ static int __init lirc_serial_init_module(void) } } + /* make sure sense is either -1, 0, or 1 */ + if (sense != -1) + sense = !!sense; + result = lirc_serial_init(); if (result) return result; @@ -1298,7 +1302,7 @@ MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); module_param(share_irq, bool, S_IRUGO); MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); -module_param(sense, bool, S_IRUGO); +module_param(sense, int, S_IRUGO); MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" " (0 = active high, 1 = active low )"); diff --git a/include/linux/dvb/Kbuild b/include/linux/dvb/Kbuild deleted file mode 100644 index e69de29bb2d..00000000000 --- a/include/linux/dvb/Kbuild +++ /dev/null diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h deleted file mode 100644 index 0be6d8f2b52..00000000000 --- a/include/linux/dvb/dmx.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * dmx.h - * - * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de> - * & Ralph Metzler <ralph@convergence.de> - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#ifndef _DVBDMX_H_ -#define _DVBDMX_H_ - -#include <linux/time.h> -#include <uapi/linux/dvb/dmx.h> - -#endif /*_DVBDMX_H_*/ diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h deleted file mode 100644 index 85c20d92569..00000000000 --- a/include/linux/dvb/video.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * video.h - * - * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de> - * & Ralph Metzler <ralph@convergence.de> - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * 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. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - */ -#ifndef _DVBVIDEO_H_ -#define _DVBVIDEO_H_ - -#include <linux/compiler.h> -#include <uapi/linux/dvb/video.h> - -#endif /*_DVBVIDEO_H_*/ diff --git a/include/media/adp1653.h b/include/media/adp1653.h index 50a1af88aed..1d9b48a3bd8 100644 --- a/include/media/adp1653.h +++ b/include/media/adp1653.h @@ -3,10 +3,10 @@ * * Copyright (C) 2008--2011 Nokia Corporation * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * Contributors: - * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Sakari Ailus <sakari.ailus@iki.fi> * Tuukka Toivonen <tuukkat76@gmail.com> * * This program is free software; you can redistribute it and/or diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h index dbf6b37682c..8dffffedbb5 100644 --- a/include/media/davinci/vpbe_display.h +++ b/include/media/davinci/vpbe_display.h @@ -16,7 +16,7 @@ /* Header files */ #include <linux/videodev2.h> #include <media/v4l2-common.h> -#include <media/videobuf-dma-contig.h> +#include <media/videobuf2-dma-contig.h> #include <media/davinci/vpbe_types.h> #include <media/davinci/vpbe_osd.h> #include <media/davinci/vpbe.h> @@ -62,6 +62,11 @@ struct display_layer_info { enum osd_v_exp_ratio v_exp; }; +struct vpbe_disp_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + /* vpbe display object structure */ struct vpbe_layer { /* number of buffers in fbuffers */ @@ -69,13 +74,15 @@ struct vpbe_layer { /* Pointer to the vpbe_display */ struct vpbe_display *disp_dev; /* Pointer pointing to current v4l2_buffer */ - struct videobuf_buffer *cur_frm; + struct vpbe_disp_buffer *cur_frm; /* Pointer pointing to next v4l2_buffer */ - struct videobuf_buffer *next_frm; + struct vpbe_disp_buffer *next_frm; /* videobuf specific parameters * Buffer queue used in video-buf */ - struct videobuf_queue buffer_queue; + struct vb2_queue buffer_queue; + /* allocator-specific contexts for each plane */ + struct vb2_alloc_ctx *alloc_ctx; /* Queue of filled frames */ struct list_head dma_queue; /* Used in video-buf */ diff --git a/include/media/davinci/vpbe_osd.h b/include/media/davinci/vpbe_osd.h index d7e397a444e..5ab0d8d41f6 100644 --- a/include/media/davinci/vpbe_osd.h +++ b/include/media/davinci/vpbe_osd.h @@ -357,7 +357,7 @@ struct osd_state { spinlock_t lock; struct device *dev; dma_addr_t osd_base_phys; - unsigned long osd_base; + void __iomem *osd_base; unsigned long osd_size; /* 1-->the isr will toggle the VID0 ping-pong buffer */ int pingpong; diff --git a/include/media/ir-kbd-i2c.h b/include/media/ir-kbd-i2c.h index 768aa77925c..e221bc74020 100644 --- a/include/media/ir-kbd-i2c.h +++ b/include/media/ir-kbd-i2c.h @@ -37,7 +37,7 @@ enum ir_kbd_get_key_fn { struct IR_i2c_init_data { char *ir_codes; const char *name; - u64 type; /* RC_TYPE_RC5, etc */ + u64 type; /* RC_BIT_RC5, etc */ u32 polling_interval; /* 0 means DEFAULT_POLLING_INTERVAL */ /* diff --git a/include/media/mt9v022.h b/include/media/mt9v022.h new file mode 100644 index 00000000000..40561801321 --- /dev/null +++ b/include/media/mt9v022.h @@ -0,0 +1,16 @@ +/* + * mt9v022 sensor + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __MT9V022_H__ +#define __MT9V022_H__ + +struct mt9v022_platform_data { + unsigned short y_skip_top; /* Lines to skip at the top */ +}; + +#endif diff --git a/include/media/rc-core.h b/include/media/rc-core.h index b0c494a6907..f03445f3c76 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -50,7 +50,7 @@ enum rc_driver_type { * @input_dev: the input child device used to communicate events to userspace * @driver_type: specifies if protocol decoding is done in hardware or software * @idle: used to keep track of RX state - * @allowed_protos: bitmask with the supported RC_TYPE_* protocols + * @allowed_protos: bitmask with the supported RC_BIT_* protocols * @scanmask: some hardware decoders are not capable of providing the full * scancode to the application. As this is a hardware limit, we can't do * anything with it. Yet, as the same keycode table can be used with other @@ -113,7 +113,7 @@ struct rc_dev { u32 max_timeout; u32 rx_resolution; u32 tx_resolution; - int (*change_protocol)(struct rc_dev *dev, u64 rc_type); + int (*change_protocol)(struct rc_dev *dev, u64 *rc_type); int (*open)(struct rc_dev *dev); void (*close)(struct rc_dev *dev); int (*s_tx_mask)(struct rc_dev *dev, u32 mask); diff --git a/include/media/rc-map.h b/include/media/rc-map.h index cfd5163ff7f..74f55a3f14e 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -11,22 +11,54 @@ #include <linux/input.h> -#define RC_TYPE_UNKNOWN 0 -#define RC_TYPE_RC5 (1 << 0) /* Philips RC5 protocol */ -#define RC_TYPE_NEC (1 << 1) -#define RC_TYPE_RC6 (1 << 2) /* Philips RC6 protocol */ -#define RC_TYPE_JVC (1 << 3) /* JVC protocol */ -#define RC_TYPE_SONY (1 << 4) /* Sony12/15/20 protocol */ -#define RC_TYPE_RC5_SZ (1 << 5) /* RC5 variant used by Streamzap */ -#define RC_TYPE_SANYO (1 << 6) /* Sanyo protocol */ -#define RC_TYPE_MCE_KBD (1 << 29) /* RC6-ish MCE keyboard/mouse */ -#define RC_TYPE_LIRC (1 << 30) /* Pass raw IR to lirc userspace */ -#define RC_TYPE_OTHER (1u << 31) +enum rc_type { + RC_TYPE_UNKNOWN = 0, /* Protocol not known */ + RC_TYPE_OTHER = 1, /* Protocol known but proprietary */ + RC_TYPE_LIRC = 2, /* Pass raw IR to lirc userspace */ + RC_TYPE_RC5 = 3, /* Philips RC5 protocol */ + RC_TYPE_RC5X = 4, /* Philips RC5x protocol */ + RC_TYPE_RC5_SZ = 5, /* StreamZap variant of RC5 */ + RC_TYPE_JVC = 6, /* JVC protocol */ + RC_TYPE_SONY12 = 7, /* Sony 12 bit protocol */ + RC_TYPE_SONY15 = 8, /* Sony 15 bit protocol */ + RC_TYPE_SONY20 = 9, /* Sony 20 bit protocol */ + RC_TYPE_NEC = 10, /* NEC protocol */ + RC_TYPE_SANYO = 11, /* Sanyo protocol */ + RC_TYPE_MCE_KBD = 12, /* RC6-ish MCE keyboard/mouse */ + RC_TYPE_RC6_0 = 13, /* Philips RC6-0-16 protocol */ + RC_TYPE_RC6_6A_20 = 14, /* Philips RC6-6A-20 protocol */ + RC_TYPE_RC6_6A_24 = 15, /* Philips RC6-6A-24 protocol */ + RC_TYPE_RC6_6A_32 = 16, /* Philips RC6-6A-32 protocol */ + RC_TYPE_RC6_MCE = 17, /* MCE (Philips RC6-6A-32 subtype) protocol */ +}; + +#define RC_BIT_NONE 0 +#define RC_BIT_UNKNOWN (1 << RC_TYPE_UNKNOWN) +#define RC_BIT_OTHER (1 << RC_TYPE_OTHER) +#define RC_BIT_LIRC (1 << RC_TYPE_LIRC) +#define RC_BIT_RC5 (1 << RC_TYPE_RC5) +#define RC_BIT_RC5X (1 << RC_TYPE_RC5X) +#define RC_BIT_RC5_SZ (1 << RC_TYPE_RC5_SZ) +#define RC_BIT_JVC (1 << RC_TYPE_JVC) +#define RC_BIT_SONY12 (1 << RC_TYPE_SONY12) +#define RC_BIT_SONY15 (1 << RC_TYPE_SONY15) +#define RC_BIT_SONY20 (1 << RC_TYPE_SONY20) +#define RC_BIT_NEC (1 << RC_TYPE_NEC) +#define RC_BIT_SANYO (1 << RC_TYPE_SANYO) +#define RC_BIT_MCE_KBD (1 << RC_TYPE_MCE_KBD) +#define RC_BIT_RC6_0 (1 << RC_TYPE_RC6_0) +#define RC_BIT_RC6_6A_20 (1 << RC_TYPE_RC6_6A_20) +#define RC_BIT_RC6_6A_24 (1 << RC_TYPE_RC6_6A_24) +#define RC_BIT_RC6_6A_32 (1 << RC_TYPE_RC6_6A_32) +#define RC_BIT_RC6_MCE (1 << RC_TYPE_RC6_MCE) -#define RC_TYPE_ALL (RC_TYPE_RC5 | RC_TYPE_NEC | RC_TYPE_RC6 | \ - RC_TYPE_JVC | RC_TYPE_SONY | RC_TYPE_LIRC | \ - RC_TYPE_RC5_SZ | RC_TYPE_SANYO | RC_TYPE_MCE_KBD | \ - RC_TYPE_OTHER) +#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \ + RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \ + RC_BIT_JVC | \ + RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \ + RC_BIT_NEC | RC_BIT_SANYO | RC_BIT_MCE_KBD | \ + RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \ + RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE) struct rc_map_table { u32 scancode; @@ -38,7 +70,7 @@ struct rc_map { unsigned int size; /* Max number of entries */ unsigned int len; /* Used number of entries */ unsigned int alloc; /* Size of *scan in bytes */ - u64 rc_type; + enum rc_type rc_type; const char *name; spinlock_t lock; }; diff --git a/include/media/s3c_camif.h b/include/media/s3c_camif.h new file mode 100644 index 00000000000..df96c2c789b --- /dev/null +++ b/include/media/s3c_camif.h @@ -0,0 +1,45 @@ +/* + * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver + * + * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#ifndef MEDIA_S3C_CAMIF_ +#define MEDIA_S3C_CAMIF_ + +#include <linux/i2c.h> +#include <media/v4l2-mediabus.h> + +/** + * struct s3c_camif_sensor_info - an image sensor description + * @i2c_board_info: pointer to an I2C sensor subdevice board info + * @clock_frequency: frequency of the clock the host provides to a sensor + * @mbus_type: media bus type + * @i2c_bus_num: i2c control bus id the sensor is attached to + * @flags: the parallel bus flags defining signals polarity (V4L2_MBUS_*) + * @use_field: 1 if parallel bus FIELD signal is used (only s3c64xx) + */ +struct s3c_camif_sensor_info { + struct i2c_board_info i2c_board_info; + unsigned long clock_frequency; + enum v4l2_mbus_type mbus_type; + u16 i2c_bus_num; + u16 flags; + u8 use_field; +}; + +struct s3c_camif_plat_data { + struct s3c_camif_sensor_info sensor; + int (*gpio_get)(void); + int (*gpio_put)(void); +}; + +/* Platform default helper functions */ +int s3c_camif_gpio_get(void); +int s3c_camif_gpio_put(void); + +#endif /* MEDIA_S3C_CAMIF_ */ diff --git a/include/media/smiapp.h b/include/media/smiapp.h index 9ab07fd45d5..07f96a89e18 100644 --- a/include/media/smiapp.h +++ b/include/media/smiapp.h @@ -4,7 +4,7 @@ * Generic driver for SMIA/SMIA++ compliant camera modules * * Copyright (C) 2011--2012 Nokia Corporation - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h index e7c5d170a9c..eff85f934b2 100644 --- a/include/media/v4l2-event.h +++ b/include/media/v4l2-event.h @@ -5,7 +5,7 @@ * * Copyright (C) 2009--2010 Nokia Corporation. * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 52513c225c1..a62ee18cb7b 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -6,7 +6,7 @@ * * Copyright (C) 2009--2010 Nokia Corporation. * - * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> + * Contact: Sakari Ailus <sakari.ailus@iki.fi> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h index e48b571ca37..4118ad1324c 100644 --- a/include/media/v4l2-ioctl.h +++ b/include/media/v4l2-ioctl.h @@ -111,6 +111,8 @@ struct v4l2_ioctl_ops { int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b); int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b); int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b); + int (*vidioc_expbuf) (struct file *file, void *fh, + struct v4l2_exportbuffer *e); int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b); int (*vidioc_create_bufs)(struct file *file, void *fh, struct v4l2_create_buffers *b); diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 131cc4a5367..7e82d2b193d 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -111,6 +111,9 @@ int v4l2_m2m_qbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, int v4l2_m2m_dqbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_buffer *buf); +int v4l2_m2m_expbuf(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, + struct v4l2_exportbuffer *eb); + int v4l2_m2m_streamon(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, enum v4l2_buf_type type); int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index e04252a9fea..9cfd4ee9e56 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -16,6 +16,7 @@ #include <linux/mutex.h> #include <linux/poll.h> #include <linux/videodev2.h> +#include <linux/dma-buf.h> struct vb2_alloc_ctx; struct vb2_fileio_data; @@ -41,6 +42,24 @@ struct vb2_fileio_data; * argument to other ops in this structure * @put_userptr: inform the allocator that a USERPTR buffer will no longer * be used + * @attach_dmabuf: attach a shared struct dma_buf for a hardware operation; + * used for DMABUF memory types; alloc_ctx is the alloc context + * dbuf is the shared dma_buf; returns NULL on failure; + * allocator private per-buffer structure on success; + * this needs to be used for further accesses to the buffer + * @detach_dmabuf: inform the exporter of the buffer that the current DMABUF + * buffer is no longer used; the buf_priv argument is the + * allocator private per-buffer structure previously returned + * from the attach_dmabuf callback + * @map_dmabuf: request for access to the dmabuf from allocator; the allocator + * of dmabuf is informed that this driver is going to use the + * dmabuf + * @unmap_dmabuf: releases access control to the dmabuf - allocator is notified + * that this driver is done using the dmabuf for now + * @prepare: called every time the buffer is passed from userspace to the + * driver, useful for cache synchronisation, optional + * @finish: called every time the buffer is passed back from the driver + * to the userspace, also optional * @vaddr: return a kernel virtual address to a given memory buffer * associated with the passed private structure or NULL if no * such mapping exists @@ -56,15 +75,27 @@ struct vb2_fileio_data; * Required ops for USERPTR types: get_userptr, put_userptr. * Required ops for MMAP types: alloc, put, num_users, mmap. * Required ops for read/write access types: alloc, put, num_users, vaddr + * Required ops for DMABUF types: attach_dmabuf, detach_dmabuf, map_dmabuf, + * unmap_dmabuf. */ struct vb2_mem_ops { void *(*alloc)(void *alloc_ctx, unsigned long size); void (*put)(void *buf_priv); + struct dma_buf *(*get_dmabuf)(void *buf_priv); void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr, unsigned long size, int write); void (*put_userptr)(void *buf_priv); + void (*prepare)(void *buf_priv); + void (*finish)(void *buf_priv); + + void *(*attach_dmabuf)(void *alloc_ctx, struct dma_buf *dbuf, + unsigned long size, int write); + void (*detach_dmabuf)(void *buf_priv); + int (*map_dmabuf)(void *buf_priv); + void (*unmap_dmabuf)(void *buf_priv); + void *(*vaddr)(void *buf_priv); void *(*cookie)(void *buf_priv); @@ -75,6 +106,8 @@ struct vb2_mem_ops { struct vb2_plane { void *mem_priv; + struct dma_buf *dbuf; + unsigned int dbuf_mapped; }; /** @@ -83,12 +116,14 @@ struct vb2_plane { * @VB2_USERPTR: driver supports USERPTR with streaming API * @VB2_READ: driver supports read() style access * @VB2_WRITE: driver supports write() style access + * @VB2_DMABUF: driver supports DMABUF with streaming API */ enum vb2_io_modes { VB2_MMAP = (1 << 0), VB2_USERPTR = (1 << 1), VB2_READ = (1 << 2), VB2_WRITE = (1 << 3), + VB2_DMABUF = (1 << 4), }; /** @@ -329,6 +364,7 @@ int __must_check vb2_queue_init(struct vb2_queue *q); void vb2_queue_release(struct vb2_queue *q); int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b); +int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb); int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking); int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type); @@ -438,6 +474,8 @@ int vb2_ioctl_qbuf(struct file *file, void *priv, struct v4l2_buffer *p); int vb2_ioctl_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p); int vb2_ioctl_streamon(struct file *file, void *priv, enum v4l2_buf_type i); int vb2_ioctl_streamoff(struct file *file, void *priv, enum v4l2_buf_type i); +int vb2_ioctl_expbuf(struct file *file, void *priv, + struct v4l2_exportbuffer *p); /* struct v4l2_file_operations helpers */ diff --git a/include/media/videobuf2-memops.h b/include/media/videobuf2-memops.h index 84e1f6c031c..f05444ca8c0 100644 --- a/include/media/videobuf2-memops.h +++ b/include/media/videobuf2-memops.h @@ -33,11 +33,6 @@ extern const struct vm_operations_struct vb2_common_vm_ops; int vb2_get_contig_userptr(unsigned long vaddr, unsigned long size, struct vm_area_struct **res_vma, dma_addr_t *res_pa); -int vb2_mmap_pfn_range(struct vm_area_struct *vma, unsigned long paddr, - unsigned long size, - const struct vm_operations_struct *vm_ops, - void *priv); - struct vm_area_struct *vb2_get_vma(struct vm_area_struct *vma); void vb2_put_vma(struct vm_area_struct *vma); diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 57bfa59cda7..3cf3e946e33 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -186,6 +186,7 @@ enum v4l2_memory { V4L2_MEMORY_MMAP = 1, V4L2_MEMORY_USERPTR = 2, V4L2_MEMORY_OVERLAY = 3, + V4L2_MEMORY_DMABUF = 4, }; /* see also http://vektor.theorem.ca/graphics/ycbcr/ */ @@ -602,6 +603,8 @@ struct v4l2_requestbuffers { * should be passed to mmap() called on the video node) * @userptr: when memory is V4L2_MEMORY_USERPTR, a userspace pointer * pointing to this plane + * @fd: when memory is V4L2_MEMORY_DMABUF, a userspace file + * descriptor associated with this plane * @data_offset: offset in the plane to the start of data; usually 0, * unless there is a header in front of the data * @@ -616,6 +619,7 @@ struct v4l2_plane { union { __u32 mem_offset; unsigned long userptr; + __s32 fd; } m; __u32 data_offset; __u32 reserved[11]; @@ -640,6 +644,8 @@ struct v4l2_plane { * (or a "cookie" that should be passed to mmap() as offset) * @userptr: for non-multiplanar buffers with memory == V4L2_MEMORY_USERPTR; * a userspace pointer pointing to this buffer + * @fd: for non-multiplanar buffers with memory == V4L2_MEMORY_DMABUF; + * a userspace file descriptor associated with this buffer * @planes: for multiplanar buffers; userspace pointer to the array of plane * info structs for this buffer * @length: size in bytes of the buffer (NOT its payload) for single-plane @@ -666,6 +672,7 @@ struct v4l2_buffer { __u32 offset; unsigned long userptr; struct v4l2_plane *planes; + __s32 fd; } m; __u32 length; __u32 reserved2; @@ -687,6 +694,33 @@ struct v4l2_buffer { #define V4L2_BUF_FLAG_NO_CACHE_INVALIDATE 0x0800 #define V4L2_BUF_FLAG_NO_CACHE_CLEAN 0x1000 +/** + * struct v4l2_exportbuffer - export of video buffer as DMABUF file descriptor + * + * @index: id number of the buffer + * @type: enum v4l2_buf_type; buffer type (type == *_MPLANE for + * multiplanar buffers); + * @plane: index of the plane to be exported, 0 for single plane queues + * @flags: flags for newly created file, currently only O_CLOEXEC is + * supported, refer to manual of open syscall for more details + * @fd: file descriptor associated with DMABUF (set by driver) + * + * Contains data used for exporting a video buffer as DMABUF file descriptor. + * The buffer is identified by a 'cookie' returned by VIDIOC_QUERYBUF + * (identical to the cookie used to mmap() the buffer to userspace). All + * reserved fields must be set to zero. The field reserved0 is expected to + * become a structure 'type' allowing an alternative layout of the structure + * content. Therefore this field should not be used for any other extensions. + */ +struct v4l2_exportbuffer { + __u32 type; /* enum v4l2_buf_type */ + __u32 index; + __u32 plane; + __u32 flags; + __s32 fd; + __u32 reserved[11]; +}; + /* * O V E R L A Y P R E V I E W */ @@ -737,7 +771,7 @@ struct v4l2_window { struct v4l2_captureparm { __u32 capability; /* Supported modes */ __u32 capturemode; /* Current mode */ - struct v4l2_fract timeperframe; /* Time per frame in .1us units */ + struct v4l2_fract timeperframe; /* Time per frame in seconds */ __u32 extendedmode; /* Driver-specific extensions */ __u32 readbuffers; /* # of buffers for read */ __u32 reserved[4]; @@ -1888,6 +1922,7 @@ struct v4l2_create_buffers { #define VIDIOC_S_FBUF _IOW('V', 11, struct v4l2_framebuffer) #define VIDIOC_OVERLAY _IOW('V', 14, int) #define VIDIOC_QBUF _IOWR('V', 15, struct v4l2_buffer) +#define VIDIOC_EXPBUF _IOWR('V', 16, struct v4l2_exportbuffer) #define VIDIOC_DQBUF _IOWR('V', 17, struct v4l2_buffer) #define VIDIOC_STREAMON _IOW('V', 18, int) #define VIDIOC_STREAMOFF _IOW('V', 19, int) |