diff options
author | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-10-09 14:00:54 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-10-09 14:00:54 -0300 |
commit | a66d05d504a24894a8fdf11e4569752f313e5764 (patch) | |
tree | 2bb40c1f6c301b231d7aeaad08c190aa5a82ba1f | |
parent | bfe01a5ba2490f299e1d2d5508cbbbadd897bbe9 (diff) | |
parent | 5563caaf8b8cd22e35997d5d74cb3609df86b223 (diff) |
Merge branch 'patchwork' into v4l_for_linusmedia/v3.18-rc1
* patchwork: (544 commits)
[media] ir-hix5hd2: fix build on c6x arch
[media] pt3: fix DTV FE I2C driver load error paths
Revert "[media] media: em28xx - remove reset_resume interface"
[media] exynos4-is: fix some warnings when compiling on arm64
[media] usb drivers: use %zu instead of %zd
[media] pci drivers: use %zu instead of %zd
[media] dvb-frontends: use %zu instead of %zd
[media] s5p-mfc: Fix several printk warnings
[media] s5p_mfc_opr: Fix warnings
[media] ti-vpe: Fix typecast
[media] s3c-camif: fix dma_addr_t printks
[media] s5p_mfc_opr_v6: get rid of warnings when compiled with 64 bits
[media] s5p_mfc_opr_v5: Fix lots of warnings on x86_64
[media] em28xx: Fix identation
[media] drxd: remove a dead code
[media] saa7146: remove return after BUG()
[media] cx88: remove return after BUG()
[media] cx88: fix cards table CodingStyle
[media] radio-sf16fmr2: declare some structs as static
[media] radio-sf16fmi: declare pnp_attached as static
...
Conflicts:
Documentation/DocBook/media/v4l/compat.xml
475 files changed, 36215 insertions, 13052 deletions
diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml index 3a626d1b8f2e..07ffc76553ba 100644 --- a/Documentation/DocBook/media/v4l/compat.xml +++ b/Documentation/DocBook/media/v4l/compat.xml @@ -2566,6 +2566,12 @@ fields changed from _s32 to _u32. <para>Added compound control types and &VIDIOC-QUERY-EXT-CTRL;. </para> </listitem> + <title>V4L2 in Linux 3.18</title> + <orderedlist> + <listitem> + <para>Added <constant>V4L2_CID_PAN_SPEED</constant> and + <constant>V4L2_CID_TILT_SPEED</constant> camera controls.</para> + </listitem> </orderedlist> </section> diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 9f5ffd85560b..e013e4bf244c 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3965,6 +3965,27 @@ by exposure, white balance or focus controls.</entry> </row> <row><entry></entry></row> + <row> + <entry spanname="id"><constant>V4L2_CID_PAN_SPEED</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">This control turns the +camera horizontally at the specific speed. The unit is undefined. A +positive value moves the camera to the right (clockwise when viewed +from above), a negative value to the left. A value of zero stops the motion +if one is in progress and has no effect otherwise.</entry> + </row> + <row><entry></entry></row> + + <row> + <entry spanname="id"><constant>V4L2_CID_TILT_SPEED</constant> </entry> + <entry>integer</entry> + </row><row><entry spanname="descr">This control turns the +camera vertically at the specified speed. The unit is undefined. A +positive value moves the camera up, a negative value down. A value of zero +stops the motion if one is in progress and has no effect otherwise.</entry> + </row> + <row><entry></entry></row> + </tbody> </tgroup> </table> @@ -4790,6 +4811,40 @@ interface and may change in the future.</para> conversion. </entry> </row> + <row> + <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_RED</constant></entry> + <entry>integer</entry> + </row> + <row> + <entry spanname="descr">Test pattern red colour component. + </entry> + </row> + <row> + <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_GREENR</constant></entry> + <entry>integer</entry> + </row> + <row> + <entry spanname="descr">Test pattern green (next to red) + colour component. + </entry> + </row> + <row> + <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_BLUE</constant></entry> + <entry>integer</entry> + </row> + <row> + <entry spanname="descr">Test pattern blue colour component. + </entry> + </row> + <row> + <entry spanname="id"><constant>V4L2_CID_TEST_PATTERN_GREENB</constant></entry> + <entry>integer</entry> + </row> + <row> + <entry spanname="descr">Test pattern green (next to blue) + colour component. + </entry> + </row> <row><entry></entry></row> </tbody> </tgroup> diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml index 2aae8e9452a4..6ab4f0f3db64 100644 --- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml +++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml @@ -237,9 +237,9 @@ for a pixel lie next to each other in memory.</para> <entry>g<subscript>4</subscript></entry> <entry>g<subscript>3</subscript></entry> </row> - <row id="V4L2-PIX-FMT-RGB555X"> - <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry> - <entry>'RGBQ'</entry> + <row id="V4L2-PIX-FMT-ARGB555X"> + <entry><constant>V4L2_PIX_FMT_ARGB555X</constant></entry> + <entry>'AR15' | (1 << 31)</entry> <entry></entry> <entry>a</entry> <entry>r<subscript>4</subscript></entry> @@ -259,6 +259,28 @@ for a pixel lie next to each other in memory.</para> <entry>b<subscript>1</subscript></entry> <entry>b<subscript>0</subscript></entry> </row> + <row id="V4L2-PIX-FMT-XRGB555X"> + <entry><constant>V4L2_PIX_FMT_XRGB555X</constant></entry> + <entry>'XR15' | (1 << 31)</entry> + <entry></entry> + <entry>-</entry> + <entry>r<subscript>4</subscript></entry> + <entry>r<subscript>3</subscript></entry> + <entry>r<subscript>2</subscript></entry> + <entry>r<subscript>1</subscript></entry> + <entry>r<subscript>0</subscript></entry> + <entry>g<subscript>4</subscript></entry> + <entry>g<subscript>3</subscript></entry> + <entry></entry> + <entry>g<subscript>2</subscript></entry> + <entry>g<subscript>1</subscript></entry> + <entry>g<subscript>0</subscript></entry> + <entry>b<subscript>4</subscript></entry> + <entry>b<subscript>3</subscript></entry> + <entry>b<subscript>2</subscript></entry> + <entry>b<subscript>1</subscript></entry> + <entry>b<subscript>0</subscript></entry> + </row> <row id="V4L2-PIX-FMT-RGB565X"> <entry><constant>V4L2_PIX_FMT_RGB565X</constant></entry> <entry>'RGBR'</entry> @@ -464,7 +486,7 @@ for a pixel lie next to each other in memory.</para> </row> <row id="V4L2-PIX-FMT-ARGB32"> <entry><constant>V4L2_PIX_FMT_ARGB32</constant></entry> - <entry>'AX24'</entry> + <entry>'BA24'</entry> <entry></entry> <entry>a<subscript>7</subscript></entry> <entry>a<subscript>6</subscript></entry> @@ -800,6 +822,28 @@ image</title> <entry>g<subscript>4</subscript></entry> <entry>g<subscript>3</subscript></entry> </row> + <row id="V4L2-PIX-FMT-RGB555X"> + <entry><constant>V4L2_PIX_FMT_RGB555X</constant></entry> + <entry>'RGBQ'</entry> + <entry></entry> + <entry>a</entry> + <entry>r<subscript>4</subscript></entry> + <entry>r<subscript>3</subscript></entry> + <entry>r<subscript>2</subscript></entry> + <entry>r<subscript>1</subscript></entry> + <entry>r<subscript>0</subscript></entry> + <entry>g<subscript>4</subscript></entry> + <entry>g<subscript>3</subscript></entry> + <entry></entry> + <entry>g<subscript>2</subscript></entry> + <entry>g<subscript>1</subscript></entry> + <entry>g<subscript>0</subscript></entry> + <entry>b<subscript>4</subscript></entry> + <entry>b<subscript>3</subscript></entry> + <entry>b<subscript>2</subscript></entry> + <entry>b<subscript>1</subscript></entry> + <entry>b<subscript>0</subscript></entry> + </row> <row id="V4L2-PIX-FMT-BGR32"> <entry><constant>V4L2_PIX_FMT_BGR32</constant></entry> <entry>'BGR4'</entry> diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml index cb7732582f03..b036f8963353 100644 --- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml +++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml @@ -76,21 +76,22 @@ <entry></entry> <entry>&v4l2-event-vsync;</entry> <entry><structfield>vsync</structfield></entry> - <entry>Event data for event V4L2_EVENT_VSYNC. + <entry>Event data for event <constant>V4L2_EVENT_VSYNC</constant>. </entry> </row> <row> <entry></entry> <entry>&v4l2-event-ctrl;</entry> <entry><structfield>ctrl</structfield></entry> - <entry>Event data for event V4L2_EVENT_CTRL. + <entry>Event data for event <constant>V4L2_EVENT_CTRL</constant>. </entry> </row> <row> <entry></entry> <entry>&v4l2-event-frame-sync;</entry> <entry><structfield>frame_sync</structfield></entry> - <entry>Event data for event V4L2_EVENT_FRAME_SYNC.</entry> + <entry>Event data for event + <constant>V4L2_EVENT_FRAME_SYNC</constant>.</entry> </row> <row> <entry></entry> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml index ce4563b87131..6df40db4c8ba 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-edid.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-edid.xml @@ -24,7 +24,7 @@ <funcdef>int <function>ioctl</function></funcdef> <paramdef>int <parameter>fd</parameter></paramdef> <paramdef>int <parameter>request</parameter></paramdef> - <paramdef>const struct v4l2_edid *<parameter>argp</parameter></paramdef> + <paramdef>struct v4l2_edid *<parameter>argp</parameter></paramdef> </funcprototype> </funcsynopsis> </refsynopsisdiv> @@ -125,17 +125,17 @@ <structfield>blocks</structfield> is 0, then the EDID is disabled or erased.</entry> </row> <row> - <entry>__u8 *</entry> - <entry><structfield>edid</structfield></entry> - <entry>Pointer to memory that contains the EDID. The minimum size is - <structfield>blocks</structfield> * 128.</entry> - </row> - <row> <entry>__u32</entry> <entry><structfield>reserved</structfield>[5]</entry> <entry>Reserved for future extensions. Applications and drivers must set the array to zero.</entry> </row> + <row> + <entry>__u8 *</entry> + <entry><structfield>edid</structfield></entry> + <entry>Pointer to memory that contains the EDID. The minimum size is + <structfield>blocks</structfield> * 128.</entry> + </row> </tbody> </tgroup> </table> diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml index 9f6095608837..d7c9365ecdbe 100644 --- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml +++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml @@ -176,7 +176,7 @@ </row> <row> <entry><constant>V4L2_EVENT_MOTION_DET</constant></entry> - <entry>5</entry> + <entry>6</entry> <entry> <para>Triggered whenever the motion detection state for one or more of the regions changes. This event has a &v4l2-event-motion-det; associated with it.</para> diff --git a/Documentation/devicetree/bindings/media/hix5hd2-ir.txt b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt new file mode 100644 index 000000000000..fb5e7606643a --- /dev/null +++ b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt @@ -0,0 +1,25 @@ +Device-Tree bindings for hix5hd2 ir IP + +Required properties: + - compatible: Should contain "hisilicon,hix5hd2-ir". + - reg: Base physical address of the controller and length of memory + mapped region. + - interrupts: interrupt-specifier for the sole interrupt generated by + the device. The interrupt specifier format depends on the interrupt + controller parent. + - clocks: clock phandle and specifier pair. + - hisilicon,power-syscon: phandle of syscon used to control power. + +Optional properties: + - linux,rc-map-name : Remote control map name. + +Example node: + + ir: ir@f8001000 { + compatible = "hisilicon,hix5hd2-ir"; + reg = <0xf8001000 0x1000>; + interrupts = <0 47 4>; + clocks = <&clock HIX5HD2_FIXED_24M>; + hisilicon,power-syscon = <&sysctrl>; + linux,rc-map-name = "rc-tivo"; + }; diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware index 26c623dd3aa3..91b43d2738c7 100755 --- a/Documentation/dvb/get_dvb_firmware +++ b/Documentation/dvb/get_dvb_firmware @@ -708,23 +708,25 @@ sub drxk_terratec_htc_stick { } sub it9135 { - my $sourcefile = "dvb-usb-it9135.zip"; - my $url = "http://www.ite.com.tw/uploads/firmware/v3.6.0.0/$sourcefile"; - my $hash = "1e55f6c8833f1d0ae067c2bb2953e6a9"; - my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0); - my $outfile = "dvb-usb-it9135.fw"; + my $url = "http://www.ite.com.tw/uploads/firmware/v3.25.0.0/"; + my $file1 = "dvb-usb-it9135-01.zip"; my $fwfile1 = "dvb-usb-it9135-01.fw"; + my $hash1 = "02fcf11174eda84745dae7e61c5ff9ba"; + my $file2 = "dvb-usb-it9135-02.zip"; my $fwfile2 = "dvb-usb-it9135-02.fw"; + my $hash2 = "d5e1437dc24358578e07999475d4cac9"; checkstandard(); - wgetfile($sourcefile, $url); - unzip($sourcefile, $tmpdir); - verify("$tmpdir/$outfile", $hash); - extract("$tmpdir/$outfile", 64, 8128, "$fwfile1"); - extract("$tmpdir/$outfile", 12866, 5817, "$fwfile2"); + wgetfile($file1, $url . $file1); + unzip($file1, ""); + verify("$fwfile1", $hash1); + + wgetfile($file2, $url . $file2); + unzip($file2, ""); + verify("$fwfile2", $hash2); - "$fwfile1 $fwfile2" + "$file1 $file2" } sub tda10071 { diff --git a/Documentation/video4linux/vivid.txt b/Documentation/video4linux/vivid.txt new file mode 100644 index 000000000000..eeb11a28e4fc --- /dev/null +++ b/Documentation/video4linux/vivid.txt @@ -0,0 +1,1111 @@ +vivid: Virtual Video Test Driver +================================ + +This driver emulates video4linux hardware of various types: video capture, video +output, vbi capture and output, radio receivers and transmitters and a software +defined radio receiver. In addition a simple framebuffer device is available for +testing capture and output overlays. + +Up to 64 vivid instances can be created, each with up to 16 inputs and 16 outputs. + +Each input can be a webcam, TV capture device, S-Video capture device or an HDMI +capture device. Each output can be an S-Video output device or an HDMI output +device. + +These inputs and outputs act exactly as a real hardware device would behave. This +allows you to use this driver as a test input for application development, since +you can test the various features without requiring special hardware. + +This document describes the features implemented by this driver: + +- Support for read()/write(), MMAP, USERPTR and DMABUF streaming I/O. +- A large list of test patterns and variations thereof +- Working brightness, contrast, saturation and hue controls +- Support for the alpha color component +- Full colorspace support, including limited/full RGB range +- All possible control types are present +- Support for various pixel aspect ratios and video aspect ratios +- Error injection to test what happens if errors occur +- Supports crop/compose/scale in any combination for both input and output +- Can emulate up to 4K resolutions +- All Field settings are supported for testing interlaced capturing +- Supports all standard YUV and RGB formats, including two multiplanar YUV formats +- Raw and Sliced VBI capture and output support +- Radio receiver and transmitter support, including RDS support +- Software defined radio (SDR) support +- Capture and output overlay support + +These features will be described in more detail below. + + +Table of Contents +----------------- + +Section 1: Configuring the driver +Section 2: Video Capture +Section 2.1: Webcam Input +Section 2.2: TV and S-Video Inputs +Section 2.3: HDMI Input +Section 3: Video Output +Section 3.1: S-Video Output +Section 3.2: HDMI Output +Section 4: VBI Capture +Section 5: VBI Output +Section 6: Radio Receiver +Section 7: Radio Transmitter +Section 8: Software Defined Radio Receiver +Section 9: Controls +Section 9.1: User Controls - Test Controls +Section 9.2: User Controls - Video Capture +Section 9.3: User Controls - Audio +Section 9.4: Vivid Controls +Section 9.4.1: Test Pattern Controls +Section 9.4.2: Capture Feature Selection Controls +Section 9.4.3: Output Feature Selection Controls +Section 9.4.4: Error Injection Controls +Section 9.4.5: VBI Raw Capture Controls +Section 9.5: Digital Video Controls +Section 9.6: FM Radio Receiver Controls +Section 9.7: FM Radio Modulator +Section 10: Video, VBI and RDS Looping +Section 10.1: Video and Sliced VBI looping +Section 10.2: Radio & RDS Looping +Section 11: Cropping, Composing, Scaling +Section 12: Formats +Section 13: Capture Overlay +Section 14: Output Overlay +Section 15: Some Future Improvements + + +Section 1: Configuring the driver +--------------------------------- + +By default the driver will create a single instance that has a video capture +device with webcam, TV, S-Video and HDMI inputs, a video output device with +S-Video and HDMI outputs, one vbi capture device, one vbi output device, one +radio receiver device, one radio transmitter device and one SDR device. + +The number of instances, devices, video inputs and outputs and their types are +all configurable using the following module options: + +n_devs: number of driver instances to create. By default set to 1. Up to 64 + instances can be created. + +node_types: which devices should each driver instance create. An array of + hexadecimal values, one for each instance. The default is 0x1d3d. + Each value is a bitmask with the following meaning: + bit 0: Video Capture node + bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both + bit 4: Radio Receiver node + bit 5: Software Defined Radio Receiver node + bit 8: Video Output node + bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both + bit 12: Radio Transmitter node + bit 16: Framebuffer for testing overlays + + So to create four instances, the first two with just one video capture + device, the second two with just one video output device you would pass + these module options to vivid: + + n_devs=4 node_types=0x1,0x1,0x100,0x100 + +num_inputs: the number of inputs, one for each instance. By default 4 inputs + are created for each video capture device. At most 16 inputs can be created, + and there must be at least one. + +input_types: the input types for each instance, the default is 0xe4. This defines + what the type of each input is when the inputs are created for each driver + instance. This is a hexadecimal value with up to 16 pairs of bits, each + pair gives the type and bits 0-1 map to input 0, bits 2-3 map to input 1, + 30-31 map to input 15. Each pair of bits has the following meaning: + + 00: this is a webcam input + 01: this is a TV tuner input + 10: this is an S-Video input + 11: this is an HDMI input + + So to create a video capture device with 8 inputs where input 0 is a TV + tuner, inputs 1-3 are S-Video inputs and inputs 4-7 are HDMI inputs you + would use the following module options: + + num_inputs=8 input_types=0xffa9 + +num_outputs: the number of outputs, one for each instance. By default 2 outputs + are created for each video output device. At most 16 outputs can be + created, and there must be at least one. + +output_types: the output types for each instance, the default is 0x02. This defines + what the type of each output is when the outputs are created for each + driver instance. This is a hexadecimal value with up to 16 bits, each bit + gives the type and bit 0 maps to output 0, bit 1 maps to output 1, bit + 15 maps to output 15. The meaning of each bit is as follows: + + 0: this is an S-Video output + 1: this is an HDMI output + + So to create a video output device with 8 outputs where outputs 0-3 are + S-Video outputs and outputs 4-7 are HDMI outputs you would use the + following module options: + + num_outputs=8 output_types=0xf0 + +vid_cap_nr: give the desired videoX start number for each video capture device. + The default is -1 which will just take the first free number. This allows + you to map capture video nodes to specific videoX device nodes. Example: + + n_devs=4 vid_cap_nr=2,4,6,8 + + This will attempt to assign /dev/video2 for the video capture device of + the first vivid instance, video4 for the next up to video8 for the last + instance. If it can't succeed, then it will just take the next free + number. + +vid_out_nr: give the desired videoX start number for each video output device. + The default is -1 which will just take the first free number. + +vbi_cap_nr: give the desired vbiX start number for each vbi capture device. + The default is -1 which will just take the first free number. + +vbi_out_nr: give the desired vbiX start number for each vbi output device. + The default is -1 which will just take the first free number. + +radio_rx_nr: give the desired radioX start number for each radio receiver device. + The default is -1 which will just take the first free number. + +radio_tx_nr: give the desired radioX start number for each radio transmitter + device. The default is -1 which will just take the first free number. + +sdr_cap_nr: give the desired swradioX start number for each SDR capture device. + The default is -1 which will just take the first free number. + +ccs_cap_mode: specify the allowed video capture crop/compose/scaling combination + for each driver instance. Video capture devices can have any combination + of cropping, composing and scaling capabilities and this will tell the + vivid driver which of those is should emulate. By default the user can + select this through controls. + + The value is either -1 (controlled by the user) or a set of three bits, + each enabling (1) or disabling (0) one of the features: + + bit 0: Enable crop support. Cropping will take only part of the + incoming picture. + bit 1: Enable compose support. Composing will copy the incoming + picture into a larger buffer. + bit 2: Enable scaling support. Scaling can scale the incoming + picture. The scaler of the vivid driver can enlarge up + or down to four times the original size. The scaler is + very simple and low-quality. Simplicity and speed were + key, not quality. + + Note that this value is ignored by webcam inputs: those enumerate + discrete framesizes and that is incompatible with cropping, composing + or scaling. + +ccs_out_mode: specify the allowed video output crop/compose/scaling combination + for each driver instance. Video output devices can have any combination + of cropping, composing and scaling capabilities and this will tell the + vivid driver which of those is should emulate. By default the user can + select this through controls. + + The value is either -1 (controlled by the user) or a set of three bits, + each enabling (1) or disabling (0) one of the features: + + bit 0: Enable crop support. Cropping will take only part of the + outgoing buffer. + bit 1: Enable compose support. Composing will copy the incoming + buffer into a larger picture frame. + bit 2: Enable scaling support. Scaling can scale the incoming + buffer. The scaler of the vivid driver can enlarge up + or down to four times the original size. The scaler is + very simple and low-quality. Simplicity and speed were + key, not quality. + +multiplanar: select whether each device instance supports multi-planar formats, + and thus the V4L2 multi-planar API. By default the first device instance + is single-planar, the second multi-planar, and it keeps alternating. + + This module option can override that for each instance. Values are: + + 0: use alternating single and multi-planar devices. + 1: this is a single-planar instance. + 2: this is a multi-planar instance. + +vivid_debug: enable driver debugging info + +no_error_inj: if set disable the error injecting controls. This option is + needed in order to run a tool like v4l2-compliance. Tools like that + exercise all controls including a control like 'Disconnect' which + emulates a USB disconnect, making the device inaccessible and so + all tests that v4l2-compliance is doing will fail afterwards. + + There may be other situations as well where you want to disable the + error injection support of vivid. When this option is set, then the + controls that select crop, compose and scale behavior are also + removed. Unless overridden by ccs_cap_mode and/or ccs_out_mode the + will default to enabling crop, compose and scaling. + +Taken together, all these module options allow you to precisely customize +the driver behavior and test your application with all sorts of permutations. +It is also very suitable to emulate hardware that is not yet available, e.g. +when developing software for a new upcoming device. + + +Section 2: Video Capture +------------------------ + +This is probably the most frequently used feature. The video capture device +can be configured by using the module options num_inputs, input_types and +ccs_cap_mode (see section 1 for more detailed information), but by default +four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI +input, one input for each input type. Those are described in more detail +below. + +Special attention has been given to the rate at which new frames become +available. The jitter will be around 1 jiffie (that depends on the HZ +configuration of your kernel, so usually 1/100, 1/250 or 1/1000 of a second), +but the long-term behavior is exactly following the framerate. So a +framerate of 59.94 Hz is really different from 60 Hz. If the framerate +exceeds your kernel's HZ value, then you will get dropped frames, but the +frame/field sequence counting will keep track of that so the sequence +count will skip whenever frames are dropped. + + +Section 2.1: Webcam Input +------------------------- + +The webcam input supports three framesizes: 320x180, 640x360 and 1280x720. It +supports frames per second settings of 10, 15, 25, 30, 50 and 60 fps. Which ones +are available depends on the chosen framesize: the larger the framesize, the +lower the maximum frames per second. + +The initially selected colorspace when you switch to the webcam input will be +sRGB. + + +Section 2.2: TV and S-Video Inputs +---------------------------------- + +The only difference between the TV and S-Video input is that the TV has a +tuner. Otherwise they behave identically. + +These inputs support audio inputs as well: one TV and one Line-In. They +both support all TV standards. If the standard is queried, then the Vivid +controls 'Standard Signal Mode' and 'Standard' determine what +the result will be. + +These inputs support all combinations of the field setting. Special care has +been taken to faithfully reproduce how fields are handled for the different +TV standards. This is particularly noticable when generating a horizontally +moving image so the temporal effect of using interlaced formats becomes clearly +visible. For 50 Hz standards the top field is the oldest and the bottom field +is the newest in time. For 60 Hz standards that is reversed: the bottom field +is the oldest and the top field is the newest in time. + +When you start capturing in V4L2_FIELD_ALTERNATE mode the first buffer will +contain the top field for 50 Hz standards and the bottom field for 60 Hz +standards. This is what capture hardware does as well. + +Finally, for PAL/SECAM standards the first half of the top line contains noise. +This simulates the Wide Screen Signal that is commonly placed there. + +The initially selected colorspace when you switch to the TV or S-Video input +will be SMPTE-170M. + +The pixel aspect ratio will depend on the TV standard. The video aspect ratio +can be selected through the 'Standard Aspect Ratio' Vivid control. +Choices are '4x3', '16x9' which will give letterboxed widescreen video and +'16x9 Anomorphic' which will give full screen squashed anamorphic widescreen +video that will need to be scaled accordingly. + +The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available +every 6 MHz, starting from 49.25 MHz. For each channel the generated image +will be in color for the +/- 0.25 MHz around it, and in grayscale for ++/- 1 MHz around the channel. Beyond that it is just noise. The VIDIOC_G_TUNER +ioctl will return 100% signal strength for +/- 0.25 MHz and 50% for +/- 1 MHz. +It will also return correct afc values to show whether the frequency is too +low or too high. + +The audio subchannels that are returned are MONO for the +/- 1 MHz range around +a valid channel frequency. When the frequency is within +/- 0.25 MHz of the +channel it will return either MONO, STEREO, either MONO | SAP (for NTSC) or +LANG1 | LANG2 (for others), or STEREO | SAP. + +Which one is returned depends on the chosen channel, each next valid channel +will cycle through the possible audio subchannel combinations. This allows +you to test the various combinations by just switching channels.. + +Finally, for these inputs the v4l2_timecode struct is filled in in the +dequeued v4l2_buffer struct. + + +Section 2.3: HDMI Input +----------------------- + +The HDMI inputs supports all CEA-861 and DMT timings, both progressive and +interlaced, for pixelclock frequencies between 25 and 600 MHz. The field +mode for interlaced formats is always V4L2_FIELD_ALTERNATE. For HDMI the +field order is always top field first, and when you start capturing an +interlaced format you will receive the top field first. + +The initially selected colorspace when you switch to the HDMI input or +select an HDMI timing is based on the format resolution: for resolutions +less than or equal to 720x576 the colorspace is set to SMPTE-170M, for +others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings). + +The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it +set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV +standard, and for all others a 1:1 pixel aspect ratio is returned. + +The video aspect ratio can be selected through the 'DV Timings Aspect Ratio' +Vivid control. Choices are 'Source Width x Height' (just use the +same ratio as the chosen format), '4x3' or '16x9', either of which can +result in pillarboxed or letterboxed video. + +For HDMI inputs it is possible to set the EDID. By default a simple EDID +is provided. You can only set the EDID for HDMI inputs. Internally, however, +the EDID is shared between all HDMI inputs. + +No interpretation is done of the EDID data. + + +Section 3: Video Output +----------------------- + +The video output device can be configured by using the module options +num_outputs, output_types and ccs_out_mode (see section 1 for more detailed +information), but by default two outputs are configured: an S-Video and an +HDMI input, one output for each output type. Those are described in more detail +below. + +Like with video capture the framerate is also exact in the long term. + + +Section 3.1: S-Video Output +--------------------------- + +This output supports audio outputs as well: "Line-Out 1" and "Line-Out 2". +The S-Video output supports all TV standards. + +This output supports all combinations of the field setting. + +The initially selected colorspace when you switch to the TV or S-Video input +will be SMPTE-170M. + + +Section 3.2: HDMI Output +------------------------ + +The HDMI output supports all CEA-861 and DMT timings, both progressive and +interlaced, for pixelclock frequencies between 25 and 600 MHz. The field +mode for interlaced formats is always V4L2_FIELD_ALTERNATE. + +The initially selected colorspace when you switch to the HDMI output or +select an HDMI timing is based on the format resolution: for resolutions +less than or equal to 720x576 the colorspace is set to SMPTE-170M, for +others it is set to REC-709 (CEA-861 timings) or sRGB (VESA DMT timings). + +The pixel aspect ratio will depend on the HDMI timing: for 720x480 is it +set as for the NTSC TV standard, for 720x576 it is set as for the PAL TV +standard, and for all others a 1:1 pixel aspect ratio is returned. + +An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID. + + +Section 4: VBI Capture +---------------------- + +There are three types of VBI capture devices: those that only support raw +(undecoded) VBI, those that only support sliced (decoded) VBI and those that +support both. This is determined by the node_types module option. In all +cases the driver will generate valid VBI data: for 60 Hz standards it will +generate Closed Caption and XDS data. The closed caption stream will +alternate between "Hello world!" and "Closed captions test" every second. +The XDS stream will give the current time once a minute. For 50 Hz standards +it will generate the Wide Screen Signal which is based on the actual Video +Aspect Ratio control setting and teletext pages 100-159, one page per frame. + +The VBI device will only work for the S-Video and TV inputs, it will give +back an error if the current input is a webcam or HDMI. + + +Section 5: VBI Output +--------------------- + +There are three types of VBI output devices: those that only support raw +(undecoded) VBI, those that only support sliced (decoded) VBI and those that +support both. This is determined by the node_types module option. + +The sliced VBI output supports the Wide Screen Signal and the teletext signal +for 50 Hz standards and Closed Captioning + XDS for 60 Hz standards. + +The VBI device will only work for the S-Video output, it will give +back an error if the current output is HDMI. + + +Section 6: Radio Receiver +------------------------- + +The radio receiver emulates an FM/AM/SW receiver. The FM band also supports RDS. +The frequency ranges are: + + FM: 64 MHz - 108 MHz + AM: 520 kHz - 1710 kHz + SW: 2300 kHz - 26.1 MHz + +Valid channels are emulated every 1 MHz for FM and every 100 kHz for AM and SW. +The signal strength decreases the further the frequency is from the valid +frequency until it becomes 0% at +/- 50 kHz (FM) or 5 kHz (AM/SW) from the +ideal frequency. The initial frequency when the driver is loaded is set to +95 MHz. + +The FM receiver supports RDS as well, both using 'Block I/O' and 'Controls' +modes. In the 'Controls' mode the RDS information is stored in read-only +controls. These controls are updated every time the frequency is changed, +or when the tuner status is requested. The Block I/O method uses the read() +interface to pass the RDS blocks on to the application for decoding. + +The RDS signal is 'detected' for +/- 12.5 kHz around the channel frequency, +and the further the frequency is away from the valid frequency the more RDS +errors are randomly introduced into the block I/O stream, up to 50% of all +blocks if you are +/- 12.5 kHz from the channel frequency. All four errors +can occur in equal proportions: blocks marked 'CORRECTED', blocks marked +'ERROR', blocks marked 'INVALID' and dropped blocks. + +The generated RDS stream contains all the standard fields contained in a +0B group, and also radio text and the current time. + +The receiver supports HW frequency seek, either in Bounded mode, Wrap Around +mode or both, which is configurable with the "Radio HW Seek Mode" control. + + +Section 7: Radio Transmitter +---------------------------- + +The radio transmitter emulates an FM/AM/SW transmitter. The FM band also supports RDS. +The frequency ranges are: + + FM: 64 MHz - 108 MHz + AM: 520 kHz - 1710 kHz + SW: 2300 kHz - 26.1 MHz + +The initial frequency when the driver is loaded is 95.5 MHz. + +The FM transmitter supports RDS as well, both using 'Block I/O' and 'Controls' +modes. In the 'Controls' mode the transmitted RDS information is configured +using controls, and in 'Block I/O' mode the blocks are passed to the driver +using write(). + + +Section 8: Software Defined Radio Receiver +------------------------------------------ + +The SDR receiver has three frequency bands for the ADC tuner: + + - 300 kHz + - 900 kHz - 2800 kHz + - 3200 kHz + +The RF tuner supports 50 MHz - 2000 MHz. + +The generated data contains the In-phase and Quadrature components of a +1 kHz tone that has an amplitude of sqrt(2). + + +Section 9: Controls +------------------- + +Different devices support different controls. The sections below will describe +each control and which devices support them. + + +Section 9.1: User Controls - Test Controls +------------------------------------------ + +The Button, Boolean, Integer 32 Bits, Integer 64 Bits, Menu, String, Bitmask and +Integer Menu are controls that represent all possible control types. The Menu +control and the Integer Menu control both have 'holes' in their menu list, +meaning that one or more menu items return EINVAL when VIDIOC_QUERYMENU is called. +Both menu controls also have a non-zero minimum control value. These features +allow you to check if your application can handle such things correctly. +These controls are supported for every device type. + + +Section 9.2: User Controls - Video Capture +------------------------------------------ + +The following controls are specific to video capture. + +The Brightness, Contrast, Saturation and Hue controls actually work and are +standard. There is one special feature with the Brightness control: each +video input has its own brightness value, so changing input will restore +the brightness for that input. In addition, each video input uses a different +brightness range (minimum and maximum control values). Switching inputs will +cause a control event to be sent with the V4L2_EVENT_CTRL_CH_RANGE flag set. +This allows you to test controls that can change their range. + +The 'Gain, Automatic' and Gain controls can be used to test volatile controls: +if 'Gain, Automatic' is set, then the Gain control is volatile and changes +constantly. If 'Gain, Automatic' is cleared, then the Gain control is a normal +control. + +The 'Horizontal Flip' and 'Vertical Flip' controls can be used to flip the +image. These combine with the 'Sensor Flipped Horizontally/Vertically' Vivid +controls. + +The 'Alpha Component' control can be used to set the alpha component for +formats containing an alpha channel. + + +Section 9.3: User Controls - Audio +---------------------------------- + +The following controls are specific to video capture and output and radio +receivers and transmitters. + +The 'Volume' and 'Mute' audio controls are typical for such devices to +control the volume and mute the audio. They don't actually do anything in +the vivid driver. + + +Section 9.4: Vivid Controls +--------------------------- + +These vivid custom controls control the image generation, error injection, etc. + + +Section 9.4.1: Test Pattern Controls +------------------------------------ + +The Test Pattern Controls are all specific to video capture. + +Test Pattern: selects which test pattern to use. Use the CSC Colorbar for + testing colorspace conversions: the colors used in that test pattern + map to valid colors in all colorspaces. The colorspace conversion + is disabled for the other test patterns. + +OSD Text Mode: selects whether the text superimposed on the + test pattern should be shown, and if so, whether only counters should + be displayed or the full text. + +Horizontal Movement: selects whether the test pattern should + move to the left or right and at what speed. + +Vertical Movement: does the same for the vertical direction. + +Show Border: show a two-pixel wide border at the edge of the actual image, + excluding letter or pillarboxing. + +Show Square: show a square in the middle of the image. If the image is + displayed with the correct pixel and image aspect ratio corrections, + then the width and height of the square on the monitor should be + the same. + +Insert SAV Code in Image: adds a SAV (Start of Active Video) code to the image. + This can be used to check if such codes in the image are inadvertently + interpreted instead of being ignored. + +Insert EAV Code in Image: does the same for the EAV (End of Active Video) code. + + +Section 9.4.2: Capture Feature Selection Controls +------------------------------------------------- + +These controls are all specific to video capture. + +Sensor Flipped Horizontally: the image is flipped horizontally and the + V4L2_IN_ST_HFLIP input status flag is set. This emulates the case where + a sensor is for example mounted upside down. + +Sensor Flipped Vertically: the image is flipped vertically and the + V4L2_IN_ST_VFLIP input status flag is set. This emulates the case where + a sensor is for example mounted upside down. + +Standard Aspect Ratio: selects if the image aspect ratio as used for the TV or + S-Video input should be 4x3, 16x9 or anamorphic widescreen. This may + introduce letterboxing. + +DV Timings Aspect Ratio: selects if the image aspect ratio as used for the HDMI + input should be the same as the source width and height ratio, or if + it should be 4x3 or 16x9. This may introduce letter or pillarboxing. + +Timestamp Source: selects when the timestamp for each buffer is taken. + +Colorspace: selects which colorspace should be used when generating the image. + This only applies if the CSC Colorbar test pattern is selected, + otherwise the test pattern will go through unconverted (except for + the so-called 'Transfer Function' corrections and the R'G'B' to Y'CbCr + conversion). This behavior is also what you want, since a 75% Colorbar + should really have 75% signal intensity and should not be affected + by colorspace conversions. + + Changing the colorspace will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a detected colorspace change. + +Limited RGB Range (16-235): selects if the RGB range of the HDMI source should + be limited or full range. This combines with the Digital Video 'Rx RGB + Quantization Range' control and can be used to test what happens if + a source provides you with the wrong quantization range information. + See the description of that control for more details. + +Apply Alpha To Red Only: apply the alpha channel as set by the 'Alpha Component' + user control to the red color of the test pattern only. + +Enable Capture Cropping: enables crop support. This control is only present if + the ccs_cap_mode module option is set to the default value of -1 and if + the no_error_inj module option is set to 0 (the default). + +Enable Capture Composing: enables composing support. This control is only + present if the ccs_cap_mode module option is set to the default value of + -1 and if the no_error_inj module option is set to 0 (the default). + +Enable Capture Scaler: enables support for a scaler (maximum 4 times upscaling + and downscaling). This control is only present if the ccs_cap_mode + module option is set to the default value of -1 and if the no_error_inj + module option is set to 0 (the default). + +Maximum EDID Blocks: determines how many EDID blocks the driver supports. + Note that the vivid driver does not actually interpret new EDID + data, it just stores it. It allows for up to 256 EDID blocks + which is the maximum supported by the standard. + +Fill Percentage of Frame: can be used to draw only the top X percent + of the image. Since each frame has to be drawn by the driver, this + demands a lot of the CPU. For large resolutions this becomes + problematic. By drawing only part of the image this CPU load can + be reduced. + + +Section 9.4.3: Output Feature Selection Controls +------------------------------------------------ + +These controls are all specific to video output. + +Enable Output Cropping: enables crop support. This control is only present if + the ccs_out_mode module option is set to the default value of -1 and if + the no_error_inj module option is set to 0 (the default). + +Enable Output Composing: enables composing support. This control is only + present if the ccs_out_mode module option is set to the default value of + -1 and if the no_error_inj module option is set to 0 (the default). + +Enable Output Scaler: enables support for a scaler (maximum 4 times upscaling + and downscaling). This control is only present if the ccs_out_mode + module option is set to the default value of -1 and if the no_error_inj + module option is set to 0 (the default). + + +Section 9.4.4: Error Injection Controls +--------------------------------------- + +The following two controls are only valid for video and vbi capture. + +Standard Signal Mode: selects the behavior of VIDIOC_QUERYSTD: what should + it return? + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a changed input condition (e.g. a cable + was plugged in or out). + +Standard: selects the standard that VIDIOC_QUERYSTD should return if the + previous control is set to "Selected Standard". + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a changed input standard. + + +The following two controls are only valid for video capture. + +DV Timings Signal Mode: selects the behavior of VIDIOC_QUERY_DV_TIMINGS: what + should it return? + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates a changed input condition (e.g. a cable + was plugged in or out). + +DV Timings: selects the timings the VIDIOC_QUERY_DV_TIMINGS should return + if the previous control is set to "Selected DV Timings". + + Changing this control will result in the V4L2_EVENT_SOURCE_CHANGE + to be sent since it emulates changed input timings. + + +The following controls are only present if the no_error_inj module option +is set to 0 (the default). These controls are valid for video and vbi +capture and output streams and for the SDR capture device except for the +Disconnect control which is valid for all devices. + +Wrap Sequence Number: test what happens when you wrap the sequence number in + struct v4l2_buffer around. + +Wrap Timestamp: test what happens when you wrap the timestamp in struct + v4l2_buffer around. + +Percentage of Dropped Buffers: sets the percentage of buffers that + are never returned by the driver (i.e., they are dropped). + +Disconnect: emulates a USB disconnect. The device will act as if it has + been disconnected. Only after all open filehandles to the device + node have been closed will the device become 'connected' again. + +Inject V4L2_BUF_FLAG_ERROR: when pressed, the next frame returned by + the driver will have the error flag set (i.e. the frame is marked + corrupt). + +Inject VIDIOC_REQBUFS Error: when pressed, the next REQBUFS or CREATE_BUFS + ioctl call will fail with an error. To be precise: the videobuf2 + queue_setup() op will return -EINVAL. + +Inject VIDIOC_QBUF Error: when pressed, the next VIDIOC_QBUF or + VIDIOC_PREPARE_BUFFER ioctl call will fail with an error. To be + precise: the videobuf2 buf_prepare() op will return -EINVAL. + +Inject VIDIOC_STREAMON Error: when pressed, the next VIDIOC_STREAMON ioctl + call will fail with an error. To be precise: the videobuf2 + start_streaming() op will return -EINVAL. + +Inject Fatal Streaming Error: when pressed, the streaming core will be + marked as having suffered a fatal error, the only way to recover + from that is to stop streaming. To be precise: the videobuf2 + vb2_queue_error() function is called. + + +Section 9.4.5: VBI Raw Capture Controls +--------------------------------------- + +Interlaced VBI Format: if set, then the raw VBI data will be interlaced instead + of providing it grouped by field. + + +Section 9.5: Digital Video Controls +----------------------------------- + +Rx RGB Quantization Range: sets the RGB quantization detection of the HDMI + input. This combines with the Vivid 'Limited RGB Range (16-235)' + control and can be used to test what happens if a source provides + you with the wrong quantization range information. This can be tested + by selecting an HDMI input, setting this control to Full or Limited + range and selecting the opposite in the 'Limited RGB Range (16-235)' + control. The effect is easy to see if the 'Gray Ramp' test pattern + is selected. + +Tx RGB Quantization Range: sets the RGB quantization detection of the HDMI + output. It is currently not used for anything in vivid, but most HDMI + transmitters would typically have this control. + +Transmit Mode: sets the transmit mode of the HDMI output to HDMI or DVI-D. This + affects the reported colorspace since DVI_D outputs will always use + sRGB. + + +Section 9.6: FM Radio Receiver Controls +--------------------------------------- + +RDS Reception: set if the RDS receiver should be enabled. + +RDS Program Type: +RDS PS Name: +RDS Radio Text: +RDS Traffic Announcement: +RDS Traffic Program: +RDS Music: these are all read-only controls. If RDS Rx I/O Mode is set to + "Block I/O", then they are inactive as well. If RDS Rx I/O Mode is set + to "Controls", then these controls report the received RDS data. Note + that the vivid implementation of this is pretty basic: they are only + updated when you set a new frequency or when you get the tuner status + (VIDIOC_G_TUNER). + +Radio HW Seek Mode: can be one of "Bounded", "Wrap Around" or "Both". This + determines if VIDIOC_S_HW_FREQ_SEEK will be bounded by the frequency + range or wrap-around or if it is selectable by the user. + +Radio Programmable HW Seek: if set, then the user can provide the lower and + upper bound of the HW Seek. Otherwise the frequency range boundaries + will be used. + +Generate RBDS Instead of RDS: if set, then generate RBDS (the US variant of + RDS) data instead of RDS (European-style RDS). This affects only the + PICODE and PTY codes. + +RDS Rx I/O Mode: this can be "Block I/O" where the RDS blocks have to be read() + by the application, or "Controls" where the RDS data is provided by + the RDS controls mentioned above. + + +Section 9.7: FM Radio Modulator Controls +---------------------------------------- + +RDS Program ID: +RDS Program Type: +RDS PS Name: +RDS Radio Text: +RDS Stereo: +RDS Artificial Head: +RDS Compressed: +RDS Dymanic PTY: +RDS Traffic Announcement: +RDS Traffic Program: +RDS Music: these are all controls that set the RDS data that is transmitted by + the FM modulator. + +RDS Tx I/O Mode: this can be "Block I/O" where the application has to use write() + to pass the RDS blocks to the driver, or "Controls" where the RDS data is + provided by the RDS controls mentioned above. + + +Section 10: Video, VBI and RDS Looping +-------------------------------------- + +The vivid driver supports looping of video output to video input, VBI output +to VBI input and RDS output to RDS input. For video/VBI looping this emulates +as if a cable was hooked up between the output and input connector. So video +and VBI looping is only supported between S-Video and HDMI inputs and outputs. +VBI is only valid for S-Video as it makes no sense for HDMI. + +Since radio is wireless this looping always happens if the radio receiver +frequency is close to the radio transmitter frequency. In that case the radio +transmitter will 'override' the emulated radio stations. + +Looping is currently supported only between devices created by the same +vivid driver instance. + + +Section 10.1: Video and Sliced VBI looping +------------------------------------------ + +The way to enable video/VBI looping is currently fairly crude. A 'Loop Video' +control is available in the "Vivid" control class of the video +output and VBI output devices. When checked the video looping will be enabled. +Once enabled any video S-Video or HDMI input will show a static test pattern +until the video output has started. At that time the video output will be +looped to the video input provided that: + +- the input type matches the output type. So the HDMI input cannot receive + video from the S-Video output. + +- the video resolution of the video input must match that of the video output. + So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz + (720x480) S-Video input, or a 720p60 HDMI output to a 1080p30 input. + +- the pixel formats must be identical on both sides. Otherwise the driver would + have to do pixel format conversion as well, and that's taking things too far. + +- the field settings must be identical on both sides. Same reason as above: + requiring the driver to convert from one field format to another complicated + matters too much. This also prohibits capturing with 'Field Top' or 'Field + Bottom' when the output video is set to 'Field Alternate'. This combination, + while legal, became too complicated to support. Both sides have to be 'Field + Alternate' for this to work. Also note that for this specific case the + sequence and field counting in struct v4l2_buffer on the capture side may not + be 100% accurate. + +- on the input side the "Standard Signal Mode" for the S-Video input or the + "DV Timings Signal Mode" for the HDMI input should be configured so that a + valid signal is passed to the video input. + +The framerates do not have to match, although this might change in the future. + +By default you will see the OSD text superimposed on top of the looped video. +This can be turned off by changing the "OSD Text Mode" control of the video +capture device. + +For VBI looping to work all of the above must be valid and in addition the vbi +output must be configured for sliced VBI. The VBI capture side can be configured +for either raw or sliced VBI. Note that at the moment only CC/XDS (60 Hz formats) +and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped. + + +Section 10.2: Radio & RDS Looping +--------------------------------- + +As mentioned in section 6 the radio receiver emulates stations are regular +frequency intervals. Depending on the frequency of the radio receiver a +signal strength value is calculated (this is returned by VIDIOC_G_TUNER). +However, it will also look at the frequency set by the radio transmitter and +if that results in a higher signal strength than the settings of the radio +transmitter will be used as if it was a valid station. This also includes +the RDS data (if any) that the transmitter 'transmits'. This is received +faithfully on the receiver side. Note that when the driver is loaded the +frequencies of the radio receiver and transmitter are not identical, so +initially no looping takes place. + + +Section 11: Cropping, Composing, Scaling +---------------------------------------- + +This driver supports cropping, composing and scaling in any combination. Normally +which features are supported can be selected through the Vivid controls, +but it is also possible to hardcode it when the module is loaded through the +ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of +these module options. + +This allows you to test your application for all these variations. + +Note that the webcam input never supports cropping, composing or scaling. That +only applies to the TV/S-Video/HDMI inputs and outputs. The reason is that +webcams, including this virtual implementation, normally use +VIDIOC_ENUM_FRAMESIZES to list a set of discrete framesizes that it supports. +And that does not combine with cropping, composing or scaling. This is +primarily a limitation of the V4L2 API which is carefully reproduced here. + +The minimum and maximum resolutions that the scaler can achieve are 16x16 and +(4096 * 4) x (2160 x 4), but it can only scale up or down by a factor of 4 or +less. So for a source resolution of 1280x720 the minimum the scaler can do is +320x180 and the maximum is 5120x2880. You can play around with this using the +qv4l2 test tool and you will see these dependencies. + +This driver also supports larger 'bytesperline' settings, something that +VIDIOC_S_FMT allows but that few drivers implement. + +The scaler is a simple scaler that uses the Coarse Bresenham algorithm. It's +designed for speed and simplicity, not quality. + +If the combination of crop, compose and scaling allows it, then it is possible +to change crop and compose rectangles on the fly. + + +Section 12: Formats +------------------- + +The driver supports all the regular packed YUYV formats, 16, 24 and 32 RGB +packed formats and two multiplanar formats (one luma and one chroma plane). + +The alpha component can be set through the 'Alpha Component' User control +for those formats that support it. If the 'Apply Alpha To Red Only' control +is set, then the alpha component is only used for the color red and set to +0 otherwise. + +The driver has to be configured to support the multiplanar formats. By default +the first driver instance is single-planar, the second is multi-planar, and it +keeps alternating. This can be changed by setting the multiplanar module option, +see section 1 for more details on that option. + +If the driver instance is using the multiplanar formats/API, then the first +single planar format (YUYV) and the multiplanar NV16M and NV61M formats the +will have a plane that has a non-zero data_offset of 128 bytes. It is rare for +data_offset to be non-zero, so this is a useful feature for testing applications. + +Video output will also honor any data_offset that the application set. + + +Section 13: Capture Overlay +--------------------------- + +Note: capture overlay support is implemented primarily to test the existing +V4L2 capture overlay API. In practice few if any GPUs support such overlays +anymore, and neither are they generally needed anymore since modern hardware +is so much more capable. By setting flag 0x10000 in the node_types module +option the vivid driver will create a simple framebuffer device that can be +used for testing this API. Whether this API should be used for new drivers is +questionable. + +This driver has support for a destructive capture overlay with bitmap clipping +and list clipping (up to 16 rectangles) capabilities. Overlays are not +supported for multiplanar formats. It also honors the struct v4l2_window field +setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is +FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay. + +The overlay only works if you are also capturing at that same time. This is a +vivid limitation since it copies from a buffer to the overlay instead of +filling the overlay directly. And if you are not capturing, then no buffers +are available to fill. + +In addition, the pixelformat of the capture format and that of the framebuffer +must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return +an error. + +In order to really see what it going on you will need to create two vivid +instances: the first with a framebuffer enabled. You configure the capture +overlay of the second instance to use the framebuffer of the first, then +you start capturing in the second instance. For the first instance you setup +the output overlay for the video output, turn on video looping and capture +to see the blended framebuffer overlay that's being written to by the second +instance. This setup would require the following commands: + + $ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1 multiplanar=1,1 + $ v4l2-ctl -d1 --find-fb + /dev/fb1 is the framebuffer associated with base address 0x12800000 + $ sudo v4l2-ctl -d2 --set-fbuf fb=1 + $ v4l2-ctl -d1 --set-fbuf fb=1 + $ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15' + $ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15' + $ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15' + $ v4l2-ctl -d0 -i2 + $ v4l2-ctl -d2 -i2 + $ v4l2-ctl -d2 -c horizontal_movement=4 + $ v4l2-ctl -d1 --overlay=1 + $ v4l2-ctl -d1 -c loop_video=1 + $ v4l2-ctl -d2 --stream-mmap --overlay=1 + +And from another console: + + $ v4l2-ctl -d1 --stream-out-mmap + +And yet another console: + + $ qv4l2 + +and start streaming. + +As you can see, this is not for the faint of heart... + + +Section 14: Output Overlay +-------------------------- + +Note: output overlays are primarily implemented in order to test the existing +V4L2 output overlay API. Whether this API should be used for new drivers is +questionable. + +This driver has support for an output overlay and is capable of: + + - bitmap clipping, + - list clipping (up to 16 rectangles) + - chromakey + - source chromakey + - global alpha + - local alpha + - local inverse alpha + +Output overlays are not supported for multiplanar formats. In addition, the +pixelformat of the capture format and that of the framebuffer must be the +same for the overlay to work. Otherwise VIDIOC_OVERLAY will return an error. + +Output overlays only work if the driver has been configured to create a +framebuffer by setting flag 0x10000 in the node_types module option. The +created framebuffer has a size of 720x576 and supports ARGB 1:5:5:5 and +RGB 5:6:5. + +In order to see the effects of the various clipping, chromakeying or alpha +processing capabilities you need to turn on video looping and see the results +on the capture side. The use of the clipping, chromakeying or alpha processing +capabilities will slow down the video loop considerably as a lot of checks have +to be done per pixel. + + +Section 15: Some Future Improvements +------------------------------------ + +Just as a reminder and in no particular order: + +- Add a virtual alsa driver to test audio +- Add virtual sub-devices and media controller support +- Some support for testing compressed video +- Add support to loop raw VBI output to raw VBI input +- Add support to loop teletext sliced VBI output to VBI input +- Fix sequence/field numbering when looping of video with alternate fields +- Add support for V4L2_CID_BG_COLOR for video outputs +- Add ARGB888 overlay support: better testing of the alpha channel +- Add custom DV timings support +- Add support for V4L2_DV_FL_REDUCED_FPS +- Improve pixel aspect support in the tpg code by passing a real v4l2_fract +- Use per-queue locks and/or per-device locks to improve throughput +- Add support to loop from a specific output to a specific input across + vivid instances +- Add support for VIDIOC_EXPBUF once support for that has been added to vb2 +- The SDR radio should use the same 'frequencies' for stations as the normal + radio receiver, and give back noise if the frequency doesn't match up with + a station frequency +- Improve the sine generation of the SDR radio. +- Make a thread for the RDS generation, that would help in particular for the + "Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated + in real-time. diff --git a/MAINTAINERS b/MAINTAINERS index f10ed3914ea8..e95e8be7376a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4177,6 +4177,16 @@ L: linuxppc-dev@lists.ozlabs.org S: Odd Fixes F: drivers/tty/hvc/ +HACKRF MEDIA DRIVER +M: Antti Palosaari <crope@iki.fi> +L: linux-media@vger.kernel.org +W: http://linuxtv.org/ +W: http://palosaari.fi/linux/ +Q: http://patchwork.linuxtv.org/project/linux-media/list/ +T: git git://linuxtv.org/anttip/media_tree.git +S: Maintained +F: drivers/media/usb/hackrf/ + HARDWARE MONITORING M: Jean Delvare <jdelvare@suse.de> M: Guenter Roeck <linux@roeck-us.net> @@ -5070,7 +5080,7 @@ W: http://palosaari.fi/linux/ Q: http://patchwork.linuxtv.org/project/linux-media/list/ T: git git://linuxtv.org/anttip/media_tree.git S: Maintained -F: drivers/media/tuners/tuner_it913x* +F: drivers/media/tuners/it913x* IVTV VIDEO4LINUX DRIVER M: Andy Walls <awalls@md.metrocast.net> @@ -8588,6 +8598,14 @@ F: include/sound/dmaengine_pcm.h F: sound/core/pcm_dmaengine.c F: sound/soc/soc-generic-dmaengine-pcm.c +SP2 MEDIA DRIVER +M: Olli Salonen <olli.salonen@iki.fi> +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/sp2* + SPARC + UltraSPARC (sparc/sparc64) M: "David S. Miller" <davem@davemloft.net> L: sparclinux@vger.kernel.org @@ -9293,6 +9311,14 @@ T: git git://linuxtv.org/media_tree.git S: Odd fixes F: drivers/media/usb/tm6000/ +TW68 VIDEO4LINUX DRIVER +M: Hans Verkuil <hverkuil@xs4all.nl> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +W: http://linuxtv.org +S: Odd Fixes +F: drivers/media/pci/tw68/ + TPM DEVICE DRIVER M: Peter Huewe <peterhuewe@gmx.de> M: Ashley Lai <ashley@ashleylai.com> diff --git a/drivers/media/common/b2c2/flexcop.h b/drivers/media/common/b2c2/flexcop.h index 897b10c85ad9..8942bdacbf61 100644 --- a/drivers/media/common/b2c2/flexcop.h +++ b/drivers/media/common/b2c2/flexcop.h @@ -4,7 +4,7 @@ * see flexcop.c for copyright information */ #ifndef __FLEXCOP_H__ -#define __FLEXCOP_H___ +#define __FLEXCOP_H__ #define FC_LOG_PREFIX "b2c2-flexcop" #include "flexcop-common.h" diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c index 6c47f3fe9b0f..b7d63933dae6 100644 --- a/drivers/media/common/saa7146/saa7146_fops.c +++ b/drivers/media/common/saa7146/saa7146_fops.c @@ -311,7 +311,6 @@ static int fops_mmap(struct file *file, struct vm_area_struct * vma) } default: BUG(); - return 0; } if (mutex_lock_interruptible(vdev->lock)) @@ -399,7 +398,6 @@ static ssize_t fops_read(struct file *file, char __user *data, size_t count, lof return -EINVAL; default: BUG(); - return 0; } } @@ -423,7 +421,6 @@ static ssize_t fops_write(struct file *file, const char __user *data, size_t cou return -EINVAL; default: BUG(); - return -EINVAL; } } diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c index 82769993eeb7..82c7a1289f05 100644 --- a/drivers/media/common/siano/sms-cards.c +++ b/drivers/media/common/siano/sms-cards.c @@ -157,6 +157,12 @@ static struct sms_board sms_boards[] = { .type = SMS_DENVER_2160, .default_mode = DEVICE_MODE_DAB_TDMB, }, + [SMS1XXX_BOARD_PCTV_77E] = { + .name = "Hauppauge microStick 77e", + .type = SMS_NOVA_B0, + .fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVB_NOVA_12MHZ_B0, + .default_mode = DEVICE_MODE_DVBT_BDA, + }, }; struct sms_board *sms_get_board(unsigned id) diff --git a/drivers/media/common/siano/sms-cards.h b/drivers/media/common/siano/sms-cards.h index c63b544c49c5..4c4caddf9869 100644 --- a/drivers/media/common/siano/sms-cards.h +++ b/drivers/media/common/siano/sms-cards.h @@ -45,6 +45,7 @@ #define SMS1XXX_BOARD_SIANO_RIO 18 #define SMS1XXX_BOARD_SIANO_DENVER_1530 19 #define SMS1XXX_BOARD_SIANO_DENVER_2160 20 +#define SMS1XXX_BOARD_PCTV_77E 21 struct sms_board_gpio_cfg { int lna_vhf_exist; diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c index 050984c5b1e3..a3677438205e 100644 --- a/drivers/media/common/siano/smscoreapi.c +++ b/drivers/media/common/siano/smscoreapi.c @@ -2129,8 +2129,6 @@ int smscore_gpio_get_level(struct smscore_device_t *coredev, u8 pin_num, static int __init smscore_module_init(void) { - int rc = 0; - INIT_LIST_HEAD(&g_smscore_notifyees); INIT_LIST_HEAD(&g_smscore_devices); kmutex_init(&g_smscore_deviceslock); @@ -2138,7 +2136,7 @@ static int __init smscore_module_init(void) INIT_LIST_HEAD(&g_smscore_registry); kmutex_init(&g_smscore_registrylock); - return rc; + return 0; } static void __exit smscore_module_exit(void) diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index c0363f1b6c90..abff803ad69a 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -1087,8 +1087,8 @@ static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) struct dmxdev_filter *dmxdevfilter = file->private_data; unsigned int mask = 0; - if (!dmxdevfilter) - return -EINVAL; + if ((!dmxdevfilter) || dmxdevfilter->dev->exit) + return POLLERR; poll_wait(file, &dmxdevfilter->buffer.queue, wait); @@ -1181,6 +1181,9 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) dprintk("function : %s\n", __func__); + if (dmxdev->exit) + return POLLERR; + poll_wait(file, &dmxdev->dvr_buffer.queue, wait); if ((file->f_flags & O_ACCMODE) == O_RDONLY) { diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 12ce19c98ded..e07a84e7bc56 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -144,6 +144,7 @@ #define USB_PID_ITETECH_IT9135 0x9135 #define USB_PID_ITETECH_IT9135_9005 0x9005 #define USB_PID_ITETECH_IT9135_9006 0x9006 +#define USB_PID_ITETECH_IT9303 0x9306 #define USB_PID_KWORLD_399U 0xe399 #define USB_PID_KWORLD_399U_2 0xe400 #define USB_PID_KWORLD_395U 0xe396 @@ -244,6 +245,7 @@ #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 #define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d +#define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index c2a6a0a85813..b8579ee68bd6 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1934,15 +1934,13 @@ static int dvb_frontend_ioctl_properties(struct file *file, struct dtv_frontend_properties *c = &fe->dtv_property_cache; int err = 0; - struct dtv_properties *tvps = NULL; + struct dtv_properties *tvps = parg; struct dtv_property *tvp = NULL; int i; dev_dbg(fe->dvb->device, "%s:\n", __func__); - if(cmd == FE_SET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; - + if (cmd == FE_SET_PROPERTY) { dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); @@ -1957,7 +1955,8 @@ static int dvb_frontend_ioctl_properties(struct file *file, goto out; } - if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + if (copy_from_user(tvp, (void __user *)tvps->props, + tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } @@ -1972,10 +1971,7 @@ static int dvb_frontend_ioctl_properties(struct file *file, if (c->state == DTV_TUNE) dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - } else - if(cmd == FE_GET_PROPERTY) { - tvps = (struct dtv_properties __user *)parg; - + } else if (cmd == FE_GET_PROPERTY) { dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); @@ -1990,7 +1986,8 @@ static int dvb_frontend_ioctl_properties(struct file *file, goto out; } - if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { + if (copy_from_user(tvp, (void __user *)tvps->props, + tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } @@ -2012,7 +2009,8 @@ static int dvb_frontend_ioctl_properties(struct file *file, (tvp + i)->result = err; } - if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { err = -EFAULT; goto out; } @@ -2072,6 +2070,23 @@ static int dtv_set_frontend(struct dvb_frontend *fe) case SYS_DVBC_ANNEX_C: rolloff = 113; break; + case SYS_DVBS: + case SYS_TURBO: + rolloff = 135; + break; + case SYS_DVBS2: + switch (c->rolloff) { + case ROLLOFF_20: + rolloff = 120; + break; + case ROLLOFF_25: + rolloff = 125; + break; + default: + case ROLLOFF_35: + rolloff = 135; + } + break; default: break; } @@ -2550,7 +2565,9 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, fe->id); - if (fe->ops.tuner_ops.sleep) + if (fe->ops.tuner_ops.suspend) + ret = fe->ops.tuner_ops.suspend(fe); + else if (fe->ops.tuner_ops.sleep) ret = fe->ops.tuner_ops.sleep(fe); if (fe->ops.sleep) @@ -2572,7 +2589,9 @@ int dvb_frontend_resume(struct dvb_frontend *fe) if (fe->ops.init) ret = fe->ops.init(fe); - if (fe->ops.tuner_ops.init) + if (fe->ops.tuner_ops.resume) + ret = fe->ops.tuner_ops.resume(fe); + else if (fe->ops.tuner_ops.init) ret = fe->ops.tuner_ops.init(fe); fe->exit = DVB_FE_NO_EXIT; diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index d398de4b6ef4..816269e5f706 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -201,6 +201,8 @@ struct dvb_tuner_ops { int (*release)(struct dvb_frontend *fe); int (*init)(struct dvb_frontend *fe); int (*sleep)(struct dvb_frontend *fe); + int (*suspend)(struct dvb_frontend *fe); + int (*resume)(struct dvb_frontend *fe); /** This is for simple PLLs - set all parameters in one go. */ int (*set_params)(struct dvb_frontend *fe); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index a5712cd7c65f..1100e98a7b1d 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -166,6 +166,31 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t return len; } +ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, + const u8 __user *buf, size_t len) +{ + int status; + size_t todo = len; + size_t split; + + split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; + + if (split > 0) { + status = copy_from_user(rbuf->data+rbuf->pwrite, buf, split); + if (status) + return len - todo; + buf += split; + todo -= split; + rbuf->pwrite = 0; + } + status = copy_from_user(rbuf->data+rbuf->pwrite, buf, todo); + if (status) + return len - todo; + rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; + + return len; +} + ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) { int status; @@ -297,3 +322,4 @@ EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); EXPORT_SYMBOL(dvb_ringbuffer_read_user); EXPORT_SYMBOL(dvb_ringbuffer_read); EXPORT_SYMBOL(dvb_ringbuffer_write); +EXPORT_SYMBOL(dvb_ringbuffer_write_user); diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h index 41f04dae69b6..9e1e11b7c39c 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.h +++ b/drivers/media/dvb-core/dvb_ringbuffer.h @@ -133,6 +133,8 @@ extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, */ extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len); +extern ssize_t dvb_ringbuffer_write_user(struct dvb_ringbuffer *rbuf, + const u8 __user *buf, size_t len); /** diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index fe0ddcca192c..5a134547e325 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -471,6 +471,11 @@ config DVB_SI2168 help Say Y when you want to support this frontend. +config DVB_AS102_FE + tristate + depends on DVB_CORE + default DVB_AS102 + comment "DVB-C (cable) frontends" depends on DVB_CORE @@ -643,6 +648,14 @@ config DVB_MB86A20S A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. Say Y when you want to support this frontend. +config DVB_TC90522 + tristate "Toshiba TC90522" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator. + Say Y when you want to support this frontend. + comment "Digital terrestrial only tuners/PLL" depends on DVB_CORE @@ -720,6 +733,13 @@ config DVB_A8293 depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT +config DVB_SP2 + tristate "CIMaX SP2" + depends on DVB_CORE && I2C + default m if !MEDIA_SUBDRV_AUTOSELECT + help + CIMaX SP2/SP2HF Common Interface module. + config DVB_LGS8GL5 tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" depends on DVB_CORE && I2C diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile index edf103d45920..ba59df63d050 100644 --- a/drivers/media/dvb-frontends/Makefile +++ b/drivers/media/dvb-frontends/Makefile @@ -107,10 +107,12 @@ obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_TDA18271C2DD) += tda18271c2dd.o obj-$(CONFIG_DVB_SI2165) += si2165.o obj-$(CONFIG_DVB_A8293) += a8293.o +obj-$(CONFIG_DVB_SP2) += sp2.o obj-$(CONFIG_DVB_TDA10071) += tda10071.o obj-$(CONFIG_DVB_RTL2830) += rtl2830.o obj-$(CONFIG_DVB_RTL2832) += rtl2832.o obj-$(CONFIG_DVB_RTL2832_SDR) += rtl2832_sdr.o obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o obj-$(CONFIG_DVB_AF9033) += af9033.o - +obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o +obj-$(CONFIG_DVB_TC90522) += tc90522.o diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index ecf6388d2200..8001690d7576 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -683,7 +683,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) switch (c->transmission_mode) { case TRANSMISSION_MODE_AUTO: - auto_mode = 1; + auto_mode = true; break; case TRANSMISSION_MODE_2K: break; @@ -693,12 +693,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid transmission_mode\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->guard_interval) { case GUARD_INTERVAL_AUTO: - auto_mode = 1; + auto_mode = true; break; case GUARD_INTERVAL_1_32: break; @@ -714,12 +714,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid guard_interval\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->hierarchy) { case HIERARCHY_AUTO: - auto_mode = 1; + auto_mode = true; break; case HIERARCHY_NONE: break; @@ -734,12 +734,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) break; default: dev_dbg(&state->i2c->dev, "%s: invalid hierarchy\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->modulation) { case QAM_AUTO: - auto_mode = 1; + auto_mode = true; break; case QPSK: break; @@ -751,7 +751,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) break; default: dev_dbg(&state->i2c->dev, "%s: invalid modulation\n", __func__); - auto_mode = 1; + auto_mode = true; } /* Use HP. How and which case we can switch to LP? */ @@ -759,7 +759,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) switch (c->code_rate_HP) { case FEC_AUTO: - auto_mode = 1; + auto_mode = true; break; case FEC_1_2: break; @@ -778,12 +778,12 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid code_rate_HP\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->code_rate_LP) { case FEC_AUTO: - auto_mode = 1; + auto_mode = true; break; case FEC_1_2: break; @@ -804,7 +804,7 @@ static int af9013_set_frontend(struct dvb_frontend *fe) default: dev_dbg(&state->i2c->dev, "%s: invalid code_rate_LP\n", __func__); - auto_mode = 1; + auto_mode = true; } switch (c->bandwidth_hz) { diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 5c90ea683a7e..63a89c1c59ff 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -24,29 +24,35 @@ /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 -struct af9033_state { - struct i2c_adapter *i2c; +struct af9033_dev { + struct i2c_client *client; struct dvb_frontend fe; struct af9033_config cfg; + bool is_af9035; + bool is_it9135; u32 bandwidth_hz; bool ts_mode_parallel; bool ts_mode_serial; - u32 ber; - u32 ucb; - unsigned long last_stat_check; + fe_status_t fe_status; + u64 post_bit_error_prev; /* for old read_ber we return (curr - prev) */ + u64 post_bit_error; + u64 post_bit_count; + u64 error_block_count; + u64 total_block_count; + struct delayed_work stat_work; }; /* write multiple registers */ -static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, +static int af9033_wr_regs(struct af9033_dev *dev, u32 reg, const u8 *val, int len) { int ret; u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { - .addr = state->cfg.i2c_addr, + .addr = dev->client->addr, .flags = 0, .len = 3 + len, .buf = buf, @@ -54,9 +60,9 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, }; if (3 + len > sizeof(buf)) { - dev_warn(&state->i2c->dev, - "%s: i2c wr reg=%04x: len=%d is too big!\n", - KBUILD_MODNAME, reg, len); + dev_warn(&dev->client->dev, + "i2c wr reg=%04x: len=%d is too big!\n", + reg, len); return -EINVAL; } @@ -65,12 +71,12 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, buf[2] = (reg >> 0) & 0xff; memcpy(&buf[3], val, len); - ret = i2c_transfer(state->i2c, msg, 1); + ret = i2c_transfer(dev->client->adapter, msg, 1); if (ret == 1) { ret = 0; } else { - dev_warn(&state->i2c->dev, "%s: i2c wr failed=%d reg=%06x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&dev->client->dev, "i2c wr failed=%d reg=%06x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -78,31 +84,31 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, } /* read multiple registers */ -static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) +static int af9033_rd_regs(struct af9033_dev *dev, u32 reg, u8 *val, int len) { int ret; u8 buf[3] = { (reg >> 16) & 0xff, (reg >> 8) & 0xff, (reg >> 0) & 0xff }; struct i2c_msg msg[2] = { { - .addr = state->cfg.i2c_addr, + .addr = dev->client->addr, .flags = 0, .len = sizeof(buf), .buf = buf }, { - .addr = state->cfg.i2c_addr, + .addr = dev->client->addr, .flags = I2C_M_RD, .len = len, .buf = val } }; - ret = i2c_transfer(state->i2c, msg, 2); + ret = i2c_transfer(dev->client->adapter, msg, 2); if (ret == 2) { ret = 0; } else { - dev_warn(&state->i2c->dev, "%s: i2c rd failed=%d reg=%06x " \ - "len=%d\n", KBUILD_MODNAME, ret, reg, len); + dev_warn(&dev->client->dev, "i2c rd failed=%d reg=%06x len=%d\n", + ret, reg, len); ret = -EREMOTEIO; } @@ -111,19 +117,19 @@ static int af9033_rd_regs(struct af9033_state *state, u32 reg, u8 *val, int len) /* write single register */ -static int af9033_wr_reg(struct af9033_state *state, u32 reg, u8 val) +static int af9033_wr_reg(struct af9033_dev *dev, u32 reg, u8 val) { - return af9033_wr_regs(state, reg, &val, 1); + return af9033_wr_regs(dev, reg, &val, 1); } /* read single register */ -static int af9033_rd_reg(struct af9033_state *state, u32 reg, u8 *val) +static int af9033_rd_reg(struct af9033_dev *dev, u32 reg, u8 *val) { - return af9033_rd_regs(state, reg, val, 1); + return af9033_rd_regs(dev, reg, val, 1); } /* write single register with mask */ -static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, +static int af9033_wr_reg_mask(struct af9033_dev *dev, u32 reg, u8 val, u8 mask) { int ret; @@ -131,7 +137,7 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, /* no need for read if whole reg is written */ if (mask != 0xff) { - ret = af9033_rd_regs(state, reg, &tmp, 1); + ret = af9033_rd_regs(dev, reg, &tmp, 1); if (ret) return ret; @@ -140,17 +146,17 @@ static int af9033_wr_reg_mask(struct af9033_state *state, u32 reg, u8 val, val |= tmp; } - return af9033_wr_regs(state, reg, &val, 1); + return af9033_wr_regs(dev, reg, &val, 1); } /* read single register with mask */ -static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, +static int af9033_rd_reg_mask(struct af9033_dev *dev, u32 reg, u8 *val, u8 mask) { int ret, i; u8 tmp; - ret = af9033_rd_regs(state, reg, &tmp, 1); + ret = af9033_rd_regs(dev, reg, &tmp, 1); if (ret) return ret; @@ -167,18 +173,17 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, } /* write reg val table using reg addr auto increment */ -static int af9033_wr_reg_val_tab(struct af9033_state *state, +static int af9033_wr_reg_val_tab(struct af9033_dev *dev, const struct reg_val *tab, int tab_len) { #define MAX_TAB_LEN 212 int ret, i, j; u8 buf[1 + MAX_TAB_LEN]; - dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); + dev_dbg(&dev->client->dev, "tab_len=%d\n", tab_len); if (tab_len > sizeof(buf)) { - dev_warn(&state->i2c->dev, "%s: tab len %d is too big\n", - KBUILD_MODNAME, tab_len); + dev_warn(&dev->client->dev, "tab len %d is too big\n", tab_len); return -EINVAL; } @@ -186,7 +191,7 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state, buf[j] = tab[i].val; if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1) { - ret = af9033_wr_regs(state, tab[i].reg - j, buf, j + 1); + ret = af9033_wr_regs(dev, tab[i].reg - j, buf, j + 1); if (ret < 0) goto err; @@ -199,16 +204,16 @@ static int af9033_wr_reg_val_tab(struct af9033_state *state, return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } -static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x) +static u32 af9033_div(struct af9033_dev *dev, u32 a, u32 b, u32 x) { u32 r = 0, c = 0, i; - dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d\n", __func__, a, b, x); + dev_dbg(&dev->client->dev, "a=%d b=%d x=%d\n", a, b, x); if (a > b) { c = a / b; @@ -225,22 +230,15 @@ static u32 af9033_div(struct af9033_state *state, u32 a, u32 b, u32 x) } r = (c << (u32)x) + r; - dev_dbg(&state->i2c->dev, "%s: a=%d b=%d x=%d r=%d r=%x\n", - __func__, a, b, x, r, r); + dev_dbg(&dev->client->dev, "a=%d b=%d x=%d r=%d r=%x\n", a, b, x, r, r); return r; } -static void af9033_release(struct dvb_frontend *fe) -{ - struct af9033_state *state = fe->demodulator_priv; - - kfree(state); -} - static int af9033_init(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, len; const struct reg_val *init; u8 buf[4]; @@ -248,7 +246,7 @@ static int af9033_init(struct dvb_frontend *fe) struct reg_val_mask tab[] = { { 0x80fb24, 0x00, 0x08 }, { 0x80004c, 0x00, 0xff }, - { 0x00f641, state->cfg.tuner, 0xff }, + { 0x00f641, dev->cfg.tuner, 0xff }, { 0x80f5ca, 0x01, 0x01 }, { 0x80f715, 0x01, 0x01 }, { 0x00f41f, 0x04, 0x04 }, @@ -267,88 +265,82 @@ static int af9033_init(struct dvb_frontend *fe) { 0x00d830, 0x01, 0xff }, { 0x00d831, 0x00, 0xff }, { 0x00d832, 0x00, 0xff }, - { 0x80f985, state->ts_mode_serial, 0x01 }, - { 0x80f986, state->ts_mode_parallel, 0x01 }, + { 0x80f985, dev->ts_mode_serial, 0x01 }, + { 0x80f986, dev->ts_mode_parallel, 0x01 }, { 0x00d827, 0x00, 0xff }, { 0x00d829, 0x00, 0xff }, - { 0x800045, state->cfg.adc_multiplier, 0xff }, + { 0x800045, dev->cfg.adc_multiplier, 0xff }, }; /* program clock control */ - clock_cw = af9033_div(state, state->cfg.clock, 1000000ul, 19ul); + clock_cw = af9033_div(dev, dev->cfg.clock, 1000000ul, 19ul); buf[0] = (clock_cw >> 0) & 0xff; buf[1] = (clock_cw >> 8) & 0xff; buf[2] = (clock_cw >> 16) & 0xff; buf[3] = (clock_cw >> 24) & 0xff; - dev_dbg(&state->i2c->dev, "%s: clock=%d clock_cw=%08x\n", - __func__, state->cfg.clock, clock_cw); + dev_dbg(&dev->client->dev, "clock=%d clock_cw=%08x\n", + dev->cfg.clock, clock_cw); - ret = af9033_wr_regs(state, 0x800025, buf, 4); + ret = af9033_wr_regs(dev, 0x800025, buf, 4); if (ret < 0) goto err; /* program ADC control */ for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { - if (clock_adc_lut[i].clock == state->cfg.clock) + if (clock_adc_lut[i].clock == dev->cfg.clock) break; } - adc_cw = af9033_div(state, clock_adc_lut[i].adc, 1000000ul, 19ul); + adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul); buf[0] = (adc_cw >> 0) & 0xff; buf[1] = (adc_cw >> 8) & 0xff; buf[2] = (adc_cw >> 16) & 0xff; - dev_dbg(&state->i2c->dev, "%s: adc=%d adc_cw=%06x\n", - __func__, clock_adc_lut[i].adc, adc_cw); + dev_dbg(&dev->client->dev, "adc=%d adc_cw=%06x\n", + clock_adc_lut[i].adc, adc_cw); - ret = af9033_wr_regs(state, 0x80f1cd, buf, 3); + ret = af9033_wr_regs(dev, 0x80f1cd, buf, 3); if (ret < 0) goto err; /* program register table */ for (i = 0; i < ARRAY_SIZE(tab); i++) { - ret = af9033_wr_reg_mask(state, tab[i].reg, tab[i].val, + ret = af9033_wr_reg_mask(dev, tab[i].reg, tab[i].val, tab[i].mask); if (ret < 0) goto err; } - /* feed clock to RF tuner */ - switch (state->cfg.tuner) { - case AF9033_TUNER_IT9135_38: - case AF9033_TUNER_IT9135_51: - case AF9033_TUNER_IT9135_52: - case AF9033_TUNER_IT9135_60: - case AF9033_TUNER_IT9135_61: - case AF9033_TUNER_IT9135_62: - ret = af9033_wr_reg(state, 0x80fba8, 0x00); + /* clock output */ + if (dev->cfg.dyn0_clk) { + ret = af9033_wr_reg(dev, 0x80fba8, 0x00); if (ret < 0) goto err; } /* settings for TS interface */ - if (state->cfg.ts_mode == AF9033_TS_MODE_USB) { - ret = af9033_wr_reg_mask(state, 0x80f9a5, 0x00, 0x01); + if (dev->cfg.ts_mode == AF9033_TS_MODE_USB) { + ret = af9033_wr_reg_mask(dev, 0x80f9a5, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x01, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x01, 0x01); if (ret < 0) goto err; } else { - ret = af9033_wr_reg_mask(state, 0x80f990, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f990, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x80f9b5, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f9b5, 0x00, 0x01); if (ret < 0) goto err; } /* load OFSM settings */ - dev_dbg(&state->i2c->dev, "%s: load ofsm settings\n", __func__); - switch (state->cfg.tuner) { + dev_dbg(&dev->client->dev, "load ofsm settings\n"); + switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_38: case AF9033_TUNER_IT9135_51: case AF9033_TUNER_IT9135_52: @@ -367,14 +359,13 @@ static int af9033_init(struct dvb_frontend *fe) break; } - ret = af9033_wr_reg_val_tab(state, init, len); + ret = af9033_wr_reg_val_tab(dev, init, len); if (ret < 0) goto err; /* load tuner specific settings */ - dev_dbg(&state->i2c->dev, "%s: load tuner specific settings\n", - __func__); - switch (state->cfg.tuner) { + dev_dbg(&dev->client->dev, "load tuner specific settings\n"); + switch (dev->cfg.tuner) { case AF9033_TUNER_TUA9001: len = ARRAY_SIZE(tuner_init_tua9001); init = tuner_init_tua9001; @@ -424,90 +415,108 @@ static int af9033_init(struct dvb_frontend *fe) init = tuner_init_it9135_62; break; default: - dev_dbg(&state->i2c->dev, "%s: unsupported tuner ID=%d\n", - __func__, state->cfg.tuner); + dev_dbg(&dev->client->dev, "unsupported tuner ID=%d\n", + dev->cfg.tuner); ret = -ENODEV; goto err; } - ret = af9033_wr_reg_val_tab(state, init, len); + ret = af9033_wr_reg_val_tab(dev, init, len); if (ret < 0) goto err; - if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { - ret = af9033_wr_reg_mask(state, 0x00d91c, 0x01, 0x01); + if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { + ret = af9033_wr_reg_mask(dev, 0x00d91c, 0x01, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x00d916, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d916, 0x00, 0x01); if (ret < 0) goto err; } - switch (state->cfg.tuner) { + switch (dev->cfg.tuner) { case AF9033_TUNER_IT9135_60: case AF9033_TUNER_IT9135_61: case AF9033_TUNER_IT9135_62: - ret = af9033_wr_reg(state, 0x800000, 0x01); + ret = af9033_wr_reg(dev, 0x800000, 0x01); if (ret < 0) goto err; } - state->bandwidth_hz = 0; /* force to program all parameters */ + dev->bandwidth_hz = 0; /* force to program all parameters */ + /* init stats here in order signal app which stats are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + /* start statistics polling */ + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int af9033_sleep(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret, i; u8 tmp; - ret = af9033_wr_reg(state, 0x80004c, 1); + /* stop statistics polling */ + cancel_delayed_work_sync(&dev->stat_work); + + ret = af9033_wr_reg(dev, 0x80004c, 1); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800000, 0); + ret = af9033_wr_reg(dev, 0x800000, 0); if (ret < 0) goto err; for (i = 100, tmp = 1; i && tmp; i--) { - ret = af9033_rd_reg(state, 0x80004c, &tmp); + ret = af9033_rd_reg(dev, 0x80004c, &tmp); if (ret < 0) goto err; usleep_range(200, 10000); } - dev_dbg(&state->i2c->dev, "%s: loop=%d\n", __func__, i); + dev_dbg(&dev->client->dev, "loop=%d\n", i); if (i == 0) { ret = -ETIMEDOUT; goto err; } - ret = af9033_wr_reg_mask(state, 0x80fb24, 0x08, 0x08); + ret = af9033_wr_reg_mask(dev, 0x80fb24, 0x08, 0x08); if (ret < 0) goto err; /* prevent current leak (?) */ - if (state->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { + if (dev->cfg.ts_mode == AF9033_TS_MODE_SERIAL) { /* enable parallel TS */ - ret = af9033_wr_reg_mask(state, 0x00d917, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d917, 0x00, 0x01); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x00d916, 0x01, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00d916, 0x01, 0x01); if (ret < 0) goto err; } @@ -515,7 +524,7 @@ static int af9033_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } @@ -533,14 +542,14 @@ static int af9033_get_tune_settings(struct dvb_frontend *fe, static int af9033_set_frontend(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, i, spec_inv, sampling_freq; u8 tmp, buf[3], bandwidth_reg_val; u32 if_frequency, freq_cw, adc_freq; - dev_dbg(&state->i2c->dev, "%s: frequency=%d bandwidth_hz=%d\n", - __func__, c->frequency, c->bandwidth_hz); + dev_dbg(&dev->client->dev, "frequency=%d bandwidth_hz=%d\n", + c->frequency, c->bandwidth_hz); /* check bandwidth */ switch (c->bandwidth_hz) { @@ -554,8 +563,7 @@ static int af9033_set_frontend(struct dvb_frontend *fe) bandwidth_reg_val = 0x02; break; default: - dev_dbg(&state->i2c->dev, "%s: invalid bandwidth_hz\n", - __func__); + dev_dbg(&dev->client->dev, "invalid bandwidth_hz\n"); ret = -EINVAL; goto err; } @@ -565,23 +573,23 @@ static int af9033_set_frontend(struct dvb_frontend *fe) fe->ops.tuner_ops.set_params(fe); /* program CFOE coefficients */ - if (c->bandwidth_hz != state->bandwidth_hz) { + if (c->bandwidth_hz != dev->bandwidth_hz) { for (i = 0; i < ARRAY_SIZE(coeff_lut); i++) { - if (coeff_lut[i].clock == state->cfg.clock && + if (coeff_lut[i].clock == dev->cfg.clock && coeff_lut[i].bandwidth_hz == c->bandwidth_hz) { break; } } - ret = af9033_wr_regs(state, 0x800001, + ret = af9033_wr_regs(dev, 0x800001, coeff_lut[i].val, sizeof(coeff_lut[i].val)); } /* program frequency control */ - if (c->bandwidth_hz != state->bandwidth_hz) { - spec_inv = state->cfg.spec_inv ? -1 : 1; + if (c->bandwidth_hz != dev->bandwidth_hz) { + spec_inv = dev->cfg.spec_inv ? -1 : 1; for (i = 0; i < ARRAY_SIZE(clock_adc_lut); i++) { - if (clock_adc_lut[i].clock == state->cfg.clock) + if (clock_adc_lut[i].clock == dev->cfg.clock) break; } adc_freq = clock_adc_lut[i].adc; @@ -602,12 +610,12 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else sampling_freq *= -1; - freq_cw = af9033_div(state, sampling_freq, adc_freq, 23ul); + freq_cw = af9033_div(dev, sampling_freq, adc_freq, 23ul); if (spec_inv == -1) freq_cw = 0x800000 - freq_cw; - if (state->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X) + if (dev->cfg.adc_multiplier == AF9033_ADC_MULTIPLIER_2X) freq_cw /= 2; buf[0] = (freq_cw >> 0) & 0xff; @@ -618,26 +626,26 @@ static int af9033_set_frontend(struct dvb_frontend *fe) if (if_frequency == 0) buf[2] = 0; - ret = af9033_wr_regs(state, 0x800029, buf, 3); + ret = af9033_wr_regs(dev, 0x800029, buf, 3); if (ret < 0) goto err; - state->bandwidth_hz = c->bandwidth_hz; + dev->bandwidth_hz = c->bandwidth_hz; } - ret = af9033_wr_reg_mask(state, 0x80f904, bandwidth_reg_val, 0x03); + ret = af9033_wr_reg_mask(dev, 0x80f904, bandwidth_reg_val, 0x03); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800040, 0x00); + ret = af9033_wr_reg(dev, 0x800040, 0x00); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800047, 0x00); + ret = af9033_wr_reg(dev, 0x800047, 0x00); if (ret < 0) goto err; - ret = af9033_wr_reg_mask(state, 0x80f999, 0x00, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f999, 0x00, 0x01); if (ret < 0) goto err; @@ -646,33 +654,33 @@ static int af9033_set_frontend(struct dvb_frontend *fe) else tmp = 0x01; /* UHF */ - ret = af9033_wr_reg(state, 0x80004b, tmp); + ret = af9033_wr_reg(dev, 0x80004b, tmp); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x800000, 0x00); + ret = af9033_wr_reg(dev, 0x800000, 0x00); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int af9033_get_frontend(struct dvb_frontend *fe) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[8]; - dev_dbg(&state->i2c->dev, "%s:\n", __func__); + dev_dbg(&dev->client->dev, "\n"); /* read all needed registers */ - ret = af9033_rd_regs(state, 0x80f900, buf, sizeof(buf)); + ret = af9033_rd_regs(dev, 0x80f900, buf, sizeof(buf)); if (ret < 0) goto err; @@ -784,21 +792,21 @@ static int af9033_get_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; u8 tmp; *status = 0; /* radio channel status, 0=no result, 1=has signal, 2=no signal */ - ret = af9033_rd_reg(state, 0x800047, &tmp); + ret = af9033_rd_reg(dev, 0x800047, &tmp); if (ret < 0) goto err; @@ -808,7 +816,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) if (tmp != 0x02) { /* TPS lock */ - ret = af9033_rd_reg_mask(state, 0x80f5a9, &tmp, 0x01); + ret = af9033_rd_reg_mask(dev, 0x80f5a9, &tmp, 0x01); if (ret < 0) goto err; @@ -817,7 +825,7 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) FE_HAS_VITERBI; /* full lock */ - ret = af9033_rd_reg_mask(state, 0x80f999, &tmp, 0x01); + ret = af9033_rd_reg_mask(dev, 0x80f999, &tmp, 0x01); if (ret < 0) goto err; @@ -827,76 +835,38 @@ static int af9033_read_status(struct dvb_frontend *fe, fe_status_t *status) FE_HAS_LOCK; } + dev->fe_status = *status; + return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr) { - struct af9033_state *state = fe->demodulator_priv; - int ret, i, len; - u8 buf[3], tmp; - u32 snr_val; - const struct val_snr *uninitialized_var(snr_lut); - - /* read value */ - ret = af9033_rd_regs(state, 0x80002c, buf, 3); - if (ret < 0) - goto err; + struct af9033_dev *dev = fe->demodulator_priv; + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; - snr_val = (buf[2] << 16) | (buf[1] << 8) | buf[0]; - - /* read current modulation */ - ret = af9033_rd_reg(state, 0x80f903, &tmp); - if (ret < 0) - goto err; - - switch ((tmp >> 0) & 3) { - case 0: - len = ARRAY_SIZE(qpsk_snr_lut); - snr_lut = qpsk_snr_lut; - break; - case 1: - len = ARRAY_SIZE(qam16_snr_lut); - snr_lut = qam16_snr_lut; - break; - case 2: - len = ARRAY_SIZE(qam64_snr_lut); - snr_lut = qam64_snr_lut; - break; - default: - goto err; - } - - for (i = 0; i < len; i++) { - tmp = snr_lut[i].snr; - - if (snr_val < snr_lut[i].val) - break; - } - - *snr = tmp * 10; /* dB/10 */ + /* use DVBv5 CNR */ + if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) + *snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */ + else + *snr = 0; return 0; - -err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); - - return ret; } static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; u8 strength2; /* read signal strength of 0-100 scale */ - ret = af9033_rd_reg(state, 0x800048, &strength2); + ret = af9033_rd_reg(dev, 0x800048, &strength2); if (ret < 0) goto err; @@ -906,244 +876,225 @@ static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); - - return ret; -} - -static int af9033_update_ch_stat(struct af9033_state *state) -{ - int ret = 0; - u32 err_cnt, bit_cnt; - u16 abort_cnt; - u8 buf[7]; - - /* only update data every half second */ - if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) { - ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf)); - if (ret < 0) - goto err; - /* in 8 byte packets? */ - abort_cnt = (buf[1] << 8) + buf[0]; - /* in bits */ - err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2]; - /* in 8 byte packets? always(?) 0x2710 = 10000 */ - bit_cnt = (buf[6] << 8) + buf[5]; - - if (bit_cnt < abort_cnt) { - abort_cnt = 1000; - state->ber = 0xffffffff; - } else { - /* 8 byte packets, that have not been rejected already */ - bit_cnt -= (u32)abort_cnt; - if (bit_cnt == 0) { - state->ber = 0xffffffff; - } else { - err_cnt -= (u32)abort_cnt * 8 * 8; - bit_cnt *= 8 * 8; - state->ber = err_cnt * (0xffffffff / bit_cnt); - } - } - state->ucb += abort_cnt; - state->last_stat_check = jiffies; - } - - return 0; -err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber) { - struct af9033_state *state = fe->demodulator_priv; - int ret; - - ret = af9033_update_ch_stat(state); - if (ret < 0) - return ret; + struct af9033_dev *dev = fe->demodulator_priv; - *ber = state->ber; + *ber = (dev->post_bit_error - dev->post_bit_error_prev); + dev->post_bit_error_prev = dev->post_bit_error; return 0; } static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { - struct af9033_state *state = fe->demodulator_priv; - int ret; - - ret = af9033_update_ch_stat(state); - if (ret < 0) - return ret; - - *ucblocks = state->ucb; + struct af9033_dev *dev = fe->demodulator_priv; + *ucblocks = dev->error_block_count; return 0; } static int af9033_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&state->i2c->dev, "%s: enable=%d\n", __func__, enable); + dev_dbg(&dev->client->dev, "enable=%d\n", enable); - ret = af9033_wr_reg_mask(state, 0x00fa04, enable, 0x01); + ret = af9033_wr_reg_mask(dev, 0x00fa04, enable, 0x01); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; - dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff); + dev_dbg(&dev->client->dev, "onoff=%d\n", onoff); - ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01); + ret = af9033_wr_reg_mask(dev, 0x80f993, onoff, 0x01); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } -static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) +static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, + int onoff) { - struct af9033_state *state = fe->demodulator_priv; + struct af9033_dev *dev = fe->demodulator_priv; int ret; u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; - dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n", - __func__, index, pid, onoff); + dev_dbg(&dev->client->dev, "index=%d pid=%04x onoff=%d\n", + index, pid, onoff); if (pid > 0x1fff) return 0; - ret = af9033_wr_regs(state, 0x80f996, wbuf, 2); + ret = af9033_wr_regs(dev, 0x80f996, wbuf, 2); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x80f994, onoff); + ret = af9033_wr_reg(dev, 0x80f994, onoff); if (ret < 0) goto err; - ret = af9033_wr_reg(state, 0x80f995, index); + ret = af9033_wr_reg(dev, 0x80f995, index); if (ret < 0) goto err; return 0; err: - dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&dev->client->dev, "failed=%d\n", ret); return ret; } -static struct dvb_frontend_ops af9033_ops; - -struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c, - struct af9033_ops *ops) +static void af9033_stat_work(struct work_struct *work) { - int ret; - struct af9033_state *state; - u8 buf[8]; + struct af9033_dev *dev = container_of(work, struct af9033_dev, stat_work.work); + struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache; + int ret, tmp, i, len; + u8 u8tmp, buf[7]; + + dev_dbg(&dev->client->dev, "\n"); + + /* signal strength */ + if (dev->fe_status & FE_HAS_SIGNAL) { + if (dev->is_af9035) { + ret = af9033_rd_reg(dev, 0x80004a, &u8tmp); + tmp = -u8tmp * 1000; + } else { + ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp); + tmp = (u8tmp - 100) * 1000; + } + if (ret) + goto err; - dev_dbg(&i2c->dev, "%s:\n", __func__); + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].svalue = tmp; + } else { + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct af9033_state), GFP_KERNEL); - if (state == NULL) - goto err; + /* CNR */ + if (dev->fe_status & FE_HAS_VITERBI) { + u32 snr_val; + const struct val_snr *snr_lut; - /* setup the state */ - state->i2c = i2c; - memcpy(&state->cfg, config, sizeof(struct af9033_config)); + /* read value */ + ret = af9033_rd_regs(dev, 0x80002c, buf, 3); + if (ret) + goto err; - if (state->cfg.clock != 12000000) { - dev_err(&state->i2c->dev, "%s: af9033: unsupported clock=%d, " \ - "only 12000000 Hz is supported currently\n", - KBUILD_MODNAME, state->cfg.clock); - goto err; - } + snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0); - /* firmware version */ - ret = af9033_rd_regs(state, 0x0083e9, &buf[0], 4); - if (ret < 0) - goto err; + /* read current modulation */ + ret = af9033_rd_reg(dev, 0x80f903, &u8tmp); + if (ret) + goto err; - ret = af9033_rd_regs(state, 0x804191, &buf[4], 4); - if (ret < 0) - goto err; + switch ((u8tmp >> 0) & 3) { + case 0: + len = ARRAY_SIZE(qpsk_snr_lut); + snr_lut = qpsk_snr_lut; + break; + case 1: + len = ARRAY_SIZE(qam16_snr_lut); + snr_lut = qam16_snr_lut; + break; + case 2: + len = ARRAY_SIZE(qam64_snr_lut); + snr_lut = qam64_snr_lut; + break; + default: + goto err_schedule_delayed_work; + } - dev_info(&state->i2c->dev, "%s: firmware version: LINK=%d.%d.%d.%d " \ - "OFDM=%d.%d.%d.%d\n", KBUILD_MODNAME, buf[0], buf[1], - buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); + for (i = 0; i < len; i++) { + tmp = snr_lut[i].snr * 1000; + if (snr_val < snr_lut[i].val) + break; + } - /* sleep */ - switch (state->cfg.tuner) { - case AF9033_TUNER_IT9135_38: - case AF9033_TUNER_IT9135_51: - case AF9033_TUNER_IT9135_52: - case AF9033_TUNER_IT9135_60: - case AF9033_TUNER_IT9135_61: - case AF9033_TUNER_IT9135_62: - /* IT9135 did not like to sleep at that early */ - break; - default: - ret = af9033_wr_reg(state, 0x80004c, 1); - if (ret < 0) - goto err; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->cnr.stat[0].svalue = tmp; + } else { + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } - ret = af9033_wr_reg(state, 0x800000, 0); - if (ret < 0) + /* UCB/PER/BER */ + if (dev->fe_status & FE_HAS_LOCK) { + /* outer FEC, 204 byte packets */ + u16 abort_packet_count, rsd_packet_count; + /* inner FEC, bits */ + u32 rsd_bit_err_count; + + /* + * Packet count used for measurement is 10000 + * (rsd_packet_count). Maybe it should be increased? + */ + + ret = af9033_rd_regs(dev, 0x800032, buf, 7); + if (ret) goto err; - } - /* configure internal TS mode */ - switch (state->cfg.ts_mode) { - case AF9033_TS_MODE_PARALLEL: - state->ts_mode_parallel = true; - break; - case AF9033_TS_MODE_SERIAL: - state->ts_mode_serial = true; - break; - case AF9033_TS_MODE_USB: - /* usb mode for AF9035 */ - default: - break; - } + abort_packet_count = (buf[1] << 8) | (buf[0] << 0); + rsd_bit_err_count = (buf[4] << 16) | (buf[3] << 8) | buf[2]; + rsd_packet_count = (buf[6] << 8) | (buf[5] << 0); - /* create dvb_frontend */ - memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); - state->fe.demodulator_priv = state; + dev->error_block_count += abort_packet_count; + dev->total_block_count += rsd_packet_count; + dev->post_bit_error += rsd_bit_err_count; + dev->post_bit_count += rsd_packet_count * 204 * 8; - if (ops) { - ops->pid_filter = af9033_pid_filter; - ops->pid_filter_ctrl = af9033_pid_filter_ctrl; - } + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue = dev->total_block_count; + + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue = dev->error_block_count; + + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue = dev->post_bit_count; - return &state->fe; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue = dev->post_bit_error; + } +err_schedule_delayed_work: + schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000)); + return; err: - kfree(state); - return NULL; + dev_dbg(&dev->client->dev, "failed=%d\n", ret); } -EXPORT_SYMBOL(af9033_attach); static struct dvb_frontend_ops af9033_ops = { .delsys = { SYS_DVBT }, @@ -1170,8 +1121,6 @@ static struct dvb_frontend_ops af9033_ops = { FE_CAN_MUTE_TS }, - .release = af9033_release, - .init = af9033_init, .sleep = af9033_sleep, @@ -1188,6 +1137,150 @@ static struct dvb_frontend_ops af9033_ops = { .i2c_gate_ctrl = af9033_i2c_gate_ctrl, }; +static int af9033_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct af9033_config *cfg = client->dev.platform_data; + struct af9033_dev *dev; + int ret; + u8 buf[8]; + u32 reg; + + /* allocate memory for the internal state */ + dev = kzalloc(sizeof(struct af9033_dev), GFP_KERNEL); + if (dev == NULL) { + ret = -ENOMEM; + dev_err(&client->dev, "Could not allocate memory for state\n"); + goto err; + } + + /* setup the state */ + dev->client = client; + INIT_DELAYED_WORK(&dev->stat_work, af9033_stat_work); + memcpy(&dev->cfg, cfg, sizeof(struct af9033_config)); + + if (dev->cfg.clock != 12000000) { + ret = -ENODEV; + dev_err(&dev->client->dev, + "unsupported clock %d Hz, only 12000000 Hz is supported currently\n", + dev->cfg.clock); + goto err_kfree; + } + + /* firmware version */ + switch (dev->cfg.tuner) { + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + dev->is_it9135 = true; + reg = 0x004bfc; + break; + default: + dev->is_af9035 = true; + reg = 0x0083e9; + break; + } + + ret = af9033_rd_regs(dev, reg, &buf[0], 4); + if (ret < 0) + goto err_kfree; + + ret = af9033_rd_regs(dev, 0x804191, &buf[4], 4); + if (ret < 0) + goto err_kfree; + + dev_info(&dev->client->dev, + "firmware version: LINK %d.%d.%d.%d - OFDM %d.%d.%d.%d\n", + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], + buf[7]); + + /* sleep */ + switch (dev->cfg.tuner) { + case AF9033_TUNER_IT9135_38: + case AF9033_TUNER_IT9135_51: + case AF9033_TUNER_IT9135_52: + case AF9033_TUNER_IT9135_60: + case AF9033_TUNER_IT9135_61: + case AF9033_TUNER_IT9135_62: + /* IT9135 did not like to sleep at that early */ + break; + default: + ret = af9033_wr_reg(dev, 0x80004c, 1); + if (ret < 0) + goto err_kfree; + + ret = af9033_wr_reg(dev, 0x800000, 0); + if (ret < 0) + goto err_kfree; + } + + /* configure internal TS mode */ + switch (dev->cfg.ts_mode) { + case AF9033_TS_MODE_PARALLEL: + dev->ts_mode_parallel = true; + break; + case AF9033_TS_MODE_SERIAL: + dev->ts_mode_serial = true; + break; + case AF9033_TS_MODE_USB: + /* usb mode for AF9035 */ + default: + break; + } + + /* create dvb_frontend */ + memcpy(&dev->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); + dev->fe.demodulator_priv = dev; + *cfg->fe = &dev->fe; + if (cfg->ops) { + cfg->ops->pid_filter = af9033_pid_filter; + cfg->ops->pid_filter_ctrl = af9033_pid_filter_ctrl; + } + i2c_set_clientdata(client, dev); + + dev_info(&dev->client->dev, "Afatech AF9033 successfully attached\n"); + return 0; +err_kfree: + kfree(dev); +err: + dev_dbg(&client->dev, "failed=%d\n", ret); + return ret; +} + +static int af9033_remove(struct i2c_client *client) +{ + struct af9033_dev *dev = i2c_get_clientdata(client); + + dev_dbg(&dev->client->dev, "\n"); + + dev->fe.ops.release = NULL; + dev->fe.demodulator_priv = NULL; + kfree(dev); + + return 0; +} + +static const struct i2c_device_id af9033_id_table[] = { + {"af9033", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, af9033_id_table); + +static struct i2c_driver af9033_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "af9033", + }, + .probe = af9033_probe, + .remove = af9033_remove, + .id_table = af9033_id_table, +}; + +module_i2c_driver(af9033_driver); + MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); MODULE_DESCRIPTION("Afatech AF9033 DVB-T demodulator driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/af9033.h b/drivers/media/dvb-frontends/af9033.h index 539f4db678b8..6ad22b69a636 100644 --- a/drivers/media/dvb-frontends/af9033.h +++ b/drivers/media/dvb-frontends/af9033.h @@ -24,13 +24,12 @@ #include <linux/kconfig.h> +/* + * I2C address (TODO: are these in 8-bit format?) + * 0x38, 0x3a, 0x3c, 0x3e + */ struct af9033_config { /* - * I2C address - */ - u8 i2c_addr; - - /* * clock Hz * 12000000, 22000000, 24000000, 34000000, 32000000, 28000000, 26000000, * 30000000, 36000000, 20480000, 16384000 @@ -75,8 +74,23 @@ struct af9033_config { * input spectrum inversion */ bool spec_inv; -}; + /* + * + */ + bool dyn0_clk; + + /* + * PID filter ops + */ + struct af9033_ops *ops; + + /* + * frontend + * returned by that driver + */ + struct dvb_frontend **fe; +}; struct af9033_ops { int (*pid_filter_ctrl)(struct dvb_frontend *fe, int onoff); @@ -84,36 +98,4 @@ struct af9033_ops { int onoff); }; - -#if IS_ENABLED(CONFIG_DVB_AF9033) -extern -struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c, - struct af9033_ops *ops); - -#else -static inline -struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c, - struct af9033_ops *ops) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} - -static inline int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -static inline int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, - int onoff) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return -ENODEV; -} - -#endif - #endif /* AF9033_H */ diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h index ded7b67d7526..c12c92cb5855 100644 --- a/drivers/media/dvb-frontends/af9033_priv.h +++ b/drivers/media/dvb-frontends/af9033_priv.h @@ -24,6 +24,7 @@ #include "dvb_frontend.h" #include "af9033.h" +#include <linux/math64.h> struct reg_val { u32 reg; diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c new file mode 100644 index 000000000000..493665899565 --- /dev/null +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -0,0 +1,480 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com> + * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.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, 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. + */ + +#include <dvb_frontend.h> + +#include "as102_fe.h" + +struct as102_state { + struct dvb_frontend frontend; + struct as10x_demod_stats demod_stats; + + const struct as102_fe_ops *ops; + void *priv; + uint8_t elna_cfg; + + /* signal strength */ + uint16_t signal_strength; + /* bit error rate */ + uint32_t ber; +}; + +static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg) +{ + uint8_t c; + + switch (arg) { + case FEC_1_2: + c = CODE_RATE_1_2; + break; + case FEC_2_3: + c = CODE_RATE_2_3; + break; + case FEC_3_4: + c = CODE_RATE_3_4; + break; + case FEC_5_6: + c = CODE_RATE_5_6; + break; + case FEC_7_8: + c = CODE_RATE_7_8; + break; + default: + c = CODE_RATE_UNKNOWN; + break; + } + + return c; +} + +static int as102_fe_set_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct as10x_tune_args tune_args = { 0 }; + + /* set frequency */ + tune_args.freq = c->frequency / 1000; + + /* fix interleaving_mode */ + tune_args.interleaving_mode = INTLV_NATIVE; + + switch (c->bandwidth_hz) { + case 8000000: + tune_args.bandwidth = BW_8_MHZ; + break; + case 7000000: + tune_args.bandwidth = BW_7_MHZ; + break; + case 6000000: + tune_args.bandwidth = BW_6_MHZ; + break; + default: + tune_args.bandwidth = BW_8_MHZ; + } + + switch (c->guard_interval) { + case GUARD_INTERVAL_1_32: + tune_args.guard_interval = GUARD_INT_1_32; + break; + case GUARD_INTERVAL_1_16: + tune_args.guard_interval = GUARD_INT_1_16; + break; + case GUARD_INTERVAL_1_8: + tune_args.guard_interval = GUARD_INT_1_8; + break; + case GUARD_INTERVAL_1_4: + tune_args.guard_interval = GUARD_INT_1_4; + break; + case GUARD_INTERVAL_AUTO: + default: + tune_args.guard_interval = GUARD_UNKNOWN; + break; + } + + switch (c->modulation) { + case QPSK: + tune_args.modulation = CONST_QPSK; + break; + case QAM_16: + tune_args.modulation = CONST_QAM16; + break; + case QAM_64: + tune_args.modulation = CONST_QAM64; + break; + default: + tune_args.modulation = CONST_UNKNOWN; + break; + } + + switch (c->transmission_mode) { + case TRANSMISSION_MODE_2K: + tune_args.transmission_mode = TRANS_MODE_2K; + break; + case TRANSMISSION_MODE_8K: + tune_args.transmission_mode = TRANS_MODE_8K; + break; + default: + tune_args.transmission_mode = TRANS_MODE_UNKNOWN; + } + + switch (c->hierarchy) { + case HIERARCHY_NONE: + tune_args.hierarchy = HIER_NONE; + break; + case HIERARCHY_1: + tune_args.hierarchy = HIER_ALPHA_1; + break; + case HIERARCHY_2: + tune_args.hierarchy = HIER_ALPHA_2; + break; + case HIERARCHY_4: + tune_args.hierarchy = HIER_ALPHA_4; + break; + case HIERARCHY_AUTO: + tune_args.hierarchy = HIER_UNKNOWN; + break; + } + + pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", + c->frequency, + tune_args.bandwidth, + tune_args.guard_interval); + + /* + * Detect a hierarchy selection + * if HP/LP are both set to FEC_NONE, HP will be selected. + */ + if ((tune_args.hierarchy != HIER_NONE) && + ((c->code_rate_LP == FEC_NONE) || + (c->code_rate_HP == FEC_NONE))) { + + if (c->code_rate_LP == FEC_NONE) { + tune_args.hier_select = HIER_HIGH_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); + } + + if (c->code_rate_HP == FEC_NONE) { + tune_args.hier_select = HIER_LOW_PRIORITY; + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_LP); + } + + pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", + tune_args.hierarchy, + tune_args.hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args.hier_select == HIER_HIGH_PRIORITY ? + "HP" : "LP", + tune_args.code_rate); + } else { + tune_args.code_rate = + as102_fe_get_code_rate(c->code_rate_HP); + } + + /* Set frontend arguments */ + return state->ops->set_tune(state->priv, &tune_args); +} + +static int as102_fe_get_frontend(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret = 0; + struct as10x_tps tps = { 0 }; + + /* send abilis command: GET_TPS */ + ret = state->ops->get_tps(state->priv, &tps); + if (ret < 0) + return ret; + + /* extract constellation */ + switch (tps.modulation) { + case CONST_QPSK: + c->modulation = QPSK; + break; + case CONST_QAM16: + c->modulation = QAM_16; + break; + case CONST_QAM64: + c->modulation = QAM_64; + break; + } + + /* extract hierarchy */ + switch (tps.hierarchy) { + case HIER_NONE: + c->hierarchy = HIERARCHY_NONE; + break; + case HIER_ALPHA_1: + c->hierarchy = HIERARCHY_1; + break; + case HIER_ALPHA_2: + c->hierarchy = HIERARCHY_2; + break; + case HIER_ALPHA_4: + c->hierarchy = HIERARCHY_4; + break; + } + + /* extract code rate HP */ + switch (tps.code_rate_HP) { + case CODE_RATE_1_2: + c->code_rate_HP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_HP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_HP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_HP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_HP = FEC_7_8; + break; + } + + /* extract code rate LP */ + switch (tps.code_rate_LP) { + case CODE_RATE_1_2: + c->code_rate_LP = FEC_1_2; + break; + case CODE_RATE_2_3: + c->code_rate_LP = FEC_2_3; + break; + case CODE_RATE_3_4: + c->code_rate_LP = FEC_3_4; + break; + case CODE_RATE_5_6: + c->code_rate_LP = FEC_5_6; + break; + case CODE_RATE_7_8: + c->code_rate_LP = FEC_7_8; + break; + } + + /* extract guard interval */ + switch (tps.guard_interval) { + case GUARD_INT_1_32: + c->guard_interval = GUARD_INTERVAL_1_32; + break; + case GUARD_INT_1_16: + c->guard_interval = GUARD_INTERVAL_1_16; + break; + case GUARD_INT_1_8: + c->guard_interval = GUARD_INTERVAL_1_8; + break; + case GUARD_INT_1_4: + c->guard_interval = GUARD_INTERVAL_1_4; + break; + } + + /* extract transmission mode */ + switch (tps.transmission_mode) { + case TRANS_MODE_2K: + c->transmission_mode = TRANSMISSION_MODE_2K; + break; + case TRANS_MODE_8K: + c->transmission_mode = TRANSMISSION_MODE_8K; + break; + } + + return 0; +} + +static int as102_fe_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) { + + settings->min_delay_ms = 1000; + + return 0; +} + +static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + int ret = 0; + struct as102_state *state = fe->demodulator_priv; + struct as10x_tune_status tstate = { 0 }; + + /* send abilis command: GET_TUNE_STATUS */ + ret = state->ops->get_status(state->priv, &tstate); + if (ret < 0) + return ret; + + state->signal_strength = tstate.signal_strength; + state->ber = tstate.BER; + + switch (tstate.tune_state) { + case TUNE_STATUS_SIGNAL_DVB_OK: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + break; + case TUNE_STATUS_STREAM_DETECTED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_VITERBI; + break; + case TUNE_STATUS_STREAM_TUNED: + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | + FE_HAS_LOCK | FE_HAS_VITERBI; + break; + default: + *status = TUNE_STATUS_NOT_TUNED; + } + + pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", + tstate.tune_state, tstate.signal_strength, + tstate.PER, tstate.BER); + + if (!(*status & FE_HAS_LOCK)) { + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + return 0; + } + + ret = state->ops->get_stats(state->priv, &state->demod_stats); + if (ret < 0) + memset(&state->demod_stats, 0, sizeof(state->demod_stats)); + + return ret; +} + +/* + * Note: + * - in AS102 SNR=MER + * - the SNR will be returned in linear terms, i.e. not in dB + * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB + * - the accuracy is >2dB for SNR values outside this range + */ +static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct as102_state *state = fe->demodulator_priv; + + *snr = state->demod_stats.mer; + + return 0; +} + +static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + struct as102_state *state = fe->demodulator_priv; + + *ber = state->ber; + + return 0; +} + +static int as102_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + struct as102_state *state = fe->demodulator_priv; + + *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2); + + return 0; +} + +static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + struct as102_state *state = fe->demodulator_priv; + + if (state->demod_stats.has_started) + *ucblocks = state->demod_stats.bad_frame_count; + else + *ucblocks = 0; + + return 0; +} + +static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) +{ + struct as102_state *state = fe->demodulator_priv; + + return state->ops->stream_ctrl(state->priv, acquire, + state->elna_cfg); +} + +static void as102_fe_release(struct dvb_frontend *fe) +{ + struct as102_state *state = fe->demodulator_priv; + + kfree(state); +} + + +static struct dvb_frontend_ops as102_fe_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Abilis AS102 DVB-T", + .frequency_min = 174000000, + .frequency_max = 862000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_INVERSION_AUTO + | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 + | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO + | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK + | FE_CAN_QAM_AUTO + | FE_CAN_TRANSMISSION_MODE_AUTO + | FE_CAN_GUARD_INTERVAL_AUTO + | FE_CAN_HIERARCHY_AUTO + | FE_CAN_RECOVER + | FE_CAN_MUTE_TS + }, + + .set_frontend = as102_fe_set_frontend, + .get_frontend = as102_fe_get_frontend, + .get_tune_settings = as102_fe_get_tune_settings, + + .read_status = as102_fe_read_status, + .read_snr = as102_fe_read_snr, + .read_ber = as102_fe_read_ber, + .read_signal_strength = as102_fe_read_signal_strength, + .read_ucblocks = as102_fe_read_ucblocks, + .ts_bus_ctrl = as102_fe_ts_bus_ctrl, + .release = as102_fe_release, +}; + +struct dvb_frontend *as102_attach(const char *name, + const struct as102_fe_ops *ops, + void *priv, + uint8_t elna_cfg) +{ + struct as102_state *state; + struct dvb_frontend *fe; + + state = kzalloc(sizeof(struct as102_state), GFP_KERNEL); + if (state == NULL) { + pr_err("%s: unable to allocate memory for state\n", __func__); + return NULL; + } + fe = &state->frontend; + fe->demodulator_priv = state; + state->ops = ops; + state->priv = priv; + state->elna_cfg = elna_cfg; + + /* init frontend callback ops */ + memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); + strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); + + return fe; + +} +EXPORT_SYMBOL_GPL(as102_attach); + +MODULE_DESCRIPTION("as102-fe"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>"); diff --git a/drivers/media/dvb-frontends/as102_fe.h b/drivers/media/dvb-frontends/as102_fe.h new file mode 100644 index 000000000000..a7c91430ca3d --- /dev/null +++ b/drivers/media/dvb-frontends/as102_fe.h @@ -0,0 +1,29 @@ +/* + * Abilis Systems Single DVB-T Receiver + * Copyright (C) 2014 Mauro Carvalho Chehab <m.chehab@samsung.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, 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. + */ + +#include "as102_fe_types.h" + +struct as102_fe_ops { + int (*set_tune)(void *priv, struct as10x_tune_args *tune_args); + int (*get_tps)(void *priv, struct as10x_tps *tps); + int (*get_status)(void *priv, struct as10x_tune_status *tstate); + int (*get_stats)(void *priv, struct as10x_demod_stats *demod_stats); + int (*stream_ctrl)(void *priv, int acquire, uint32_t elna_cfg); +}; + +struct dvb_frontend *as102_attach(const char *name, + const struct as102_fe_ops *ops, + void *priv, + uint8_t elna_cfg); diff --git a/drivers/staging/media/as102/as10x_types.h b/drivers/media/dvb-frontends/as102_fe_types.h index af26e057d9a2..80a5398b580f 100644 --- a/drivers/staging/media/as102/as10x_types.h +++ b/drivers/media/dvb-frontends/as102_fe_types.h @@ -11,16 +11,10 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _AS10X_TYPES_H_ #define _AS10X_TYPES_H_ -#include "as10x_handle.h" - /*********************************/ /* MACRO DEFINITIONS */ /*********************************/ diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 39a29dd29519..638c7aa0fb7e 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -639,12 +639,12 @@ static int bcm3510_download_firmware(struct dvb_frontend* fe) err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret); return ret; } - deb_info("got firmware: %zd\n",fw->size); + deb_info("got firmware: %zu\n", fw->size); b = fw->data; for (i = 0; i < fw->size;) { - addr = le16_to_cpu( *( (u16 *)&b[i] ) ); - len = le16_to_cpu( *( (u16 *)&b[i+2] ) ); + addr = le16_to_cpu(*((__le16 *)&b[i])); + len = le16_to_cpu(*((__le16 *)&b[i+2])); deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04zx\n",addr,len,fw->size); if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) { err("firmware download failed: %d\n",ret); diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c index 0f4657e01cde..149fdca3fb44 100644 --- a/drivers/media/dvb-frontends/cxd2820r_c.c +++ b/drivers/media/dvb-frontends/cxd2820r_c.c @@ -65,7 +65,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe) } priv->delivery_system = SYS_DVBC_ANNEX_A; - priv->ber_running = 0; /* tune stops BER counter */ + priv->ber_running = false; /* tune stops BER counter */ /* program IF frequency */ if (fe->ops.tuner_ops.get_if_frequency) { @@ -168,7 +168,7 @@ int cxd2820r_read_ber_c(struct dvb_frontend *fe, u32 *ber) start_ber = 1; } } else { - priv->ber_running = 1; + priv->ber_running = true; start_ber = 1; } diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 03930d5e9fea..cd2af3edbd04 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -564,10 +564,10 @@ static enum dvbfe_search cxd2820r_search(struct dvb_frontend *fe) /* check if we have a valid signal */ if (status & FE_HAS_LOCK) { - priv->last_tune_failed = 0; + priv->last_tune_failed = false; return DVBFE_ALGO_SEARCH_SUCCESS; } else { - priv->last_tune_failed = 1; + priv->last_tune_failed = true; return DVBFE_ALGO_SEARCH_AGAIN; } diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c index 9b5a45b907bc..51401d036530 100644 --- a/drivers/media/dvb-frontends/cxd2820r_t.c +++ b/drivers/media/dvb-frontends/cxd2820r_t.c @@ -89,7 +89,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe) } priv->delivery_system = SYS_DVBT; - priv->ber_running = 0; /* tune stops BER counter */ + priv->ber_running = false; /* tune stops BER counter */ /* program IF frequency */ if (fe->ops.tuner_ops.get_if_frequency) { @@ -272,7 +272,7 @@ int cxd2820r_read_ber_t(struct dvb_frontend *fe, u32 *ber) start_ber = 1; } } else { - priv->ber_running = 1; + priv->ber_running = true; start_ber = 1; } diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 661760d60232..589134e95175 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2559,7 +2559,7 @@ static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode) dib7000p_write_word(state, 1288, reg_1288); } -int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) +static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) { struct dib7000p_state *state = fe->demodulator_priv; u16 reg_1287; diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index 7ca7a21df183..5ec221ffdfca 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -2174,7 +2174,7 @@ int drxj_dap_atomic_read_reg32(struct i2c_device_addr *dev_addr, u32 addr, u32 *data, u32 flags) { - u8 buf[sizeof(*data)]; + u8 buf[sizeof(*data)] = { 0 }; int rc = -EIO; u32 word = 0; @@ -4193,7 +4193,7 @@ int drxj_dap_scu_atomic_read_reg16(struct i2c_device_addr *dev_addr, u32 addr, u16 *data, u32 flags) { - u8 buf[2]; + u8 buf[2] = { 0 }; int rc = -EIO; u16 word = 0; @@ -10667,7 +10667,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod, enum drx_standard standard = ext_attr->standard; int rc; u32 ber, cnt, err, pkt; - u16 mer, strength; + u16 mer, strength = 0; rc = get_sig_strength(demod, &strength); if (rc < 0) { @@ -11602,7 +11602,7 @@ static u16 drx_u_code_compute_crc(u8 *block_data, u16 nr_words) u32 carry = 0; while (i < nr_words) { - crc_word |= (u32)be16_to_cpu(*(u32 *)(block_data)); + crc_word |= (u32)be16_to_cpu(*(__be16 *)(block_data)); for (j = 0; j < 16; j++) { crc_word <<= 1; if (carry != 0) @@ -11629,7 +11629,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, int i; unsigned count = 2 * sizeof(u16); u32 mc_dev_type, mc_version, mc_base_version; - u16 mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data + sizeof(u16))); + u16 mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data + sizeof(u16))); /* * Scan microcode blocks first for version info @@ -11647,13 +11647,13 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, goto eof; /* Process block header */ - block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data + count)); count += sizeof(u32); - block_hdr.size = be16_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data + count)); count += sizeof(u16); - block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data + count)); count += sizeof(u16); - block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data + count)); + block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data + count)); count += sizeof(u16); pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n", @@ -11667,7 +11667,7 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, if (block_hdr.addr + sizeof(u16) > size) goto eof; - auxtype = be16_to_cpu(*(u32 *)(auxblk)); + auxtype = be16_to_cpu(*(__be16 *)(auxblk)); /* Aux block. Check type */ if (DRX_ISMCVERTYPE(auxtype)) { @@ -11675,11 +11675,11 @@ static int drx_check_firmware(struct drx_demod_instance *demod, u8 *mc_data, goto eof; auxblk += sizeof(u16); - mc_dev_type = be32_to_cpu(*(u32 *)(auxblk)); + mc_dev_type = be32_to_cpu(*(__be32 *)(auxblk)); auxblk += sizeof(u32); - mc_version = be32_to_cpu(*(u32 *)(auxblk)); + mc_version = be32_to_cpu(*(__be32 *)(auxblk)); auxblk += sizeof(u32); - mc_base_version = be32_to_cpu(*(u32 *)(auxblk)); + mc_base_version = be32_to_cpu(*(__be32 *)(auxblk)); DRX_ATTR_MCRECORD(demod).aux_type = auxtype; DRX_ATTR_MCRECORD(demod).mc_dev_type = mc_dev_type; @@ -11765,9 +11765,9 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, mc_data = (void *)mc_data_init; /* Check data */ - mc_magic_word = be16_to_cpu(*(u32 *)(mc_data)); + mc_magic_word = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); - mc_nr_of_blks = be16_to_cpu(*(u32 *)(mc_data)); + mc_nr_of_blks = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); if ((mc_magic_word != DRX_UCODE_MAGIC_WORD) || (mc_nr_of_blks == 0)) { @@ -11791,13 +11791,13 @@ static int drx_ctrl_u_code(struct drx_demod_instance *demod, u16 mc_block_nr_bytes = 0; /* Process block header */ - block_hdr.addr = be32_to_cpu(*(u32 *)(mc_data)); + block_hdr.addr = be32_to_cpu(*(__be32 *)(mc_data)); mc_data += sizeof(u32); - block_hdr.size = be16_to_cpu(*(u32 *)(mc_data)); + block_hdr.size = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); - block_hdr.flags = be16_to_cpu(*(u32 *)(mc_data)); + block_hdr.flags = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); - block_hdr.CRC = be16_to_cpu(*(u32 *)(mc_data)); + block_hdr.CRC = be16_to_cpu(*(__be16 *)(mc_data)); mc_data += sizeof(u16); pr_debug("%u: addr %u, size %u, flags 0x%04x, CRC 0x%04x\n", diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index ae2276db77bc..687e893d29fe 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2628,10 +2628,11 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size) break; /* Apply I2c address patch to B1 */ - if (!state->type_A && state->m_HiI2cPatch != NULL) + if (!state->type_A && state->m_HiI2cPatch != NULL) { status = WriteTable(state, state->m_HiI2cPatch); if (status < 0) break; + } if (state->type_A) { /* HI firmware patch for UIO readout, @@ -2830,14 +2831,8 @@ static int drxd_read_status(struct dvb_frontend *fe, fe_status_t * status) static int drxd_init(struct dvb_frontend *fe) { struct drxd_state *state = fe->demodulator_priv; - int err = 0; -/* if (request_firmware(&state->fw, "drxd.fw", state->dev)<0) */ return DRXD_init(state, NULL, 0); - - err = DRXD_init(state, state->fw->data, state->fw->size); - release_firmware(state->fw); - return err; } static int drxd_config_i2c(struct dvb_frontend *fe, int onoff) diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index cce94a75b2e1..672195147d01 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -1028,7 +1028,7 @@ static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result) ((state->m_hi_cfg_ctrl) & SIO_HI_RA_RAM_PAR_5_CFG_SLEEP__M) == SIO_HI_RA_RAM_PAR_5_CFG_SLEEP_ZZZ); - if (powerdown_cmd == false) { + if (!powerdown_cmd) { /* Wait until command rdy */ u32 retry_count = 0; u16 wait_cmd; @@ -1129,7 +1129,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable) if (status < 0) goto error; - if (mpeg_enable == false) { + if (!mpeg_enable) { /* Set MPEG TS pads to inputmode */ status = write16(state, SIO_PDR_MSTRT_CFG__A, 0x0000); if (status < 0) @@ -1190,7 +1190,7 @@ static int mpegts_configure_pins(struct drxk_state *state, bool mpeg_enable) if (status < 0) goto error; - if (state->m_enable_parallel == true) { + if (state->m_enable_parallel) { /* parallel -> enable MD1 to MD7 */ status = write16(state, SIO_PDR_MD1_CFG__A, sio_pdr_mdx_cfg); @@ -1392,7 +1392,7 @@ static int dvbt_enable_ofdm_token_ring(struct drxk_state *state, bool enable) dprintk(1, "\n"); - if (enable == false) { + if (!enable) { desired_ctrl = SIO_OFDM_SH_OFDM_RING_ENABLE_OFF; desired_status = SIO_OFDM_SH_OFDM_RING_STATUS_DOWN; } @@ -2012,7 +2012,7 @@ static int mpegts_dto_setup(struct drxk_state *state, goto error; fec_oc_reg_mode &= (~FEC_OC_MODE_PARITY__M); fec_oc_reg_ipr_mode &= (~FEC_OC_IPR_MODE_MVAL_DIS_PAR__M); - if (state->m_insert_rs_byte == true) { + if (state->m_insert_rs_byte) { /* enable parity symbol forward */ fec_oc_reg_mode |= FEC_OC_MODE_PARITY__M; /* MVAL disable during parity bytes */ @@ -2023,7 +2023,7 @@ static int mpegts_dto_setup(struct drxk_state *state, /* Check serial or parallel output */ fec_oc_reg_ipr_mode &= (~(FEC_OC_IPR_MODE_SERIAL__M)); - if (state->m_enable_parallel == false) { + if (!state->m_enable_parallel) { /* MPEG data output is serial -> set ipr_mode[0] */ fec_oc_reg_ipr_mode |= FEC_OC_IPR_MODE_SERIAL__M; } @@ -2136,19 +2136,19 @@ static int mpegts_configure_polarity(struct drxk_state *state) /* Control selective inversion of output bits */ fec_oc_reg_ipr_invert &= (~(invert_data_mask)); - if (state->m_invert_data == true) + if (state->m_invert_data) fec_oc_reg_ipr_invert |= invert_data_mask; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MERR__M)); - if (state->m_invert_err == true) + if (state->m_invert_err) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MERR__M; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MSTRT__M)); - if (state->m_invert_str == true) + if (state->m_invert_str) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MSTRT__M; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MVAL__M)); - if (state->m_invert_val == true) + if (state->m_invert_val) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MVAL__M; fec_oc_reg_ipr_invert &= (~(FEC_OC_IPR_INVERT_MCLK__M)); - if (state->m_invert_clk == true) + if (state->m_invert_clk) fec_oc_reg_ipr_invert |= FEC_OC_IPR_INVERT_MCLK__M; return write16(state, FEC_OC_IPR_INVERT__A, fec_oc_reg_ipr_invert); @@ -2220,12 +2220,13 @@ static int set_agc_rf(struct drxk_state *state, } /* Set TOP, only if IF-AGC is in AUTO mode */ - if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) + if (p_if_agc_settings->ctrl_mode == DRXK_AGC_CTRL_AUTO) { status = write16(state, SCU_RAM_AGC_IF_IACCU_HI_TGT_MAX__A, p_agc_cfg->top); if (status < 0) goto error; + } /* Cut-Off current */ status = write16(state, SCU_RAM_AGC_RF_IACCU_HI_CO__A, @@ -3352,7 +3353,7 @@ static int dvbt_ctrl_set_inc_enable(struct drxk_state *state, bool *enabled) int status; dprintk(1, "\n"); - if (*enabled == true) + if (*enabled) status = write16(state, IQM_CF_BYPASSDET__A, 0); else status = write16(state, IQM_CF_BYPASSDET__A, 1); @@ -3368,7 +3369,7 @@ static int dvbt_ctrl_set_fr_enable(struct drxk_state *state, bool *enabled) int status; dprintk(1, "\n"); - if (*enabled == true) { + if (*enabled) { /* write mask to 1 */ status = write16(state, OFDM_SC_RA_RAM_FR_THRES_8K__A, DEFAULT_FR_THRES_8K); @@ -6794,11 +6795,11 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config, state->enable_merr_cfg = config->enable_merr_cfg; if (config->dynamic_clk) { - state->m_dvbt_static_clk = 0; - state->m_dvbc_static_clk = 0; + state->m_dvbt_static_clk = false; + state->m_dvbc_static_clk = false; } else { - state->m_dvbt_static_clk = 1; - state->m_dvbc_static_clk = 1; + state->m_dvbt_static_clk = true; + state->m_dvbc_static_clk = true; } diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index dfe0c2f7f1ef..81657e94c5a4 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -159,6 +159,7 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv, { int ret, i, j; u8 buf[83]; + dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); if (tab_len > 83) { @@ -247,8 +248,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u8 u8tmp, u8tmp1, u8tmp2; u8 buf[2]; u16 u16tmp, divide_ratio; - u32 tuner_frequency, target_mclk, ts_clk; + u32 tuner_frequency, target_mclk; s32 s32tmp; + dev_dbg(&priv->i2c->dev, "%s: delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", __func__, c->delivery_system, @@ -316,9 +318,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) target_mclk = 144000; break; case M88DS3103_TS_PARALLEL: - case M88DS3103_TS_PARALLEL_12: - case M88DS3103_TS_PARALLEL_16: - case M88DS3103_TS_PARALLEL_19_2: case M88DS3103_TS_CI: if (c->symbol_rate < 18000000) target_mclk = 96000; @@ -352,33 +351,17 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) switch (priv->cfg->ts_mode) { case M88DS3103_TS_SERIAL: u8tmp1 = 0x00; - ts_clk = 0; - u8tmp = 0x46; + u8tmp = 0x06; break; case M88DS3103_TS_SERIAL_D7: u8tmp1 = 0x20; - ts_clk = 0; - u8tmp = 0x46; + u8tmp = 0x06; break; case M88DS3103_TS_PARALLEL: - ts_clk = 24000; - u8tmp = 0x42; - break; - case M88DS3103_TS_PARALLEL_12: - ts_clk = 12000; - u8tmp = 0x42; - break; - case M88DS3103_TS_PARALLEL_16: - ts_clk = 16000; - u8tmp = 0x42; - break; - case M88DS3103_TS_PARALLEL_19_2: - ts_clk = 19200; - u8tmp = 0x42; + u8tmp = 0x02; break; case M88DS3103_TS_CI: - ts_clk = 6000; - u8tmp = 0x43; + u8tmp = 0x03; break; default: dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__); @@ -386,6 +369,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; } + if (priv->cfg->ts_clk_pol) + u8tmp |= 0x40; + /* TS mode */ ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp); if (ret) @@ -399,8 +385,8 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) goto err; } - if (ts_clk) { - divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk); + if (priv->cfg->ts_clk) { + divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk); u8tmp1 = divide_ratio / 2; u8tmp2 = DIV_ROUND_UP(divide_ratio, 2); } else { @@ -411,7 +397,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) dev_dbg(&priv->i2c->dev, "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n", - __func__, target_mclk, ts_clk, divide_ratio); + __func__, target_mclk, priv->cfg->ts_clk, divide_ratio); u8tmp1--; u8tmp2--; @@ -536,6 +522,7 @@ static int m88ds3103_init(struct dvb_frontend *fe) const struct firmware *fw = NULL; u8 *fw_file = M88DS3103_FIRMWARE; u8 u8tmp; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); /* set cold state by default */ @@ -648,6 +635,7 @@ static int m88ds3103_sleep(struct dvb_frontend *fe) { struct m88ds3103_priv *priv = fe->demodulator_priv; int ret; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); priv->delivery_system = SYS_UNDEFINED; @@ -682,6 +670,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; u8 buf[3]; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); if (!priv->warm || !(priv->fe_status & FE_HAS_LOCK)) { @@ -857,6 +846,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr) u8 buf[3]; u16 noise, signal; u32 noise_tot, signal_tot; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); /* reports SNR in resolution of 0.1 dB */ @@ -933,6 +923,7 @@ static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber) int ret; unsigned int utmp; u8 buf[3], u8tmp; + dev_dbg(&priv->i2c->dev, "%s:\n", __func__); switch (c->delivery_system) { @@ -1013,6 +1004,7 @@ static int m88ds3103_set_tone(struct dvb_frontend *fe, struct m88ds3103_priv *priv = fe->demodulator_priv; int ret; u8 u8tmp, tone, reg_a1_mask; + dev_dbg(&priv->i2c->dev, "%s: fe_sec_tone_mode=%d\n", __func__, fe_sec_tone_mode); @@ -1053,12 +1045,64 @@ err: return ret; } +static int m88ds3103_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t fe_sec_voltage) +{ + struct m88ds3103_priv *priv = fe->demodulator_priv; + int ret; + u8 u8tmp; + bool voltage_sel, voltage_dis; + + dev_dbg(&priv->i2c->dev, "%s: fe_sec_voltage=%d\n", __func__, + fe_sec_voltage); + + if (!priv->warm) { + ret = -EAGAIN; + goto err; + } + + switch (fe_sec_voltage) { + case SEC_VOLTAGE_18: + voltage_sel = true; + voltage_dis = false; + break; + case SEC_VOLTAGE_13: + voltage_sel = false; + voltage_dis = false; + break; + case SEC_VOLTAGE_OFF: + voltage_sel = false; + voltage_dis = true; + break; + default: + dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_voltage\n", + __func__); + ret = -EINVAL; + goto err; + } + + /* output pin polarity */ + voltage_sel ^= priv->cfg->lnb_hv_pol; + voltage_dis ^= priv->cfg->lnb_en_pol; + + u8tmp = voltage_dis << 1 | voltage_sel << 0; + ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0x03); + if (ret) + goto err; + + return 0; +err: + dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); + return ret; +} + static int m88ds3103_diseqc_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *diseqc_cmd) { struct m88ds3103_priv *priv = fe->demodulator_priv; int ret, i; u8 u8tmp; + dev_dbg(&priv->i2c->dev, "%s: msg=%*ph\n", __func__, diseqc_cmd->msg_len, diseqc_cmd->msg); @@ -1130,6 +1174,7 @@ static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe, struct m88ds3103_priv *priv = fe->demodulator_priv; int ret, i; u8 u8tmp, burst; + dev_dbg(&priv->i2c->dev, "%s: fe_sec_mini_cmd=%d\n", __func__, fe_sec_mini_cmd); @@ -1202,6 +1247,7 @@ static int m88ds3103_get_tune_settings(struct dvb_frontend *fe, static void m88ds3103_release(struct dvb_frontend *fe) { struct m88ds3103_priv *priv = fe->demodulator_priv; + i2c_del_mux_adapter(priv->i2c_adapter); kfree(priv); } @@ -1370,6 +1416,7 @@ static struct dvb_frontend_ops m88ds3103_ops = { .diseqc_send_burst = m88ds3103_diseqc_send_burst, .set_tone = m88ds3103_set_tone, + .set_voltage = m88ds3103_set_voltage, }; MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h index bbb7e3aa5675..9b3b4962da7c 100644 --- a/drivers/media/dvb-frontends/m88ds3103.h +++ b/drivers/media/dvb-frontends/m88ds3103.h @@ -47,14 +47,23 @@ struct m88ds3103_config { */ #define M88DS3103_TS_SERIAL 0 /* TS output pin D0, normal */ #define M88DS3103_TS_SERIAL_D7 1 /* TS output pin D7 */ -#define M88DS3103_TS_PARALLEL 2 /* 24 MHz, normal */ -#define M88DS3103_TS_PARALLEL_12 3 /* 12 MHz */ -#define M88DS3103_TS_PARALLEL_16 4 /* 16 MHz */ -#define M88DS3103_TS_PARALLEL_19_2 5 /* 19.2 MHz */ -#define M88DS3103_TS_CI 6 /* 6 MHz */ +#define M88DS3103_TS_PARALLEL 2 /* TS Parallel mode */ +#define M88DS3103_TS_CI 3 /* TS CI Mode */ u8 ts_mode; /* + * TS clk in KHz + * Default: 0. + */ + u32 ts_clk; + + /* + * TS clk polarity. + * Default: 0. 1-active at falling edge; 0-active at rising edge. + */ + u8 ts_clk_pol:1; + + /* * spectrum inversion * Default: 0 */ @@ -86,6 +95,22 @@ struct m88ds3103_config { * Default: none, must set */ u8 agc; + + /* + * LNB H/V pin polarity + * Default: 0. + * 1: pin high set to VOLTAGE_13, pin low to set VOLTAGE_18. + * 0: pin high set to VOLTAGE_18, pin low to set VOLTAGE_13. + */ + u8 lnb_hv_pol:1; + + /* + * LNB enable pin polarity + * Default: 0. + * 1: pin high to enable, pin low to disable. + * 0: pin high to disable, pin low to enable. + */ + u8 lnb_en_pol:1; }; /* diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 9ae40abfd71a..3ddea4471d2b 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -28,7 +28,7 @@ #include "mb86a16.h" #include "mb86a16_priv.h" -unsigned int verbose = 5; +static unsigned int verbose = 5; module_param(verbose, int, 0644); #define ABS(x) ((x) < 0 ? (-x) : (x)) @@ -115,9 +115,11 @@ static int mb86a16_read(struct mb86a16_state *state, u8 reg, u8 *val) }; ret = i2c_transfer(state->i2c_adap, msg, 2); if (ret != 2) { - dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=0x%i)", + dprintk(verbose, MB86A16_ERROR, 1, "read error(reg=0x%02x, ret=%i)", reg, ret); + if (ret < 0) + return ret; return -EREMOTEIO; } *val = b1[0]; diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index b931179c70a4..e6f165a5b90d 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -33,7 +33,7 @@ enum mb86a20s_bandwidth { MB86A20S_3SEG = 3, }; -u8 mb86a20s_subchannel[] = { +static u8 mb86a20s_subchannel[] = { 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x00, 0x10, 0x20, }; @@ -1228,7 +1228,7 @@ struct linear_segments { * All tables below return a dB/1000 measurement */ -static struct linear_segments cnr_to_db_table[] = { +static const struct linear_segments cnr_to_db_table[] = { { 19648, 0}, { 18187, 1000}, { 16534, 2000}, @@ -1262,7 +1262,7 @@ static struct linear_segments cnr_to_db_table[] = { { 788, 30000}, }; -static struct linear_segments cnr_64qam_table[] = { +static const struct linear_segments cnr_64qam_table[] = { { 3922688, 0}, { 3920384, 1000}, { 3902720, 2000}, @@ -1296,7 +1296,7 @@ static struct linear_segments cnr_64qam_table[] = { { 388864, 30000}, }; -static struct linear_segments cnr_16qam_table[] = { +static const struct linear_segments cnr_16qam_table[] = { { 5314816, 0}, { 5219072, 1000}, { 5118720, 2000}, @@ -1330,7 +1330,7 @@ static struct linear_segments cnr_16qam_table[] = { { 95744, 30000}, }; -struct linear_segments cnr_qpsk_table[] = { +static const struct linear_segments cnr_qpsk_table[] = { { 2834176, 0}, { 2683648, 1000}, { 2536960, 2000}, @@ -1364,7 +1364,7 @@ struct linear_segments cnr_qpsk_table[] = { { 11520, 30000}, }; -static u32 interpolate_value(u32 value, struct linear_segments *segments, +static u32 interpolate_value(u32 value, const struct linear_segments *segments, unsigned len) { u64 tmp64; @@ -1448,7 +1448,7 @@ static int mb86a20s_get_blk_error_layer_CNR(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; u32 mer, cnr; int rc, val, layer; - struct linear_segments *segs; + const struct linear_segments *segs; unsigned segs_len; dev_dbg(&state->i2c->dev, "%s called.\n", __func__); diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index a74ac0ddb833..2163490c1e6b 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -103,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, if (1 + count > sizeof(buf)) { printk(KERN_WARNING - "mt312: write: len=%zd is too big!\n", count); + "mt312: write: len=%zu is too big!\n", count); return -EINVAL; } diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index 10cfc0579168..873ea1da844b 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -111,7 +111,7 @@ static int or51211_load_firmware (struct dvb_frontend* fe, u8 tudata[585]; int i; - dprintk("Firmware is %zd bytes\n",fw->size); + dprintk("Firmware is %zu bytes\n", fw->size); /* Get eprom data */ tudata[0] = 17; diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index fdbed35c87fa..eb737cf29a36 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -936,7 +936,7 @@ static void rtl2832_i2c_gate_work(struct work_struct *work) if (ret != 1) goto err; - priv->i2c_gate_state = 0; + priv->i2c_gate_state = false; return; err: diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c index 023e0f49c786..7bf98cf6bbe1 100644 --- a/drivers/media/dvb-frontends/rtl2832_sdr.c +++ b/drivers/media/dvb-frontends/rtl2832_sdr.c @@ -329,7 +329,7 @@ static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg, static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf( struct rtl2832_sdr_state *s) { - unsigned long flags = 0; + unsigned long flags; struct rtl2832_sdr_frame_buf *buf = NULL; spin_lock_irqsave(&s->queued_bufs_lock, flags); @@ -365,17 +365,19 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s, dst_len = 0; } - /* calculate samping rate and output it in 10 seconds intervals */ + /* calculate sample rate and output it in 10 seconds intervals */ if (unlikely(time_is_before_jiffies(s->jiffies_next))) { -#define MSECS 10000UL + #define MSECS 10000UL + unsigned int msecs = jiffies_to_msecs(jiffies - + s->jiffies_next + msecs_to_jiffies(MSECS)); unsigned int samples = s->sample - s->sample_measured; s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); s->sample_measured = s->sample; dev_dbg(&s->udev->dev, - "slen=%d samples=%u msecs=%lu sampling rate=%lu\n", - src_len, samples, MSECS, - samples * 1000UL / MSECS); + "slen=%u samples=%u msecs=%u sample rate=%lu\n", + src_len, samples, msecs, + samples * 1000UL / msecs); } /* total number of I+Q pairs */ @@ -394,8 +396,8 @@ static void rtl2832_sdr_urb_complete(struct urb *urb) struct rtl2832_sdr_frame_buf *fbuf; dev_dbg_ratelimited(&s->udev->dev, - "%s: status=%d length=%d/%d errors=%d\n", - __func__, urb->status, urb->actual_length, + "status=%d length=%d/%d errors=%d\n", + urb->status, urb->actual_length, urb->transfer_buffer_length, urb->error_count); switch (urb->status) { @@ -443,7 +445,7 @@ static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s) int i; for (i = s->urbs_submitted - 1; i >= 0; i--) { - dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i); + dev_dbg(&s->udev->dev, "kill urb=%d\n", i); /* stop the URB */ usb_kill_urb(s->urb_list[i]); } @@ -457,7 +459,7 @@ static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s) int i, ret; for (i = 0; i < s->urbs_initialized; i++) { - dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i); + dev_dbg(&s->udev->dev, "submit urb=%d\n", i); ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC); if (ret) { dev_err(&s->udev->dev, @@ -477,8 +479,7 @@ static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s) if (s->flags & USB_STATE_URB_BUF) { while (s->buf_num) { s->buf_num--; - dev_dbg(&s->udev->dev, "%s: free buf=%d\n", - __func__, s->buf_num); + dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num); usb_free_coherent(s->udev, s->buf_size, s->buf_list[s->buf_num], s->dma_addr[s->buf_num]); @@ -494,24 +495,22 @@ static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s) s->buf_num = 0; s->buf_size = BULK_BUFFER_SIZE; - dev_dbg(&s->udev->dev, - "%s: all in all I will use %u bytes for streaming\n", - __func__, MAX_BULK_BUFS * BULK_BUFFER_SIZE); + dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n", + MAX_BULK_BUFS * BULK_BUFFER_SIZE); for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) { s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev, BULK_BUFFER_SIZE, GFP_ATOMIC, &s->dma_addr[s->buf_num]); if (!s->buf_list[s->buf_num]) { - dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n", - __func__, s->buf_num); + dev_dbg(&s->udev->dev, "alloc buf=%d failed\n", + s->buf_num); rtl2832_sdr_free_stream_bufs(s); return -ENOMEM; } - dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", - __func__, s->buf_num, - s->buf_list[s->buf_num], + dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n", + s->buf_num, s->buf_list[s->buf_num], (long long)s->dma_addr[s->buf_num]); s->flags |= USB_STATE_URB_BUF; } @@ -527,8 +526,7 @@ static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s) for (i = s->urbs_initialized - 1; i >= 0; i--) { if (s->urb_list[i]) { - dev_dbg(&s->udev->dev, "%s: free urb=%d\n", - __func__, i); + dev_dbg(&s->udev->dev, "free urb=%d\n", i); /* free the URBs */ usb_free_urb(s->urb_list[i]); } @@ -544,10 +542,10 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s) /* allocate the URBs */ for (i = 0; i < MAX_BULK_BUFS; i++) { - dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i); + dev_dbg(&s->udev->dev, "alloc urb=%d\n", i); s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); if (!s->urb_list[i]) { - dev_dbg(&s->udev->dev, "%s: failed\n", __func__); + dev_dbg(&s->udev->dev, "failed\n"); for (j = 0; j < i; j++) usb_free_urb(s->urb_list[j]); return -ENOMEM; @@ -570,9 +568,9 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s) /* Must be called with vb_queue_lock hold */ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s) { - unsigned long flags = 0; + unsigned long flags; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); spin_lock_irqsave(&s->queued_bufs_lock, flags); while (!list_empty(&s->queued_bufs)) { @@ -591,7 +589,7 @@ static void rtl2832_sdr_release_sec(struct dvb_frontend *fe) { struct rtl2832_sdr_state *s = fe->sec_priv; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); mutex_lock(&s->vb_queue_lock); mutex_lock(&s->v4l2_lock); @@ -613,7 +611,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); strlcpy(cap->card, s->vdev.name, sizeof(cap->card)); @@ -631,15 +629,15 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq, { struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers); /* Need at least 8 buffers */ if (vq->num_buffers + *nbuffers < 8) *nbuffers = 8 - vq->num_buffers; *nplanes = 1; sizes[0] = PAGE_ALIGN(s->buffersize); - dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", - __func__, *nbuffers, sizes[0]); + dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n", + *nbuffers, sizes[0]); return 0; } @@ -659,7 +657,7 @@ static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb) struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue); struct rtl2832_sdr_frame_buf *buf = container_of(vb, struct rtl2832_sdr_frame_buf, vb); - unsigned long flags = 0; + unsigned long flags; /* Check the device has not disconnected between prep and queuing */ if (!s->udev) { @@ -681,7 +679,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) u64 u64tmp; u32 u32tmp; - dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc); + dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc); if (!test_bit(POWER_ON, &s->flags)) return 0; @@ -715,8 +713,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s) u64tmp = -u64tmp; u32tmp = u64tmp & 0x3fffff; - dev_dbg(&s->udev->dev, "%s: f_if=%u if_ctl=%08x\n", - __func__, f_if, u32tmp); + dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp); buf[0] = (u32tmp >> 16) & 0xff; buf[1] = (u32tmp >> 8) & 0xff; @@ -903,7 +900,7 @@ static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s) { int ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); /* PID filter */ ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1); @@ -964,8 +961,8 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s) c->frequency = s->f_tuner; c->delivery_system = SYS_DVBT; - dev_dbg(&s->udev->dev, "%s: frequency=%u bandwidth=%d\n", - __func__, c->frequency, c->bandwidth_hz); + dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n", + c->frequency, c->bandwidth_hz); if (!test_bit(POWER_ON, &s->flags)) return 0; @@ -980,7 +977,7 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s) { struct dvb_frontend *fe = s->fe; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (fe->ops.tuner_ops.init) fe->ops.tuner_ops.init(fe); @@ -992,7 +989,7 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s) { struct dvb_frontend *fe = s->fe; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (fe->ops.tuner_ops.sleep) fe->ops.tuner_ops.sleep(fe); @@ -1005,7 +1002,7 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count) struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); int ret; - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (!s->udev) return -ENODEV; @@ -1054,7 +1051,7 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq) { struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); mutex_lock(&s->v4l2_lock); @@ -1088,8 +1085,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n", - __func__, v->index, v->type); + dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type); if (v->index == 0) { strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name)); @@ -1115,7 +1111,7 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (v->index > 1) return -EINVAL; @@ -1127,8 +1123,8 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n", - __func__, band->tuner, band->type, band->index); + dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n", + band->tuner, band->type, band->index); if (band->tuner == 0) { if (band->index >= ARRAY_SIZE(bands_adc)) @@ -1153,8 +1149,8 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); int ret = 0; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n", - __func__, f->tuner, f->type); + dev_dbg(&s->udev->dev, "tuner=%d type=%d\n", + f->tuner, f->type); if (f->tuner == 0) { f->frequency = s->f_adc; @@ -1175,8 +1171,8 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); int ret, band; - dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", - __func__, f->tuner, f->type, f->frequency); + dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n", + f->tuner, f->type, f->frequency); /* ADC band midpoints */ #define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) @@ -1194,15 +1190,13 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv, bands_adc[band].rangelow, bands_adc[band].rangehigh); - dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", - __func__, s->f_adc); + dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc); ret = rtl2832_sdr_set_adc(s); } else if (f->tuner == 1) { s->f_tuner = clamp_t(unsigned int, f->frequency, bands_fm[0].rangelow, bands_fm[0].rangehigh); - dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", - __func__, f->frequency); + dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency); ret = rtl2832_sdr_set_tuner_freq(s); } else { @@ -1217,7 +1211,7 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); if (f->index >= s->num_formats) return -EINVAL; @@ -1233,7 +1227,7 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv, { struct rtl2832_sdr_state *s = video_drvdata(file); - dev_dbg(&s->udev->dev, "%s:\n", __func__); + dev_dbg(&s->udev->dev, "\n"); f->fmt.sdr.pixelformat = s->pixelformat; f->fmt.sdr.buffersize = s->buffersize; @@ -1250,7 +1244,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv, struct vb2_queue *q = &s->vb_queue; int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n", (char *)&f->fmt.sdr.pixelformat); if (vb2_is_busy(q)) @@ -1280,7 +1274,7 @@ static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv, struct rtl2832_sdr_state *s = video_drvdata(file); int i; - dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n", (char *)&f->fmt.sdr.pixelformat); memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); @@ -1354,8 +1348,8 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl) int ret; dev_dbg(&s->udev->dev, - "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", - __func__, ctrl->id, ctrl->name, ctrl->val, + "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n", + ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum, ctrl->step); switch (ctrl->id) { @@ -1432,7 +1426,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe, s->pixelformat = formats[0].pixelformat; s->buffersize = formats[0].buffersize; s->num_formats = NUM_FORMATS; - if (rtl2832_sdr_emulated_fmt == false) + if (!rtl2832_sdr_emulated_fmt) s->num_formats -= 1; mutex_init(&s->v4l2_lock); diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 3a2d6c5aded6..98ddb49ad52b 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -1,5 +1,5 @@ /* - Driver for Silicon Labs SI2165 DVB-C/-T Demodulator + Driver for Silicon Labs Si2161 DVB-T and Si2165 DVB-C/-T Demodulator Copyright (C) 2013-2014 Matthias Schwarzott <zzam@gentoo.org> @@ -44,9 +44,7 @@ struct si2165_state { struct si2165_config config; - /* chip revision */ - u8 revcode; - /* chip type */ + u8 chip_revcode; u8 chip_type; /* calculated by xtal and div settings */ @@ -312,7 +310,7 @@ static u32 si2165_get_fe_clk(struct si2165_state *state) return state->adc_clk; } -static bool si2165_wait_init_done(struct si2165_state *state) +static int si2165_wait_init_done(struct si2165_state *state) { int ret = -EINVAL; u8 val = 0; @@ -407,7 +405,7 @@ static int si2165_upload_firmware(struct si2165_state *state) int ret; const struct firmware *fw = NULL; - u8 *fw_file = SI2165_FIRMWARE; + u8 *fw_file; const u8 *data; u32 len; u32 offset; @@ -415,10 +413,20 @@ static int si2165_upload_firmware(struct si2165_state *state) u8 block_count; u16 crc_expected; + switch (state->chip_revcode) { + case 0x03: /* revision D */ + fw_file = SI2165_FIRMWARE_REV_D; + break; + default: + dev_info(&state->i2c->dev, "%s: no firmware file for revision=%d\n", + KBUILD_MODNAME, state->chip_revcode); + return 0; + } + /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, state->i2c->dev.parent); if (ret) { - dev_warn(&state->i2c->dev, "%s: firmare file '%s' not found\n", + dev_warn(&state->i2c->dev, "%s: firmware file '%s' not found\n", KBUILD_MODNAME, fw_file); goto error; } @@ -908,7 +916,7 @@ static void si2165_release(struct dvb_frontend *fe) static struct dvb_frontend_ops si2165_ops = { .info = { - .name = "Silicon Labs Si2165", + .name = "Silicon Labs ", .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | @@ -948,6 +956,8 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, int n; int io_ret; u8 val; + char rev_char; + const char *chip_name; if (config == NULL || i2c == NULL) goto error; @@ -984,7 +994,7 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, if (val != state->config.chip_mode) goto error; - io_ret = si2165_readreg8(state, 0x0023 , &state->revcode); + io_ret = si2165_readreg8(state, 0x0023, &state->chip_revcode); if (io_ret < 0) goto error; @@ -997,22 +1007,35 @@ struct dvb_frontend *si2165_attach(const struct si2165_config *config, if (io_ret < 0) goto error; - dev_info(&state->i2c->dev, "%s: hardware revision 0x%02x, chip type 0x%02x\n", - KBUILD_MODNAME, state->revcode, state->chip_type); + if (state->chip_revcode < 26) + rev_char = 'A' + state->chip_revcode; + else + rev_char = '?'; - /* It is a guess that register 0x0118 (chip type?) can be used to - * differ between si2161, si2163 and si2165 - * Only si2165 has been tested. - */ - if (state->revcode == 0x03 && state->chip_type == 0x07) { + switch (state->chip_type) { + case 0x06: + chip_name = "Si2161"; + state->has_dvbt = true; + break; + case 0x07: + chip_name = "Si2165"; state->has_dvbt = true; state->has_dvbc = true; - } else { - dev_err(&state->i2c->dev, "%s: Unsupported chip.\n", - KBUILD_MODNAME); + break; + default: + dev_err(&state->i2c->dev, "%s: Unsupported Silicon Labs chip (type %d, rev %d)\n", + KBUILD_MODNAME, state->chip_type, state->chip_revcode); goto error; } + dev_info(&state->i2c->dev, + "%s: Detected Silicon Labs %s-%c (type %d, rev %d)\n", + KBUILD_MODNAME, chip_name, rev_char, state->chip_type, + state->chip_revcode); + + strlcat(state->frontend.ops.info.name, chip_name, + sizeof(state->frontend.ops.info.name)); + n = 0; if (state->has_dvbt) { state->frontend.ops.delsys[n++] = SYS_DVBT; @@ -1037,4 +1060,4 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("Silicon Labs Si2165 DVB-C/-T Demodulator driver"); MODULE_AUTHOR("Matthias Schwarzott <zzam@gentoo.org>"); MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(SI2165_FIRMWARE); +MODULE_FIRMWARE(SI2165_FIRMWARE_REV_D); diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h index d4cc93fe1096..2b70cf12cd79 100644 --- a/drivers/media/dvb-frontends/si2165_priv.h +++ b/drivers/media/dvb-frontends/si2165_priv.h @@ -18,6 +18,6 @@ #ifndef _DVB_SI2165_PRIV #define _DVB_SI2165_PRIV -#define SI2165_FIRMWARE "dvb-demod-si2165.fw" +#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw" #endif /* _DVB_SI2165_PRIV */ diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 8f81d979de30..1cd93be281ed 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -55,8 +55,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) break; } - dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", - __func__, + dev_dbg(&s->client->dev, "cmd execution took %d ms\n", jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); @@ -75,7 +74,7 @@ err_mutex_unlock: return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -150,12 +149,12 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status) c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } - dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n", - __func__, *status, cmd.rlen, cmd.args); + dev_dbg(&s->client->dev, "status=%02x args=%*ph\n", + *status, cmd.rlen, cmd.args); return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -168,10 +167,10 @@ static int si2168_set_frontend(struct dvb_frontend *fe) u8 bandwidth, delivery_system; dev_dbg(&s->client->dev, - "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n", - __func__, c->delivery_system, c->modulation, + "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n", + c->delivery_system, c->modulation, c->frequency, c->bandwidth_hz, c->symbol_rate, - c->inversion); + c->inversion, c->stream_id); if (!s->active) { ret = -EAGAIN; @@ -235,6 +234,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe) if (ret) goto err; + if (c->delivery_system == SYS_DVBT2) { + /* select PLP */ + cmd.args[0] = 0x52; + cmd.args[1] = c->stream_id & 0xff; + cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1; + cmd.wlen = 3; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + } + memcpy(cmd.args, "\x51\x03", 2); cmd.wlen = 2; cmd.rlen = 12; @@ -297,13 +308,6 @@ static int si2168_set_frontend(struct dvb_frontend *fe) if (ret) goto err; - memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6); - cmd.wlen = 6; - cmd.rlen = 4; - ret = si2168_cmd_execute(s, &cmd); - if (ret) - goto err; - memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6); cmd.wlen = 6; cmd.rlen = 4; @@ -343,7 +347,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -357,8 +361,9 @@ static int si2168_init(struct dvb_frontend *fe) struct si2168_cmd cmd; unsigned int chip_id; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); + /* initialize */ memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13); cmd.wlen = 13; cmd.rlen = 0; @@ -366,6 +371,26 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; + if (s->fw_loaded) { + /* resume */ + memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8); + cmd.wlen = 8; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + + memcpy(cmd.args, "\x85", 1); + cmd.wlen = 1; + cmd.rlen = 1; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + + goto warm; + } + + /* power up */ memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8); cmd.wlen = 8; cmd.rlen = 1; @@ -400,16 +425,16 @@ static int si2168_init(struct dvb_frontend *fe) break; default: dev_err(&s->client->dev, - "%s: unkown chip version Si21%d-%c%c%c\n", - KBUILD_MODNAME, cmd.args[2], cmd.args[1], + "unknown chip version Si21%d-%c%c%c\n", + cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]); ret = -EINVAL; goto err; } /* cold state - try to download firmware */ - dev_info(&s->client->dev, "%s: found a '%s' in cold state\n", - KBUILD_MODNAME, si2168_ops.info.name); + dev_info(&s->client->dev, "found a '%s' in cold state\n", + si2168_ops.info.name); /* request the firmware, this will block and timeout */ ret = request_firmware(&fw, fw_file, &s->client->dev); @@ -422,18 +447,18 @@ static int si2168_init(struct dvb_frontend *fe) if (ret == 0) { dev_notice(&s->client->dev, - "%s: please install firmware file '%s'\n", - KBUILD_MODNAME, SI2168_B40_FIRMWARE); + "please install firmware file '%s'\n", + SI2168_B40_FIRMWARE); } else { dev_err(&s->client->dev, - "%s: firmware file '%s' not found\n", - KBUILD_MODNAME, fw_file); + "firmware file '%s' not found\n", + fw_file); goto err; } } - dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n", - KBUILD_MODNAME, fw_file); + dev_info(&s->client->dev, "downloading firmware from file '%s'\n", + fw_file); for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) { len = remaining; @@ -446,8 +471,8 @@ static int si2168_init(struct dvb_frontend *fe) ret = si2168_cmd_execute(s, &cmd); if (ret) { dev_err(&s->client->dev, - "%s: firmware download failed=%d\n", - KBUILD_MODNAME, ret); + "firmware download failed=%d\n", + ret); goto err; } } @@ -462,8 +487,20 @@ static int si2168_init(struct dvb_frontend *fe) if (ret) goto err; - dev_info(&s->client->dev, "%s: found a '%s' in warm state\n", - KBUILD_MODNAME, si2168_ops.info.name); + /* set ts mode */ + memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6); + cmd.args[4] |= s->ts_mode; + cmd.wlen = 6; + cmd.rlen = 4; + ret = si2168_cmd_execute(s, &cmd); + if (ret) + goto err; + + s->fw_loaded = true; + +warm: + dev_info(&s->client->dev, "found a '%s' in warm state\n", + si2168_ops.info.name); s->active = true; @@ -472,7 +509,7 @@ err: if (fw) release_firmware(fw); - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -482,7 +519,7 @@ static int si2168_sleep(struct dvb_frontend *fe) int ret; struct si2168_cmd cmd; - dev_dbg(&s->client->dev, "%s:\n", __func__); + dev_dbg(&s->client->dev, "\n"); s->active = false; @@ -495,7 +532,7 @@ static int si2168_sleep(struct dvb_frontend *fe) return 0; err: - dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&s->client->dev, "failed=%d\n", ret); return ret; } @@ -528,8 +565,7 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan) /* open tuner I2C gate */ ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1); if (ret != 1) { - dev_warn(&s->client->dev, "%s: i2c write failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&s->client->dev, "i2c write failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; } else { @@ -553,8 +589,7 @@ static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan) /* close tuner I2C gate */ ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1); if (ret != 1) { - dev_warn(&s->client->dev, "%s: i2c write failed=%d\n", - KBUILD_MODNAME, ret); + dev_warn(&s->client->dev, "i2c write failed=%d\n", ret); if (ret >= 0) ret = -EREMOTEIO; } else { @@ -587,7 +622,8 @@ static const struct dvb_frontend_ops si2168_ops = { FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_MUTE_TS | - FE_CAN_2G_MODULATION + FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .get_tune_settings = si2168_get_tune_settings, @@ -607,12 +643,12 @@ static int si2168_probe(struct i2c_client *client, struct si2168 *s; int ret; - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); s = kzalloc(sizeof(struct si2168), GFP_KERNEL); if (!s) { ret = -ENOMEM; - dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME); + dev_err(&client->dev, "kzalloc() failed\n"); goto err; } @@ -633,16 +669,17 @@ static int si2168_probe(struct i2c_client *client, *config->i2c_adapter = s->adapter; *config->fe = &s->fe; + s->ts_mode = config->ts_mode; + s->fw_loaded = false; i2c_set_clientdata(client, s); dev_info(&s->client->dev, - "%s: Silicon Labs Si2168 successfully attached\n", - KBUILD_MODNAME); + "Silicon Labs Si2168 successfully attached\n"); return 0; err: kfree(s); - dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } @@ -650,7 +687,7 @@ static int si2168_remove(struct i2c_client *client) { struct si2168 *s = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s:\n", __func__); + dev_dbg(&client->dev, "\n"); i2c_del_mux_adapter(s->adapter); diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h index 3c5b5ab01796..e086d6719451 100644 --- a/drivers/media/dvb-frontends/si2168.h +++ b/drivers/media/dvb-frontends/si2168.h @@ -34,6 +34,12 @@ struct si2168_config { * returned by driver */ struct i2c_adapter **i2c_adapter; + + /* TS mode */ + u8 ts_mode; }; +#define SI2168_TS_PARALLEL 0x06 +#define SI2168_TS_SERIAL 0x03 + #endif diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h index ebbf502ec313..e13983ed4be1 100644 --- a/drivers/media/dvb-frontends/si2168_priv.h +++ b/drivers/media/dvb-frontends/si2168_priv.h @@ -36,6 +36,8 @@ struct si2168 { fe_delivery_system_t delivery_system; fe_status_t fe_status; bool active; + bool fw_loaded; + u8 ts_mode; }; /* firmare command struct */ diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index 73b47cc6a13b..16850e2bf02f 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -236,6 +236,9 @@ static int si21_writeregs(struct si21xx_state *state, u8 reg1, .len = len + 1 }; + if (len > sizeof(buf) - 1) + return -EINVAL; + msg.buf[0] = reg1; memcpy(msg.buf + 1, data, len); diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c new file mode 100644 index 000000000000..9b684d5c8f91 --- /dev/null +++ b/drivers/media/dvb-frontends/sp2.c @@ -0,0 +1,441 @@ +/* + * CIMaX SP2/SP2HF (Atmel T90FJR) CI driver + * + * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi> + * + * Heavily based on CIMax2(R) SP2 driver in conjunction with NetUp Dual + * DVB-S2 CI card (cimax2) with following copyrights: + * + * Copyright (C) 2009 NetUP Inc. + * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru> + * Copyright (C) 2009 Abylay Ospan <aospan@netup.ru> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "sp2_priv.h" + +static int sp2_read_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) +{ + int ret; + struct i2c_client *client = s->client; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg[] = { + { + .addr = client->addr, + .flags = 0, + .buf = ®, + .len = 1 + }, { + .addr = client->addr, + .flags = I2C_M_RD, + .buf = buf, + .len = len + } + }; + + ret = i2c_transfer(adap, msg, 2); + + if (ret != 2) { + dev_err(&client->dev, "i2c read error, reg = 0x%02x, status = %d\n", + reg, ret); + if (ret < 0) + return ret; + else + return -EIO; + } + + dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %02x\n", + client->addr, reg, buf[0]); + + return 0; +} + +static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len) +{ + int ret; + u8 buffer[35]; + struct i2c_client *client = s->client; + struct i2c_adapter *adap = client->adapter; + struct i2c_msg msg = { + .addr = client->addr, + .flags = 0, + .buf = &buffer[0], + .len = len + 1 + }; + + if ((len + 1) > sizeof(buffer)) { + dev_err(&client->dev, "i2c wr reg=%02x: len=%d is too big!\n", + reg, len); + return -EINVAL; + } + + buffer[0] = reg; + memcpy(&buffer[1], buf, len); + + ret = i2c_transfer(adap, &msg, 1); + + if (ret != 1) { + dev_err(&client->dev, "i2c write error, reg = 0x%02x, status = %d\n", + reg, ret); + if (ret < 0) + return ret; + else + return -EIO; + } + + return 0; +} + +static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs, + u8 read, int addr, u8 data) +{ + struct sp2 *s = en50221->data; + u8 store; + int mem, ret; + int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control; + + dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x", + slot, acs, addr, data); + + if (slot != 0) + return -EINVAL; + + /* + * change module access type between IO space and attribute memory + * when needed + */ + if (s->module_access_type != acs) { + ret = sp2_read_i2c(s, 0x00, &store, 1); + + if (ret) + return ret; + + store &= ~(SP2_MOD_CTL_ACS1 | SP2_MOD_CTL_ACS0); + store |= acs; + + ret = sp2_write_i2c(s, 0x00, &store, 1); + if (ret) + return ret; + } + + s->module_access_type = acs; + + /* implementation of ci_op_cam is device specific */ + if (ci_op_cam) { + ret = ci_op_cam(s->priv, read, addr, data, &mem); + } else { + dev_err(&s->client->dev, "callback not defined"); + return -EINVAL; + } + + if (ret) + return ret; + + if (read) { + dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x", + addr, mem); + return mem; + } else { + return 0; + } +} + +int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, + SP2_CI_RD, addr, 0); +} + +int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_ATTR_ACS, + SP2_CI_WR, addr, data); +} + +int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, + SP2_CI_RD, addr, 0); +} + +int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr, u8 data) +{ + return sp2_ci_op_cam(en50221, slot, SP2_CI_IO_ACS, + SP2_CI_WR, addr, data); +} + +int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot) +{ + struct sp2 *s = en50221->data; + u8 buf; + int ret; + + dev_dbg(&s->client->dev, "slot: %d\n", slot); + + if (slot != 0) + return -EINVAL; + + /* RST on */ + buf = SP2_MOD_CTL_RST; + ret = sp2_write_i2c(s, 0x00, &buf, 1); + + if (ret) + return ret; + + usleep_range(500, 600); + + /* RST off */ + buf = 0x00; + ret = sp2_write_i2c(s, 0x00, &buf, 1); + + if (ret) + return ret; + + msleep(1000); + + return 0; +} + +int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot) +{ + struct sp2 *s = en50221->data; + + dev_dbg(&s->client->dev, "slot:%d\n", slot); + + /* not implemented */ + return 0; +} + +int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot) +{ + struct sp2 *s = en50221->data; + u8 buf; + + dev_dbg(&s->client->dev, "slot:%d\n", slot); + + if (slot != 0) + return -EINVAL; + + sp2_read_i2c(s, 0x00, &buf, 1); + + /* disable bypass and enable TS */ + buf |= (SP2_MOD_CTL_TSOEN | SP2_MOD_CTL_TSIEN); + return sp2_write_i2c(s, 0, &buf, 1); +} + +int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open) +{ + struct sp2 *s = en50221->data; + u8 buf[2]; + int ret; + + dev_dbg(&s->client->dev, "slot:%d open:%d\n", slot, open); + + /* + * CAM module INSERT/REMOVE processing. Slow operation because of i2c + * transfers. Throttle read to one per sec. + */ + if (time_after(jiffies, s->next_status_checked_time)) { + ret = sp2_read_i2c(s, 0x00, buf, 1); + s->next_status_checked_time = jiffies + msecs_to_jiffies(1000); + + if (ret) + return 0; + + if (buf[0] & SP2_MOD_CTL_DET) + s->status = DVB_CA_EN50221_POLL_CAM_PRESENT | + DVB_CA_EN50221_POLL_CAM_READY; + else + s->status = 0; + } + + return s->status; +} + +int sp2_init(struct sp2 *s) +{ + int ret = 0; + u8 buf; + u8 cimax_init[34] = { + 0x00, /* module A control*/ + 0x00, /* auto select mask high A */ + 0x00, /* auto select mask low A */ + 0x00, /* auto select pattern high A */ + 0x00, /* auto select pattern low A */ + 0x44, /* memory access time A, 600 ns */ + 0x00, /* invert input A */ + 0x00, /* RFU */ + 0x00, /* RFU */ + 0x00, /* module B control*/ + 0x00, /* auto select mask high B */ + 0x00, /* auto select mask low B */ + 0x00, /* auto select pattern high B */ + 0x00, /* auto select pattern low B */ + 0x44, /* memory access time B, 600 ns */ + 0x00, /* invert input B */ + 0x00, /* RFU */ + 0x00, /* RFU */ + 0x00, /* auto select mask high Ext */ + 0x00, /* auto select mask low Ext */ + 0x00, /* auto select pattern high Ext */ + 0x00, /* auto select pattern low Ext */ + 0x00, /* RFU */ + 0x02, /* destination - module A */ + 0x01, /* power control reg, VCC power on */ + 0x00, /* RFU */ + 0x00, /* int status read only */ + 0x00, /* Interrupt Mask Register */ + 0x05, /* EXTINT=active-high, INT=push-pull */ + 0x00, /* USCG1 */ + 0x04, /* ack active low */ + 0x00, /* LOCK = 0 */ + 0x22, /* unknown */ + 0x00, /* synchronization? */ + }; + + dev_dbg(&s->client->dev, "\n"); + + s->ca.owner = THIS_MODULE; + s->ca.read_attribute_mem = sp2_ci_read_attribute_mem; + s->ca.write_attribute_mem = sp2_ci_write_attribute_mem; + s->ca.read_cam_control = sp2_ci_read_cam_control; + s->ca.write_cam_control = sp2_ci_write_cam_control; + s->ca.slot_reset = sp2_ci_slot_reset; + s->ca.slot_shutdown = sp2_ci_slot_shutdown; + s->ca.slot_ts_enable = sp2_ci_slot_ts_enable; + s->ca.poll_slot_status = sp2_ci_poll_slot_status; + s->ca.data = s; + s->module_access_type = 0; + + /* initialize all regs */ + ret = sp2_write_i2c(s, 0x00, &cimax_init[0], 34); + if (ret) + goto err; + + /* lock registers */ + buf = 1; + ret = sp2_write_i2c(s, 0x1f, &buf, 1); + if (ret) + goto err; + + /* power on slots */ + ret = sp2_write_i2c(s, 0x18, &buf, 1); + if (ret) + goto err; + + ret = dvb_ca_en50221_init(s->dvb_adap, &s->ca, 0, 1); + if (ret) + goto err; + + return 0; + +err: + dev_dbg(&s->client->dev, "init failed=%d\n", ret); + return ret; +} + +int sp2_exit(struct i2c_client *client) +{ + struct sp2 *s; + + dev_dbg(&client->dev, "\n"); + + if (client == NULL) + return 0; + + s = i2c_get_clientdata(client); + if (s == NULL) + return 0; + + if (s->ca.data == NULL) + return 0; + + dvb_ca_en50221_release(&s->ca); + + return 0; +} + +static int sp2_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct sp2_config *cfg = client->dev.platform_data; + struct sp2 *s; + int ret; + + dev_dbg(&client->dev, "\n"); + + s = kzalloc(sizeof(struct sp2), GFP_KERNEL); + if (!s) { + ret = -ENOMEM; + dev_err(&client->dev, "kzalloc() failed\n"); + goto err; + } + + s->client = client; + s->dvb_adap = cfg->dvb_adap; + s->priv = cfg->priv; + s->ci_control = cfg->ci_control; + + i2c_set_clientdata(client, s); + + ret = sp2_init(s); + if (ret) + goto err; + + dev_info(&s->client->dev, "CIMaX SP2 successfully attached\n"); + return 0; +err: + dev_dbg(&client->dev, "init failed=%d\n", ret); + kfree(s); + + return ret; +} + +static int sp2_remove(struct i2c_client *client) +{ + struct si2157 *s = i2c_get_clientdata(client); + + dev_dbg(&client->dev, "\n"); + + sp2_exit(client); + if (s != NULL) + kfree(s); + + return 0; +} + +static const struct i2c_device_id sp2_id[] = { + {"sp2", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, sp2_id); + +static struct i2c_driver sp2_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "sp2", + }, + .probe = sp2_probe, + .remove = sp2_remove, + .id_table = sp2_id, +}; + +module_i2c_driver(sp2_driver); + +MODULE_DESCRIPTION("CIMaX SP2/HF CI driver"); +MODULE_AUTHOR("Olli Salonen <olli.salonen@iki.fi>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/sp2.h b/drivers/media/dvb-frontends/sp2.h new file mode 100644 index 000000000000..6cceea022d49 --- /dev/null +++ b/drivers/media/dvb-frontends/sp2.h @@ -0,0 +1,53 @@ +/* + * CIMaX SP2/HF CI driver + * + * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SP2_H +#define SP2_H + +#include <linux/kconfig.h> +#include "dvb_ca_en50221.h" + +/* + * I2C address + * 0x40 (port 0) + * 0x41 (port 1) + */ +struct sp2_config { + /* dvb_adapter to attach the ci to */ + struct dvb_adapter *dvb_adap; + + /* function ci_control handles the device specific ci ops */ + void *ci_control; + + /* priv is passed back to function ci_control */ + void *priv; +}; + +extern int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr); +extern int sp2_ci_write_attribute_mem(struct dvb_ca_en50221 *en50221, + int slot, int addr, u8 data); +extern int sp2_ci_read_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr); +extern int sp2_ci_write_cam_control(struct dvb_ca_en50221 *en50221, + int slot, u8 addr, u8 data); +extern int sp2_ci_slot_reset(struct dvb_ca_en50221 *en50221, int slot); +extern int sp2_ci_slot_shutdown(struct dvb_ca_en50221 *en50221, int slot); +extern int sp2_ci_slot_ts_enable(struct dvb_ca_en50221 *en50221, int slot); +extern int sp2_ci_poll_slot_status(struct dvb_ca_en50221 *en50221, + int slot, int open); + +#endif diff --git a/drivers/media/dvb-frontends/sp2_priv.h b/drivers/media/dvb-frontends/sp2_priv.h new file mode 100644 index 000000000000..37fef7bcd63f --- /dev/null +++ b/drivers/media/dvb-frontends/sp2_priv.h @@ -0,0 +1,50 @@ +/* + * CIMaX SP2/HF CI driver + * + * Copyright (C) 2014 Olli Salonen <olli.salonen@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef SP2_PRIV_H +#define SP2_PRIV_H + +#include "sp2.h" +#include "dvb_frontend.h" + +/* state struct */ +struct sp2 { + int status; + struct i2c_client *client; + struct dvb_adapter *dvb_adap; + struct dvb_ca_en50221 ca; + int module_access_type; + unsigned long next_status_checked_time; + void *priv; + void *ci_control; +}; + +#define SP2_CI_ATTR_ACS 0x00 +#define SP2_CI_IO_ACS 0x04 +#define SP2_CI_WR 0 +#define SP2_CI_RD 1 + +/* Module control register (0x00 module A, 0x09 module B) bits */ +#define SP2_MOD_CTL_DET 0x01 +#define SP2_MOD_CTL_AUTO 0x02 +#define SP2_MOD_CTL_ACS0 0x04 +#define SP2_MOD_CTL_ACS1 0x08 +#define SP2_MOD_CTL_HAD 0x10 +#define SP2_MOD_CTL_TSIEN 0x20 +#define SP2_MOD_CTL_TSOEN 0x40 +#define SP2_MOD_CTL_RST 0x80 + +#endif diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index 2aa8ef76eba2..57dc2abaa87b 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -394,8 +394,7 @@ static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber) if (ret < 0) return -EIO; - tmp = ret << 6; - + tmp = ret << 6; if (tmp >= 0x3FFF0) tmp = ~0; diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 59b6e661acc0..b31ff265ff24 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -59,7 +59,6 @@ struct stv0367cab_state { int locked; /* channel found */ u32 freq_khz; /* found frequency (in kHz) */ u32 symbol_rate; /* found symbol rate (in Bds) */ - enum stv0367cab_mod modulation; /* modulation */ fe_spectral_inversion_t spect_inv; /* Spectrum Inversion */ }; @@ -554,7 +553,7 @@ static struct st_register def0367ter[STV0367TER_NBREGS] = { #define RF_LOOKUP_TABLE_SIZE 31 #define RF_LOOKUP_TABLE2_SIZE 16 /* RF Level (for RF AGC->AGC1) Lookup Table, depends on the board and tuner.*/ -s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { +static const s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { {/*AGC1*/ 48, 50, 51, 53, 54, 56, 57, 58, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, @@ -566,7 +565,7 @@ s32 stv0367cab_RF_LookUp1[RF_LOOKUP_TABLE_SIZE][RF_LOOKUP_TABLE_SIZE] = { } }; /* RF Level (for IF AGC->AGC2) Lookup Table, depends on the board and tuner.*/ -s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { +static const s32 stv0367cab_RF_LookUp2[RF_LOOKUP_TABLE2_SIZE][RF_LOOKUP_TABLE2_SIZE] = { {/*AGC2*/ 28, 29, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, @@ -1935,8 +1934,6 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct stv0367_state *state = fe->demodulator_priv; struct stv0367ter_state *ter_state = state->ter_state; - - int error = 0; enum stv0367_ter_mode mode; int constell = 0,/* snr = 0,*/ Data = 0; @@ -2020,7 +2017,7 @@ static int stv0367ter_get_frontend(struct dvb_frontend *fe) p->guard_interval = stv0367_readbits(state, F367TER_SYR_GUARD); - return error; + return 0; } static int stv0367ter_read_snr(struct dvb_frontend *fe, u16 *snr) @@ -2999,7 +2996,6 @@ enum stv0367_cab_signal_type stv0367cab_algo(struct stv0367_state *state, if (QAMFEC_Lock) { signalType = FE_CAB_DATAOK; - cab_state->modulation = p->modulation; cab_state->spect_inv = stv0367_readbits(state, F367CAB_QUAD_INV); #if 0 @@ -3165,7 +3161,7 @@ static int stv0367cab_get_frontend(struct dvb_frontend *fe) case FE_CAB_MOD_QAM128: p->modulation = QAM_128; break; - case QAM_256: + case FE_CAB_MOD_QAM256: p->modulation = QAM_256; break; default: diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index e5a87b57d855..2c88abfab531 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1270,7 +1270,6 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp, enum fe_stv0900_demod_mode LDPC_Mode, enum fe_stv0900_demod_num demod) { - enum fe_stv0900_error error = STV0900_NO_ERROR; s32 reg_ind; dprintk("%s\n", __func__); @@ -1337,7 +1336,7 @@ enum fe_stv0900_error stv0900_st_dvbs2_single(struct stv0900_internal *intp, break; } - return error; + return STV0900_NO_ERROR; } static enum fe_stv0900_error stv0900_init_internal(struct dvb_frontend *fe, @@ -1555,8 +1554,6 @@ static int stv0900_status(struct stv0900_internal *intp, static int stv0900_set_mis(struct stv0900_internal *intp, enum fe_stv0900_demod_num demod, int mis) { - enum fe_stv0900_error error = STV0900_NO_ERROR; - dprintk("%s\n", __func__); if (mis < 0 || mis > 255) { @@ -1569,7 +1566,7 @@ static int stv0900_set_mis(struct stv0900_internal *intp, stv0900_write_reg(intp, ISIBITENA, 0xff); } - return error; + return STV0900_NO_ERROR; } diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c index 4ce1d260b3eb..a0a7b1664c53 100644 --- a/drivers/media/dvb-frontends/stv0900_sw.c +++ b/drivers/media/dvb-frontends/stv0900_sw.c @@ -1733,9 +1733,10 @@ static void stv0900_set_search_standard(struct stv0900_internal *intp, break; case STV0900_SEARCH_DSS: dprintk("Search Standard = DSS\n"); - case STV0900_SEARCH_DVBS2: break; + case STV0900_SEARCH_DVBS2: dprintk("Search Standard = DVBS2\n"); + break; case STV0900_AUTO_SEARCH: default: dprintk("Search Standard = AUTO\n"); diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c new file mode 100644 index 000000000000..d9905fb52f84 --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.c @@ -0,0 +1,840 @@ +/* + * Toshiba TC90522 Demodulator + * + * Copyright (C) 2014 Akihiro Tsukada <tskd08@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 version 2. + * + * + * 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. + */ + +/* + * NOTICE: + * This driver is incomplete and lacks init/config of the chips, + * as the necessary info is not disclosed. + * It assumes that users of this driver (such as a PCI bridge of + * DTV receiver cards) properly init and configure the chip + * via I2C *before* calling this driver's init() function. + * + * Currently, PT3 driver is the only one that uses this driver, + * and contains init/config code in its firmware. + * Thus some part of the code might be dependent on PT3 specific config. + */ + +#include <linux/kernel.h> +#include <linux/math64.h> +#include <linux/dvb/frontend.h> +#include "dvb_math.h" +#include "tc90522.h" + +#define TC90522_I2C_THRU_REG 0xfe + +#define TC90522_MODULE_IDX(addr) (((u8)(addr) & 0x02U) >> 1) + +struct tc90522_state { + struct tc90522_config cfg; + struct dvb_frontend fe; + struct i2c_client *i2c_client; + struct i2c_adapter tuner_i2c; + + bool lna; +}; + +struct reg_val { + u8 reg; + u8 val; +}; + +static int +reg_write(struct tc90522_state *state, const struct reg_val *regs, int num) +{ + int i, ret; + struct i2c_msg msg; + + ret = 0; + msg.addr = state->i2c_client->addr; + msg.flags = 0; + msg.len = 2; + for (i = 0; i < num; i++) { + msg.buf = (u8 *)®s[i]; + ret = i2c_transfer(state->i2c_client->adapter, &msg, 1); + if (ret == 0) + ret = -EIO; + if (ret < 0) + return ret; + } + return 0; +} + +static int reg_read(struct tc90522_state *state, u8 reg, u8 *val, u8 len) +{ + struct i2c_msg msgs[2] = { + { + .addr = state->i2c_client->addr, + .flags = 0, + .buf = ®, + .len = 1, + }, + { + .addr = state->i2c_client->addr, + .flags = I2C_M_RD, + .buf = val, + .len = len, + }, + }; + int ret; + + ret = i2c_transfer(state->i2c_client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret == ARRAY_SIZE(msgs)) + ret = 0; + else if (ret >= 0) + ret = -EIO; + return ret; +} + +static struct tc90522_state *cfg_to_state(struct tc90522_config *c) +{ + return container_of(c, struct tc90522_state, cfg); +} + + +static int tc90522s_set_tsid(struct dvb_frontend *fe) +{ + struct reg_val set_tsid[] = { + { 0x8f, 00 }, + { 0x90, 00 } + }; + + set_tsid[0].val = (fe->dtv_property_cache.stream_id & 0xff00) >> 8; + set_tsid[1].val = fe->dtv_property_cache.stream_id & 0xff; + return reg_write(fe->demodulator_priv, set_tsid, ARRAY_SIZE(set_tsid)); +} + +static int tc90522t_set_layers(struct dvb_frontend *fe) +{ + struct reg_val rv; + u8 laysel; + + laysel = ~fe->dtv_property_cache.isdbt_layer_enabled & 0x07; + laysel = (laysel & 0x01) << 2 | (laysel & 0x02) | (laysel & 0x04) >> 2; + rv.reg = 0x71; + rv.val = laysel; + return reg_write(fe->demodulator_priv, &rv, 1); +} + +/* frontend ops */ + +static int tc90522s_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct tc90522_state *state; + int ret; + u8 reg; + + state = fe->demodulator_priv; + ret = reg_read(state, 0xc3, ®, 1); + if (ret < 0) + return ret; + + *status = 0; + if (reg & 0x80) /* input level under min ? */ + return 0; + *status |= FE_HAS_SIGNAL; + + if (reg & 0x60) /* carrier? */ + return 0; + *status |= FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC; + + if (reg & 0x10) + return 0; + if (reg_read(state, 0xc5, ®, 1) < 0 || !(reg & 0x03)) + return 0; + *status |= FE_HAS_LOCK; + return 0; +} + +static int tc90522t_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct tc90522_state *state; + int ret; + u8 reg; + + state = fe->demodulator_priv; + ret = reg_read(state, 0x96, ®, 1); + if (ret < 0) + return ret; + + *status = 0; + if (reg & 0xe0) { + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI + | FE_HAS_SYNC | FE_HAS_LOCK; + return 0; + } + + ret = reg_read(state, 0x80, ®, 1); + if (ret < 0) + return ret; + + if (reg & 0xf0) + return 0; + *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER; + + if (reg & 0x0c) + return 0; + *status |= FE_HAS_SYNC | FE_HAS_VITERBI; + + if (reg & 0x02) + return 0; + *status |= FE_HAS_LOCK; + return 0; +} + +static const fe_code_rate_t fec_conv_sat[] = { + FEC_NONE, /* unused */ + FEC_1_2, /* for BPSK */ + FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, /* for QPSK */ + FEC_2_3, /* for 8PSK. (trellis code) */ +}; + +static int tc90522s_get_frontend(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + struct dtv_frontend_properties *c; + struct dtv_fe_stats *stats; + int ret, i; + int layers; + u8 val[10]; + u32 cndat; + + state = fe->demodulator_priv; + c = &fe->dtv_property_cache; + c->delivery_system = SYS_ISDBS; + + layers = 0; + ret = reg_read(state, 0xe8, val, 3); + if (ret == 0) { + int slots; + u8 v; + + /* high/single layer */ + v = (val[0] & 0x70) >> 4; + c->modulation = (v == 7) ? PSK_8 : QPSK; + c->fec_inner = fec_conv_sat[v]; + c->layer[0].fec = c->fec_inner; + c->layer[0].modulation = c->modulation; + c->layer[0].segment_count = val[1] & 0x3f; /* slots */ + + /* low layer */ + v = (val[0] & 0x07); + c->layer[1].fec = fec_conv_sat[v]; + if (v == 0) /* no low layer */ + c->layer[1].segment_count = 0; + else + c->layer[1].segment_count = val[2] & 0x3f; /* slots */ + /* actually, BPSK if v==1, but not defined in fe_modulation_t */ + c->layer[1].modulation = QPSK; + layers = (v > 0) ? 2 : 1; + + slots = c->layer[0].segment_count + c->layer[1].segment_count; + c->symbol_rate = 28860000 * slots / 48; + } + + /* statistics */ + + stats = &c->strength; + stats->len = 0; + /* let the connected tuner set RSSI property cache */ + if (fe->ops.tuner_ops.get_rf_strength) { + u16 dummy; + + fe->ops.tuner_ops.get_rf_strength(fe, &dummy); + } + + stats = &c->cnr; + stats->len = 1; + stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; + cndat = 0; + ret = reg_read(state, 0xbc, val, 2); + if (ret == 0) + cndat = val[0] << 8 | val[1]; + if (cndat >= 3000) { + u32 p, p4; + s64 cn; + + cndat -= 3000; /* cndat: 4.12 fixed point float */ + /* + * cnr[mdB] = -1634.6 * P^5 + 14341 * P^4 - 50259 * P^3 + * + 88977 * P^2 - 89565 * P + 58857 + * (P = sqrt(cndat) / 64) + */ + /* p := sqrt(cndat) << 8 = P << 14, 2.14 fixed point float */ + /* cn = cnr << 3 */ + p = int_sqrt(cndat << 16); + p4 = cndat * cndat; + cn = div64_s64(-16346LL * p4 * p, 10) >> 35; + cn += (14341LL * p4) >> 21; + cn -= (50259LL * cndat * p) >> 23; + cn += (88977LL * cndat) >> 9; + cn -= (89565LL * p) >> 11; + cn += 58857 << 3; + stats->stat[0].svalue = cn >> 3; + stats->stat[0].scale = FE_SCALE_DECIBEL; + } + + /* per-layer post viterbi BER (or PER? config dependent?) */ + stats = &c->post_bit_error; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + ret = reg_read(state, 0xeb, val, 10); + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = val[i * 5] << 16 + | val[i * 5 + 1] << 8 | val[i * 5 + 2]; + } + } + stats = &c->post_bit_count; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = + val[i * 5 + 3] << 8 | val[i * 5 + 4]; + stats->stat[i].uvalue *= 204 * 8; + } + } + + return 0; +} + + +static const fe_transmit_mode_t tm_conv[] = { + TRANSMISSION_MODE_2K, + TRANSMISSION_MODE_4K, + TRANSMISSION_MODE_8K, + 0 +}; + +static const fe_code_rate_t fec_conv_ter[] = { + FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, FEC_7_8, 0, 0, 0 +}; + +static const fe_modulation_t mod_conv[] = { + DQPSK, QPSK, QAM_16, QAM_64, 0, 0, 0, 0 +}; + +static int tc90522t_get_frontend(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + struct dtv_frontend_properties *c; + struct dtv_fe_stats *stats; + int ret, i; + int layers; + u8 val[15], mode; + u32 cndat; + + state = fe->demodulator_priv; + c = &fe->dtv_property_cache; + c->delivery_system = SYS_ISDBT; + c->bandwidth_hz = 6000000; + mode = 1; + ret = reg_read(state, 0xb0, val, 1); + if (ret == 0) { + mode = (val[0] & 0xc0) >> 2; + c->transmission_mode = tm_conv[mode]; + c->guard_interval = (val[0] & 0x30) >> 4; + } + + ret = reg_read(state, 0xb2, val, 6); + layers = 0; + if (ret == 0) { + u8 v; + + c->isdbt_partial_reception = val[0] & 0x01; + c->isdbt_sb_mode = (val[0] & 0xc0) == 0x01; + + /* layer A */ + v = (val[2] & 0x78) >> 3; + if (v == 0x0f) + c->layer[0].segment_count = 0; + else { + layers++; + c->layer[0].segment_count = v; + c->layer[0].fec = fec_conv_ter[(val[1] & 0x1c) >> 2]; + c->layer[0].modulation = mod_conv[(val[1] & 0xe0) >> 5]; + v = (val[1] & 0x03) << 1 | (val[2] & 0x80) >> 7; + c->layer[0].interleaving = v; + } + + /* layer B */ + v = (val[3] & 0x03) << 1 | (val[4] & 0xc0) >> 6; + if (v == 0x0f) + c->layer[1].segment_count = 0; + else { + layers++; + c->layer[1].segment_count = v; + c->layer[1].fec = fec_conv_ter[(val[3] & 0xe0) >> 5]; + c->layer[1].modulation = mod_conv[(val[2] & 0x07)]; + c->layer[1].interleaving = (val[3] & 0x1c) >> 2; + } + + /* layer C */ + v = (val[5] & 0x1e) >> 1; + if (v == 0x0f) + c->layer[2].segment_count = 0; + else { + layers++; + c->layer[2].segment_count = v; + c->layer[2].fec = fec_conv_ter[(val[4] & 0x07)]; + c->layer[2].modulation = mod_conv[(val[4] & 0x38) >> 3]; + c->layer[2].interleaving = (val[5] & 0xe0) >> 5; + } + } + + /* statistics */ + + stats = &c->strength; + stats->len = 0; + /* let the connected tuner set RSSI property cache */ + if (fe->ops.tuner_ops.get_rf_strength) { + u16 dummy; + + fe->ops.tuner_ops.get_rf_strength(fe, &dummy); + } + + stats = &c->cnr; + stats->len = 1; + stats->stat[0].scale = FE_SCALE_NOT_AVAILABLE; + cndat = 0; + ret = reg_read(state, 0x8b, val, 3); + if (ret == 0) + cndat = val[0] << 16 | val[1] << 8 | val[2]; + if (cndat != 0) { + u32 p, tmp; + s64 cn; + + /* + * cnr[mdB] = 0.024 P^4 - 1.6 P^3 + 39.8 P^2 + 549.1 P + 3096.5 + * (P = 10log10(5505024/cndat)) + */ + /* cn = cnr << 3 (61.3 fixed point float */ + /* p = 10log10(5505024/cndat) << 24 (8.24 fixed point float)*/ + p = intlog10(5505024) - intlog10(cndat); + p *= 10; + + cn = 24772; + cn += div64_s64(43827LL * p, 10) >> 24; + tmp = p >> 8; + cn += div64_s64(3184LL * tmp * tmp, 10) >> 32; + tmp = p >> 13; + cn -= div64_s64(128LL * tmp * tmp * tmp, 10) >> 33; + tmp = p >> 18; + cn += div64_s64(192LL * tmp * tmp * tmp * tmp, 1000) >> 24; + + stats->stat[0].svalue = cn >> 3; + stats->stat[0].scale = FE_SCALE_DECIBEL; + } + + /* per-layer post viterbi BER (or PER? config dependent?) */ + stats = &c->post_bit_error; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + ret = reg_read(state, 0x9d, val, 15); + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = val[i * 3] << 16 + | val[i * 3 + 1] << 8 | val[i * 3 + 2]; + } + } + stats = &c->post_bit_count; + memset(stats, 0, sizeof(*stats)); + stats->len = layers; + if (ret < 0) + for (i = 0; i < layers; i++) + stats->stat[i].scale = FE_SCALE_NOT_AVAILABLE; + else { + for (i = 0; i < layers; i++) { + stats->stat[i].scale = FE_SCALE_COUNTER; + stats->stat[i].uvalue = + val[9 + i * 2] << 8 | val[9 + i * 2 + 1]; + stats->stat[i].uvalue *= 204 * 8; + } + } + + return 0; +} + +static const struct reg_val reset_sat = { 0x03, 0x01 }; +static const struct reg_val reset_ter = { 0x01, 0x40 }; + +static int tc90522_set_frontend(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + int ret; + + state = fe->demodulator_priv; + + if (fe->ops.tuner_ops.set_params) + ret = fe->ops.tuner_ops.set_params(fe); + else + ret = -ENODEV; + if (ret < 0) + goto failed; + + if (fe->ops.delsys[0] == SYS_ISDBS) { + ret = tc90522s_set_tsid(fe); + if (ret < 0) + goto failed; + ret = reg_write(state, &reset_sat, 1); + } else { + ret = tc90522t_set_layers(fe); + if (ret < 0) + goto failed; + ret = reg_write(state, &reset_ter, 1); + } + if (ret < 0) + goto failed; + + return 0; + +failed: + dev_warn(&state->tuner_i2c.dev, "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static int tc90522_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *settings) +{ + if (fe->ops.delsys[0] == SYS_ISDBS) { + settings->min_delay_ms = 250; + settings->step_size = 1000; + settings->max_drift = settings->step_size * 2; + } else { + settings->min_delay_ms = 400; + settings->step_size = 142857; + settings->max_drift = settings->step_size; + } + return 0; +} + +static int tc90522_set_if_agc(struct dvb_frontend *fe, bool on) +{ + struct reg_val agc_sat[] = { + { 0x0a, 0x00 }, + { 0x10, 0x30 }, + { 0x11, 0x00 }, + { 0x03, 0x01 }, + }; + struct reg_val agc_ter[] = { + { 0x25, 0x00 }, + { 0x23, 0x4c }, + { 0x01, 0x40 }, + }; + struct tc90522_state *state; + struct reg_val *rv; + int num; + + state = fe->demodulator_priv; + if (fe->ops.delsys[0] == SYS_ISDBS) { + agc_sat[0].val = on ? 0xff : 0x00; + agc_sat[1].val |= 0x80; + agc_sat[1].val |= on ? 0x01 : 0x00; + agc_sat[2].val |= on ? 0x40 : 0x00; + rv = agc_sat; + num = ARRAY_SIZE(agc_sat); + } else { + agc_ter[0].val = on ? 0x40 : 0x00; + agc_ter[1].val |= on ? 0x00 : 0x01; + rv = agc_ter; + num = ARRAY_SIZE(agc_ter); + } + return reg_write(state, rv, num); +} + +static const struct reg_val sleep_sat = { 0x17, 0x01 }; +static const struct reg_val sleep_ter = { 0x03, 0x90 }; + +static int tc90522_sleep(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + int ret; + + state = fe->demodulator_priv; + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = reg_write(state, &sleep_sat, 1); + else { + ret = reg_write(state, &sleep_ter, 1); + if (ret == 0 && fe->ops.set_lna && + fe->dtv_property_cache.lna == LNA_AUTO) { + fe->dtv_property_cache.lna = 0; + ret = fe->ops.set_lna(fe); + fe->dtv_property_cache.lna = LNA_AUTO; + } + } + if (ret < 0) + dev_warn(&state->tuner_i2c.dev, + "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; +} + +static const struct reg_val wakeup_sat = { 0x17, 0x00 }; +static const struct reg_val wakeup_ter = { 0x03, 0x80 }; + +static int tc90522_init(struct dvb_frontend *fe) +{ + struct tc90522_state *state; + int ret; + + /* + * Because the init sequence is not public, + * the parent device/driver should have init'ed the device before. + * just wake up the device here. + */ + + state = fe->demodulator_priv; + if (fe->ops.delsys[0] == SYS_ISDBS) + ret = reg_write(state, &wakeup_sat, 1); + else { + ret = reg_write(state, &wakeup_ter, 1); + if (ret == 0 && fe->ops.set_lna && + fe->dtv_property_cache.lna == LNA_AUTO) { + fe->dtv_property_cache.lna = 1; + ret = fe->ops.set_lna(fe); + fe->dtv_property_cache.lna = LNA_AUTO; + } + } + if (ret < 0) { + dev_warn(&state->tuner_i2c.dev, + "(%s) failed. [adap%d-fe%d]\n", + __func__, fe->dvb->num, fe->id); + return ret; + } + + /* prefer 'all-layers' to 'none' as a default */ + if (fe->dtv_property_cache.isdbt_layer_enabled == 0) + fe->dtv_property_cache.isdbt_layer_enabled = 7; + return tc90522_set_if_agc(fe, true); +} + + +/* + * tuner I2C adapter functions + */ + +static int +tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct tc90522_state *state; + struct i2c_msg *new_msgs; + int i, j; + int ret, rd_num; + u8 wbuf[256]; + u8 *p, *bufend; + + if (num <= 0) + return -EINVAL; + + rd_num = 0; + for (i = 0; i < num; i++) + if (msgs[i].flags & I2C_M_RD) + rd_num++; + new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL); + if (!new_msgs) + return -ENOMEM; + + state = i2c_get_adapdata(adap); + p = wbuf; + bufend = wbuf + sizeof(wbuf); + for (i = 0, j = 0; i < num; i++, j++) { + new_msgs[j].addr = state->i2c_client->addr; + new_msgs[j].flags = msgs[i].flags; + + if (msgs[i].flags & I2C_M_RD) { + new_msgs[j].flags &= ~I2C_M_RD; + if (p + 2 > bufend) + break; + p[0] = TC90522_I2C_THRU_REG; + p[1] = msgs[i].addr << 1 | 0x01; + new_msgs[j].buf = p; + new_msgs[j].len = 2; + p += 2; + j++; + new_msgs[j].addr = state->i2c_client->addr; + new_msgs[j].flags = msgs[i].flags; + new_msgs[j].buf = msgs[i].buf; + new_msgs[j].len = msgs[i].len; + continue; + } + + if (p + msgs[i].len + 2 > bufend) + break; + p[0] = TC90522_I2C_THRU_REG; + p[1] = msgs[i].addr << 1; + memcpy(p + 2, msgs[i].buf, msgs[i].len); + new_msgs[j].buf = p; + new_msgs[j].len = msgs[i].len + 2; + p += new_msgs[j].len; + } + + if (i < num) + ret = -ENOMEM; + else + ret = i2c_transfer(state->i2c_client->adapter, new_msgs, j); + if (ret >= 0 && ret < j) + ret = -EIO; + kfree(new_msgs); + return (ret == j) ? num : ret; +} + +static u32 tc90522_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C; +} + +static const struct i2c_algorithm tc90522_tuner_i2c_algo = { + .master_xfer = &tc90522_master_xfer, + .functionality = &tc90522_functionality, +}; + + +/* + * I2C driver functions + */ + +static const struct dvb_frontend_ops tc90522_ops_sat = { + .delsys = { SYS_ISDBS }, + .info = { + .name = "Toshiba TC90522 ISDB-S module", + .frequency_min = 950000, + .frequency_max = 2150000, + .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO, + }, + + .init = tc90522_init, + .sleep = tc90522_sleep, + .set_frontend = tc90522_set_frontend, + .get_tune_settings = tc90522_get_tune_settings, + + .get_frontend = tc90522s_get_frontend, + .read_status = tc90522s_read_status, +}; + +static const struct dvb_frontend_ops tc90522_ops_ter = { + .delsys = { SYS_ISDBT }, + .info = { + .name = "Toshiba TC90522 ISDB-T module", + .frequency_min = 470000000, + .frequency_max = 770000000, + .frequency_stepsize = 142857, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER | + FE_CAN_HIERARCHY_AUTO, + }, + + .init = tc90522_init, + .sleep = tc90522_sleep, + .set_frontend = tc90522_set_frontend, + .get_tune_settings = tc90522_get_tune_settings, + + .get_frontend = tc90522t_get_frontend, + .read_status = tc90522t_read_status, +}; + + +static int tc90522_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct tc90522_state *state; + struct tc90522_config *cfg; + const struct dvb_frontend_ops *ops; + struct i2c_adapter *adap; + int ret; + + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (!state) + return -ENOMEM; + state->i2c_client = client; + + cfg = client->dev.platform_data; + memcpy(&state->cfg, cfg, sizeof(state->cfg)); + cfg->fe = state->cfg.fe = &state->fe; + ops = id->driver_data == 0 ? &tc90522_ops_sat : &tc90522_ops_ter; + memcpy(&state->fe.ops, ops, sizeof(*ops)); + state->fe.demodulator_priv = state; + + adap = &state->tuner_i2c; + adap->owner = THIS_MODULE; + adap->algo = &tc90522_tuner_i2c_algo; + adap->dev.parent = &client->dev; + strlcpy(adap->name, "tc90522_sub", sizeof(adap->name)); + i2c_set_adapdata(adap, state); + ret = i2c_add_adapter(adap); + if (ret < 0) + goto err; + cfg->tuner_i2c = state->cfg.tuner_i2c = adap; + + i2c_set_clientdata(client, &state->cfg); + dev_info(&client->dev, "Toshiba TC90522 attached.\n"); + return 0; + +err: + kfree(state); + return ret; +} + +static int tc90522_remove(struct i2c_client *client) +{ + struct tc90522_state *state; + + state = cfg_to_state(i2c_get_clientdata(client)); + i2c_del_adapter(&state->tuner_i2c); + kfree(state); + return 0; +} + + +static const struct i2c_device_id tc90522_id[] = { + { TC90522_I2C_DEV_SAT, 0 }, + { TC90522_I2C_DEV_TER, 1 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, tc90522_id); + +static struct i2c_driver tc90522_driver = { + .driver = { + .name = "tc90522", + }, + .probe = tc90522_probe, + .remove = tc90522_remove, + .id_table = tc90522_id, +}; + +module_i2c_driver(tc90522_driver); + +MODULE_DESCRIPTION("Toshiba TC90522 frontend"); +MODULE_AUTHOR("Akihiro TSUKADA"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/tc90522.h b/drivers/media/dvb-frontends/tc90522.h new file mode 100644 index 000000000000..b1cbddfa6ee6 --- /dev/null +++ b/drivers/media/dvb-frontends/tc90522.h @@ -0,0 +1,42 @@ +/* + * Toshiba TC90522 Demodulator + * + * Copyright (C) 2014 Akihiro Tsukada <tskd08@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 version 2. + * + * + * 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. + */ + +/* + * The demod has 4 input (2xISDB-T and 2xISDB-S), + * and provides independent sub modules for each input. + * As the sub modules work in parallel and have the separate i2c addr's, + * this driver treats each sub module as one demod device. + */ + +#ifndef TC90522_H +#define TC90522_H + +#include <linux/i2c.h> +#include "dvb_frontend.h" + +/* I2C device types */ +#define TC90522_I2C_DEV_SAT "tc90522sat" +#define TC90522_I2C_DEV_TER "tc90522ter" + +struct tc90522_config { + /* [OUT] frontend returned by driver */ + struct dvb_frontend *fe; + + /* [OUT] tuner I2C adapter returned by driver */ + struct i2c_adapter *tuner_i2c; +}; + +#endif /* TC90522_H */ diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index 9619be5d4827..4a19b85995f1 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -1037,7 +1037,7 @@ static int tda10071_init(struct dvb_frontend *fe) ret = -EFAULT; goto error; } else { - priv->warm = 1; + priv->warm = true; } cmd.args[0] = CMD_GET_FW_VERSION; diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c index 91b6b2e9b792..ee09ec26c553 100644 --- a/drivers/media/dvb-frontends/zl10039.c +++ b/drivers/media/dvb-frontends/zl10039.c @@ -111,7 +111,7 @@ static int zl10039_write(struct zl10039_state *state, if (1 + count > sizeof(buf)) { printk(KERN_WARNING - "%s: i2c wr reg=%04x: len=%zd is too big!\n", + "%s: i2c wr reg=%04x: len=%zu is too big!\n", KBUILD_MODNAME, reg, count); return -EINVAL; } diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c index d1a1a1324ef8..251a556112a9 100644 --- a/drivers/media/firewire/firedtv-avc.c +++ b/drivers/media/firewire/firedtv-avc.c @@ -1157,6 +1157,10 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) if (pmt_cmd_id != 1 && pmt_cmd_id != 4) dev_err(fdtv->device, "invalid pmt_cmd_id %d\n", pmt_cmd_id); + if (program_info_length > sizeof(c->operand) - 4 - write_pos) { + ret = -EINVAL; + goto out; + } memcpy(&c->operand[write_pos], &msg[read_pos], program_info_length); @@ -1180,6 +1184,12 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) dev_err(fdtv->device, "invalid pmt_cmd_id %d " "at stream level\n", pmt_cmd_id); + if (es_info_length > sizeof(c->operand) - 4 - + write_pos) { + ret = -EINVAL; + goto out; + } + memcpy(&c->operand[write_pos], &msg[read_pos], es_info_length); read_pos += es_info_length; diff --git a/drivers/media/i2c/adv7343_regs.h b/drivers/media/i2c/adv7343_regs.h index 446606764346..2f04ce4b9118 100644 --- a/drivers/media/i2c/adv7343_regs.h +++ b/drivers/media/i2c/adv7343_regs.h @@ -13,7 +13,7 @@ * GNU General Public License for more details. */ -#ifndef ADV7343_REG_H +#ifndef ADV7343_REGS_H #define ADV7343_REGS_H struct adv7343_std_info { diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index de88b980a837..47795ff71688 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1593,7 +1593,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, bt->height += hdmi_read16(sd, 0x0b, 0xfff); bt->il_vfrontporch = hdmi_read16(sd, 0x2c, 0x1fff) / 2; bt->il_vsync = hdmi_read16(sd, 0x30, 0x1fff) / 2; - bt->vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; + bt->il_vbackporch = hdmi_read16(sd, 0x34, 0x1fff) / 2; } adv7604_fill_optional_dv_timings_fields(sd, timings); } else { diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 0d554919cdd5..48b628bc6714 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1435,6 +1435,8 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, v4l2_dbg(1, debug, sd, "%s:\n", __func__); + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + /* SDP block */ if (state->mode == ADV7842_MODE_SDP) return -ENODATA; @@ -1483,7 +1485,7 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd, hdmi_read(sd, 0x2d)) / 2; bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x1f) * 256 + hdmi_read(sd, 0x31)) / 2; - bt->vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + + bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x1f) * 256 + hdmi_read(sd, 0x35)) / 2; } adv7842_fill_optional_dv_timings_fields(sd, timings); diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index e6588ee5bdb0..4cf8f18bf097 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -224,7 +224,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { diff --git a/drivers/media/i2c/lm3560.c b/drivers/media/i2c/lm3560.c index c23de593c17d..d9ece4b2d047 100644 --- a/drivers/media/i2c/lm3560.c +++ b/drivers/media/i2c/lm3560.c @@ -100,14 +100,14 @@ static int lm3560_enable_ctrl(struct lm3560_flash *flash, int rval; if (led_no == LM3560_LED0) { - if (on == true) + if (on) rval = regmap_update_bits(flash->regmap, REG_ENABLE, 0x08, 0x08); else rval = regmap_update_bits(flash->regmap, REG_ENABLE, 0x08, 0x00); } else { - if (on == true) + if (on) rval = regmap_update_bits(flash->regmap, REG_ENABLE, 0x10, 0x10); else diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index cdd7c1b7259b..dd3db2458a4f 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -19,6 +19,7 @@ #include <media/v4l2-device.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-mediabus.h> +#include <media/v4l2-image-sizes.h> #include <media/ov7670.h> MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); @@ -30,19 +31,6 @@ module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); /* - * Basic window sizes. These probably belong somewhere more globally - * useful. - */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 - -/* * The 7670 sits on i2c with ID 0x42 */ #define OV7670_I2C_ADDR 0x42 diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 564f05f2c9ef..0e461a6fd065 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -816,7 +816,7 @@ static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state) "error setting frame interval: %d\n", err); state->error = -EINVAL; } - }; + } v4l2_err(&state->sd, "cannot find correct frame interval\n"); state->error = -ERANGE; } diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 04e9e55018a5..4024ea6f1371 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -660,7 +660,7 @@ static const struct v4l2_subdev_ops saa6752hs_ops = { static int saa6752hs_probe(struct i2c_client *client, const struct i2c_device_id *id) { - struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); + struct saa6752hs_state *h; struct v4l2_subdev *sd; struct v4l2_ctrl_handler *hdl; u8 addr = 0x13; @@ -668,6 +668,8 @@ static int saa6752hs_probe(struct i2c_client *client, v4l_info(client, "chip found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); + + h = devm_kzalloc(&client->dev, sizeof(*h), GFP_KERNEL); if (h == NULL) return -ENOMEM; sd = &h->sd; @@ -752,7 +754,6 @@ static int saa6752hs_probe(struct i2c_client *client, int err = hdl->error; v4l2_ctrl_handler_free(hdl); - kfree(h); return err; } v4l2_ctrl_cluster(3, &h->video_bitrate_mode); @@ -767,7 +768,6 @@ static int saa6752hs_remove(struct i2c_client *client) v4l2_device_unregister_subdev(sd); v4l2_ctrl_handler_free(&to_state(sd)->hdl); - kfree(to_state(sd)); return 0; } diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 62acb10630f9..932ed9be9ff3 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -31,8 +31,9 @@ #include <linux/device.h> #include <linux/gpio.h> #include <linux/module.h> -#include <linux/slab.h> #include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/smiapp.h> #include <linux/v4l2-mediabus.h> #include <media/v4l2-device.h> @@ -297,8 +298,9 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor) if (rval < 0) return rval; - *sensor->pixel_rate_parray->p_cur.p_s64 = pll->vt_pix_clk_freq_hz; - *sensor->pixel_rate_csi->p_cur.p_s64 = pll->pixel_rate_csi; + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray, + pll->vt_pix_clk_freq_hz); + __v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi); return 0; } @@ -319,13 +321,7 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) + sensor->vblank->val - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN]; - ctrl->maximum = max; - if (ctrl->default_value > max) - ctrl->default_value = max; - if (ctrl->val > max) - ctrl->val = max; - if (ctrl->cur.val > max) - ctrl->cur.val = max; + __v4l2_ctrl_modify_range(ctrl, ctrl->minimum, max, ctrl->step, max); } /* @@ -404,6 +400,14 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor) pixel_order_str[pixel_order]); } +static const char * const smiapp_test_patterns[] = { + "Disabled", + "Solid Colour", + "Eight Vertical Colour Bars", + "Colour Bars With Fade to Grey", + "Pseudorandom Sequence (PN9)", +}; + static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) { struct smiapp_sensor *sensor = @@ -477,6 +481,39 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) return smiapp_pll_update(sensor); + case V4L2_CID_TEST_PATTERN: { + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_activate( + sensor->test_data[i], + ctrl->val == + V4L2_SMIAPP_TEST_PATTERN_MODE_SOLID_COLOUR); + + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_PATTERN_MODE, ctrl->val); + } + + case V4L2_CID_TEST_PATTERN_RED: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_RED, ctrl->val); + + case V4L2_CID_TEST_PATTERN_GREENR: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_GREENR, ctrl->val); + + case V4L2_CID_TEST_PATTERN_BLUE: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_BLUE, ctrl->val); + + case V4L2_CID_TEST_PATTERN_GREENB: + return smiapp_write( + sensor, SMIAPP_REG_U16_TEST_DATA_GREENB, ctrl->val); + + case V4L2_CID_PIXEL_RATE: + /* For v4l2_ctrl_s_ctrl_int64() used internally. */ + return 0; + default: return -EINVAL; } @@ -489,10 +526,10 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { static int smiapp_init_controls(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - unsigned int max; + unsigned int max, i; int rval; - rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7); + rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12); if (rval) return rval; sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; @@ -535,6 +572,20 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); + v4l2_ctrl_new_std_menu_items(&sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(smiapp_test_patterns) - 1, + 0, 0, smiapp_test_patterns); + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { + int max_value = (1 << sensor->csi_format->width) - 1; + sensor->test_data[i] = + v4l2_ctrl_new_std( + &sensor->pixel_array->ctrl_handler, + &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i, + 0, max_value, 1, max_value); + } + if (sensor->pixel_array->ctrl_handler.error) { dev_err(&client->dev, "pixel array controls initialization failed (%d)\n", @@ -782,36 +833,25 @@ static void smiapp_update_blanking(struct smiapp_sensor *sensor) { struct v4l2_ctrl *vblank = sensor->vblank; struct v4l2_ctrl *hblank = sensor->hblank; + int min, max; - vblank->minimum = - max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], - sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); - vblank->maximum = - sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - + min = max_t(int, + sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], + sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); + max = sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; - vblank->val = clamp_t(int, vblank->val, - vblank->minimum, vblank->maximum); - vblank->default_value = vblank->minimum; - vblank->val = vblank->val; - vblank->cur.val = vblank->val; - - hblank->minimum = - max_t(int, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, - sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); - hblank->maximum = - sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - + __v4l2_ctrl_modify_range(vblank, min, max, vblank->step, min); + + min = max_t(int, + sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, + sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); + max = sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; - hblank->val = clamp_t(int, hblank->val, - hblank->minimum, hblank->maximum); - hblank->default_value = hblank->minimum; - hblank->val = hblank->val; - hblank->cur.val = hblank->val; + __v4l2_ctrl_modify_range(hblank, min, max, hblank->step, min); __smiapp_update_exposure_limits(sensor); } @@ -1272,7 +1312,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor) clk_disable_unprepare(sensor->ext_clk); usleep_range(5000, 5000); regulator_disable(sensor->vana); - sensor->streaming = 0; + sensor->streaming = false; } static int smiapp_set_power(struct v4l2_subdev *subdev, int on) @@ -1462,13 +1502,13 @@ static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) return 0; if (enable) { - sensor->streaming = 1; + sensor->streaming = true; rval = smiapp_start_streaming(sensor); if (rval < 0) - sensor->streaming = 0; + sensor->streaming = false; } else { rval = smiapp_stop_streaming(sensor); - sensor->streaming = 0; + sensor->streaming = false; } return rval; @@ -1664,17 +1704,34 @@ static int smiapp_set_format(struct v4l2_subdev *subdev, if (fmt->pad == ssd->source_pad) { u32 code = fmt->format.code; int rval = __smiapp_get_format(subdev, fh, fmt); + bool range_changed = false; + unsigned int i; if (!rval && subdev == &sensor->src->sd) { const struct smiapp_csi_data_format *csi_format = smiapp_validate_csi_data_format(sensor, code); - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + if (csi_format->width != + sensor->csi_format->width) + range_changed = true; + sensor->csi_format = csi_format; + } + fmt->format.code = csi_format->code; } mutex_unlock(&sensor->mutex); - return rval; + if (rval || !range_changed) + return rval; + + for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) + v4l2_ctrl_modify_range( + sensor->test_data[i], + 0, (1 << sensor->csi_format->width) - 1, 1, 0); + + return 0; } /* Sink pad. Width and height are changeable here. */ diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index 7cc5aae662fd..874b49ffd88f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -54,6 +54,8 @@ (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ + (clk) / 1000 - 1) / ((clk) / 1000)) +#define SMIAPP_COLOUR_COMPONENTS 4 + #include "smiapp-limits.h" struct smiapp_quirk; @@ -241,6 +243,8 @@ struct smiapp_sensor { /* src controls */ struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate_csi; + /* test pattern colour components */ + struct v4l2_ctrl *test_data[SMIAPP_COLOUR_COMPONENTS]; }; #define to_smiapp_subdev(_sd) \ diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c index 46f431a13782..996d7b4007a5 100644 --- a/drivers/media/i2c/soc_camera/mt9t112.c +++ b/drivers/media/i2c/soc_camera/mt9t112.c @@ -29,6 +29,7 @@ #include <media/soc_camera.h> #include <media/v4l2-clk.h> #include <media/v4l2-common.h> +#include <media/v4l2-image-sizes.h> /* you can check PLL/clock info */ /* #define EXT_CLOCK 24000000 */ @@ -42,9 +43,6 @@ #define MAX_WIDTH 2048 #define MAX_HEIGHT 1536 -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 - /* * macro of read/write */ diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 7f2b3c8926af..970a04e1e56e 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -29,6 +29,7 @@ #include <media/v4l2-clk.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-subdev.h> +#include <media/v4l2-image-sizes.h> /* * register offset @@ -360,10 +361,6 @@ #define SCAL0_ACTRL 0x08 /* Auto scaling factor control */ #define SCAL1_2_ACTRL 0x04 /* Auto scaling factor control */ -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 #define OV772X_MAX_WIDTH VGA_WIDTH #define OV772X_MAX_HEIGHT VGA_HEIGHT diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index ea76863dfdb4..ee9eb635d540 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -564,13 +564,13 @@ static int ov9740_set_res(struct i2c_client *client, u32 width, u32 height) u32 y_start; u32 x_end; u32 y_end; - bool scaling = 0; + bool scaling = false; u32 scale_input_x; u32 scale_input_y; int ret; if ((width != OV9740_MAX_WIDTH) || (height != OV9740_MAX_HEIGHT)) - scaling = 1; + scaling = true; /* * Try to use as much of the sensor area as possible when supporting diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index 72af644fa051..cf93021a6500 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -293,7 +293,7 @@ static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl) if (t->mute->val) { lf |= TDA7432_MUTE; lr |= TDA7432_MUTE; - lf |= TDA7432_MUTE; + rf |= TDA7432_MUTE; rr |= TDA7432_MUTE; } /* Mute & update balance*/ diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 11f2387e1dab..51bac762638b 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -775,25 +775,20 @@ static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index, static int tvp7002_s_stream(struct v4l2_subdev *sd, int enable) { struct tvp7002 *device = to_tvp7002(sd); - int error = 0; + int error; if (device->streaming == enable) return 0; - if (enable) { - /* Set output state on (low impedance means stream on) */ - error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x00); - device->streaming = enable; - } else { - /* Set output state off (high impedance means stream off) */ - error = tvp7002_write(sd, TVP7002_MISC_CTL_2, 0x03); - if (error) - v4l2_dbg(1, debug, sd, "Unable to stop streaming\n"); - - device->streaming = enable; + /* low impedance: on, high impedance: off */ + error = tvp7002_write(sd, TVP7002_MISC_CTL_2, enable ? 0x00 : 0x03); + if (error) { + v4l2_dbg(1, debug, sd, "Fail to set streaming\n"); + return error; } - return error; + device->streaming = enable; + return 0; } /* diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c index 23f4f65fccd7..373f2df52492 100644 --- a/drivers/media/i2c/vs6624.c +++ b/drivers/media/i2c/vs6624.c @@ -30,22 +30,10 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-mediabus.h> +#include <media/v4l2-image-sizes.h> #include "vs6624_regs.h" -#define VGA_WIDTH 640 -#define VGA_HEIGHT 480 -#define QVGA_WIDTH 320 -#define QVGA_HEIGHT 240 -#define QQVGA_WIDTH 160 -#define QQVGA_HEIGHT 120 -#define CIF_WIDTH 352 -#define CIF_HEIGHT 288 -#define QCIF_WIDTH 176 -#define QCIF_HEIGHT 144 -#define QQCIF_WIDTH 88 -#define QQCIF_HEIGHT 72 - #define MAX_FRAME_RATE 30 struct vs6624 { diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 73a432934bd8..7b39440192d6 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -103,10 +103,8 @@ static long media_device_enum_entities(struct media_device *mdev, return -EINVAL; u_ent.id = ent->id; - if (ent->name) { - strncpy(u_ent.name, ent->name, sizeof(u_ent.name)); - u_ent.name[sizeof(u_ent.name) - 1] = '\0'; - } + if (ent->name) + strlcpy(u_ent.name, ent->name, sizeof(u_ent.name)); u_ent.type = ent->type; u_ent.revision = ent->revision; u_ent.flags = ent->flags; diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 7acd19c881de..ebf9626e5ae5 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -192,7 +192,6 @@ static int media_open(struct inode *inode, struct file *filp) static int media_release(struct inode *inode, struct file *filp) { struct media_devnode *mdev = media_devnode_data(filp); - int ret = 0; if (mdev->fops->release) mdev->fops->release(filp); @@ -201,7 +200,7 @@ static int media_release(struct inode *inode, struct file *filp) return value is ignored. */ put_device(&mdev->dev); filp->private_data = NULL; - return ret; + return 0; } static const struct file_operations media_devnode_fops = { diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c index 9bc105b3db1b..e6b497528cea 100644 --- a/drivers/media/parport/pms.c +++ b/drivers/media/parport/pms.c @@ -629,11 +629,15 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) { int y; int dw = 2 * dev->width; - char tmp[dw + 32]; /* using a temp buffer is faster than direct */ + char *tmp; /* using a temp buffer is faster than direct */ int cnt = 0; int len = 0; unsigned char r8 = 0x5; /* value for reg8 */ + tmp = kmalloc(dw + 32, GFP_KERNEL); + if (!tmp) + return 0; + if (rgb555) r8 |= 0x20; /* else use untranslated rgb = 565 */ mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */ @@ -664,6 +668,7 @@ static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count) len += dt; } } + kfree(tmp); return len; } diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 5c16c9c2203e..f8cec8e8cf82 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -20,6 +20,7 @@ source "drivers/media/pci/ivtv/Kconfig" source "drivers/media/pci/zoran/Kconfig" source "drivers/media/pci/saa7146/Kconfig" source "drivers/media/pci/solo6x10/Kconfig" +source "drivers/media/pci/tw68/Kconfig" endif if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT @@ -41,6 +42,7 @@ source "drivers/media/pci/b2c2/Kconfig" source "drivers/media/pci/pluto2/Kconfig" source "drivers/media/pci/dm1105/Kconfig" source "drivers/media/pci/pt1/Kconfig" +source "drivers/media/pci/pt3/Kconfig" source "drivers/media/pci/mantis/Kconfig" source "drivers/media/pci/ngene/Kconfig" source "drivers/media/pci/ddbridge/Kconfig" diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile index e5b53fb569ef..a12926e4b51f 100644 --- a/drivers/media/pci/Makefile +++ b/drivers/media/pci/Makefile @@ -7,10 +7,10 @@ obj-y += ttpci/ \ pluto2/ \ dm1105/ \ pt1/ \ + pt3/ \ mantis/ \ ngene/ \ ddbridge/ \ - b2c2/ \ saa7146/ obj-$(CONFIG_VIDEO_IVTV) += ivtv/ @@ -22,6 +22,7 @@ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_BT848) += bt8xx/ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ +obj-$(CONFIG_VIDEO_TW68) += tw68/ obj-$(CONFIG_VIDEO_MEYE) += meye/ obj-$(CONFIG_STA2X11_VIP) += sta2x11/ obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 970e542d3a51..4a8176c09fc9 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -1531,7 +1531,6 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, { struct bttv_buffer *old; unsigned long flags; - int retval = 0; dprintk("switch_overlay: enter [new=%p]\n", new); if (new) @@ -1551,7 +1550,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh, if (NULL == new) free_btres_lock(btv,fh,RESOURCE_OVERLAY); dprintk("switch_overlay: done\n"); - return retval; + return 0; } /* ----------------------------------------------------------------------- */ @@ -3856,7 +3855,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) btwrite(btread(BT848_INT_MASK) & (-1 ^ BT848_INT_GPINT), BT848_INT_MASK); - }; + } bttv_print_irqbits(stat,astat); diff --git a/drivers/media/pci/bt8xx/dst_ca.c b/drivers/media/pci/bt8xx/dst_ca.c index 0e788fca992c..c22c4ae06844 100644 --- a/drivers/media/pci/bt8xx/dst_ca.c +++ b/drivers/media/pci/bt8xx/dst_ca.c @@ -674,11 +674,9 @@ static int dst_ca_release(struct inode *inode, struct file *file) static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { - ssize_t bytes_read = 0; - dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); - return bytes_read; + return 0; } static ssize_t dst_ca_write(struct file *file, const char __user *buffer, size_t length, loff_t *offset) diff --git a/drivers/media/pci/cx18/cx18-alsa-pcm.c b/drivers/media/pci/cx18/cx18-alsa-pcm.c index 180077c49123..ffb6acdc575f 100644 --- a/drivers/media/pci/cx18/cx18-alsa-pcm.c +++ b/drivers/media/pci/cx18/cx18-alsa-pcm.c @@ -80,7 +80,7 @@ void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, int period_elapsed = 0; int length; - dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc, + dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zu\n", cxsc, pcm_data, num_bytes); substream = cxsc->capture_pcm_substream; diff --git a/drivers/media/pci/cx18/cx18-firmware.c b/drivers/media/pci/cx18/cx18-firmware.c index a1c1cec05f98..c6c83445f8bf 100644 --- a/drivers/media/pci/cx18/cx18-firmware.c +++ b/drivers/media/pci/cx18/cx18-firmware.c @@ -130,7 +130,7 @@ static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) } } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); + CX18_INFO("loaded %s firmware (%zu bytes)\n", fn, fw->size); size = fw->size; release_firmware(fw); cx18_setup_page(cx, SCB_OFFSET); @@ -164,7 +164,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; while (offset + sizeof(seghdr) < fw->size) { - const u32 *shptr = src + offset / 4; + const __le32 *shptr = (__force __le32 *)src + offset / 4; seghdr.sync1 = le32_to_cpu(shptr[0]); seghdr.sync2 = le32_to_cpu(shptr[1]); @@ -202,7 +202,7 @@ static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, offset += seghdr.size; } if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", + CX18_INFO("loaded %s firmware V%08x (%zu bytes)\n", fn, apu_version, fw->size); size = fw->size; release_firmware(fw); diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c index 8884537bd62f..2a247d264b87 100644 --- a/drivers/media/pci/cx18/cx18-queue.c +++ b/drivers/media/pci/cx18/cx18-queue.c @@ -364,7 +364,7 @@ int cx18_stream_alloc(struct cx18_stream *s) ((char __iomem *)cx->scb->cpu_mdl)); CX18_ERR("Too many buffers, cannot fit in SCB area\n"); - CX18_ERR("Max buffers = %zd\n", + CX18_ERR("Max buffers = %zu\n", bufsz / sizeof(struct cx18_mdl_ent)); return -ENOMEM; } diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index e12c006e6e2d..f613314b360b 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -3,12 +3,11 @@ config VIDEO_CX23885 depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND select SND_PCM select I2C_ALGOBIT - select VIDEO_BTCX select VIDEO_TUNER select VIDEO_TVEEPROM depends on RC_CORE - select VIDEOBUF_DVB - select VIDEOBUF_DMA_SG + select VIDEOBUF2_DVB + select VIDEOBUF2_DMA_SG select VIDEO_CX25840 select VIDEO_CX2341X select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT @@ -32,12 +31,16 @@ config VIDEO_CX23885 select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT + select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for Conexant 23885 based diff --git a/drivers/media/pci/cx23885/Makefile b/drivers/media/pci/cx23885/Makefile index 2a2cafb8cf5b..a2cbdcf15a8c 100644 --- a/drivers/media/pci/cx23885/Makefile +++ b/drivers/media/pci/cx23885/Makefile @@ -8,7 +8,6 @@ obj-$(CONFIG_VIDEO_CX23885) += cx23885.o obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o ccflags-y += -Idrivers/media/i2c -ccflags-y += -Idrivers/media/common ccflags-y += -Idrivers/media/tuners ccflags-y += -Idrivers/media/dvb-core ccflags-y += -Idrivers/media/dvb-frontends diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index 2926f7fadccd..2bbbf545b042 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -16,10 +16,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -52,8 +48,8 @@ * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| * +-------+-------+-------+-------+-------+-------+-------+-------+ */ -#include <media/videobuf-dma-sg.h> -#include <media/videobuf-dvb.h> +#include <dvb_demux.h> +#include <dvb_frontend.h> #include "altera-ci.h" #include "dvb_ca_en50221.h" diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 4998c96caebe..5028f0cf83f4 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -16,10 +16,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef __ALTERA_CI_H #define __ALTERA_CI_H diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 16fa7ea4d4aa..631e4f24aea6 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -17,10 +17,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx23885.h" diff --git a/drivers/media/pci/cx23885/cimax2.h b/drivers/media/pci/cx23885/cimax2.h index 518744a4c8a5..565e958f6f8d 100644 --- a/drivers/media/pci/cx23885/cimax2.h +++ b/drivers/media/pci/cx23885/cimax2.h @@ -17,10 +17,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef CIMAX2_H diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index bf89fc88692e..3948db386fb5 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -18,10 +18,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -865,6 +861,11 @@ static int cx23885_api_cmd(struct cx23885_dev *dev, return err; } +static int cx23885_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +{ + return cx23885_mbox_func(priv, cmd, in, out, data); +} + static int cx23885_find_mailbox(struct cx23885_dev *dev) { u32 signature[4] = { @@ -941,7 +942,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zd, expected %d)\n", + "(have %zu, expected %d)\n", firmware->size, CX23885_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; @@ -1033,12 +1034,12 @@ static void cx23885_codec_settings(struct cx23885_dev *dev) cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->ts1.height, dev->ts1.width); - dev->mpeg_params.width = dev->ts1.width; - dev->mpeg_params.height = dev->ts1.height; - dev->mpeg_params.is_50hz = + dev->cxhdl.width = dev->ts1.width; + dev->cxhdl.height = dev->ts1.height; + dev->cxhdl.is_50hz = (dev->encodernorm.id & V4L2_STD_625_50) != 0; - cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params); + cx2341x_handler_setup(&dev->cxhdl); cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1); cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1); @@ -1137,85 +1138,107 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) /* ------------------------------------------------------------------ */ -static int bb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_fh *fh = q->priv_data; - - fh->dev->ts1.ts_packet_size = mpeglinesize; - fh->dev->ts1.ts_packet_count = mpeglines; - - *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count; - *count = mpegbufs; + struct cx23885_dev *dev = q->drv_priv; + dev->ts1.ts_packet_size = mpeglinesize; + dev->ts1.ts_packet_count = mpeglines; + *num_planes = 1; + sizes[0] = mpeglinesize * mpeglines; + *num_buffers = mpegbufs; return 0; } -static int bb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - return cx23885_buf_prepare(q, &fh->dev->ts1, - (struct cx23885_buffer *)vb, - field); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + return cx23885_buf_prepare(buf, &dev->ts1); } -static void bb_buf_queue(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(dev, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void bb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); -} + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); -static struct videobuf_queue_ops cx23885_qops = { - .buf_setup = bb_buf_setup, - .buf_prepare = bb_buf_prepare, - .buf_queue = bb_buf_queue, - .buf_release = bb_buf_release, -}; + cx23885_buf_queue(&dev->ts1, buf); +} -/* ------------------------------------------------------------------ */ +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->ts1.mpegq; + unsigned long flags; + int ret; + + ret = cx23885_initialize_codec(dev, 1); + if (ret == 0) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + cx23885_start_dma(&dev->ts1, dmaq, buf); + return 0; + } + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); -static const u32 *ctrl_classes[] = { - cx2341x_mpeg_ctrls, - NULL -}; + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&dev->slock, flags); + return ret; +} -static int cx23885_queryctrl(struct cx23885_dev *dev, - struct v4l2_queryctrl *qctrl) +static void cx23885_stop_streaming(struct vb2_queue *q) { - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; + struct cx23885_dev *dev = q->drv_priv; - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + /* stop mpeg capture */ + cx23885_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, + CX23885_END_NOW, CX23885_MPEG_CAPTURE, + CX23885_RAW_BITS_NONE); - return 0; + msleep(500); + cx23885_417_check_encoder(dev); + cx23885_cancel_buffers(&dev->ts1); } -static int cx23885_querymenu(struct cx23885_dev *dev, - struct v4l2_querymenu *qmenu) -{ - struct v4l2_queryctrl qctrl; +static struct vb2_ops cx23885_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; - qctrl.id = qmenu->id; - cx23885_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id)); -} +/* ------------------------------------------------------------------ */ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); *id = dev->tvnorm; return 0; @@ -1223,29 +1246,26 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); unsigned int i; + int ret; for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++) if (id & cx23885_tvnorms[i].id) break; if (i == ARRAY_SIZE(cx23885_tvnorms)) return -EINVAL; - dev->encodernorm = cx23885_tvnorms[i]; - /* Have the drier core notify the subdevices */ - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, id); - mutex_unlock(&dev->lock); - - return 0; + ret = cx23885_set_tvnorm(dev, id); + if (!ret) + dev->encodernorm = cx23885_tvnorms[i]; + return ret; } static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); return cx23885_enum_input(dev, i); } @@ -1263,8 +1283,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1281,8 +1300,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1296,8 +1314,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1315,27 +1332,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, return cx23885_set_frequency(file, priv, f); } -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_tsport *tsport = &dev->ts1; strlcpy(cap->driver, dev->name, sizeof(cap->driver)); @@ -1368,8 +1368,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; @@ -1378,285 +1377,63 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = 0; f->fmt.pix.width = dev->ts1.width; f->fmt.pix.height = dev->ts1.height; - f->fmt.pix.field = fh->mpegq.field; - dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); return 0; } static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; f->fmt.pix.sizeimage = dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; f->fmt.pix.colorspace = 0; - dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", - dev->ts1.width, dev->ts1.height, fh->mpegq.field); + f->fmt.pix.field = V4L2_FIELD_INTERLACED; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n", + dev->ts1.width, dev->ts1.height); return 0; } static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; f->fmt.pix.sizeimage = dev->ts1.ts_packet_size * dev->ts1.ts_packet_count; f->fmt.pix.colorspace = 0; + f->fmt.pix.field = V4L2_FIELD_INTERLACED; dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_reqbufs(&fh->mpegq, p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_querybuf(&fh->mpegq, p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_qbuf(&fh->mpegq, p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx23885_fh *fh = priv; - - return videobuf_dqbuf(&fh->mpegq, b, file->f_flags & O_NONBLOCK); -} - - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamon(&fh->mpegq); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_streamoff(&fh->mpegq); -} - -static int vidioc_g_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - - if (err == 0) { - err = cx2341x_update(dev, cx23885_mbox_func, - &dev->mpeg_params, &p); - dev->mpeg_params = p; - } - return err; -} - -static int vidioc_try_ext_ctrls(struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - - p = dev->mpeg_params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - return err; -} - static int vidioc_log_status(struct file *file, void *priv) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", dev->name); - printk(KERN_INFO - "%s/2: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); - cx2341x_log_status(&dev->mpeg_params, name); - printk(KERN_INFO - "%s/2: ============= END LOG STATUS =============\n", - dev->name); + v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name); return 0; } -static int vidioc_querymenu(struct file *file, void *priv, - struct v4l2_querymenu *a) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_querymenu(dev, a); -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *c) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - - return cx23885_queryctrl(dev, c); -} - -static int mpeg_open(struct file *file) -{ - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - - dprintk(2, "%s()\n", __func__); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (!fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - - videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops, - &dev->pci->dev, &dev->ts1.slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - return 0; -} - -static int mpeg_release(struct file *file) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - /* FIXME: Review this crap */ - /* Shut device down on last close */ - if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) { - if (atomic_dec_return(&dev->v4l_reader_count) == 0) { - /* stop mpeg capture */ - cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - CX23885_END_NOW, CX23885_MPEG_CAPTURE, - CX23885_RAW_BITS_NONE); - - msleep(500); - cx23885_417_check_encoder(dev); - - cx23885_cancel_buffers(&fh->dev->ts1); - } - } - - if (fh->mpegq.streaming) - videobuf_streamoff(&fh->mpegq); - if (fh->mpegq.reading) - videobuf_read_stop(&fh->mpegq); - - videobuf_mmap_free(&fh->mpegq); - file->private_data = NULL; - kfree(fh); - - return 0; -} - -static ssize_t mpeg_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - /* Deal w/ A/V decoder * and mpeg encoder sync issues. */ - /* Start mpeg encoder on first read. */ - if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) { - if (atomic_inc_return(&dev->v4l_reader_count) == 1) { - if (cx23885_initialize_codec(dev, 1) < 0) - return -EINVAL; - } - } - - return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0, - file->f_flags & O_NONBLOCK); -} - -static unsigned int mpeg_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s\n", __func__); - - return videobuf_poll_stream(file, &fh->mpegq, wait); -} - -static int mpeg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - dprintk(2, "%s()\n", __func__); - - return videobuf_mmap_mapper(&fh->mpegq, vma); -} - static struct v4l2_file_operations mpeg_fops = { .owner = THIS_MODULE, - .open = mpeg_open, - .release = mpeg_release, - .read = mpeg_read, - .poll = mpeg_poll, - .mmap = mpeg_mmap, - .ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { @@ -1669,25 +1446,19 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_log_status = vidioc_log_status, - .vidioc_querymenu = vidioc_querymenu, - .vidioc_queryctrl = vidioc_queryctrl, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_chip_info = cx23885_g_chip_info, .vidioc_g_register = cx23885_g_register, @@ -1711,6 +1482,7 @@ void cx23885_417_unregister(struct cx23885_dev *dev) video_unregister_device(dev->v4l_device); else video_device_release(dev->v4l_device); + v4l2_ctrl_handler_free(&dev->cxhdl.hdl); dev->v4l_device = NULL; } } @@ -1742,6 +1514,7 @@ int cx23885_417_register(struct cx23885_dev *dev) /* FIXME: Port1 hardcoded here */ int err = -ENODEV; struct cx23885_tsport *tsport = &dev->ts1; + struct vb2_queue *q; dprintk(1, "%s()\n", __func__); @@ -1757,14 +1530,36 @@ int cx23885_417_register(struct cx23885_dev *dev) tsport->height = 576; tsport->width = 720; - cx2341x_fill_defaults(&dev->mpeg_params); - - dev->mpeg_params.port = CX2341X_PORT_SERIAL; + dev->cxhdl.port = CX2341X_PORT_SERIAL; + err = cx2341x_handler_init(&dev->cxhdl, 50); + if (err) + return err; + dev->cxhdl.priv = dev; + dev->cxhdl.func = cx23885_api_func; + cx2341x_handler_set_50hz(&dev->cxhdl, tsport->height == 576); + v4l2_ctrl_add_handler(&dev->ctrl_handler, &dev->cxhdl.hdl, NULL); /* Allocate and initialize V4L video device */ dev->v4l_device = cx23885_video_dev_alloc(tsport, dev->pci, &cx23885_mpeg_template, "mpeg"); + q = &dev->vb2_mpegq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + return err; video_set_drvdata(dev->v4l_device, dev); + dev->v4l_device->lock = &dev->lock; + dev->v4l_device->queue = q; err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 554798dcedd0..ae7c2e89ad1c 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -15,10 +15,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -84,6 +80,82 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]"); #define AUD_INT_MCHG_IRQ (1 << 21) #define GP_COUNT_CONTROL_RESET 0x3 +static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages) +{ + struct cx23885_audio_buffer *buf = chip->buf; + struct page *pg; + int i; + + buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); + if (NULL == buf->vaddr) { + dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); + return -ENOMEM; + } + + dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", + (unsigned long)buf->vaddr, + nr_pages << PAGE_SHIFT); + + memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); + buf->nr_pages = nr_pages; + + buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); + if (NULL == buf->sglist) + goto vzalloc_err; + + sg_init_table(buf->sglist, buf->nr_pages); + for (i = 0; i < buf->nr_pages; i++) { + pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); + if (NULL == pg) + goto vmalloc_to_page_err; + sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); + } + return 0; + +vmalloc_to_page_err: + vfree(buf->sglist); + buf->sglist = NULL; +vzalloc_err: + vfree(buf->vaddr); + buf->vaddr = NULL; + return -ENOMEM; +} + +static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev) +{ + struct cx23885_audio_buffer *buf = dev->buf; + + buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist, + buf->nr_pages, PCI_DMA_FROMDEVICE); + + if (0 == buf->sglen) { + pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__); + return -ENOMEM; + } + return 0; +} + +static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev) +{ + struct cx23885_audio_buffer *buf = dev->buf; + + if (!buf->sglen) + return 0; + + dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE); + buf->sglen = 0; + return 0; +} + +static int cx23885_alsa_dma_free(struct cx23885_audio_buffer *buf) +{ + vfree(buf->sglist); + buf->sglist = NULL; + vfree(buf->vaddr); + buf->vaddr = NULL; + return 0; +} + /* * BOARD Specific: Sets audio DMA */ @@ -198,15 +270,18 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask) static int dsp_buffer_free(struct cx23885_audio_dev *chip) { + struct cx23885_riscmem *risc; + BUG_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); - videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc); - videobuf_dma_free(chip->dma_risc); - btcx_riscmem_free(chip->pci, &chip->buf->risc); + cx23885_alsa_dma_unmap(chip); + cx23885_alsa_dma_free(chip->buf); + risc = &chip->buf->risc; + pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); kfree(chip->buf); - chip->dma_risc = NULL; + chip->buf = NULL; chip->dma_size = 0; return 0; @@ -289,6 +364,7 @@ static int snd_cx23885_close(struct snd_pcm_substream *substream) return 0; } + /* * hw_params callback */ @@ -296,8 +372,6 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct cx23885_audio_dev *chip = snd_pcm_substream_chip(substream); - struct videobuf_dmabuf *dma; - struct cx23885_audio_buffer *buf; int ret; @@ -318,19 +392,18 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, return -ENOMEM; buf->bpl = chip->period_size; + chip->buf = buf; - dma = &buf->dma; - videobuf_dma_init(dma); - ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE, + ret = cx23885_alsa_dma_init(chip, (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; - ret = videobuf_dma_map(&chip->pci->dev, dma); + ret = cx23885_alsa_dma_map(chip); if (ret < 0) goto error; - ret = cx23885_risc_databuffer(chip->pci, &buf->risc, dma->sglist, + ret = cx23885_risc_databuffer(chip->pci, &buf->risc, buf->sglist, chip->period_size, chip->num_periods, 1); if (ret < 0) goto error; @@ -340,10 +413,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - chip->buf = buf; - chip->dma_risc = dma; - - substream->runtime->dma_area = chip->dma_risc->vaddr; + substream->runtime->dma_area = chip->buf->vaddr; substream->runtime->dma_bytes = chip->dma_size; substream->runtime->dma_addr = 0; @@ -351,6 +421,7 @@ static int snd_cx23885_hw_params(struct snd_pcm_substream *substream, error: kfree(buf); + chip->buf = NULL; return ret; } diff --git a/drivers/media/pci/cx23885/cx23885-av.c b/drivers/media/pci/cx23885/cx23885-av.c index c443b7ac5adf..877dad89107e 100644 --- a/drivers/media/pci/cx23885/cx23885-av.c +++ b/drivers/media/pci/cx23885/cx23885-av.c @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-av.h b/drivers/media/pci/cx23885/cx23885-av.h index d2915c3e53a2..97f232f8efb9 100644 --- a/drivers/media/pci/cx23885/cx23885-av.h +++ b/drivers/media/pci/cx23885/cx23885-av.h @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_AV_H_ diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index c2b608007190..88c257d1161b 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/init.h> @@ -679,6 +675,11 @@ struct cx23885_board cx23885_boards[] = { .amux = CX25840_AUDIO7, } }, }, + [CX23885_BOARD_DVBSKY_T9580] = { + .name = "DVBSky T9580", + .portb = CX23885_MPEG_DVB, + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -934,6 +935,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xdb98, .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2, + }, { + .subvendor = 0x4254, + .subdevice = 0x9580, + .card = CX23885_BOARD_DVBSKY_T9580, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -1528,6 +1533,14 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) cx_set(GP0_IO, 0x00040004); mdelay(60); break; + case CX23885_BOARD_DVBSKY_T9580: + /* enable GPIO3-18 pins */ + cx_write(MC417_CTL, 0x00000037); + cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1); + cx23885_gpio_clear(dev, GPIO_2 | GPIO_11); + mdelay(100); + cx23885_gpio_set(dev, GPIO_2 | GPIO_11); + break; } } @@ -1851,6 +1864,14 @@ void cx23885_card_setup(struct cx23885_dev *dev) ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; break; + case CX23885_BOARD_DVBSKY_T9580: + ts1->gen_ctrl_val = 0x5; /* Parallel */ + ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + ts2->gen_ctrl_val = 0x8; /* Serial bus */ + ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ + ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; + break; case CX23885_BOARD_HAUPPAUGE_HVR1250: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: @@ -1913,6 +1934,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_AVERMEDIA_HC81R: case CX23885_BOARD_TBS_6980: case CX23885_BOARD_TBS_6981: + case CX23885_BOARD_DVBSKY_T9580: dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_bus[2].i2c_adap, "cx25840", 0x88 >> 1, NULL); @@ -1970,5 +1992,3 @@ void cx23885_card_setup(struct cx23885_dev *dev) } } } - -/* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index edcd79db1e4e..331eddac7222 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/init.h> @@ -420,39 +416,23 @@ static int cx23885_risc_decode(u32 risc) return incr[risc >> 28] ? incr[risc >> 28] : 1; } -void cx23885_wakeup(struct cx23885_tsport *port, +static void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - v4l2_get_timestamp(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_WARNING "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + buf->vb.v4l2_buf.sequence = q->count++; + dprintk(1, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index, + count, q->count); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } int cx23885_sram_channel_setup(struct cx23885_dev *dev, @@ -482,8 +462,8 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev, lines = 6; BUG_ON(lines < 2); - cx_write(8 + 0, RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - cx_write(8 + 4, 8); + cx_write(8 + 0, RISC_JUMP | RISC_CNT_RESET); + cx_write(8 + 4, 12); cx_write(8 + 8, 0); /* write CDT */ @@ -590,7 +570,7 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, } static void cx23885_risc_disasm(struct cx23885_tsport *port, - struct btcx_riscmem *risc) + struct cx23885_riscmem *risc) { struct cx23885_dev *dev = port->dev; unsigned int i, j, n; @@ -699,10 +679,6 @@ static int get_resources(struct cx23885_dev *dev) return -EBUSY; } -static void cx23885_timeout(unsigned long data); -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno) { @@ -719,11 +695,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, port->nr = portno; INIT_LIST_HEAD(&port->mpegq.active); - INIT_LIST_HEAD(&port->mpegq.queued); - port->mpegq.timeout.function = cx23885_timeout; - port->mpegq.timeout.data = (unsigned long)port; - init_timer(&port->mpegq.timeout); - mutex_init(&port->frontends.lock); INIT_LIST_HEAD(&port->frontends.felist); port->frontends.active_fe_id = 0; @@ -776,9 +747,6 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, BUG(); } - cx23885_risc_stopper(dev->pci, &port->mpegq.stopper, - port->reg_dma_ctl, port->dma_ctl_val, 0x00); - return 0; } @@ -1089,11 +1057,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev) static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi) + unsigned int lines, unsigned int lpi, bool jump) { struct scatterlist *sg; unsigned int line, todo, sol; + + if (jump) { + *(rp++) = cpu_to_le32(RISC_JUMP); + *(rp++) = cpu_to_le32(0); + *(rp++) = cpu_to_le32(0); /* bits 63-32 */ + } + /* sync instruction */ if (sync_line != NO_SYNC_LINE) *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line); @@ -1146,14 +1121,13 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist, return rp; } -int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -1168,19 +1142,20 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + instructions += 5; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; if (UNSET != top_offset) rp = cx23885_risc_field(rp, sglist, top_offset, 0, - bpl, padding, lines, 0); + bpl, padding, lines, 0, true); if (UNSET != bottom_offset) rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines, 0); + bpl, padding, lines, 0, UNSET == top_offset); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1189,14 +1164,13 @@ int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, } int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi) { u32 instructions; __le32 *rp; - int rc; /* estimate risc mem: worst case is one write per page border + one write per scan line + syncs + jump (all 2 dwords). Here @@ -1204,16 +1178,17 @@ int cx23885_risc_databuffer(struct pci_dev *pci, than PAGE_SIZE */ /* Jump and write need an extra dword */ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; - instructions += 1; + instructions += 4; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; rp = cx23885_risc_field(rp, sglist, 0, NO_SYNC_LINE, - bpl, 0, lines, lpi); + bpl, 0, lines, lpi, lpi == 0); /* save pointer to jmp instruction address */ risc->jmp = rp; @@ -1221,14 +1196,13 @@ int cx23885_risc_databuffer(struct pci_dev *pci, return 0; } -int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, +int cx23885_risc_vbibuffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { u32 instructions, fields; __le32 *rp; - int rc; fields = 0; if (UNSET != top_offset) @@ -1243,22 +1217,23 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* write and jump need and extra dword */ instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); - instructions += 2; - rc = btcx_riscmem_alloc(pci, risc, instructions*12); - if (rc < 0) - return rc; + instructions += 5; + risc->size = instructions * 12; + risc->cpu = pci_alloc_consistent(pci, risc->size, &risc->dma); + if (risc->cpu == NULL) + return -ENOMEM; /* write risc instructions */ rp = risc->cpu; /* Sync to line 6, so US CC line 21 will appear in line '12' * in the userland vbi payload */ if (UNSET != top_offset) - rp = cx23885_risc_field(rp, sglist, top_offset, 6, - bpl, padding, lines, 0); + rp = cx23885_risc_field(rp, sglist, top_offset, 0, + bpl, padding, lines, 0, true); if (UNSET != bottom_offset) - rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x207, - bpl, padding, lines, 0); + rp = cx23885_risc_field(rp, sglist, bottom_offset, 0x200, + bpl, padding, lines, 0, UNSET == top_offset); @@ -1269,38 +1244,12 @@ int cx23885_risc_vbibuffer(struct pci_dev *pci, struct btcx_riscmem *risc, } -int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value) +void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf) { - __le32 *rp; - int rc; - - rc = btcx_riscmem_alloc(pci, risc, 4*16); - if (rc < 0) - return rc; - - /* write risc instructions */ - rp = risc->cpu; - *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2); - *(rp++) = cpu_to_le32(reg); - *(rp++) = cpu_to_le32(value); - *(rp++) = cpu_to_le32(mask); - *(rp++) = cpu_to_le32(RISC_JUMP); - *(rp++) = cpu_to_le32(risc->dma); - *(rp++) = cpu_to_le32(0); /* bits 63-32 */ - return 0; -} - -void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + struct cx23885_riscmem *risc = &buf->risc; BUG_ON(in_interrupt()); - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_dma_unmap(q->dev, dma); - videobuf_dma_free(dma); - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; + pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); } static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) @@ -1355,7 +1304,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk)); } -static int cx23885_start_dma(struct cx23885_tsport *port, +int cx23885_start_dma(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, struct cx23885_buffer *buf) { @@ -1363,7 +1312,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, u32 reg; dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, - buf->vb.width, buf->vb.height, buf->vb.field); + dev->width, dev->height, dev->field); /* Stop the fifo and risc engine for this port */ cx_clear(port->reg_dma_ctl, port->dma_ctl_val); @@ -1379,7 +1328,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, } /* write TS length to chip */ - cx_write(port->reg_lngth, buf->vb.width); + cx_write(port->reg_lngth, port->ts_packet_size); if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { @@ -1408,7 +1357,7 @@ static int cx23885_start_dma(struct cx23885_tsport *port, /* NOTE: this is 2 (reserved) for portb, does it matter? */ /* reset counter to zero */ cx_write(port->reg_gpcnt_ctl, 3); - q->count = 1; + q->count = 0; /* Set VIDB pins to input */ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { @@ -1497,134 +1446,83 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) return 0; } -int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q) -{ - struct cx23885_dev *dev = port->dev; - struct cx23885_buffer *buf; - - dprintk(5, "%s()\n", __func__); - if (list_empty(&q->active)) { - struct cx23885_buffer *prev; - prev = NULL; - - dprintk(5, "%s() queue is empty\n", __func__); - - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_dma(port, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(5, "[%p/%d] restart_queue - f/active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - 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); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(5, "[%p/%d] restart_queue - m/active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } - return 0; - } - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_dma(port, q, buf); - list_for_each_entry(buf, &q->active, vb.queue) - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; -} - /* ------------------------------------------------------------------ */ -int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port, - struct cx23885_buffer *buf, enum v4l2_field field) +int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; int size = port->ts_packet_size * port->ts_packet_count; + struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0); int rc; dprintk(1, "%s: %p\n", __func__, buf); - if (0 != buf->vb.baddr && buf->vb.bsize < size) + if (vb2_plane_size(&buf->vb, 0) < size) return -EINVAL; + vb2_set_plane_payload(&buf->vb, 0, size); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = port->ts_packet_size; - buf->vb.height = port->ts_packet_count; - buf->vb.size = size; - buf->vb.field = field /*V4L2_FIELD_TOP*/; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_databuffer(dev->pci, &buf->risc, - videobuf_to_dma(&buf->vb)->sglist, - buf->vb.width, buf->vb.height, 0); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!rc) + return -EIO; - fail: - cx23885_free_buffer(q, buf); - return rc; + cx23885_risc_databuffer(dev->pci, &buf->risc, + sgt->sgl, + port->ts_packet_size, port->ts_packet_count, 0); + return 0; } +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) { struct cx23885_buffer *prev; struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *cx88q = &port->mpegq; + unsigned long flags; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma); + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ + spin_lock_irqsave(&dev->slock, flags); if (list_empty(&cx88q->active)) { - dprintk(1, "queue is empty - first active\n"); - list_add_tail(&buf->vb.queue, &cx88q->active); - cx23885_start_dma(port, cx88q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; - mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT); + list_add_tail(&buf->queue, &cx88q->active); dprintk(1, "[%p/%d] %s - first active\n", - buf, buf->vb.i, __func__); + buf, buf->vb.v4l2_buf.index, __func__); } else { - dprintk(1, "queue is not empty - append to active\n"); + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(cx88q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &cx88q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = cx88q->count++; + queue); + list_add_tail(&buf->queue, &cx88q->active); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */ dprintk(1, "[%p/%d] %s - append to active\n", - buf, buf->vb.i, __func__); + buf, buf->vb.v4l2_buf.index, __func__); } + spin_unlock_irqrestore(&dev->slock, flags); } /* ----------------------------------------------------------- */ -static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, - int restart) +static void do_cancel_buffers(struct cx23885_tsport *port, char *reason) { struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; @@ -1634,16 +1532,11 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, spin_lock_irqsave(&port->slock, flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); + queue); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); dprintk(1, "[%p/%d] %s - dma=0x%08lx\n", - buf, buf->vb.i, reason, (unsigned long)buf->risc.dma); - } - if (restart) { - dprintk(1, "restarting queue\n"); - cx23885_restart_queue(port, q); + buf, buf->vb.v4l2_buf.index, reason, (unsigned long)buf->risc.dma); } spin_unlock_irqrestore(&port->slock, flags); } @@ -1651,27 +1544,10 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason, void cx23885_cancel_buffers(struct cx23885_tsport *port) { struct cx23885_dev *dev = port->dev; - struct cx23885_dmaqueue *q = &port->mpegq; - - dprintk(1, "%s()\n", __func__); - del_timer_sync(&q->timeout); - cx23885_stop_dma(port); - do_cancel_buffers(port, "cancel", 0); -} - -static void cx23885_timeout(unsigned long data) -{ - struct cx23885_tsport *port = (struct cx23885_tsport *)data; - struct cx23885_dev *dev = port->dev; dprintk(1, "%s()\n", __func__); - - if (debug > 5) - cx23885_sram_channel_dump(dev, - &dev->sram_channels[port->sram_chno]); - cx23885_stop_dma(port); - do_cancel_buffers(port, "timeout", 1); + do_cancel_buffers(port, "cancel"); } int cx23885_irq_417(struct cx23885_dev *dev, u32 status) @@ -1721,11 +1597,6 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status) spin_lock(&port->slock); cx23885_wakeup(port, &port->mpegq, count); spin_unlock(&port->slock); - } else if (status & VID_B_MSK_RISCI2) { - dprintk(7, " VID_B_MSK_RISCI2\n"); - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); } if (status) { cx_write(port->reg_ts_int_stat, status); @@ -1777,14 +1648,6 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) cx23885_wakeup(port, &port->mpegq, count); spin_unlock(&port->slock); - } else if (status & VID_BC_MSK_RISCI2) { - - dprintk(7, " (RISCI2 0x%08x)\n", VID_BC_MSK_RISCI2); - - spin_lock(&port->slock); - cx23885_restart_queue(port, &port->mpegq); - spin_unlock(&port->slock); - } if (status) { cx_write(port->reg_ts_int_stat, status); @@ -2087,6 +1950,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct cx23885_dev *dev; + struct v4l2_ctrl_handler *hdl; int err; dev = kzalloc(sizeof(*dev), GFP_KERNEL); @@ -2097,6 +1961,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev, if (err < 0) goto fail_free; + hdl = &dev->ctrl_handler; + v4l2_ctrl_handler_init(hdl, 6); + if (hdl->error) { + err = hdl->error; + goto fail_ctrl; + } + dev->v4l2_dev.ctrl_handler = hdl; + /* Prepare to handle notifications from subdevices */ cx23885_v4l2_dev_notify_init(dev); @@ -2104,12 +1976,12 @@ static int cx23885_initdev(struct pci_dev *pci_dev, dev->pci = pci_dev; if (pci_enable_device(pci_dev)) { err = -EIO; - goto fail_unreg; + goto fail_ctrl; } if (cx23885_dev_setup(dev) < 0) { err = -EINVAL; - goto fail_unreg; + goto fail_ctrl; } /* print pci info */ @@ -2157,7 +2029,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev, fail_irq: cx23885_dev_unregister(dev); -fail_unreg: +fail_ctrl: + v4l2_ctrl_handler_free(hdl); v4l2_device_unregister(&dev->v4l2_dev); fail_free: kfree(dev); @@ -2180,6 +2053,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev) free_irq(pci_dev->irq, dev); cx23885_dev_unregister(dev); + v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_device_unregister(v4l2_dev); kfree(dev); } diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 968fecc32f9c..13734b8c7917 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -73,6 +69,10 @@ #include "a8293.h" #include "mb86a20s.h" #include "si2165.h" +#include "si2168.h" +#include "si2157.h" +#include "m88ds3103.h" +#include "m88ts2022.h" static unsigned int debug; @@ -91,59 +91,95 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* ------------------------------------------------------------------ */ -static int dvb_buf_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_tsport *port = q->priv_data; + struct cx23885_tsport *port = q->drv_priv; port->ts_packet_size = 188 * 4; port->ts_packet_count = 32; - - *size = port->ts_packet_size * port->ts_packet_count; - *count = 32; + *num_planes = 1; + sizes[0] = port->ts_packet_size * port->ts_packet_count; + *num_buffers = 32; return 0; } -static int dvb_buf_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, enum v4l2_field field) + +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_tsport *port = q->priv_data; - return cx23885_buf_prepare(q, port, (struct cx23885_buffer *)vb, field); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = + container_of(vb, struct cx23885_buffer, vb); + + return cx23885_buf_prepare(buf, port); } -static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_tsport *port = q->priv_data; - cx23885_buf_queue(port, (struct cx23885_buffer *)vb); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_dev *dev = port->dev; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(dev, buf); + + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void dvb_buf_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) +static void buffer_queue(struct vb2_buffer *vb) { - cx23885_free_buffer(q, (struct cx23885_buffer *)vb); + struct cx23885_tsport *port = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + + cx23885_buf_queue(port, buf); } static void cx23885_dvb_gate_ctrl(struct cx23885_tsport *port, int open) { - struct videobuf_dvb_frontends *f; - struct videobuf_dvb_frontend *fe; + struct vb2_dvb_frontends *f; + struct vb2_dvb_frontend *fe; f = &port->frontends; if (f->gate <= 1) /* undefined or fe0 */ - fe = videobuf_dvb_get_frontend(f, 1); + fe = vb2_dvb_get_frontend(f, 1); else - fe = videobuf_dvb_get_frontend(f, f->gate); + fe = vb2_dvb_get_frontend(f, f->gate); if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl) fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open); } -static struct videobuf_queue_ops dvb_qops = { - .buf_setup = dvb_buf_setup, - .buf_prepare = dvb_buf_prepare, - .buf_queue = dvb_buf_queue, - .buf_release = dvb_buf_release, +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct cx23885_tsport *port = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &port->mpegq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + cx23885_start_dma(port, dmaq, buf); + return 0; +} + +static void cx23885_stop_streaming(struct vb2_queue *q) +{ + struct cx23885_tsport *port = q->drv_priv; + + cx23885_cancel_buffers(port); +} + +static struct vb2_ops dvb_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, }; static struct s5h1409_config hauppauge_generic_config = { @@ -551,6 +587,35 @@ static int p8000_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) return 0; } +static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe, + fe_sec_voltage_t voltage) +{ + struct cx23885_tsport *port = fe->dvb->priv; + struct cx23885_dev *dev = port->dev; + + cx23885_gpio_enable(dev, GPIO_0 | GPIO_1, 1); + + switch (voltage) { + case SEC_VOLTAGE_13: + cx23885_gpio_set(dev, GPIO_1); + cx23885_gpio_clear(dev, GPIO_0); + break; + case SEC_VOLTAGE_18: + cx23885_gpio_set(dev, GPIO_1); + cx23885_gpio_set(dev, GPIO_0); + break; + case SEC_VOLTAGE_OFF: + cx23885_gpio_clear(dev, GPIO_1); + cx23885_gpio_clear(dev, GPIO_0); + break; + } + + /* call the frontend set_voltage function */ + port->fe_set_voltage(fe, voltage); + + return 0; +} + static int cx23885_dvb_set_frontend(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; @@ -715,6 +780,19 @@ static const struct si2165_config hauppauge_hvr4400_si2165_config = { .ref_freq_Hz = 16000000, }; +static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = { + .i2c_addr = 0x68, + .clock = 27000000, + .i2c_wr_max = 33, + .clock_out = 0, + .ts_mode = M88DS3103_TS_PARALLEL, + .ts_clk = 16000, + .ts_clk_pol = 1, + .lnb_en_pol = 1, + .lnb_hv_pol = 0, + .agc = 0x99, +}; + static int netup_altera_fpga_rw(void *device, int flag, int data, int read) { struct cx23885_dev *dev = (struct cx23885_dev *)device; @@ -863,16 +941,23 @@ static int dvb_register(struct cx23885_tsport *port) struct dib7000p_ops dib7000p_ops; struct cx23885_dev *dev = port->dev; struct cx23885_i2c *i2c_bus = NULL, *i2c_bus2 = NULL; - struct videobuf_dvb_frontend *fe0, *fe1 = NULL; + struct vb2_dvb_frontend *fe0, *fe1 = NULL; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + struct m88ts2022_config m88ts2022_config; + struct i2c_board_info info; + struct i2c_adapter *adapter; + struct i2c_client *client_demod; + struct i2c_client *client_tuner; int mfe_shared = 0; /* bus not shared by default */ int ret; /* Get the first frontend */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); if (!fe0) return -EINVAL; - /* init struct videobuf_dvb */ + /* init struct vb2_dvb */ fe0->dvb.name = dev->name; /* multi-frontend gate control is undefined or defaults to fe0 */ @@ -1392,7 +1477,7 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend); } /* MFE frontend 2 */ - fe1 = videobuf_dvb_get_frontend(&port->frontends, 2); + fe1 = vb2_dvb_get_frontend(&port->frontends, 2); if (fe1 == NULL) goto frontend_detach; /* DVB-C init */ @@ -1491,7 +1576,7 @@ static int dvb_register(struct cx23885_tsport *port) &hauppauge_hvr4400_si2165_config, &i2c_bus->i2c_adap); if (fe0->dvb.frontend != NULL) { - fe0->dvb.frontend->ops.i2c_gate_ctrl = 0; + fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL; if (!dvb_attach(tda18271_attach, fe0->dvb.frontend, 0x60, &i2c_bus2->i2c_adap, @@ -1501,6 +1586,97 @@ static int dvb_register(struct cx23885_tsport *port) break; } break; + case CX23885_BOARD_DVBSKY_T9580: + i2c_bus = &dev->i2c_bus[0]; + i2c_bus2 = &dev->i2c_bus[1]; + switch (port->nr) { + /* port b - satellite */ + case 1: + /* attach frontend */ + fe0->dvb.frontend = dvb_attach(m88ds3103_attach, + &dvbsky_t9580_m88ds3103_config, + &i2c_bus2->i2c_adap, &adapter); + if (fe0->dvb.frontend == NULL) + break; + + /* attach tuner */ + m88ts2022_config.fe = fe0->dvb.frontend; + m88ts2022_config.clock = 27000000; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &m88ts2022_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || + client_tuner->dev.driver == NULL) + goto frontend_detach; + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + goto frontend_detach; + } + + /* delegate signal strength measurement to tuner */ + fe0->dvb.frontend->ops.read_signal_strength = + fe0->dvb.frontend->ops.tuner_ops.get_rf_strength; + + /* + * for setting the voltage we need to set GPIOs on + * the card. + */ + port->fe_set_voltage = + fe0->dvb.frontend->ops.set_voltage; + fe0->dvb.frontend->ops.set_voltage = + dvbsky_t9580_set_voltage; + + port->i2c_client_tuner = client_tuner; + + break; + /* port c - terrestrial/cable */ + case 2: + /* attach frontend */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &fe0->dvb.frontend; + si2168_config.ts_mode = SI2168_TS_SERIAL; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info); + if (client_demod == NULL || + client_demod->dev.driver == NULL) + goto frontend_detach; + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_demod = client_demod; + + /* attach tuner */ + si2157_config.fe = fe0->dvb.frontend; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || + client_tuner->dev.driver == NULL) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + goto frontend_detach; + } + port->i2c_client_tuner = client_tuner; + break; + } + break; default: printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " " isn't supported yet\n", @@ -1532,7 +1708,7 @@ static int dvb_register(struct cx23885_tsport *port) fe0->dvb.frontend->ops.analog_ops.standby(fe0->dvb.frontend); /* register everything */ - ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port, + ret = vb2_dvb_register_bus(&port->frontends, THIS_MODULE, port, &dev->pci->dev, adapter_nr, mfe_shared); if (ret) goto frontend_detach; @@ -1575,20 +1751,36 @@ static int dvb_register(struct cx23885_tsport *port) memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); break; } + case CX23885_BOARD_DVBSKY_T9580: { + u8 eeprom[256]; /* 24C02 i2c eeprom */ + + if (port->nr > 2) + break; + + /* Read entire EEPROM */ + dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; + tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, + sizeof(eeprom)); + printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n", + port->nr, eeprom + 0xc0 + (port->nr-1) * 8); + memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + + (port->nr-1) * 8, 6); + break; + } } return ret; frontend_detach: port->gate_ctrl = NULL; - videobuf_dvb_dealloc_frontends(&port->frontends); + vb2_dvb_dealloc_frontends(&port->frontends); return -EINVAL; } int cx23885_dvb_register(struct cx23885_tsport *port) { - struct videobuf_dvb_frontend *fe0; + struct vb2_dvb_frontend *fe0; struct cx23885_dev *dev = port->dev; int err, i; @@ -1605,13 +1797,15 @@ int cx23885_dvb_register(struct cx23885_tsport *port) port->num_frontends); for (i = 1; i <= port->num_frontends; i++) { - if (videobuf_dvb_alloc_frontend( + struct vb2_queue *q; + + if (vb2_dvb_alloc_frontend( &port->frontends, i) == NULL) { printk(KERN_ERR "%s() failed to alloc\n", __func__); return -ENOMEM; } - fe0 = videobuf_dvb_get_frontend(&port->frontends, i); + fe0 = vb2_dvb_get_frontend(&port->frontends, i); if (!fe0) err = -EINVAL; @@ -1627,10 +1821,21 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); - videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops, - &dev->pci->dev, &port->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP, - sizeof(struct cx23885_buffer), port, NULL); + q = &fe0->dvb.dvbq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = port; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &dvb_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + return err; } err = dvb_register(port); if (err != 0) @@ -1642,18 +1847,27 @@ int cx23885_dvb_register(struct cx23885_tsport *port) int cx23885_dvb_unregister(struct cx23885_tsport *port) { - struct videobuf_dvb_frontend *fe0; - - /* FIXME: in an error condition where the we have - * an expected number of frontends (attach problem) - * then this might not clean up correctly, if 1 - * is invalid. - * This comment only applies to future boards IF they - * implement MFE support. - */ - fe0 = videobuf_dvb_get_frontend(&port->frontends, 1); + struct vb2_dvb_frontend *fe0; + struct i2c_client *client; + + /* remove I2C client for tuner */ + client = port->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C client for demodulator */ + client = port->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + fe0 = vb2_dvb_get_frontend(&port->frontends, 1); + if (fe0 && fe0->dvb.frontend) - videobuf_dvb_unregister_bus(&port->frontends); + vb2_dvb_unregister_bus(&port->frontends); switch (port->dev->board) { case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: @@ -1668,4 +1882,3 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port) return 0; } - diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index 5444cc526008..6f817d8732da 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -22,10 +22,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx23885.h" diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 4887314339cb..fd71306af6e2 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> @@ -386,11 +382,3 @@ void cx23885_av_clk(struct cx23885_dev *dev, int enable) i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1); } - -/* ----------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 1940c18e186c..9d37fe661691 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -28,11 +28,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include <linux/slab.h> diff --git a/drivers/media/pci/cx23885/cx23885-input.h b/drivers/media/pci/cx23885/cx23885-input.h index 87dc44e69977..6199c7e86e83 100644 --- a/drivers/media/pci/cx23885/cx23885-input.h +++ b/drivers/media/pci/cx23885/cx23885-input.h @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_INPUT_H_ diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.c b/drivers/media/pci/cx23885/cx23885-ioctl.c index 271d69d1ca8c..d2cdd40f79f5 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.c +++ b/drivers/media/pci/cx23885/cx23885-ioctl.c @@ -15,10 +15,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx23885.h" @@ -28,7 +24,7 @@ int cx23885_g_chip_info(struct file *file, void *fh, struct v4l2_dbg_chip_info *chip) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (chip->match.addr > 1) return -EINVAL; @@ -64,7 +60,7 @@ static int cx23417_g_register(struct cx23885_dev *dev, int cx23885_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (reg->match.addr > 1) return -EINVAL; @@ -96,7 +92,7 @@ static int cx23417_s_register(struct cx23885_dev *dev, int cx23885_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { - struct cx23885_dev *dev = ((struct cx23885_fh *)fh)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (reg->match.addr > 1) return -EINVAL; diff --git a/drivers/media/pci/cx23885/cx23885-ioctl.h b/drivers/media/pci/cx23885/cx23885-ioctl.h index 92d9f0774366..cc5dbb6c1afc 100644 --- a/drivers/media/pci/cx23885/cx23885-ioctl.h +++ b/drivers/media/pci/cx23885/cx23885-ioctl.h @@ -15,10 +15,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _CX23885_IOCTL_H_ diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c index bfef19359291..89dc4cc3e1ce 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.c +++ b/drivers/media/pci/cx23885/cx23885-ir.c @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include <media/v4l2-device.h> diff --git a/drivers/media/pci/cx23885/cx23885-ir.h b/drivers/media/pci/cx23885/cx23885-ir.h index 0c9d8bda9e28..8e93d1f10ae0 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.h +++ b/drivers/media/pci/cx23885/cx23885-ir.h @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_IR_H_ diff --git a/drivers/media/pci/cx23885/cx23885-reg.h b/drivers/media/pci/cx23885/cx23885-reg.h index a99936e0cbc2..2d3cbafe2402 100644 --- a/drivers/media/pci/cx23885/cx23885-reg.h +++ b/drivers/media/pci/cx23885/cx23885-reg.h @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _CX23885_REG_H_ diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index a1154f035bc1..a7c6ef8f3ea3 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/kernel.h> @@ -42,33 +38,32 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ #define VBI_LINE_LENGTH 1440 -#define NTSC_VBI_START_LINE 10 /* line 10 - 21 */ -#define NTSC_VBI_END_LINE 21 -#define NTSC_VBI_LINES (NTSC_VBI_END_LINE - NTSC_VBI_START_LINE + 1) +#define VBI_NTSC_LINE_COUNT 12 +#define VBI_PAL_LINE_COUNT 18 int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); + f->fmt.vbi.sampling_rate = 27000000; + f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; + f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; + f->fmt.vbi.offset = 0; + f->fmt.vbi.flags = 0; if (dev->tvnorm & V4L2_STD_525_60) { /* ntsc */ - f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH; - f->fmt.vbi.sampling_rate = 27000000; - f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; - f->fmt.vbi.offset = 0; - f->fmt.vbi.flags = 0; - f->fmt.vbi.start[0] = 10; - f->fmt.vbi.count[0] = 17; - f->fmt.vbi.start[1] = 263 + 10 + 1; - f->fmt.vbi.count[1] = 17; + f->fmt.vbi.start[0] = V4L2_VBI_ITU_525_F1_START + 9; + f->fmt.vbi.start[1] = V4L2_VBI_ITU_525_F2_START + 9; + f->fmt.vbi.count[0] = VBI_NTSC_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_NTSC_LINE_COUNT; } else if (dev->tvnorm & V4L2_STD_625_50) { /* pal */ - f->fmt.vbi.sampling_rate = 35468950; - f->fmt.vbi.start[0] = 7 - 1; - f->fmt.vbi.start[1] = 319 - 1; + f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5; + f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5; + f->fmt.vbi.count[0] = VBI_PAL_LINE_COUNT; + f->fmt.vbi.count[1] = VBI_PAL_LINE_COUNT; } return 0; @@ -94,15 +89,6 @@ int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status) handled++; } - if (status & VID_BC_MSK_VBI_RISCI2) { - dprintk(1, "%s() VID_BC_MSK_VBI_RISCI2\n", __func__); - dprintk(2, "stopper vbi\n"); - spin_lock(&dev->slock); - cx23885_restart_vbi_queue(dev, &dev->vbiq); - spin_unlock(&dev->slock); - handled++; - } - return handled; } @@ -114,13 +100,13 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH02], - buf->vb.width, buf->risc.dma); + VBI_LINE_LENGTH, buf->risc.dma); /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); cx_write(VID_A_VBI_CTRL, 3); cx_write(VBI_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -133,163 +119,153 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, return 0; } +/* ------------------------------------------------------------------ */ -int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_buffer *buf; - struct list_head *item; - - if (list_empty(&q->active)) - return 0; - - buf = list_entry(q->active.next, struct cx23885_buffer, vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_vbi_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); + struct cx23885_dev *dev = q->drv_priv; + unsigned lines = VBI_PAL_LINE_COUNT; + + if (dev->tvnorm & V4L2_STD_525_60) + lines = VBI_NTSC_LINE_COUNT; + *num_planes = 1; + sizes[0] = lines * VBI_LINE_LENGTH * 2; return 0; } -void cx23885_vbi_timeout(unsigned long data) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vbiq; - struct cx23885_buffer *buf; - unsigned long flags; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + unsigned lines = VBI_PAL_LINE_COUNT; + int ret; - /* Stop the VBI engine */ - cx_clear(VID_A_DMA_CTL, 0x22); + if (dev->tvnorm & V4L2_STD_525_60) + lines = VBI_NTSC_LINE_COUNT; - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->name, - buf, buf->vb.i, (unsigned long)buf->risc.dma); - } - cx23885_restart_vbi_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} + if (vb2_plane_size(vb, 0) < lines * VBI_LINE_LENGTH * 2) + return -EINVAL; + vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2); -/* ------------------------------------------------------------------ */ -#define VBI_LINE_LENGTH 1440 -#define VBI_LINE_COUNT 17 + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; -static int -vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) -{ - *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 == *count) - *count = vbibufs; - if (*count < 2) - *count = 2; - if (*count > 32) - *count = 32; + cx23885_risc_vbibuffer(dev->pci, &buf->risc, + sgt->sgl, + 0, VBI_LINE_LENGTH * lines, + VBI_LINE_LENGTH, 0, + lines); return 0; } -static int -vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static void buffer_finish(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - unsigned int size; - int rc; - - size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2; - if (0 != buf->vb.baddr && buf->vb.bsize < size) - return -EINVAL; + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = VBI_LINE_LENGTH; - buf->vb.height = VBI_LINE_COUNT; - buf->vb.size = size; - buf->vb.field = V4L2_FIELD_SEQ_TB; - - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - cx23885_risc_vbibuffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->vb.width * buf->vb.height, - buf->vb.width, 0, - buf->vb.height); - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); - fail: - cx23885_free_buffer(q, buf); - return rc; + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void -vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ +static void buffer_queue(struct vb2_buffer *vb) { - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); - struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; - struct cx23885_dmaqueue *q = &dev->vbiq; - - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); + struct cx23885_buffer *prev; + struct cx23885_dmaqueue *q = &dev->vbiq; + unsigned long flags; + + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_vbi_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies + (BUFFER_TIMEOUT / 30)); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->queue, &q->active); + spin_unlock_irqrestore(&dev->slock, flags); dprintk(2, "[%p/%d] vbi_queue - first active\n", - buf, buf->vb.i); + buf, buf->vb.v4l2_buf.index); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - list_add_tail(&buf->vb.queue, &q->active); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; + queue); + spin_lock_irqsave(&dev->slock, flags); + list_add_tail(&buf->queue, &q->active); + spin_unlock_irqrestore(&dev->slock, flags); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63-32 */ dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); + buf, buf->vb.v4l2_buf.index); } } -static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct cx23885_buffer *buf = - container_of(vb, struct cx23885_buffer, vb); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vbiq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - cx23885_free_buffer(q, buf); + cx23885_start_vbi_dma(dev, dmaq, buf); + return 0; } -struct videobuf_queue_ops cx23885_vbi_qops = { - .buf_setup = vbi_setup, - .buf_prepare = vbi_prepare, - .buf_queue = vbi_queue, - .buf_release = vbi_release, -}; +static void cx23885_stop_streaming(struct vb2_queue *q) +{ + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vbiq; + unsigned long flags; -/* ------------------------------------------------------------------ */ -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ + cx_clear(VID_A_DMA_CTL, 0x22); /* FIFO and RISC enable */ + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&dev->slock, flags); +} + + +struct vb2_ops cx23885_vbi_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 91e4cb457296..682a4f95df6b 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/init.h> @@ -35,6 +31,7 @@ #include "cx23885-video.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include "cx23885-ioctl.h" #include "tuner-xc2028.h" @@ -48,15 +45,12 @@ MODULE_LICENSE("GPL"); static unsigned int video_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (CX23885_MAXBOARDS - 1)] = UNSET }; module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); MODULE_PARM_DESC(video_nr, "video device numbers"); MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug; module_param(video_debug, int, 0644); @@ -79,77 +73,14 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); /* static data */ #define FORMAT_FLAGS_PACKED 0x01 -#if 0 -static struct cx23885_fmt formats[] = { - { - .name = "8 bpp, gray", - .fourcc = V4L2_PIX_FMT_GREY, - .depth = 8, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB555, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "15 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB555X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_RGB565, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "16 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB565X, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "24 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, le", - .fourcc = V4L2_PIX_FMT_BGR32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "32 bpp RGB, be", - .fourcc = V4L2_PIX_FMT_RGB32, - .depth = 32, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, -}; -#else static struct cx23885_fmt formats[] = { { -#if 0 - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .depth = 16, - .flags = FORMAT_FLAGS_PACKED, - }, { -#endif .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .depth = 16, .flags = FORMAT_FLAGS_PACKED, } }; -#endif static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) { @@ -158,163 +89,27 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc) for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fourcc) return formats+i; - - printk(KERN_ERR "%s(%c%c%c%c) NOT FOUND\n", __func__, - (fourcc & 0xff), - ((fourcc >> 8) & 0xff), - ((fourcc >> 16) & 0xff), - ((fourcc >> 24) & 0xff) - ); return NULL; } /* ------------------------------------------------------------------- */ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, -}; - -static struct cx23885_ctrl cx23885_ctls[] = { - /* --- video --- */ - { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = LUMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = LUMA_CTRL, - .mask = 0xff00, - .shift = 8, - }, { - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = -127, - .maximum = 128, - .step = 1, - .default_value = 0x0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = CHROMA_CTRL, - .mask = 0xff0000, - .shift = 16, - }, { - /* strictly, this only describes only U saturation. - * V saturation is handled specially through code. - */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = CHROMA_CTRL, - .mask = 0x00ff, - .shift = 0, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = PATH1_CTL1, - .mask = (0x1f << 24), - .shift = 24, - }, { - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535 / 100, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = PATH1_VOL_CTL, - .mask = 0xff, - .shift = 0, - } -}; -static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); - -/* Must be sorted from low to high control ID! */ -static const u32 cx23885_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_MUTE, - 0 -}; - -static const u32 *ctrl_classes[] = { - cx23885_user_ctrls, - NULL -}; - void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_buffer *buf; - int bc; - - for (bc = 0;; bc++) { - if (list_empty(&q->active)) - break; - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - - /* count comes from the hw and is is 16bit wide -- - * this trick handles wrap-arounds correctly for - * up to 32767 buffers in flight... */ - if ((s16) (count - buf->count) < 0) - break; - - v4l2_get_timestamp(&buf->vb.ts); - dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.i, - count, buf->count); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - } + if (list_empty(&q->active)) - del_timer(&q->timeout); - else - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - if (bc != 1) - printk(KERN_ERR "%s: %d buffers handled (should be 1)\n", - __func__, bc); + return; + buf = list_entry(q->active.next, + struct cx23885_buffer, queue); + + buf->vb.v4l2_buf.sequence = q->count++; + v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); + dprintk(2, "[%p/%d] wakeup reg=%d buf=%d\n", buf, buf->vb.v4l2_buf.index, + count, q->count); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE); } int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) @@ -324,6 +119,12 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) (unsigned int)norm, v4l2_norm_to_name(norm)); + if (dev->tvnorm != norm) { + if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || + vb2_is_busy(&dev->vb2_mpegq)) + return -EBUSY; + } + dev->tvnorm = norm; call_all(dev, video, s_std, norm); @@ -345,79 +146,13 @@ static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, *vfd = *template; vfd->v4l2_dev = &dev->v4l2_dev; vfd->release = video_device_release; + vfd->lock = &dev->lock; snprintf(vfd->name, sizeof(vfd->name), "%s (%s)", cx23885_boards[dev->board].name, type); video_set_drvdata(vfd, dev); return vfd; } -static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX23885_CTLS; i++) - if (cx23885_ctls[i].v.id == qctrl->id) - break; - if (i == CX23885_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx23885_ctls[i].v; - return 0; -} - -/* ------------------------------------------------------------------- */ -/* resource management */ - -static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bit) -{ - dprintk(1, "%s()\n", __func__); - if (fh->resources & bit) - /* have it already allocated */ - return 1; - - /* is it free? */ - mutex_lock(&dev->lock); - if (dev->resources & bit) { - /* no, someone else uses it */ - mutex_unlock(&dev->lock); - return 0; - } - /* it's free, grab it */ - fh->resources |= bit; - dev->resources |= bit; - dprintk(1, "res: get %d\n", bit); - mutex_unlock(&dev->lock); - return 1; -} - -static int res_check(struct cx23885_fh *fh, unsigned int bit) -{ - return fh->resources & bit; -} - -static int res_locked(struct cx23885_dev *dev, unsigned int bit) -{ - return dev->resources & bit; -} - -static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, - unsigned int bits) -{ - BUG_ON((fh->resources & bits) != bits); - dprintk(1, "%s()\n", __func__); - - mutex_lock(&dev->lock); - fh->resources &= ~bits; - dev->resources &= ~bits; - dprintk(1, "res: put %d\n", bits); - mutex_unlock(&dev->lock); -} - int cx23885_flatiron_write(struct cx23885_dev *dev, u8 reg, u8 data) { /* 8 bit registers, 8 bit values */ @@ -567,7 +302,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, /* reset counter */ cx_write(VID_A_GPCNT_CTL, 3); - q->count = 1; + q->count = 0; /* enable irq */ cx23885_irq_add_enable(dev, 0x01); @@ -580,479 +315,206 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev, return 0; } - -static int cx23885_restart_video_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q) -{ - struct cx23885_buffer *buf, *prev; - struct list_head *item; - dprintk(1, "%s()\n", __func__); - - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct cx23885_buffer, - vb.queue); - dprintk(2, "restart_queue [%p/%d]: restart dma\n", - buf, buf->vb.i); - cx23885_start_video_dma(dev, q, buf); - list_for_each(item, &q->active) { - buf = list_entry(item, struct cx23885_buffer, - vb.queue); - buf->count = q->count++; - } - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct cx23885_buffer, - vb.queue); - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); - dprintk(2, "[%p/%d] restart_queue - first active\n", - buf, buf->vb.i); - - } else if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - 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); - prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */ - dprintk(2, "[%p/%d] restart_queue - move to active\n", - buf, buf->vb.i); - } else { - return 0; - } - prev = buf; - } -} - -static int buffer_setup(struct videobuf_queue *q, unsigned int *count, - unsigned int *size) +static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct cx23885_fh *fh = q->priv_data; + struct cx23885_dev *dev = q->drv_priv; - *size = fh->fmt->depth*fh->width*fh->height >> 3; - if (0 == *count) - *count = 32; - if (*size * *count > vid_limit * 1024 * 1024) - *count = (vid_limit * 1024 * 1024) / *size; + *num_planes = 1; + sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3; return 0; } -static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) +static int buffer_prepare(struct vb2_buffer *vb) { - struct cx23885_fh *fh = q->priv_data; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); - int rc, init_buffer = 0; u32 line0_offset, line1_offset; - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); int field_tff; + int ret; - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(dev->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(dev->tvnorm)) - return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) + buf->bpl = (dev->width * dev->fmt->depth) >> 3; + + if (vb2_plane_size(vb, 0) < dev->height * buf->bpl) return -EINVAL; + vb2_set_plane_payload(vb, 0, dev->height * buf->bpl); - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || - buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; - buf->vb.field = field; - init_buffer = 1; - } + ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); + if (!ret) + return -EIO; - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - init_buffer = 1; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (0 != rc) - goto fail; - } + switch (dev->field) { + case V4L2_FIELD_TOP: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, 0, UNSET, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_BOTTOM: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, UNSET, 0, + buf->bpl, 0, dev->height); + break; + case V4L2_FIELD_INTERLACED: + if (dev->tvnorm & V4L2_STD_525_60) + /* NTSC or */ + field_tff = 1; + else + field_tff = 0; + + if (cx23885_boards[dev->board].force_bff) + /* PAL / SECAM OR 888 in NTSC MODE */ + field_tff = 0; - if (init_buffer) { - buf->bpl = buf->vb.width * buf->fmt->depth >> 3; - switch (buf->vb.field) { - case V4L2_FIELD_TOP: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, 0, UNSET, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_BOTTOM: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, UNSET, 0, - buf->bpl, 0, buf->vb.height); - break; - case V4L2_FIELD_INTERLACED: - if (dev->tvnorm & V4L2_STD_NTSC) - /* NTSC or */ - field_tff = 1; - else - field_tff = 0; - - if (cx23885_boards[dev->board].force_bff) - /* PAL / SECAM OR 888 in NTSC MODE */ - field_tff = 0; - - if (field_tff) { - /* cx25840 transmits NTSC bottom field first */ - dprintk(1, "%s() Creating TFF/NTSC risc\n", + if (field_tff) { + /* cx25840 transmits NTSC bottom field first */ + dprintk(1, "%s() Creating TFF/NTSC risc\n", __func__); - line0_offset = buf->bpl; - line1_offset = 0; - } else { - /* All other formats are top field first */ - dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", + line0_offset = buf->bpl; + line1_offset = 0; + } else { + /* All other formats are top field first */ + dprintk(1, "%s() Creating BFF/PAL/SECAM risc\n", __func__); - line0_offset = 0; - line1_offset = buf->bpl; - } - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, line0_offset, - line1_offset, - buf->bpl, buf->bpl, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_TB: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - 0, buf->bpl * (buf->vb.height >> 1), - buf->bpl, 0, - buf->vb.height >> 1); - break; - case V4L2_FIELD_SEQ_BT: - cx23885_risc_buffer(dev->pci, &buf->risc, - dma->sglist, - buf->bpl * (buf->vb.height >> 1), 0, - buf->bpl, 0, - buf->vb.height >> 1); - break; - default: - BUG(); + line0_offset = 0; + line1_offset = buf->bpl; } + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, line0_offset, + line1_offset, + buf->bpl, buf->bpl, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_TB: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + 0, buf->bpl * (dev->height >> 1), + buf->bpl, 0, + dev->height >> 1); + break; + case V4L2_FIELD_SEQ_BT: + cx23885_risc_buffer(dev->pci, &buf->risc, + sgt->sgl, + buf->bpl * (dev->height >> 1), 0, + buf->bpl, 0, + dev->height >> 1); + break; + default: + BUG(); } - dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", - buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + dprintk(2, "[%p/%d] buffer_init - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + buf, buf->vb.v4l2_buf.index, + dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); - - buf->vb.state = VIDEOBUF_PREPARED; return 0; +} + +static void buffer_finish(struct vb2_buffer *vb) +{ + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; + struct cx23885_buffer *buf = container_of(vb, + struct cx23885_buffer, vb); + struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0); + + cx23885_free_buffer(vb->vb2_queue->drv_priv, buf); - fail: - cx23885_free_buffer(q, buf); - return rc; + dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE); } -static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) +/* + * The risc program for each buffer works as follows: it starts with a simple + * 'JUMP to addr + 12', which is effectively a NOP. Then the code to DMA the + * buffer follows and at the end we have a JUMP back to the start + 12 (skipping + * the initial JUMP). + * + * This is the risc program of the first buffer to be queued if the active list + * is empty and it just keeps DMAing this buffer without generating any + * interrupts. + * + * If a new buffer is added then the initial JUMP in the code for that buffer + * will generate an interrupt which signals that the previous buffer has been + * DMAed successfully and that it can be returned to userspace. + * + * It also sets the final jump of the previous buffer to the start of the new + * buffer, thus chaining the new buffer into the DMA chain. This is a single + * atomic u32 write, so there is no race condition. + * + * The end-result of all this that you only get an interrupt when a buffer + * is ready, so the control flow is very easy. + */ +static void buffer_queue(struct vb2_buffer *vb) { + struct cx23885_dev *dev = vb->vb2_queue->drv_priv; struct cx23885_buffer *buf = container_of(vb, struct cx23885_buffer, vb); struct cx23885_buffer *prev; - struct cx23885_fh *fh = vq->priv_data; - struct cx23885_dev *dev = fh->dev; struct cx23885_dmaqueue *q = &dev->vidq; + unsigned long flags; - /* add jump to stopper */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); + /* add jump to start */ + buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); + buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12); buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */ - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - append to queued\n", - buf, buf->vb.i); - - } else if (list_empty(&q->active)) { - list_add_tail(&buf->vb.queue, &q->active); - cx23885_start_video_dma(dev, q, buf); - buf->vb.state = VIDEOBUF_ACTIVE; - buf->count = q->count++; - mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); + spin_lock_irqsave(&dev->slock, flags); + if (list_empty(&q->active)) { + list_add_tail(&buf->queue, &q->active); dprintk(2, "[%p/%d] buffer_queue - first active\n", - buf, buf->vb.i); - + buf, buf->vb.v4l2_buf.index); } else { + buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); prev = list_entry(q->active.prev, struct cx23885_buffer, - vb.queue); - if (prev->vb.width == buf->vb.width && - prev->vb.height == buf->vb.height && - prev->fmt == buf->fmt) { - list_add_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); - /* 64 bit bits 63-32 */ - prev->risc.jmp[2] = cpu_to_le32(0); - dprintk(2, "[%p/%d] buffer_queue - append to active\n", - buf, buf->vb.i); - - } else { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(2, "[%p/%d] buffer_queue - first queued\n", - buf, buf->vb.i); - } - } -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx23885_buffer *buf = container_of(vb, - struct cx23885_buffer, vb); - - cx23885_free_buffer(q, buf); -} - -static struct videobuf_queue_ops cx23885_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static struct videobuf_queue *get_queue(struct cx23885_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return &fh->vbiq; - default: - BUG(); - return NULL; - } -} - -static int get_resource(struct cx23885_fh *fh) -{ - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: - return RESOURCE_VBI; - default: - BUG(); - return 0; + queue); + list_add_tail(&buf->queue, &q->active); + prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); + dprintk(2, "[%p/%d] buffer_queue - append to active\n", + buf, buf->vb.v4l2_buf.index); } + spin_unlock_irqrestore(&dev->slock, flags); } -static int video_open(struct file *file) +static int cx23885_start_streaming(struct vb2_queue *q, unsigned int count) { - struct video_device *vdev = video_devdata(file); - struct cx23885_dev *dev = video_drvdata(file); - struct cx23885_fh *fh; - enum v4l2_buf_type type = 0; - int radio = 0; - - switch (vdev->vfl_type) { - case VFL_TYPE_GRABBER: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - break; - case VFL_TYPE_VBI: - type = V4L2_BUF_TYPE_VBI_CAPTURE; - break; - case VFL_TYPE_RADIO: - radio = 1; - break; - } - - dprintk(1, "open dev=%s radio=%d type=%s\n", - video_device_node_name(vdev), radio, v4l2_type_names[type]); - - /* allocate + initialize per filehandle data */ - fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) - return -ENOMEM; - - file->private_data = fh; - fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); - - videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx23885_buffer), - fh, NULL); - - videobuf_queue_sg_init(&fh->vbiq, &cx23885_vbi_qops, - &dev->pci->dev, &dev->slock, - V4L2_BUF_TYPE_VBI_CAPTURE, - V4L2_FIELD_SEQ_TB, - sizeof(struct cx23885_buffer), - fh, NULL); - - - dprintk(1, "post videobuf_queue_init()\n"); + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); + cx23885_start_video_dma(dev, dmaq, buf); return 0; } -static ssize_t video_read(struct file *file, char __user *data, - size_t count, loff_t *ppos) +static void cx23885_stop_streaming(struct vb2_queue *q) { - struct cx23885_fh *fh = file->private_data; - - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (res_locked(fh->dev, RESOURCE_VIDEO)) - return -EBUSY; - return videobuf_read_one(&fh->vidq, data, count, ppos, - file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: - if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return -EBUSY; - return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, - file->f_flags & O_NONBLOCK); - default: - BUG(); - return 0; - } -} - -static unsigned int video_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_buffer *buf; - unsigned int rc = POLLERR; - - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { - if (!res_get(fh->dev, fh, RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); - } - - mutex_lock(&fh->vidq.vb_lock); - if (res_check(fh, RESOURCE_VIDEO)) { - /* streaming capture */ - if (list_empty(&fh->vidq.stream)) - goto done; - buf = list_entry(fh->vidq.stream.next, - struct cx23885_buffer, vb.stream); - } else { - /* read() capture */ - buf = (struct cx23885_buffer *)fh->vidq.read_buf; - if (NULL == buf) - goto done; - } - poll_wait(file, &buf->vb.done, wait); - if (buf->vb.state == VIDEOBUF_DONE || - buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; -done: - mutex_unlock(&fh->vidq.vb_lock); - return rc; -} - -static int video_release(struct file *file) -{ - struct cx23885_fh *fh = file->private_data; - struct cx23885_dev *dev = fh->dev; - - /* turn off overlay */ - if (res_check(fh, RESOURCE_OVERLAY)) { - /* FIXME */ - res_free(dev, fh, RESOURCE_OVERLAY); - } + struct cx23885_dev *dev = q->drv_priv; + struct cx23885_dmaqueue *dmaq = &dev->vidq; + unsigned long flags; - /* stop video capture */ - if (res_check(fh, RESOURCE_VIDEO)) { - videobuf_queue_cancel(&fh->vidq); - res_free(dev, fh, RESOURCE_VIDEO); - } - if (fh->vidq.read_buf) { - buffer_release(&fh->vidq, fh->vidq.read_buf); - kfree(fh->vidq.read_buf); - } + cx_clear(VID_A_DMA_CTL, 0x11); + spin_lock_irqsave(&dev->slock, flags); + while (!list_empty(&dmaq->active)) { + struct cx23885_buffer *buf = list_entry(dmaq->active.next, + struct cx23885_buffer, queue); - /* stop vbi capture */ - if (res_check(fh, RESOURCE_VBI)) { - if (fh->vbiq.streaming) - videobuf_streamoff(&fh->vbiq); - if (fh->vbiq.reading) - videobuf_read_stop(&fh->vbiq); - res_free(dev, fh, RESOURCE_VBI); + list_del(&buf->queue); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); } - - videobuf_mmap_free(&fh->vidq); - videobuf_mmap_free(&fh->vbiq); - - file->private_data = NULL; - kfree(fh); - - /* We are not putting the tuner to sleep here on exit, because - * we want to use the mpeg encoder in another session to capture - * tuner video. Closing this will result in no video to the encoder. - */ - - return 0; -} - -static int video_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx23885_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); -} - -/* ------------------------------------------------------------------ */ -/* VIDEO CTRL IOCTLS */ - -int cx23885_get_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); - call_all(dev, core, g_ctrl, ctl); - return 0; -} - -int cx23885_set_control(struct cx23885_dev *dev, - struct v4l2_control *ctl) -{ - dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)\n", __func__); - call_all(dev, core, s_ctrl, ctl); - - return 0; + spin_unlock_irqrestore(&dev->slock, flags); } -static void init_controls(struct cx23885_dev *dev) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX23885_CTLS; i++) { - ctrl.id = cx23885_ctls[i].v.id; - ctrl.value = cx23885_ctls[i].v.default_value; - - cx23885_set_control(dev, &ctrl); - } -} +static struct vb2_ops cx23885_video_qops = { + .queue_setup = queue_setup, + .buf_prepare = buffer_prepare, + .buf_finish = buffer_finish, + .buf_queue = buffer_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .start_streaming = cx23885_start_streaming, + .stop_streaming = cx23885_stop_streaming, +}; /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -1060,16 +522,17 @@ static void init_controls(struct cx23885_dev *dev) static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = priv; + struct cx23885_dev *dev = video_drvdata(file); - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; - f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; + f->fmt.pix.field = dev->field; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; + (f->fmt.pix.width * dev->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -1077,7 +540,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); struct cx23885_fmt *fmt; enum v4l2_field field; unsigned int maxw, maxh; @@ -1102,9 +565,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, maxh = maxh / 2; break; case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: break; default: - return -EINVAL; + field = V4L2_FIELD_INTERLACED; + break; } f->fmt.pix.field = field; @@ -1114,6 +580,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -1121,8 +588,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); struct v4l2_mbus_framefmt mbus_fmt; int err; @@ -1131,34 +597,44 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; - fh->vidq.field = f->fmt.pix.field; + + if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq) || + vb2_is_busy(&dev->vb2_mpegq)) + return -EBUSY; + + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + dev->field = f->fmt.pix.field; dprintk(2, "%s() width=%d height=%d field=%d\n", __func__, - fh->width, fh->height, fh->vidq.field); + dev->width, dev->height, dev->field); v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED); call_all(dev, video, s_mbus_fmt, &mbus_fmt); v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt); + /* s_mbus_fmt overwrites f->fmt.pix.field, restore it */ + f->fmt.pix.field = dev->field; return 0; } static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); strcpy(cap->driver, "cx23885"); strlcpy(cap->card, cx23885_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_AUDIO; if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; + cap->device_caps |= V4L2_CAP_TUNER; + if (vdev->vfl_type == VFL_TYPE_VBI) + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + else + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + cap->capabilities = cap->device_caps | V4L2_CAP_VBI_CAPTURE | + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -1175,85 +651,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_reqbufs(get_queue(fh), p); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_querybuf(get_queue(fh), p); -} - -static int vidioc_qbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_qbuf(get_queue(fh), p); -} - -static int vidioc_dqbuf(struct file *file, void *priv, - struct v4l2_buffer *p) -{ - struct cx23885_fh *fh = priv; - return videobuf_dqbuf(get_queue(fh), p, - file->f_flags & O_NONBLOCK); -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - dprintk(1, "%s()\n", __func__); - - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - if (unlikely(i != fh->type)) - return -EINVAL; - - if (unlikely(!res_get(dev, fh, get_resource(fh)))) - return -EBUSY; - - /* Don't start VBI streaming unless vida streaming - * has already started. - */ - if ((fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) && - ((cx_read(VID_A_DMA_CTL) & 0x11) == 0)) - return -EINVAL; - - return videobuf_streamon(get_queue(fh)); -} - -static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) -{ - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; - int err, res; - dprintk(1, "%s()\n", __func__); - - if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - if (i != fh->type) - return -EINVAL; - - res = get_resource(fh); - err = videobuf_streamoff(get_queue(fh)); - if (err < 0) - return err; - res_free(dev, fh, res); - return 0; -} - static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); *id = dev->tvnorm; @@ -1262,14 +662,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, tvnorms); - mutex_unlock(&dev->lock); - - return 0; + return cx23885_set_tvnorm(dev, tvnorms); } int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) @@ -1299,16 +695,16 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n)->type]); + i->std = CX23885_NORMS; if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) || (CX23885_VMUX_CABLE == INPUT(n)->type)) { i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX23885_NORMS; + i->audioset = 4; + } else { + /* Two selectable audio inputs for non-tv inputs */ + i->audioset = 3; } - /* Two selectable audio inputs for non-tv inputs */ - if (INPUT(n)->type != CX23885_VMUX_TELEVISION) - i->audioset = 0x3; - if (dev->input == n) { /* enum'd input matches our configured input. * Ask the video decoder to process the call @@ -1324,14 +720,14 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s()\n", __func__); return cx23885_enum_input(dev, i); } int cx23885_get_input(struct file *file, void *priv, unsigned int *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); *i = dev->input; dprintk(1, "%s() returns %d\n", __func__, *i); @@ -1345,7 +741,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) int cx23885_set_input(struct file *file, void *priv, unsigned int i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); dprintk(1, "%s(%d)\n", __func__, i); @@ -1357,13 +753,11 @@ int cx23885_set_input(struct file *file, void *priv, unsigned int i) if (INPUT(i)->type == 0) return -EINVAL; - mutex_lock(&dev->lock); cx23885_video_mux(dev, i); /* By default establish the default audio input for the card also */ /* Caller is free to use VIDIOC_S_AUDIO to override afterwards */ cx23885_audio_mux(dev, i); - mutex_unlock(&dev->lock); return 0; } @@ -1374,39 +768,32 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_log_status(struct file *file, void *priv) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); - printk(KERN_INFO - "%s/0: ============ START LOG STATUS ============\n", - dev->name); call_all(dev, core, log_status); - printk(KERN_INFO - "%s/0: ============= END LOG STATUS =============\n", - dev->name); return 0; } static int cx23885_query_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); static const char *iname[] = { [0] = "Baseband L/R 1", [1] = "Baseband L/R 2", + [2] = "TV", }; unsigned int n; dprintk(1, "%s()\n", __func__); n = i->index; - if (n >= 2) + if (n >= 3) return -EINVAL; memset(i, 0, sizeof(*i)); i->index = n; strcpy(i->name, iname[n]); - i->capability = V4L2_AUDCAP_STEREO; - i->mode = V4L2_AUDMODE_AVL; + i->capability = V4L2_AUDCAP_STEREO; return 0; } @@ -1420,9 +807,13 @@ static int vidioc_enum_audinput(struct file *file, void *priv, static int vidioc_g_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); - i->index = dev->audinput; + if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || + (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) + i->index = 2; + else + i->index = dev->audinput; dprintk(1, "%s(input=%d)\n", __func__, i->index); return cx23885_query_audinput(file, priv, i); @@ -1431,8 +822,13 @@ static int vidioc_g_audinput(struct file *file, void *priv, static int vidioc_s_audinput(struct file *file, void *priv, const struct v4l2_audio *i) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - if (i->index >= 2) + struct cx23885_dev *dev = video_drvdata(file); + + if ((CX23885_VMUX_TELEVISION == INPUT(dev->input)->type) || + (CX23885_VMUX_CABLE == INPUT(dev->input)->type)) { + return i->index != 2 ? -EINVAL : 0; + } + if (i->index > 1) return -EINVAL; dprintk(1, "%s(%d)\n", __func__, i->index); @@ -1445,35 +841,10 @@ static int vidioc_s_audinput(struct file *file, void *priv, return 0; } -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx23885_ctrl_query(qctrl); -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_get_control(dev, ctl); -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; - - return cx23885_set_control(dev, ctl); -} - static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1489,7 +860,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { - struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; @@ -1504,14 +875,12 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; - /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; + f->type = V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; call_all(dev, tuner, g_frequency, f); @@ -1521,20 +890,23 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency *f) { - struct v4l2_control ctrl; + struct v4l2_ctrl *mute; + int old_mute_val = 1; if (dev->tuner_type == TUNER_ABSENT) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; - mutex_lock(&dev->lock); dev->freq = f->frequency; /* I need to mute audio here */ - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - cx23885_set_control(dev, &ctrl); + mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (mute) { + old_mute_val = v4l2_ctrl_g_ctrl(mute); + if (!old_mute_val) + v4l2_ctrl_s_ctrl(mute, 1); + } call_all(dev, tuner, s_frequency, f); @@ -1542,10 +914,8 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency msleep(100); /* I need to unmute audio here */ - ctrl.value = 0; - cx23885_set_control(dev, &ctrl); - - mutex_unlock(&dev->lock); + if (old_mute_val == 0) + v4l2_ctrl_s_ctrl(mute, old_mute_val); return 0; } @@ -1553,8 +923,9 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, const struct v4l2_frequency *f) { - struct v4l2_control ctrl; - struct videobuf_dvb_frontend *vfe; + struct v4l2_ctrl *mute; + int old_mute_val = 1; + struct vb2_dvb_frontend *vfe; struct dvb_frontend *fe; struct analog_parameters params = { @@ -1564,21 +935,22 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, .frequency = f->frequency }; - mutex_lock(&dev->lock); dev->freq = f->frequency; /* I need to mute audio here */ - ctrl.id = V4L2_CID_AUDIO_MUTE; - ctrl.value = 1; - cx23885_set_control(dev, &ctrl); + mute = v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_AUDIO_MUTE); + if (mute) { + old_mute_val = v4l2_ctrl_g_ctrl(mute); + if (!old_mute_val) + v4l2_ctrl_s_ctrl(mute, 1); + } /* If HVR1850 */ dprintk(1, "%s() frequency=%d tuner=%d std=0x%llx\n", __func__, params.frequency, f->tuner, params.std); - vfe = videobuf_dvb_get_frontend(&dev->ts2.frontends, 1); + vfe = vb2_dvb_get_frontend(&dev->ts2.frontends, 1); if (!vfe) { - mutex_unlock(&dev->lock); return -EINVAL; } @@ -1600,10 +972,8 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, msleep(100); /* I need to unmute audio here */ - ctrl.value = 0; - cx23885_set_control(dev, &ctrl); - - mutex_unlock(&dev->lock); + if (old_mute_val == 0) + v4l2_ctrl_s_ctrl(mute, old_mute_val); return 0; } @@ -1611,8 +981,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { - struct cx23885_fh *fh = priv; - struct cx23885_dev *dev = fh->dev; + struct cx23885_dev *dev = video_drvdata(file); int ret; switch (dev->board) { @@ -1636,28 +1005,6 @@ static int vidioc_s_frequency(struct file *file, void *priv, /* ----------------------------------------------------------- */ -static void cx23885_vid_timeout(unsigned long data) -{ - struct cx23885_dev *dev = (struct cx23885_dev *)data; - struct cx23885_dmaqueue *q = &dev->vidq; - struct cx23885_buffer *buf; - unsigned long flags; - - spin_lock_irqsave(&dev->slock, flags); - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, - struct cx23885_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_ERR "%s: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - cx23885_restart_video_queue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} - int cx23885_video_irq(struct cx23885_dev *dev, u32 status) { u32 mask, count; @@ -1702,13 +1049,6 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) spin_unlock(&dev->slock); handled++; } - if (status & VID_BC_MSK_RISCI2) { - dprintk(2, "stopper video\n"); - spin_lock(&dev->slock); - cx23885_restart_video_queue(dev, &dev->vidq); - spin_unlock(&dev->slock); - handled++; - } /* Allow the VBI framework to process it's payload */ handled += cx23885_vbi_irq(dev, status); @@ -1721,12 +1061,12 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) static const struct v4l2_file_operations video_fops = { .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .read = video_read, - .poll = video_poll, - .mmap = video_mmap, - .ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, }; static const struct v4l2_ioctl_ops video_ioctl_ops = { @@ -1738,21 +1078,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_try_fmt_vbi_cap = cx23885_vbi_fmt, .vidioc_s_fmt_vbi_cap = cx23885_vbi_fmt, - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, .vidioc_s_std = vidioc_s_std, .vidioc_g_std = vidioc_g_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, @@ -1765,6 +1103,8 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_enumaudio = vidioc_enum_audinput, .vidioc_g_audio = vidioc_g_audinput, .vidioc_s_audio = vidioc_s_audinput, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx23885_vbi_template; @@ -1775,14 +1115,6 @@ static struct video_device cx23885_video_template = { .tvnorms = CX23885_NORMS, }; -static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, -}; - - void cx23885_video_unregister(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); @@ -1794,7 +1126,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->vbi_dev); dev->vbi_dev = NULL; - btcx_riscmem_free(dev->pci, &dev->vbiq.stopper); } if (dev->video_dev) { if (video_is_registered(dev->video_dev)) @@ -1802,8 +1133,6 @@ void cx23885_video_unregister(struct cx23885_dev *dev) else video_device_release(dev->video_dev); dev->video_dev = NULL; - - btcx_riscmem_free(dev->pci, &dev->vidq.stopper); } if (dev->audio_dev) @@ -1812,6 +1141,7 @@ void cx23885_video_unregister(struct cx23885_dev *dev) int cx23885_video_register(struct cx23885_dev *dev) { + struct vb2_queue *q; int err; dprintk(1, "%s()\n", __func__); @@ -1822,24 +1152,16 @@ int cx23885_video_register(struct cx23885_dev *dev) strcpy(cx23885_vbi_template.name, "cx23885-vbi"); dev->tvnorm = V4L2_STD_NTSC_M; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_YUYV); + dev->field = V4L2_FIELD_INTERLACED; + dev->width = 720; + dev->height = norm_maxh(dev->tvnorm); /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - dev->vidq.timeout.function = cx23885_vid_timeout; - dev->vidq.timeout.data = (unsigned long)dev; - init_timer(&dev->vidq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vidq.stopper, - VID_A_DMA_CTL, 0x11, 0x00); /* init vbi dma queues */ INIT_LIST_HEAD(&dev->vbiq.active); - INIT_LIST_HEAD(&dev->vbiq.queued); - dev->vbiq.timeout.function = cx23885_vbi_timeout; - dev->vbiq.timeout.data = (unsigned long)dev; - init_timer(&dev->vbiq.timeout); - cx23885_risc_stopper(dev->pci, &dev->vbiq.stopper, - VID_A_DMA_CTL, 0x22, 0x00); cx23885_irq_add_enable(dev, 0x01); @@ -1893,9 +1215,49 @@ int cx23885_video_register(struct cx23885_dev *dev) } } + /* initial device configuration */ + mutex_lock(&dev->lock); + cx23885_set_tvnorm(dev, dev->tvnorm); + cx23885_video_mux(dev, 0); + cx23885_audio_mux(dev, 0); + mutex_unlock(&dev->lock); + + q = &dev->vb2_vidq; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_video_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + + q = &dev->vb2_vbiq; + q->type = V4L2_BUF_TYPE_VBI_CAPTURE; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; + q->gfp_flags = GFP_DMA32; + q->min_buffers_needed = 2; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct cx23885_buffer); + q->ops = &cx23885_vbi_qops; + q->mem_ops = &vb2_dma_sg_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->lock = &dev->lock; + + err = vb2_queue_init(q); + if (err < 0) + goto fail_unreg; + /* register Video device */ dev->video_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_video_template, "video"); + dev->video_dev->queue = &dev->vb2_vidq; err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { @@ -1909,6 +1271,7 @@ int cx23885_video_register(struct cx23885_dev *dev) /* register VBI device */ dev->vbi_dev = cx23885_vdev_init(dev, dev->pci, &cx23885_vbi_template, "vbi"); + dev->vbi_dev->queue = &dev->vb2_vbiq; err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { @@ -1922,18 +1285,9 @@ int cx23885_video_register(struct cx23885_dev *dev) /* Register ALSA audio device */ dev->audio_dev = cx23885_audio_register(dev); - /* initial device configuration */ - mutex_lock(&dev->lock); - cx23885_set_tvnorm(dev, dev->tvnorm); - init_controls(dev); - cx23885_video_mux(dev, 0); - cx23885_audio_mux(dev, 0); - mutex_unlock(&dev->lock); - return 0; fail_unreg: cx23885_video_unregister(dev); return err; } - diff --git a/drivers/media/pci/cx23885/cx23885-video.h b/drivers/media/pci/cx23885/cx23885-video.h index c961a2b0de0f..291e8f3189f0 100644 --- a/drivers/media/pci/cx23885/cx23885-video.h +++ b/drivers/media/pci/cx23885/cx23885-video.h @@ -12,11 +12,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23885_VIDEO_H_ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index 0e086c03da67..6c35e6115969 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -13,10 +13,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/pci.h> @@ -25,19 +21,20 @@ #include <linux/slab.h> #include <media/v4l2-device.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-ctrls.h> #include <media/tuner.h> #include <media/tveeprom.h> -#include <media/videobuf-dma-sg.h> -#include <media/videobuf-dvb.h> +#include <media/videobuf2-dma-sg.h> +#include <media/videobuf2-dvb.h> #include <media/rc-core.h> -#include "btcx-risc.h" #include "cx23885-reg.h" #include "media/cx2341x.h" #include <linux/mutex.h> -#define CX23885_VERSION "0.0.3" +#define CX23885_VERSION "0.0.4" #define UNSET (-1U) @@ -46,9 +43,6 @@ /* Max number of inputs by card */ #define MAX_CX23885_INPUT 8 #define INPUT(nr) (&cx23885_boards[dev->board].input[nr]) -#define RESOURCE_OVERLAY 1 -#define RESOURCE_VIDEO 2 -#define RESOURCE_VBI 4 #define BUFFER_TIMEOUT (HZ) /* 0.5 seconds */ @@ -98,6 +92,7 @@ #define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42 #define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE 43 #define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44 +#define CX23885_BOARD_DVBSKY_T9580 45 #define GPIO_0 0x00000001 #define GPIO_1 0x00000002 @@ -131,14 +126,6 @@ struct cx23885_fmt { u32 cxformat; }; -struct cx23885_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 mask; - u32 shift; -}; - struct cx23885_tvnorm { char *name; v4l2_std_id id; @@ -146,30 +133,6 @@ struct cx23885_tvnorm { u32 cxoformat; }; -struct cx23885_fh { - struct cx23885_dev *dev; - enum v4l2_buf_type type; - int radio; - u32 resources; - - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - - /* video capture */ - struct cx23885_fmt *fmt; - unsigned int width, height; - - /* vbi capture */ - struct videobuf_queue vidq; - struct videobuf_queue vbiq; - - /* MPEG Encoder specifics ONLY */ - struct videobuf_queue mpegq; - atomic_t v4l_reading; -}; - enum cx23885_itype { CX23885_VMUX_COMPOSITE1 = 1, CX23885_VMUX_COMPOSITE2, @@ -189,14 +152,22 @@ enum cx23885_src_sel_type { CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO }; +struct cx23885_riscmem { + unsigned int size; + __le32 *cpu; + __le32 *jmp; + dma_addr_t dma; +}; + /* buffer for one video frame */ struct cx23885_buffer { /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; + struct vb2_buffer vb; + struct list_head queue; /* cx23885 specific */ unsigned int bpl; - struct btcx_riscmem risc; + struct cx23885_riscmem risc; struct cx23885_fmt *fmt; u32 count; }; @@ -268,9 +239,6 @@ struct cx23885_i2c { struct cx23885_dmaqueue { struct list_head active; - struct list_head queued; - struct timer_list timeout; - struct btcx_riscmem stopper; u32 count; }; @@ -280,7 +248,7 @@ struct cx23885_tsport { int nr; int sram_chno; - struct videobuf_dvb_frontends frontends; + struct vb2_dvb_frontends frontends; /* dma queues */ struct cx23885_dmaqueue mpegq; @@ -326,7 +294,12 @@ struct cx23885_tsport { /* Workaround for a temp dvb_frontend that the tuner can attached to */ struct dvb_frontend analog_fe; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; + int (*set_frontend)(struct dvb_frontend *fe); + int (*fe_set_voltage)(struct dvb_frontend *fe, + fe_sec_voltage_t voltage); }; struct cx23885_kernel_ir { @@ -339,8 +312,11 @@ struct cx23885_kernel_ir { struct cx23885_audio_buffer { unsigned int bpl; - struct btcx_riscmem risc; - struct videobuf_dmabuf dma; + struct cx23885_riscmem risc; + void *vaddr; + struct scatterlist *sglist; + int sglen; + int nr_pages; }; struct cx23885_audio_dev { @@ -358,8 +334,6 @@ struct cx23885_audio_dev { unsigned int period_size; unsigned int num_periods; - struct videobuf_dmabuf *dma_risc; - struct cx23885_audio_buffer *buf; struct snd_pcm_substream *substream; @@ -368,6 +342,7 @@ struct cx23885_audio_dev { struct cx23885_dev { atomic_t refcount; struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl_handler; /* pci stuff */ struct pci_dev *pci; @@ -407,7 +382,6 @@ struct cx23885_dev { } bridge; /* Analog video */ - u32 resources; unsigned int input; unsigned int audinput; /* Selectable audio input */ u32 tvaudio; @@ -417,7 +391,6 @@ struct cx23885_dev { unsigned int tuner_bus; unsigned int radio_type; unsigned char radio_addr; - unsigned int has_radio; struct v4l2_subdev *sd_cx25840; struct work_struct cx25840_work; @@ -435,17 +408,24 @@ struct cx23885_dev { u32 freq; struct video_device *video_dev; struct video_device *vbi_dev; - struct video_device *radio_dev; + + /* video capture */ + struct cx23885_fmt *fmt; + unsigned int width, height; + unsigned field; struct cx23885_dmaqueue vidq; + struct vb2_queue vb2_vidq; struct cx23885_dmaqueue vbiq; + struct vb2_queue vb2_vbiq; + spinlock_t slock; /* MPEG Encoder ONLY settings */ u32 cx23417_mailbox; - struct cx2341x_mpeg_params mpeg_params; + struct cx2341x_handler cxhdl; struct video_device *v4l_device; - atomic_t v4l_reader_count; + struct vb2_queue vb2_mpegq; struct cx23885_tvnorm encodernorm; /* Analog raw audio */ @@ -521,26 +501,21 @@ extern int cx23885_sram_channel_setup(struct cx23885_dev *dev, extern void cx23885_sram_channel_dump(struct cx23885_dev *dev, struct sram_channel *ch); -extern int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, - u32 reg, u32 mask, u32 value); - -extern int cx23885_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, +extern int cx23885_risc_buffer(struct pci_dev *pci, struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); extern int cx23885_risc_vbibuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, struct scatterlist *sglist, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines); +int cx23885_start_dma(struct cx23885_tsport *port, + struct cx23885_dmaqueue *q, + struct cx23885_buffer *buf); void cx23885_cancel_buffers(struct cx23885_tsport *port); -extern int cx23885_restart_queue(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q); - -extern void cx23885_wakeup(struct cx23885_tsport *port, - struct cx23885_dmaqueue *q, u32 count); extern void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask); extern void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask); @@ -574,13 +549,11 @@ extern void cx23885_card_setup_pre_i2c(struct cx23885_dev *dev); extern int cx23885_dvb_register(struct cx23885_tsport *port); extern int cx23885_dvb_unregister(struct cx23885_tsport *port); -extern int cx23885_buf_prepare(struct videobuf_queue *q, - struct cx23885_tsport *port, - struct cx23885_buffer *buf, - enum v4l2_field field); +extern int cx23885_buf_prepare(struct cx23885_buffer *buf, + struct cx23885_tsport *port); extern void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf); -extern void cx23885_free_buffer(struct videobuf_queue *q, +extern void cx23885_free_buffer(struct cx23885_dev *dev, struct cx23885_buffer *buf); /* ----------------------------------------------------------- */ @@ -595,8 +568,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i); int cx23885_set_input(struct file *file, void *priv, unsigned int i); int cx23885_get_input(struct file *file, void *priv, unsigned int *i); int cx23885_set_frequency(struct file *file, void *priv, const struct v4l2_frequency *f); -int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl); -int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl); int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); /* ----------------------------------------------------------- */ @@ -604,9 +575,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm); extern int cx23885_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); extern void cx23885_vbi_timeout(unsigned long data); -extern struct videobuf_queue_ops cx23885_vbi_qops; -extern int cx23885_restart_vbi_queue(struct cx23885_dev *dev, - struct cx23885_dmaqueue *q); +extern struct vb2_ops cx23885_vbi_qops; extern int cx23885_vbi_irq(struct cx23885_dev *dev, u32 status); /* cx23885-i2c.c */ @@ -638,7 +607,7 @@ extern struct cx23885_audio_dev *cx23885_audio_register( extern void cx23885_audio_unregister(struct cx23885_dev *dev); extern int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask); extern int cx23885_risc_databuffer(struct pci_dev *pci, - struct btcx_riscmem *risc, + struct cx23885_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, @@ -649,15 +618,10 @@ extern int cx23885_risc_databuffer(struct pci_dev *pci, static inline unsigned int norm_maxw(v4l2_std_id norm) { - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768; + return (norm & V4L2_STD_525_60) ? 720 : 768; } static inline unsigned int norm_maxh(v4l2_std_id norm) { - return (norm & V4L2_STD_625_50) ? 576 : 480; -} - -static inline unsigned int norm_swidth(v4l2_std_id norm) -{ - return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922; + return (norm & V4L2_STD_525_60) ? 480 : 576; } diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index 2c951dec2d33..c1aa888af705 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #include <linux/kfifo.h> @@ -263,7 +258,7 @@ static inline unsigned int lpf_count_to_us(unsigned int count) } /* - * FIFO register pulse width count compuations + * FIFO register pulse width count computations */ static u32 clock_divider_to_resolution(u16 divider) { diff --git a/drivers/media/pci/cx23885/cx23888-ir.h b/drivers/media/pci/cx23885/cx23888-ir.h index d2de41caaf1d..ff74a93575d6 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.h +++ b/drivers/media/pci/cx23885/cx23888-ir.h @@ -14,11 +14,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ #ifndef _CX23888_IR_H_ diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c index 98a48f500684..b6542ee4385b 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.c +++ b/drivers/media/pci/cx23885/netup-eeprom.c @@ -17,10 +17,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ # diff --git a/drivers/media/pci/cx23885/netup-eeprom.h b/drivers/media/pci/cx23885/netup-eeprom.h index 13926e18feba..90cac5b655d5 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.h +++ b/drivers/media/pci/cx23885/netup-eeprom.h @@ -16,10 +16,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef NETUP_EEPROM_H diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c index 0044fef7ca24..76d9487aafc8 100644 --- a/drivers/media/pci/cx23885/netup-init.c +++ b/drivers/media/pci/cx23885/netup-init.c @@ -17,10 +17,6 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx23885.h" diff --git a/drivers/media/pci/cx23885/netup-init.h b/drivers/media/pci/cx23885/netup-init.h index d26ae4b1590e..daaa212adfba 100644 --- a/drivers/media/pci/cx23885/netup-init.h +++ b/drivers/media/pci/cx23885/netup-init.h @@ -17,9 +17,5 @@ * 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 General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ extern void netup_initialize(struct cx23885_dev *dev); diff --git a/drivers/media/pci/cx25821/cx25821-video-upstream.c b/drivers/media/pci/cx25821/cx25821-video-upstream.c index 1f43be0b04c8..a664997e1958 100644 --- a/drivers/media/pci/cx25821/cx25821-video-upstream.c +++ b/drivers/media/pci/cx25821/cx25821-video-upstream.c @@ -330,8 +330,9 @@ int cx25821_write_frame(struct cx25821_channel *chan, if (frame_size - curpos < count) count = frame_size - curpos; - memcpy((char *)out->_data_buf_virt_addr + frame_offset + curpos, - data, count); + if (copy_from_user((__force char *)out->_data_buf_virt_addr + frame_offset + curpos, + data, count)) + return -EFAULT; curpos += count; if (curpos == frame_size) { out->_frame_count++; diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index e18a7ace08b1..851754bf1291 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -78,19 +78,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE3, .vmux = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE4, .vmux = 3, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE] = { .name = "Hauppauge WinTV 34xxx models", @@ -99,23 +99,23 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, // internal decoder - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, // mono from tuner chip - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xff02, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xff01, @@ -127,13 +127,13 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, }, [CX88_BOARD_PIXELVIEW] = { .name = "PixelView", @@ -141,17 +141,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xff00, // internal decoder - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xff10, @@ -164,19 +164,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x03ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x03fe, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x03fe, - }}, + } }, }, [CX88_BOARD_WINFAST2000XP_EXPERT] = { .name = "Leadtek Winfast 2000XP Expert", @@ -185,28 +185,28 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00F5e700, .gpio1 = 0x00003004, .gpio2 = 0x00F5e700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00F5c700, .gpio1 = 0x00003004, .gpio2 = 0x00F5c700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00F5c700, .gpio1 = 0x00003004, .gpio2 = 0x00F5c700, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00F5d700, @@ -222,19 +222,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio1 = 0xe09f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio1 = 0xe05f, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio1 = 0xe05f, - }}, + } }, .radio = { .gpio1 = 0xe0df, .type = CX88_RADIO, @@ -249,25 +249,25 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER_NTSC, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000040bf, .gpio1 = 0x000080c0, .gpio2 = 0x0000ff40, - }}, + } }, .radio = { .type = CX88_RADIO, .vmux = 3, @@ -283,14 +283,14 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0035e700, .gpio1 = 0x00003004, .gpio2 = 0x0035e700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, @@ -298,14 +298,14 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x00003004, .gpio2 = 0x0035c700, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0035c700, .gpio1 = 0x0035c700, .gpio2 = 0x02000000, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0035d700, @@ -322,22 +322,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000bde2, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000bde6, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000bde6, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000bd62, @@ -351,16 +351,16 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE2, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, }, [CX88_BOARD_PROLINK_PLAYTVPVR] = { .name = "Prolink PlayTV PVR", @@ -369,19 +369,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xbff0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xbff3, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xbff3, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xbff0, @@ -394,16 +394,16 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000fde6, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000fde6, // 0x0000fda6 L,R RCA audio in? .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x0000fde2, @@ -417,22 +417,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc08, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc68, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000fbf, .gpio2 = 0x0000fc68, - }}, + } }, }, [CX88_BOARD_KWORLD_DVB_T] = { .name = "KWorld/VStream XPert DVB-T", @@ -440,17 +440,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = { @@ -459,15 +459,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000027df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000027df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_LTV883] = { @@ -476,23 +476,23 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x07f8, - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0x07f9, // mono from tuner chip - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000007fa, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000007fa, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x000007f8, @@ -521,23 +521,23 @@ static const struct cx88_board cx88_boards[] = { 0 - normal RF 1 - high RF */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0f0d, - },{ + }, { .type = CX88_VMUX_CABLE, .vmux = 0, .gpio0 = 0x0f05, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0f00, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0f00, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_DVB_T1] = { @@ -546,10 +546,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_CONEXANT_DVB_T1] = { @@ -558,10 +558,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PROVIDEO_PV259] = { @@ -570,11 +570,11 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .audioroute = 1, - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = { @@ -583,15 +583,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000027df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000027df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DNTV_LIVE_DVB_T] = { @@ -600,17 +600,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000700, .gpio2 = 0x00000101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000700, .gpio2 = 0x00000101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PCHDTV_HD3000] = { @@ -632,19 +632,19 @@ static const struct cx88_board cx88_boards[] = { * * GPIO[16] = Remote control input */ - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00008484, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00008400, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00008400, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00008404, @@ -659,25 +659,25 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xed1a, .gpio2 = 0x00ff, - },{ + }, { .type = CX88_VMUX_DEBUG, .vmux = 0, .gpio0 = 0xff01, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xff02, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xed92, .gpio2 = 0x00ff, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xed96, @@ -692,22 +692,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00009d80, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00009d76, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00009d76, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00009d00, @@ -722,19 +722,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 1, .gpio1 = 0x0000e03f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 2, .gpio1 = 0x0000e07f, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 3, .gpio1 = 0x0000e07f, - }} + } } }, [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = { .name = "PixelView PlayTV Ultra Pro (Stereo)", @@ -745,19 +745,19 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, /* Some variants use a tda9874 and so need the tvaudio module. */ .audio_chip = CX88_AUDIO_TVAUDIO, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xbf61, /* internal decoder */ - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xbf63, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xbf63, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xbf60, @@ -770,19 +770,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x97ed, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x97e9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x97e9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_ADSTECH_DVB_T_PCI] = { @@ -791,32 +791,32 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = { .name = "TerraTec Cinergy 1400 DVB-T", .tuner_type = TUNER_ABSENT, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = { @@ -826,19 +826,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x87fd, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x87f9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x87f9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = { @@ -848,22 +848,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 0, .gpio0 = 0x0000cd73, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 1, .gpio0 = 0x0000cd73, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_TELEVISION, .vmux = 3, .gpio0 = 0x0000cdb3, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .vmux = 2, @@ -876,21 +876,21 @@ static const struct cx88_board cx88_boards[] = { /* Alexander Wold <awold@bigfoot.com> */ .name = "Kworld V-Stream Xpert DVD", .tuner_type = UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x03000000, .gpio1 = 0x01000000, .gpio2 = 0x02000000, .gpio3 = 0x00100000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x03000000, .gpio1 = 0x01000000, .gpio2 = 0x02000000, .gpio3 = 0x00100000, - }}, + } }, }, [CX88_BOARD_ATI_HDTVWONDER] = { .name = "ATI HDTV Wonder", @@ -898,28 +898,28 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00000ff7, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00000ffe, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00000ffe, .gpio1 = 0x000000ff, .gpio2 = 0x00000001, .gpio3 = 0x00000000, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_WINFAST_DTV1000] = { @@ -928,16 +928,16 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_AVERTV_303] = { @@ -947,28 +947,28 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00ff, .gpio1 = 0xe09f, .gpio2 = 0x0010, .gpio3 = 0x0000, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x00ff, .gpio1 = 0xe05f, .gpio2 = 0x0010, .gpio3 = 0x0000, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x00ff, .gpio1 = 0xe05f, .gpio2 = 0x0010, .gpio3 = 0x0000, - }}, + } }, }, [CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = { .name = "Hauppauge Nova-S-Plus DVB-S", @@ -978,22 +978,22 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .audio_chip = CX88_AUDIO_WM8775, .i2sinputcntl = 2, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = { @@ -1002,10 +1002,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_DVBS_100] = { @@ -1015,22 +1015,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .audio_chip = CX88_AUDIO_WM8775, - .input = {{ + .input = { { .type = CX88_VMUX_DVB, .vmux = 0, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, /* 2: Line-In */ .audioroute = 2, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, /* 2: Line-In */ .audioroute = 2, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_HAUPPAUGE_HVR1100] = { @@ -1040,16 +1040,16 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, - }}, + } }, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB, }, @@ -1060,13 +1060,13 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - }}, + } }, /* fixme: Add radio support */ .mpeg = CX88_MPEG_DVB, }, @@ -1078,19 +1078,19 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0xf80808, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0xf80808, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0xf80808, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0xf80808, @@ -1106,17 +1106,17 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0700, .gpio2 = 0x0101, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0700, .gpio2 = 0x0101, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = { @@ -1125,15 +1125,15 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x000067df, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x000067df, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { @@ -1142,22 +1142,22 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x3de2, .gpio2 = 0x00ff, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x3de6, .audioroute = 1, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x3de6, .audioroute = 1, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x3de6, @@ -1171,19 +1171,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000a75f, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0000a75b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x0000a75b, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_PCHDTV_HD5500] = { @@ -1193,19 +1193,19 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x87fd, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x87f9, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x87f9, - }}, + } }, .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_MCE200_DELUXE] = { @@ -1217,11 +1217,11 @@ static const struct cx88_board cx88_boards[] = { .tda9887_conf = TDA9887_PRESENT, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0000BDE6 - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = { @@ -1233,11 +1233,11 @@ static const struct cx88_board cx88_boards[] = { .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x5da6, - }}, + } }, .mpeg = CX88_MPEG_BLACKBIRD, }, [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = { @@ -1246,19 +1246,19 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x0788, - },{ + }, { .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x078b, - },{ + }, { .type = CX88_VMUX_SVIDEO, .vmux = 2, .gpio0 = 0x078b, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x074a, @@ -1271,7 +1271,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00017304, @@ -1299,7 +1299,7 @@ static const struct cx88_board cx88_boards[] = { .gpio1 = 0x0000b207, .gpio2 = 0x0001d701, .gpio3 = 0x02000000, - }}, + } }, .radio = { .type = CX88_RADIO, .gpio0 = 0x00015702, @@ -1316,35 +1316,35 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .input = {{ + .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00017300, .gpio1 = 0x00008207, .gpio2 = 0x00000000, .gpio3 = 0x02000000, - },{ + }, { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00018300, .g |