diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 639e74857968..df2962d9e11e 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -174,7 +174,7 @@ FILENAME = \
DOCUMENTED = \
-e "s/\(enum *\)v4l2_mpeg_cx2341x_video_\([a-z]*_spatial_filter_type\)/\1v4l2_mpeg_cx2341x_video_\2<\/link>/g" \
-e "s/\(\(enum\|struct\) *\)\(v4l2_[a-zA-Z0-9_]*\)/\1\3<\/link>/g" \
- -e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\) /\1<\/link> /g" \
+ -e "s/\(V4L2_PIX_FMT_[A-Z0-9_]\+\)\(\s\+v4l2_fourcc\)/\1<\/link>\2/g" \
-e ":a;s/\(linkend=\".*\)_\(.*\">\)/\1-\2/;ta" \
-e "s/v4l2\-mpeg\-vbi\-ITV0/v4l2-mpeg-vbi-itv0-1/g"
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index 24c22cabc668..948ddaab592e 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -555,10 +555,46 @@ typedef enum fe_delivery_system {
DTV_ISDBT_LAYER*_TIME_INTERLEAVING
- Possible values: 0, 1, 2, 3, -1 (AUTO)
- Note: The real inter-leaver depth-names depend on the mode (fft-size); the values
- here are referring to what can be found in the TMCC-structure -
- independent of the mode.
+ Valid values: 0, 1, 2, 4, -1 (AUTO)
+ when DTV_ISDBT_SOUND_BROADCASTING is active, value 8 is also valid.
+ Note: The real time interleaving length depends on the mode (fft-size). The values
+ here are referring to what can be found in the TMCC-structure, as shown in the table below.
+
+
+
+
+ DTV_ISDBT_LAYER*_TIME_INTERLEAVING
+ Mode 1 (2K FFT)
+ Mode 2 (4K FFT)
+ Mode 3 (8K FFT)
+
+
+ 0
+ 0
+ 0
+ 0
+
+
+ 1
+ 4
+ 2
+ 1
+
+
+ 2
+ 8
+ 4
+ 2
+
+
+ 4
+ 16
+ 8
+ 4
+
+
+
+ DTV_ATSCMH_FIC_VER
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 47198eef75a4..9f5ffd85560b 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -13,6 +13,19 @@ correctly with any device.
All controls are accessed using an ID value. V4L2 defines
several IDs for specific purposes. Drivers can also implement their
own custom controls using V4L2_CID_PRIVATE_BASE
+The use of V4L2_CID_PRIVATE_BASE
+is problematic because different drivers may use the same
+V4L2_CID_PRIVATE_BASE ID for different controls.
+This makes it hard to programatically set such controls since the meaning
+of the control with that ID is driver dependent. In order to resolve this
+drivers use unique IDs and the V4L2_CID_PRIVATE_BASE
+IDs are mapped to those unique IDs by the kernel. Consider these
+V4L2_CID_PRIVATE_BASE IDs as aliases to the real
+IDs.
+Many applications today still use the V4L2_CID_PRIVATE_BASE
+IDs instead of using &VIDIOC-QUERYCTRL; with the V4L2_CTRL_FLAG_NEXT_CTRL
+flag to enumerate all IDs, so support for V4L2_CID_PRIVATE_BASE
+is still around.
and higher values. The pre-defined control IDs have the prefix
V4L2_CID_, and are listed in . The ID is used when querying the attributes of
@@ -31,25 +44,22 @@ the current video input or output, tuner or modulator, or audio input
or output. Different in the sense of other bounds, another default and
current value, step size or other menu items. A control with a certain
custom ID can also change name and
-type.
- It will be more convenient for applications if drivers
-make use of the V4L2_CTRL_FLAG_DISABLED flag, but
-that was never required.
- Control values are stored globally, they do not
+type.
+
+ If a control is not applicable to the current configuration
+of the device (for example, it doesn't apply to the current video input)
+drivers set the V4L2_CTRL_FLAG_INACTIVE flag.
+
+ Control values are stored globally, they do not
change when switching except to stay within the reported bounds. They
also do not change ⪚ when the device is opened or closed, when the
tuner radio frequency is changed or generally never without
-application request. Since V4L2 specifies no event mechanism, panel
-applications intended to cooperate with other panel applications (be
-they built into a larger application, as a TV viewer) may need to
-regularly poll control values to update their user
-interface.
- Applications could call an ioctl to request events.
-After another process called &VIDIOC-S-CTRL; or another ioctl changing
-shared properties the &func-select; function would indicate
-readability until any ioctl (querying the properties) is
-called.
-
+application request.
+
+ V4L2 specifies an event mechanism to notify applications
+when controls change value (see &VIDIOC-SUBSCRIBE-EVENT;, event
+V4L2_EVENT_CTRL), panel applications might want to make
+use of that in order to always reflect the correct control value.
All controls use machine endianness.
@@ -398,14 +408,17 @@ to work.
V4L2_CID_ALPHA_COMPONENTinteger
- Sets the alpha color component on the capture device or on
- the capture buffer queue of a mem-to-mem device. When a mem-to-mem
- device produces frame format that includes an alpha component
+ Sets the alpha color component. When a capture device (or
+ capture queue of a mem-to-mem device) produces a frame format that
+ includes an alpha component
(e.g. packed RGB image formats)
- and the alpha value is not defined by the mem-to-mem input data
- this control lets you select the alpha component value of all
- pixels. It is applicable to any pixel format that contains an alpha
- component.
+ and the alpha value is not defined by the device or the mem-to-mem
+ input data this control lets you select the alpha component value of
+ all pixels. When an output device (or output queue of a mem-to-mem
+ device) consumes a frame format that doesn't include an alpha
+ component and the device supports alpha channel processing this
+ control lets you set the alpha component value of all pixels for
+ further processing in the device.
@@ -434,73 +447,98 @@ Drivers must implement VIDIOC_QUERYCTRL,
controls, VIDIOC_QUERYMENU when it has one or
more menu type controls.
-
- Enumerating all controls
+
+ Enumerating all user controls
&v4l2-queryctrl; queryctrl;
&v4l2-querymenu; querymenu;
-static void
-enumerate_menu (void)
+static void enumerate_menu(void)
{
- printf (" Menu items:\n");
+ printf(" Menu items:\n");
- memset (&querymenu, 0, sizeof (querymenu));
+ memset(&querymenu, 0, sizeof(querymenu));
querymenu.id = queryctrl.id;
for (querymenu.index = queryctrl.minimum;
querymenu.index <= queryctrl.maximum;
- querymenu.index++) {
- if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &querymenu)) {
- printf (" %s\n", querymenu.name);
+ querymenu.index++) {
+ if (0 == ioctl(fd, &VIDIOC-QUERYMENU;, &querymenu)) {
+ printf(" %s\n", querymenu.name);
}
}
}
-memset (&queryctrl, 0, sizeof (queryctrl));
+memset(&queryctrl, 0, sizeof(queryctrl));
for (queryctrl.id = V4L2_CID_BASE;
queryctrl.id < V4L2_CID_LASTP1;
queryctrl.id++) {
- if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
continue;
- printf ("Control %s\n", queryctrl.name);
+ printf("Control %s\n", queryctrl.name);
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
- enumerate_menu ();
+ enumerate_menu();
} else {
if (errno == EINVAL)
continue;
- perror ("VIDIOC_QUERYCTRL");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_QUERYCTRL");
+ exit(EXIT_FAILURE);
}
}
for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
queryctrl.id++) {
- if (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
continue;
- printf ("Control %s\n", queryctrl.name);
+ printf("Control %s\n", queryctrl.name);
if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
- enumerate_menu ();
+ enumerate_menu();
} else {
if (errno == EINVAL)
break;
- perror ("VIDIOC_QUERYCTRL");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_QUERYCTRL");
+ exit(EXIT_FAILURE);
}
}
+
+ Enumerating all user controls (alternative)
+
+memset(&queryctrl, 0, sizeof(queryctrl));
+
+queryctrl.id = V4L2_CTRL_CLASS_USER | V4L2_CTRL_FLAG_NEXT_CTRL;
+while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+ if (V4L2_CTRL_ID2CLASS(queryctrl.id) != V4L2_CTRL_CLASS_USER)
+ break;
+ if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)
+ continue;
+
+ printf("Control %s\n", queryctrl.name);
+
+ if (queryctrl.type == V4L2_CTRL_TYPE_MENU)
+ enumerate_menu();
+
+ queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
+if (errno != EINVAL) {
+ perror("VIDIOC_QUERYCTRL");
+ exit(EXIT_FAILURE);
+}
+
+
+
Changing controls
@@ -508,53 +546,53 @@ for (queryctrl.id = V4L2_CID_PRIVATE_BASE;;
&v4l2-queryctrl; queryctrl;
&v4l2-control; control;
-memset (&queryctrl, 0, sizeof (queryctrl));
+memset(&queryctrl, 0, sizeof(queryctrl));
queryctrl.id = V4L2_CID_BRIGHTNESS;
-if (-1 == ioctl (fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
+if (-1 == ioctl(fd, &VIDIOC-QUERYCTRL;, &queryctrl)) {
if (errno != EINVAL) {
- perror ("VIDIOC_QUERYCTRL");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_QUERYCTRL");
+ exit(EXIT_FAILURE);
} else {
- printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+ printf("V4L2_CID_BRIGHTNESS is not supported\n");
}
} else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
- printf ("V4L2_CID_BRIGHTNESS is not supported\n");
+ printf("V4L2_CID_BRIGHTNESS is not supported\n");
} else {
- memset (&control, 0, sizeof (control));
+ memset(&control, 0, sizeof (control));
control.id = V4L2_CID_BRIGHTNESS;
control.value = queryctrl.default_value;
- if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &control)) {
- perror ("VIDIOC_S_CTRL");
- exit (EXIT_FAILURE);
+ if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &control)) {
+ perror("VIDIOC_S_CTRL");
+ exit(EXIT_FAILURE);
}
}
-memset (&control, 0, sizeof (control));
+memset(&control, 0, sizeof(control));
control.id = V4L2_CID_CONTRAST;
-if (0 == ioctl (fd, &VIDIOC-G-CTRL;, &control)) {
+if (0 == ioctl(fd, &VIDIOC-G-CTRL;, &control)) {
control.value += 1;
/* The driver may clamp the value or return ERANGE, ignored here */
- if (-1 == ioctl (fd, &VIDIOC-S-CTRL;, &control)
+ if (-1 == ioctl(fd, &VIDIOC-S-CTRL;, &control)
&& errno != ERANGE) {
- perror ("VIDIOC_S_CTRL");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_S_CTRL");
+ exit(EXIT_FAILURE);
}
/* Ignore if V4L2_CID_CONTRAST is unsupported */
} else if (errno != EINVAL) {
- perror ("VIDIOC_G_CTRL");
- exit (EXIT_FAILURE);
+ perror("VIDIOC_G_CTRL");
+ exit(EXIT_FAILURE);
}
control.id = V4L2_CID_AUDIO_MUTE;
-control.value = TRUE; /* silence */
+control.value = 1; /* silence */
/* Errors ignored */
-ioctl (fd, VIDIOC_S_CTRL, &control);
+ioctl(fd, VIDIOC_S_CTRL, &control);
@@ -625,16 +663,29 @@ supported.
&v4l2-control;, except for the fact that it also allows for 64-bit
values and pointers to be passed.
+ Since the &v4l2-ext-control; supports pointers it is now
+also possible to have controls with compound types such as N-dimensional arrays
+and/or structures. You need to specify the V4L2_CTRL_FLAG_NEXT_COMPOUND
+when enumerating controls to actually be able to see such compound controls.
+In other words, these controls with compound types should only be used
+programmatically.
+
+ Since such compound controls need to expose more information
+about themselves than is possible with &VIDIOC-QUERYCTRL; the
+&VIDIOC-QUERY-EXT-CTRL; ioctl was added. In particular, this ioctl gives
+the dimensions of the N-dimensional array if this control consists of more than
+one element.
+
It is important to realize that due to the flexibility of
controls it is necessary to check whether the control you want to set
actually is supported in the driver and what the valid range of values
-is. So use the &VIDIOC-QUERYCTRL; and &VIDIOC-QUERYMENU; ioctls to
-check this. Also note that it is possible that some of the menu
-indices in a control of type V4L2_CTRL_TYPE_MENU
-may not be supported (VIDIOC_QUERYMENU will
-return an error). A good example is the list of supported MPEG audio
-bitrates. Some drivers only support one or two bitrates, others
-support a wider range.
+is. So use the &VIDIOC-QUERYCTRL; (or &VIDIOC-QUERY-EXT-CTRL;) and
+&VIDIOC-QUERYMENU; ioctls to check this. Also note that it is possible
+that some of the menu indices in a control of type
+V4L2_CTRL_TYPE_MENU may not be supported
+(VIDIOC_QUERYMENU will return an error). A good
+example is the list of supported MPEG audio bitrates. Some drivers only
+support one or two bitrates, others support a wider range.
All controls use machine endianness.
@@ -675,12 +726,12 @@ control class is found:
qctrl.id = V4L2_CTRL_CLASS_MPEG | V4L2_CTRL_FLAG_NEXT_CTRL;
-while (0 == ioctl (fd, &VIDIOC-QUERYCTRL;, &qctrl)) {
- if (V4L2_CTRL_ID2CLASS (qctrl.id) != V4L2_CTRL_CLASS_MPEG)
+while (0 == ioctl(fd, &VIDIOC-QUERYCTRL;, &qctrl)) {
+ if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_MPEG)
break;
/* ... */
- qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
- }
+ qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL;
+}
@@ -700,7 +751,7 @@ ID based on a control ID.
VIDIOC_QUERYCTRL will fail when used in
combination with V4L2_CTRL_FLAG_NEXT_CTRL. In
that case the old method of enumerating control should be used (see
-1.8). But if it is supported, then it is guaranteed to enumerate over
+). But if it is supported, then it is guaranteed to enumerate over
all controls, including driver-private controls.
@@ -3998,6 +4049,68 @@ in Annex E of . The length of Radio Text strings depe
used to transmit it, either 32 (2A block) or 64 (2B block). However, it is also possible
to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64.
+
+
+ V4L2_CID_RDS_TX_MONO_STEREO
+ boolean
+
+ Sets the Mono/Stereo bit of the Decoder Identification code. If set,
+then the audio was recorded as stereo.
+
+
+ V4L2_CID_RDS_TX_ARTIFICIAL_HEAD
+ boolean
+
+ Sets the
+Artificial Head bit of the Decoder
+Identification code. If set, then the audio was recorded using an artificial head.
+
+
+ V4L2_CID_RDS_TX_COMPRESSED
+ boolean
+
+ Sets the Compressed bit of the Decoder Identification code. If set,
+then the audio is compressed.
+
+
+ V4L2_CID_RDS_TX_DYNAMIC_PTY
+ boolean
+
+ Sets the Dynamic PTY bit of the Decoder Identification code. If set,
+then the PTY code is dynamically switched.
+
+
+ V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT
+ boolean
+
+ If set, then a traffic announcement is in progress.
+
+
+ V4L2_CID_RDS_TX_TRAFFIC_PROGRAM
+ boolean
+
+ If set, then the tuned programme carries traffic announcements.
+
+
+ V4L2_CID_RDS_TX_MUSIC_SPEECH
+ boolean
+
+ If set, then this channel broadcasts music. If cleared, then it
+broadcasts speech. If the transmitter doesn't make this distinction, then it should be set.
+
+
+ V4L2_CID_RDS_TX_ALT_FREQS_ENABLE
+ boolean
+
+ If set, then transmit alternate frequencies.
+
+
+ V4L2_CID_RDS_TX_ALT_FREQS
+ __u32 array
+
+ The alternate frequencies in kHz units. The RDS standard allows
+for up to 25 frequencies to be defined. Drivers may support fewer frequencies so check
+the array size.V4L2_CID_AUDIO_LIMITER_ENABLED
@@ -4976,6 +5089,57 @@ description of this control class.
Enables/disables RDS
reception by the radio tuner
+
+ V4L2_CID_RDS_RX_PTY
+ integer
+
+ Gets RDS Programme Type field.
+This encodes up to 31 pre-defined programme types.
+
+
+ V4L2_CID_RDS_RX_PS_NAME
+ string
+
+ Gets the Programme Service name (PS_NAME).
+It is intended for static display on a receiver. It is the primary aid to listeners in programme service
+identification and selection. In Annex E of , the RDS specification,
+there is a full description of the correct character encoding for Programme Service name strings.
+Also from RDS specification, PS is usually a single eight character text. However, it is also possible
+to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
+with steps of 8 characters. The result is it must always contain a string with size multiple of 8.
+
+
+ V4L2_CID_RDS_RX_RADIO_TEXT
+ string
+
+ Gets the Radio Text info. It is a textual description of
+what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
+programme-related information or any other text. In these cases, RadioText can be used in addition to
+V4L2_CID_RDS_RX_PS_NAME. The encoding for Radio Text strings is also fully described
+in Annex E of . The length of Radio Text strings depends on which RDS Block is being
+used to transmit it, either 32 (2A block) or 64 (2B block). However, it is also possible
+to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
+with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64.
+
+
+ V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT
+ boolean
+
+ If set, then a traffic announcement is in progress.
+
+
+ V4L2_CID_RDS_RX_TRAFFIC_PROGRAM
+ boolean
+
+ If set, then the tuned programme carries traffic announcements.
+
+
+ V4L2_CID_RDS_RX_MUSIC_SPEECH
+ boolean
+
+ If set, then this channel broadcasts music. If cleared, then it
+broadcasts speech. If the transmitter doesn't make this distinction, then it will be set.
+ V4L2_CID_TUNE_DEEMPHASISenum v4l2_deemphasis
@@ -5007,6 +5171,102 @@ defines possible values for de-emphasis. Here they are:
+
+
+
+ Detect Control Reference
+
+ The Detect class includes controls for common features of
+ various motion or object detection capable devices.
+
+
+ Detect Control IDs
+
+
+
+
+
+
+
+
+
+
+ ID
+ Type
+ Description
+
+
+
+
+
+ V4L2_CID_DETECT_CLASS
+ class
+ The Detect class
+descriptor. Calling &VIDIOC-QUERYCTRL; for this control will return a
+description of this control class.
+
+
+ V4L2_CID_DETECT_MD_MODE
+ menu
+ Sets the motion detection mode.
+
+
+
+
+
+ V4L2_DETECT_MD_MODE_DISABLED
+ Disable motion detection.
+
+
+ V4L2_DETECT_MD_MODE_GLOBAL
+ Use a single motion detection threshold.
+
+
+ V4L2_DETECT_MD_MODE_THRESHOLD_GRID
+ The image is divided into a grid, each cell with its own
+ motion detection threshold. These thresholds are set through the
+ V4L2_CID_DETECT_MD_THRESHOLD_GRID matrix control.
+
+
+ V4L2_DETECT_MD_MODE_REGION_GRID
+ The image is divided into a grid, each cell with its own
+ region value that specifies which per-region motion detection thresholds
+ should be used. Each region has its own thresholds. How these per-region
+ thresholds are set up is driver-specific. The region values for the grid are set
+ through the V4L2_CID_DETECT_MD_REGION_GRID matrix
+ control.
+
+
+
+
+
+ V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD
+ integer
+
+ Sets the global motion detection threshold to be
+ used with the V4L2_DETECT_MD_MODE_GLOBAL motion detection mode.
+
+
+ V4L2_CID_DETECT_MD_THRESHOLD_GRID
+ __u16 matrix
+
+ Sets the motion detection thresholds for each cell in the grid.
+ To be used with the V4L2_DETECT_MD_MODE_THRESHOLD_GRID
+ motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+ grid.
+
+
+ V4L2_CID_DETECT_MD_REGION_GRID
+ __u8 matrix
+
+ Sets the motion detection region value for each cell in the grid.
+ To be used with the V4L2_DETECT_MD_MODE_REGION_GRID
+ motion detection mode. Matrix element (0, 0) represents the cell at the top-left of the
+ grid.
+
+
+
+
diff --git a/Documentation/DocBook/media/v4l/dev-raw-vbi.xml b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml
index b788c72c885e..f4b61b6ce3c2 100644
--- a/Documentation/DocBook/media/v4l/dev-raw-vbi.xml
+++ b/Documentation/DocBook/media/v4l/dev-raw-vbi.xml
@@ -150,9 +150,15 @@ signal. Drivers shall not convert the sample format by software.
This is the scanning system line number
associated with the first line of the VBI image, of the first and the
second field respectively. See and
- for valid values. VBI input drivers can
-return start values 0 if the hardware cannot reliable identify
-scanning lines, VBI acquisition may not require this
+ for valid values.
+The V4L2_VBI_ITU_525_F1_START,
+V4L2_VBI_ITU_525_F2_START,
+V4L2_VBI_ITU_625_F1_START and
+V4L2_VBI_ITU_625_F2_START defines give the start line
+numbers for each field for each 525 or 625 line format as a convenience.
+Don't forget that ITU line numbering starts at 1, not 0.
+VBI input drivers can return start values 0 if the hardware cannot
+reliable identify scanning lines, VBI acquisition may not require this
information.
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml
index dc14804f5436..f8903568a243 100644
--- a/Documentation/DocBook/media/v4l/dev-sdr.xml
+++ b/Documentation/DocBook/media/v4l/dev-sdr.xml
@@ -72,9 +72,12 @@ To use the format ioctls applications set the
V4L2_BUF_TYPE_SDR_CAPTURE and use the &v4l2-sdr-format;
sdr member of the fmt
union as needed per the desired operation.
-Currently only the pixelformat field of
-&v4l2-sdr-format; is used. The content of that field is the V4L2 fourcc code
-of the data format.
+Currently there is two fields, pixelformat and
+buffersize, of struct &v4l2-sdr-format; which are
+used. Content of the pixelformat is V4L2 FourCC
+code of the data format. The buffersize field is
+maximum buffer size in bytes required for data transfer, set by the driver in
+order to inform application.
@@ -91,9 +94,16 @@ little endian four character code.
V4L2 defines SDR formats in .
+
+ __u32
+ buffersize
+
+Maximum size in bytes required for data. Value is set by the driver.
+
+ __u8
- reserved[28]
+ reserved[24]This array is reserved for future extensions.
Drivers and applications must set it to zero.
diff --git a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
index 548f8ea28dee..7a8bf3011ee9 100644
--- a/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
+++ b/Documentation/DocBook/media/v4l/dev-sliced-vbi.xml
@@ -185,7 +185,14 @@ tables, sigh. -->
Drivers must set
service_lines[0][0] and
-service_lines[1][0] to zero.
+service_lines[1][0] to zero.
+The V4L2_VBI_ITU_525_F1_START,
+V4L2_VBI_ITU_525_F2_START,
+V4L2_VBI_ITU_625_F1_START and
+V4L2_VBI_ITU_625_F2_START defines give the start
+line numbers for each field for each 525 or 625 line format as a
+convenience. Don't forget that ITU line numbering starts at 1, not 0.
+
__u32
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index a086a5db7a18..e5e8325aa3d7 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -870,7 +870,8 @@ should set this to 0.
If the application sets this to 0 for an output stream, then
bytesused will be set to the size of the
plane (see the length field of this struct)
- by the driver.
+ by the driver. Note that the actual image data starts at
+ data_offset which may not be 0.
__u32
@@ -919,6 +920,10 @@ should set this to 0.
Offset in bytes to video data in the plane.
Drivers must set this field when type
refers to an input stream, applications when it refers to an output stream.
+ Note that data_offset is included in bytesused.
+ So the size of the image in the plane is
+ bytesused-data_offset at
+ offset data_offset from the start of the plane.
@@ -1066,7 +1071,7 @@ state, in the application domain so to say.
Drivers set or clear this flag when calling the
VIDIOC_DQBUF ioctl. It may be set by video
capture devices when the buffer contains a compressed image which is a
-key frame (or field), &ie; can be decompressed on its own. Also know as
+key frame (or field), &ie; can be decompressed on its own. Also known as
an I-frame. Applications can set this bit when type
refers to an output stream.
diff --git a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
index e1c4f8b4c0b3..2aae8e9452a4 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-packed-rgb.xml
@@ -15,9 +15,6 @@ typical PC graphics frame buffers. They occupy 8, 16, 24 or 32 bits
per pixel. These are all packed-pixel formats, meaning all the data
for a pixel lie next to each other in memory.
- When one of these formats is used, drivers shall report the
-colorspace V4L2_COLORSPACE_SRGB.
-
+
+ Bit 7 is the most significant bit.
+
+ The usage and value of the alpha bits (a) in the ARGB and ABGR formats
+ (collectively referred to as alpha formats) depend on the device type and
+ hardware operation. Capture devices
+ (including capture queues of mem-to-mem devices) fill the alpha component in
+ memory. When the device outputs an alpha channel the alpha component will
+ have a meaningful value. Otherwise, when the device doesn't output an alpha
+ channel but can set the alpha bit to a user-configurable value, the V4L2_CID_ALPHA_COMPONENT
+ control is used to specify that alpha value, and the alpha component
+ of all pixels will be set to the value specified by that control. Otherwise
+ a corresponding format without an alpha component (XRGB or XBGR) must be
+ used instead of an alpha format.
+
+ Output devices (including output queues
+ of mem-to-mem devices and video output overlay
+ devices) read the alpha component from memory. When the device processes the
+ alpha channel the alpha component must be filled with meaningful values by
+ applications. Otherwise a corresponding format without an alpha component
+ (XRGB or XBGR) must be used instead of an alpha format.
+
+ The XRGB and XBGR formats contain undefined bits (-). Applications,
+ devices and drivers must ignore those bits, for both capture and output
+ devices.
+
+
+ V4L2_PIX_FMT_BGR24 4 × 4 pixel
+image
+
+
+ Byte Order.
+ Each cell is one byte.
+
+
+
+
+
+ start + 0:
+ B00
+ G00
+ R00
+ B01
+ G01
+ R01
+ B02
+ G02
+ R02
+ B03
+ G03
+ R03
+
+
+ start + 12:
+ B10
+ G10
+ R10
+ B11
+ G11
+ R11
+ B12
+ G12
+ R12
+ B13
+ G13
+ R13
+
+
+ start + 24:
+ B20
+ G20
+ R20
+ B21
+ G21
+ R21
+ B22
+ G22
+ R22
+ B23
+ G23
+ R23
+
+
+ start + 36:
+ B30
+ G30
+ R30
+ B31
+ G31
+ R31
+ B32
+ G32
+ R32
+ B33
+ G33
+ R33
+
+
+
+
+
+
+
+
+ Formats defined in are
+ deprecated and must not be used by new drivers. They are documented here for
+ reference. The meaning of their alpha bits (a) is ill-defined and
+ interpreted as in either the corresponding ARGB or XRGB format, depending on
+ the driver.
+
+
- Bit 7 is the most significant bit. The value of the a = alpha
-bits is undefined when reading from the driver, ignored when writing
-to the driver, except when alpha blending has been negotiated for a
-Video Overlay or
-Video Output Overlay or when the alpha component has been configured
-for a Video Capture by means of V4L2_CID_ALPHA_COMPONENT
- control.
-
-
- V4L2_PIX_FMT_BGR24 4 × 4 pixel
-image
-
-
- Byte Order.
- Each cell is one byte.
-
-
-
-
-
- start + 0:
- B00
- G00
- R00
- B01
- G01
- R01
- B02
- G02
- R02
- B03
- G03
- R03
-
-
- start + 12:
- B10
- G10
- R10
- B11
- G11
- R11
- B12
- G12
- R12
- B13
- G13
- R13
-
-
- start + 24:
- B20
- G20
- R20
- B21
- G21
- R21
- B22
- G22
- R22
- B23
- G23
- R23
-
-
- start + 36:
- B30
- G30
- R30
- B31
- G31
- R31
- B32
- G32
- R32
- B33
- G33
- R33
-
-
-
-
-
-
-
-
A test utility to determine which RGB formats a driver
actually supports is available from the LinuxTV v4l-dvb repository.
See &v4l-dvb; for access instructions.
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml
new file mode 100644
index 000000000000..6118d8f7a20c
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-cs08.xml
@@ -0,0 +1,44 @@
+
+
+ V4L2_SDR_FMT_CS8 ('CS08')
+ &manvol;
+
+
+
+ V4L2_SDR_FMT_CS8
+
+ Complex signed 8-bit IQ sample
+
+
+ Description
+
+This format contains sequence of complex number samples. Each complex number
+consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
+represented as a 8 bit signed number. I value comes first and Q value after
+that.
+
+
+ V4L2_SDR_FMT_CS8 1 sample
+
+ Byte Order.
+ Each cell is one byte.
+
+
+
+
+
+ start + 0:
+ I'0
+
+
+ start + 1:
+ Q'0
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml
new file mode 100644
index 000000000000..e4b494ce1369
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-cs14le.xml
@@ -0,0 +1,47 @@
+
+
+ V4L2_SDR_FMT_CS14LE ('CS14')
+ &manvol;
+
+
+
+ V4L2_SDR_FMT_CS14LE
+
+ Complex signed 14-bit little endian IQ sample
+
+
+ Description
+
+This format contains sequence of complex number samples. Each complex number
+consist two parts, called In-phase and Quadrature (IQ). Both I and Q are
+represented as a 14 bit signed little endian number. I value comes first
+and Q value after that. 14 bit value is stored in 16 bit space with unused
+high bits padded with 0.
+
+
+ V4L2_SDR_FMT_CS14LE 1 sample
+
+ Byte Order.
+ Each cell is one byte.
+
+
+
+
+
+ start + 0:
+ I'0[7:0]
+ I'0[13:8]
+
+
+ start + 2:
+ Q'0[7:0]
+ Q'0[13:8]
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml b/Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml
new file mode 100644
index 000000000000..3df076b99f94
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/pixfmt-sdr-ru12le.xml
@@ -0,0 +1,40 @@
+
+
+ V4L2_SDR_FMT_RU12LE ('RU12')
+ &manvol;
+
+
+
+ V4L2_SDR_FMT_RU12LE
+
+ Real unsigned 12-bit little endian sample
+
+
+ Description
+
+This format contains sequence of real number samples. Each sample is
+represented as a 12 bit unsigned little endian number. Sample is stored
+in 16 bit space with unused high bits padded with 0.
+
+
+ V4L2_SDR_FMT_RU12LE 1 sample
+
+ Byte Order.
+ Each cell is one byte.
+
+
+
+
+
+ start + 0:
+ I'0[7:0]
+ I'0[11:8]
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
index 9ba4fb690bc0..96947f17fca1 100644
--- a/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt-srggb12.xml
@@ -18,7 +18,7 @@
DescriptionThe following four pixel formats are raw sRGB / Bayer formats with
-12 bits per colour. Each colour component is stored in a 16-bit word, with 6
+12 bits per colour. Each colour component is stored in a 16-bit word, with 4
unused high bits filled with zeros. Each n-pixel row contains n/2 green samples
and n/2 blue or red samples, with alternating red and blue rows. Bytes are
stored in memory in little endian order. They are conventionally described
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index 91dcbc84f3f8..df5b23d46552 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -112,9 +112,34 @@ see .
__u32priv
- Reserved for custom (driver defined) additional
-information about formats. When not used drivers and applications must
-set this field to zero.
+ This field indicates whether the remaining fields of the
+v4l2_pix_format structure, also called the extended
+fields, are valid. When set to V4L2_PIX_FMT_PRIV_MAGIC, it
+indicates that the extended fields have been correctly initialized. When set to
+any other value it indicates that the extended fields contain undefined values.
+
+Applications that wish to use the pixel format extended fields must first
+ensure that the feature is supported by querying the device for the
+V4L2_CAP_EXT_PIX_FORMAT
+capability. If the capability isn't set the pixel format extended fields are not
+supported and using the extended fields will lead to undefined results.
+To use the extended fields, applications must set the
+priv field to
+V4L2_PIX_FMT_PRIV_MAGIC, initialize all the extended fields
+and zero the unused bytes of the v4l2_format
+raw_data field.
+When the priv field isn't set to
+V4L2_PIX_FMT_PRIV_MAGIC drivers must act as if all the
+extended fields were set to zero. On return drivers must set the
+priv field to
+V4L2_PIX_FMT_PRIV_MAGIC and all the extended fields to
+applicable values.
+
+
+ __u32
+ flags
+ Flags set by the application or driver, see .
@@ -201,9 +226,15 @@ codes can be used.
and the number of valid entries in the
plane_fmt array.
+
+ __u8
+ flags
+ Flags set by the application or driver, see .
+ __u8
- reserved[11]
+ reserved[10]Reserved for future extensions. Should be zeroed by the
application.
@@ -248,7 +279,7 @@ has just as many pad bytes after it as the other rows.In V4L2 each format has an identifier which looks like
PIX_FMT_XXX, defined in the videodev.h header file. These identifiers
+linkend="videodev">videodev2.h header file. These identifiers
represent four character (FourCC) codes
which are also listed below, however they are not the same as those
used in the Windows world.
@@ -828,6 +859,9 @@ interface only.
&sub-sdr-cu08;
&sub-sdr-cu16le;
+ &sub-sdr-cs08;
+ &sub-sdr-cs14le;
+ &sub-sdr-ru12le;
@@ -1060,4 +1094,21 @@ concatenated to form the JPEG stream.
+
+
+ Format Flags
+
+ &cs-def;
+
+
+ V4L2_PIX_FMT_FLAG_PREMUL_ALPHA
+ 0x00000001
+ The color values are premultiplied by the alpha channel
+value. For example, if a light blue pixel with 50% transparency was described by
+RGBA values (128, 192, 255, 128), the same pixel described with premultiplied
+colors would be described by RGBA values (64, 96, 128, 128)
+
+
+
+
diff --git a/Documentation/DocBook/media/v4l/selection-api.xml b/Documentation/DocBook/media/v4l/selection-api.xml
index 4c238ce068b0..28cbded766c9 100644
--- a/Documentation/DocBook/media/v4l/selection-api.xml
+++ b/Documentation/DocBook/media/v4l/selection-api.xml
@@ -86,47 +86,47 @@ selection targets available for a video capture device. It is recommended to
configure the cropping targets before to the composing targets.
The range of coordinates of the top left corner, width and height of
-areas that can be sampled is given by the V4L2_SEL_TGT_CROP_BOUNDS
- target. It is recommended for the driver developers to put the
-top/left corner at position (0,0) . The rectangle's
+areas that can be sampled is given by the V4L2_SEL_TGT_CROP_BOUNDS
+target. It is recommended for the driver developers to put the
+top/left corner at position (0,0). The rectangle's
coordinates are expressed in pixels.The top left corner, width and height of the source rectangle, that is
-the area actually sampled, is given by the V4L2_SEL_TGT_CROP
- target. It uses the same coordinate system as
-V4L2_SEL_TGT_CROP_BOUNDS . The active cropping area must lie
-completely inside the capture boundaries. The driver may further adjust the
-requested size and/or position according to hardware limitations.
+the area actually sampled, is given by the V4L2_SEL_TGT_CROP
+target. It uses the same coordinate system as V4L2_SEL_TGT_CROP_BOUNDS.
+The active cropping area must lie completely inside the capture boundaries. The
+driver may further adjust the requested size and/or position according to hardware
+limitations.
Each capture device has a default source rectangle, given by the
- V4L2_SEL_TGT_CROP_DEFAULT target. This rectangle shall
+V4L2_SEL_TGT_CROP_DEFAULT target. This rectangle shall
over what the driver writer considers the complete picture. Drivers shall set
the active crop rectangle to the default when the driver is first loaded, but
not later.The composing targets refer to a memory buffer. The limits of composing
-coordinates are obtained using V4L2_SEL_TGT_COMPOSE_BOUNDS
-. All coordinates are expressed in pixels. The rectangle's top/left
-corner must be located at position (0,0) . The width and
-height are equal to the image size set by VIDIOC_S_FMT .
+coordinates are obtained using V4L2_SEL_TGT_COMPOSE_BOUNDS.
+All coordinates are expressed in pixels. The rectangle's top/left
+corner must be located at position (0,0). The width and
+height are equal to the image size set by VIDIOC_S_FMT.
The part of a buffer into which the image is inserted by the hardware is
-controlled by the V4L2_SEL_TGT_COMPOSE target.
+controlled by the V4L2_SEL_TGT_COMPOSE target.
The rectangle's coordinates are also expressed in the same coordinate system as
the bounds rectangle. The composing rectangle must lie completely inside bounds
rectangle. The driver must adjust the composing rectangle to fit to the
bounding limits. Moreover, the driver can perform other adjustments according
to hardware limitations. The application can control rounding behaviour using
- constraint flags .
+ constraint flags.
For capture devices the default composing rectangle is queried using
- V4L2_SEL_TGT_COMPOSE_DEFAULT . It is usually equal to the
+V4L2_SEL_TGT_COMPOSE_DEFAULT. It is usually equal to the
bounding rectangle.The part of a buffer that is modified by the hardware is given by
- V4L2_SEL_TGT_COMPOSE_PADDED . It contains all pixels
-defined using V4L2_SEL_TGT_COMPOSE plus all
+V4L2_SEL_TGT_COMPOSE_PADDED. It contains all pixels
+defined using V4L2_SEL_TGT_COMPOSE plus all
padding data modified by hardware during insertion process. All pixels outside
this rectangle must not be changed by the hardware. The
content of pixels that lie inside the padded area but outside active area is
@@ -140,52 +140,51 @@ where the rubbish pixels are located and remove them if needed.Configuration of video outputFor output devices targets and ioctls are used similarly to the video
-capture case. The composing rectangle refers to the
+capture case. The composing rectangle refers to the
insertion of an image into a video signal. The cropping rectangles refer to a
memory buffer. It is recommended to configure the composing targets before to
the cropping targets.The cropping targets refer to the memory buffer that contains an image to
be inserted into a video signal or graphical screen. The limits of cropping
-coordinates are obtained using V4L2_SEL_TGT_CROP_BOUNDS .
+coordinates are obtained using V4L2_SEL_TGT_CROP_BOUNDS.
All coordinates are expressed in pixels. The top/left corner is always point
- (0,0) . The width and height is equal to the image size
-specified using VIDIOC_S_FMT ioctl.
+(0,0). The width and height is equal to the image size
+specified using VIDIOC_S_FMT ioctl.
The top left corner, width and height of the source rectangle, that is
the area from which image date are processed by the hardware, is given by the
- V4L2_SEL_TGT_CROP . Its coordinates are expressed
+V4L2_SEL_TGT_CROP. Its coordinates are expressed
in in the same coordinate system as the bounds rectangle. The active cropping
area must lie completely inside the crop boundaries and the driver may further
adjust the requested size and/or position according to hardware
limitations.For output devices the default cropping rectangle is queried using
- V4L2_SEL_TGT_CROP_DEFAULT . It is usually equal to the
+V4L2_SEL_TGT_CROP_DEFAULT. It is usually equal to the
bounding rectangle.The part of a video signal or graphics display where the image is
-inserted by the hardware is controlled by
-V4L2_SEL_TGT_COMPOSE target. The rectangle's coordinates
-are expressed in pixels. The composing rectangle must lie completely inside the
-bounds rectangle. The driver must adjust the area to fit to the bounding
-limits. Moreover, the driver can perform other adjustments according to
-hardware limitations.
+inserted by the hardware is controlled by V4L2_SEL_TGT_COMPOSE
+target. The rectangle's coordinates are expressed in pixels. The composing
+rectangle must lie completely inside the bounds rectangle. The driver must
+adjust the area to fit to the bounding limits. Moreover, the driver can
+perform other adjustments according to hardware limitations.
-The device has a default composing rectangle, given by the
-V4L2_SEL_TGT_COMPOSE_DEFAULT target. This rectangle shall cover what
+The device has a default composing rectangle, given by the
+V4L2_SEL_TGT_COMPOSE_DEFAULT target. This rectangle shall cover what
the driver writer considers the complete picture. It is recommended for the
-driver developers to put the top/left corner at position (0,0)
-. Drivers shall set the active composing rectangle to the default
+driver developers to put the top/left corner at position (0,0).
+Drivers shall set the active composing rectangle to the default
one when the driver is first loaded.The devices may introduce additional content to video signal other than
an image from memory buffers. It includes borders around an image. However,
such a padded area is driver-dependent feature not covered by this document.
Driver developers are encouraged to keep padded rectangle equal to active one.
-The padded target is accessed by the V4L2_SEL_TGT_COMPOSE_PADDED
- identifier. It must contain all pixels from the
-V4L2_SEL_TGT_COMPOSE target.
+The padded target is accessed by the V4L2_SEL_TGT_COMPOSE_PADDED
+identifier. It must contain all pixels from the V4L2_SEL_TGT_COMPOSE
+target.
@@ -194,8 +193,8 @@ V4L2_SEL_TGT_COMPOSE target.
Scaling controlAn application can detect if scaling is performed by comparing the width
-and the height of rectangles obtained using V4L2_SEL_TGT_CROP
- and V4L2_SEL_TGT_COMPOSE targets. If
+and the height of rectangles obtained using V4L2_SEL_TGT_CROP
+and V4L2_SEL_TGT_COMPOSE targets. If
these are not equal then the scaling is applied. The application can compute
the scaling ratios using these values.
@@ -208,7 +207,7 @@ the scaling ratios using these values.
Comparison with old cropping APIThe selection API was introduced to cope with deficiencies of previous
- API , that was designed to control simple capture
+ API, that was designed to control simple capture
devices. Later the cropping API was adopted by video output drivers. The ioctls
are used to select a part of the display were the video signal is inserted. It
should be considered as an API abuse because the described operation is
@@ -220,7 +219,7 @@ part of an image by abusing V4L2 API. Cropping a smaller image from a larger
one is achieved by setting the field
&v4l2-pix-format;::bytesperline. Introducing an image offsets
could be done by modifying field &v4l2-buffer;::m_userptr
-before calling VIDIOC_QBUF . Those
+before calling VIDIOC_QBUF. Those
operations should be avoided because they are not portable (endianness), and do
not work for macroblock and Bayer formats and mmap buffers. The selection API
deals with configuration of buffer cropping/composing in a clear, intuitive and
@@ -229,7 +228,7 @@ and constraints flags are introduced. Finally, &v4l2-crop; and &v4l2-cropcap;
have no reserved fields. Therefore there is no way to extend their functionality.
The new &v4l2-selection; provides a lot of place for future
extensions. Driver developers are encouraged to implement only selection API.
-The former cropping API would be simulated using the new one.
+The former cropping API would be simulated using the new one.
@@ -238,9 +237,9 @@ The former cropping API would be simulated using the new one.
Resetting the cropping parameters
- (A video capture device is assumed; change
-V4L2_BUF_TYPE_VIDEO_CAPTURE for other devices; change target to
- V4L2_SEL_TGT_COMPOSE_* family to configure composing
+ (A video capture device is assumed; change
+V4L2_BUF_TYPE_VIDEO_CAPTURE for other devices; change target to
+V4L2_SEL_TGT_COMPOSE_* family to configure composing
area)
@@ -292,8 +291,8 @@ area)Querying for scaling factors
- A video output device is assumed; change
-V4L2_BUF_TYPE_VIDEO_OUTPUT for other devices
+ A video output device is assumed; change
+V4L2_BUF_TYPE_VIDEO_OUTPUT for other devices
&v4l2-selection; compose = {
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index b445161b912c..f2f81f06a17b 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -151,6 +151,14 @@ structs, ioctls) must be noted in more detail in the history chapter
(compat.xml), along with the possible impact on existing drivers and
applications. -->
+
+ 3.16
+ 2014-05-27
+ lp
+ Extended &v4l2-pix-format;. Added format flags.
+
+
+
3.152014-02-03
diff --git a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
index 820f86e8744b..cb7732582f03 100644
--- a/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-dqevent.xml
@@ -92,6 +92,18 @@
frame_syncEvent data for event V4L2_EVENT_FRAME_SYNC.
+
+
+ &v4l2-event-motion-det;
+ motion_det
+ Event data for event V4L2_EVENT_MOTION_DET.
+
+
+
+ &v4l2-event-src-change;
+ src_change
+ Event data for event V4L2_EVENT_SOURCE_CHANGE.
+ __u8
@@ -258,6 +270,44 @@
+
+ struct v4l2_event_motion_det
+
+ &cs-str;
+
+
+ __u32
+ flags
+
+ Currently only one flag is available: if V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ
+ is set, then the frame_sequence field is valid,
+ otherwise that field should be ignored.
+
+
+
+ __u32
+ frame_sequence
+
+ The sequence number of the frame being received. Only valid if the
+ V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ flag was set.
+
+
+
+ __u32
+ region_mask
+
+ The bitmask of the regions that reported motion. There is at least one
+ region. If this field is 0, then no motion was detected at all.
+ If there is no V4L2_CID_DETECT_MD_REGION_GRID control
+ (see ) to assign a different region
+ to each cell in the motion detection grid, then that all cells
+ are automatically assigned to the default region 0.
+
+
+
+
+
+
Changes
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
index e9f6735c0823..c5bdbfcc42b3 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-ext-ctrls.xml
@@ -72,23 +72,30 @@ initialize the id,
size and reserved2 fields
of each &v4l2-ext-control; and call the
VIDIOC_G_EXT_CTRLS ioctl. String controls controls
-must also set the string field.
+must also set the string field. Controls
+of compound types (V4L2_CTRL_FLAG_HAS_PAYLOAD is set)
+must set the ptr field.
If the size is too small to
receive the control result (only relevant for pointer-type controls
like strings), then the driver will set size
to a valid value and return an &ENOSPC;. You should re-allocate the
-string memory to this new size and try again. It is possible that the
-same issue occurs again if the string has grown in the meantime. It is
+memory to this new size and try again. For the string type it is possible that
+the same issue occurs again if the string has grown in the meantime. It is
recommended to call &VIDIOC-QUERYCTRL; first and use
maximum+1 as the new size
value. It is guaranteed that that is sufficient memory.
+ N-dimensional arrays are set and retrieved row-by-row. You cannot set a partial
+array, all elements have to be set or retrieved. The total size is calculated
+as elems * elem_size.
+These values can be obtained by calling &VIDIOC-QUERY-EXT-CTRL;.
+
To change the value of a set of controls applications
initialize the id, size,
reserved2 and
-value/string fields of each &v4l2-ext-control; and
+value/value64/string/ptr fields of each &v4l2-ext-control; and
call the VIDIOC_S_EXT_CTRLS ioctl. The controls
will only be set if all control values are
valid.
@@ -96,7 +103,7 @@ valid.
To check if a set of controls have correct values applications
initialize the id, size,
reserved2 and
-value/string fields of each &v4l2-ext-control; and
+value/value64/string/ptr fields of each &v4l2-ext-control; and
call the VIDIOC_TRY_EXT_CTRLS ioctl. It is up to
the driver whether wrong values are automatically adjusted to a valid
value or if an error is returned.
@@ -158,19 +165,47 @@ applications must set the array to zero.
__s32value
- New value or current value.
+ New value or current value. Valid if this control is not of
+type V4L2_CTRL_TYPE_INTEGER64 and
+V4L2_CTRL_FLAG_HAS_PAYLOAD is not set.__s64value64
- New value or current value.
+ New value or current value. Valid if this control is of
+type V4L2_CTRL_TYPE_INTEGER64 and
+V4L2_CTRL_FLAG_HAS_PAYLOAD is not set.char *string
- A pointer to a string.
+ A pointer to a string. Valid if this control is of
+type V4L2_CTRL_TYPE_STRING.
+
+
+
+ __u8 *
+ p_u8
+ A pointer to a matrix control of unsigned 8-bit values.
+Valid if this control is of type V4L2_CTRL_TYPE_U8.
+
+
+
+ __u16 *
+ p_u16
+ A pointer to a matrix control of unsigned 16-bit values.
+Valid if this control is of type V4L2_CTRL_TYPE_U16.
+
+
+
+ void *
+ ptr
+ A pointer to a compound type which can be an N-dimensional array and/or a
+compound type (the control's type is >= V4L2_CTRL_COMPOUND_TYPES).
+Valid if V4L2_CTRL_FLAG_HAS_PAYLOAD is set for this control.
+
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
index 7c63815e7afd..20460730b02c 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-fbuf.xml
@@ -152,13 +152,10 @@ a valid base address, so applications can find the corresponding Linux
framebuffer device (see ).
- &v4l2-pix-format;
+ structfmt
- Layout of the frame buffer. The
-v4l2_pix_format structure is defined in , for clarification the fields and acceptable values
- are listed below:
+ Layout of the frame buffer.
@@ -276,9 +273,8 @@ see .
__u32priv
- Reserved for additional information about custom
-(driver defined) formats. When not used drivers and applications must
-set this field to zero.
+ Reserved. Drivers and applications must set this field to
+zero.
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
index b11ec75e21a1..9c04ac8661b1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-selection.xml
@@ -58,17 +58,16 @@
The ioctls are used to query and configure selection rectangles.
- To query the cropping (composing) rectangle set &v4l2-selection;
+To query the cropping (composing) rectangle set &v4l2-selection;
type field to the respective buffer type.
-Do not use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE
- instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
-. Use V4L2_BUF_TYPE_VIDEO_OUTPUT instead of
- V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE . The next step is
+Do not use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE
+instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE. Use
+V4L2_BUF_TYPE_VIDEO_OUTPUT instead of
+V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE. The next step is
setting the value of &v4l2-selection; target field
-to V4L2_SEL_TGT_CROP (
-V4L2_SEL_TGT_COMPOSE ). Please refer to table or for additional
-targets. The flags and reserved
+to V4L2_SEL_TGT_CROP (V4L2_SEL_TGT_COMPOSE).
+Please refer to table or
+for additional targets. The flags and reserved
fields of &v4l2-selection; are ignored and they must be filled
with zeros. The driver fills the rest of the structure or
returns &EINVAL; if incorrect buffer type or target was used. If cropping
@@ -77,19 +76,18 @@ always equal to the bounds rectangle. Finally, the &v4l2-rect;
r rectangle is filled with the current cropping
(composing) coordinates. The coordinates are expressed in driver-dependent
units. The only exception are rectangles for images in raw formats, whose
-coordinates are always expressed in pixels.
+coordinates are always expressed in pixels.
- To change the cropping (composing) rectangle set the &v4l2-selection;
+To change the cropping (composing) rectangle set the &v4l2-selection;
type field to the respective buffer type. Do not
-use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE
- instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
-. Use V4L2_BUF_TYPE_VIDEO_OUTPUT instead of
- V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE . The next step is
+use multiplanar buffers. Use V4L2_BUF_TYPE_VIDEO_CAPTURE
+instead of V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE. Use
+V4L2_BUF_TYPE_VIDEO_OUTPUT instead of
+V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE. The next step is
setting the value of &v4l2-selection; target to
-V4L2_SEL_TGT_CROP (
-V4L2_SEL_TGT_COMPOSE ). Please refer to table or for additional
-targets. The &v4l2-rect; r rectangle need to be
+V4L2_SEL_TGT_CROP (V4L2_SEL_TGT_COMPOSE).
+Please refer to table or
+for additional targets. The &v4l2-rect; r rectangle need to be
set to the desired active area. Field &v4l2-selection; reserved
is ignored and must be filled with zeros. The driver may adjust
coordinates of the requested rectangle. An application may
@@ -149,8 +147,8 @@ On success the &v4l2-rect; r field contains
the adjusted rectangle. When the parameters are unsuitable the application may
modify the cropping (composing) or image parameters and repeat the cycle until
satisfactory parameters have been negotiated. If constraints flags have to be
-violated at then ERANGE is returned. The error indicates that there
-exist no rectangle that satisfies the constraints.
+violated at then ERANGE is returned. The error indicates that there
+exist no rectangle that satisfies the constraints.Selection targets and flags are documented in .
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
index 370d49d6fb64..d0c5e604f014 100644
--- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
@@ -300,6 +300,12 @@ modulator programming see
0x00100000The device supports the
SDR Capture interface.
+
+
+ V4L2_CAP_EXT_PIX_FORMAT
+ 0x00200000
+ The device supports the &v4l2-pix-format; extended
+fields.V4L2_CAP_READWRITE
diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
index e6645b996558..2bd98fd7a4e5 100644
--- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml
@@ -1,11 +1,12 @@
- ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU
+ ioctl VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU
&manvol;
VIDIOC_QUERYCTRL
+ VIDIOC_QUERY_EXT_CTRLVIDIOC_QUERYMENUEnumerate controls and menu control items
@@ -19,6 +20,14 @@
struct v4l2_queryctrl *argp
+
+
+ int ioctl
+ int fd
+ int request
+ struct v4l2_query_ext_ctrl *argp
+
+ int ioctl
@@ -42,7 +51,7 @@
request
- VIDIOC_QUERYCTRL, VIDIOC_QUERYMENU
+ VIDIOC_QUERYCTRL, VIDIOC_QUERY_EXT_CTRL, VIDIOC_QUERYMENU
@@ -67,7 +76,7 @@ structure. The driver fills the rest of the structure or returns an
VIDIOC_QUERYCTRL with successive
id values starting from
V4L2_CID_BASE up to and exclusive
-V4L2_CID_BASE_LASTP1. Drivers may return
+V4L2_CID_LASTP1. Drivers may return
EINVAL if a control in this range is not
supported. Further applications can enumerate private controls, which
are not defined in this specification, by starting at
@@ -89,9 +98,23 @@ prematurely end the enumeration).
When the application ORs id with
V4L2_CTRL_FLAG_NEXT_CTRL the driver returns the
-next supported control, or EINVAL if there is
-none. Drivers which do not support this flag yet always return
-EINVAL.
+next supported non-compound control, or EINVAL
+if there is none. In addition, the V4L2_CTRL_FLAG_NEXT_COMPOUND
+flag can be specified to enumerate all compound controls (i.e. controls
+with type ≥ V4L2_CTRL_COMPOUND_TYPES). Specify both
+V4L2_CTRL_FLAG_NEXT_CTRL and
+V4L2_CTRL_FLAG_NEXT_COMPOUND in order to enumerate
+all controls, compound or not. Drivers which do not support these flags yet
+always return EINVAL.
+
+ The VIDIOC_QUERY_EXT_CTRL ioctl was
+introduced in order to better support controls that can use compound
+types, and to expose additional control information that cannot be
+returned in &v4l2-queryctrl; since that structure is full.
+
+ VIDIOC_QUERY_EXT_CTRL is used in the
+same way as VIDIOC_QUERYCTRL, except that the
+reserved array must be zeroed as well.Additional information is required for menu controls: the
names of the menu items. To query them applications set the
@@ -142,38 +165,23 @@ string. This information is intended for the user.
__s32minimumMinimum value, inclusive. This field gives a lower
-bound for V4L2_CTRL_TYPE_INTEGER controls and the
-lowest valid index for V4L2_CTRL_TYPE_MENU controls.
-For V4L2_CTRL_TYPE_STRING controls the minimum value
-gives the minimum length of the string. This length does not include the terminating
-zero. It may not be valid for any other type of control, including
-V4L2_CTRL_TYPE_INTEGER64 controls. Note that this is a
-signed value.
+bound for the control. See &v4l2-ctrl-type; how the minimum value is to
+be used for each possible control type. Note that this a signed 32-bit value.
__s32maximumMaximum value, inclusive. This field gives an upper
-bound for V4L2_CTRL_TYPE_INTEGER controls and the
-highest valid index for V4L2_CTRL_TYPE_MENU
-controls. For V4L2_CTRL_TYPE_BITMASK controls it is the
-set of usable bits.
-For V4L2_CTRL_TYPE_STRING controls the maximum value
-gives the maximum length of the string. This length does not include the terminating
-zero. It may not be valid for any other type of control, including
-V4L2_CTRL_TYPE_INTEGER64 controls. Note that this is a
-signed value.
+bound for the control. See &v4l2-ctrl-type; how the maximum value is to
+be used for each possible control type. Note that this a signed 32-bit value.
__s32step
- This field gives a step size for
-V4L2_CTRL_TYPE_INTEGER controls. For
-V4L2_CTRL_TYPE_STRING controls this field refers to
-the string length that has to be a multiple of this step size.
-It may not be valid for any other type of control, including
-V4L2_CTRL_TYPE_INTEGER64
-controls.Generally drivers should not scale hardware
+ This field gives a step size for the control.
+See &v4l2-ctrl-type; how the step value is to be used for each possible
+control type. Note that this an unsigned 32-bit value.
+Generally drivers should not scale hardware
control values. It may be necessary for example when the
name or id imply
a particular unit and the hardware actually accepts only multiples of
@@ -192,10 +200,11 @@ be always positive.default_valueThe default value of a
V4L2_CTRL_TYPE_INTEGER,
-_BOOLEAN or _MENU control.
-Not valid for other types of controls. Drivers reset controls only
-when the driver is loaded, not later, in particular not when the
-func-open; is called.
+_BOOLEAN, _BITMASK,
+_MENU or _INTEGER_MENU control.
+Not valid for other types of controls.
+Note that drivers reset controls to their default value only when the
+driver is first loaded, never afterwards.__u32
@@ -213,6 +222,126 @@ the array to zero.
+
+ struct v4l2_query_ext_ctrl
+
+ &cs-str;
+
+
+ __u32
+ id
+ Identifies the control, set by the application. See
+ for predefined IDs. When the ID is ORed
+with V4L2_CTRL_FLAG_NEXT_CTRL the driver clears the
+flag and returns the first non-compound control with a higher ID. When the
+ID is ORed with V4L2_CTRL_FLAG_NEXT_COMPOUND the driver
+clears the flag and returns the first compound control with a higher ID.
+Set both to get the first control (compound or not) with a higher ID.
+
+
+ __u32
+ type
+ Type of control, see .
+
+
+ char
+ name[32]
+ Name of the control, a NUL-terminated ASCII
+string. This information is intended for the user.
+
+
+ __s64
+ minimum
+ Minimum value, inclusive. This field gives a lower
+bound for the control. See &v4l2-ctrl-type; how the minimum value is to
+be used for each possible control type. Note that this a signed 64-bit value.
+
+
+ __s64
+ maximum
+ Maximum value, inclusive. This field gives an upper
+bound for the control. See &v4l2-ctrl-type; how the maximum value is to
+be used for each possible control type. Note that this a signed 64-bit value.
+
+
+ __u64
+ step
+ This field gives a step size for the control.
+See &v4l2-ctrl-type; how the step value is to be used for each possible
+control type. Note that this an unsigned 64-bit value.
+Generally drivers should not scale hardware
+control values. It may be necessary for example when the
+name or id imply
+a particular unit and the hardware actually accepts only multiples of
+said unit. If so, drivers must take care values are properly rounded
+when scaling, such that errors will not accumulate on repeated
+read-write cycles.This field gives the smallest change of
+an integer control actually affecting hardware. Often the information
+is needed when the user can change controls by keyboard or GUI
+buttons, rather than a slider. When for example a hardware register
+accepts values 0-511 and the driver reports 0-65535, step should be
+128.
+
+
+ __s64
+ default_value
+ The default value of a
+V4L2_CTRL_TYPE_INTEGER, _INTEGER64,
+_BOOLEAN, _BITMASK,
+_MENU, _INTEGER_MENU,
+_U8 or _U16 control.
+Not valid for other types of controls.
+Note that drivers reset controls to their default value only when the
+driver is first loaded, never afterwards.
+
+
+
+ __u32
+ flags
+ Control flags, see .
+
+
+ __u32
+ elem_size
+ The size in bytes of a single element of the array.
+Given a char pointer p to a 3-dimensional array you can find the
+position of cell (z, y, x) as follows:
+p + ((z * dims[1] + y) * dims[0] + x) * elem_size. elem_size
+is always valid, also when the control isn't an array. For string controls
+elem_size is equal to maximum + 1.
+
+
+
+ __u32
+ elems
+ The number of elements in the N-dimensional array. If this control
+is not an array, then elems is 1. The elems
+field can never be 0.
+
+
+ __u32
+ nr_of_dims
+ The number of dimension in the N-dimensional array. If this control
+is not an array, then this field is 0.
+
+
+ __u32
+ dims[V4L2_CTRL_MAX_DIMS]
+ The size of each dimension. The first nr_of_dims
+elements of this array must be non-zero, all remaining elements must be zero.
+
+
+ __u32
+ reserved[32]
+ Reserved for future extensions. Applications and drivers
+must set the array to zero.
+
+
+
+
+
struct v4l2_querymenu
@@ -347,11 +476,14 @@ Drivers must ignore the value passed with
V4L2_CTRL_TYPE_INTEGER64
- n/a
- n/a
- n/a
+ any
+ any
+ anyA 64-bit integer valued control. Minimum, maximum
-and step size cannot be queried.
+and step size cannot be queried using VIDIOC_QUERYCTRL.
+Only VIDIOC_QUERY_EXT_CTRL can retrieve the 64-bit
+min/max/step values, they should be interpreted as n/a when using
+VIDIOC_QUERYCTRL.
V4L2_CTRL_TYPE_STRING
@@ -379,6 +511,26 @@ ioctl returns the name of the control class and this control type.
Older drivers which do not support this feature return an
&EINVAL;.
+
+ V4L2_CTRL_TYPE_U8
+ any
+ any
+ any
+ An unsigned 8-bit valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware.
+
+
+
+ V4L2_CTRL_TYPE_U16
+ any
+ any
+ any
+ An unsigned 16-bit valued control ranging from minimum to
+maximum inclusive. The step value indicates the increment between
+values which are actually different on the hardware.
+
+
@@ -450,6 +602,14 @@ is in auto-gain mode. In such a case the hardware calculates the gain value base
the lighting conditions which can change over time. Note that setting a new value for
a volatile control will have no effect. The new value will just be ignored.
+
+ V4L2_CTRL_FLAG_HAS_PAYLOAD
+ 0x0100
+ This control has a pointer type, so its value has to be accessed
+using one of the pointer fields of &v4l2-ext-control;. This flag is set for controls
+that are an array, string, or have a compound type. In all cases you have to set a
+pointer to memory containing the payload of the control.
+
diff --git a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
index 17efa870d4d2..9f6095608837 100644
--- a/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-subscribe-event.xml
@@ -174,6 +174,14 @@
will have the ORed value of all the events generated.
+
+ V4L2_EVENT_MOTION_DET
+ 5
+
+ 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.
+
+ V4L2_EVENT_PRIVATE_START0x08000000
diff --git a/Documentation/devicetree/bindings/media/atmel-isi.txt b/Documentation/devicetree/bindings/media/atmel-isi.txt
new file mode 100644
index 000000000000..17e71b7b44c6
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/atmel-isi.txt
@@ -0,0 +1,51 @@
+Atmel Image Sensor Interface (ISI) SoC Camera Subsystem
+----------------------------------------------
+
+Required properties:
+- compatible: must be "atmel,at91sam9g45-isi"
+- reg: physical base address and length of the registers set for the device;
+- interrupts: should contain IRQ line for the ISI;
+- clocks: list of clock specifiers, corresponding to entries in
+ the clock-names property;
+- clock-names: must contain "isi_clk", which is the isi peripherial clock.
+
+ISI supports a single port node with parallel bus. It should contain one
+'port' child node with child 'endpoint' node. Please refer to the bindings
+defined in Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+ isi: isi@f0034000 {
+ compatible = "atmel,at91sam9g45-isi";
+ reg = <0xf0034000 0x4000>;
+ interrupts = <37 IRQ_TYPE_LEVEL_HIGH 5>;
+
+ clocks = <&isi_clk>;
+ clock-names = "isi_clk";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_isi>;
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ isi_0: endpoint {
+ remote-endpoint = <&ov2640_0>;
+ bus-width = <8>;
+ };
+ };
+ };
+
+ i2c1: i2c@f0018000 {
+ ov2640: camera@0x30 {
+ compatible = "omnivision,ov2640";
+ reg = <0x30>;
+
+ port {
+ ov2640_0: endpoint {
+ remote-endpoint = <&isi_0>;
+ bus-width = <8>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
index 937b755baf8f..bf52ed4a5067 100644
--- a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
+++ b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
@@ -3,9 +3,13 @@ Samsung S5P/EXYNOS SoC series JPEG codec
Required properties:
- compatible : should be one of:
- "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg";
+ "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg",
+ "samsung,exynos3250-jpeg";
- reg : address and length of the JPEG codec IP register set;
- interrupts : specifies the JPEG codec IP interrupt;
-- clocks : should contain the JPEG codec IP gate clock specifier, from the
- common clock bindings;
-- clock-names : should contain "jpeg" entry.
+- clock-names : should contain:
+ - "jpeg" for the core gate clock,
+ - "sclk" for the special clock (optional).
+- clocks : should contain the clock specifier and clock ID list
+ matching entries in the clock-names property; from
+ the common clock bindings.
diff --git a/Documentation/devicetree/bindings/media/i2c/mt9m111.txt b/Documentation/devicetree/bindings/media/i2c/mt9m111.txt
new file mode 100644
index 000000000000..ed5a334b1e57
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/mt9m111.txt
@@ -0,0 +1,28 @@
+Micron 1.3Mp CMOS Digital Image Sensor
+
+The Micron MT9M111 is a CMOS active pixel digital image sensor with an active
+array size of 1280H x 1024V. It is programmable through a simple two-wire serial
+interface.
+
+Required Properties:
+- compatible: value should be "micron,mt9m111"
+
+For further reading on port node refer to
+Documentation/devicetree/bindings/media/video-interfaces.txt.
+
+Example:
+
+ i2c_master {
+ mt9m111@5d {
+ compatible = "micron,mt9m111";
+ reg = <0x5d>;
+
+ remote = <&pxa_camera>;
+ port {
+ mt9m111_1: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&pxa_camera>;
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/pxa-camera.txt b/Documentation/devicetree/bindings/media/pxa-camera.txt
new file mode 100644
index 000000000000..11f5b5d51af8
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/pxa-camera.txt
@@ -0,0 +1,43 @@
+Marvell PXA camera host interface
+
+Required properties:
+ - compatible: Should be "marvell,pxa270-qci"
+ - reg: register base and size
+ - interrupts: the interrupt number
+ - any required generic properties defined in video-interfaces.txt
+
+Optional properties:
+ - clocks: input clock (see clock-bindings.txt)
+ - clock-output-names: should contain the name of the clock driving the
+ sensor master clock MCLK
+ - clock-frequency: host interface is driving MCLK, and MCLK rate is this rate
+
+Example:
+
+ pxa_camera: pxa_camera@50000000 {
+ compatible = "marvell,pxa270-qci";
+ reg = <0x50000000 0x1000>;
+ interrupts = <33>;
+
+ clocks = <&pxa2xx_clks 24>;
+ clock-names = "ciclk";
+ clock-frequency = <50000000>;
+ clock-output-names = "qci_mclk";
+
+ status = "okay";
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Parallel bus endpoint */
+ qci: endpoint@0 {
+ reg = <0>; /* Local endpoint # */
+ remote-endpoint = <&mt9m111_1>;
+ bus-width = <8>; /* Used data lines */
+ hsync-active = <0>; /* Active low */
+ vsync-active = <0>; /* Active low */
+ pclk-sample = <1>; /* Rising */
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt
new file mode 100644
index 000000000000..ba61782c2af9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/rcar_vin.txt
@@ -0,0 +1,86 @@
+Renesas RCar Video Input driver (rcar_vin)
+------------------------------------------
+
+The rcar_vin device provides video input capabilities for the Renesas R-Car
+family of devices. The current blocks are always slaves and suppot one input
+channel which can be either RGB, YUYV or BT656.
+
+ - compatible: Must be one of the following
+ - "renesas,vin-r8a7791" for the R8A7791 device
+ - "renesas,vin-r8a7790" for the R8A7790 device
+ - "renesas,vin-r8a7779" for the R8A7779 device
+ - "renesas,vin-r8a7778" for the R8A7778 device
+ - reg: the register base and size for the device registers
+ - interrupts: the interrupt for the device
+ - clocks: Reference to the parent clock
+
+Additionally, an alias named vinX will need to be created to specify
+which video input device this is.
+
+The per-board settings:
+ - port sub-node describing a single endpoint connected to the vin
+ as described in video-interfaces.txt[1]. Only the first one will
+ be considered as each vin interface has one input port.
+
+ These settings are used to work out video input format and widths
+ into the system.
+
+
+Device node example
+-------------------
+
+ aliases {
+ vin0 = &vin0;
+ };
+
+ vin0: vin@0xe6ef0000 {
+ compatible = "renesas,vin-r8a7790";
+ clocks = <&mstp8_clks R8A7790_CLK_VIN0>;
+ reg = <0 0xe6ef0000 0 0x1000>;
+ interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+Board setup example (vin1 composite video input)
+------------------------------------------------
+
+&i2c2 {
+ status = "ok";
+ pinctrl-0 = <&i2c2_pins>;
+ pinctrl-names = "default";
+
+ adv7180@20 {
+ compatible = "adi,adv7180";
+ reg = <0x20>;
+ remote = <&vin1>;
+
+ port {
+ adv7180: endpoint {
+ bus-width = <8>;
+ remote-endpoint = <&vin1ep0>;
+ };
+ };
+ };
+};
+
+/* composite video input */
+&vin1 {
+ pinctrl-0 = <&vin1_pins>;
+ pinctrl-names = "default";
+
+ status = "ok";
+
+ port {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ vin1ep0: endpoint {
+ remote-endpoint = <&adv7180>;
+ bus-width = <8>;
+ };
+ };
+};
+
+
+
+[1] video-interfaces.txt common video media interface
diff --git a/Documentation/devicetree/bindings/media/sunxi-ir.txt b/Documentation/devicetree/bindings/media/sunxi-ir.txt
new file mode 100644
index 000000000000..23dd5ad07b7c
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/sunxi-ir.txt
@@ -0,0 +1,23 @@
+Device-Tree bindings for SUNXI IR controller found in sunXi SoC family
+
+Required properties:
+- compatible : should be "allwinner,sun4i-a10-ir";
+- clocks : list of clock specifiers, corresponding to
+ entries in clock-names property;
+- clock-names : should contain "apb" and "ir" entries;
+- interrupts : should contain IR IRQ number;
+- reg : should contain IO map address for IR.
+
+Optional properties:
+- linux,rc-map-name : Remote control map name.
+
+Example:
+
+ir0: ir@01c21800 {
+ compatible = "allwinner,sun4i-a10-ir";
+ clocks = <&apb0_gates 6>, <&ir0_clk>;
+ clock-names = "apb", "ir";
+ interrupts = <0 5 1>;
+ reg = <0x01C21800 0x40>;
+ linux,rc-map-name = "rc-rc6-mce";
+};
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index d91b8be80b66..26c623dd3aa3 100755
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -29,7 +29,7 @@ use IO::Handle;
"af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
"lme2510c_s7395_old", "drxk", "drxk_terratec_h5",
"drxk_hauppauge_hvr930c", "tda10071", "it9135", "drxk_pctv",
- "drxk_terratec_htc_stick", "sms1xxx_hcw");
+ "drxk_terratec_htc_stick", "sms1xxx_hcw", "si2165");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -783,6 +783,37 @@ sub sms1xxx_hcw {
$allfiles;
}
+sub si2165 {
+ my $sourcefile = "model_111xxx_122xxx_driver_6_0_119_31191_WHQL.zip";
+ my $url = "http://www.hauppauge.de/files/drivers/";
+ my $hash = "76633e7c76b0edee47c3ba18ded99336";
+ my $fwfile = "dvb-demod-si2165.fw";
+ my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
+
+ checkstandard();
+
+ wgetfile($sourcefile, $url . $sourcefile);
+ verify($sourcefile, $hash);
+ unzip($sourcefile, $tmpdir);
+ extract("$tmpdir/Driver10/Hcw10bda.sys", 0x80788, 0x81E08-0x80788, "$tmpdir/fw1");
+
+ delzero("$tmpdir/fw1","$tmpdir/fw1-1");
+ #verify("$tmpdir/fw1","5e0909858fdf0b5b09ad48b9fe622e70");
+
+ my $CRC="\x0A\xCC";
+ my $BLOCKS_MAIN="\x27";
+ open FW,">$fwfile";
+ print FW "\x01\x00"; # just a version id for the driver itself
+ print FW "\x9A"; # fw version
+ print FW "\x00"; # padding
+ print FW "$BLOCKS_MAIN"; # number of blocks of main part
+ print FW "\x00"; # padding
+ print FW "$CRC"; # 16bit crc value of main part
+ appendfile(FW,"$tmpdir/fw1");
+
+ "$fwfile";
+}
+
# ---------------------------------------------------------------
# Utilities
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index fc009d0ee7d6..a74eeccfe700 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -41,3 +41,5 @@
40 -> TurboSight TBS 6981 [6981:8888]
41 -> TurboSight TBS 6980 [6980:8888]
42 -> Leadtek Winfast PxPVR2200 [107d:6f21]
+ 43 -> Hauppauge ImpactVCB-e [0070:7133]
+ 44 -> DViCO FusionHDTV DVB-T Dual Express2 [18ac:db98]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 5a3ddcd340d3..bc3351bb48b4 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -77,7 +77,7 @@
76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340]
77 -> EM2874 Leadership ISDBT (em2874)
78 -> PCTV nanoStick T2 290e (em28174)
- 79 -> Terratec Cinergy H5 (em2884) [0ccd:10a2,0ccd:10ad,0ccd:10b6]
+ 79 -> Terratec Cinergy H5 (em2884) [eb1a:2885,0ccd:10a2,0ccd:10ad,0ccd:10b6]
80 -> PCTV DVB-S2 Stick (460e) (em28174)
81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605]
82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2]
diff --git a/Documentation/video4linux/v4l2-controls.txt b/Documentation/video4linux/v4l2-controls.txt
index 06cf3ac83631..0f84ce8c9a7b 100644
--- a/Documentation/video4linux/v4l2-controls.txt
+++ b/Documentation/video4linux/v4l2-controls.txt
@@ -77,9 +77,9 @@ Basic usage for V4L2 and sub-device drivers
Where foo->v4l2_dev is of type struct v4l2_device.
- Finally, remove all control functions from your v4l2_ioctl_ops:
- vidioc_queryctrl, vidioc_querymenu, vidioc_g_ctrl, vidioc_s_ctrl,
- vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
+ Finally, remove all control functions from your v4l2_ioctl_ops (if any):
+ vidioc_queryctrl, vidioc_query_ext_ctrl, vidioc_querymenu, vidioc_g_ctrl,
+ vidioc_s_ctrl, vidioc_g_ext_ctrls, vidioc_try_ext_ctrls and vidioc_s_ext_ctrls.
Those are now no longer needed.
1.3.2) For sub-device drivers do this:
@@ -258,8 +258,8 @@ The new control value has already been validated, so all you need to do is
to actually update the hardware registers.
You're done! And this is sufficient for most of the drivers we have. No need
-to do any validation of control values, or implement QUERYCTRL/QUERYMENU. And
-G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
+to do any validation of control values, or implement QUERYCTRL, QUERY_EXT_CTRL
+and QUERYMENU. And G/S_CTRL as well as G/TRY/S_EXT_CTRLS are automatically supported.
==============================================================================
@@ -288,30 +288,45 @@ of v4l2_device.
Accessing Control Values
========================
-The v4l2_ctrl struct contains these two unions:
+The following union is used inside the control framework to access control
+values:
- /* The current control value. */
- union {
+union v4l2_ctrl_ptr {
+ s32 *p_s32;
+ s64 *p_s64;
+ char *p_char;
+ void *p;
+};
+
+The v4l2_ctrl struct contains these fields that can be used to access both
+current and new values:
+
+ s32 val;
+ struct {
s32 val;
- s64 val64;
- char *string;
} cur;
- /* The new control value. */
- union {
- s32 val;
- s64 val64;
- char *string;
- };
-Within the control ops you can freely use these. The val and val64 speak for
-themselves. The string pointers point to character buffers of length
+ union v4l2_ctrl_ptr p_new;
+ union v4l2_ctrl_ptr p_cur;
+
+If the control has a simple s32 type type, then:
+
+ &ctrl->val == ctrl->p_new.p_s32
+ &ctrl->cur.val == ctrl->p_cur.p_s32
+
+For all other types use ctrl->p_cur.p. Basically the val
+and cur.val fields can be considered an alias since these are used so often.
+
+Within the control ops you can freely use these. The val and cur.val speak for
+themselves. The p_char pointers point to character buffers of length
ctrl->maximum + 1, and are always 0-terminated.
-In most cases 'cur' contains the current cached control value. When you create
-a new control this value is made identical to the default value. After calling
-v4l2_ctrl_handler_setup() this value is passed to the hardware. It is generally
-a good idea to call this function.
+Unless the control is marked volatile the p_cur field points to the the
+current cached control value. When you create a new control this value is made
+identical to the default value. After calling v4l2_ctrl_handler_setup() this
+value is passed to the hardware. It is generally a good idea to call this
+function.
Whenever a new value is set that new value is automatically cached. This means
that most drivers do not need to implement the g_volatile_ctrl() op. The
@@ -362,8 +377,8 @@ will result in a deadlock since these helpers lock the handler as well.
You can also take the handler lock yourself:
mutex_lock(&state->ctrl_handler.lock);
- printk(KERN_INFO "String value is '%s'\n", ctrl1->cur.string);
- printk(KERN_INFO "Integer value is '%s'\n", ctrl2->cur.val);
+ pr_info("String value is '%s'\n", ctrl1->p_cur.p_char);
+ pr_info("Integer value is '%s'\n", ctrl2->cur.val);
mutex_unlock(&state->ctrl_handler.lock);
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index 667a43361706..a11dff07ef71 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -675,11 +675,6 @@ You should also set these fields:
video_device is initialized you *do* know which parent PCI device to use and
so you set dev_device to the correct PCI device.
-- flags: optional. Set to V4L2_FL_USE_FH_PRIO if you want to let the framework
- handle the VIDIOC_G/S_PRIORITY ioctls. This requires that you use struct
- v4l2_fh. Eventually this flag will disappear once all drivers use the core
- priority handling. But for now it has to be set explicitly.
-
If you use v4l2_ioctl_ops, then you should set .unlocked_ioctl to video_ioctl2
in your v4l2_file_operations struct.
@@ -909,8 +904,7 @@ struct v4l2_fh
struct v4l2_fh provides a way to easily keep file handle specific data
that is used by the V4L2 framework. New drivers must use struct v4l2_fh
-since it is also used to implement priority handling (VIDIOC_G/S_PRIORITY)
-if the video_device flag V4L2_FL_USE_FH_PRIO is also set.
+since it is also used to implement priority handling (VIDIOC_G/S_PRIORITY).
The users of v4l2_fh (in the V4L2 framework, not the driver) know
whether a driver uses v4l2_fh as its file->private_data pointer by
diff --git a/Documentation/video4linux/v4l2-pci-skeleton.c b/Documentation/video4linux/v4l2-pci-skeleton.c
index 46904fe49609..006721e43b2a 100644
--- a/Documentation/video4linux/v4l2-pci-skeleton.c
+++ b/Documentation/video4linux/v4l2-pci-skeleton.c
@@ -883,11 +883,6 @@ static int skeleton_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
vdev->v4l2_dev = &skel->v4l2_dev;
/* Supported SDTV standards, if any */
vdev->tvnorms = SKEL_TVNORMS;
- /* If this bit is set, then the v4l2 core will provide the support
- * for the VIDIOC_G/S_PRIORITY ioctls. This flag will eventually
- * go away once all drivers have been converted to use struct v4l2_fh.
- */
- set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
video_set_drvdata(vdev, skel);
ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
diff --git a/Documentation/zh_CN/video4linux/v4l2-framework.txt b/Documentation/zh_CN/video4linux/v4l2-framework.txt
index 0da95dbaef34..2b828e631e31 100644
--- a/Documentation/zh_CN/video4linux/v4l2-framework.txt
+++ b/Documentation/zh_CN/video4linux/v4l2-framework.txt
@@ -580,11 +580,6 @@ release()回调必须被设置,且在最后一个 video_device 用户退出之
v4l2_device 无法与特定的 PCI 设备关联,所有没有设置父设备。但当
video_device 配置后,就知道使用哪个父 PCI 设备了。
-- flags:可选。如果你要让框架处理设置 VIDIOC_G/S_PRIORITY ioctls,
- 请设置 V4L2_FL_USE_FH_PRIO。这要求你使用 v4l2_fh 结构体。
- 一旦所有驱动使用了核心的优先级处理,最终这个标志将消失。但现在它
- 必须被显式设置。
-
如果你使用 v4l2_ioctl_ops,则应该在 v4l2_file_operations 结构体中
设置 .unlocked_ioctl 指向 video_ioctl2。
@@ -789,7 +784,7 @@ v4l2_fh 结构体
-------------
v4l2_fh 结构体提供一个保存用于 V4L2 框架的文件句柄特定数据的简单方法。
-如果 video_device 的 flag 设置了 V4L2_FL_USE_FH_PRIO 标志,新驱动
+如果 video_device 标志,新驱动
必须使用 v4l2_fh 结构体,因为它也用于实现优先级处理(VIDIOC_G/S_PRIORITY)。
v4l2_fh 的用户(位于 V4l2 框架中,并非驱动)可通过测试
diff --git a/MAINTAINERS b/MAINTAINERS
index 0f066ddc13e7..d5a78f24d14e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -516,6 +516,16 @@ S: Supported
F: fs/aio.c
F: include/linux/*aio*.h
+AIRSPY MEDIA DRIVER
+M: Antti Palosaari
+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/airspy/
+
ALCATEL SPEEDTOUCH USB DRIVER
M: Duncan Sands
L: linux-usb@vger.kernel.org
@@ -3993,6 +4003,12 @@ F: Documentation/isdn/README.gigaset
F: drivers/isdn/gigaset/
F: include/uapi/linux/gigaset_dev.h
+GO7007 MPEG CODEC
+M: Hans Verkuil
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/usb/go7007/
+
GPIO SUBSYSTEM
M: Linus Walleij
M: Alexandre Courbot
@@ -5965,9 +5981,9 @@ 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/staging/media/msi3101/msi001*
+F: drivers/media/tuners/msi001*
-MSI3101 MEDIA DRIVER
+MSI2500 MEDIA DRIVER
M: Antti Palosaari
L: linux-media@vger.kernel.org
W: http://linuxtv.org/
@@ -5975,7 +5991,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/staging/media/msi3101/sdr-msi3101*
+F: drivers/media/usb/msi2500/
MT9M032 APTINA SENSOR DRIVER
M: Laurent Pinchart
@@ -6499,11 +6515,12 @@ L: linux-omap@vger.kernel.org
S: Maintained
F: arch/arm/mach-omap2/omap_hwmod_44xx_data.c
-OMAP IMAGE SIGNAL PROCESSOR (ISP)
+OMAP IMAGING SUBSYSTEM (OMAP3 ISP and OMAP4 ISS)
M: Laurent Pinchart
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/platform/omap3isp/
+F: drivers/staging/media/omap4iss/
OMAP USB SUPPORT
M: Felipe Balbi
@@ -7611,7 +7628,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/staging/media/rtl2832u_sdr/rtl2832_sdr*
+F: drivers/media/dvb-frontends/rtl2832_sdr*
RTL8180 WIRELESS DRIVER
M: "John W. Linville"
@@ -8380,6 +8397,12 @@ M: Chris Boot
S: Maintained
F: drivers/leds/leds-net48xx.c
+SOFTLOGIC 6x10 MPEG CODEC
+M: Ismael Luceno
+L: linux-media@vger.kernel.org
+S: Supported
+F: drivers/media/pci/solo6x10/
+
SOFTWARE RAID (Multiple Disks) SUPPORT
M: Neil Brown
L: linux-raid@vger.kernel.org
@@ -8586,11 +8609,6 @@ M: Marek Belisko
S: Odd Fixes
F: drivers/staging/ft1000/
-STAGING - GO7007 MPEG CODEC
-M: Hans Verkuil
-S: Maintained
-F: drivers/staging/media/go7007/
-
STAGING - INDUSTRIAL IO
M: Jonathan Cameron
L: linux-iio@vger.kernel.org
@@ -8648,11 +8666,6 @@ M: Christopher Harrer
S: Odd Fixes
F: drivers/staging/slicoss/
-STAGING - SOFTLOGIC 6x10 MPEG CODEC
-M: Ismael Luceno
-S: Supported
-F: drivers/staging/media/solo6x10/
-
STAGING - SPEAKUP CONSOLE SPEECH DRIVER
M: William Hubbs
M: Chris Brannon
@@ -9519,15 +9532,6 @@ L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/usb/smsc95xx.*
-USB SN9C1xx DRIVER
-M: Luca Risolia
-L: linux-usb@vger.kernel.org
-L: linux-media@vger.kernel.org
-T: git git://linuxtv.org/media_tree.git
-W: http://www.linux-projects.org
-S: Maintained
-F: drivers/staging/media/sn9c102/
-
USB SUBSYSTEM
M: Greg Kroah-Hartman
L: linux-usb@vger.kernel.org
diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c
index cf1a9f1c1217..045f8ebf16b5 100644
--- a/drivers/hid/hid-picolcd_cir.c
+++ b/drivers/hid/hid-picolcd_cir.c
@@ -114,7 +114,7 @@ int picolcd_init_cir(struct picolcd_data *data, struct hid_report *report)
rdev->priv = data;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
rdev->open = picolcd_cir_open;
rdev->close = picolcd_cir_close;
rdev->input_name = data->hdev->name;
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 1d0758aeb8e4..f60bad491eb6 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -59,6 +59,13 @@ config MEDIA_RADIO_SUPPORT
support radio reception. Disabling this option will
disable support for them.
+config MEDIA_SDR_SUPPORT
+ bool "Software defined radio support"
+ ---help---
+ Enable software defined radio support.
+
+ Say Y when you have a software defined radio device.
+
config MEDIA_RC_SUPPORT
bool "Remote Controller support"
depends on INPUT
@@ -95,7 +102,7 @@ config MEDIA_CONTROLLER
config VIDEO_DEV
tristate
depends on MEDIA_SUPPORT
- depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+ depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT
default y
config VIDEO_V4L2_SUBDEV_API
@@ -171,10 +178,11 @@ comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
config MEDIA_SUBDRV_AUTOSELECT
bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
- depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT
+ depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT
depends on HAS_IOMEM
select I2C
select I2C_MUX
+ select SPI
default y
help
By default, a media driver auto-selects all possible ancillary
diff --git a/drivers/media/common/saa7146/saa7146_fops.c b/drivers/media/common/saa7146/saa7146_fops.c
index eda01bc68ab2..d9e1d6395ed9 100644
--- a/drivers/media/common/saa7146/saa7146_fops.c
+++ b/drivers/media/common/saa7146/saa7146_fops.c
@@ -533,13 +533,12 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
if (dev->ext_vv_data->capabilities & V4L2_CAP_VBI_CAPTURE)
saa7146_vbi_uops.init(dev,vv);
- fmt = &vv->ov_fb.fmt;
- fmt->width = vv->standard->h_max_out;
- fmt->height = vv->standard->v_max_out;
- fmt->pixelformat = V4L2_PIX_FMT_RGB565;
- fmt->bytesperline = 2 * fmt->width;
- fmt->sizeimage = fmt->bytesperline * fmt->height;
- fmt->colorspace = V4L2_COLORSPACE_SRGB;
+ vv->ov_fb.fmt.width = vv->standard->h_max_out;
+ vv->ov_fb.fmt.height = vv->standard->v_max_out;
+ vv->ov_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
+ vv->ov_fb.fmt.bytesperline = 2 * vv->ov_fb.fmt.width;
+ vv->ov_fb.fmt.sizeimage = vv->ov_fb.fmt.bytesperline * vv->ov_fb.fmt.height;
+ vv->ov_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB;
fmt = &vv->video_fmt;
fmt->width = 384;
@@ -613,7 +612,6 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
vfd->lock = &dev->v4l2_lock;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->tvnorms = 0;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
strlcpy(vfd->name, name, sizeof(vfd->name));
diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig
index f953d33ee151..4bfbd5f463d1 100644
--- a/drivers/media/common/siano/Kconfig
+++ b/drivers/media/common/siano/Kconfig
@@ -22,8 +22,7 @@ config SMS_SIANO_DEBUGFS
bool "Enable debugfs for smsdvb"
depends on SMS_SIANO_MDTV
depends on DEBUG_FS
- depends on SMS_USB_DRV
- depends on CONFIG_SMS_USB_DRV = CONFIG_SMS_SDIO_DRV
+ depends on SMS_USB_DRV = SMS_SDIO_DRV
---help---
Choose Y to enable visualizing a dump of the frontend
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 6d7c0c858bd0..273043ea8f47 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -88,7 +88,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
dev->priv = coredev;
dev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(dev, RC_BIT_ALL);
+ dev->allowed_protocols = RC_BIT_ALL;
dev->map_name = sms_get_board(board_id)->rc_codes;
dev->driver_name = MODULE_NAME;
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 11d2bea23b02..5135a096bfa6 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -244,6 +244,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_TVSTICK_CT2_4400 0x3014
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
@@ -363,6 +364,7 @@
#define USB_PID_TVWAY_PLUS 0x0002
#define USB_PID_SVEON_STV20 0xe39d
#define USB_PID_SVEON_STV20_RTL2832U 0xd39d
+#define USB_PID_SVEON_STV21 0xd3b0
#define USB_PID_SVEON_STV22 0xe401
#define USB_PID_SVEON_STV22_IT9137 0xe411
#define USB_PID_AZUREWAVE_AZ6027 0x3275
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 6ce435ac866f..c2a6a0a85813 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -96,10 +96,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to seconds on open(
* FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
*/
-#define DVB_FE_NO_EXIT 0
-#define DVB_FE_NORMAL_EXIT 1
-#define DVB_FE_DEVICE_REMOVED 2
-
static DEFINE_MUTEX(frontend_mutex);
struct dvb_frontend_private {
@@ -113,7 +109,6 @@ struct dvb_frontend_private {
wait_queue_head_t wait_queue;
struct task_struct *thread;
unsigned long release_jiffies;
- unsigned int exit;
unsigned int wakeup;
fe_status_t status;
unsigned long tune_mode_flags;
@@ -565,7 +560,7 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
{
struct dvb_frontend_private *fepriv = fe->frontend_priv;
- if (fepriv->exit != DVB_FE_NO_EXIT)
+ if (fe->exit != DVB_FE_NO_EXIT)
return 1;
if (fepriv->dvbdev->writers == 1)
@@ -629,7 +624,7 @@ restart:
/* got signal or quitting */
if (!down_interruptible(&fepriv->sem))
semheld = true;
- fepriv->exit = DVB_FE_NORMAL_EXIT;
+ fe->exit = DVB_FE_NORMAL_EXIT;
break;
}
@@ -739,9 +734,9 @@ restart:
fepriv->thread = NULL;
if (kthread_should_stop())
- fepriv->exit = DVB_FE_DEVICE_REMOVED;
+ fe->exit = DVB_FE_DEVICE_REMOVED;
else
- fepriv->exit = DVB_FE_NO_EXIT;
+ fe->exit = DVB_FE_NO_EXIT;
mb();
if (semheld)
@@ -756,7 +751,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
- fepriv->exit = DVB_FE_NORMAL_EXIT;
+ if (fe->exit != DVB_FE_DEVICE_REMOVED)
+ fe->exit = DVB_FE_NORMAL_EXIT;
mb();
if (!fepriv->thread)
@@ -826,7 +822,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s:\n", __func__);
if (fepriv->thread) {
- if (fepriv->exit == DVB_FE_NO_EXIT)
+ if (fe->exit == DVB_FE_NO_EXIT)
return 0;
else
dvb_frontend_stop (fe);
@@ -838,7 +834,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return -EINTR;
fepriv->state = FESTATE_IDLE;
- fepriv->exit = DVB_FE_NO_EXIT;
+ fe->exit = DVB_FE_NO_EXIT;
fepriv->thread = NULL;
mb();
@@ -1906,7 +1902,7 @@ static int dvb_frontend_ioctl(struct file *file,
if (down_interruptible(&fepriv->sem))
return -ERESTARTSYS;
- if (fepriv->exit != DVB_FE_NO_EXIT) {
+ if (fe->exit != DVB_FE_NO_EXIT) {
up(&fepriv->sem);
return -ENODEV;
}
@@ -2424,7 +2420,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
int ret;
dev_dbg(fe->dvb->device, "%s:\n", __func__);
- if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
+ if (fe->exit == DVB_FE_DEVICE_REMOVED)
return -ENODEV;
if (adapter->mfe_shared) {
@@ -2529,7 +2525,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if (dvbdev->users == -1) {
wake_up(&fepriv->wait_queue);
- if (fepriv->exit != DVB_FE_NO_EXIT)
+ if (fe->exit != DVB_FE_NO_EXIT)
wake_up(&dvbdev->wait_queue);
if (fe->ops.ts_bus_ctrl)
fe->ops.ts_bus_ctrl(fe, 0);
@@ -2572,12 +2568,14 @@ int dvb_frontend_resume(struct dvb_frontend *fe)
dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num,
fe->id);
+ fe->exit = DVB_FE_DEVICE_RESUME;
if (fe->ops.init)
ret = fe->ops.init(fe);
if (fe->ops.tuner_ops.init)
ret = fe->ops.tuner_ops.init(fe);
+ fe->exit = DVB_FE_NO_EXIT;
fepriv->state = FESTATE_RETUNE;
dvb_frontend_wakeup(fe);
@@ -2666,20 +2664,20 @@ void dvb_frontend_detach(struct dvb_frontend* fe)
if (fe->ops.release_sec) {
fe->ops.release_sec(fe);
- symbol_put_addr(fe->ops.release_sec);
+ dvb_detach(fe->ops.release_sec);
}
if (fe->ops.tuner_ops.release) {
fe->ops.tuner_ops.release(fe);
- symbol_put_addr(fe->ops.tuner_ops.release);
+ dvb_detach(fe->ops.tuner_ops.release);
}
if (fe->ops.analog_ops.release) {
fe->ops.analog_ops.release(fe);
- symbol_put_addr(fe->ops.analog_ops.release);
+ dvb_detach(fe->ops.analog_ops.release);
}
ptr = (void*)fe->ops.release;
if (ptr) {
fe->ops.release(fe);
- symbol_put_addr(ptr);
+ dvb_detach(ptr);
}
}
#else
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
index 371b6caf486c..d398de4b6ef4 100644
--- a/drivers/media/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb-core/dvb_frontend.h
@@ -405,6 +405,11 @@ struct dtv_frontend_properties {
struct dtv_fe_stats block_count;
};
+#define DVB_FE_NO_EXIT 0
+#define DVB_FE_NORMAL_EXIT 1
+#define DVB_FE_DEVICE_REMOVED 2
+#define DVB_FE_DEVICE_RESUME 3
+
struct dvb_frontend {
struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
@@ -418,6 +423,7 @@ struct dvb_frontend {
#define DVB_FRONTEND_COMPONENT_DEMOD 1
int (*callback)(void *adapter_priv, int component, int cmd, int arg);
int id;
+ unsigned int exit;
};
extern int dvb_register_frontend(struct dvb_adapter *dvb,
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
index 93a9470d3f0c..f96b28e7fc95 100644
--- a/drivers/media/dvb-core/dvbdev.h
+++ b/drivers/media/dvb-core/dvbdev.h
@@ -136,11 +136,15 @@ extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
__r; \
})
+#define dvb_detach(FUNC) symbol_put_addr(FUNC)
+
#else
#define dvb_attach(FUNCTION, ARGS...) ({ \
FUNCTION(ARGS); \
})
+#define dvb_detach(FUNC) {}
+
#endif
#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 1469d44acb22..fe0ddcca192c 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -63,6 +63,15 @@ config DVB_TDA18271C2DD
Say Y when you want to support this tuner.
+config DVB_SI2165
+ tristate "Silicon Labs si2165 based"
+ depends on DVB_CORE && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ A DVB-C/T demodulator.
+
+ Say Y when you want to support this frontend.
+
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
@@ -446,6 +455,15 @@ config DVB_RTL2832
help
Say Y when you want to support this frontend.
+config DVB_RTL2832_SDR
+ tristate "Realtek RTL2832 SDR"
+ depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB
+ select DVB_RTL2832
+ select VIDEOBUF2_VMALLOC
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this SDR module.
+
config DVB_SI2168
tristate "Silicon Labs Si2168"
depends on DVB_CORE && I2C && I2C_MUX
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index dda0bee36f29..edf103d45920 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -5,6 +5,11 @@
ccflags-y += -I$(srctree)/drivers/media/dvb-core/
ccflags-y += -I$(srctree)/drivers/media/tuners/
+# FIXME: RTL2832 SDR driver uses power management directly from USB IF driver
+ifdef CONFIG_DVB_RTL2832_SDR
+ ccflags-y += -I$(srctree)/drivers/media/usb/dvb-usb-v2
+endif
+
stb0899-objs := stb0899_drv.o stb0899_algo.o
stv0900-objs := stv0900_core.o stv0900_sw.o
drxd-objs := drxd_firm.o drxd_hard.o
@@ -100,10 +105,12 @@ obj-$(CONFIG_DVB_STV0367) += stv0367.o
obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o
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_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
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index fb504f1e9125..ecf6388d2200 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -470,7 +470,6 @@ static int af9013_statistics_snr_result(struct dvb_frontend *fe)
break;
default:
goto err;
- break;
}
for (i = 0; i < len; i++) {
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index 23a0d05ba426..33aa9410b624 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -220,7 +220,7 @@ static void setup_vbi(struct au8522_state *state, int aud_input)
}
-static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
+static void setup_decoder_defaults(struct au8522_state *state, bool is_svideo)
{
int i;
int filter_coef_type;
@@ -237,13 +237,10 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
/* Other decoder registers */
au8522_writereg(state, AU8522_TVDEC_INT_MASK_REG010H, 0x00);
- if (input_mode == 0x23) {
- /* S-Video input mapping */
+ if (is_svideo)
au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x04);
- } else {
- /* All other modes (CVBS/ATVRF etc.) */
+ else
au8522_writereg(state, AU8522_VIDEO_MODE_REG011H, 0x00);
- }
au8522_writereg(state, AU8522_TVDEC_PGA_REG012H,
AU8522_TVDEC_PGA_REG012H_CVBS);
@@ -251,12 +248,23 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
AU8522_TVDEC_COMB_MODE_REG015H_CVBS);
au8522_writereg(state, AU8522_TVDED_DBG_MODE_REG060H,
AU8522_TVDED_DBG_MODE_REG060H_CVBS);
- au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
- AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
- AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
- AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
- au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
- AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
+
+ if (state->std == V4L2_STD_PAL_M) {
+ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_AUTO);
+ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+ AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M);
+ } else {
+ /* NTSC */
+ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL1_REG061H,
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_FIELD_LEN_525 |
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_LINE_LEN_63_492 |
+ AU8522_TVDEC_FORMAT_CTRL1_REG061H_SUBCARRIER_NTSC_MN);
+ au8522_writereg(state, AU8522_TVDEC_FORMAT_CTRL2_REG062H,
+ AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC);
+ }
au8522_writereg(state, AU8522_TVDEC_VCR_DET_LLIM_REG063H,
AU8522_TVDEC_VCR_DET_LLIM_REG063H_CVBS);
au8522_writereg(state, AU8522_TVDEC_VCR_DET_HLIM_REG064H,
@@ -275,8 +283,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
- if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
- input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+ if (is_svideo) {
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
@@ -317,8 +324,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
setup_vbi(state, 0);
- if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
- input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+ if (is_svideo) {
/* Despite what the table says, for the HVR-950q we still need
to be in CVBS mode for the S-Video input (reason unknown). */
/* filter_coef_type = 3; */
@@ -346,7 +352,7 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
au8522_writereg(state, AU8522_REG436H, 0x3c);
}
-static void au8522_setup_cvbs_mode(struct au8522_state *state)
+static void au8522_setup_cvbs_mode(struct au8522_state *state, u8 input_mode)
{
/* here we're going to try the pre-programmed route */
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
@@ -358,16 +364,16 @@ static void au8522_setup_cvbs_mode(struct au8522_state *state)
/* Enable clamping control */
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
- au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
- AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
- setup_decoder_defaults(state, AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
+ setup_decoder_defaults(state, false);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
}
-static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
+static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state,
+ u8 input_mode)
{
/* here we're going to try the pre-programmed route */
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
@@ -384,24 +390,22 @@ static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
- au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
- AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
- setup_decoder_defaults(state,
- AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF);
+ setup_decoder_defaults(state, false);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
}
-static void au8522_setup_svideo_mode(struct au8522_state *state)
+static void au8522_setup_svideo_mode(struct au8522_state *state,
+ u8 input_mode)
{
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_SVIDEO);
/* Set input to Y on Channe1, C on Channel 3 */
- au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
- AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+ au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H, input_mode);
/* PGA in automatic mode */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
@@ -409,8 +413,7 @@ static void au8522_setup_svideo_mode(struct au8522_state *state)
/* Enable clamping control */
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
- setup_decoder_defaults(state,
- AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
+ setup_decoder_defaults(state, true);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
@@ -432,8 +435,9 @@ static void disable_audio_input(struct au8522_state *state)
}
/* 0=disable, 1=SIF */
-static void set_audio_input(struct au8522_state *state, int aud_input)
+static void set_audio_input(struct au8522_state *state)
{
+ int aud_input = state->aud_input;
int i;
/* Note that this function needs to be used in conjunction with setting
@@ -465,8 +469,9 @@ static void set_audio_input(struct au8522_state *state, int aud_input)
au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
msleep(150);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x00);
- msleep(1);
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H, 0x9d);
+ msleep(10);
+ au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
msleep(50);
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
@@ -539,58 +544,109 @@ static int au8522_s_register(struct v4l2_subdev *sd,
}
#endif
+static void au8522_video_set(struct au8522_state *state)
+{
+ u8 input_mode;
+
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ switch (state->vid_input) {
+ case AU8522_COMPOSITE_CH1:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH1;
+ au8522_setup_cvbs_mode(state, input_mode);
+ break;
+ case AU8522_COMPOSITE_CH2:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH2;
+ au8522_setup_cvbs_mode(state, input_mode);
+ break;
+ case AU8522_COMPOSITE_CH3:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH3;
+ au8522_setup_cvbs_mode(state, input_mode);
+ break;
+ case AU8522_COMPOSITE_CH4:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4;
+ au8522_setup_cvbs_mode(state, input_mode);
+ break;
+ case AU8522_SVIDEO_CH13:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13;
+ au8522_setup_svideo_mode(state, input_mode);
+ break;
+ case AU8522_SVIDEO_CH24:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24;
+ au8522_setup_svideo_mode(state, input_mode);
+ break;
+ default:
+ case AU8522_COMPOSITE_CH4_SIF:
+ input_mode = AU8522_INPUT_CONTROL_REG081H_CVBS_CH4_SIF;
+ au8522_setup_cvbs_tuner_mode(state, input_mode);
+ break;
+ }
+}
+
static int au8522_s_stream(struct v4l2_subdev *sd, int enable)
{
struct au8522_state *state = to_state(sd);
if (enable) {
+ /*
+ * Clear out any state associated with the digital side of the
+ * chip, so that when it gets powered back up it won't think
+ * that it is already tuned
+ */
+ state->current_frequency = 0;
+
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
0x01);
- msleep(1);
- au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+ msleep(10);
+
+ au8522_video_set(state);
+ set_audio_input(state);
+
+ state->operational_mode = AU8522_ANALOG_MODE;
} else {
/* This does not completely power down the device
(it only reduces it from around 140ma to 80ma) */
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
1 << 5);
+ state->operational_mode = AU8522_SUSPEND_MODE;
}
return 0;
}
-static int au8522_reset(struct v4l2_subdev *sd, u32 val)
-{
- struct au8522_state *state = to_state(sd);
-
- state->operational_mode = AU8522_ANALOG_MODE;
-
- /* Clear out any state associated with the digital side of the
- chip, so that when it gets powered back up it won't think
- that it is already tuned */
- state->current_frequency = 0;
-
- au8522_writereg(state, 0xa4, 1 << 5);
-
- return 0;
-}
-
static int au8522_s_video_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct au8522_state *state = to_state(sd);
- au8522_reset(sd, 0);
-
- if (input == AU8522_COMPOSITE_CH1) {
- au8522_setup_cvbs_mode(state);
- } else if (input == AU8522_SVIDEO_CH13) {
- au8522_setup_svideo_mode(state);
- } else if (input == AU8522_COMPOSITE_CH4_SIF) {
- au8522_setup_cvbs_tuner_mode(state);
- } else {
+ switch(input) {
+ case AU8522_COMPOSITE_CH1:
+ case AU8522_SVIDEO_CH13:
+ case AU8522_COMPOSITE_CH4_SIF:
+ state->vid_input = input;
+ break;
+ default:
printk(KERN_ERR "au8522 mode not currently supported\n");
return -EINVAL;
}
+
+ if (state->operational_mode == AU8522_ANALOG_MODE)
+ au8522_video_set(state);
+
+ return 0;
+}
+
+static int au8522_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
+{
+ struct au8522_state *state = to_state(sd);
+
+ if ((std & (V4L2_STD_PAL_M | V4L2_STD_NTSC_M)) == 0)
+ return -EINVAL;
+
+ state->std = std;
+
+ if (state->operational_mode == AU8522_ANALOG_MODE)
+ au8522_video_set(state);
+
return 0;
}
@@ -598,7 +654,12 @@ static int au8522_s_audio_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
struct au8522_state *state = to_state(sd);
- set_audio_input(state, input);
+
+ state->aud_input = input;
+
+ if (state->operational_mode == AU8522_ANALOG_MODE)
+ set_audio_input(state);
+
return 0;
}
@@ -629,7 +690,6 @@ static int au8522_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
static const struct v4l2_subdev_core_ops au8522_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
- .reset = au8522_reset,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = au8522_g_register,
.s_register = au8522_s_register,
@@ -647,6 +707,7 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
static const struct v4l2_subdev_video_ops au8522_video_ops = {
.s_routing = au8522_s_video_routing,
.s_stream = au8522_s_stream,
+ .s_std = au8522_s_std,
};
static const struct v4l2_subdev_ops au8522_ops = {
@@ -729,6 +790,7 @@ static int au8522_probe(struct i2c_client *client,
}
state->c = client;
+ state->std = V4L2_STD_NTSC_M;
state->vid_input = AU8522_COMPOSITE_CH1;
state->aud_input = AU8522_AUDIO_NONE;
state->id = 8522;
diff --git a/drivers/media/dvb-frontends/au8522_priv.h b/drivers/media/dvb-frontends/au8522_priv.h
index aa0f16d6b610..b8aca1c84786 100644
--- a/drivers/media/dvb-frontends/au8522_priv.h
+++ b/drivers/media/dvb-frontends/au8522_priv.h
@@ -37,6 +37,7 @@
#define AU8522_ANALOG_MODE 0
#define AU8522_DIGITAL_MODE 1
+#define AU8522_SUSPEND_MODE 2
struct au8522_state {
struct i2c_client *c;
@@ -347,6 +348,7 @@ int au8522_led_ctrl(struct au8522_state *state, int led);
/* Format control 2 */
#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_AUTODETECT 0x00
#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_NTSC 0x01
+#define AU8522_TVDEC_FORMAT_CTRL2_REG062H_STD_PAL_M 0x02
#define AU8522_INPUT_CONTROL_REG081H_ATSC 0xC4
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
index 82b3d93718f8..6095dbcf7850 100644
--- a/drivers/media/dvb-frontends/cxd2820r.h
+++ b/drivers/media/dvb-frontends/cxd2820r.h
@@ -52,6 +52,12 @@ struct cxd2820r_config {
*/
u8 ts_mode;
+ /* TS clock inverted.
+ * Default: 0
+ * Values: 0, 1
+ */
+ bool ts_clock_inv;
+
/* IF AGC polarity.
* Default: 0
* Values: 0, 1
diff --git a/drivers/media/dvb-frontends/cxd2820r_c.c b/drivers/media/dvb-frontends/cxd2820r_c.c
index 5c6ab4921bf1..0f4657e01cde 100644
--- a/drivers/media/dvb-frontends/cxd2820r_c.c
+++ b/drivers/media/dvb-frontends/cxd2820r_c.c
@@ -45,6 +45,7 @@ int cxd2820r_set_frontend_c(struct dvb_frontend *fe)
{ 0x1008b, 0x07, 0xff },
{ 0x1001f, priv->cfg.if_agc_polarity << 7, 0x80 },
{ 0x10070, priv->cfg.ts_mode, 0xff },
+ { 0x10071, !priv->cfg.ts_clock_inv << 4, 0x10 },
};
dev_dbg(&priv->i2c->dev, "%s: frequency=%d symbol_rate=%d\n", __func__,
diff --git a/drivers/media/dvb-frontends/cxd2820r_t.c b/drivers/media/dvb-frontends/cxd2820r_t.c
index fa184ca2dd68..9b5a45b907bc 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t.c
@@ -46,6 +46,7 @@ int cxd2820r_set_frontend_t(struct dvb_frontend *fe)
{ 0x00088, 0x01, 0xff },
{ 0x00070, priv->cfg.ts_mode, 0xff },
+ { 0x00071, !priv->cfg.ts_clock_inv << 4, 0x10 },
{ 0x000cb, priv->cfg.if_agc_polarity << 6, 0x40 },
{ 0x000a5, 0x00, 0x01 },
{ 0x00082, 0x20, 0x60 },
diff --git a/drivers/media/dvb-frontends/cxd2820r_t2.c b/drivers/media/dvb-frontends/cxd2820r_t2.c
index 2ba130e245b6..9c0c4f42175c 100644
--- a/drivers/media/dvb-frontends/cxd2820r_t2.c
+++ b/drivers/media/dvb-frontends/cxd2820r_t2.c
@@ -47,6 +47,7 @@ int cxd2820r_set_frontend_t2(struct dvb_frontend *fe)
{ 0x02083, 0x0a, 0xff },
{ 0x020cb, priv->cfg.if_agc_polarity << 6, 0x40 },
{ 0x02070, priv->cfg.ts_mode, 0xff },
+ { 0x02071, !priv->cfg.ts_clock_inv << 6, 0x40 },
{ 0x020b5, priv->cfg.spec_inv << 4, 0x10 },
{ 0x02567, 0x07, 0x0f },
{ 0x02569, 0x03, 0x03 },
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index 3ee22ff76315..68e2af2650d3 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -2557,10 +2557,19 @@ static int dib0090_set_params(struct dvb_frontend *fe)
do {
ret = dib0090_tune(fe);
- if (ret != FE_CALLBACK_TIME_NEVER)
- msleep(ret / 10);
- else
+ if (ret == FE_CALLBACK_TIME_NEVER)
break;
+
+ /*
+ * Despite dib0090_tune returns time at a 0.1 ms range,
+ * the actual sleep time depends on CONFIG_HZ. The worse case
+ * is when CONFIG_HZ=100. In such case, the minimum granularity
+ * is 10ms. On some real field tests, the tuner sometimes don't
+ * lock when this timer is lower than 10ms. So, enforce a 10ms
+ * granularity and use usleep_range() instead of msleep().
+ */
+ ret = 10 * (ret + 99)/100;
+ usleep_range(ret * 1000, (ret + 1) * 1000);
} while (state->tune_state != CT_TUNER_STOP);
return 0;
diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c
index 148bf79236fb..dcb9a15ef0c2 100644
--- a/drivers/media/dvb-frontends/dib7000m.c
+++ b/drivers/media/dvb-frontends/dib7000m.c
@@ -1041,10 +1041,7 @@ static int dib7000m_tune(struct dvb_frontend *demod)
u16 value;
// we are already tuned - just resuming from suspend
- if (ch != NULL)
- dib7000m_set_channel(state, ch, 0);
- else
- return -EINVAL;
+ dib7000m_set_channel(state, ch, 0);
// restart demod
ret |= dib7000m_write_word(state, 898, 0x4000);
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index effb87f773b0..661760d60232 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -11,6 +11,7 @@
#include
#include
#include
+#include
#include "dvb_math.h"
#include "dvb_frontend.h"
@@ -72,6 +73,12 @@ struct dib7000p_state {
struct mutex i2c_buffer_lock;
u8 input_mode_mpeg;
+
+ /* for DVBv5 stats */
+ s64 old_ucb;
+ unsigned long per_jiffies_stats;
+ unsigned long ber_jiffies_stats;
+ unsigned long get_stats_time;
};
enum dib7000p_power_mode {
@@ -401,7 +408,7 @@ static int dib7000p_sad_calib(struct dib7000p_state *state)
return 0;
}
-int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
+static int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
{
struct dib7000p_state *state = demod->demodulator_priv;
if (value > 4095)
@@ -409,9 +416,8 @@ int dib7000p_set_wbd_ref(struct dvb_frontend *demod, u16 value)
state->wbd_ref = value;
return dib7000p_write_word(state, 105, (dib7000p_read_word(state, 105) & 0xf000) | value);
}
-EXPORT_SYMBOL(dib7000p_set_wbd_ref);
-int dib7000p_get_agc_values(struct dvb_frontend *fe,
+static int dib7000p_get_agc_values(struct dvb_frontend *fe,
u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
{
struct dib7000p_state *state = fe->demodulator_priv;
@@ -427,14 +433,12 @@ int dib7000p_get_agc_values(struct dvb_frontend *fe,
return 0;
}
-EXPORT_SYMBOL(dib7000p_get_agc_values);
-int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
+static int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
{
struct dib7000p_state *state = fe->demodulator_priv;
return dib7000p_write_word(state, 108, v);
}
-EXPORT_SYMBOL(dib7000p_set_agc1_min);
static void dib7000p_reset_pll(struct dib7000p_state *state)
{
@@ -478,7 +482,7 @@ static u32 dib7000p_get_internal_freq(struct dib7000p_state *state)
return internal;
}
-int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
+static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
{
struct dib7000p_state *state = fe->demodulator_priv;
u16 reg_1857, reg_1856 = dib7000p_read_word(state, 1856);
@@ -513,7 +517,6 @@ int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config
}
return -EIO;
}
-EXPORT_SYMBOL(dib7000p_update_pll);
static int dib7000p_reset_gpio(struct dib7000p_state *st)
{
@@ -546,12 +549,11 @@ static int dib7000p_cfg_gpio(struct dib7000p_state *st, u8 num, u8 dir, u8 val)
return 0;
}
-int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
+static int dib7000p_set_gpio(struct dvb_frontend *demod, u8 num, u8 dir, u8 val)
{
struct dib7000p_state *state = demod->demodulator_priv;
return dib7000p_cfg_gpio(state, num, dir, val);
}
-EXPORT_SYMBOL(dib7000p_set_gpio);
static u16 dib7000p_defaults[] = {
// auto search configuration
@@ -636,6 +638,8 @@ static u16 dib7000p_defaults[] = {
0,
};
+static void dib7000p_reset_stats(struct dvb_frontend *fe);
+
static int dib7000p_demod_reset(struct dib7000p_state *state)
{
dib7000p_set_power_mode(state, DIB7000P_POWER_ALL);
@@ -934,7 +938,7 @@ static void dib7000p_update_timf(struct dib7000p_state *state)
}
-u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
+static u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
{
struct dib7000p_state *state = fe->demodulator_priv;
switch (op) {
@@ -950,7 +954,6 @@ u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
dib7000p_set_bandwidth(state, state->current_bandwidth);
return state->timf;
}
-EXPORT_SYMBOL(dib7000p_ctrl_timf);
static void dib7000p_set_channel(struct dib7000p_state *state,
struct dtv_frontend_properties *ch, u8 seq)
@@ -1360,6 +1363,9 @@ static int dib7000p_tune(struct dvb_frontend *demod)
dib7000p_spur_protect(state, ch->frequency / 1000, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
dib7000p_set_bandwidth(state, BANDWIDTH_TO_KHZ(ch->bandwidth_hz));
+
+ dib7000p_reset_stats(demod);
+
return 0;
}
@@ -1552,6 +1558,8 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe)
return ret;
}
+static int dib7000p_get_stats(struct dvb_frontend *fe, fe_status_t stat);
+
static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
{
struct dib7000p_state *state = fe->demodulator_priv;
@@ -1570,6 +1578,8 @@ static int dib7000p_read_status(struct dvb_frontend *fe, fe_status_t * stat)
if ((lock & 0x0038) == 0x38)
*stat |= FE_HAS_LOCK;
+ dib7000p_get_stats(fe, *stat);
+
return 0;
}
@@ -1595,7 +1605,7 @@ static int dib7000p_read_signal_strength(struct dvb_frontend *fe, u16 * strength
return 0;
}
-static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
+static u32 dib7000p_get_snr(struct dvb_frontend *fe)
{
struct dib7000p_state *state = fe->demodulator_priv;
u16 val;
@@ -1625,10 +1635,351 @@ static int dib7000p_read_snr(struct dvb_frontend *fe, u16 * snr)
else
result -= intlog10(2) * 10 * noise_exp - 100;
+ return result;
+}
+
+static int dib7000p_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ u32 result;
+
+ result = dib7000p_get_snr(fe);
+
*snr = result / ((1 << 24) / 10);
return 0;
}
+static void dib7000p_reset_stats(struct dvb_frontend *demod)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ struct dtv_frontend_properties *c = &demod->dtv_property_cache;
+ u32 ucb;
+
+ memset(&c->strength, 0, sizeof(c->strength));
+ memset(&c->cnr, 0, sizeof(c->cnr));
+ memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
+ memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
+ memset(&c->block_error, 0, sizeof(c->block_error));
+
+ c->strength.len = 1;
+ c->cnr.len = 1;
+ c->block_error.len = 1;
+ c->block_count.len = 1;
+ c->post_bit_error.len = 1;
+ c->post_bit_count.len = 1;
+
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->strength.stat[0].uvalue = 0;
+
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+ dib7000p_read_unc_blocks(demod, &ucb);
+
+ state->old_ucb = ucb;
+ state->ber_jiffies_stats = 0;
+ state->per_jiffies_stats = 0;
+}
+
+struct linear_segments {
+ unsigned x;
+ signed y;
+};
+
+/*
+ * Table to estimate signal strength in dBm.
+ * This table should be empirically determinated by measuring the signal
+ * strength generated by a RF generator directly connected into
+ * a device.
+ * This table was determinated by measuring the signal strength generated
+ * by a DTA-2111 RF generator directly connected into a dib7000p device
+ * (a Hauppauge Nova-TD stick), using a good quality 3 meters length
+ * RC6 cable and good RC6 connectors, connected directly to antenna 1.
+ * As the minimum output power of DTA-2111 is -31dBm, a 16 dBm attenuator
+ * were used, for the lower power values.
+ * The real value can actually be on other devices, or even at the
+ * second antena input, depending on several factors, like if LNA
+ * is enabled or not, if diversity is enabled, type of connectors, etc.
+ * Yet, it is better to use this measure in dB than a random non-linear
+ * percentage value, especially for antenna adjustments.
+ * On my tests, the precision of the measure using this table is about
+ * 0.5 dB, with sounds reasonable enough to adjust antennas.
+ */
+#define DB_OFFSET 131000
+
+static struct linear_segments strength_to_db_table[] = {
+ { 63630, DB_OFFSET - 20500},
+ { 62273, DB_OFFSET - 21000},
+ { 60162, DB_OFFSET - 22000},
+ { 58730, DB_OFFSET - 23000},
+ { 58294, DB_OFFSET - 24000},
+ { 57778, DB_OFFSET - 25000},
+ { 57320, DB_OFFSET - 26000},
+ { 56779, DB_OFFSET - 27000},
+ { 56293, DB_OFFSET - 28000},
+ { 55724, DB_OFFSET - 29000},
+ { 55145, DB_OFFSET - 30000},
+ { 54680, DB_OFFSET - 31000},
+ { 54293, DB_OFFSET - 32000},
+ { 53813, DB_OFFSET - 33000},
+ { 53427, DB_OFFSET - 34000},
+ { 52981, DB_OFFSET - 35000},
+
+ { 52636, DB_OFFSET - 36000},
+ { 52014, DB_OFFSET - 37000},
+ { 51674, DB_OFFSET - 38000},
+ { 50692, DB_OFFSET - 39000},
+ { 49824, DB_OFFSET - 40000},
+ { 49052, DB_OFFSET - 41000},
+ { 48436, DB_OFFSET - 42000},
+ { 47836, DB_OFFSET - 43000},
+ { 47368, DB_OFFSET - 44000},
+ { 46468, DB_OFFSET - 45000},
+ { 45597, DB_OFFSET - 46000},
+ { 44586, DB_OFFSET - 47000},
+ { 43667, DB_OFFSET - 48000},
+ { 42673, DB_OFFSET - 49000},
+ { 41816, DB_OFFSET - 50000},
+ { 40876, DB_OFFSET - 51000},
+ { 0, 0},
+};
+
+static u32 interpolate_value(u32 value, struct linear_segments *segments,
+ unsigned len)
+{
+ u64 tmp64;
+ u32 dx;
+ s32 dy;
+ int i, ret;
+
+ if (value >= segments[0].x)
+ return segments[0].y;
+ if (value < segments[len-1].x)
+ return segments[len-1].y;
+
+ for (i = 1; i < len - 1; i++) {
+ /* If value is identical, no need to interpolate */
+ if (value == segments[i].x)
+ return segments[i].y;
+ if (value > segments[i].x)
+ break;
+ }
+
+ /* Linear interpolation between the two (x,y) points */
+ dy = segments[i - 1].y - segments[i].y;
+ dx = segments[i - 1].x - segments[i].x;
+
+ tmp64 = value - segments[i].x;
+ tmp64 *= dy;
+ do_div(tmp64, dx);
+ ret = segments[i].y + tmp64;
+
+ return ret;
+}
+
+/* FIXME: may require changes - this one was borrowed from dib8000 */
+static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer)
+{
+ struct dtv_frontend_properties *c = &demod->dtv_property_cache;
+ u64 time_us, tmp64;
+ u32 tmp, denom;
+ int guard, rate_num, rate_denum = 1, bits_per_symbol;
+ int interleaving = 0, fft_div;
+
+ switch (c->guard_interval) {
+ case GUARD_INTERVAL_1_4:
+ guard = 4;
+ break;
+ case GUARD_INTERVAL_1_8:
+ guard = 8;
+ break;
+ case GUARD_INTERVAL_1_16:
+ guard = 16;
+ break;
+ default:
+ case GUARD_INTERVAL_1_32:
+ guard = 32;
+ break;
+ }
+
+ switch (c->transmission_mode) {
+ case TRANSMISSION_MODE_2K:
+ fft_div = 4;
+ break;
+ case TRANSMISSION_MODE_4K:
+ fft_div = 2;
+ break;
+ default:
+ case TRANSMISSION_MODE_8K:
+ fft_div = 1;
+ break;
+ }
+
+ switch (c->modulation) {
+ case DQPSK:
+ case QPSK:
+ bits_per_symbol = 2;
+ break;
+ case QAM_16:
+ bits_per_symbol = 4;
+ break;
+ default:
+ case QAM_64:
+ bits_per_symbol = 6;
+ break;
+ }
+
+ switch ((c->hierarchy == 0 || 1 == 1) ? c->code_rate_HP : c->code_rate_LP) {
+ case FEC_1_2:
+ rate_num = 1;
+ rate_denum = 2;
+ break;
+ case FEC_2_3:
+ rate_num = 2;
+ rate_denum = 3;
+ break;
+ case FEC_3_4:
+ rate_num = 3;
+ rate_denum = 4;
+ break;
+ case FEC_5_6:
+ rate_num = 5;
+ rate_denum = 6;
+ break;
+ default:
+ case FEC_7_8:
+ rate_num = 7;
+ rate_denum = 8;
+ break;
+ }
+
+ interleaving = interleaving;
+
+ denom = bits_per_symbol * rate_num * fft_div * 384;
+
+ /* If calculus gets wrong, wait for 1s for the next stats */
+ if (!denom)
+ return 0;
+
+ /* Estimate the period for the total bit rate */
+ time_us = rate_denum * (1008 * 1562500L);
+ tmp64 = time_us;
+ do_div(tmp64, guard);
+ time_us = time_us + tmp64;
+ time_us += denom / 2;
+ do_div(time_us, denom);
+
+ tmp = 1008 * 96 * interleaving;
+ time_us += tmp + tmp / guard;
+
+ return time_us;
+}
+
+static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
+{
+ struct dib7000p_state *state = demod->demodulator_priv;
+ struct dtv_frontend_properties *c = &demod->dtv_property_cache;
+ int i;
+ int show_per_stats = 0;
+ u32 time_us = 0, val, snr;
+ u64 blocks, ucb;
+ s32 db;
+ u16 strength;
+
+ /* Get Signal strength */
+ dib7000p_read_signal_strength(demod, &strength);
+ val = strength;
+ db = interpolate_value(val,
+ strength_to_db_table,
+ ARRAY_SIZE(strength_to_db_table)) - DB_OFFSET;
+ c->strength.stat[0].svalue = db;
+
+ /* UCB/BER/CNR measures require lock */
+ if (!(stat & FE_HAS_LOCK)) {
+ c->cnr.len = 1;
+ c->block_count.len = 1;
+ c->block_error.len = 1;
+ c->post_bit_error.len = 1;
+ c->post_bit_count.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ return 0;
+ }
+
+ /* Check if time for stats was elapsed */
+ if (time_after(jiffies, state->per_jiffies_stats)) {
+ state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
+
+ /* Get SNR */
+ snr = dib7000p_get_snr(demod);
+ if (snr)
+ snr = (1000L * snr) >> 24;
+ else
+ snr = 0;
+ c->cnr.stat[0].svalue = snr;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+
+ /* Get UCB measures */
+ dib7000p_read_unc_blocks(demod, &val);
+ ucb = val - state->old_ucb;
+ if (val < state->old_ucb)
+ ucb += 0x100000000LL;
+
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue = ucb;
+
+ /* Estimate the number of packets based on bitrate */
+ if (!time_us)
+ time_us = dib7000p_get_time_us(demod, -1);
+
+ if (time_us) {
+ blocks = 1250000ULL * 1000000ULL;
+ do_div(blocks, time_us * 8 * 204);
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += blocks;
+ }
+
+ show_per_stats = 1;
+ }
+
+ /* Get post-BER measures */
+ if (time_after(jiffies, state->ber_jiffies_stats)) {
+ time_us = dib7000p_get_time_us(demod, -1);
+ state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
+
+ dprintk("Next all layers stats available in %u us.", time_us);
+
+ dib7000p_read_ber(demod, &val);
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue += val;
+
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue += 100000000;
+ }
+
+ /* Get PER measures */
+ if (show_per_stats) {
+ dib7000p_read_unc_blocks(demod, &val);
+
+ c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_error.stat[0].uvalue += val;
+
+ time_us = dib7000p_get_time_us(demod, i);
+ if (time_us) {
+ blocks = 1250000ULL * 1000000ULL;
+ do_div(blocks, time_us * 8 * 204);
+ c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->block_count.stat[0].uvalue += blocks;
+ }
+ }
+ return 0;
+}
+
static int dib7000p_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
@@ -1643,7 +1994,7 @@ static void dib7000p_release(struct dvb_frontend *demod)
kfree(st);
}
-int dib7000pc_detection(struct i2c_adapter *i2c_adap)
+static int dib7000pc_detection(struct i2c_adapter *i2c_adap)
{
u8 *tx, *rx;
struct i2c_msg msg[2] = {
@@ -1688,16 +2039,14 @@ rx_memory_error:
kfree(tx);
return ret;
}
-EXPORT_SYMBOL(dib7000pc_detection);
-struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
+static struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating)
{
struct dib7000p_state *st = demod->demodulator_priv;
return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
}
-EXPORT_SYMBOL(dib7000p_get_i2c_master);
-int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
{
struct dib7000p_state *state = fe->demodulator_priv;
u16 val = dib7000p_read_word(state, 235) & 0xffef;
@@ -1705,17 +2054,15 @@ int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
dprintk("PID filter enabled %d", onoff);
return dib7000p_write_word(state, 235, val);
}
-EXPORT_SYMBOL(dib7000p_pid_filter_ctrl);
-int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
{
struct dib7000p_state *state = fe->demodulator_priv;
dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff);
return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0);
}
-EXPORT_SYMBOL(dib7000p_pid_filter);
-int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
+static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
{
struct dib7000p_state *dpst;
int k = 0;
@@ -1774,7 +2121,6 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
kfree(dpst);
return 0;
}
-EXPORT_SYMBOL(dib7000p_i2c_enumeration);
static const s32 lut_1000ln_mant[] = {
6908, 6956, 7003, 7047, 7090, 7131, 7170, 7208, 7244, 7279, 7313, 7346, 7377, 7408, 7438, 7467, 7495, 7523, 7549, 7575, 7600
@@ -2032,12 +2378,11 @@ static struct i2c_algorithm dib7090_tuner_xfer_algo = {
.functionality = dib7000p_i2c_func,
};
-struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
+static struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
{
struct dib7000p_state *st = fe->demodulator_priv;
return &st->dib7090_tuner_adap;
}
-EXPORT_SYMBOL(dib7090_get_i2c_tuner);
static int dib7090_host_bus_drive(struct dib7000p_state *state, u8 drive)
{
@@ -2329,7 +2674,7 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode)
return ret;
}
-int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
+static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
struct dib7000p_state *state = fe->demodulator_priv;
u16 en_cur_state;
@@ -2352,15 +2697,13 @@ int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
return 0;
}
-EXPORT_SYMBOL(dib7090_tuner_sleep);
-int dib7090_get_adc_power(struct dvb_frontend *fe)
+static int dib7090_get_adc_power(struct dvb_frontend *fe)
{
return dib7000p_get_adc_power(fe);
}
-EXPORT_SYMBOL(dib7090_get_adc_power);
-int dib7090_slave_reset(struct dvb_frontend *fe)
+static int dib7090_slave_reset(struct dvb_frontend *fe)
{
struct dib7000p_state *state = fe->demodulator_priv;
u16 reg;
@@ -2371,10 +2714,9 @@ int dib7090_slave_reset(struct dvb_frontend *fe)
dib7000p_write_word(state, 1032, 0xffff);
return 0;
}
-EXPORT_SYMBOL(dib7090_slave_reset);
static struct dvb_frontend_ops dib7000p_ops;
-struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
{
struct dvb_frontend *demod;
struct dib7000p_state *st;
@@ -2423,6 +2765,8 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
dib7000p_demod_reset(st);
+ dib7000p_reset_stats(demod);
+
if (st->version == SOC7090) {
dib7090_set_output_mode(demod, st->cfg.output_mode);
dib7090_set_diversity_in(demod, 0);
@@ -2434,6 +2778,31 @@ error:
kfree(st);
return NULL;
}
+
+void *dib7000p_attach(struct dib7000p_ops *ops)
+{
+ if (!ops)
+ return NULL;
+
+ ops->slave_reset = dib7090_slave_reset;
+ ops->get_adc_power = dib7090_get_adc_power;
+ ops->dib7000pc_detection = dib7000pc_detection;
+ ops->get_i2c_tuner = dib7090_get_i2c_tuner;
+ ops->tuner_sleep = dib7090_tuner_sleep;
+ ops->init = dib7000p_init;
+ ops->set_agc1_min = dib7000p_set_agc1_min;
+ ops->set_gpio = dib7000p_set_gpio;
+ ops->i2c_enumeration = dib7000p_i2c_enumeration;
+ ops->pid_filter = dib7000p_pid_filter;
+ ops->pid_filter_ctrl = dib7000p_pid_filter_ctrl;
+ ops->get_i2c_master = dib7000p_get_i2c_master;
+ ops->update_pll = dib7000p_update_pll;
+ ops->ctrl_timf = dib7000p_ctrl_timf;
+ ops->get_agc_values = dib7000p_get_agc_values;
+ ops->set_wbd_ref = dib7000p_set_wbd_ref;
+
+ return ops;
+}
EXPORT_SYMBOL(dib7000p_attach);
static struct dvb_frontend_ops dib7000p_ops = {
diff --git a/drivers/media/dvb-frontends/dib7000p.h b/drivers/media/dvb-frontends/dib7000p.h
index d08cdff59bdf..1fea0e972654 100644
--- a/drivers/media/dvb-frontends/dib7000p.h
+++ b/drivers/media/dvb-frontends/dib7000p.h
@@ -46,121 +46,34 @@ struct dib7000p_config {
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
-#if IS_ENABLED(CONFIG_DVB_DIB7000P)
-extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
-extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
-extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value);
-extern int dib7000pc_detection(struct i2c_adapter *i2c_adap);
-extern int dib7000p_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff);
-extern int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
-extern u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf);
-extern int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff);
-extern int dib7090_get_adc_power(struct dvb_frontend *fe);
-extern struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe);
-extern int dib7090_slave_reset(struct dvb_frontend *fe);
-extern int dib7000p_get_agc_values(struct dvb_frontend *fe,
+struct dib7000p_ops {
+ int (*set_wbd_ref)(struct dvb_frontend *demod, u16 value);
+ int (*get_agc_values)(struct dvb_frontend *fe,
u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd);
-extern int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v);
+ int (*set_agc1_min)(struct dvb_frontend *fe, u16 v);
+ int (*update_pll)(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw);
+ int (*set_gpio)(struct dvb_frontend *demod, u8 num, u8 dir, u8 val);
+ u32 (*ctrl_timf)(struct dvb_frontend *fe, u8 op, u32 timf);
+ int (*dib7000pc_detection)(struct i2c_adapter *i2c_adap);
+ struct i2c_adapter *(*get_i2c_master)(struct dvb_frontend *demod, enum dibx000_i2c_interface intf, int gating);
+ int (*pid_filter_ctrl)(struct dvb_frontend *fe, u8 onoff);
+ int (*pid_filter)(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
+ int (*i2c_enumeration)(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]);
+ struct i2c_adapter *(*get_i2c_tuner)(struct dvb_frontend *fe);
+ int (*tuner_sleep)(struct dvb_frontend *fe, int onoff);
+ int (*get_adc_power)(struct dvb_frontend *fe);
+ int (*slave_reset)(struct dvb_frontend *fe);
+ struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg);
+};
+
+#if IS_ENABLED(CONFIG_DVB_DIB7000P)
+void *dib7000p_attach(struct dib7000p_ops *ops);
#else
-static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg)
+static inline void *dib7000p_attach(struct dib7000p_ops *ops)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
-
-static inline struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-
-static inline int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[])
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000pc_detection(struct i2c_adapter *i2c_adap)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, uint8_t onoff)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth_config *bw)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline u32 dib7000p_ctrl_timf(struct dvb_frontend *fe, u8 op, u32 timf)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return 0;
-}
-
-static inline int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7090_get_adc_power(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline struct i2c_adapter *dib7090_get_i2c_tuner(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-
-static inline int dib7090_slave_reset(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_get_agc_values(struct dvb_frontend *fe,
- u16 *agc_global, u16 *agc1, u16 *agc2, u16 *wbd)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib7000p_set_agc1_min(struct dvb_frontend *fe, u16 v)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
#endif
#endif
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 1632d78a5479..61e31f2d2f71 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -115,7 +115,7 @@ struct dib8000_state {
u16 found_guard;
u8 subchannel;
u8 symbol_duration;
- u32 timeout;
+ unsigned long timeout;
u8 longest_intlv_layer;
u16 output_mode;
@@ -588,8 +588,8 @@ static int dib8000_set_adc_state(struct dib8000_state *state, enum dibx000_adc_s
break;
case DIBX000_ADC_OFF: // leave the VBG voltage on
- reg_907 |= (1 << 14) | (1 << 13) | (1 << 12);
- reg_908 |= (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2);
+ reg_907 = (1 << 13) | (1 << 12);
+ reg_908 = (1 << 6) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 1);
break;
case DIBX000_VBG_ENABLE:
@@ -656,7 +656,7 @@ static int dib8000_sad_calib(struct dib8000_state *state)
return 0;
}
-int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
+static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
{
struct dib8000_state *state = fe->demodulator_priv;
if (value > 4095)
@@ -664,7 +664,6 @@ int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
state->wbd_ref = value;
return dib8000_write_word(state, 106, value);
}
-EXPORT_SYMBOL(dib8000_set_wbd_ref);
static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw)
{
@@ -739,7 +738,7 @@ static void dib8000_reset_pll(struct dib8000_state *state)
dib8000_reset_pll_common(state, pll);
}
-int dib8000_update_pll(struct dvb_frontend *fe,
+static int dib8000_update_pll(struct dvb_frontend *fe,
struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
{
struct dib8000_state *state = fe->demodulator_priv;
@@ -815,8 +814,6 @@ int dib8000_update_pll(struct dvb_frontend *fe,
return 0;
}
-EXPORT_SYMBOL(dib8000_update_pll);
-
static int dib8000_reset_gpio(struct dib8000_state *st)
{
@@ -849,13 +846,12 @@ static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val)
return 0;
}
-int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
+static int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
{
struct dib8000_state *state = fe->demodulator_priv;
return dib8000_cfg_gpio(state, num, dir, val);
}
-EXPORT_SYMBOL(dib8000_set_gpio);
static const u16 dib8000_defaults[] = {
/* auto search configuration - lock0 by default waiting
* for cpil_lock; lock1 cpil_lock; lock2 tmcc_sync_lock */
@@ -1054,6 +1050,7 @@ static int dib8000_reset(struct dvb_frontend *fe)
dib8000_write_word(state, 770, 0xffff);
dib8000_write_word(state, 771, 0xffff);
dib8000_write_word(state, 772, 0xfffc);
+ dib8000_write_word(state, 898, 0x000c); /* restart sad */
if (state->revision == 0x8090)
dib8000_write_word(state, 1280, 0x0045);
else
@@ -1228,20 +1225,19 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band)
return 0;
}
-void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
+static void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
dib8000_set_adc_state(state, DIBX000_ADC_ON);
dib8000_set_agc_config(state, (unsigned char)(BAND_OF_FREQUENCY(fe->dtv_property_cache.frequency / 1000)));
}
-EXPORT_SYMBOL(dib8000_pwm_agc_reset);
static int dib8000_agc_soft_split(struct dib8000_state *state)
{
u16 agc, split_offset;
if (!state->current_agc || !state->current_agc->perform_agc_softsplit || state->current_agc->split.max == 0)
- return FE_CALLBACK_TIME_NEVER;
+ return 0;
// n_agc_global
agc = dib8000_read_word(state, 390);
@@ -1881,14 +1877,13 @@ static struct i2c_algorithm dib8096p_tuner_xfer_algo = {
.functionality = dib8096p_i2c_func,
};
-struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
+static struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
{
struct dib8000_state *st = fe->demodulator_priv;
return &st->dib8096p_tuner_adap;
}
-EXPORT_SYMBOL(dib8096p_get_i2c_tuner);
-int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
+static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
struct dib8000_state *state = fe->demodulator_priv;
u16 en_cur_state;
@@ -1912,14 +1907,13 @@ int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
return 0;
}
-EXPORT_SYMBOL(dib8096p_tuner_sleep);
static const s32 lut_1000ln_mant[] =
{
908, 7003, 7090, 7170, 7244, 7313, 7377, 7438, 7495, 7549, 7600
};
-s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
+static s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
{
struct dib8000_state *state = fe->demodulator_priv;
u32 ix = 0, tmp_val = 0, exp = 0, mant = 0;
@@ -1937,9 +1931,8 @@ s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
}
return val;
}
-EXPORT_SYMBOL(dib8000_get_adc_power);
-int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
+static int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
{
struct dib8000_state *state = fe->demodulator_priv;
int val = 0;
@@ -1957,7 +1950,6 @@ int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
return val;
}
-EXPORT_SYMBOL(dib8090p_get_dc_power);
static void dib8000_update_timf(struct dib8000_state *state)
{
@@ -1968,7 +1960,7 @@ static void dib8000_update_timf(struct dib8000_state *state)
dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default);
}
-u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
+static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
{
struct dib8000_state *state = fe->demodulator_priv;
@@ -1986,21 +1978,11 @@ u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf)
return state->timf;
}
-EXPORT_SYMBOL(dib8000_ctrl_timf);
static const u16 adc_target_16dB[11] = {
- (1 << 13) - 825 - 117,
- (1 << 13) - 837 - 117,
- (1 << 13) - 811 - 117,
- (1 << 13) - 766 - 117,
- (1 << 13) - 737 - 117,
- (1 << 13) - 693 - 117,
- (1 << 13) - 648 - 117,
- (1 << 13) - 619 - 117,
- (1 << 13) - 575 - 117,
- (1 << 13) - 531 - 117,
- (1 << 13) - 501 - 117
+ 7250, 7238, 7264, 7309, 7338, 7382, 7427, 7456, 7500, 7544, 7574
};
+
static const u8 permu_seg[] = { 6, 5, 7, 4, 8, 3, 9, 2, 10, 1, 11, 0, 12 };
static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 max_constellation)
@@ -2043,9 +2025,8 @@ static u16 dib8000_set_layer(struct dib8000_state *state, u8 layer_index, u16 ma
break;
}
- if ((c->layer[layer_index].interleaving > 0) && ((c->layer[layer_index].interleaving <= 3) || (c->layer[layer_index].interleaving == 4 && c->isdbt_sb_mode == 1)))
- time_intlv = c->layer[layer_index].interleaving;
- else
+ time_intlv = fls(c->layer[layer_index].interleaving);
+ if (time_intlv > 3 && !(time_intlv == 4 && c->isdbt_sb_mode == 1))
time_intlv = 0;
dib8000_write_word(state, 2 + layer_index, (constellation << 10) | ((c->layer[layer_index].segment_count & 0xf) << 6) | (cr << 3) | time_intlv);
@@ -2362,6 +2343,9 @@ static void dib8000_set_isdbt_common_channel(struct dib8000_state *state, u8 seq
int init_prbs;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+ if (autosearching)
+ c->isdbt_partial_reception = 1;
+
/* P_mode */
dib8000_write_word(state, 10, (seq << 4));
@@ -2856,12 +2840,12 @@ static void dib8000_set_sync_wait(struct dib8000_state *state)
dib8000_write_word(state, 273, (dib8000_read_word(state, 273) & 0x000f) | (sync_wait << 4));
}
-static u32 dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
+static unsigned long dib8000_get_timeout(struct dib8000_state *state, u32 delay, enum timeout_mode mode)
{
if (mode == SYMBOL_DEPENDENT_ON)
- return systime() + (delay * state->symbol_duration);
- else
- return systime() + delay;
+ delay *= state->symbol_duration;
+
+ return jiffies + usecs_to_jiffies(delay * 100);
}
static s32 dib8000_get_status(struct dvb_frontend *fe)
@@ -2870,21 +2854,19 @@ static s32 dib8000_get_status(struct dvb_frontend *fe)
return state->status;
}
-enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
+static enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
return state->tune_state;
}
-EXPORT_SYMBOL(dib8000_get_tune_state);
-int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+static int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
{
struct dib8000_state *state = fe->demodulator_priv;
state->tune_state = tune_state;
return 0;
}
-EXPORT_SYMBOL(dib8000_set_tune_state);
static int dib8000_tune_restart_from_demod(struct dvb_frontend *fe)
{
@@ -3015,8 +2997,8 @@ static int dib8000_tune(struct dvb_frontend *fe)
u16 locks, deeper_interleaver = 0, i;
int ret = 1; /* 1 symbol duration (in 100us unit) delay most of the time */
- u32 *timeout = &state->timeout;
- u32 now = systime();
+ unsigned long *timeout = &state->timeout;
+ unsigned long now = jiffies;
#ifdef DIB8000_AGC_FREEZE
u16 agc1, agc2;
#endif
@@ -3026,318 +3008,327 @@ static int dib8000_tune(struct dvb_frontend *fe)
#if 0
if (*tune_state < CT_DEMOD_STOP)
- dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u systime = %u", state->channel_parameters_set, *tune_state, state->autosearch_state, now);
+ dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu",
+ state->channel_parameters_set, *tune_state, state->autosearch_state, now);
#endif
switch (*tune_state) {
case CT_DEMOD_START: /* 30 */
- dib8000_reset_stats(fe);
+ dib8000_reset_stats(fe);
- if (state->revision == 0x8090)
- dib8090p_init_sdram(state);
- state->status = FE_STATUS_TUNE_PENDING;
- state->channel_parameters_set = is_manual_mode(c);
+ if (state->revision == 0x8090)
+ dib8090p_init_sdram(state);
+ state->status = FE_STATUS_TUNE_PENDING;
+ state->channel_parameters_set = is_manual_mode(c);
- dprintk("Tuning channel on %s search mode",
- state->channel_parameters_set ? "manual" : "auto");
+ dprintk("Tuning channel on %s search mode",
+ state->channel_parameters_set ? "manual" : "auto");
- dib8000_viterbi_state(state, 0); /* force chan dec in restart */
+ dib8000_viterbi_state(state, 0); /* force chan dec in restart */
- /* Layer monitor */
- dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
+ /* Layer monitor */
+ dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
- dib8000_set_frequency_offset(state);
- dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
+ dib8000_set_frequency_offset(state);
+ dib8000_set_bandwidth(fe, c->bandwidth_hz / 1000);
- if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
+ if (state->channel_parameters_set == 0) { /* The channel struct is unknown, search it ! */
#ifdef DIB8000_AGC_FREEZE
- if (state->revision != 0x8090) {
- state->agc1_max = dib8000_read_word(state, 108);
- state->agc1_min = dib8000_read_word(state, 109);
- state->agc2_max = dib8000_read_word(state, 110);
- state->agc2_min = dib8000_read_word(state, 111);
- agc1 = dib8000_read_word(state, 388);
- agc2 = dib8000_read_word(state, 389);
- dib8000_write_word(state, 108, agc1);
- dib8000_write_word(state, 109, agc1);
- dib8000_write_word(state, 110, agc2);
- dib8000_write_word(state, 111, agc2);
- }
-#endif
- state->autosearch_state = AS_SEARCHING_FFT;
- state->found_nfft = TRANSMISSION_MODE_AUTO;
- state->found_guard = GUARD_INTERVAL_AUTO;
- *tune_state = CT_DEMOD_SEARCH_NEXT;
- } else { /* we already know the channel struct so TUNE only ! */
- state->autosearch_state = AS_DONE;
- *tune_state = CT_DEMOD_STEP_3;
+ if (state->revision != 0x8090) {
+ state->agc1_max = dib8000_read_word(state, 108);
+ state->agc1_min = dib8000_read_word(state, 109);
+ state->agc2_max = dib8000_read_word(state, 110);
+ state->agc2_min = dib8000_read_word(state, 111);
+ agc1 = dib8000_read_word(state, 388);
+ agc2 = dib8000_read_word(state, 389);
+ dib8000_write_word(state, 108, agc1);
+ dib8000_write_word(state, 109, agc1);
+ dib8000_write_word(state, 110, agc2);
+ dib8000_write_word(state, 111, agc2);
}
- state->symbol_duration = dib8000_get_symbol_duration(state);
- break;
+#endif
+ state->autosearch_state = AS_SEARCHING_FFT;
+ state->found_nfft = TRANSMISSION_MODE_AUTO;
+ state->found_guard = GUARD_INTERVAL_AUTO;
+ *tune_state = CT_DEMOD_SEARCH_NEXT;
+ } else { /* we already know the channel struct so TUNE only ! */
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STEP_3;
+ }
+ state->symbol_duration = dib8000_get_symbol_duration(state);
+ break;
case CT_DEMOD_SEARCH_NEXT: /* 51 */
- dib8000_autosearch_start(fe);
+ dib8000_autosearch_start(fe);
+ if (state->revision == 0x8090)
+ ret = 50;
+ else
+ ret = 15;
+ *tune_state = CT_DEMOD_STEP_1;
+ break;
+
+ case CT_DEMOD_STEP_1: /* 31 */
+ switch (dib8000_autosearch_irq(fe)) {
+ case 1: /* fail */
+ state->status = FE_STATUS_TUNE_FAILED;
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STOP; /* else we are done here */
+ break;
+ case 2: /* Succes */
+ state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
+ *tune_state = CT_DEMOD_STEP_3;
+ if (state->autosearch_state == AS_SEARCHING_GUARD)
+ *tune_state = CT_DEMOD_STEP_2;
+ else
+ state->autosearch_state = AS_DONE;
+ break;
+ case 3: /* Autosearch FFT max correlation endded */
+ *tune_state = CT_DEMOD_STEP_2;
+ break;
+ }
+ break;
+
+ case CT_DEMOD_STEP_2:
+ switch (state->autosearch_state) {
+ case AS_SEARCHING_FFT:
+ /* searching for the correct FFT */
+ if (state->revision == 0x8090) {
+ corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+ corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+ corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
+ } else {
+ corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
+ corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
+ corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
+ }
+ /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
+
+ max_value = 0;
+ for (find_index = 1 ; find_index < 3 ; find_index++) {
+ if (corm[max_value] < corm[find_index])
+ max_value = find_index ;
+ }
+
+ switch (max_value) {
+ case 0:
+ state->found_nfft = TRANSMISSION_MODE_2K;
+ break;
+ case 1:
+ state->found_nfft = TRANSMISSION_MODE_4K;
+ break;
+ case 2:
+ default:
+ state->found_nfft = TRANSMISSION_MODE_8K;
+ break;
+ }
+ /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
+
+ *tune_state = CT_DEMOD_SEARCH_NEXT;
+ state->autosearch_state = AS_SEARCHING_GUARD;
if (state->revision == 0x8090)
ret = 50;
else
- ret = 15;
- *tune_state = CT_DEMOD_STEP_1;
+ ret = 10;
break;
+ case AS_SEARCHING_GUARD:
+ /* searching for the correct guard interval */
+ if (state->revision == 0x8090)
+ state->found_guard = dib8000_read_word(state, 572) & 0x3;
+ else
+ state->found_guard = dib8000_read_word(state, 570) & 0x3;
+ /* dprintk("guard interval found=%i", state->found_guard); */
- case CT_DEMOD_STEP_1: /* 31 */
- switch (dib8000_autosearch_irq(fe)) {
- case 1: /* fail */
- state->status = FE_STATUS_TUNE_FAILED;
- state->autosearch_state = AS_DONE;
- *tune_state = CT_DEMOD_STOP; /* else we are done here */
- break;
- case 2: /* Succes */
- state->status = FE_STATUS_FFT_SUCCESS; /* signal to the upper layer, that there was a channel found and the parameters can be read */
- *tune_state = CT_DEMOD_STEP_3;
- if (state->autosearch_state == AS_SEARCHING_GUARD)
- *tune_state = CT_DEMOD_STEP_2;
- else
- state->autosearch_state = AS_DONE;
- break;
- case 3: /* Autosearch FFT max correlation endded */
- *tune_state = CT_DEMOD_STEP_2;
- break;
- }
+ *tune_state = CT_DEMOD_STEP_3;
break;
-
- case CT_DEMOD_STEP_2:
- switch (state->autosearch_state) {
- case AS_SEARCHING_FFT:
- /* searching for the correct FFT */
- if (state->revision == 0x8090) {
- corm[2] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
- corm[1] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
- corm[0] = (dib8000_read_word(state, 600) << 16) | (dib8000_read_word(state, 601));
- } else {
- corm[2] = (dib8000_read_word(state, 594) << 16) | (dib8000_read_word(state, 595));
- corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597));
- corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599));
- }
- /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */
-
- max_value = 0;
- for (find_index = 1 ; find_index < 3 ; find_index++) {
- if (corm[max_value] < corm[find_index])
- max_value = find_index ;
- }
-
- switch (max_value) {
- case 0:
- state->found_nfft = TRANSMISSION_MODE_2K;
- break;
- case 1:
- state->found_nfft = TRANSMISSION_MODE_4K;
- break;
- case 2:
- default:
- state->found_nfft = TRANSMISSION_MODE_8K;
- break;
- }
- /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */
-
- *tune_state = CT_DEMOD_SEARCH_NEXT;
- state->autosearch_state = AS_SEARCHING_GUARD;
- if (state->revision == 0x8090)
- ret = 50;
- else
- ret = 10;
- break;
- case AS_SEARCHING_GUARD:
- /* searching for the correct guard interval */
- if (state->revision == 0x8090)
- state->found_guard = dib8000_read_word(state, 572) & 0x3;
- else
- state->found_guard = dib8000_read_word(state, 570) & 0x3;
- /* dprintk("guard interval found=%i", state->found_guard); */
-
- *tune_state = CT_DEMOD_STEP_3;
- break;
- default:
- /* the demod should never be in this state */
- state->status = FE_STATUS_TUNE_FAILED;
- state->autosearch_state = AS_DONE;
- *tune_state = CT_DEMOD_STOP; /* else we are done here */
- break;
- }
+ default:
+ /* the demod should never be in this state */
+ state->status = FE_STATUS_TUNE_FAILED;
+ state->autosearch_state = AS_DONE;
+ *tune_state = CT_DEMOD_STOP; /* else we are done here */
break;
+ }
+ break;
case CT_DEMOD_STEP_3: /* 33 */
- state->symbol_duration = dib8000_get_symbol_duration(state);
- dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
- dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
- *tune_state = CT_DEMOD_STEP_4;
- break;
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_1);
+ dib8000_set_isdbt_common_channel(state, 0, 0);/* setting the known channel parameters here */
+ *tune_state = CT_DEMOD_STEP_4;
+ break;
case CT_DEMOD_STEP_4: /* (34) */
- dib8000_demod_restart(state);
+ dib8000_demod_restart(state);
- dib8000_set_sync_wait(state);
- dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
+ dib8000_set_sync_wait(state);
+ dib8000_set_diversity_in(state->fe[0], state->diversity_onoff);
- locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
- /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
- *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
- *tune_state = CT_DEMOD_STEP_5;
- break;
+ locks = (dib8000_read_word(state, 180) >> 6) & 0x3f; /* P_coff_winlen ? */
+ /* coff should lock over P_coff_winlen ofdm symbols : give 3 times this length to lock */
+ *timeout = dib8000_get_timeout(state, 2 * locks, SYMBOL_DEPENDENT_ON);
+ *tune_state = CT_DEMOD_STEP_5;
+ break;
case CT_DEMOD_STEP_5: /* (35) */
- locks = dib8000_read_lock(fe);
- if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
- dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
- if (!state->differential_constellation) {
- /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
- *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
- *tune_state = CT_DEMOD_STEP_7;
- } else {
- *tune_state = CT_DEMOD_STEP_8;
- }
- } else if (now > *timeout) {
- *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ locks = dib8000_read_lock(fe);
+ if (locks & (0x3 << 11)) { /* coff-lock and off_cpil_lock achieved */
+ dib8000_update_timf(state); /* we achieved a coff_cpil_lock - it's time to update the timf */
+ if (!state->differential_constellation) {
+ /* 2 times lmod4_win_len + 10 symbols (pipe delay after coff + nb to compute a 1st correlation) */
+ *timeout = dib8000_get_timeout(state, (20 * ((dib8000_read_word(state, 188)>>5)&0x1f)), SYMBOL_DEPENDENT_ON);
+ *tune_state = CT_DEMOD_STEP_7;
+ } else {
+ *tune_state = CT_DEMOD_STEP_8;
}
- break;
+ } else if (time_after(now, *timeout)) {
+ *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ }
+ break;
case CT_DEMOD_STEP_6: /* (36) if there is an input (diversity) */
- if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
- /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
- if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
- *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
- else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
- *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
- dib8000_viterbi_state(state, 1); /* start viterbi chandec */
- dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
- state->status = FE_STATUS_TUNE_FAILED;
- }
- } else {
+ if ((state->fe[1] != NULL) && (state->output_mode != OUTMODE_DIVERSITY)) {
+ /* if there is a diversity fe in input and this fe is has not already failled : wait here until this this fe has succedeed or failled */
+ if (dib8000_get_status(state->fe[1]) <= FE_STATUS_STD_SUCCESS) /* Something is locked on the input fe */
+ *tune_state = CT_DEMOD_STEP_8; /* go for mpeg */
+ else if (dib8000_get_status(state->fe[1]) >= FE_STATUS_TUNE_TIME_TOO_SHORT) { /* fe in input failled also, break the current one */
+ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
dib8000_viterbi_state(state, 1); /* start viterbi chandec */
dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
- *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
state->status = FE_STATUS_TUNE_FAILED;
}
- break;
-
- case CT_DEMOD_STEP_7: /* 37 */
- locks = dib8000_read_lock(fe);
- if (locks & (1<<10)) { /* lmod4_lock */
- ret = 14; /* wait for 14 symbols */
- *tune_state = CT_DEMOD_STEP_8;
- } else if (now > *timeout)
- *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
- break;
-
- case CT_DEMOD_STEP_8: /* 38 */
+ } else {
dib8000_viterbi_state(state, 1); /* start viterbi chandec */
dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+ *tune_state = CT_DEMOD_STOP; /* else we are done here ; step 8 will close the loops and exit */
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ break;
- /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
- if (c->isdbt_sb_mode
- && c->isdbt_sb_subchannel < 14
- && !state->differential_constellation) {
- state->subchannel = 0;
- *tune_state = CT_DEMOD_STEP_11;
- } else {
- *tune_state = CT_DEMOD_STEP_9;
- state->status = FE_STATUS_LOCKED;
- }
- break;
+ case CT_DEMOD_STEP_7: /* 37 */
+ locks = dib8000_read_lock(fe);
+ if (locks & (1<<10)) { /* lmod4_lock */
+ ret = 14; /* wait for 14 symbols */
+ *tune_state = CT_DEMOD_STEP_8;
+ } else if (time_after(now, *timeout))
+ *tune_state = CT_DEMOD_STEP_6; /* goto check for diversity input connection */
+ break;
+
+ case CT_DEMOD_STEP_8: /* 38 */
+ dib8000_viterbi_state(state, 1); /* start viterbi chandec */
+ dib8000_set_isdbt_loop_params(state, LOOP_TUNE_2);
+
+ /* mpeg will never lock on this condition because init_prbs is not set : search for it !*/
+ if (c->isdbt_sb_mode
+ && c->isdbt_sb_subchannel < 14
+ && !state->differential_constellation) {
+ state->subchannel = 0;
+ *tune_state = CT_DEMOD_STEP_11;
+ } else {
+ *tune_state = CT_DEMOD_STEP_9;
+ state->status = FE_STATUS_LOCKED;
+ }
+ break;
case CT_DEMOD_STEP_9: /* 39 */
- if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
- /* defines timeout for mpeg lock depending on interleaver length of longest layer */
- for (i = 0; i < 3; i++) {
- if (c->layer[i].interleaving >= deeper_interleaver) {
- dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
- if (c->layer[i].segment_count > 0) { /* valid layer */
- deeper_interleaver = c->layer[0].interleaving;
- state->longest_intlv_layer = i;
- }
+ if ((state->revision == 0x8090) || ((dib8000_read_word(state, 1291) >> 9) & 0x1)) { /* fe capable of deinterleaving : esram */
+ /* defines timeout for mpeg lock depending on interleaver length of longest layer */
+ for (i = 0; i < 3; i++) {
+ if (c->layer[i].interleaving >= deeper_interleaver) {
+ dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving);
+ if (c->layer[i].segment_count > 0) { /* valid layer */
+ deeper_interleaver = c->layer[0].interleaving;
+ state->longest_intlv_layer = i;
}
}
+ }
- if (deeper_interleaver == 0)
- locks = 2; /* locks is the tmp local variable name */
- else if (deeper_interleaver == 3)
- locks = 8;
- else
- locks = 2 * deeper_interleaver;
+ if (deeper_interleaver == 0)
+ locks = 2; /* locks is the tmp local variable name */
+ else if (deeper_interleaver == 3)
+ locks = 8;
+ else
+ locks = 2 * deeper_interleaver;
- if (state->diversity_onoff != 0) /* because of diversity sync */
- locks *= 2;
+ if (state->diversity_onoff != 0) /* because of diversity sync */
+ locks *= 2;
- *timeout = now + (2000 * locks); /* give the mpeg lock 800ms if sram is present */
- dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %d", deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
+ *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */
+ dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld",
+ deeper_interleaver, state->longest_intlv_layer, locks, *timeout);
- *tune_state = CT_DEMOD_STEP_10;
- } else
- *tune_state = CT_DEMOD_STOP;
- break;
+ *tune_state = CT_DEMOD_STEP_10;
+ } else
+ *tune_state = CT_DEMOD_STOP;
+ break;
case CT_DEMOD_STEP_10: /* 40 */
- locks = dib8000_read_lock(fe);
- if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
- dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
- if (c->isdbt_sb_mode
- && c->isdbt_sb_subchannel < 14
- && !state->differential_constellation)
- /* signal to the upper layer, that there was a channel found and the parameters can be read */
- state->status = FE_STATUS_DEMOD_SUCCESS;
- else
+ locks = dib8000_read_lock(fe);
+ if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */
+ dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s",
+ c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+ c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+ c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
+ if (c->isdbt_sb_mode
+ && c->isdbt_sb_subchannel < 14
+ && !state->differential_constellation)
+ /* signal to the upper layer, that there was a channel found and the parameters can be read */
+ state->status = FE_STATUS_DEMOD_SUCCESS;
+ else
+ state->status = FE_STATUS_DATA_LOCKED;
+ *tune_state = CT_DEMOD_STOP;
+ } else if (time_after(now, *timeout)) {
+ if (c->isdbt_sb_mode
+ && c->isdbt_sb_subchannel < 14
+ && !state->differential_constellation) { /* continue to try init prbs autosearch */
+ state->subchannel += 3;
+ *tune_state = CT_DEMOD_STEP_11;
+ } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
+ if (locks & (0x7 << 5)) {
+ dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s",
+ jiffies_to_msecs(now - *timeout),
+ c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+ c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled",
+ c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled");
+
state->status = FE_STATUS_DATA_LOCKED;
+ } else
+ state->status = FE_STATUS_TUNE_FAILED;
*tune_state = CT_DEMOD_STOP;
- } else if (now > *timeout) {
- if (c->isdbt_sb_mode
- && c->isdbt_sb_subchannel < 14
- && !state->differential_constellation) { /* continue to try init prbs autosearch */
- state->subchannel += 3;
- *tune_state = CT_DEMOD_STEP_11;
- } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */
- if (locks & (0x7<<5)) {
- dprintk("Mpeg locks [ L0 : %d | L1 : %d | L2 : %d ]", (locks>>7)&0x1, (locks>>6)&0x1, (locks>>5)&0x1);
- state->status = FE_STATUS_DATA_LOCKED;
- } else
- state->status = FE_STATUS_TUNE_FAILED;
- *tune_state = CT_DEMOD_STOP;
- }
}
- break;
+ }
+ break;
case CT_DEMOD_STEP_11: /* 41 : init prbs autosearch */
- if (state->subchannel <= 41) {
- dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
- *tune_state = CT_DEMOD_STEP_9;
- } else {
- *tune_state = CT_DEMOD_STOP;
- state->status = FE_STATUS_TUNE_FAILED;
- }
- break;
+ if (state->subchannel <= 41) {
+ dib8000_set_subchannel_prbs(state, dib8000_get_init_prbs(state, state->subchannel));
+ *tune_state = CT_DEMOD_STEP_9;
+ } else {
+ *tune_state = CT_DEMOD_STOP;
+ state->status = FE_STATUS_TUNE_FAILED;
+ }
+ break;
default:
- break;
+ break;
}
/* tuning is finished - cleanup the demod */
switch (*tune_state) {
case CT_DEMOD_STOP: /* (42) */
#ifdef DIB8000_AGC_FREEZE
- if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
- dib8000_write_word(state, 108, state->agc1_max);
- dib8000_write_word(state, 109, state->agc1_min);
- dib8000_write_word(state, 110, state->agc2_max);
- dib8000_write_word(state, 111, state->agc2_min);
- state->agc1_max = 0;
- state->agc1_min = 0;
- state->agc2_max = 0;
- state->agc2_min = 0;
- }
+ if ((state->revision != 0x8090) && (state->agc1_max != 0)) {
+ dib8000_write_word(state, 108, state->agc1_max);
+ dib8000_write_word(state, 109, state->agc1_min);
+ dib8000_write_word(state, 110, state->agc2_max);
+ dib8000_write_word(state, 111, state->agc2_min);
+ state->agc1_max = 0;
+ state->agc1_min = 0;
+ state->agc2_max = 0;
+ state->agc2_min = 0;
+ }
#endif
- ret = FE_CALLBACK_TIME_NEVER;
- break;
+ ret = 0;
+ break;
default:
- break;
+ break;
}
if ((ret > 0) && (*tune_state > CT_DEMOD_STEP_3))
@@ -3408,7 +3399,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
if (!(stat & FE_HAS_SYNC))
return 0;
- dprintk("TMCC lock");
+ dprintk("dib8000_get_frontend: TMCC lock");
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
if (stat&FE_HAS_SYNC) {
@@ -3444,91 +3435,117 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
switch ((val & 0x30) >> 4) {
case 1:
fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_2K;
+ dprintk("dib8000_get_frontend: transmission mode 2K");
+ break;
+ case 2:
+ fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_4K;
+ dprintk("dib8000_get_frontend: transmission mode 4K");
break;
case 3:
default:
fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_8K;
+ dprintk("dib8000_get_frontend: transmission mode 8K");
break;
}
switch (val & 0x3) {
case 0:
fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_32;
- dprintk("dib8000_get_frontend GI = 1/32 ");
+ dprintk("dib8000_get_frontend: Guard Interval = 1/32 ");
break;
case 1:
fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_16;
- dprintk("dib8000_get_frontend GI = 1/16 ");
+ dprintk("dib8000_get_frontend: Guard Interval = 1/16 ");
break;
case 2:
- dprintk("dib8000_get_frontend GI = 1/8 ");
+ dprintk("dib8000_get_frontend: Guard Interval = 1/8 ");
fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_8;
break;
case 3:
- dprintk("dib8000_get_frontend GI = 1/4 ");
+ dprintk("dib8000_get_frontend: Guard Interval = 1/4 ");
fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_1_4;
break;
}
val = dib8000_read_word(state, 505);
fe->dtv_property_cache.isdbt_partial_reception = val & 1;
- dprintk("dib8000_get_frontend : partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
+ dprintk("dib8000_get_frontend: partial_reception = %d ", fe->dtv_property_cache.isdbt_partial_reception);
for (i = 0; i < 3; i++) {
- val = dib8000_read_word(state, 493 + i);
- fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
- dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
+ int show;
+
+ val = dib8000_read_word(state, 493 + i) & 0x0f;
+ fe->dtv_property_cache.layer[i].segment_count = val;
+
+ if (val == 0 || val > 13)
+ show = 0;
+ else
+ show = 1;
+
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d segments = %d ",
+ i, fe->dtv_property_cache.layer[i].segment_count);
val = dib8000_read_word(state, 499 + i) & 0x3;
/* Interleaving can be 0, 1, 2 or 4 */
if (val == 3)
val = 4;
fe->dtv_property_cache.layer[i].interleaving = val;
- dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
- i, fe->dtv_property_cache.layer[i].interleaving);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ",
+ i, fe->dtv_property_cache.layer[i].interleaving);
val = dib8000_read_word(state, 481 + i);
switch (val & 0x7) {
case 1:
fe->dtv_property_cache.layer[i].fec = FEC_1_2;
- dprintk("dib8000_get_frontend : Layer %d Code Rate = 1/2 ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i);
break;
case 2:
fe->dtv_property_cache.layer[i].fec = FEC_2_3;
- dprintk("dib8000_get_frontend : Layer %d Code Rate = 2/3 ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i);
break;
case 3:
fe->dtv_property_cache.layer[i].fec = FEC_3_4;
- dprintk("dib8000_get_frontend : Layer %d Code Rate = 3/4 ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i);
break;
case 5:
fe->dtv_property_cache.layer[i].fec = FEC_5_6;
- dprintk("dib8000_get_frontend : Layer %d Code Rate = 5/6 ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i);
break;
default:
fe->dtv_property_cache.layer[i].fec = FEC_7_8;
- dprintk("dib8000_get_frontend : Layer %d Code Rate = 7/8 ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i);
break;
}
val = dib8000_read_word(state, 487 + i);
switch (val & 0x3) {
case 0:
- dprintk("dib8000_get_frontend : Layer %d DQPSK ", i);
fe->dtv_property_cache.layer[i].modulation = DQPSK;
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d DQPSK ", i);
break;
case 1:
fe->dtv_property_cache.layer[i].modulation = QPSK;
- dprintk("dib8000_get_frontend : Layer %d QPSK ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d QPSK ", i);
break;
case 2:
fe->dtv_property_cache.layer[i].modulation = QAM_16;
- dprintk("dib8000_get_frontend : Layer %d QAM16 ", i);
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d QAM16 ", i);
break;
case 3:
default:
- dprintk("dib8000_get_frontend : Layer %d QAM64 ", i);
fe->dtv_property_cache.layer[i].modulation = QAM_64;
+ if (show)
+ dprintk("dib8000_get_frontend: Layer %d QAM64 ", i);
break;
}
}
@@ -3554,9 +3571,9 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
- int l, i, active, time, time_slave = FE_CALLBACK_TIME_NEVER;
+ int l, i, active, time, time_slave = 0;
u8 exit_condition, index_frontend;
- u32 delay, callback_time;
+ unsigned long delay, callback_time;
if (c->frequency == 0) {
dprintk("dib8000: must at least specify frequency ");
@@ -3608,15 +3625,24 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
time = dib8000_agc_startup(state->fe[0]);
for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
time_slave = dib8000_agc_startup(state->fe[index_frontend]);
- if (time == FE_CALLBACK_TIME_NEVER)
+ if (time == 0)
time = time_slave;
- else if ((time_slave != FE_CALLBACK_TIME_NEVER) && (time_slave > time))
+ else if ((time_slave != 0) && (time_slave > time))
time = time_slave;
}
- if (time != FE_CALLBACK_TIME_NEVER)
- msleep(time / 10);
- else
+ if (time == 0)
break;
+
+ /*
+ * Despite dib8000_agc_startup returns time at a 0.1 ms range,
+ * the actual sleep time depends on CONFIG_HZ. The worse case
+ * is when CONFIG_HZ=100. In such case, the minimum granularity
+ * is 10ms. On some real field tests, the tuner sometimes don't
+ * lock when this timer is lower than 10ms. So, enforce a 10ms
+ * granularity.
+ */
+ time = 10 * (time + 99)/100;
+ usleep_range(time * 1000, (time + 1) * 1000);
exit_condition = 1;
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
if (dib8000_get_tune_state(state->fe[index_frontend]) != CT_AGC_STOP) {
@@ -3631,11 +3657,14 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
active = 1;
do {
- callback_time = FE_CALLBACK_TIME_NEVER;
+ callback_time = 0;
for (index_frontend = 0; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
delay = dib8000_tune(state->fe[index_frontend]);
- if (delay != FE_CALLBACK_TIME_NEVER)
- delay += systime();
+ if (delay != 0) {
+ delay = jiffies + usecs_to_jiffies(100 * delay);
+ if (!callback_time || delay < callback_time)
+ callback_time = delay;
+ }
/* we are in autosearch */
if (state->channel_parameters_set == 0) { /* searching */
@@ -3646,6 +3675,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
for (l = 0; (l < MAX_NUMBER_OF_FRONTENDS) && (state->fe[l] != NULL); l++) {
if (l != index_frontend) { /* and for all frontend except the successful one */
+ dprintk("Restarting frontend %d\n", l);
dib8000_tune_restart_from_demod(state->fe[l]);
state->fe[l]->dtv_property_cache.isdbt_sb_mode = state->fe[index_frontend]->dtv_property_cache.isdbt_sb_mode;
@@ -3664,8 +3694,6 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
}
}
}
- if (delay < callback_time)
- callback_time = delay;
}
/* tuning is done when the master frontend is done (failed or success) */
if (dib8000_get_status(state->fe[0]) == FE_STATUS_TUNE_FAILED ||
@@ -3681,12 +3709,12 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
dprintk("tuning done with status %d", dib8000_get_status(state->fe[0]));
}
- if ((active == 1) && (callback_time == FE_CALLBACK_TIME_NEVER)) {
+ if ((active == 1) && (callback_time == 0)) {
dprintk("strange callback time something went wrong");
active = 0;
}
- while ((active == 1) && (systime() < callback_time))
+ while ((active == 1) && (time_before(jiffies, callback_time)))
msleep(100);
} while (active);
@@ -4201,7 +4229,7 @@ static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
return 0;
}
-int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
+static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
{
struct dib8000_state *state = fe->demodulator_priv;
u8 index_frontend = 1;
@@ -4217,9 +4245,8 @@ int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_
dprintk("too many slave frontend");
return -ENOMEM;
}
-EXPORT_SYMBOL(dib8000_set_slave_frontend);
-int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
+static int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
{
struct dib8000_state *state = fe->demodulator_priv;
u8 index_frontend = 1;
@@ -4235,9 +4262,8 @@ int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
dprintk("no frontend to be removed");
return -ENODEV;
}
-EXPORT_SYMBOL(dib8000_remove_slave_frontend);
-struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+static struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
{
struct dib8000_state *state = fe->demodulator_priv;
@@ -4245,10 +4271,8 @@ struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int sla
return NULL;
return state->fe[slave_index];
}
-EXPORT_SYMBOL(dib8000_get_slave_frontend);
-
-int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
+static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
u8 default_addr, u8 first_addr, u8 is_dib8096p)
{
int k = 0, ret = 0;
@@ -4325,7 +4349,6 @@ error_memory_read:
return ret;
}
-EXPORT_SYMBOL(dib8000_i2c_enumeration);
static int dib8000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1000;
@@ -4348,15 +4371,13 @@ static void dib8000_release(struct dvb_frontend *fe)
kfree(st);
}
-struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
+static struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating)
{
struct dib8000_state *st = fe->demodulator_priv;
return dibx000_get_i2c_adapter(&st->i2c_master, intf, gating);
}
-EXPORT_SYMBOL(dib8000_get_i2c_master);
-
-int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
{
struct dib8000_state *st = fe->demodulator_priv;
u16 val = dib8000_read_word(st, 299) & 0xffef;
@@ -4365,15 +4386,13 @@ int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
dprintk("pid filter enabled %d", onoff);
return dib8000_write_word(st, 299, val);
}
-EXPORT_SYMBOL(dib8000_pid_filter_ctrl);
-int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
{
struct dib8000_state *st = fe->demodulator_priv;
dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0);
}
-EXPORT_SYMBOL(dib8000_pid_filter);
static const struct dvb_frontend_ops dib8000_ops = {
.delsys = { SYS_ISDBT },
@@ -4405,12 +4424,12 @@ static const struct dvb_frontend_ops dib8000_ops = {
.read_ucblocks = dib8000_read_unc_blocks,
};
-struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
+static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
{
struct dvb_frontend *fe;
struct dib8000_state *state;
- dprintk("dib8000_attach");
+ dprintk("dib8000_init");
state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL);
if (state == NULL)
@@ -4467,6 +4486,33 @@ error:
return NULL;
}
+void *dib8000_attach(struct dib8000_ops *ops)
+{
+ if (!ops)
+ return NULL;
+
+ ops->pwm_agc_reset = dib8000_pwm_agc_reset;
+ ops->get_dc_power = dib8090p_get_dc_power;
+ ops->set_gpio = dib8000_set_gpio;
+ ops->get_slave_frontend = dib8000_get_slave_frontend;
+ ops->set_tune_state = dib8000_set_tune_state;
+ ops->pid_filter_ctrl = dib8000_pid_filter_ctrl;
+ ops->remove_slave_frontend = dib8000_remove_slave_frontend;
+ ops->get_adc_power = dib8000_get_adc_power;
+ ops->update_pll = dib8000_update_pll;
+ ops->tuner_sleep = dib8096p_tuner_sleep;
+ ops->get_tune_state = dib8000_get_tune_state;
+ ops->get_i2c_tuner = dib8096p_get_i2c_tuner;
+ ops->set_slave_frontend = dib8000_set_slave_frontend;
+ ops->pid_filter = dib8000_pid_filter;
+ ops->ctrl_timf = dib8000_ctrl_timf;
+ ops->init = dib8000_init;
+ ops->get_i2c_master = dib8000_get_i2c_master;
+ ops->i2c_enumeration = dib8000_i2c_enumeration;
+ ops->set_wbd_ref = dib8000_set_wbd_ref;
+
+ return ops;
+}
EXPORT_SYMBOL(dib8000_attach);
MODULE_AUTHOR("Olivier Grenie ");
diff --git a/drivers/media/dvb-frontends/dib8000.h b/drivers/media/dvb-frontends/dib8000.h
index b8c11e52c512..84cc10383dcd 100644
--- a/drivers/media/dvb-frontends/dib8000.h
+++ b/drivers/media/dvb-frontends/dib8000.h
@@ -39,134 +39,34 @@ struct dib8000_config {
#define DEFAULT_DIB8000_I2C_ADDRESS 18
-#if IS_ENABLED(CONFIG_DVB_DIB8000)
-extern struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
-extern struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int);
-
-extern int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods,
- u8 default_addr, u8 first_addr, u8 is_dib8096p);
-
-extern int dib8000_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val);
-extern int dib8000_set_wbd_ref(struct dvb_frontend *, u16 value);
-extern int dib8000_pid_filter_ctrl(struct dvb_frontend *, u8 onoff);
-extern int dib8000_pid_filter(struct dvb_frontend *, u8 id, u16 pid, u8 onoff);
-extern int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
-extern enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe);
-extern void dib8000_pwm_agc_reset(struct dvb_frontend *fe);
-extern s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode);
-extern struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe);
-extern int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff);
-extern int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ);
-extern u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
- uint8_t op, uint32_t timf);
-extern int dib8000_update_pll(struct dvb_frontend *fe,
+struct dib8000_ops {
+ int (*set_wbd_ref)(struct dvb_frontend *fe, u16 value);
+ int (*update_pll)(struct dvb_frontend *fe,
struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio);
-extern int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
-extern int dib8000_remove_slave_frontend(struct dvb_frontend *fe);
-extern struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index);
+ int (*set_gpio)(struct dvb_frontend *fe, u8 num, u8 dir, u8 val);
+ void (*pwm_agc_reset)(struct dvb_frontend *fe);
+ struct i2c_adapter *(*get_i2c_tuner)(struct dvb_frontend *fe);
+ int (*tuner_sleep)(struct dvb_frontend *fe, int onoff);
+ s32 (*get_adc_power)(struct dvb_frontend *fe, u8 mode);
+ int (*get_dc_power)(struct dvb_frontend *fe, u8 IQ);
+ u32 (*ctrl_timf)(struct dvb_frontend *fe, uint8_t op, uint32_t timf);
+ enum frontend_tune_state (*get_tune_state)(struct dvb_frontend *fe);
+ int (*set_tune_state)(struct dvb_frontend *fe, enum frontend_tune_state tune_state);
+ int (*set_slave_frontend)(struct dvb_frontend *fe, struct dvb_frontend *fe_slave);
+ int (*remove_slave_frontend)(struct dvb_frontend *fe);
+ struct dvb_frontend *(*get_slave_frontend)(struct dvb_frontend *fe, int slave_index);
+ int (*i2c_enumeration)(struct i2c_adapter *host, int no_of_demods,
+ u8 default_addr, u8 first_addr, u8 is_dib8096p);
+ struct i2c_adapter *(*get_i2c_master)(struct dvb_frontend *fe, enum dibx000_i2c_interface intf, int gating);
+ int (*pid_filter_ctrl)(struct dvb_frontend *fe, u8 onoff);
+ int (*pid_filter)(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff);
+ struct dvb_frontend *(*init)(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg);
+};
+
+#if IS_ENABLED(CONFIG_DVB_DIB8000)
+void *dib8000_attach(struct dib8000_ops *ops);
#else
-static inline struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib8000_config *cfg)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-
-static inline struct i2c_adapter *dib8000_get_i2c_master(struct dvb_frontend *fe, enum dibx000_i2c_interface i, int x)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-
-static inline int dib8000_i2c_enumeration(struct i2c_adapter *host,
- int no_of_demods, u8 default_addr, u8 first_addr,
- u8 is_dib8096p)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib8000_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-static inline int dib8000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-static inline enum frontend_tune_state dib8000_get_tune_state(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return CT_SHUTDOWN;
-}
-static inline void dib8000_pwm_agc_reset(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
-}
-static inline struct i2c_adapter *dib8096p_get_i2c_tuner(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-static inline int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return 0;
-}
-static inline s32 dib8000_get_adc_power(struct dvb_frontend *fe, u8 mode)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return 0;
-}
-static inline int dib8090p_get_dc_power(struct dvb_frontend *fe, u8 IQ)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return 0;
-}
-static inline u32 dib8000_ctrl_timf(struct dvb_frontend *fe,
- uint8_t op, uint32_t timf)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return 0;
-}
-static inline int dib8000_update_pll(struct dvb_frontend *fe,
- struct dibx000_bandwidth_config *pll, u32 bw, u8 ratio)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-static inline int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-int dib8000_remove_slave_frontend(struct dvb_frontend *fe)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
-
-static inline struct dvb_frontend *dib8000_get_slave_frontend(struct dvb_frontend *fe, int slave_index)
+static inline int dib8000_attach(struct dib8000_ops *ops)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c
index e540cfb13bac..f75dec443783 100644
--- a/drivers/media/dvb-frontends/dib9000.c
+++ b/drivers/media/dvb-frontends/dib9000.c
@@ -1040,13 +1040,18 @@ static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 addres
if (address >= 1024 || !state->platform.risc.fw_is_running)
return -EINVAL;
+ if (len > 18)
+ return -EINVAL;
+
/* dprintk( "APB access thru wr fw %d %x", address, attribute); */
- mb[0] = (unsigned short)address;
- for (i = 0; i < len && i < 20; i += 2)
- mb[1 + (i / 2)] = (b[i] << 8 | b[i + 1]);
+ mb[0] = (u16)address;
+ for (i = 0; i + 1 < len; i += 2)
+ mb[1 + i / 2] = b[i] << 8 | b[i + 1];
+ if (len & 1)
+ mb[1 + len / 2] = b[len - 1] << 8;
- dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, 1 + len / 2, attribute);
+ dib9000_mbx_send_attr(state, OUT_MSG_BRIDGE_APB_W, mb, (3 + len) / 2, attribute);
return dib9000_mbx_get_message_attr(state, IN_MSG_END_BRIDGE_APB_RW, mb, &s, attribute) == 1 ? 0 : -EINVAL;
}
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 9482954fd453..7ca7a21df183 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -2159,7 +2159,7 @@ int drxj_dap_atomic_read_write_block(struct i2c_device_addr *dev_addr,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
@@ -2252,7 +2252,7 @@ static int hi_cfg_command(const struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -2363,7 +2363,7 @@ hi_command(struct i2c_device_addr *dev_addr, const struct drxj_hi_cmd *cmd, u16
/* if ( powerdown_cmd == true ) */
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -2434,7 +2434,7 @@ static int init_hi(const struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -2650,7 +2650,7 @@ static int get_device_capabilities(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -3338,7 +3338,7 @@ ctrl_set_cfg_mpeg_output(struct drx_demod_instance *demod, struct drx_cfg_mpeg_o
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*----------------------------------------------------------------------------*/
@@ -3421,7 +3421,7 @@ static int set_mpegtei_handling(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*----------------------------------------------------------------------------*/
@@ -3464,7 +3464,7 @@ static int bit_reverse_mpeg_output(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*----------------------------------------------------------------------------*/
@@ -3508,7 +3508,7 @@ static int set_mpeg_start_width(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*----------------------------------------------------------------------------*/
@@ -3652,7 +3652,7 @@ static int ctrl_set_uio_cfg(struct drx_demod_instance *demod, struct drxuio_cfg
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -3854,7 +3854,7 @@ ctrl_uio_write(struct drx_demod_instance *demod, struct drxuio_data *uio_data)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*---------------------------------------------------------------------------*/
@@ -3969,7 +3969,7 @@ static int smart_ant_init(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd)
@@ -4109,7 +4109,7 @@ static int scu_command(struct i2c_device_addr *dev_addr, struct drxjscu_cmd *cmd
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -4178,7 +4178,7 @@ int drxj_dap_scu_atomic_read_write_block(struct i2c_device_addr *dev_addr, u32 a
return 0;
rw_error:
- return -EIO;
+ return rc;
}
@@ -4290,7 +4290,7 @@ static int adc_sync_measurement(struct drx_demod_instance *demod, u16 *count)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -4349,7 +4349,7 @@ static int adc_synchronization(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -4734,7 +4734,7 @@ static int init_agc(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -4831,7 +4831,7 @@ set_frequency(struct drx_demod_instance *demod,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -4879,7 +4879,7 @@ static int get_acc_pkt_err(struct drx_demod_instance *demod, u16 *packet_err)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
#endif
@@ -5097,7 +5097,7 @@ set_agc_rf(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -5326,7 +5326,7 @@ set_agc_if(struct drx_demod_instance *demod, struct drxj_cfg_agc *agc_settings,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -5362,7 +5362,7 @@ static int set_iqm_af(struct drx_demod_instance *demod, bool active)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -5470,7 +5470,7 @@ static int power_down_vsb(struct drx_demod_instance *demod, bool primary)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -5686,7 +5686,7 @@ static int set_vsb_leak_n_gain(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -6192,7 +6192,7 @@ static int set_vsb(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -6231,7 +6231,7 @@ static int get_vsb_post_rs_pck_err(struct i2c_device_addr *dev_addr,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -6276,7 +6276,7 @@ static int get_vs_bpost_viterbi_ber(struct i2c_device_addr *dev_addr,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -6321,7 +6321,7 @@ static int get_vsbmer(struct i2c_device_addr *dev_addr, u16 *mer)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
@@ -6434,7 +6434,7 @@ static int power_down_qam(struct drx_demod_instance *demod, bool primary)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -6646,7 +6646,7 @@ set_qam_measurement(struct drx_demod_instance *demod,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -6881,7 +6881,7 @@ static int set_qam16(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -7116,7 +7116,7 @@ static int set_qam32(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -7351,7 +7351,7 @@ static int set_qam64(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -7586,7 +7586,7 @@ static int set_qam128(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -7821,7 +7821,7 @@ static int set_qam256(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -8650,7 +8650,7 @@ set_qam(struct drx_demod_instance *demod,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -8831,7 +8831,7 @@ static int qam_flip_spec(struct drx_demod_instance *demod, struct drx_channel *c
return 0;
rw_error:
- return -EIO;
+ return rc;
}
@@ -8984,7 +8984,7 @@ qam64auto(struct drx_demod_instance *demod,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -9068,7 +9068,7 @@ qam256auto(struct drx_demod_instance *demod,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -9273,7 +9273,7 @@ rw_error:
/* restore starting value */
if (auto_flag)
channel->constellation = DRX_CONSTELLATION_AUTO;
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -9344,7 +9344,7 @@ get_qamrs_err_count(struct i2c_device_addr *dev_addr,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -9425,8 +9425,8 @@ static int get_sig_strength(struct drx_demod_instance *demod, u16 *sig_strength)
*sig_strength = 0;
return 0;
- rw_error:
- return -EIO;
+rw_error:
+ return rc;
}
/**
@@ -9643,7 +9643,7 @@ rw_error:
p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- return -EIO;
+ return rc;
}
#endif /* #ifndef DRXJ_VSB_ONLY */
@@ -9810,7 +9810,7 @@ power_down_atv(struct drx_demod_instance *demod, enum drx_standard standard, boo
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -9840,7 +9840,7 @@ static int power_down_aud(struct drx_demod_instance *demod)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -9874,7 +9874,7 @@ static int set_orx_nsu_aox(struct drx_demod_instance *demod, bool active)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/**
@@ -10398,7 +10398,7 @@ static int ctrl_set_oob(struct drx_demod_instance *demod, struct drxoob *oob_par
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -10638,7 +10638,7 @@ ctrl_set_channel(struct drx_demod_instance *demod, struct drx_channel *channel)
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*=============================================================================
@@ -10756,7 +10756,7 @@ ctrl_sig_quality(struct drx_demod_instance *demod,
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -10844,7 +10844,7 @@ ctrl_lock_status(struct drx_demod_instance *demod, enum drx_lock_status *lock_st
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -10941,7 +10941,7 @@ ctrl_set_standard(struct drx_demod_instance *demod, enum drx_standard *standard)
rw_error:
/* Don't know what the standard is now ... try again */
ext_attr->standard = DRX_STANDARD_UNKNOWN;
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -11222,7 +11222,7 @@ ctrl_set_cfg_pre_saw(struct drx_demod_instance *demod, struct drxj_cfg_pre_saw *
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -11303,7 +11303,7 @@ ctrl_set_cfg_afe_gain(struct drx_demod_instance *demod, struct drxj_cfg_afe_gain
return 0;
rw_error:
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -11315,6 +11315,7 @@ rw_error:
static int drx_ctrl_u_code(struct drx_demod_instance *demod,
struct drxu_code_info *mc_info,
enum drxu_code_action action);
+static int drxj_set_lna_state(struct drx_demod_instance *demod, bool state);
/**
* \fn drxj_open()
@@ -11527,10 +11528,11 @@ static int drxj_open(struct drx_demod_instance *demod)
ext_attr->aud_data = drxj_default_aud_data_g;
demod->my_common_attr->is_opened = true;
+ drxj_set_lna_state(demod, false);
return 0;
rw_error:
common_attr->is_opened = false;
- return -EIO;
+ return rc;
}
/*============================================================================*/
@@ -11578,7 +11580,7 @@ static int drxj_close(struct drx_demod_instance *demod)
rw_error:
DRX_ATTR_ISOPENED(demod) = false;
- return -EIO;
+ return rc;
}
/*
@@ -11890,6 +11892,33 @@ release:
return rc;
}
+/* caller is expeced to check if lna is supported before enabling */
+static int drxj_set_lna_state(struct drx_demod_instance *demod, bool state)
+{
+ struct drxuio_cfg uio_cfg;
+ struct drxuio_data uio_data;
+ int result;
+
+ uio_cfg.uio = DRX_UIO1;
+ uio_cfg.mode = DRX_UIO_MODE_READWRITE;
+ /* Configure user-I/O #3: enable read/write */
+ result = ctrl_set_uio_cfg(demod, &uio_cfg);
+ if (result) {
+ pr_err("Failed to setup LNA GPIO!\n");
+ return result;
+ }
+
+ uio_data.uio = DRX_UIO1;
+ uio_data.value = state;
+ result = ctrl_uio_write(demod, &uio_data);
+ if (result != 0) {
+ pr_err("Failed to %sable LNA!\n",
+ state ? "en" : "dis");
+ return result;
+ }
+ return 0;
+}
+
/*
* The Linux DVB Driver for Micronas DRX39xx family (drx3933j)
*
@@ -12040,7 +12069,6 @@ static int drx39xxj_set_frontend(struct dvb_frontend *fe)
enum drx_standard standard = DRX_STANDARD_8VSB;
struct drx_channel channel;
int result;
- struct drxuio_data uio_data;
static const struct drx_channel def_channel = {
/* frequency */ 0,
/* bandwidth */ DRX_BANDWIDTH_6MHZ,
@@ -12125,13 +12153,7 @@ static int drx39xxj_set_frontend(struct dvb_frontend *fe)
return -EINVAL;
}
/* Just for giggles, let's shut off the LNA again.... */
- uio_data.uio = DRX_UIO1;
- uio_data.value = false;
- result = ctrl_uio_write(demod, &uio_data);
- if (result != 0) {
- pr_err("Failed to disable LNA!\n");
- return 0;
- }
+ drxj_set_lna_state(demod, false);
/* After set_frontend, except for strength, stats aren't available */
p->strength.stat[0].scale = FE_SCALE_RELATIVE;
@@ -12180,21 +12202,28 @@ static int drx39xxj_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
static int drx39xxj_init(struct dvb_frontend *fe)
{
- /* Bring the demod out of sleep */
- drx39xxj_set_powerstate(fe, 1);
+ struct drx39xxj_state *state = fe->demodulator_priv;
+ struct drx_demod_instance *demod = state->demod;
+ int rc = 0;
- return 0;
+ if (fe->exit == DVB_FE_DEVICE_RESUME) {
+ /* so drxj_open() does what it needs to do */
+ demod->my_common_attr->is_opened = false;
+ rc = drxj_open(demod);
+ if (rc != 0)
+ pr_err("drx39xxj_init(): DRX open failed rc=%d!\n", rc);
+ } else
+ drx39xxj_set_powerstate(fe, 1);
+
+ return rc;
}
static int drx39xxj_set_lna(struct dvb_frontend *fe)
{
- int result;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct drx39xxj_state *state = fe->demodulator_priv;
struct drx_demod_instance *demod = state->demod;
struct drxj_data *ext_attr = demod->my_ext_attr;
- struct drxuio_cfg uio_cfg;
- struct drxuio_data uio_data;
if (c->lna) {
if (!ext_attr->has_lna) {
@@ -12204,26 +12233,7 @@ static int drx39xxj_set_lna(struct dvb_frontend *fe)
}
}
- /* Turn off the LNA */
- uio_cfg.uio = DRX_UIO1;
- uio_cfg.mode = DRX_UIO_MODE_READWRITE;
- /* Configure user-I/O #3: enable read/write */
- result = ctrl_set_uio_cfg(demod, &uio_cfg);
- if (result) {
- pr_err("Failed to setup LNA GPIO!\n");
- return result;
- }
-
- uio_data.uio = DRX_UIO1;
- uio_data.value = c->lna;
- result = ctrl_uio_write(demod, &uio_data);
- if (result != 0) {
- pr_err("Failed to %sable LNA!\n",
- c->lna ? "en" : "dis");
- return result;
- }
-
- return 0;
+ return drxj_set_lna_state(demod, c->lna);
}
static int drx39xxj_get_tune_settings(struct dvb_frontend *fe,
@@ -12238,7 +12248,9 @@ static void drx39xxj_release(struct dvb_frontend *fe)
struct drx39xxj_state *state = fe->demodulator_priv;
struct drx_demod_instance *demod = state->demod;
- drxj_close(demod);
+ /* if device is removed don't access it */
+ if (fe->exit != DVB_FE_DEVICE_REMOVED)
+ drxj_close(demod);
kfree(demod->my_ext_attr);
kfree(demod->my_common_attr);
@@ -12259,8 +12271,6 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
struct drxj_data *demod_ext_attr = NULL;
struct drx_demod_instance *demod = NULL;
struct dtv_frontend_properties *p;
- struct drxuio_cfg uio_cfg;
- struct drxuio_data uio_data;
int result;
/* allocate memory for the internal state */
@@ -12272,22 +12282,20 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
if (demod == NULL)
goto error;
- demod_addr = kmalloc(sizeof(struct i2c_device_addr), GFP_KERNEL);
+ demod_addr = kmemdup(&drxj_default_addr_g,
+ sizeof(struct i2c_device_addr), GFP_KERNEL);
if (demod_addr == NULL)
goto error;
- memcpy(demod_addr, &drxj_default_addr_g,
- sizeof(struct i2c_device_addr));
- demod_comm_attr = kmalloc(sizeof(struct drx_common_attr), GFP_KERNEL);
+ demod_comm_attr = kmemdup(&drxj_default_comm_attr_g,
+ sizeof(struct drx_common_attr), GFP_KERNEL);
if (demod_comm_attr == NULL)
goto error;
- memcpy(demod_comm_attr, &drxj_default_comm_attr_g,
- sizeof(struct drx_common_attr));
- demod_ext_attr = kmalloc(sizeof(struct drxj_data), GFP_KERNEL);
+ demod_ext_attr = kmemdup(&drxj_data_g, sizeof(struct drxj_data),
+ GFP_KERNEL);
if (demod_ext_attr == NULL)
goto error;
- memcpy(demod_ext_attr, &drxj_data_g, sizeof(struct drxj_data));
/* setup the state */
state->i2c = i2c;
@@ -12313,24 +12321,6 @@ struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c)
goto error;
}
- /* Turn off the LNA */
- uio_cfg.uio = DRX_UIO1;
- uio_cfg.mode = DRX_UIO_MODE_READWRITE;
- /* Configure user-I/O #3: enable read/write */
- result = ctrl_set_uio_cfg(demod, &uio_cfg);
- if (result) {
- pr_err("Failed to setup LNA GPIO!\n");
- goto error;
- }
-
- uio_data.uio = DRX_UIO1;
- uio_data.value = false;
- result = ctrl_uio_write(demod, &uio_data);
- if (result != 0) {
- pr_err("Failed to disable LNA!\n");
- goto error;
- }
-
/* create dvb_frontend */
memcpy(&state->frontend.ops, &drx39xxj_ops,
sizeof(struct dvb_frontend_ops));
diff --git a/drivers/media/dvb-frontends/drxd.h b/drivers/media/dvb-frontends/drxd.h
index 5f1d6b5f1685..d998e4d5a7fc 100644
--- a/drivers/media/dvb-frontends/drxd.h
+++ b/drivers/media/dvb-frontends/drxd.h
@@ -69,5 +69,4 @@ struct dvb_frontend *drxd_attach(const struct drxd_config *config,
}
#endif
-extern int drxd_config_i2c(struct dvb_frontend *, int);
#endif
diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c
index 5b87ece69414..ae2276db77bc 100644
--- a/drivers/media/dvb-frontends/drxd_hard.c
+++ b/drivers/media/dvb-frontends/drxd_hard.c
@@ -2840,7 +2840,7 @@ static int drxd_init(struct dvb_frontend *fe)
return err;
}
-int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
+static int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
{
struct drxd_state *state = fe->demodulator_priv;
@@ -2849,7 +2849,6 @@ int drxd_config_i2c(struct dvb_frontend *fe, int onoff)
return DRX_ConfigureI2CBridge(state, onoff);
}
-EXPORT_SYMBOL(drxd_config_i2c);
static int drxd_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *sets)
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index 2ef8ce13fb60..dfe0c2f7f1ef 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -879,7 +879,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
/* SNR(X) dB = 10 * ln(X) / ln(10) dB */
tmp = DIV_ROUND_CLOSEST(tmp, 8 * M88DS3103_SNR_ITERATIONS);
if (tmp)
- *snr = 100ul * intlog2(tmp) / intlog2(10);
+ *snr = div_u64((u64) 100 * intlog2(tmp), intlog2(10));
else
*snr = 0;
break;
@@ -908,7 +908,7 @@ static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
/* SNR(X) dB = 10 * log10(X) dB */
if (signal > noise) {
tmp = signal / noise;
- *snr = 100ul * intlog10(tmp) / (1 << 24);
+ *snr = div_u64((u64) 100 * intlog10(tmp), (1 << 24));
} else {
*snr = 0;
}
@@ -926,6 +926,86 @@ err:
return ret;
}
+static int m88ds3103_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct m88ds3103_priv *priv = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ unsigned int utmp;
+ u8 buf[3], u8tmp;
+ dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ ret = m88ds3103_wr_reg(priv, 0xf9, 0x04);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_rd_reg(priv, 0xf8, &u8tmp);
+ if (ret)
+ goto err;
+
+ if (!(u8tmp & 0x10)) {
+ u8tmp |= 0x10;
+
+ ret = m88ds3103_rd_regs(priv, 0xf6, buf, 2);
+ if (ret)
+ goto err;
+
+ priv->ber = (buf[1] << 8) | (buf[0] << 0);
+
+ /* restart counters */
+ ret = m88ds3103_wr_reg(priv, 0xf8, u8tmp);
+ if (ret)
+ goto err;
+ }
+ break;
+ case SYS_DVBS2:
+ ret = m88ds3103_rd_regs(priv, 0xd5, buf, 3);
+ if (ret)
+ goto err;
+
+ utmp = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
+
+ if (utmp > 3000) {
+ ret = m88ds3103_rd_regs(priv, 0xf7, buf, 2);
+ if (ret)
+ goto err;
+
+ priv->ber = (buf[1] << 8) | (buf[0] << 0);
+
+ /* restart counters */
+ ret = m88ds3103_wr_reg(priv, 0xd1, 0x01);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_wr_reg(priv, 0xf9, 0x01);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_wr_reg(priv, 0xf9, 0x00);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_wr_reg(priv, 0xd1, 0x00);
+ if (ret)
+ goto err;
+ }
+ break;
+ default:
+ dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+ __func__);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ *ber = priv->ber;
+
+ return 0;
+err:
+ dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
static int m88ds3103_set_tone(struct dvb_frontend *fe,
fe_sec_tone_mode_t fe_sec_tone_mode)
@@ -1284,6 +1364,7 @@ static struct dvb_frontend_ops m88ds3103_ops = {
.read_status = m88ds3103_read_status,
.read_snr = m88ds3103_read_snr,
+ .read_ber = m88ds3103_read_ber,
.diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd,
.diseqc_send_burst = m88ds3103_diseqc_send_burst,
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index 84c3c06df622..9169fdd143cf 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -22,6 +22,7 @@
#include "dvb_math.h"
#include
#include
+#include
#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
#define M88DS3103_MCLK_KHZ 96000
@@ -34,6 +35,7 @@ struct m88ds3103_priv {
struct dvb_frontend fe;
fe_delivery_system_t delivery_system;
fe_status_t fe_status;
+ u32 ber;
bool warm; /* FW running */
struct i2c_adapter *i2c_adapter;
};
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index 2f458bb188c7..b931179c70a4 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -459,6 +459,9 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
unsigned layer)
{
int rc;
+ int interleaving[] = {
+ 0, 1, 2, 4, 8
+ };
static unsigned char reg[] = {
[0] = 0x88, /* Layer A */
@@ -475,20 +478,7 @@ static int mb86a20s_get_interleaving(struct mb86a20s_state *state,
if (rc < 0)
return rc;
- switch ((rc >> 4) & 0x07) {
- case 1:
- return GUARD_INTERVAL_1_4;
- case 2:
- return GUARD_INTERVAL_1_8;
- case 3:
- return GUARD_INTERVAL_1_16;
- case 4:
- return GUARD_INTERVAL_1_32;
-
- default:
- case 0:
- return GUARD_INTERVAL_AUTO;
- }
+ return interleaving[(rc >> 4) & 0x07];
}
static int mb86a20s_get_segment_count(struct mb86a20s_state *state,
@@ -566,7 +556,7 @@ static u32 isdbt_rate[3][5][4] = {
static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
u32 modulation, u32 forward_error_correction,
- u32 interleaving,
+ u32 guard_interval,
u32 segment)
{
struct mb86a20s_state *state = fe->demodulator_priv;
@@ -574,7 +564,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
int mod, fec, guard;
/*
- * If modulation/fec/interleaving is not detected, the default is
+ * If modulation/fec/guard is not detected, the default is
* to consider the lowest bit rate, to avoid taking too long time
* to get BER.
*/
@@ -612,7 +602,7 @@ static void mb86a20s_layer_bitrate(struct dvb_frontend *fe, u32 layer,
break;
}
- switch (interleaving) {
+ switch (guard_interval) {
default:
case GUARD_INTERVAL_1_4:
guard = 0;
@@ -703,7 +693,7 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
c->layer[layer].interleaving = rc;
mb86a20s_layer_bitrate(fe, layer, c->layer[layer].modulation,
c->layer[layer].fec,
- c->layer[layer].interleaving,
+ c->guard_interval,
c->layer[layer].segment_count);
}
@@ -721,11 +711,10 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
rc = mb86a20s_readreg(state, 0x07);
if (rc < 0)
return rc;
+ c->transmission_mode = TRANSMISSION_MODE_AUTO;
if ((rc & 0x60) == 0x20) {
- switch (rc & 0x0c >> 2) {
- case 0:
- c->transmission_mode = TRANSMISSION_MODE_2K;
- break;
+ /* Only modes 2 and 3 are supported */
+ switch ((rc >> 2) & 0x03) {
case 1:
c->transmission_mode = TRANSMISSION_MODE_4K;
break;
@@ -734,7 +723,9 @@ static int mb86a20s_get_frontend(struct dvb_frontend *fe)
break;
}
}
+ c->guard_interval = GUARD_INTERVAL_AUTO;
if (!(rc & 0x10)) {
+ /* Guard interval 1/32 is not supported */
switch (rc & 0x3) {
case 0:
c->guard_interval = GUARD_INTERVAL_1_4;
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
similarity index 94%
rename from drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
rename to drivers/media/dvb-frontends/rtl2832_sdr.c
index 093df6b6ae35..023e0f49c786 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -35,6 +35,10 @@
#include
#include
+static bool rtl2832_sdr_emulated_fmt;
+module_param_named(emulated_formats, rtl2832_sdr_emulated_fmt, bool, 0644);
+MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)");
+
#define MAX_BULK_BUFS (10)
#define BULK_BUFFER_SIZE (128 * 512)
@@ -80,15 +84,18 @@ static const struct v4l2_frequency_band bands_fm[] = {
struct rtl2832_sdr_format {
char *name;
u32 pixelformat;
+ u32 buffersize;
};
static struct rtl2832_sdr_format formats[] = {
{
- .name = "IQ U8",
- .pixelformat = V4L2_SDR_FMT_CU8,
+ .name = "Complex U8",
+ .pixelformat = V4L2_SDR_FMT_CU8,
+ .buffersize = BULK_BUFFER_SIZE,
}, {
- .name = "IQ U16LE (emulated)",
+ .name = "Complex U16LE (emulated)",
.pixelformat = V4L2_SDR_FMT_CU16LE,
+ .buffersize = BULK_BUFFER_SIZE * 2,
},
};
@@ -139,6 +146,8 @@ struct rtl2832_sdr_state {
unsigned int f_adc, f_tuner;
u32 pixelformat;
+ u32 buffersize;
+ unsigned int num_formats;
/* Controls */
struct v4l2_ctrl_handler hdl;
@@ -348,6 +357,7 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
/* convert u8 to u16 */
unsigned int i;
u16 *u16dst = dst;
+
for (i = 0; i < src_len; i++)
*u16dst++ = (src[i] << 8) | (src[i] >> 0);
dst_len = 2 * src_len;
@@ -359,6 +369,7 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
#define MSECS 10000UL
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,
@@ -560,11 +571,13 @@ static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
{
unsigned long flags = 0;
+
dev_dbg(&s->udev->dev, "%s:\n", __func__);
spin_lock_irqsave(&s->queued_bufs_lock, flags);
while (!list_empty(&s->queued_bufs)) {
struct rtl2832_sdr_frame_buf *buf;
+
buf = list_entry(s->queued_bufs.next,
struct rtl2832_sdr_frame_buf, list);
list_del(&buf->list);
@@ -577,6 +590,7 @@ static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
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__);
mutex_lock(&s->vb_queue_lock);
@@ -598,6 +612,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
+
dev_dbg(&s->udev->dev, "%s:\n", __func__);
strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
@@ -615,14 +630,14 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+
dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers);
/* Need at least 8 buffers */
if (vq->num_buffers + *nbuffers < 8)
*nbuffers = 8 - vq->num_buffers;
*nplanes = 1;
- /* 2 = max 16-bit sample returned */
- sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2);
+ sizes[0] = PAGE_ALIGN(s->buffersize);
dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
__func__, *nbuffers, sizes[0]);
return 0;
@@ -665,6 +680,7 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
u8 buf[4], u8tmp1, u8tmp2;
u64 u64tmp;
u32 u32tmp;
+
dev_dbg(&s->udev->dev, "%s: f_adc=%u\n", __func__, s->f_adc);
if (!test_bit(POWER_ON, &s->flags))
@@ -935,7 +951,8 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
/*
* bandwidth (Hz)
*/
- bandwidth_auto = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
+ bandwidth_auto = v4l2_ctrl_find(&s->hdl,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
if (v4l2_ctrl_g_ctrl(bandwidth_auto)) {
c->bandwidth_hz = s->f_adc;
@@ -987,6 +1004,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__);
if (!s->udev)
@@ -1035,6 +1053,7 @@ err:
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__);
mutex_lock(&s->v4l2_lock);
@@ -1068,6 +1087,7 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
+
dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
__func__, v->index, v->type);
@@ -1094,6 +1114,7 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *v)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
+
dev_dbg(&s->udev->dev, "%s:\n", __func__);
if (v->index > 1)
@@ -1105,6 +1126,7 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
struct v4l2_frequency_band *band)
{
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);
@@ -1130,6 +1152,7 @@ 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);
@@ -1193,9 +1216,10 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
+
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- if (f->index >= NUM_FORMATS)
+ if (f->index >= s->num_formats)
return -EINVAL;
strlcpy(f->description, formats[f->index].name, sizeof(f->description));
@@ -1208,9 +1232,12 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
+
dev_dbg(&s->udev->dev, "%s:\n", __func__);
f->fmt.sdr.pixelformat = s->pixelformat;
+ f->fmt.sdr.buffersize = s->buffersize;
+
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
return 0;
@@ -1222,6 +1249,7 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
struct rtl2832_sdr_state *s = video_drvdata(file);
struct vb2_queue *q = &s->vb_queue;
int i;
+
dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
(char *)&f->fmt.sdr.pixelformat);
@@ -1229,15 +1257,19 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
return -EBUSY;
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
- for (i = 0; i < NUM_FORMATS; i++) {
+ for (i = 0; i < s->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
- s->pixelformat = f->fmt.sdr.pixelformat;
+ s->pixelformat = formats[i].pixelformat;
+ s->buffersize = formats[i].buffersize;
+ f->fmt.sdr.buffersize = formats[i].buffersize;
return 0;
}
}
- f->fmt.sdr.pixelformat = formats[0].pixelformat;
s->pixelformat = formats[0].pixelformat;
+ s->buffersize = formats[0].buffersize;
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
+ f->fmt.sdr.buffersize = formats[0].buffersize;
return 0;
}
@@ -1247,16 +1279,20 @@ 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__,
(char *)&f->fmt.sdr.pixelformat);
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
- for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].pixelformat == f->fmt.sdr.pixelformat)
+ for (i = 0; i < s->num_formats; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+ f->fmt.sdr.buffersize = formats[i].buffersize;
return 0;
+ }
}
f->fmt.sdr.pixelformat = formats[0].pixelformat;
+ f->fmt.sdr.buffersize = formats[0].buffersize;
return 0;
}
@@ -1316,8 +1352,9 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
struct dvb_frontend *fe = s->fe;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
+
dev_dbg(&s->udev->dev,
- "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+ "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
__func__, ctrl->id, ctrl->name, ctrl->val,
ctrl->minimum, ctrl->maximum, ctrl->step);
@@ -1327,14 +1364,16 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
/* TODO: these controls should be moved to tuner drivers */
if (s->bandwidth_auto->val) {
/* Round towards the closest legal value */
- s32 val = s->f_adc + s->bandwidth->step / 2;
+ s32 val = s->f_adc + div_u64(s->bandwidth->step, 2);
u32 offset;
- val = clamp(val, s->bandwidth->minimum, s->bandwidth->maximum);
+
+ val = clamp_t(s32, val, s->bandwidth->minimum,
+ s->bandwidth->maximum);
offset = val - s->bandwidth->minimum;
- offset = s->bandwidth->step * (offset / s->bandwidth->step);
+ offset = s->bandwidth->step *
+ div_u64(offset, s->bandwidth->step);
s->bandwidth->val = s->bandwidth->minimum + offset;
}
-
c->bandwidth_hz = s->bandwidth->val;
if (!test_bit(POWER_ON, &s->flags))
@@ -1390,7 +1429,11 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
s->cfg = cfg;
s->f_adc = bands_adc[0].rangelow;
s->f_tuner = bands_fm[0].rangelow;
- s->pixelformat = V4L2_SDR_FMT_CU8;
+ s->pixelformat = formats[0].pixelformat;
+ s->buffersize = formats[0].buffersize;
+ s->num_formats = NUM_FORMATS;
+ if (rtl2832_sdr_emulated_fmt == false)
+ s->num_formats -= 1;
mutex_init(&s->v4l2_lock);
mutex_init(&s->vb_queue_lock);
@@ -1420,15 +1463,24 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
break;
case RTL2832_TUNER_R820T:
v4l2_ctrl_handler_init(&s->hdl, 2);
- s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
- s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 0, 8000000, 100000, 0);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+ 0, 1, 1, 1);
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH,
+ 0, 8000000, 100000, 0);
v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
break;
case RTL2832_TUNER_FC0012:
case RTL2832_TUNER_FC0013:
v4l2_ctrl_handler_init(&s->hdl, 2);
- s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
- s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops, V4L2_CID_RF_TUNER_BANDWIDTH, 6000000, 8000000, 1000000, 6000000);
+ s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+ 0, 1, 1, 1);
+ s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH,
+ 6000000, 8000000, 1000000,
+ 6000000);
v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
break;
default:
@@ -1448,7 +1500,6 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
s->vdev = rtl2832_sdr_template;
s->vdev.queue = &s->vb_queue;
s->vdev.queue->lock = &s->vb_queue_lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev.flags);
video_set_drvdata(&s->vdev, s);
/* Register the v4l2_device structure */
@@ -1480,6 +1531,9 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
dev_info(&s->i2c->dev, "%s: Realtek RTL2832 SDR attached\n",
KBUILD_MODNAME);
+ dev_notice(&s->udev->dev,
+ "%s: SDR API is still slightly experimental and functionality changes may follow\n",
+ KBUILD_MODNAME);
return fe;
err_unregister_v4l2_dev:
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h b/drivers/media/dvb-frontends/rtl2832_sdr.h
similarity index 100%
rename from drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.h
rename to drivers/media/dvb-frontends/rtl2832_sdr.h
diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c
new file mode 100644
index 000000000000..3a2d6c5aded6
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2165.c
@@ -0,0 +1,1040 @@
+/*
+ Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+ Copyright (C) 2013-2014 Matthias Schwarzott
+
+ 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.
+
+ References:
+ http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "si2165_priv.h"
+#include "si2165.h"
+
+/* Hauppauge WinTV-HVR-930C-HD B130 / PCTV QuatroStick 521e 1113xx
+ * uses 16 MHz xtal */
+
+/* Hauppauge WinTV-HVR-930C-HD B131 / PCTV QuatroStick 522e 1114xx
+ * uses 24 MHz clock provided by tuner */
+
+struct si2165_state {
+ struct i2c_adapter *i2c;
+
+ struct dvb_frontend frontend;
+
+ struct si2165_config config;
+
+ /* chip revision */
+ u8 revcode;
+ /* chip type */
+ u8 chip_type;
+
+ /* calculated by xtal and div settings */
+ u32 fvco_hz;
+ u32 sys_clk;
+ u32 adc_clk;
+
+ bool has_dvbc;
+ bool has_dvbt;
+ bool firmware_loaded;
+};
+
+#define DEBUG_OTHER 0x01
+#define DEBUG_I2C_WRITE 0x02
+#define DEBUG_I2C_READ 0x04
+#define DEBUG_REG_READ 0x08
+#define DEBUG_REG_WRITE 0x10
+#define DEBUG_FW_LOAD 0x20
+
+static int debug = 0x00;
+
+#define dprintk(args...) \
+ do { \
+ if (debug & DEBUG_OTHER) \
+ printk(KERN_DEBUG "si2165: " args); \
+ } while (0)
+
+#define deb_i2c_write(args...) \
+ do { \
+ if (debug & DEBUG_I2C_WRITE) \
+ printk(KERN_DEBUG "si2165: i2c write: " args); \
+ } while (0)
+
+#define deb_i2c_read(args...) \
+ do { \
+ if (debug & DEBUG_I2C_READ) \
+ printk(KERN_DEBUG "si2165: i2c read: " args); \
+ } while (0)
+
+#define deb_readreg(args...) \
+ do { \
+ if (debug & DEBUG_REG_READ) \
+ printk(KERN_DEBUG "si2165: reg read: " args); \
+ } while (0)
+
+#define deb_writereg(args...) \
+ do { \
+ if (debug & DEBUG_REG_WRITE) \
+ printk(KERN_DEBUG "si2165: reg write: " args); \
+ } while (0)
+
+#define deb_fw_load(args...) \
+ do { \
+ if (debug & DEBUG_FW_LOAD) \
+ printk(KERN_DEBUG "si2165: fw load: " args); \
+ } while (0)
+
+static int si2165_write(struct si2165_state *state, const u16 reg,
+ const u8 *src, const int count)
+{
+ int ret;
+ struct i2c_msg msg;
+ u8 buf[2 + 4]; /* write a maximum of 4 bytes of data */
+
+ if (count + 2 > sizeof(buf)) {
+ dev_warn(&state->i2c->dev,
+ "%s: i2c wr reg=%04x: count=%d is too big!\n",
+ KBUILD_MODNAME, reg, count);
+ return -EINVAL;
+ }
+ buf[0] = reg >> 8;
+ buf[1] = reg & 0xff;
+ memcpy(buf + 2, src, count);
+
+ msg.addr = state->config.i2c_addr;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = count + 2;
+
+ if (debug & DEBUG_I2C_WRITE)
+ deb_i2c_write("reg: 0x%04x, data: %*ph\n", reg, count, src);
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1) {
+ dev_err(&state->i2c->dev, "%s: ret == %d\n", __func__, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int si2165_read(struct si2165_state *state,
+ const u16 reg, u8 *val, const int count)
+{
+ int ret;
+ u8 reg_buf[] = { reg >> 8, reg & 0xff };
+ struct i2c_msg msg[] = {
+ { .addr = state->config.i2c_addr,
+ .flags = 0, .buf = reg_buf, .len = 2 },
+ { .addr = state->config.i2c_addr,
+ .flags = I2C_M_RD, .buf = val, .len = count },
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ dev_err(&state->i2c->dev, "%s: error (addr %02x reg %04x error (ret == %i)\n",
+ __func__, state->config.i2c_addr, reg, ret);
+ if (ret < 0)
+ return ret;
+ else
+ return -EREMOTEIO;
+ }
+
+ if (debug & DEBUG_I2C_READ)
+ deb_i2c_read("reg: 0x%04x, data: %*ph\n", reg, count, val);
+
+ return 0;
+}
+
+static int si2165_readreg8(struct si2165_state *state,
+ const u16 reg, u8 *val)
+{
+ int ret;
+
+ ret = si2165_read(state, reg, val, 1);
+ deb_readreg("R(0x%04x)=0x%02x\n", reg, *val);
+ return ret;
+}
+
+static int si2165_readreg16(struct si2165_state *state,
+ const u16 reg, u16 *val)
+{
+ u8 buf[2];
+
+ int ret = si2165_read(state, reg, buf, 2);
+ *val = buf[0] | buf[1] << 8;
+ deb_readreg("R(0x%04x)=0x%04x\n", reg, *val);
+ return ret;
+}
+
+static int si2165_writereg8(struct si2165_state *state, const u16 reg, u8 val)
+{
+ return si2165_write(state, reg, &val, 1);
+}
+
+static int si2165_writereg16(struct si2165_state *state, const u16 reg, u16 val)
+{
+ u8 buf[2] = { val & 0xff, (val >> 8) & 0xff };
+
+ return si2165_write(state, reg, buf, 2);
+}
+
+static int si2165_writereg24(struct si2165_state *state, const u16 reg, u32 val)
+{
+ u8 buf[3] = { val & 0xff, (val >> 8) & 0xff, (val >> 16) & 0xff };
+
+ return si2165_write(state, reg, buf, 3);
+}
+
+static int si2165_writereg32(struct si2165_state *state, const u16 reg, u32 val)
+{
+ u8 buf[4] = {
+ val & 0xff,
+ (val >> 8) & 0xff,
+ (val >> 16) & 0xff,
+ (val >> 24) & 0xff
+ };
+ return si2165_write(state, reg, buf, 4);
+}
+
+static int si2165_writereg_mask8(struct si2165_state *state, const u16 reg,
+ u8 val, u8 mask)
+{
+ int ret;
+ u8 tmp;
+
+ if (mask != 0xff) {
+ ret = si2165_readreg8(state, reg, &tmp);
+ if (ret < 0)
+ goto err;
+
+ val &= mask;
+ tmp &= ~mask;
+ val |= tmp;
+ }
+
+ ret = si2165_writereg8(state, reg, val);
+err:
+ return ret;
+}
+
+static int si2165_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 1000;
+ return 0;
+}
+
+static int si2165_init_pll(struct si2165_state *state)
+{
+ u32 ref_freq_Hz = state->config.ref_freq_Hz;
+ u8 divr = 1; /* 1..7 */
+ u8 divp = 1; /* only 1 or 4 */
+ u8 divn = 56; /* 1..63 */
+ u8 divm = 8;
+ u8 divl = 12;
+ u8 buf[4];
+
+ /* hardcoded values can be deleted if calculation is verified
+ * or it yields the same values as the windows driver */
+ switch (ref_freq_Hz) {
+ case 16000000u:
+ divn = 56;
+ break;
+ case 24000000u:
+ divr = 2;
+ divp = 4;
+ divn = 19;
+ break;
+ default:
+ /* ref_freq / divr must be between 4 and 16 MHz */
+ if (ref_freq_Hz > 16000000u)
+ divr = 2;
+
+ /* now select divn and divp such that
+ * fvco is in 1624..1824 MHz */
+ if (1624000000u * divr > ref_freq_Hz * 2u * 63u)
+ divp = 4;
+
+ /* is this already correct regarding rounding? */
+ divn = 1624000000u * divr / (ref_freq_Hz * 2u * divp);
+ break;
+ }
+
+ /* adc_clk and sys_clk depend on xtal and pll settings */
+ state->fvco_hz = ref_freq_Hz / divr
+ * 2u * divn * divp;
+ state->adc_clk = state->fvco_hz / (divm * 4u);
+ state->sys_clk = state->fvco_hz / (divl * 2u);
+
+ /* write pll registers 0x00a0..0x00a3 at once */
+ buf[0] = divl;
+ buf[1] = divm;
+ buf[2] = (divn & 0x3f) | ((divp == 1) ? 0x40 : 0x00) | 0x80;
+ buf[3] = divr;
+ return si2165_write(state, 0x00a0, buf, 4);
+}
+
+static int si2165_adjust_pll_divl(struct si2165_state *state, u8 divl)
+{
+ state->sys_clk = state->fvco_hz / (divl * 2u);
+ return si2165_writereg8(state, 0x00a0, divl); /* pll_divl */
+}
+
+static u32 si2165_get_fe_clk(struct si2165_state *state)
+{
+ /* assume Oversampling mode Ovr4 is used */
+ return state->adc_clk;
+}
+
+static bool si2165_wait_init_done(struct si2165_state *state)
+{
+ int ret = -EINVAL;
+ u8 val = 0;
+ int i;
+
+ for (i = 0; i < 3; ++i) {
+ si2165_readreg8(state, 0x0054, &val);
+ if (val == 0x01)
+ return 0;
+ usleep_range(1000, 50000);
+ }
+ dev_err(&state->i2c->dev, "%s: init_done was not set\n",
+ KBUILD_MODNAME);
+ return ret;
+}
+
+static int si2165_upload_firmware_block(struct si2165_state *state,
+ const u8 *data, u32 len, u32 *poffset, u32 block_count)
+{
+ int ret;
+ u8 buf_ctrl[4] = { 0x00, 0x00, 0x00, 0xc0 };
+ u8 wordcount;
+ u32 cur_block = 0;
+ u32 offset = poffset ? *poffset : 0;
+
+ if (len < 4)
+ return -EINVAL;
+ if (len % 4 != 0)
+ return -EINVAL;
+
+ deb_fw_load("si2165_upload_firmware_block called with len=0x%x offset=0x%x blockcount=0x%x\n",
+ len, offset, block_count);
+ while (offset+12 <= len && cur_block < block_count) {
+ deb_fw_load("si2165_upload_firmware_block in while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+ len, offset, cur_block, block_count);
+ wordcount = data[offset];
+ if (wordcount < 1 || data[offset+1] ||
+ data[offset+2] || data[offset+3]) {
+ dev_warn(&state->i2c->dev,
+ "%s: bad fw data[0..3] = %*ph\n",
+ KBUILD_MODNAME, 4, data);
+ return -EINVAL;
+ }
+
+ if (offset + 8 + wordcount * 4 > len) {
+ dev_warn(&state->i2c->dev,
+ "%s: len is too small for block len=%d, wordcount=%d\n",
+ KBUILD_MODNAME, len, wordcount);
+ return -EINVAL;
+ }
+
+ buf_ctrl[0] = wordcount - 1;
+
+ ret = si2165_write(state, 0x0364, buf_ctrl, 4);
+ if (ret < 0)
+ goto error;
+ ret = si2165_write(state, 0x0368, data+offset+4, 4);
+ if (ret < 0)
+ goto error;
+
+ offset += 8;
+
+ while (wordcount > 0) {
+ ret = si2165_write(state, 0x36c, data+offset, 4);
+ if (ret < 0)
+ goto error;
+ wordcount--;
+ offset += 4;
+ }
+ cur_block++;
+ }
+
+ deb_fw_load("si2165_upload_firmware_block after while len=0x%x offset=0x%x cur_block=0x%x blockcount=0x%x\n",
+ len, offset, cur_block, block_count);
+
+ if (poffset)
+ *poffset = offset;
+
+ deb_fw_load("si2165_upload_firmware_block returned offset=0x%x\n",
+ offset);
+
+ return 0;
+error:
+ return ret;
+}
+
+static int si2165_upload_firmware(struct si2165_state *state)
+{
+ /* int ret; */
+ u8 val[3];
+ u16 val16;
+ int ret;
+
+ const struct firmware *fw = NULL;
+ u8 *fw_file = SI2165_FIRMWARE;
+ const u8 *data;
+ u32 len;
+ u32 offset;
+ u8 patch_version;
+ u8 block_count;
+ u16 crc_expected;
+
+ /* 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",
+ KBUILD_MODNAME, fw_file);
+ goto error;
+ }
+
+ data = fw->data;
+ len = fw->size;
+
+ dev_info(&state->i2c->dev, "%s: downloading firmware from file '%s' size=%d\n",
+ KBUILD_MODNAME, fw_file, len);
+
+ if (len % 4 != 0) {
+ dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* check header (8 bytes) */
+ if (len < 8) {
+ dev_warn(&state->i2c->dev, "%s: firmware header is missing\n",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ if (data[0] != 1 || data[1] != 0) {
+ dev_warn(&state->i2c->dev, "%s: firmware file version is wrong\n",
+ KBUILD_MODNAME);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ patch_version = data[2];
+ block_count = data[4];
+ crc_expected = data[7] << 8 | data[6];
+
+ /* start uploading fw */
+ /* boot/wdog status */
+ ret = si2165_writereg8(state, 0x0341, 0x00);
+ if (ret < 0)
+ goto error;
+ /* reset */
+ ret = si2165_writereg8(state, 0x00c0, 0x00);
+ if (ret < 0)
+ goto error;
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, val);
+ if (ret < 0)
+ goto error;
+
+ /* enable reset on error */
+ ret = si2165_readreg8(state, 0x035c, val);
+ if (ret < 0)
+ goto error;
+ ret = si2165_readreg8(state, 0x035c, val);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x035c, 0x02);
+ if (ret < 0)
+ goto error;
+
+ /* start right after the header */
+ offset = 8;
+
+ dev_info(&state->i2c->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n",
+ KBUILD_MODNAME, patch_version, block_count, crc_expected);
+
+ ret = si2165_upload_firmware_block(state, data, len, &offset, 1);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_writereg8(state, 0x0344, patch_version);
+ if (ret < 0)
+ goto error;
+
+ /* reset crc */
+ ret = si2165_writereg8(state, 0x0379, 0x01);
+ if (ret)
+ return ret;
+
+ ret = si2165_upload_firmware_block(state, data, len,
+ &offset, block_count);
+ if (ret < 0) {
+ dev_err(&state->i2c->dev,
+ "%s: firmare could not be uploaded\n",
+ KBUILD_MODNAME);
+ goto error;
+ }
+
+ /* read crc */
+ ret = si2165_readreg16(state, 0x037a, &val16);
+ if (ret)
+ goto error;
+
+ if (val16 != crc_expected) {
+ dev_err(&state->i2c->dev,
+ "%s: firmware crc mismatch %04x != %04x\n",
+ KBUILD_MODNAME, val16, crc_expected);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ ret = si2165_upload_firmware_block(state, data, len, &offset, 5);
+ if (ret)
+ goto error;
+
+ if (len != offset) {
+ dev_err(&state->i2c->dev,
+ "%s: firmare len mismatch %04x != %04x\n",
+ KBUILD_MODNAME, len, offset);
+ ret = -EINVAL;
+ goto error;
+ }
+
+ /* reset watchdog error register */
+ ret = si2165_writereg_mask8(state, 0x0341, 0x02, 0x02);
+ if (ret < 0)
+ goto error;
+
+ /* enable reset on error */
+ ret = si2165_writereg_mask8(state, 0x035c, 0x01, 0x01);
+ if (ret < 0)
+ goto error;
+
+ dev_info(&state->i2c->dev, "%s: fw load finished\n", KBUILD_MODNAME);
+
+ ret = 0;
+ state->firmware_loaded = true;
+error:
+ if (fw) {
+ release_firmware(fw);
+ fw = NULL;
+ }
+
+ return ret;
+}
+
+static int si2165_init(struct dvb_frontend *fe)
+{
+ int ret = 0;
+ struct si2165_state *state = fe->demodulator_priv;
+ u8 val;
+ u8 patch_version = 0x00;
+
+ dprintk("%s: called\n", __func__);
+
+ /* powerup */
+ ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+ if (ret < 0)
+ goto error;
+ /* dsp_clock_enable */
+ ret = si2165_writereg8(state, 0x0104, 0x01);
+ if (ret < 0)
+ goto error;
+ ret = si2165_readreg8(state, 0x0000, &val); /* verify chip_mode */
+ if (ret < 0)
+ goto error;
+ if (val != state->config.chip_mode) {
+ dev_err(&state->i2c->dev, "%s: could not set chip_mode\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ /* agc */
+ ret = si2165_writereg8(state, 0x018b, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0190, 0x01);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0170, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0171, 0x07);
+ if (ret < 0)
+ goto error;
+ /* rssi pad */
+ ret = si2165_writereg8(state, 0x0646, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0641, 0x00);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_init_pll(state);
+ if (ret < 0)
+ goto error;
+
+ /* enable chip_init */
+ ret = si2165_writereg8(state, 0x0050, 0x01);
+ if (ret < 0)
+ goto error;
+ /* set start_init */
+ ret = si2165_writereg8(state, 0x0096, 0x01);
+ if (ret < 0)
+ goto error;
+ ret = si2165_wait_init_done(state);
+ if (ret < 0)
+ goto error;
+
+ /* disable chip_init */
+ ret = si2165_writereg8(state, 0x0050, 0x00);
+ if (ret < 0)
+ goto error;
+
+ /* ber_pkt */
+ ret = si2165_writereg16(state, 0x0470 , 0x7530);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_readreg8(state, 0x0344, &patch_version);
+ if (ret < 0)
+ goto error;
+
+ ret = si2165_writereg8(state, 0x00cb, 0x00);
+ if (ret < 0)
+ goto error;
+
+ /* dsp_addr_jump */
+ ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+ if (ret < 0)
+ goto error;
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, &val);
+ if (ret < 0)
+ goto error;
+
+ if (patch_version == 0x00) {
+ ret = si2165_upload_firmware(state);
+ if (ret < 0)
+ goto error;
+ }
+
+ /* write adc values after each reset*/
+ ret = si2165_writereg8(state, 0x012a, 0x46);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x012c, 0x00);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x012e, 0x0a);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x012f, 0xff);
+ if (ret < 0)
+ goto error;
+ ret = si2165_writereg8(state, 0x0123, 0x70);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+error:
+ return ret;
+}
+
+static int si2165_sleep(struct dvb_frontend *fe)
+{
+ int ret;
+ struct si2165_state *state = fe->demodulator_priv;
+
+ /* dsp clock disable */
+ ret = si2165_writereg8(state, 0x0104, 0x00);
+ if (ret < 0)
+ return ret;
+ /* chip mode */
+ ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int si2165_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ int ret;
+ u8 fec_lock = 0;
+ struct si2165_state *state = fe->demodulator_priv;
+
+ if (!state->has_dvbt)
+ return -EINVAL;
+
+ /* check fec_lock */
+ ret = si2165_readreg8(state, 0x4e0, &fec_lock);
+ if (ret < 0)
+ return ret;
+ *status = 0;
+ if (fec_lock & 0x01) {
+ *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+ *status |= FE_HAS_LOCK;
+ }
+
+ return 0;
+}
+
+static int si2165_set_oversamp(struct si2165_state *state, u32 dvb_rate)
+{
+ u64 oversamp;
+ u32 reg_value;
+
+ oversamp = si2165_get_fe_clk(state);
+ oversamp <<= 23;
+ do_div(oversamp, dvb_rate);
+ reg_value = oversamp & 0x3fffffff;
+
+ /* oversamp, usbdump contained 0x03100000; */
+ return si2165_writereg32(state, 0x00e4, reg_value);
+}
+
+static int si2165_set_if_freq_shift(struct si2165_state *state, u32 IF)
+{
+ u64 if_freq_shift;
+ s32 reg_value = 0;
+ u32 fe_clk = si2165_get_fe_clk(state);
+
+ if_freq_shift = IF;
+ if_freq_shift <<= 29;
+
+ do_div(if_freq_shift, fe_clk);
+ reg_value = (s32)if_freq_shift;
+
+ if (state->config.inversion)
+ reg_value = -reg_value;
+
+ reg_value = reg_value & 0x1fffffff;
+
+ /* if_freq_shift, usbdump contained 0x023ee08f; */
+ return si2165_writereg32(state, 0x00e8, reg_value);
+}
+
+static int si2165_set_parameters(struct dvb_frontend *fe)
+{
+ int ret;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ struct si2165_state *state = fe->demodulator_priv;
+ u8 val[3];
+ u32 IF;
+ u32 dvb_rate = 0;
+ u16 bw10k;
+
+ dprintk("%s: called\n", __func__);
+
+ if (!fe->ops.tuner_ops.get_if_frequency) {
+ dev_err(&state->i2c->dev,
+ "%s: Error: get_if_frequency() not defined at tuner. Can't work without it!\n",
+ KBUILD_MODNAME);
+ return -EINVAL;
+ }
+
+ if (!state->has_dvbt)
+ return -EINVAL;
+
+ if (p->bandwidth_hz > 0) {
+ dvb_rate = p->bandwidth_hz * 8 / 7;
+ bw10k = p->bandwidth_hz / 10000;
+ } else {
+ dvb_rate = 8 * 8 / 7;
+ bw10k = 800;
+ }
+
+ /* standard = DVB-T */
+ ret = si2165_writereg8(state, 0x00ec, 0x01);
+ if (ret < 0)
+ return ret;
+ ret = si2165_adjust_pll_divl(state, 12);
+ if (ret < 0)
+ return ret;
+
+ fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+ ret = si2165_set_if_freq_shift(state, IF);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x08f8, 0x00);
+ if (ret < 0)
+ return ret;
+ /* ts output config */
+ ret = si2165_writereg8(state, 0x04e4, 0x20);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg16(state, 0x04ef, 0x00fe);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg24(state, 0x04f4, 0x555555);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x04e5, 0x01);
+ if (ret < 0)
+ return ret;
+ /* bandwidth in 10KHz steps */
+ ret = si2165_writereg16(state, 0x0308, bw10k);
+ if (ret < 0)
+ return ret;
+ ret = si2165_set_oversamp(state, dvb_rate);
+ if (ret < 0)
+ return ret;
+ /* impulsive_noise_remover */
+ ret = si2165_writereg8(state, 0x031c, 0x01);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x00cb, 0x00);
+ if (ret < 0)
+ return ret;
+ /* agc2 */
+ ret = si2165_writereg8(state, 0x016e, 0x41);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x016c, 0x0e);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x016d, 0x10);
+ if (ret < 0)
+ return ret;
+ /* agc */
+ ret = si2165_writereg8(state, 0x015b, 0x03);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x0150, 0x78);
+ if (ret < 0)
+ return ret;
+ /* agc */
+ ret = si2165_writereg8(state, 0x01a0, 0x78);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x01c8, 0x68);
+ if (ret < 0)
+ return ret;
+ /* freq_sync_range */
+ ret = si2165_writereg16(state, 0x030c, 0x0064);
+ if (ret < 0)
+ return ret;
+ /* gp_reg0 */
+ ret = si2165_readreg8(state, 0x0387, val);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x0387, 0x00);
+ if (ret < 0)
+ return ret;
+ /* dsp_addr_jump */
+ ret = si2165_writereg32(state, 0x0348, 0xf4000000);
+ if (ret < 0)
+ return ret;
+
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* recalc if_freq_shift if IF might has changed */
+ fe->ops.tuner_ops.get_if_frequency(fe, &IF);
+ ret = si2165_set_if_freq_shift(state, IF);
+ if (ret < 0)
+ return ret;
+
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, val);
+ if (ret < 0)
+ return ret;
+ ret = si2165_writereg8(state, 0x0341, 0x00);
+ if (ret < 0)
+ return ret;
+ /* reset all */
+ ret = si2165_writereg8(state, 0x00c0, 0x00);
+ if (ret < 0)
+ return ret;
+ /* gp_reg0 */
+ ret = si2165_writereg32(state, 0x0384, 0x00000000);
+ if (ret < 0)
+ return ret;
+ /* start_synchro */
+ ret = si2165_writereg8(state, 0x02e0, 0x01);
+ if (ret < 0)
+ return ret;
+ /* boot/wdog status */
+ ret = si2165_readreg8(state, 0x0341, val);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static void si2165_release(struct dvb_frontend *fe)
+{
+ struct si2165_state *state = fe->demodulator_priv;
+
+ dprintk("%s: called\n", __func__);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops si2165_ops = {
+ .info = {
+ .name = "Silicon Labs Si2165",
+ .caps = 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_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_RECOVER
+ },
+
+ .get_tune_settings = si2165_get_tune_settings,
+
+ .init = si2165_init,
+ .sleep = si2165_sleep,
+
+ .set_frontend = si2165_set_parameters,
+ .read_status = si2165_read_status,
+
+ .release = si2165_release,
+};
+
+struct dvb_frontend *si2165_attach(const struct si2165_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct si2165_state *state = NULL;
+ int n;
+ int io_ret;
+ u8 val;
+
+ if (config == NULL || i2c == NULL)
+ goto error;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct si2165_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->i2c = i2c;
+ state->config = *config;
+
+ if (state->config.ref_freq_Hz < 4000000
+ || state->config.ref_freq_Hz > 27000000) {
+ dev_err(&state->i2c->dev, "%s: ref_freq of %d Hz not supported by this driver\n",
+ KBUILD_MODNAME, state->config.ref_freq_Hz);
+ goto error;
+ }
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &si2165_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* powerup */
+ io_ret = si2165_writereg8(state, 0x0000, state->config.chip_mode);
+ if (io_ret < 0)
+ goto error;
+
+ io_ret = si2165_readreg8(state, 0x0000, &val);
+ if (io_ret < 0)
+ goto error;
+ if (val != state->config.chip_mode)
+ goto error;
+
+ io_ret = si2165_readreg8(state, 0x0023 , &state->revcode);
+ if (io_ret < 0)
+ goto error;
+
+ io_ret = si2165_readreg8(state, 0x0118, &state->chip_type);
+ if (io_ret < 0)
+ goto error;
+
+ /* powerdown */
+ io_ret = si2165_writereg8(state, 0x0000, SI2165_MODE_OFF);
+ 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);
+
+ /* 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) {
+ state->has_dvbt = true;
+ state->has_dvbc = true;
+ } else {
+ dev_err(&state->i2c->dev, "%s: Unsupported chip.\n",
+ KBUILD_MODNAME);
+ goto error;
+ }
+
+ n = 0;
+ if (state->has_dvbt) {
+ state->frontend.ops.delsys[n++] = SYS_DVBT;
+ strlcat(state->frontend.ops.info.name, " DVB-T",
+ sizeof(state->frontend.ops.info.name));
+ }
+ if (state->has_dvbc)
+ dev_warn(&state->i2c->dev, "%s: DVB-C is not yet supported.\n",
+ KBUILD_MODNAME);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(si2165_attach);
+
+module_param(debug, int, 0644);
+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 ");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SI2165_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/si2165.h b/drivers/media/dvb-frontends/si2165.h
new file mode 100644
index 000000000000..efaa08123b92
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2165.h
@@ -0,0 +1,62 @@
+/*
+ Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+ Copyright (C) 2013-2014 Matthias Schwarzott
+
+ 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.
+
+ References:
+ http://www.silabs.com/Support%20Documents/TechnicalDocs/Si2165-short.pdf
+*/
+
+#ifndef _DVB_SI2165_H
+#define _DVB_SI2165_H
+
+#include
+
+enum {
+ SI2165_MODE_OFF = 0x00,
+ SI2165_MODE_PLL_EXT = 0x20,
+ SI2165_MODE_PLL_XTAL = 0x21
+};
+
+struct si2165_config {
+ /* i2c addr
+ * possible values: 0x64,0x65,0x66,0x67 */
+ u8 i2c_addr;
+
+ /* external clock or XTAL */
+ u8 chip_mode;
+
+ /* frequency of external clock or xtal in Hz
+ * possible values: 4000000, 16000000, 20000000, 240000000, 27000000
+ */
+ u32 ref_freq_Hz;
+
+ /* invert the spectrum */
+ bool inversion;
+};
+
+#if IS_ENABLED(CONFIG_DVB_SI2165)
+struct dvb_frontend *si2165_attach(
+ const struct si2165_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *si2165_attach(
+ const struct si2165_config *config,
+ struct i2c_adapter *i2c)
+{
+ pr_warn("%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_SI2165 */
+
+#endif /* _DVB_SI2165_H */
diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h
new file mode 100644
index 000000000000..d4cc93fe1096
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2165_priv.h
@@ -0,0 +1,23 @@
+/*
+ Driver for Silicon Labs SI2165 DVB-C/-T Demodulator
+
+ Copyright (C) 2013-2014 Matthias Schwarzott
+
+ 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 _DVB_SI2165_PRIV
+#define _DVB_SI2165_PRIV
+
+#define SI2165_FIRMWARE "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 2e3cdcfa0a67..8f81d979de30 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -95,20 +95,17 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
switch (c->delivery_system) {
case SYS_DVBT:
- cmd.args[0] = 0xa0;
- cmd.args[1] = 0x01;
+ memcpy(cmd.args, "\xa0\x01", 2);
cmd.wlen = 2;
cmd.rlen = 13;
break;
case SYS_DVBC_ANNEX_A:
- cmd.args[0] = 0x90;
- cmd.args[1] = 0x01;
+ memcpy(cmd.args, "\x90\x01", 2);
cmd.wlen = 2;
cmd.rlen = 9;
break;
case SYS_DVBT2:
- cmd.args[0] = 0x50;
- cmd.args[1] = 0x01;
+ memcpy(cmd.args, "\x50\x01", 2);
cmd.wlen = 2;
cmd.rlen = 14;
break;
@@ -144,6 +141,15 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
s->fe_status = *status;
+ if (*status & FE_HAS_LOCK) {
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = cmd.args[3] * 1000 / 4;
+ } else {
+ c->cnr.len = 1;
+ 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);
@@ -243,51 +249,23 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
- memcpy(cmd.args, "\x14\x00\x01\x04\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x03\x10\x17\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x02\x10\x15\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
cmd.wlen = 6;
- cmd.rlen = 1;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x0b\x10\x88\x13", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
cmd.wlen = 6;
- cmd.rlen = 1;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
@@ -295,124 +273,66 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
cmd.args[4] = delivery_system | bandwidth;
cmd.wlen = 6;
- cmd.rlen = 1;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
- memcpy(cmd.args, "\x14\x00\x04\x10\x15\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x05\x10\xa1\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
+ /* set DVB-C symbol rate */
+ if (c->delivery_system == SYS_DVBC_ANNEX_A) {
+ memcpy(cmd.args, "\x14\x00\x02\x11", 4);
+ cmd.args[4] = (c->symbol_rate / 1000) & 0xff;
+ cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff;
+ cmd.wlen = 6;
+ cmd.rlen = 4;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+ }
memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x0d\x10\xd0\x02", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- 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 = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x04\x03\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x03\x03\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x08\x03\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x07\x03\x01\x02", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x06\x03\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x05\x03\x00\x00", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x40", 6);
- cmd.wlen = 6;
- cmd.rlen = 1;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
cmd.wlen = 6;
- cmd.rlen = 1;
+ 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;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
cmd.wlen = 6;
- cmd.rlen = 1;
+ cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
- cmd.args[0] = 0x85;
+ memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 4;
+ 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);
@@ -432,59 +352,61 @@ static int si2168_init(struct dvb_frontend *fe)
struct si2168 *s = fe->demodulator_priv;
int ret, len, remaining;
const struct firmware *fw = NULL;
- u8 *fw_file = SI2168_FIRMWARE;
+ u8 *fw_file;
const unsigned int i2c_wr_max = 8;
struct si2168_cmd cmd;
+ unsigned int chip_id;
dev_dbg(&s->client->dev, "%s:\n", __func__);
- cmd.args[0] = 0x13;
- cmd.wlen = 1;
- cmd.rlen = 0;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
- cmd.args[0] = 0xc0;
- cmd.args[1] = 0x12;
- cmd.args[2] = 0x00;
- cmd.args[3] = 0x0c;
- cmd.args[4] = 0x00;
- cmd.args[5] = 0x0d;
- cmd.args[6] = 0x16;
- cmd.args[7] = 0x00;
- cmd.args[8] = 0x00;
- cmd.args[9] = 0x00;
- cmd.args[10] = 0x00;
- cmd.args[11] = 0x00;
- cmd.args[12] = 0x00;
+ memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
cmd.wlen = 13;
cmd.rlen = 0;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
- cmd.args[0] = 0xc0;
- cmd.args[1] = 0x06;
- cmd.args[2] = 0x01;
- cmd.args[3] = 0x0f;
- cmd.args[4] = 0x00;
- cmd.args[5] = 0x20;
- cmd.args[6] = 0x20;
- cmd.args[7] = 0x01;
+ memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
cmd.wlen = 8;
cmd.rlen = 1;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
- cmd.args[0] = 0x02;
+ /* query chip revision */
+ memcpy(cmd.args, "\x02", 1);
cmd.wlen = 1;
cmd.rlen = 13;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
+ chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
+ cmd.args[4] << 0;
+
+ #define SI2168_A20 ('A' << 24 | 68 << 16 | '2' << 8 | '0' << 0)
+ #define SI2168_A30 ('A' << 24 | 68 << 16 | '3' << 8 | '0' << 0)
+ #define SI2168_B40 ('B' << 24 | 68 << 16 | '4' << 8 | '0' << 0)
+
+ switch (chip_id) {
+ case SI2168_A20:
+ fw_file = SI2168_A20_FIRMWARE;
+ break;
+ case SI2168_A30:
+ fw_file = SI2168_A30_FIRMWARE;
+ break;
+ case SI2168_B40:
+ fw_file = SI2168_B40_FIRMWARE;
+ 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],
+ 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);
@@ -492,9 +414,22 @@ static int si2168_init(struct dvb_frontend *fe)
/* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, &s->client->dev);
if (ret) {
- dev_err(&s->client->dev, "%s: firmare file '%s' not found\n",
- KBUILD_MODNAME, fw_file);
- goto err;
+ /* fallback mechanism to handle old name for Si2168 B40 fw */
+ if (chip_id == SI2168_B40) {
+ fw_file = SI2168_B40_FIRMWARE_FALLBACK;
+ ret = request_firmware(&fw, fw_file, &s->client->dev);
+ }
+
+ if (ret == 0) {
+ dev_notice(&s->client->dev,
+ "%s: please install firmware file '%s'\n",
+ KBUILD_MODNAME, SI2168_B40_FIRMWARE);
+ } else {
+ dev_err(&s->client->dev,
+ "%s: firmware file '%s' not found\n",
+ KBUILD_MODNAME, fw_file);
+ goto err;
+ }
}
dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
@@ -520,8 +455,7 @@ static int si2168_init(struct dvb_frontend *fe)
release_firmware(fw);
fw = NULL;
- cmd.args[0] = 0x01;
- cmd.args[1] = 0x01;
+ memcpy(cmd.args, "\x01\x01", 2);
cmd.wlen = 2;
cmd.rlen = 1;
ret = si2168_cmd_execute(s, &cmd);
@@ -545,12 +479,24 @@ err:
static int si2168_sleep(struct dvb_frontend *fe)
{
struct si2168 *s = fe->demodulator_priv;
+ int ret;
+ struct si2168_cmd cmd;
dev_dbg(&s->client->dev, "%s:\n", __func__);
s->active = false;
+ memcpy(cmd.args, "\x13", 1);
+ cmd.wlen = 1;
+ cmd.rlen = 0;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
}
static int si2168_get_tune_settings(struct dvb_frontend *fe,
@@ -660,7 +606,6 @@ static int si2168_probe(struct i2c_client *client,
struct si2168_config *config = client->dev.platform_data;
struct si2168 *s;
int ret;
- struct si2168_cmd cmd;
dev_dbg(&client->dev, "%s:\n", __func__);
@@ -674,18 +619,13 @@ static int si2168_probe(struct i2c_client *client,
s->client = client;
mutex_init(&s->i2c_mutex);
- /* check if the demod is there */
- cmd.wlen = 0;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret)
- goto err;
-
/* create mux i2c adapter for tuner */
s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s,
0, 0, 0, si2168_select, si2168_deselect);
- if (s->adapter == NULL)
+ if (s->adapter == NULL) {
+ ret = -ENODEV;
goto err;
+ }
/* create dvb_frontend */
memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
@@ -743,4 +683,6 @@ module_i2c_driver(si2168_driver);
MODULE_AUTHOR("Antti Palosaari ");
MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver");
MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(SI2168_FIRMWARE);
+MODULE_FIRMWARE(SI2168_A20_FIRMWARE);
+MODULE_FIRMWARE(SI2168_A30_FIRMWARE);
+MODULE_FIRMWARE(SI2168_B40_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index 53f7f06ae343..ebbf502ec313 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -22,7 +22,10 @@
#include
#include
-#define SI2168_FIRMWARE "dvb-demod-si2168-02.fw"
+#define SI2168_A20_FIRMWARE "dvb-demod-si2168-a20-01.fw"
+#define SI2168_A30_FIRMWARE "dvb-demod-si2168-a30-01.fw"
+#define SI2168_B40_FIRMWARE "dvb-demod-si2168-b40-01.fw"
+#define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw"
/* state struct */
struct si2168 {
@@ -36,9 +39,9 @@ struct si2168 {
};
/* firmare command struct */
-#define SI2157_ARGLEN 30
+#define SI2168_ARGLEN 30
struct si2168_cmd {
- u8 args[SI2157_ARGLEN];
+ u8 args[SI2168_ARGLEN];
unsigned wlen;
unsigned rlen;
};
diff --git a/drivers/media/dvb-frontends/stb6100_cfg.h b/drivers/media/dvb-frontends/stb6100_cfg.h
index 6314d18c797a..6edc15365847 100644
--- a/drivers/media/dvb-frontends/stb6100_cfg.h
+++ b/drivers/media/dvb-frontends/stb6100_cfg.h
@@ -21,17 +21,14 @@
static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
- if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+ err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
@@ -42,18 +39,16 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
t_state.frequency = frequency;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+
if (tuner_ops->set_state) {
- if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+ err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
@@ -68,12 +63,9 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
struct tuner_state t_state;
int err = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
- if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+ err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
@@ -84,18 +76,16 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
t_state.bandwidth = bandwidth;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+
if (tuner_ops->set_state) {
- if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+ err = tuner_ops->set_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
diff --git a/drivers/media/dvb-frontends/stb6100_proc.h b/drivers/media/dvb-frontends/stb6100_proc.h
index 112163a48622..bd8a0ec9e2cc 100644
--- a/drivers/media/dvb-frontends/stb6100_proc.h
+++ b/drivers/media/dvb-frontends/stb6100_proc.h
@@ -19,15 +19,11 @@
static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state state;
int err = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
@@ -49,16 +45,13 @@ static int stb6100_get_freq(struct dvb_frontend *fe, u32 *frequency)
static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state state;
int err = 0;
state.frequency = frequency;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+
if (tuner_ops->set_state) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
@@ -79,15 +72,11 @@ static int stb6100_set_freq(struct dvb_frontend *fe, u32 frequency)
static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state state;
int err = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
@@ -109,16 +98,13 @@ static int stb6100_get_bandw(struct dvb_frontend *fe, u32 *bandwidth)
static int stb6100_set_bandw(struct dvb_frontend *fe, u32 bandwidth)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state state;
int err = 0;
state.bandwidth = bandwidth;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+
if (tuner_ops->set_state) {
if (frontend_ops->i2c_gate_ctrl)
frontend_ops->i2c_gate_ctrl(fe, 1);
diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c
index 458772739423..59b6e661acc0 100644
--- a/drivers/media/dvb-frontends/stv0367.c
+++ b/drivers/media/dvb-frontends/stv0367.c
@@ -922,18 +922,13 @@ static int stv0367ter_gate_ctrl(struct dvb_frontend *fe, int enable)
static u32 stv0367_get_tuner_freq(struct dvb_frontend *fe)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
u32 freq = 0;
int err = 0;
dprintk("%s:\n", __func__);
-
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_frequency) {
err = tuner_ops->get_frequency(fe, &freq);
if (err < 0) {
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c
index 2c54586ac07f..de0a1c110972 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd.c
+++ b/drivers/media/dvb-frontends/tda18271c2dd.c
@@ -1030,7 +1030,7 @@ static int ChannelConfiguration(struct tda_state *state,
state->m_Regs[EP4] = state->m_EP4 | state->m_IFLevelDigital;
if ((Standard == HF_FM_Radio) && state->m_bFMInput)
- state->m_Regs[EP4] |= 80;
+ state->m_Regs[EP4] |= 0x80;
state->m_Regs[MPD] &= ~0x80;
if (Standard > HF_AnalogMax)
diff --git a/drivers/media/dvb-frontends/tda18271c2dd_maps.h b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
index b87661b9df14..f3bca5c237d7 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd_maps.h
+++ b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
@@ -5,7 +5,7 @@ enum HF_S {
HF_DVBC_8MHZ, HF_DVBC
};
-struct SStandardParam m_StandardTable[] = {
+static struct SStandardParam m_StandardTable[] = {
{ 0, 0, 0x00, 0x00 }, /* HF_None */
{ 6000000, 7000000, 0x1D, 0x2C }, /* HF_B, */
{ 6900000, 8000000, 0x1E, 0x2C }, /* HF_DK, */
@@ -27,7 +27,7 @@ struct SStandardParam m_StandardTable[] = {
{ 0, 0, 0x00, 0x00 }, /* HF_DVBC (Unused) */
};
-struct SMap m_BP_Filter_Map[] = {
+static struct SMap m_BP_Filter_Map[] = {
{ 62000000, 0x00 },
{ 84000000, 0x01 },
{ 100000000, 0x02 },
@@ -799,14 +799,14 @@ static struct SRFBandMap m_RF_Band_Map[7] = {
{ 865000000, 489500000, 697500000, 842000000},
};
-u8 m_Thermometer_Map_1[16] = {
+static u8 m_Thermometer_Map_1[16] = {
60, 62, 66, 64,
74, 72, 68, 70,
90, 88, 84, 86,
76, 78, 82, 80,
};
-u8 m_Thermometer_Map_2[16] = {
+static u8 m_Thermometer_Map_2[16] = {
92, 94, 98, 96,
106, 104, 100, 102,
122, 120, 116, 118,
diff --git a/drivers/media/dvb-frontends/tda8261_cfg.h b/drivers/media/dvb-frontends/tda8261_cfg.h
index 46710744173b..04a19e14ee5a 100644
--- a/drivers/media/dvb-frontends/tda8261_cfg.h
+++ b/drivers/media/dvb-frontends/tda8261_cfg.h
@@ -19,17 +19,14 @@
static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
- if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+ err = tuner_ops->get_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
@@ -41,18 +38,16 @@ static int tda8261_get_frequency(struct dvb_frontend *fe, u32 *frequency)
static int tda8261_set_frequency(struct dvb_frontend *fe, u32 frequency)
{
- struct dvb_frontend_ops *frontend_ops = NULL;
- struct dvb_tuner_ops *tuner_ops = NULL;
+ struct dvb_frontend_ops *frontend_ops = &fe->ops;
+ struct dvb_tuner_ops *tuner_ops = &frontend_ops->tuner_ops;
struct tuner_state t_state;
int err = 0;
t_state.frequency = frequency;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
+
if (tuner_ops->set_state) {
- if ((err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state)) < 0) {
+ err = tuner_ops->set_state(fe, DVBFE_TUNER_FREQUENCY, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
@@ -68,12 +63,9 @@ static int tda8261_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
struct tuner_state t_state;
int err = 0;
- if (&fe->ops)
- frontend_ops = &fe->ops;
- if (&frontend_ops->tuner_ops)
- tuner_ops = &frontend_ops->tuner_ops;
if (tuner_ops->get_state) {
- if ((err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state)) < 0) {
+ err = tuner_ops->get_state(fe, DVBFE_TUNER_BANDWIDTH, &t_state);
+ if (err < 0) {
printk("%s: Invalid parameter\n", __func__);
return err;
}
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 441053be7f55..f40b4cf6107a 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -551,6 +551,7 @@ config VIDEO_MT9V032
tristate "Micron MT9V032 sensor support"
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on MEDIA_CAMERA_SUPPORT
+ select REGMAP_I2C
---help---
This is a Video4Linux2 sensor-level driver for the Micron
MT9V032 752x480 CMOS sensor.
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index ac1cdbe251a3..821178dcb08e 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -663,7 +663,6 @@ static int adv7180_remove(struct i2c_client *client)
if (state->irq > 0)
free_irq(client->irq, state);
- v4l2_device_unregister_subdev(sd);
adv7180_exit_controls(state);
mutex_destroy(&state->mutex);
return 0;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 1778d320272e..d4fa213ba74a 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -2588,8 +2588,11 @@ static const struct adv7604_reg_seq adv7604_recommended_settings_hdmi[] = {
};
static const struct adv7604_reg_seq adv7611_recommended_settings_hdmi[] = {
+ /* ADV7611 Register Settings Recommendations Rev 1.5, May 2014 */
{ ADV7604_REG(ADV7604_PAGE_CP, 0x6c), 0x00 },
- { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x0c },
+ { ADV7604_REG(ADV7604_PAGE_HDMI, 0x9b), 0x03 },
+ { ADV7604_REG(ADV7604_PAGE_HDMI, 0x6f), 0x08 },
+ { ADV7604_REG(ADV7604_PAGE_HDMI, 0x85), 0x1f },
{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x87), 0x70 },
{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x57), 0xda },
{ ADV7604_REG(ADV7604_PAGE_HDMI, 0x58), 0x01 },
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index c8fe1358ec9e..8311f1a9a38e 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -62,8 +62,8 @@ module_param(debug, int, 0644); /* debug level (0,1,2) */
/* ----------------------------------------------------------------------- */
-static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
- int size, int offset)
+static int get_key_haup_common(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *ptoggle, int size, int offset)
{
unsigned char buf[6];
int start, range, toggle, dev, code, ircode;
@@ -86,19 +86,10 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
if (!start)
/* no key pressed */
return 0;
- /*
- * Hauppauge remotes (black/silver) always use
- * specific device ids. If we do not filter the
- * device ids then messages destined for devices
- * such as TVs (id=0) will get through causing
- * mis-fired events.
- *
- * We also filter out invalid key presses which
- * produce annoying debug log entries.
- */
- ircode= (start << 12) | (toggle << 11) | (dev << 6) | code;
- if ((ircode & 0x1fff)==0x1fff)
- /* invalid key press */
+
+ /* filter out invalid key presses */
+ ircode = (start << 12) | (toggle << 11) | (dev << 6) | code;
+ if ((ircode & 0x1fff) == 0x1fff)
return 0;
if (!range)
@@ -107,18 +98,20 @@ static int get_key_haup_common(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
start, range, toggle, dev, code);
- /* return key */
- *ir_key = (dev << 8) | code;
- *ir_raw = ircode;
+ *protocol = RC_TYPE_RC5;
+ *scancode = RC_SCANCODE_RC5(dev, code);
+ *ptoggle = toggle;
return 1;
}
-static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
- return get_key_haup_common (ir, ir_key, ir_raw, 3, 0);
+ return get_key_haup_common (ir, protocol, scancode, toggle, 3, 0);
}
-static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_haup_xvr(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
int ret;
unsigned char buf[1] = { 0 };
@@ -133,10 +126,11 @@ static int get_key_haup_xvr(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (ret != 1)
return (ret < 0) ? ret : -EINVAL;
- return get_key_haup_common (ir, ir_key, ir_raw, 6, 3);
+ return get_key_haup_common(ir, protocol, scancode, toggle, 6, 3);
}
-static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pixelview(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char b;
@@ -145,12 +139,15 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
dprintk(1,"read error\n");
return -EIO;
}
- *ir_key = b;
- *ir_raw = b;
+
+ *protocol = RC_TYPE_OTHER;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
-static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_fusionhdtv(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char buf[4];
@@ -168,13 +165,14 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if(buf[0] != 0x1 || buf[1] != 0xfe)
return 0;
- *ir_key = buf[2];
- *ir_raw = (buf[2] << 8) | buf[3];
-
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = buf[2];
+ *toggle = 0;
return 1;
}
-static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_knc1(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char b;
@@ -197,13 +195,14 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
/* keep old data */
return 1;
- *ir_key = b;
- *ir_raw = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
-static int get_key_avermedia_cardbus(struct IR_i2c *ir,
- u32 *ir_key, u32 *ir_raw)
+static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char subaddr, key, keygroup;
struct i2c_msg msg[] = { { .addr = ir->c->addr, .flags = 0,
@@ -237,12 +236,11 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
}
key |= (keygroup & 1) << 6;
- *ir_key = key;
- *ir_raw = key;
- if (!strcmp(ir->ir_codes, RC_MAP_AVERMEDIA_M733A_RM_K6)) {
- *ir_key |= keygroup << 8;
- *ir_raw |= keygroup << 8;
- }
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = key;
+ if (ir->c->addr == 0x41) /* AVerMedia EM78P153 */
+ *scancode |= keygroup << 8;
+ *toggle = 0;
return 1;
}
@@ -250,19 +248,22 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir,
static int ir_key_poll(struct IR_i2c *ir)
{
- static u32 ir_key, ir_raw;
+ enum rc_type protocol;
+ u32 scancode;
+ u8 toggle;
int rc;
dprintk(3, "%s\n", __func__);
- rc = ir->get_key(ir, &ir_key, &ir_raw);
+ rc = ir->get_key(ir, &protocol, &scancode, &toggle);
if (rc < 0) {
dprintk(2,"error\n");
return rc;
}
if (rc) {
- dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
- rc_keydown(ir->rc, ir_key, 0);
+ dprintk(1, "%s: proto = 0x%04x, scancode = 0x%08x\n",
+ __func__, protocol, scancode);
+ rc_keydown(ir->rc, protocol, scancode, toggle);
}
return 0;
}
@@ -327,7 +328,7 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x6b:
name = "FusionHDTV";
ir->get_key = get_key_fusionhdtv;
- rc_type = RC_BIT_RC5;
+ rc_type = RC_BIT_UNKNOWN;
ir_codes = RC_MAP_FUSIONHDTV_MCE;
break;
case 0x40:
@@ -431,8 +432,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
* Initialize the other fields of rc_dev
*/
rc->map_name = ir->ir_codes;
- rc_set_allowed_protocols(rc, rc_type);
- rc_set_enabled_protocols(rc, rc_type);
+ rc->allowed_protocols = rc_type;
+ rc->enabled_protocols = rc_type;
if (!rc->driver_name)
rc->driver_name = MODULE_NAME;
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 40172b8d8ea2..d044bce312e0 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -1,5 +1,5 @@
/*
- * Driver for MT9V032 CMOS Image Sensor from Micron
+ * Driver for MT9V022, MT9V024, MT9V032, and MT9V034 CMOS Image Sensors
*
* Copyright (C) 2010, Laurent Pinchart
*
@@ -17,6 +17,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -87,6 +88,7 @@
#define MT9V032_READ_MODE_COLUMN_FLIP (1 << 5)
#define MT9V032_READ_MODE_DARK_COLUMNS (1 << 6)
#define MT9V032_READ_MODE_DARK_ROWS (1 << 7)
+#define MT9V032_READ_MODE_RESERVED 0x0300
#define MT9V032_PIXEL_OPERATION_MODE 0x0f
#define MT9V034_PIXEL_OPERATION_MODE_HDR (1 << 0)
#define MT9V034_PIXEL_OPERATION_MODE_COLOR (1 << 1)
@@ -133,8 +135,12 @@
#define MT9V032_THERMAL_INFO 0xc1
enum mt9v032_model {
- MT9V032_MODEL_V032_COLOR,
- MT9V032_MODEL_V032_MONO,
+ MT9V032_MODEL_V022_COLOR, /* MT9V022IX7ATC */
+ MT9V032_MODEL_V022_MONO, /* MT9V022IX7ATM */
+ MT9V032_MODEL_V024_COLOR, /* MT9V024IA7XTC */
+ MT9V032_MODEL_V024_MONO, /* MT9V024IA7XTM */
+ MT9V032_MODEL_V032_COLOR, /* MT9V032C12STM */
+ MT9V032_MODEL_V032_MONO, /* MT9V032C12STC */
MT9V032_MODEL_V034_COLOR,
MT9V032_MODEL_V034_MONO,
};
@@ -160,14 +166,14 @@ struct mt9v032_model_info {
};
static const struct mt9v032_model_version mt9v032_versions[] = {
- { MT9V032_CHIP_ID_REV1, "MT9V032 rev1/2" },
- { MT9V032_CHIP_ID_REV3, "MT9V032 rev3" },
- { MT9V034_CHIP_ID_REV1, "MT9V034 rev1" },
+ { MT9V032_CHIP_ID_REV1, "MT9V022/MT9V032 rev1/2" },
+ { MT9V032_CHIP_ID_REV3, "MT9V022/MT9V032 rev3" },
+ { MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" },
};
static const struct mt9v032_model_data mt9v032_model_data[] = {
{
- /* MT9V032 revisions 1/2/3 */
+ /* MT9V022, MT9V032 revisions 1/2/3 */
.min_row_time = 660,
.min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
@@ -176,7 +182,7 @@ static const struct mt9v032_model_data mt9v032_model_data[] = {
.max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
.pclk_reg = MT9V032_PIXEL_CLOCK,
}, {
- /* MT9V034 */
+ /* MT9V024, MT9V034 */
.min_row_time = 690,
.min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
.min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
@@ -188,6 +194,22 @@ static const struct mt9v032_model_data mt9v032_model_data[] = {
};
static const struct mt9v032_model_info mt9v032_models[] = {
+ [MT9V032_MODEL_V022_COLOR] = {
+ .data = &mt9v032_model_data[0],
+ .color = true,
+ },
+ [MT9V032_MODEL_V022_MONO] = {
+ .data = &mt9v032_model_data[0],
+ .color = false,
+ },
+ [MT9V032_MODEL_V024_COLOR] = {
+ .data = &mt9v032_model_data[1],
+ .color = true,
+ },
+ [MT9V032_MODEL_V024_MONO] = {
+ .data = &mt9v032_model_data[1],
+ .color = false,
+ },
[MT9V032_MODEL_V032_COLOR] = {
.data = &mt9v032_model_data[0],
.color = true,
@@ -224,6 +246,7 @@ struct mt9v032 {
struct mutex power_lock;
int power_count;
+ struct regmap *regmap;
struct clk *clk;
struct mt9v032_platform_data *pdata;
@@ -231,7 +254,6 @@ struct mt9v032 {
const struct mt9v032_model_version *version;
u32 sysclk;
- u16 chip_control;
u16 aec_agc;
u16 hblank;
struct {
@@ -245,40 +267,10 @@ static struct mt9v032 *to_mt9v032(struct v4l2_subdev *sd)
return container_of(sd, struct mt9v032, subdev);
}
-static int mt9v032_read(struct i2c_client *client, const u8 reg)
-{
- s32 data = i2c_smbus_read_word_swapped(client, reg);
- dev_dbg(&client->dev, "%s: read 0x%04x from 0x%02x\n", __func__,
- data, reg);
- return data;
-}
-
-static int mt9v032_write(struct i2c_client *client, const u8 reg,
- const u16 data)
-{
- dev_dbg(&client->dev, "%s: writing 0x%04x to 0x%02x\n", __func__,
- data, reg);
- return i2c_smbus_write_word_swapped(client, reg, data);
-}
-
-static int mt9v032_set_chip_control(struct mt9v032 *mt9v032, u16 clear, u16 set)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
- u16 value = (mt9v032->chip_control & ~clear) | set;
- int ret;
-
- ret = mt9v032_write(client, MT9V032_CHIP_CONTROL, value);
- if (ret < 0)
- return ret;
-
- mt9v032->chip_control = value;
- return 0;
-}
-
static int
mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ struct regmap *map = mt9v032->regmap;
u16 value = mt9v032->aec_agc;
int ret;
@@ -287,7 +279,7 @@ mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
else
value &= ~which;
- ret = mt9v032_write(client, MT9V032_AEC_AGC_ENABLE, value);
+ ret = regmap_write(map, MT9V032_AEC_AGC_ENABLE, value);
if (ret < 0)
return ret;
@@ -298,23 +290,23 @@ mt9v032_update_aec_agc(struct mt9v032 *mt9v032, u16 which, int enable)
static int
mt9v032_update_hblank(struct mt9v032 *mt9v032)
{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
struct v4l2_rect *crop = &mt9v032->crop;
unsigned int min_hblank = mt9v032->model->data->min_hblank;
unsigned int hblank;
if (mt9v032->version->version == MT9V034_CHIP_ID_REV1)
min_hblank += (mt9v032->hratio - 1) * 10;
- min_hblank = max_t(unsigned int, (int)mt9v032->model->data->min_row_time - crop->width,
- (int)min_hblank);
+ min_hblank = max_t(int, mt9v032->model->data->min_row_time - crop->width,
+ min_hblank);
hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
- return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank);
+ return regmap_write(mt9v032->regmap, MT9V032_HORIZONTAL_BLANKING,
+ hblank);
}
static int mt9v032_power_on(struct mt9v032 *mt9v032)
{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ struct regmap *map = mt9v032->regmap;
int ret;
ret = clk_set_rate(mt9v032->clk, mt9v032->sysclk);
@@ -328,15 +320,15 @@ static int mt9v032_power_on(struct mt9v032 *mt9v032)
udelay(1);
/* Reset the chip and stop data read out */
- ret = mt9v032_write(client, MT9V032_RESET, 1);
+ ret = regmap_write(map, MT9V032_RESET, 1);
if (ret < 0)
return ret;
- ret = mt9v032_write(client, MT9V032_RESET, 0);
+ ret = regmap_write(map, MT9V032_RESET, 0);
if (ret < 0)
return ret;
- return mt9v032_write(client, MT9V032_CHIP_CONTROL, 0);
+ return regmap_write(map, MT9V032_CHIP_CONTROL, 0);
}
static void mt9v032_power_off(struct mt9v032 *mt9v032)
@@ -346,7 +338,7 @@ static void mt9v032_power_off(struct mt9v032 *mt9v032)
static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
{
- struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ struct regmap *map = mt9v032->regmap;
int ret;
if (!on) {
@@ -360,14 +352,14 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
/* Configure the pixel clock polarity */
if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
- ret = mt9v032_write(client, mt9v032->model->data->pclk_reg,
+ ret = regmap_write(map, mt9v032->model->data->pclk_reg,
MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
if (ret < 0)
return ret;
}
/* Disable the noise correction algorithm and restore the controls. */
- ret = mt9v032_write(client, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
+ ret = regmap_write(map, MT9V032_ROW_NOISE_CORR_CONTROL, 0);
if (ret < 0)
return ret;
@@ -411,38 +403,39 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
const u16 mode = MT9V032_CHIP_CONTROL_MASTER_MODE
| MT9V032_CHIP_CONTROL_DOUT_ENABLE
| MT9V032_CHIP_CONTROL_SEQUENTIAL;
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
struct v4l2_rect *crop = &mt9v032->crop;
+ struct regmap *map = mt9v032->regmap;
unsigned int hbin;
unsigned int vbin;
int ret;
if (!enable)
- return mt9v032_set_chip_control(mt9v032, mode, 0);
+ return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, 0);
/* Configure the window size and row/column bin */
hbin = fls(mt9v032->hratio) - 1;
vbin = fls(mt9v032->vratio) - 1;
- ret = mt9v032_write(client, MT9V032_READ_MODE,
- hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
- vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
+ ret = regmap_update_bits(map, MT9V032_READ_MODE,
+ ~MT9V032_READ_MODE_RESERVED,
+ hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
+ vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
if (ret < 0)
return ret;
- ret = mt9v032_write(client, MT9V032_COLUMN_START, crop->left);
+ ret = regmap_write(map, MT9V032_COLUMN_START, crop->left);
if (ret < 0)
return ret;
- ret = mt9v032_write(client, MT9V032_ROW_START, crop->top);
+ ret = regmap_write(map, MT9V032_ROW_START, crop->top);
if (ret < 0)
return ret;
- ret = mt9v032_write(client, MT9V032_WINDOW_WIDTH, crop->width);
+ ret = regmap_write(map, MT9V032_WINDOW_WIDTH, crop->width);
if (ret < 0)
return ret;
- ret = mt9v032_write(client, MT9V032_WINDOW_HEIGHT, crop->height);
+ ret = regmap_write(map, MT9V032_WINDOW_HEIGHT, crop->height);
if (ret < 0)
return ret;
@@ -451,7 +444,7 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
return ret;
/* Switch to master "normal" mode */
- return mt9v032_set_chip_control(mt9v032, 0, mode);
+ return regmap_update_bits(map, MT9V032_CHIP_CONTROL, mode, mode);
}
static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
@@ -633,7 +626,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9v032 *mt9v032 =
container_of(ctrl->handler, struct mt9v032, ctrls);
- struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
+ struct regmap *map = mt9v032->regmap;
u32 freq;
u16 data;
@@ -643,23 +636,23 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
ctrl->val);
case V4L2_CID_GAIN:
- return mt9v032_write(client, MT9V032_ANALOG_GAIN, ctrl->val);
+ return regmap_write(map, MT9V032_ANALOG_GAIN, ctrl->val);
case V4L2_CID_EXPOSURE_AUTO:
return mt9v032_update_aec_agc(mt9v032, MT9V032_AEC_ENABLE,
!ctrl->val);
case V4L2_CID_EXPOSURE:
- return mt9v032_write(client, MT9V032_TOTAL_SHUTTER_WIDTH,
- ctrl->val);
+ return regmap_write(map, MT9V032_TOTAL_SHUTTER_WIDTH,
+ ctrl->val);
case V4L2_CID_HBLANK:
mt9v032->hblank = ctrl->val;
return mt9v032_update_hblank(mt9v032);
case V4L2_CID_VBLANK:
- return mt9v032_write(client, MT9V032_VERTICAL_BLANKING,
- ctrl->val);
+ return regmap_write(map, MT9V032_VERTICAL_BLANKING,
+ ctrl->val);
case V4L2_CID_PIXEL_RATE:
case V4L2_CID_LINK_FREQ:
@@ -667,7 +660,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
break;
freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val];
- mt9v032->pixel_rate->val64 = freq;
+ *mt9v032->pixel_rate->p_new.p_s64 = freq;
mt9v032->sysclk = freq;
break;
@@ -696,7 +689,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl)
| MT9V032_TEST_PATTERN_FLIP;
break;
}
- return mt9v032_write(client, MT9V032_TEST_PATTERN, data);
+ return regmap_write(map, MT9V032_TEST_PATTERN, data);
}
return 0;
@@ -764,7 +757,7 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
struct i2c_client *client = v4l2_get_subdevdata(subdev);
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
unsigned int i;
- s32 version;
+ u32 version;
int ret;
dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
@@ -777,10 +770,10 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
}
/* Read and check the sensor version */
- version = mt9v032_read(client, MT9V032_CHIP_VERSION);
- if (version < 0) {
+ ret = regmap_read(mt9v032->regmap, MT9V032_CHIP_VERSION, &version);
+ if (ret < 0) {
dev_err(&client->dev, "Failed reading chip version\n");
- return version;
+ return ret;
}
for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
@@ -867,6 +860,13 @@ static const struct v4l2_subdev_internal_ops mt9v032_subdev_internal_ops = {
.close = mt9v032_close,
};
+static const struct regmap_config mt9v032_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+ .max_register = 0xff,
+ .cache_type = REGCACHE_RBTREE,
+};
+
/* -----------------------------------------------------------------------------
* Driver initialization and probing
*/
@@ -890,6 +890,10 @@ static int mt9v032_probe(struct i2c_client *client,
if (!mt9v032)
return -ENOMEM;
+ mt9v032->regmap = devm_regmap_init_i2c(client, &mt9v032_regmap_config);
+ if (IS_ERR(mt9v032->regmap))
+ return PTR_ERR(mt9v032->regmap);
+
mt9v032->clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(mt9v032->clk))
return PTR_ERR(mt9v032->clk);
@@ -931,7 +935,7 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->pixel_rate =
v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
- V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+ V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
if (pdata && pdata->link_freqs) {
unsigned int def = 0;
@@ -984,10 +988,19 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_init(&mt9v032->subdev.entity, 1, &mt9v032->pad, 0);
-
if (ret < 0)
- v4l2_ctrl_handler_free(&mt9v032->ctrls);
+ goto err;
+ mt9v032->subdev.dev = &client->dev;
+ ret = v4l2_async_register_subdev(&mt9v032->subdev);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+
+err:
+ media_entity_cleanup(&mt9v032->subdev.entity);
+ v4l2_ctrl_handler_free(&mt9v032->ctrls);
return ret;
}
@@ -996,6 +1009,7 @@ static int mt9v032_remove(struct i2c_client *client)
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
+ v4l2_async_unregister_subdev(subdev);
v4l2_ctrl_handler_free(&mt9v032->ctrls);
v4l2_device_unregister_subdev(subdev);
media_entity_cleanup(&subdev->entity);
@@ -1004,6 +1018,10 @@ static int mt9v032_remove(struct i2c_client *client)
}
static const struct i2c_device_id mt9v032_id[] = {
+ { "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] },
+ { "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] },
+ { "mt9v024", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_COLOR] },
+ { "mt9v024m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_MONO] },
{ "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] },
{ "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] },
{ "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] },
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 271d0b7967a6..7eae48766e2b 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -554,6 +554,7 @@ static int noon010_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
nf = noon010_try_fmt(sd, &fmt->format);
noon010_try_frame_size(&fmt->format, &size);
fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
+ fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
if (fh) {
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index 2750de634270..1fcc76fd1bbf 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -594,6 +594,7 @@ static int s5k4ecgx_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
pf = s5k4ecgx_try_fmt(sd, &fmt->format);
s5k4ecgx_try_frame_size(&fmt->format, &fsize);
fmt->format.colorspace = V4L2_COLORSPACE_JPEG;
+ fmt->format.field = V4L2_FIELD_NONE;
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
if (fh) {
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 2d768ef67cc5..564f05f2c9ef 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -1313,6 +1313,8 @@ static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
const struct s5k5baf_pixfmt *pixfmt;
int ret = 0;
+ mf->field = V4L2_FIELD_NONE;
+
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
*v4l2_subdev_get_try_format(fh, fmt->pad) = *mf;
return 0;
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index 7bc2271ca009..c11a40850ed1 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -115,6 +115,7 @@ static void s5k6a3_try_format(struct v4l2_mbus_framefmt *mf)
fmt = find_sensor_format(mf);
mf->code = fmt->code;
+ mf->field = V4L2_FIELD_NONE;
v4l_bound_align_image(&mf->width, S5K6A3_SENSOR_MIN_WIDTH,
S5K6A3_SENSOR_MAX_WIDTH, 0,
&mf->height, S5K6A3_SENSOR_MIN_HEIGHT,
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 06fb03291d59..1eaf975d3612 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -297,8 +297,8 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
if (rval < 0)
return rval;
- sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
- sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
+ *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;
return 0;
}
@@ -533,7 +533,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
sensor->pixel_rate_parray = v4l2_ctrl_new_std(
&sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+ V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
if (sensor->pixel_array->ctrl_handler.error) {
dev_err(&client->dev,
@@ -562,7 +562,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
sensor->pixel_rate_csi = v4l2_ctrl_new_std(
&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
+ V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1);
if (sensor->src->ctrl_handler.error) {
dev_err(&client->dev,
@@ -1554,6 +1554,7 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev,
fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
fmt->format.width = r->width;
fmt->format.height = r->height;
+ fmt->format.field = V4L2_FIELD_NONE;
}
return 0;
@@ -1687,6 +1688,7 @@ static int smiapp_set_format(struct v4l2_subdev *subdev,
fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
fmt->format.width &= ~1;
fmt->format.height &= ~1;
+ fmt->format.field = V4L2_FIELD_NONE;
fmt->format.width =
clamp(fmt->format.width,
@@ -2544,9 +2546,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
snprintf(this->sd.name,
- sizeof(this->sd.name), "%s %d-%4.4x %s",
- sensor->minfo.name, i2c_adapter_id(client->adapter),
- client->addr, _this->name);
+ sizeof(this->sd.name), "%s %s %d-%4.4x",
+ sensor->minfo.name, _this->name,
+ i2c_adapter_id(client->adapter), client->addr);
this->sink_fmt.width =
sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
@@ -2674,6 +2676,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
try_fmt->code = mbus_code;
+ try_fmt->field = V4L2_FIELD_NONE;
try_crop->top = 0;
try_crop->left = 0;
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index df97033fa6ef..dbd8c142d6ef 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -403,7 +403,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
if (ctrl->val <= ctrl->default_value) {
/* Pack it into 0..1 step 0.125, register values 0..8 */
unsigned long range = ctrl->default_value - ctrl->minimum;
- data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+ data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range;
dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9M001_GLOBAL_GAIN, data);
@@ -413,7 +413,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
/* Pack it into 1.125..15 variable step, register values 9..67 */
/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
unsigned long range = ctrl->maximum - ctrl->default_value - 1;
- unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+ unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) *
111 + range / 2) / range + 9;
if (gain <= 32)
@@ -434,7 +434,7 @@ static int mt9m001_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
unsigned long range = exp->maximum - exp->minimum;
- unsigned long shutter = ((exp->val - exp->minimum) * 1048 +
+ unsigned long shutter = ((exp->val - (s32)exp->minimum) * 1048 +
range / 2) / range + 1;
dev_dbg(&client->dev,
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index ccf59406a172..b51e8562e775 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -931,6 +931,12 @@ static int mt9m111_probe(struct i2c_client *client,
struct soc_camera_subdev_desc *ssdd = soc_camera_i2c_to_desc(client);
int ret;
+ if (client->dev.of_node) {
+ ssdd = devm_kzalloc(&client->dev, sizeof(*ssdd), GFP_KERNEL);
+ if (!ssdd)
+ return -ENOMEM;
+ client->dev.platform_data = ssdd;
+ }
if (!ssdd) {
dev_err(&client->dev, "mt9m111: driver needs platform data\n");
return -EINVAL;
@@ -1015,6 +1021,11 @@ static int mt9m111_remove(struct i2c_client *client)
return 0;
}
+static const struct of_device_id mt9m111_of_match[] = {
+ { .compatible = "micron,mt9m111", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mt9m111_of_match);
static const struct i2c_device_id mt9m111_id[] = {
{ "mt9m111", 0 },
@@ -1025,6 +1036,7 @@ MODULE_DEVICE_TABLE(i2c, mt9m111_id);
static struct i2c_driver mt9m111_i2c_driver = {
.driver = {
.name = "mt9m111",
+ .of_match_table = of_match_ptr(mt9m111_of_match),
},
.probe = mt9m111_probe,
.remove = mt9m111_remove,
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
index ee7bb0ffcecb..f8358c4071a9 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -474,7 +474,7 @@ static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
if (ctrl->val <= ctrl->default_value) {
/* Pack it into 0..1 step 0.125, register values 0..8 */
unsigned long range = ctrl->default_value - ctrl->minimum;
- data = ((ctrl->val - ctrl->minimum) * 8 + range / 2) / range;
+ data = ((ctrl->val - (s32)ctrl->minimum) * 8 + range / 2) / range;
dev_dbg(&client->dev, "Setting gain %d\n", data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
@@ -485,7 +485,7 @@ static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
/* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
unsigned long range = ctrl->maximum - ctrl->default_value - 1;
/* calculated gain: map 65..127 to 9..1024 step 0.125 */
- unsigned long gain = ((ctrl->val - ctrl->default_value - 1) *
+ unsigned long gain = ((ctrl->val - (s32)ctrl->default_value - 1) *
1015 + range / 2) / range + 9;
if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
@@ -507,7 +507,7 @@ static int mt9t031_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE_AUTO:
if (ctrl->val == V4L2_EXPOSURE_MANUAL) {
unsigned int range = exp->maximum - exp->minimum;
- unsigned int shutter = ((exp->val - exp->minimum) * 1048 +
+ unsigned int shutter = ((exp->val - (s32)exp->minimum) * 1048 +
range / 2) / range + 1;
u32 old;
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index f9f95f815b1a..99022c8d76eb 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -583,7 +583,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
/* mt9v022 has minimum == default */
unsigned long range = gain->maximum - gain->minimum;
/* Valid values 16 to 64, 32 to 64 must be even. */
- unsigned long gain_val = ((gain->val - gain->minimum) *
+ unsigned long gain_val = ((gain->val - (s32)gain->minimum) *
48 + range / 2) / range + 16;
if (gain_val >= 32)
@@ -608,7 +608,7 @@ static int mt9v022_s_ctrl(struct v4l2_ctrl *ctrl)
} else {
struct v4l2_ctrl *exp = mt9v022->exposure;
unsigned long range = exp->maximum - exp->minimum;
- unsigned long shutter = ((exp->val - exp->minimum) *
+ unsigned long shutter = ((exp->val - (s32)exp->minimum) *
479 + range / 2) / range + 1;
/*
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index a9121254e37a..193e7d6c29c8 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -56,38 +56,29 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
{
struct i2c_client *c = v4l2_get_subdevdata(sd);
- unsigned char buffer[1];
int rc;
- struct i2c_msg msg[] = {
- { .addr = c->addr, .flags = 0,
- .buf = &addr, .len = 1 },
- { .addr = c->addr, .flags = I2C_M_RD,
- .buf = buffer, .len = 1 }
- };
- rc = i2c_transfer(c->adapter, msg, 2);
- if (rc < 0 || rc != 2) {
- v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
- return rc < 0 ? rc : -EIO;
+ rc = i2c_smbus_read_byte_data(c, addr);
+ if (rc < 0) {
+ v4l2_err(sd, "i2c i/o error: rc == %d\n", rc);
+ return rc;
}
- v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
+ v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc);
- return (buffer[0]);
+ return rc;
}
static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
unsigned char value)
{
struct i2c_client *c = v4l2_get_subdevdata(sd);
- unsigned char buffer[2];
int rc;
- buffer[0] = addr;
- buffer[1] = value;
- v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", buffer[0], buffer[1]);
- if (2 != (rc = i2c_master_send(c, buffer, 2)))
- v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
+ v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value);
+ rc = i2c_smbus_write_byte_data(c, addr, value);
+ if (rc < 0)
+ v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc);
}
static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
@@ -1148,10 +1139,10 @@ static int tvp5150_probe(struct i2c_client *c,
/* Is TVP5150A */
if (tvp5150_id[2] == 3 || tvp5150_id[3] == 0x21) {
v4l2_info(sd, "tvp%02x%02xa detected.\n",
- tvp5150_id[2], tvp5150_id[3]);
+ tvp5150_id[0], tvp5150_id[1]);
} else {
v4l2_info(sd, "*** unknown tvp%02x%02x chip detected.\n",
- tvp5150_id[2], tvp5150_id[3]);
+ tvp5150_id[0], tvp5150_id[1]);
v4l2_info(sd, "*** Rom ver is %d.%d\n",
tvp5150_id[2], tvp5150_id[3]);
}
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 88b97c9e64ac..73a432934bd8 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -106,8 +106,6 @@ static long media_device_enum_entities(struct media_device *mdev,
if (ent->name) {
strncpy(u_ent.name, ent->name, sizeof(u_ent.name));
u_ent.name[sizeof(u_ent.name) - 1] = '\0';
- } else {
- memset(u_ent.name, 0, sizeof(u_ent.name));
}
u_ent.type = ent->type;
u_ent.revision = ent->revision;
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c
index 416507a83668..67b9da1dc43f 100644
--- a/drivers/media/parport/bw-qcam.c
+++ b/drivers/media/parport/bw-qcam.c
@@ -759,7 +759,6 @@ static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
pix->sizeimage = pix->width * pix->height;
/* Just a guess */
pix->colorspace = V4L2_COLORSPACE_SRGB;
- pix->priv = 0;
return 0;
}
@@ -785,7 +784,6 @@ static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format
pix->sizeimage = pix->width * pix->height;
/* Just a guess */
pix->colorspace = V4L2_COLORSPACE_SRGB;
- pix->priv = 0;
return 0;
}
@@ -990,7 +988,6 @@ static struct qcam *qcam_init(struct parport *port)
qcam->vdev.fops = &qcam_fops;
qcam->vdev.lock = &qcam->lock;
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
- set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
qcam->vdev.release = video_device_release_empty;
video_set_drvdata(&qcam->vdev, qcam);
diff --git a/drivers/media/parport/c-qcam.c b/drivers/media/parport/c-qcam.c
index ec51e1f12e82..b9010bd3ed3e 100644
--- a/drivers/media/parport/c-qcam.c
+++ b/drivers/media/parport/c-qcam.c
@@ -761,7 +761,6 @@ static struct qcam *qcam_init(struct parport *port)
qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
qcam->vdev.release = video_device_release_empty;
qcam->vdev.ctrl_handler = &qcam->hdl;
- set_bit(V4L2_FL_USE_FH_PRIO, &qcam->vdev.flags);
video_set_drvdata(&qcam->vdev, qcam);
mutex_init(&qcam->lock);
diff --git a/drivers/media/parport/pms.c b/drivers/media/parport/pms.c
index 66c957a02ba7..9bc105b3db1b 100644
--- a/drivers/media/parport/pms.c
+++ b/drivers/media/parport/pms.c
@@ -1091,7 +1091,6 @@ static int pms_probe(struct device *pdev, unsigned int card)
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
- set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
video_set_drvdata(&dev->vdev, dev);
dev->std = V4L2_STD_NTSC_M;
dev->height = 240;
diff --git a/drivers/media/parport/w9966.c b/drivers/media/parport/w9966.c
index db2a6003a1c3..f7502f3a6a3c 100644
--- a/drivers/media/parport/w9966.c
+++ b/drivers/media/parport/w9966.c
@@ -883,7 +883,6 @@ static int w9966_init(struct w9966 *cam, struct parport *port)
cam->vdev.ioctl_ops = &w9966_ioctl_ops;
cam->vdev.release = video_device_release_empty;
cam->vdev.ctrl_handler = &cam->hdl;
- set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
video_set_drvdata(&cam->vdev, cam);
mutex_init(&cam->lock);
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index 53196f1366f3..5c16c9c2203e 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -19,6 +19,7 @@ if MEDIA_ANALOG_TV_SUPPORT
source "drivers/media/pci/ivtv/Kconfig"
source "drivers/media/pci/zoran/Kconfig"
source "drivers/media/pci/saa7146/Kconfig"
+source "drivers/media/pci/solo6x10/Kconfig"
endif
if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index 35cc57862c01..e5b53fb569ef 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
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 da780f42b121..970e542d3a51 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -3886,7 +3886,6 @@ static struct video_device *vdev_init(struct bttv *btv,
vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release;
vfd->debug = bttv_debug;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
video_set_drvdata(vfd, btv);
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c
index 5930bce16658..67c8d6b2c335 100644
--- a/drivers/media/pci/bt8xx/bttv-input.c
+++ b/drivers/media/pci/bt8xx/bttv-input.c
@@ -73,12 +73,12 @@ static void ir_handle_key(struct bttv *btv)
if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
(ir->mask_keyup && !(gpio & ir->mask_keyup))) {
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
} else {
/* HACK: Probably, ir->mask_keydown is missing
for this board */
if (btv->c.type == BTTV_BOARD_WINFAST2000)
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
rc_keyup(ir->dev);
}
@@ -103,7 +103,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
gpio, data,
(gpio & ir->mask_keyup) ? " up" : "up/down");
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
if (keyup)
rc_keyup(ir->dev);
} else {
@@ -117,7 +117,7 @@ static void ir_enltv_handle_key(struct bttv *btv)
if (keyup)
rc_keyup(ir->dev);
else
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
}
ir->last_gpio = data | keyup;
@@ -154,10 +154,10 @@ static void bttv_input_timer(unsigned long data)
* testing.
*/
-#define RC5_START(x) (((x) >> 12) & 3)
-#define RC5_TOGGLE(x) (((x) >> 11) & 1)
-#define RC5_ADDR(x) (((x) >> 6) & 31)
-#define RC5_INSTR(x) ((x) & 63)
+#define RC5_START(x) (((x) >> 12) & 0x03)
+#define RC5_TOGGLE(x) (((x) >> 11) & 0x01)
+#define RC5_ADDR(x) (((x) >> 6) & 0x1f)
+#define RC5_INSTR(x) (((x) >> 0) & 0x3f)
/* decode raw bit pattern to RC5 code */
static u32 bttv_rc5_decode(unsigned int code)
@@ -195,8 +195,8 @@ static void bttv_rc5_timer_end(unsigned long data)
{
struct bttv_ir *ir = (struct bttv_ir *)data;
struct timeval tv;
- u32 gap;
- u32 rc5 = 0;
+ u32 gap, rc5, scancode;
+ u8 toggle, command, system;
/* get time */
do_gettimeofday(&tv);
@@ -221,26 +221,29 @@ static void bttv_rc5_timer_end(unsigned long data)
if (ir->last_bit < 20) {
/* ignore spurious codes (caused by light/other remotes) */
dprintk("short code: %x\n", ir->code);
- } else {
- ir->code = (ir->code << ir->shift_by) | 1;
- rc5 = bttv_rc5_decode(ir->code);
-
- /* two start bits? */
- if (RC5_START(rc5) != ir->start) {
- pr_info(DEVNAME ":"
- " rc5 start bits invalid: %u\n", RC5_START(rc5));
-
- /* right address? */
- } else if (RC5_ADDR(rc5) == ir->addr) {
- u32 toggle = RC5_TOGGLE(rc5);
- u32 instr = RC5_INSTR(rc5);
-
- /* Good code */
- rc_keydown(ir->dev, instr, toggle);
- dprintk("instruction %x, toggle %x\n",
- instr, toggle);
- }
+ return;
}
+
+ ir->code = (ir->code << ir->shift_by) | 1;
+ rc5 = bttv_rc5_decode(ir->code);
+
+ toggle = RC5_TOGGLE(rc5);
+ system = RC5_ADDR(rc5);
+ command = RC5_INSTR(rc5);
+
+ switch (RC5_START(rc5)) {
+ case 0x3:
+ break;
+ case 0x2:
+ command += 0x40;
+ break;
+ default:
+ return;
+ }
+
+ scancode = RC_SCANCODE_RC5(system, command);
+ rc_keydown(ir->dev, RC_TYPE_RC5, scancode, toggle);
+ dprintk("scancode %x, toggle %x\n", scancode, toggle);
}
static int bttv_rc5_irq(struct bttv *btv)
@@ -310,8 +313,6 @@ static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
/* set timer_end for code completion */
setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir);
ir->shift_by = 1;
- ir->start = 3;
- ir->addr = 0x0;
ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
@@ -335,7 +336,8 @@ static void bttv_ir_stop(struct bttv *btv)
* Get_key functions used by I2C remotes
*/
-static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pv951(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char b;
@@ -362,8 +364,9 @@ static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
* the device is bound to the vendor-provided RC.
*/
- *ir_key = b;
- *ir_raw = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
@@ -490,8 +493,8 @@ int bttv_input_init(struct bttv *btv)
ir->polling = 50; // ms
break;
case BTTV_BOARD_NEBULA_DIGITV:
- ir_codes = RC_MAP_NEBULA;
- ir->rc5_gpio = true;
+ ir_codes = RC_MAP_NEBULA;
+ ir->rc5_gpio = true;
break;
case BTTV_BOARD_MACHTV_MAGICTV:
ir_codes = RC_MAP_APAC_VIEWCOMP;
@@ -514,7 +517,8 @@ int bttv_input_init(struct bttv *btv)
ir->mask_keycode);
break;
}
- if (NULL == ir_codes) {
+
+ if (!ir_codes) {
dprintk("Ooops: IR config error [card=%d]\n", btv->c.type);
err = -ENODEV;
goto err_out_free;
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 6eefb595d0fa..9fe19488b30b 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -133,8 +133,6 @@ struct bttv_ir {
u32 polling;
u32 last_gpio;
int shift_by;
- int start; // What should RC5_START() be
- int addr; // What RC5_ADDR() should be.
int rc5_remote_gap;
/* RC5 gpio */
diff --git a/drivers/media/pci/cx18/cx18-alsa.h b/drivers/media/pci/cx18/cx18-alsa.h
index 447da374c9e8..2718be28bf5f 100644
--- a/drivers/media/pci/cx18/cx18-alsa.h
+++ b/drivers/media/pci/cx18/cx18-alsa.h
@@ -48,7 +48,6 @@ static inline void snd_cx18_unlock(struct snd_cx18_card *cxsc)
mutex_unlock(&cx->serialize_lock);
}
-#define CX18_ALSA_DBGFLG_WARN (1 << 0)
#define CX18_ALSA_DBGFLG_WARN (1 << 0)
#define CX18_ALSA_DBGFLG_INFO (1 << 1)
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index fefb2cd35838..6f2b59042b73 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -156,7 +156,6 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
pixfmt->height = cx->cxhdl.height;
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
pixfmt->field = V4L2_FIELD_INTERLACED;
- pixfmt->priv = 0;
if (id->type == CX18_ENC_STREAM_TYPE_YUV) {
pixfmt->pixelformat = s->pixelformat;
pixfmt->sizeimage = s->vb_bytes_per_frame;
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index 843c62b2f482..f3541b5156ce 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -375,7 +375,6 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
s->video_dev->release = video_device_release;
s->video_dev->tvnorms = V4L2_STD_ALL;
s->video_dev->lock = &cx->serialize_lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags);
cx18_set_funcs(s->video_dev);
return 0;
}
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index d1dcb1d2e087..e12c006e6e2d 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -31,12 +31,14 @@ config VIDEO_CX23885
select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT
select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2165 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 DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
---help---
This is a video4linux driver for Conexant 23885 based
TV cards.
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 95666eee7b27..bf89fc88692e 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1266,7 +1266,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- if (UNSET == dev->tuner_type)
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1284,7 +1284,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- if (UNSET == dev->tuner_type)
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
/* Update the A/V core */
@@ -1299,7 +1299,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct cx23885_fh *fh = file->private_data;
struct cx23885_dev *dev = fh->dev;
- if (UNSET == dev->tuner_type)
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
f->type = V4L2_TUNER_ANALOG_TV;
f->frequency = dev->freq;
@@ -1347,7 +1347,7 @@ static int vidioc_querycap(struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
0;
- if (UNSET != dev->tuner_type)
+ if (dev->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index 79f20c8c842e..c2b608007190 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -619,7 +619,12 @@ struct cx23885_board cx23885_boards[] = {
},
[CX23885_BOARD_HAUPPAUGE_HVR4400] = {
.name = "Hauppauge WinTV-HVR4400",
+ .porta = CX23885_ANALOG_VIDEO,
.portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60, /* 0xc0 >> 1 */
+ .tuner_bus = 1,
},
[CX23885_BOARD_AVERMEDIA_HC81R] = {
.name = "AVerTV Hybrid Express Slim HC81R",
@@ -649,7 +654,31 @@ struct cx23885_board cx23885_boards[] = {
CX25840_NONE1_CH3,
.amux = CX25840_AUDIO6,
} },
- }
+ },
+ [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2] = {
+ .name = "DViCO FusionHDTV DVB-T Dual Express2",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_IMPACTVCBE] = {
+ .name = "Hauppauge ImpactVCB-e",
+ .tuner_type = TUNER_ABSENT,
+ .porta = CX23885_ANALOG_VIDEO,
+ .input = {{
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN6_CH1,
+ .amux = CX25840_AUDIO7,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_VIN7_CH3 |
+ CX25840_VIN4_CH2 |
+ CX25840_VIN8_CH1 |
+ CX25840_SVIDEO_ON,
+ .amux = CX25840_AUDIO7,
+ } },
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -897,6 +926,14 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x1461,
.subdevice = 0xd939,
.card = CX23885_BOARD_AVERMEDIA_HC81R,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x7133,
+ .card = CX23885_BOARD_HAUPPAUGE_IMPACTVCBE,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb98,
+ .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -977,6 +1014,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 71009:
/* WinTV-HVR1200 (PCIe, Retail, full height)
* DVB-T and basic analog */
+ case 71100:
+ /* WinTV-ImpactVCB-e (PCIe, Retail, half height)
+ * Basic analog */
case 71359:
/* WinTV-HVR1200 (PCIe, OEM, half height)
* DVB-T and basic analog */
@@ -1137,6 +1177,7 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2:
/* Two identical tuners on two different i2c buses,
* we need to reset the correct gpio. */
if (port->nr == 1)
@@ -1280,6 +1321,7 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_set(GP0_IO, 0x000f000f);
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2:
/* GPIO-0 portb xc3028 reset */
/* GPIO-1 portb zl10353 reset */
/* GPIO-2 portc xc3028 reset */
@@ -1449,13 +1491,16 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
break;
case CX23885_BOARD_HAUPPAUGE_HVR4400:
/* GPIO-8 tda10071 demod reset */
+ /* GPIO-9 si2165 demod reset */
/* Put the parts into reset and back */
- cx23885_gpio_enable(dev, GPIO_8, 1);
- cx23885_gpio_clear(dev, GPIO_8);
+ cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
+
+ cx23885_gpio_clear(dev, GPIO_8 | GPIO_9);
mdelay(100);
- cx23885_gpio_set(dev, GPIO_8);
+ cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
mdelay(100);
+
break;
case CX23885_BOARD_AVERMEDIA_HC81R:
cx_clear(MC417_CTL, 1);
@@ -1585,6 +1630,7 @@ int cx23885_ir_init(struct cx23885_dev *dev)
ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2:
request_module("ir-kbd-i2c");
break;
}
@@ -1701,6 +1747,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_HAUPPAUGE_HVR4400:
+ case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
@@ -1720,6 +1767,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP:
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -1799,6 +1847,9 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ 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:
@@ -1807,6 +1858,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1200:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H_XC4000:
@@ -1835,6 +1887,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 4be01b3bd4f5..968fecc32f9c 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -44,6 +44,7 @@
#include "tuner-xc2028.h"
#include "tuner-simple.h"
#include "dib7000p.h"
+#include "dib0070.h"
#include "dibx000_common.h"
#include "zl10353.h"
#include "stv0900.h"
@@ -71,6 +72,7 @@
#include "tda10071.h"
#include "a8293.h"
#include "mb86a20s.h"
+#include "si2165.h"
static unsigned int debug;
@@ -302,6 +304,11 @@ static struct tda18271_config hauppauge_hvr1210_tuner_config = {
.output_opt = TDA18271_OUTPUT_LT_OFF,
};
+static struct tda18271_config hauppauge_hvr4400_tuner_config = {
+ .gate = TDA18271_GATE_DIGITAL,
+ .output_opt = TDA18271_OUTPUT_LT_OFF,
+};
+
static struct tda18271_std_map hauppauge_hvr127x_std_map = {
.atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
.if_lvl = 1, .rfagc_top = 0x58 },
@@ -702,6 +709,12 @@ static const struct a8293_config hauppauge_a8293_config = {
.i2c_addr = 0x0b,
};
+static const struct si2165_config hauppauge_hvr4400_si2165_config = {
+ .i2c_addr = 0x64,
+ .chip_mode = SI2165_MODE_PLL_XTAL,
+ .ref_freq_Hz = 16000000,
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -746,8 +759,108 @@ static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
return 0;
};
+static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+ struct dib7000p_ops *dib7000p_ops = fe->sec_priv;
+
+ return dib7000p_ops->set_gpio(fe, 8, 0, !onoff);
+}
+
+static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+ return 0;
+}
+
+static struct dib0070_config dib7070p_dib0070_config = {
+ .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS,
+ .reset = dib7070_tuner_reset,
+ .sleep = dib7070_tuner_sleep,
+ .clock_khz = 12000,
+ .freq_offset_khz_vhf = 550,
+ /* .flip_chip = 1, */
+};
+
+/* DIB7070 generic */
+static struct dibx000_agc_config dib7070_agc_config = {
+ .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+
+ /*
+ * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5,
+ * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+ * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0
+ */
+ .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) |
+ (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
+ .inv_gain = 600,
+ .time_stabiliz = 10,
+ .alpha_level = 0,
+ .thlock = 118,
+ .wbd_inv = 0,
+ .wbd_ref = 3530,
+ .wbd_sel = 1,
+ .wbd_alpha = 5,
+ .agc1_max = 65535,
+ .agc1_min = 0,
+ .agc2_max = 65535,
+ .agc2_min = 0,
+ .agc1_pt1 = 0,
+ .agc1_pt2 = 40,
+ .agc1_pt3 = 183,
+ .agc1_slope1 = 206,
+ .agc1_slope2 = 255,
+ .agc2_pt1 = 72,
+ .agc2_pt2 = 152,
+ .agc2_slope1 = 88,
+ .agc2_slope2 = 90,
+ .alpha_mant = 17,
+ .alpha_exp = 27,
+ .beta_mant = 23,
+ .beta_exp = 51,
+ .perform_agc_softsplit = 0,
+};
+
+static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
+ .internal = 60000,
+ .sampling = 15000,
+ .pll_prediv = 1,
+ .pll_ratio = 20,
+ .pll_range = 3,
+ .pll_reset = 1,
+ .pll_bypass = 0,
+ .enable_refdiv = 0,
+ .bypclk_div = 0,
+ .IO_CLK_en_core = 1,
+ .ADClkSrc = 1,
+ .modulo = 2,
+ /* refsel, sel, freq_15k */
+ .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0),
+ .ifreq = (0 << 25) | 0,
+ .timf = 20452225,
+ .xtal_hz = 12000000,
+};
+
+static struct dib7000p_config dib7070p_dib7000p_config = {
+ /* .output_mode = OUTMODE_MPEG2_FIFO, */
+ .output_mode = OUTMODE_MPEG2_SERIAL,
+ /* .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, */
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+ .tuner_is_baseband = 1,
+ .spur_protect = 1,
+
+ .gpio_dir = 0xfcef, /* DIB7000P_GPIO_DEFAULT_DIRECTIONS, */
+ .gpio_val = 0x0110, /* DIB7000P_GPIO_DEFAULT_VALUES, */
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+};
+
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;
@@ -925,8 +1038,11 @@ static int dvb_register(struct cx23885_tsport *port)
break;
case CX23885_BOARD_HAUPPAUGE_HVR1400:
i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(dib7000p_attach,
- &i2c_bus->i2c_adap,
+
+ if (!dvb_attach(dib7000p_attach, &dib7000p_ops))
+ return -ENODEV;
+
+ fe0->dvb.frontend = dib7000p_ops.init(&i2c_bus->i2c_adap,
0x12, &hauppauge_hvr1400_dib7000_config);
if (fe0->dvb.frontend != NULL) {
struct dvb_frontend *fe;
@@ -989,6 +1105,30 @@ static int dvb_register(struct cx23885_tsport *port)
}
break;
}
+ case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2: {
+ i2c_bus = &dev->i2c_bus[port->nr - 1];
+ /* cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); */
+ /* cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); */
+
+ if (!dvb_attach(dib7000p_attach, &dib7000p_ops))
+ return -ENODEV;
+
+ if (dib7000p_ops.i2c_enumeration(&i2c_bus->i2c_adap, 1, 0x12, &dib7070p_dib7000p_config) < 0) {
+ printk(KERN_WARNING "Unable to enumerate dib7000p\n");
+ return -ENODEV;
+ }
+ fe0->dvb.frontend = dib7000p_ops.init(&i2c_bus->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+ if (fe0->dvb.frontend != NULL) {
+ struct i2c_adapter *tun_i2c;
+
+ fe0->dvb.frontend->sec_priv = kmalloc(sizeof(dib7000p_ops), GFP_KERNEL);
+ memcpy(fe0->dvb.frontend->sec_priv, &dib7000p_ops, sizeof(dib7000p_ops));
+ tun_i2c = dib7000p_ops.get_i2c_master(fe0->dvb.frontend, DIBX000_I2C_INTERFACE_TUNER, 1);
+ if (!dvb_attach(dib0070_attach, fe0->dvb.frontend, tun_i2c, &dib7070p_dib0070_config))
+ return -ENODEV;
+ }
+ break;
+ }
case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H:
case CX23885_BOARD_COMPRO_VIDEOMATE_E650F:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
@@ -1331,13 +1471,34 @@ static int dvb_register(struct cx23885_tsport *port)
break;
case CX23885_BOARD_HAUPPAUGE_HVR4400:
i2c_bus = &dev->i2c_bus[0];
- fe0->dvb.frontend = dvb_attach(tda10071_attach,
+ i2c_bus2 = &dev->i2c_bus[1];
+ switch (port->nr) {
+ /* port b */
+ case 1:
+ fe0->dvb.frontend = dvb_attach(tda10071_attach,
&hauppauge_tda10071_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(a8293_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_a8293_config);
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(a8293_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_a8293_config))
+ goto frontend_detach;
+ }
+ break;
+ /* port c */
+ case 2:
+ fe0->dvb.frontend = dvb_attach(si2165_attach,
+ &hauppauge_hvr4400_si2165_config,
+ &i2c_bus->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = 0;
+ if (!dvb_attach(tda18271_attach,
+ fe0->dvb.frontend,
+ 0x60, &i2c_bus2->i2c_adap,
+ &hauppauge_hvr4400_tuner_config))
+ goto frontend_detach;
+ }
+ break;
}
break;
default:
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 097d0a0b5f57..1940c18e186c 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -346,7 +346,7 @@ int cx23885_input_init(struct cx23885_dev *dev)
}
rc->dev.parent = &dev->pci->dev;
rc->driver_type = driver_type;
- rc_set_allowed_protocols(rc, allowed_protos);
+ rc->allowed_protocols = allowed_protos;
rc->priv = kernel_ir;
rc->open = cx23885_input_ir_open;
rc->close = cx23885_input_ir_close;
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index e0a59523cf3c..91e4cb457296 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -507,6 +507,7 @@ static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
if ((dev->board == CX23885_BOARD_HAUPPAUGE_HVR1800) ||
(dev->board == CX23885_BOARD_MPX885) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1250) ||
+ (dev->board == CX23885_BOARD_HAUPPAUGE_IMPACTVCBE) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1255_22111) ||
(dev->board == CX23885_BOARD_HAUPPAUGE_HVR1850) ||
@@ -1156,7 +1157,7 @@ static int vidioc_querycap(struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_VBI_CAPTURE;
- if (UNSET != dev->tuner_type)
+ if (dev->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
}
@@ -1474,7 +1475,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- if (unlikely(UNSET == dev->tuner_type))
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1490,7 +1491,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- if (UNSET == dev->tuner_type)
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
@@ -1506,7 +1507,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
- if (unlikely(UNSET == dev->tuner_type))
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
/* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */
@@ -1522,7 +1523,7 @@ static int cx23885_set_freq(struct cx23885_dev *dev, const struct v4l2_frequency
{
struct v4l2_control ctrl;
- if (unlikely(UNSET == dev->tuner_type))
+ if (dev->tuner_type == TUNER_ABSENT)
return -EINVAL;
if (unlikely(f->tuner != 0))
return -EINVAL;
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 0fa4048ab872..0e086c03da67 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -96,6 +96,8 @@
#define CX23885_BOARD_TBS_6981 40
#define CX23885_BOARD_TBS_6980 41
#define CX23885_BOARD_LEADTEK_WINFAST_PXPVR2200 42
+#define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE 43
+#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index d270819fd875..3a419f134584 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -576,7 +576,6 @@ static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -615,7 +614,6 @@ static int cx25821_vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.bytesperline = (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;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -867,7 +865,6 @@ static int cx25821_vidioc_try_fmt_vid_out(struct file *file, void *priv,
f->fmt.pix.bytesperline = (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;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1109,7 +1106,6 @@ int cx25821_video_register(struct cx25821_dev *dev)
else
vdev->vfl_dir = VFL_DIR_TX;
vdev->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
video_set_drvdata(vdev, chan);
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index e061c88b697e..71630238027b 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -1045,7 +1045,6 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
core->name, type, core->board.name);
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
return vfd;
}
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index f991696a6c59..3f1342c98b46 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -130,25 +130,41 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
- rc_keydown(ir->dev, data, 0);
+ rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0);
+
+ } else if (ir->core->boardnr == CX88_BOARD_PROLINK_PLAYTVPVR ||
+ ir->core->boardnr == CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO) {
+ /* bit cleared on keydown, NEC scancode, 0xAAAACC, A = 0x866b */
+ u16 addr;
+ u8 cmd;
+ u32 scancode;
+
+ addr = (data >> 8) & 0xffff;
+ cmd = (data >> 0) & 0x00ff;
+ scancode = RC_SCANCODE_NECX(addr, cmd);
+
+ if (0 == (gpio & ir->mask_keyup))
+ rc_keydown_notimeout(ir->dev, RC_TYPE_NEC, scancode, 0);
+ else
+ rc_keyup(ir->dev);
} else if (ir->mask_keydown) {
/* bit set on keydown */
if (gpio & ir->mask_keydown)
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
else
rc_keyup(ir->dev);
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
if (0 == (gpio & ir->mask_keyup))
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
else
rc_keyup(ir->dev);
} else {
/* can't distinguish keydown/up :-/ */
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
rc_keyup(ir->dev);
}
}
@@ -329,6 +345,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
* 002-T mini RC, provided with newer PV hardware
*/
ir_codes = RC_MAP_PIXELVIEW_MK12;
+ rc_type = RC_BIT_NEC;
ir->gpio_addr = MO_GP1_IO;
ir->mask_keyup = 0x80;
ir->polling = 10; /* ms */
@@ -416,7 +433,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_TWINHAN_VP1027_DVBS:
ir_codes = RC_MAP_TWINHAN_VP1027_DVBS;
- rc_type = RC_BIT_NEC;
ir->sampling = 0xff00; /* address */
break;
}
@@ -462,14 +478,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
dev->priv = core;
dev->open = cx88_ir_open;
dev->close = cx88_ir_close;
- dev->scanmask = hardware_mask;
+ dev->scancode_mask = hardware_mask;
if (ir->sampling) {
dev->driver_type = RC_DRIVER_IR_RAW;
dev->timeout = 10 * 1000 * 1000; /* 10 ms */
} else {
dev->driver_type = RC_DRIVER_SCANCODE;
- rc_set_allowed_protocols(dev, rc_type);
+ dev->allowed_protocols = rc_type;
}
ir->core = core;
@@ -539,7 +555,8 @@ void cx88_ir_irq(struct cx88_core *core)
ir_raw_event_handle(ir->dev);
}
-static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
int flags, code;
@@ -563,8 +580,9 @@ static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
code & 0xff, flags & 0xff);
- *ir_key = code & 0xff;
- *ir_raw = code;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = code & 0xff;
+ *toggle = 0;
return 1;
}
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index fb52bda8d45f..da8f848be3b8 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -1663,11 +1663,40 @@ static struct ddb_info ddb_octopus_le = {
.port_num = 2,
};
+static struct ddb_info ddb_octopus_mini = {
+ .type = DDB_OCTOPUS,
+ .name = "Digital Devices Octopus Mini",
+ .port_num = 4,
+};
+
static struct ddb_info ddb_v6 = {
.type = DDB_OCTOPUS,
.name = "Digital Devices Cine S2 V6 DVB adapter",
.port_num = 3,
};
+static struct ddb_info ddb_v6_5 = {
+ .type = DDB_OCTOPUS,
+ .name = "Digital Devices Cine S2 V6.5 DVB adapter",
+ .port_num = 4,
+};
+
+static struct ddb_info ddb_dvbct = {
+ .type = DDB_OCTOPUS,
+ .name = "Digital Devices DVBCT V6.1 DVB adapter",
+ .port_num = 3,
+};
+
+static struct ddb_info ddb_satixS2v3 = {
+ .type = DDB_OCTOPUS,
+ .name = "Mystique SaTiX-S2 V3 DVB adapter",
+ .port_num = 3,
+};
+
+static struct ddb_info ddb_octopusv3 = {
+ .type = DDB_OCTOPUS,
+ .name = "Digital Devices Octopus V3 DVB adapter",
+ .port_num = 4,
+};
#define DDVID 0xdd01 /* Digital Devices Vendor ID */
@@ -1680,8 +1709,12 @@ static const struct pci_device_id ddb_id_tbl[] = {
DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
- DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus),
+ DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini),
DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
+ DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5),
+ DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct),
+ DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3),
+ DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3),
/* in case sub-ids got deleted in flash */
DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
{0}
diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c
index e60ac35fc10c..e8826c535ccd 100644
--- a/drivers/media/pci/dm1105/dm1105.c
+++ b/drivers/media/pci/dm1105/dm1105.c
@@ -678,7 +678,8 @@ static void dm1105_emit_key(struct work_struct *work)
data = (ircom >> 8) & 0x7f;
- rc_keydown(ir->dev, data, 0);
+ /* FIXME: UNKNOWN because we don't generate a full NEC scancode (yet?) */
+ rc_keydown(ir->dev, RC_TYPE_UNKNOWN, data, 0);
}
/* work handler */
diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
index c60424601cb9..2b0ab26e11e8 100644
--- a/drivers/media/pci/ivtv/ivtv-controls.c
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
@@ -135,8 +135,8 @@ static int ivtv_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
/* V4L2_CID_MPEG_VIDEO_DEC_PTS and V4L2_CID_MPEG_VIDEO_DEC_FRAME
control cluster */
case V4L2_CID_MPEG_VIDEO_DEC_PTS:
- return ivtv_g_pts_frame(itv, &itv->ctrl_pts->val64,
- &itv->ctrl_frame->val64);
+ return ivtv_g_pts_frame(itv, itv->ctrl_pts->p_new.p_s64,
+ itv->ctrl_frame->p_new.p_s64);
}
return 0;
}
diff --git a/drivers/media/pci/ivtv/ivtv-i2c.c b/drivers/media/pci/ivtv/ivtv-i2c.c
index ceed2d87abfd..1a41ba5c7d30 100644
--- a/drivers/media/pci/ivtv/ivtv-i2c.c
+++ b/drivers/media/pci/ivtv/ivtv-i2c.c
@@ -148,7 +148,8 @@ static const char * const hw_devicenames[] = {
"ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */
};
-static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_adaptec(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char keybuf[4];
@@ -167,9 +168,9 @@ static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
keybuf[2] &= 0x7f;
keybuf[3] |= 0x80;
- *ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
- *ir_raw = *ir_key;
-
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
+ *toggle = 0;
return 1;
}
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index b3667a00db3a..3e0cb77d5930 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -351,7 +351,6 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
pixfmt->height = itv->cxhdl.height;
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
pixfmt->field = V4L2_FIELD_INTERLACED;
- pixfmt->priv = 0;
if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
pixfmt->pixelformat = V4L2_PIX_FMT_HM12;
/* YUV size is (Y=(h*720) + UV=(h*(720/2))) */
@@ -418,7 +417,6 @@ static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *f
pixfmt->height = itv->main_rect.height;
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
pixfmt->field = V4L2_FIELD_INTERLACED;
- pixfmt->priv = 0;
if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
case IVTV_YUV_MODE_INTERLACED:
@@ -1384,7 +1382,6 @@ static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
fb->fmt.bytesperline = fb->fmt.width;
fb->fmt.colorspace = V4L2_COLORSPACE_SMPTE170M;
fb->fmt.field = V4L2_FIELD_INTERLACED;
- fb->fmt.priv = 0;
if (fb->fmt.pixelformat != V4L2_PIX_FMT_PAL8)
fb->fmt.bytesperline *= 2;
if (fb->fmt.pixelformat == V4L2_PIX_FMT_RGB32 ||
diff --git a/drivers/media/pci/ivtv/ivtv-streams.c b/drivers/media/pci/ivtv/ivtv-streams.c
index 70dad588a677..f0a1cc472313 100644
--- a/drivers/media/pci/ivtv/ivtv-streams.c
+++ b/drivers/media/pci/ivtv/ivtv-streams.c
@@ -251,7 +251,6 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
v4l2_disable_ioctl(s->vdev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(s->vdev, VIDIOC_S_STD);
}
- set_bit(V4L2_FL_USE_FH_PRIO, &s->vdev->flags);
ivtv_set_funcs(s->vdev);
return 0;
}
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index 54d5c821007c..aeae54708811 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1166,7 +1166,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1232,7 +1231,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1749,7 +1747,6 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent)
v4l2_ctrl_handler_setup(&meye.hdl);
meye.vdev->ctrl_handler = &meye.hdl;
- set_bit(V4L2_FL_USE_FH_PRIO, &meye.vdev->flags);
if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
video_nr) < 0) {
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 970e83308525..826228c3800e 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -910,7 +910,6 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev,
{
dma_addr_t tmp;
u32 i, j;
- int status = 0;
u32 SCListMemSize = pRingBuffer->NumBuffers
* ((Buffer2Length != 0) ? (NUM_SCATTER_GATHER_ENTRIES * 2) :
NUM_SCATTER_GATHER_ENTRIES)
@@ -1010,14 +1009,12 @@ static int AllocateRingBuffers(struct pci_dev *pci_dev,
}
- return status;
+ return 0;
}
static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
struct SRingBufferDescriptor *pRingBuffer)
{
- int status = 0;
-
/* Copy pointer to scatter gather list in TSRingbuffer
structure for buffer 2
Load number of buffer
@@ -1038,7 +1035,7 @@ static int FillTSIdleBuffer(struct SRingBufferDescriptor *pIdleBuffer,
pIdleBuffer->Head->ngeneBuffer.Number_of_entries_1;
Cur = Cur->Next;
}
- return status;
+ return 0;
}
static u32 RingBufferSizes[MAX_STREAM] = {
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index be19a051a492..9ff03a69ced4 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -811,7 +811,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
vfd->release = video_device_release;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
dev->name, type, saa7134_boards[dev->board].name);
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
video_set_drvdata(vfd, dev);
return vfd;
}
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 0006d6bf8c18..e4ea85fd1b23 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -130,7 +130,6 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -148,7 +147,6 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -166,7 +164,6 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -270,7 +267,6 @@ static int empress_init(struct saa7134_dev *dev)
snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
"%s empress (%s)", dev->name,
saa7134_boards[dev->board].name);
- set_bit(V4L2_FL_USE_FH_PRIO, &dev->empress_dev->flags);
v4l2_ctrl_handler_init(hdl, 21);
v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter);
if (dev->empress_sd)
diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c
index 6f4312663bdf..dc3d6516edf7 100644
--- a/drivers/media/pci/saa7134/saa7134-input.c
+++ b/drivers/media/pci/saa7134/saa7134-input.c
@@ -83,14 +83,14 @@ static int build_key(struct saa7134_dev *dev)
if (data == ir->mask_keycode)
rc_keyup(ir->dev);
else
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
return 0;
}
if (ir->polling) {
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
} else {
rc_keyup(ir->dev);
}
@@ -98,7 +98,7 @@ static int build_key(struct saa7134_dev *dev)
else { /* IRQ driven mode - handle key press and release in one go */
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keydown_notimeout(ir->dev, RC_TYPE_UNKNOWN, data, 0);
rc_keyup(ir->dev);
}
}
@@ -108,7 +108,8 @@ static int build_key(struct saa7134_dev *dev)
/* --------------------- Chip specific I2C key builders ----------------- */
-static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
int gpio;
int attempt = 0;
@@ -132,10 +133,6 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (0x40000 & ~gpio)
return 0; /* No button press */
- /* No button press - only before first key pressed */
- if (b == 0xFF)
- return 0;
-
/* poll IR chip */
/* weak up the IR chip */
b = 0;
@@ -158,13 +155,14 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return -EIO;
}
- *ir_key = b;
- *ir_raw = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
-static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw)
+static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char b;
int gpio;
@@ -205,14 +203,15 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
/* Button pressed */
dprintk("get_key_msi_tvanywhere_plus: Key = 0x%02X\n", b);
- *ir_key = b;
- *ir_raw = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
/* copied and modified from get_key_msi_tvanywhere_plus() */
-static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw)
+static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char b;
unsigned int gpio;
@@ -253,12 +252,14 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, u32 *ir_key,
/* Button pressed */
dprintk("get_key_kworld_pc150u: Key = 0x%02X\n", b);
- *ir_key = b;
- *ir_raw = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
-static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_purpletv(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char b;
@@ -276,12 +277,14 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (b & 0x80)
return 1;
- *ir_key = b;
- *ir_raw = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
+ *toggle = 0;
return 1;
}
-static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_hvr1110(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char buf[5];
@@ -299,14 +302,20 @@ static int get_key_hvr1110(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
* by preserving it into two separate readings
* buf[4] bits 0 and 1, and buf[1] and buf[2] are always
* zero.
+ *
+ * Note that the keymap which the hvr1110 uses is RC5.
+ *
+ * FIXME: start bits could maybe be used...?
*/
- *ir_key = 0x1fff & ((buf[3] << 8) | (buf[4] >> 2));
- *ir_raw = *ir_key;
+ *protocol = RC_TYPE_RC5;
+ *scancode = RC_SCANCODE_RC5(buf[3] & 0x1f, buf[4] >> 2);
+ *toggle = !!(buf[3] & 0x40);
return 1;
}
-static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_beholdm6xx(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
unsigned char data[12];
u32 gpio;
@@ -332,17 +341,18 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (data[9] != (unsigned char)(~data[8]))
return 0;
- *ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
- *ir_key = *ir_raw;
-
+ *protocol = RC_TYPE_NEC;
+ *scancode = RC_SCANCODE_NECX(data[11] << 8 | data[10], data[9]);
+ *toggle = 0;
return 1;
}
/* Common (grey or coloured) pinnacle PCTV remote handling
*
*/
-static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
- int parity_offset, int marker, int code_modulo)
+static int get_key_pinnacle(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle, int parity_offset,
+ int marker, int code_modulo)
{
unsigned char b[4];
unsigned int start = 0,parity = 0,code = 0;
@@ -377,11 +387,11 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
code %= code_modulo;
- *ir_raw = code;
- *ir_key = code;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = code;
+ *toggle = 0;
i2cdprintk("Pinnacle PCTV key %02x\n", code);
-
return 1;
}
@@ -394,10 +404,11 @@ static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
*
* Sylvain Pasche
*/
-static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_grey(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
- return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+ return get_key_pinnacle(ir, protocol, scancode, toggle, 1, 0xfe, 0xff);
}
@@ -405,7 +416,8 @@ static int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
*
* Ricardo Cerqueira
*/
-static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_color(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *scancode, u8 *toggle)
{
/* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
*
@@ -413,7 +425,7 @@ static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
* codes < 128
*/
- return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+ return get_key_pinnacle(ir, protocol, scancode, toggle, 2, 0x80, 0x88);
}
void saa7134_input_irq(struct saa7134_dev *dev)
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index d37599980768..0cfa2ca6a32a 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1235,7 +1235,6 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1315,7 +1314,6 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.priv = 0;
return 0;
}
diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index 5c5cc3ebf9bd..16ae71592e8c 100644
--- a/drivers/media/pci/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -242,16 +242,14 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
if (!demux->dmx.frontend)
return -EINVAL;
- if (dvb) {
- mutex_lock(&dvb->lock);
- if (dvb->feeding++ == 0) {
- /* Start transport */
- ret = saa7164_dvb_start_port(port);
- }
- mutex_unlock(&dvb->lock);
- dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
- __func__, port->nr, dvb->feeding);
+ mutex_lock(&dvb->lock);
+ if (dvb->feeding++ == 0) {
+ /* Start transport */
+ ret = saa7164_dvb_start_port(port);
}
+ mutex_unlock(&dvb->lock);
+ dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
+ __func__, port->nr, dvb->feeding);
return ret;
}
@@ -266,16 +264,14 @@ static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
- if (dvb) {
- mutex_lock(&dvb->lock);
- if (--dvb->feeding == 0) {
- /* Stop transport */
- ret = saa7164_dvb_stop_streaming(port);
- }
- mutex_unlock(&dvb->lock);
- dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
- __func__, port->nr, dvb->feeding);
+ mutex_lock(&dvb->lock);
+ if (--dvb->feeding == 0) {
+ /* Stop transport */
+ ret = saa7164_dvb_stop_streaming(port);
}
+ mutex_unlock(&dvb->lock);
+ dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
+ __func__, port->nr, dvb->feeding);
return ret;
}
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig
similarity index 93%
rename from drivers/staging/media/solo6x10/Kconfig
rename to drivers/media/pci/solo6x10/Kconfig
index 6a1906fa1117..d9e06a6bf1eb 100644
--- a/drivers/staging/media/solo6x10/Kconfig
+++ b/drivers/media/pci/solo6x10/Kconfig
@@ -1,6 +1,7 @@
-config SOLO6X10
+config VIDEO_SOLO6X10
tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
depends on PCI && VIDEO_DEV && SND && I2C
+ select BITREVERSE
select FONT_SUPPORT
select FONT_8x16
select VIDEOBUF2_DMA_SG
diff --git a/drivers/staging/media/solo6x10/Makefile b/drivers/media/pci/solo6x10/Makefile
similarity index 82%
rename from drivers/staging/media/solo6x10/Makefile
rename to drivers/media/pci/solo6x10/Makefile
index 7aae118947b2..f4742266ef7c 100644
--- a/drivers/staging/media/solo6x10/Makefile
+++ b/drivers/media/pci/solo6x10/Makefile
@@ -2,4 +2,4 @@ solo6x10-y := solo6x10-core.o solo6x10-i2c.o solo6x10-p2m.o solo6x10-v4l2.o \
solo6x10-tw28.o solo6x10-gpio.o solo6x10-disp.o solo6x10-enc.o \
solo6x10-v4l2-enc.o solo6x10-g723.o solo6x10-eeprom.o
-obj-$(CONFIG_SOLO6X10) += solo6x10.o
+obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10.o
diff --git a/drivers/staging/media/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c
similarity index 98%
rename from drivers/staging/media/solo6x10/solo6x10-core.c
rename to drivers/media/pci/solo6x10/solo6x10-core.c
index f67046955ef6..172583d736fe 100644
--- a/drivers/staging/media/solo6x10/solo6x10-core.c
+++ b/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
@@ -307,8 +303,8 @@ static ssize_t p2m_timeout_store(struct device *dev,
struct solo_dev *solo_dev =
container_of(dev, struct solo_dev, dev);
unsigned long ms;
-
int ret = kstrtoul(buf, 10, &ms);
+
if (ret < 0 || ms > 200)
return -EINVAL;
solo_dev->p2m_jiffies = msecs_to_jiffies(ms);
diff --git a/drivers/staging/media/solo6x10/solo6x10-disp.c b/drivers/media/pci/solo6x10/solo6x10-disp.c
similarity index 95%
rename from drivers/staging/media/solo6x10/solo6x10-disp.c
rename to drivers/media/pci/solo6x10/solo6x10-disp.c
index 145295a5db72..5ea9cac03968 100644
--- a/drivers/staging/media/solo6x10/solo6x10-disp.c
+++ b/drivers/media/pci/solo6x10/solo6x10-disp.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
@@ -211,21 +207,25 @@ int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val)
}
int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
- const struct solo_motion_thresholds *thresholds)
+ const u16 *thresholds)
{
+ const unsigned size = sizeof(u16) * 64;
u32 off = SOLO_MOT_FLAG_AREA + ch * SOLO_MOT_THRESH_SIZE * 2;
- u16 buf[64];
+ u16 *buf;
int x, y;
int ret = 0;
- memset(buf, 0, sizeof(buf));
+ buf = kzalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
for (y = 0; y < SOLO_MOTION_SZ; y++) {
for (x = 0; x < SOLO_MOTION_SZ; x++)
- buf[x] = cpu_to_le16(thresholds->thresholds[y][x]);
+ buf[x] = cpu_to_le16(thresholds[y * SOLO_MOTION_SZ + x]);
ret |= solo_p2m_dma(solo_dev, 1, buf,
- SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * sizeof(buf),
- sizeof(buf), 0, 0);
+ SOLO_MOTION_EXT_ADDR(solo_dev) + off + y * size,
+ size, 0, 0);
}
+ kfree(buf);
return ret;
}
diff --git a/drivers/staging/media/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
similarity index 94%
rename from drivers/staging/media/solo6x10/solo6x10-eeprom.c
rename to drivers/media/pci/solo6x10/solo6x10-eeprom.c
index 9d1c9bb53d6b..af40b3aba410 100644
--- a/drivers/staging/media/solo6x10/solo6x10-eeprom.c
+++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/solo6x10/solo6x10-enc.c b/drivers/media/pci/solo6x10/solo6x10-enc.c
similarity index 97%
rename from drivers/staging/media/solo6x10/solo6x10-enc.c
rename to drivers/media/pci/solo6x10/solo6x10-enc.c
index 2db53b68c62f..d19c0aef5abc 100644
--- a/drivers/staging/media/solo6x10/solo6x10-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-enc.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c
similarity index 98%
rename from drivers/staging/media/solo6x10/solo6x10-g723.c
rename to drivers/media/pci/solo6x10/solo6x10-g723.c
index 74f037b6166c..c7141f2e63bd 100644
--- a/drivers/staging/media/solo6x10/solo6x10-g723.c
+++ b/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/solo6x10/solo6x10-gpio.c b/drivers/media/pci/solo6x10/solo6x10-gpio.c
similarity index 92%
rename from drivers/staging/media/solo6x10/solo6x10-gpio.c
rename to drivers/media/pci/solo6x10/solo6x10-gpio.c
index 73276dc92875..6d3b4a36bc11 100644
--- a/drivers/staging/media/solo6x10/solo6x10-gpio.c
+++ b/drivers/media/pci/solo6x10/solo6x10-gpio.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/solo6x10/solo6x10-i2c.c b/drivers/media/pci/solo6x10/solo6x10-i2c.c
similarity index 97%
rename from drivers/staging/media/solo6x10/solo6x10-i2c.c
rename to drivers/media/pci/solo6x10/solo6x10-i2c.c
index 01aa417c9258..c908672b2c40 100644
--- a/drivers/staging/media/solo6x10/solo6x10-i2c.c
+++ b/drivers/media/pci/solo6x10/solo6x10-i2c.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/* XXX: The SOLO6x10 i2c does not have separate interrupts for each i2c
diff --git a/drivers/staging/media/solo6x10/solo6x10-jpeg.h b/drivers/media/pci/solo6x10/solo6x10-jpeg.h
similarity index 96%
rename from drivers/staging/media/solo6x10/solo6x10-jpeg.h
rename to drivers/media/pci/solo6x10/solo6x10-jpeg.h
index c5218ceeabca..1c66a46da514 100644
--- a/drivers/staging/media/solo6x10/solo6x10-jpeg.h
+++ b/drivers/media/pci/solo6x10/solo6x10-jpeg.h
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6X10_JPEG_H
@@ -110,7 +106,7 @@ static const unsigned char jpeg_header[] = {
/* This is the byte marker for the start of the DQT */
#define DQT_START 17
#define DQT_LEN 138
-const unsigned char jpeg_dqt[4][DQT_LEN] = {
+static const unsigned char jpeg_dqt[4][DQT_LEN] = {
{
0xff, 0xdb, 0x00, 0x43, 0x00,
0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
diff --git a/drivers/staging/media/solo6x10/solo6x10-offsets.h b/drivers/media/pci/solo6x10/solo6x10-offsets.h
similarity index 93%
rename from drivers/staging/media/solo6x10/solo6x10-offsets.h
rename to drivers/media/pci/solo6x10/solo6x10-offsets.h
index 13eeb4470dcf..d6aea7c2a676 100644
--- a/drivers/staging/media/solo6x10/solo6x10-offsets.h
+++ b/drivers/media/pci/solo6x10/solo6x10-offsets.h
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6X10_OFFSETS_H
diff --git a/drivers/staging/media/solo6x10/solo6x10-p2m.c b/drivers/media/pci/solo6x10/solo6x10-p2m.c
similarity index 97%
rename from drivers/staging/media/solo6x10/solo6x10-p2m.c
rename to drivers/media/pci/solo6x10/solo6x10-p2m.c
index 7f2f2472655b..8c8484674d2f 100644
--- a/drivers/staging/media/solo6x10/solo6x10-p2m.c
+++ b/drivers/media/pci/solo6x10/solo6x10-p2m.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/solo6x10/solo6x10-regs.h b/drivers/media/pci/solo6x10/solo6x10-regs.h
similarity index 99%
rename from drivers/staging/media/solo6x10/solo6x10-regs.h
rename to drivers/media/pci/solo6x10/solo6x10-regs.h
index 428f6c951180..e34ac56ab101 100644
--- a/drivers/staging/media/solo6x10/solo6x10-regs.h
+++ b/drivers/media/pci/solo6x10/solo6x10-regs.h
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6X10_REGISTERS_H
diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c
similarity index 99%
rename from drivers/staging/media/solo6x10/solo6x10-tw28.c
rename to drivers/media/pci/solo6x10/solo6x10-tw28.c
index 36daa1720b54..edd0781ee4b5 100644
--- a/drivers/staging/media/solo6x10/solo6x10-tw28.c
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
@@ -214,6 +210,7 @@ static void tw_write_and_verify(struct solo_dev *solo_dev, u8 addr, u8 off,
for (i = 0; i < 5; i++) {
u8 rval = solo_i2c_readbyte(solo_dev, SOLO_I2C_TW, addr, off);
+
if (rval == val)
return;
diff --git a/drivers/staging/media/solo6x10/solo6x10-tw28.h b/drivers/media/pci/solo6x10/solo6x10-tw28.h
similarity index 91%
rename from drivers/staging/media/solo6x10/solo6x10-tw28.h
rename to drivers/media/pci/solo6x10/solo6x10-tw28.h
index 1a02c87d4cf0..0966b45057a3 100644
--- a/drivers/staging/media/solo6x10/solo6x10-tw28.h
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.h
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6X10_TW28_H
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
similarity index 90%
rename from drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
rename to drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index b8ff113c20f4..28023f9f1dc7 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
@@ -243,6 +239,8 @@ static int solo_enc_on(struct solo_enc_dev *solo_enc)
if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
return -EBUSY;
solo_enc->sequence = 0;
+ solo_enc->motion_last_state = false;
+ solo_enc->frames_since_last_motion = 0;
solo_dev->enc_bw_remain -= solo_enc->bw_weight;
if (solo_enc->type == SOLO_ENC_TYPE_EXT)
@@ -476,8 +474,9 @@ static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
/* may discard all previous data in vbuf->sgl */
- dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
- DMA_FROM_DEVICE);
+ if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+ DMA_FROM_DEVICE))
+ return -ENOMEM;
ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
@@ -523,8 +522,9 @@ static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
/* may discard all previous data in vbuf->sgl */
- dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
- DMA_FROM_DEVICE);
+ if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
+ DMA_FROM_DEVICE))
+ return -ENOMEM;
ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
SOLO_MP4E_EXT_ADDR(solo_dev),
SOLO_MP4E_EXT_SIZE(solo_dev));
@@ -544,15 +544,6 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
const vop_header *vh = enc_buf->vh;
int ret;
- /* Check for motion flags */
- vb->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_MOTION_ON |
- V4L2_BUF_FLAG_MOTION_DETECTED);
- if (solo_is_motion_on(solo_enc)) {
- vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_ON;
- if (enc_buf->motion)
- vb->v4l2_buf.flags |= V4L2_BUF_FLAG_MOTION_DETECTED;
- }
-
switch (solo_enc->fmt) {
case V4L2_PIX_FMT_MPEG4:
case V4L2_PIX_FMT_H264:
@@ -564,9 +555,49 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
}
if (!ret) {
+ bool send_event = false;
+
vb->v4l2_buf.sequence = solo_enc->sequence++;
vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
+
+ /* Check for motion flags */
+ if (solo_is_motion_on(solo_enc)) {
+ /* It takes a few frames for the hardware to detect
+ * motion. Once it does it clears the motion detection
+ * register and it takes again a few frames before
+ * motion is seen. This means in practice that when the
+ * motion field is 1, it will go back to 0 for the next
+ * frame. This leads to motion detection event being
+ * sent all the time, which is not what we want.
+ * Instead wait a few frames before deciding that the
+ * motion has halted. After some experimentation it
+ * turns out that waiting for 5 frames works well.
+ */
+ if (enc_buf->motion == 0 &&
+ solo_enc->motion_last_state &&
+ solo_enc->frames_since_last_motion++ > 5)
+ send_event = true;
+ else if (enc_buf->motion) {
+ solo_enc->frames_since_last_motion = 0;
+ send_event = !solo_enc->motion_last_state;
+ }
+ }
+
+ if (send_event) {
+ struct v4l2_event ev = {
+ .type = V4L2_EVENT_MOTION_DET,
+ .u.motion_det = {
+ .flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
+ .frame_sequence = vb->v4l2_buf.sequence,
+ .region_mask = enc_buf->motion ? 1 : 0,
+ },
+ };
+
+ solo_enc->motion_last_state = enc_buf->motion;
+ solo_enc->frames_since_last_motion = 0;
+ v4l2_event_queue(solo_enc->vfd, &ev);
+ }
}
vb2_buffer_done(vb, ret ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
@@ -669,6 +700,7 @@ static int solo_ring_thread(void *data)
for (;;) {
long timeout = schedule_timeout_interruptible(HZ);
+
if (timeout == -ERESTARTSYS || kthread_should_stop())
break;
solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
@@ -715,6 +747,7 @@ static int solo_ring_start(struct solo_dev *solo_dev)
SOLO6X10_NAME "_ring");
if (IS_ERR(solo_dev->ring_thread)) {
int err = PTR_ERR(solo_dev->ring_thread);
+
solo_dev->ring_thread = NULL;
return err;
}
@@ -1068,31 +1101,6 @@ static int solo_s_parm(struct file *file, void *priv,
return solo_g_parm(file, priv, sp);
}
-static long solo_enc_default(struct file *file, void *fh,
- bool valid_prio, unsigned int cmd, void *arg)
-{
- struct solo_enc_dev *solo_enc = video_drvdata(file);
- struct solo_dev *solo_dev = solo_enc->solo_dev;
- struct solo_motion_thresholds *thresholds = arg;
-
- switch (cmd) {
- case SOLO_IOC_G_MOTION_THRESHOLDS:
- *thresholds = solo_enc->motion_thresholds;
- return 0;
-
- case SOLO_IOC_S_MOTION_THRESHOLDS:
- if (!valid_prio)
- return -EBUSY;
- solo_enc->motion_thresholds = *thresholds;
- if (solo_enc->motion_enabled && !solo_enc->motion_global)
- return solo_set_motion_block(solo_dev, solo_enc->ch,
- &solo_enc->motion_thresholds);
- return 0;
- default:
- return -ENOTTY;
- }
-}
-
static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct solo_enc_dev *solo_enc =
@@ -1110,30 +1118,43 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
ctrl->val);
case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
solo_enc->gop = ctrl->val;
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP(solo_enc->ch), solo_enc->gop);
+ solo_reg_write(solo_dev, SOLO_VE_CH_GOP_E(solo_enc->ch), solo_enc->gop);
return 0;
- case V4L2_CID_MOTION_THRESHOLD:
- solo_enc->motion_thresh = ctrl->val;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ solo_enc->qp = ctrl->val;
+ solo_reg_write(solo_dev, SOLO_VE_CH_QP(solo_enc->ch), solo_enc->qp);
+ solo_reg_write(solo_dev, SOLO_VE_CH_QP_E(solo_enc->ch), solo_enc->qp);
+ return 0;
+ case V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD:
+ solo_enc->motion_thresh = ctrl->val << 8;
if (!solo_enc->motion_global || !solo_enc->motion_enabled)
return 0;
return solo_set_motion_threshold(solo_dev, solo_enc->ch,
- ctrl->val);
- case V4L2_CID_MOTION_MODE:
- solo_enc->motion_global = ctrl->val == 1;
- solo_enc->motion_enabled = ctrl->val > 0;
+ solo_enc->motion_thresh);
+ case V4L2_CID_DETECT_MD_MODE:
+ solo_enc->motion_global = ctrl->val == V4L2_DETECT_MD_MODE_GLOBAL;
+ solo_enc->motion_enabled = ctrl->val > V4L2_DETECT_MD_MODE_DISABLED;
if (ctrl->val) {
if (solo_enc->motion_global)
- solo_set_motion_threshold(solo_dev,
- solo_enc->ch, solo_enc->motion_thresh);
+ err = solo_set_motion_threshold(solo_dev, solo_enc->ch,
+ solo_enc->motion_thresh);
else
- solo_set_motion_block(solo_dev, solo_enc->ch,
- &solo_enc->motion_thresholds);
+ err = solo_set_motion_block(solo_dev, solo_enc->ch,
+ solo_enc->md_thresholds->p_cur.p_u16);
+ if (err)
+ return err;
}
solo_motion_toggle(solo_enc, ctrl->val);
return 0;
+ case V4L2_CID_DETECT_MD_THRESHOLD_GRID:
+ if (solo_enc->motion_enabled && !solo_enc->motion_global)
+ return solo_set_motion_block(solo_dev, solo_enc->ch,
+ solo_enc->md_thresholds->p_new.p_u16);
+ break;
case V4L2_CID_OSD_TEXT:
- strcpy(solo_enc->osd_text, ctrl->string);
- err = solo_osd_print(solo_enc);
- return err;
+ strcpy(solo_enc->osd_text, ctrl->p_new.p_char);
+ return solo_osd_print(solo_enc);
default:
return -EINVAL;
}
@@ -1141,6 +1162,21 @@ static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int solo_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+
+ switch (sub->type) {
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ case V4L2_EVENT_MOTION_DET:
+ /* Allow for up to 30 events (1 second for NTSC) to be
+ * stored. */
+ return v4l2_event_subscribe(fh, sub, 30, NULL);
+ }
+ return -EINVAL;
+}
+
static const struct v4l2_file_operations solo_enc_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
@@ -1179,9 +1215,8 @@ static const struct v4l2_ioctl_ops solo_enc_ioctl_ops = {
.vidioc_g_parm = solo_g_parm,
/* Logging and events */
.vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_subscribe_event = solo_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
- .vidioc_default = solo_enc_default,
};
static const struct video_device solo_enc_template = {
@@ -1197,33 +1232,6 @@ static const struct v4l2_ctrl_ops solo_ctrl_ops = {
.s_ctrl = solo_s_ctrl,
};
-static const struct v4l2_ctrl_config solo_motion_threshold_ctrl = {
- .ops = &solo_ctrl_ops,
- .id = V4L2_CID_MOTION_THRESHOLD,
- .name = "Motion Detection Threshold",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .max = 0xffff,
- .def = SOLO_DEF_MOT_THRESH,
- .step = 1,
- .flags = V4L2_CTRL_FLAG_SLIDER,
-};
-
-static const char * const solo_motion_mode_menu[] = {
- "Disabled",
- "Global Threshold",
- "Regional Threshold",
- NULL
-};
-
-static const struct v4l2_ctrl_config solo_motion_enable_ctrl = {
- .ops = &solo_ctrl_ops,
- .id = V4L2_CID_MOTION_MODE,
- .name = "Motion Detection Mode",
- .type = V4L2_CTRL_TYPE_MENU,
- .qmenu = solo_motion_mode_menu,
- .max = 2,
-};
-
static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
.ops = &solo_ctrl_ops,
.id = V4L2_CID_OSD_TEXT,
@@ -1233,13 +1241,22 @@ static const struct v4l2_ctrl_config solo_osd_text_ctrl = {
.step = 1,
};
+/* Motion Detection Threshold matrix */
+static const struct v4l2_ctrl_config solo_md_thresholds = {
+ .ops = &solo_ctrl_ops,
+ .id = V4L2_CID_DETECT_MD_THRESHOLD_GRID,
+ .dims = { SOLO_MOTION_SZ, SOLO_MOTION_SZ },
+ .def = SOLO_DEF_MOT_THRESH,
+ .max = 65535,
+ .step = 1,
+};
+
static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
u8 ch, unsigned nr)
{
struct solo_enc_dev *solo_enc;
struct v4l2_ctrl_handler *hdl;
int ret;
- int x, y;
solo_enc = kzalloc(sizeof(*solo_enc), GFP_KERNEL);
if (!solo_enc)
@@ -1260,9 +1277,18 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
V4L2_CID_SHARPNESS, 0, 15, 1, 0);
v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 255, 1, solo_dev->fps);
- v4l2_ctrl_new_custom(hdl, &solo_motion_threshold_ctrl, NULL);
- v4l2_ctrl_new_custom(hdl, &solo_motion_enable_ctrl, NULL);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 31, 1, SOLO_DEFAULT_QP);
+ v4l2_ctrl_new_std_menu(hdl, &solo_ctrl_ops,
+ V4L2_CID_DETECT_MD_MODE,
+ V4L2_DETECT_MD_MODE_THRESHOLD_GRID, 0,
+ V4L2_DETECT_MD_MODE_DISABLED);
+ v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
+ V4L2_CID_DETECT_MD_GLOBAL_THRESHOLD, 0, 0xff, 1,
+ SOLO_DEF_MOT_THRESH >> 8);
v4l2_ctrl_new_custom(hdl, &solo_osd_text_ctrl, NULL);
+ solo_enc->md_thresholds =
+ v4l2_ctrl_new_custom(hdl, &solo_md_thresholds, NULL);
if (hdl->error) {
ret = hdl->error;
goto hdl_free;
@@ -1283,11 +1309,6 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
solo_enc->mode = SOLO_ENC_MODE_CIF;
solo_enc->motion_global = true;
solo_enc->motion_thresh = SOLO_DEF_MOT_THRESH;
- for (y = 0; y < SOLO_MOTION_SZ; y++)
- for (x = 0; x < SOLO_MOTION_SZ; x++)
- solo_enc->motion_thresholds.thresholds[y][x] =
- SOLO_DEF_MOT_THRESH;
-
solo_enc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
solo_enc->vidq.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
solo_enc->vidq.ops = &solo_enc_video_qops;
@@ -1326,7 +1347,6 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
solo_enc->vfd->ctrl_handler = hdl;
solo_enc->vfd->queue = &solo_enc->vidq;
solo_enc->vfd->lock = &solo_enc->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &solo_enc->vfd->flags);
video_set_drvdata(solo_enc->vfd, solo_enc);
ret = video_register_device(solo_enc->vfd, VFL_TYPE_GRABBER, nr);
if (ret < 0)
@@ -1381,6 +1401,7 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
if (i != solo_dev->nr_chans) {
int ret = PTR_ERR(solo_dev->v4l2_enc[i]);
+
while (i--)
solo_enc_free(solo_dev->v4l2_enc[i]);
pci_free_consistent(solo_dev->pdev, solo_dev->vh_size,
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
similarity index 98%
rename from drivers/staging/media/solo6x10/solo6x10-v4l2.c
rename to drivers/media/pci/solo6x10/solo6x10-v4l2.c
index 5d0100eb38e6..63ae8a61f603 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include
@@ -98,6 +94,7 @@ static int solo_v4l2_ch_ext_4up(struct solo_dev *solo_dev, u8 idx, int on)
if (!on) {
u8 i;
+
for (i = ch; i < ch + 4; i++)
solo_win_setup(solo_dev, i, solo_dev->video_hsize,
solo_vlines(solo_dev),
@@ -206,6 +203,7 @@ static void solo_fillbuf(struct solo_dev *solo_dev,
if (erase_off(solo_dev)) {
void *p = vb2_plane_vaddr(vb, 0);
int image_size = solo_image_size(solo_dev);
+
for (i = 0; i < image_size; i += 2) {
((u8 *)p)[i] = 0x80;
((u8 *)p)[i + 1] = 0x00;
@@ -275,6 +273,7 @@ static int solo_thread(void *data)
for (;;) {
long timeout = schedule_timeout_interruptible(HZ);
+
if (timeout == -ERESTARTSYS || kthread_should_stop())
break;
solo_thread_try(solo_dev);
@@ -414,6 +413,7 @@ static int solo_enum_input(struct file *file, void *priv,
if (input->index >= solo_dev->nr_chans) {
int ret = solo_enum_ext_input(solo_dev, input);
+
if (ret < 0)
return ret;
} else {
@@ -666,7 +666,6 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
goto fail;
}
solo_dev->vfd->ctrl_handler = &solo_dev->disp_hdl;
- set_bit(V4L2_FL_USE_FH_PRIO, &solo_dev->vfd->flags);
video_set_drvdata(solo_dev->vfd, solo_dev);
diff --git a/drivers/staging/media/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
similarity index 89%
rename from drivers/staging/media/solo6x10/solo6x10.h
rename to drivers/media/pci/solo6x10/solo6x10.h
index 8964f8be158e..c6154b00fcbd 100644
--- a/drivers/staging/media/solo6x10/solo6x10.h
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -16,10 +16,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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __SOLO6X10_H
@@ -96,14 +92,7 @@
#define SOLO_DEFAULT_QP 3
-#ifndef V4L2_BUF_FLAG_MOTION_ON
-#define V4L2_BUF_FLAG_MOTION_ON 0x10000
-#define V4L2_BUF_FLAG_MOTION_DETECTED 0x20000
-#endif
-
#define SOLO_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
-#define V4L2_CID_MOTION_MODE (SOLO_CID_CUSTOM_BASE+0)
-#define V4L2_CID_MOTION_THRESHOLD (SOLO_CID_CUSTOM_BASE+1)
#define V4L2_CID_MOTION_TRACE (SOLO_CID_CUSTOM_BASE+2)
#define V4L2_CID_OSD_TEXT (SOLO_CID_CUSTOM_BASE+3)
@@ -113,19 +102,10 @@
* effect, 44x30 samples are used for NTSC, and 44x36 for PAL.
* The 5th sample on the 10th row is (10*64)+5 = 645.
*
- * Using a 64x64 array will result in a problem on some architectures like
- * the powerpc where the size of the argument is limited to 13 bits.
- * Since both PAL and NTSC do not use the full table anyway I've chosen
- * to limit the array to 45x45 (45*16 = 720, which is the maximum PAL/NTSC
- * width).
+ * Internally it is stored as a 45x45 array (45*16 = 720, which is the
+ * maximum PAL/NTSC width).
*/
#define SOLO_MOTION_SZ (45)
-struct solo_motion_thresholds {
- __u16 thresholds[SOLO_MOTION_SZ][SOLO_MOTION_SZ];
-};
-
-#define SOLO_IOC_G_MOTION_THRESHOLDS _IOR('V', BASE_VIDIOC_PRIVATE+0, struct solo_motion_thresholds)
-#define SOLO_IOC_S_MOTION_THRESHOLDS _IOW('V', BASE_VIDIOC_PRIVATE+1, struct solo_motion_thresholds)
enum SOLO_I2C_STATE {
IIC_STATE_IDLE,
@@ -168,6 +148,7 @@ struct solo_enc_dev {
struct solo_dev *solo_dev;
/* V4L2 Items */
struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *md_thresholds;
struct video_device *vfd;
/* General accounting */
struct mutex lock;
@@ -176,9 +157,10 @@ struct solo_enc_dev {
u8 mode, gop, qp, interlaced, interval;
u8 bw_weight;
u16 motion_thresh;
- struct solo_motion_thresholds motion_thresholds;
bool motion_global;
bool motion_enabled;
+ bool motion_last_state;
+ u8 frames_since_last_motion;
u16 width;
u16 height;
@@ -404,7 +386,7 @@ void solo_update_mode(struct solo_enc_dev *solo_enc);
/* Set the threshold for motion detection */
int solo_set_motion_threshold(struct solo_dev *solo_dev, u8 ch, u16 val);
int solo_set_motion_block(struct solo_dev *solo_dev, u8 ch,
- const struct solo_motion_thresholds *thresholds);
+ const u16 *thresholds);
#define SOLO_DEF_MOT_THRESH 0x0300
/* Write text on OSD */
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index d2abd3b5c2bf..365bd21301ba 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -640,7 +640,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.width * 2 * f->fmt.pix.height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1093,7 +1092,6 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
vip->video_dev = &video_dev_template;
vip->video_dev->v4l2_dev = &vip->v4l2_dev;
vip->video_dev->queue = &vip->vb_vidq;
- set_bit(V4L2_FL_USE_FH_PRIO, &vip->video_dev->flags);
video_set_drvdata(vip->video_dev, vip);
ret = video_register_device(vip->video_dev, VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 0acf9202103d..1feeeff3681b 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -161,14 +161,14 @@ static void msp430_ir_interrupt(unsigned long data)
return;
if (budget_ci->ir.full_rc5) {
- rc_keydown(dev,
- budget_ci->ir.rc5_device <<8 | budget_ci->ir.ir_key,
- (command & 0x20) ? 1 : 0);
+ rc_keydown(dev, RC_TYPE_RC5,
+ RC_SCANCODE_RC5(budget_ci->ir.rc5_device, budget_ci->ir.ir_key),
+ !!(command & 0x20));
return;
}
/* FIXME: We should generate complete scancodes for all devices */
- rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
+ rc_keydown(dev, RC_TYPE_UNKNOWN, budget_ci->ir.ir_key, !!(command & 0x20));
}
static int msp430_ir_init(struct budget_ci *budget_ci)
@@ -234,7 +234,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
break;
}
if (!budget_ci->ir.full_rc5)
- dev->scanmask = 0xff;
+ dev->scancode_mask = 0xff;
error = rc_register_device(dev);
if (error) {
diff --git a/drivers/media/pci/zoran/zr36050.h b/drivers/media/pci/zoran/zr36050.h
index 9f52f0cdde50..ea083adda045 100644
--- a/drivers/media/pci/zoran/zr36050.h
+++ b/drivers/media/pci/zoran/zr36050.h
@@ -125,7 +125,6 @@ struct zr36050 {
/* zr36050 mode register bits */
-#define ZR050_MO_COMP 0x80
#define ZR050_MO_COMP 0x80
#define ZR050_MO_ATP 0x40
#define ZR050_MO_PASS2 0x20
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 8108c698b548..6d86646d9743 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -96,6 +96,7 @@ config VIDEO_OMAP3
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
select ARM_DMA_USE_IOMMU
select OMAP_IOMMU
+ select VIDEOBUF2_DMA_CONTIG
---help---
Driver for an OMAP 3 camera controller.
@@ -142,6 +143,7 @@ config VIDEO_CODA
select SRAM
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
+ select GENERIC_ALLOCATOR
---help---
Coda is a range of video codec IPs that supports
H.264, MPEG-4, and other video formats.
@@ -165,12 +167,13 @@ config VIDEO_SAMSUNG_S5P_G2D
2d graphics accelerator.
config VIDEO_SAMSUNG_S5P_JPEG
- tristate "Samsung S5P/Exynos4 JPEG codec driver"
+ tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver"
depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
---help---
- This is a v4l2 driver for Samsung S5P and EXYNOS4 JPEG codec
+ This is a v4l2 driver for Samsung S5P, EXYNOS3250
+ and EXYNOS4 JPEG codec
config VIDEO_SAMSUNG_S5P_MFC
tristate "Samsung S5P MFC Video Codec"
diff --git a/drivers/media/platform/arv.c b/drivers/media/platform/arv.c
index e9410e41ae0c..03c5098499c4 100644
--- a/drivers/media/platform/arv.c
+++ b/drivers/media/platform/arv.c
@@ -773,7 +773,6 @@ static int __init ar_init(void)
ar->vdev.fops = &ar_fops;
ar->vdev.ioctl_ops = &ar_ioctl_ops;
ar->vdev.release = video_device_release_empty;
- set_bit(V4L2_FL_USE_FH_PRIO, &ar->vdev.flags);
video_set_drvdata(&ar->vdev, ar);
if (vga) {
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 16e4b1c525c4..9b5daa65841c 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -446,7 +446,7 @@ static void bcap_stop_streaming(struct vb2_queue *vq)
while (!list_empty(&bcap_dev->dma_queue)) {
bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
struct bcap_buffer, list);
- list_del(&bcap_dev->cur_frm->list);
+ list_del_init(&bcap_dev->cur_frm->list);
vb2_buffer_done(&bcap_dev->cur_frm->vb, VB2_BUF_STATE_ERROR);
}
}
@@ -533,7 +533,7 @@ static irqreturn_t bcap_isr(int irq, void *dev_id)
}
bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
struct bcap_buffer, list);
- list_del(&bcap_dev->cur_frm->list);
+ list_del_init(&bcap_dev->cur_frm->list);
} else {
/* clear error flag, we will get a new frame */
if (ppi->err)
@@ -583,7 +583,7 @@ static int bcap_streamon(struct file *file, void *priv,
bcap_dev->cur_frm = list_entry(bcap_dev->dma_queue.next,
struct bcap_buffer, list);
/* remove buffer from the dma queue */
- list_del(&bcap_dev->cur_frm->list);
+ list_del_init(&bcap_dev->cur_frm->list);
addr = vb2_dma_contig_plane_dma_addr(&bcap_dev->cur_frm->vb, 0);
/* update DMA address */
ppi->ops->update_addr(ppi, (unsigned long)addr);
@@ -939,7 +939,7 @@ static int bcap_probe(struct platform_device *pdev)
bcap_dev->cfg = config;
- bcap_dev->ppi = ppi_create_instance(config->ppi_info);
+ bcap_dev->ppi = ppi_create_instance(pdev, config->ppi_info);
if (!bcap_dev->ppi) {
v4l2_err(pdev->dev.driver, "Unable to create ppi\n");
ret = -ENODEV;
@@ -966,7 +966,6 @@ static int bcap_probe(struct platform_device *pdev)
vfd->ioctl_ops = &bcap_ioctl_ops;
vfd->tvnorms = 0;
vfd->v4l2_dev = &bcap_dev->v4l2_dev;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
strncpy(vfd->name, CAPTURE_DRV_NAME, sizeof(vfd->name));
bcap_dev->video_dev = vfd;
diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c
index 15e9c2bac2b1..cff63e511e6d 100644
--- a/drivers/media/platform/blackfin/ppi.c
+++ b/drivers/media/platform/blackfin/ppi.c
@@ -19,6 +19,7 @@
#include
#include
+#include
#include
#include
@@ -205,6 +206,20 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
int dma_config, bytes_per_line;
int hcount, hdelay, samples_per_line;
+#ifdef CONFIG_PINCTRL
+ static const char * const pin_state[] = {"8bit", "16bit", "24bit"};
+ struct pinctrl *pctrl;
+ struct pinctrl_state *pstate;
+
+ if (params->dlen > 24 || params->dlen <= 0)
+ return -EINVAL;
+ pctrl = devm_pinctrl_get(ppi->dev);
+ pstate = pinctrl_lookup_state(pctrl,
+ pin_state[(params->dlen + 7) / 8 - 1]);
+ if (pinctrl_select_state(pctrl, pstate))
+ return -EINVAL;
+#endif
+
bytes_per_line = params->width * params->bpp / 8;
/* convert parameters unit from pixels to samples */
hcount = params->width * params->bpp / params->dlen;
@@ -307,26 +322,30 @@ static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
set_dma_start_addr(ppi->info->dma_ch, addr);
}
-struct ppi_if *ppi_create_instance(const struct ppi_info *info)
+struct ppi_if *ppi_create_instance(struct platform_device *pdev,
+ const struct ppi_info *info)
{
struct ppi_if *ppi;
if (!info || !info->pin_req)
return NULL;
+#ifndef CONFIG_PINCTRL
if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
- pr_err("request peripheral failed\n");
+ dev_err(&pdev->dev, "request peripheral failed\n");
return NULL;
}
+#endif
ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
if (!ppi) {
peripheral_free_list(info->pin_req);
- pr_err("unable to allocate memory for ppi handle\n");
+ dev_err(&pdev->dev, "unable to allocate memory for ppi handle\n");
return NULL;
}
ppi->ops = &ppi_ops;
ppi->info = info;
+ ppi->dev = &pdev->dev;
pr_info("ppi probe success\n");
return ppi;
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index b1783791d426..3a6d1d2b429e 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -12,6 +12,7 @@
*/
#include
+#include
#include
#include
#include
@@ -22,10 +23,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
@@ -41,22 +44,18 @@
#define CODADX6_MAX_INSTANCES 4
-#define CODA_FMO_BUF_SIZE 32
-#define CODADX6_WORK_BUF_SIZE (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
-#define CODA7_WORK_BUF_SIZE (128 * 1024)
-#define CODA7_TEMP_BUF_SIZE (304 * 1024)
#define CODA_PARA_BUF_SIZE (10 * 1024)
#define CODA_ISRAM_SIZE (2048 * 2)
-#define CODADX6_IRAM_SIZE 0xb000
-#define CODA7_IRAM_SIZE 0x14000
#define CODA7_PS_BUF_SIZE 0x28000
+#define CODA9_PS_SAVE_SIZE (512 * 1024)
#define CODA_MAX_FRAMEBUFFERS 8
#define CODA_MAX_FRAME_SIZE 0x100000
#define FMO_SLICE_SAVE_BUF_SIZE (32)
#define CODA_DEFAULT_GAMMA 4096
+#define CODA9_DEFAULT_GAMMA 24576 /* 0.75 * 32768 */
#define MIN_W 176
#define MIN_H 144
@@ -84,6 +83,7 @@ enum coda_inst_type {
enum coda_product {
CODA_DX6 = 0xf001,
CODA_7541 = 0xf012,
+ CODA_960 = 0xf020,
};
struct coda_fmt {
@@ -105,20 +105,26 @@ struct coda_devtype {
struct coda_codec *codecs;
unsigned int num_codecs;
size_t workbuf_size;
+ size_t tempbuf_size;
+ size_t iram_size;
};
/* Per-queue, driver-specific private data */
struct coda_q_data {
unsigned int width;
unsigned int height;
+ unsigned int bytesperline;
unsigned int sizeimage;
unsigned int fourcc;
+ struct v4l2_rect rect;
};
struct coda_aux_buf {
void *vaddr;
dma_addr_t paddr;
u32 size;
+ struct debugfs_blob_wrapper blob;
+ struct dentry *dentry;
};
struct coda_dev {
@@ -130,32 +136,38 @@ struct coda_dev {
void __iomem *regs_base;
struct clk *clk_per;
struct clk *clk_ahb;
+ struct reset_control *rstc;
struct coda_aux_buf codebuf;
struct coda_aux_buf tempbuf;
struct coda_aux_buf workbuf;
struct gen_pool *iram_pool;
- long unsigned int iram_vaddr;
- long unsigned int iram_paddr;
- unsigned long iram_size;
+ struct coda_aux_buf iram;
spinlock_t irqlock;
struct mutex dev_mutex;
struct mutex coda_mutex;
+ struct workqueue_struct *workqueue;
struct v4l2_m2m_dev *m2m_dev;
struct vb2_alloc_ctx *alloc_ctx;
struct list_head instances;
unsigned long instance_mask;
- struct delayed_work timeout;
+ struct dentry *debugfs_root;
};
struct coda_params {
u8 rot_mode;
u8 h264_intra_qp;
u8 h264_inter_qp;
+ u8 h264_min_qp;
+ u8 h264_max_qp;
+ u8 h264_deblk_enabled;
+ u8 h264_deblk_alpha;
+ u8 h264_deblk_beta;
u8 mpeg4_intra_qp;
u8 mpeg4_inter_qp;
u8 gop_size;
+ int intra_refresh;
int codec_mode;
int codec_mode_aux;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
@@ -175,13 +187,34 @@ struct coda_iram_info {
phys_addr_t buf_btp_use;
phys_addr_t search_ram_paddr;
int search_ram_size;
+ int remaining;
+ phys_addr_t next_paddr;
+};
+
+struct gdi_tiled_map {
+ int xy2ca_map[16];
+ int xy2ba_map[16];
+ int xy2ra_map[16];
+ int rbc2axi_map[32];
+ int xy2rbc_config;
+ int map_type;
+#define GDI_LINEAR_FRAME_MAP 0
+};
+
+struct coda_timestamp {
+ struct list_head list;
+ u32 sequence;
+ struct v4l2_timecode timecode;
+ struct timeval timestamp;
};
struct coda_ctx {
struct coda_dev *dev;
struct mutex buffer_mutex;
struct list_head list;
- struct work_struct skip_run;
+ struct work_struct pic_run_work;
+ struct work_struct seq_end_work;
+ struct completion completion;
int aborting;
int initialized;
int streamon_out;
@@ -189,12 +222,12 @@ struct coda_ctx {
u32 isequence;
u32 qsequence;
u32 osequence;
+ u32 sequence_offset;
struct coda_q_data q_data[2];
enum coda_inst_type inst_type;
struct coda_codec *codec;
enum v4l2_colorspace colorspace;
struct coda_params params;
- struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_ctrl_handler ctrls;
struct v4l2_fh fh;
int gopcounter;
@@ -204,19 +237,26 @@ struct coda_ctx {
struct kfifo bitstream_fifo;
struct mutex bitstream_mutex;
struct coda_aux_buf bitstream;
- bool prescan_failed;
+ bool hold;
struct coda_aux_buf parabuf;
struct coda_aux_buf psbuf;
struct coda_aux_buf slicebuf;
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
+ u32 frame_types[CODA_MAX_FRAMEBUFFERS];
+ struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS];
+ u32 frame_errors[CODA_MAX_FRAMEBUFFERS];
+ struct list_head timestamp_list;
struct coda_aux_buf workbuf;
int num_internal_frames;
int idx;
int reg_idx;
struct coda_iram_info iram_info;
+ struct gdi_tiled_map tiled_map;
u32 bit_stream_param;
u32 frm_dis_flg;
+ u32 frame_mem_ctrl;
int display_idx;
+ struct dentry *debugfs_entry;
};
static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff,
@@ -264,15 +304,23 @@ static void coda_command_async(struct coda_ctx *ctx, int cmd)
{
struct coda_dev *dev = ctx->dev;
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_960 ||
+ dev->devtype->product == CODA_7541) {
/* Restore context related registers to CODA */
coda_write(dev, ctx->bit_stream_param,
CODA_REG_BIT_BIT_STREAM_PARAM);
coda_write(dev, ctx->frm_dis_flg,
CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
+ coda_write(dev, ctx->frame_mem_ctrl,
+ CODA_REG_BIT_FRAME_MEM_CTRL);
coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
}
+ if (dev->devtype->product == CODA_960) {
+ coda_write(dev, 1, CODA9_GDI_WPROT_ERR_CLR);
+ coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+ }
+
coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
@@ -290,6 +338,39 @@ static int coda_command_sync(struct coda_ctx *ctx, int cmd)
return coda_wait_timeout(dev);
}
+static int coda_hw_reset(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+ unsigned long timeout;
+ unsigned int idx;
+ int ret;
+
+ if (!dev->rstc)
+ return -ENOENT;
+
+ idx = coda_read(dev, CODA_REG_BIT_RUN_INDEX);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ coda_write(dev, 0x11, CODA9_GDI_BUS_CTRL);
+ while (coda_read(dev, CODA9_GDI_BUS_STATUS) != 0x77) {
+ if (time_after(jiffies, timeout))
+ return -ETIME;
+ cpu_relax();
+ }
+
+ ret = reset_control_reset(dev->rstc);
+ if (ret < 0)
+ return ret;
+
+ coda_write(dev, 0x00, CODA9_GDI_BUS_CTRL);
+ coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
+ coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
+ ret = coda_wait_timeout(dev);
+ coda_write(dev, idx, CODA_REG_BIT_RUN_INDEX);
+
+ return ret;
+}
+
static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
enum v4l2_buf_type type)
{
@@ -299,9 +380,8 @@ static struct coda_q_data *get_q_data(struct coda_ctx *ctx,
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
return &(ctx->q_data[V4L2_M2M_DST]);
default:
- BUG();
+ return NULL;
}
- return NULL;
}
/*
@@ -348,6 +428,13 @@ static struct coda_codec coda7_codecs[] = {
CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080),
};
+static struct coda_codec coda9_codecs[] = {
+ CODA_CODEC(CODA9_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1920, 1080),
+ CODA_CODEC(CODA9_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1920, 1080),
+ CODA_CODEC(CODA9_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1080),
+ CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1080),
+};
+
static bool coda_format_is_yuv(u32 fourcc)
{
switch (fourcc) {
@@ -426,6 +513,8 @@ static char *coda_product_name(int product)
return "CodaDx6";
case CODA_7541:
return "CODA7541";
+ case CODA_960:
+ return "CODA960";
default:
snprintf(buf, sizeof(buf), "(0x%04x)", product);
return buf;
@@ -515,7 +604,7 @@ static int coda_enum_fmt_vid_cap(struct file *file, void *priv,
struct coda_q_data *q_data_src;
/* If the source format is already fixed, only list matching formats */
- src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (vb2_is_streaming(src_vq)) {
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
@@ -535,24 +624,18 @@ static int coda_enum_fmt_vid_out(struct file *file, void *priv,
static int coda_g_fmt(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct vb2_queue *vq;
struct coda_q_data *q_data;
struct coda_ctx *ctx = fh_to_ctx(priv);
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
- if (!vq)
- return -EINVAL;
-
q_data = get_q_data(ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.pixelformat = q_data->fourcc;
f->fmt.pix.width = q_data->width;
f->fmt.pix.height = q_data->height;
- if (coda_format_is_yuv(f->fmt.pix.pixelformat))
- f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 2);
- else /* encoded formats h.264/mpeg4 */
- f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.bytesperline = q_data->bytesperline;
f->fmt.pix.sizeimage = q_data->sizeimage;
f->fmt.pix.colorspace = ctx->colorspace;
@@ -592,14 +675,16 @@ static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec,
break;
default:
q_data = get_q_data(ctx, f->type);
+ if (!q_data)
+ return -EINVAL;
f->fmt.pix.pixelformat = q_data->fourcc;
}
switch (f->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- /* Frame stride must be multiple of 8 */
- f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 8);
+ /* Frame stride must be multiple of 8, but 16 for h.264 */
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 3 / 2;
break;
@@ -613,8 +698,6 @@ static int coda_try_fmt(struct coda_ctx *ctx, struct coda_codec *codec,
BUG();
}
- f->fmt.pix.priv = 0;
-
return 0;
}
@@ -630,7 +713,7 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
* If the source format is already fixed, try to find a codec that
* converts to the given destination format
*/
- src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (vb2_is_streaming(src_vq)) {
struct coda_q_data *q_data_src;
@@ -653,9 +736,9 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
/* The h.264 decoder only returns complete 16x16 macroblocks */
if (codec && codec->src_fourcc == V4L2_PIX_FMT_H264) {
- f->fmt.pix.width = round_up(f->fmt.pix.width, 16);
+ f->fmt.pix.width = f->fmt.pix.width;
f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
- f->fmt.pix.bytesperline = f->fmt.pix.width;
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 3 / 2;
}
@@ -684,7 +767,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
struct coda_q_data *q_data;
struct vb2_queue *vq;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -700,7 +783,12 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f)
q_data->fourcc = f->fmt.pix.pixelformat;
q_data->width = f->fmt.pix.width;
q_data->height = f->fmt.pix.height;
+ q_data->bytesperline = f->fmt.pix.bytesperline;
q_data->sizeimage = f->fmt.pix.sizeimage;
+ q_data->rect.left = 0;
+ q_data->rect.top = 0;
+ q_data->rect.width = f->fmt.pix.width;
+ q_data->rect.height = f->fmt.pix.height;
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
@@ -739,36 +827,12 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
return ret;
}
-static int coda_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct coda_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int coda_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct coda_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
static int coda_qbuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int coda_expbuf(struct file *file, void *priv,
- struct v4l2_exportbuffer *eb)
-{
- struct coda_ctx *ctx = fh_to_ctx(priv);
-
- return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
+ return v4l2_m2m_qbuf(file, ctx->fh.m2m_ctx, buf);
}
static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
@@ -776,7 +840,7 @@ static bool coda_buf_is_end_of_stream(struct coda_ctx *ctx,
{
struct vb2_queue *src_vq;
- src_vq = v4l2_m2m_get_vq(ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
return ((ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) &&
(buf->sequence == (ctx->qsequence - 1)));
@@ -788,7 +852,7 @@ static int coda_dqbuf(struct file *file, void *priv,
struct coda_ctx *ctx = fh_to_ctx(priv);
int ret;
- ret = v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+ ret = v4l2_m2m_dqbuf(file, ctx->fh.m2m_ctx, buf);
/* If this is the last capture buffer, emit an end-of-stream event */
if (buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
@@ -803,38 +867,48 @@ static int coda_dqbuf(struct file *file, void *priv,
return ret;
}
-static int coda_create_bufs(struct file *file, void *priv,
- struct v4l2_create_buffers *create)
+static int coda_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
{
- struct coda_ctx *ctx = fh_to_ctx(priv);
+ struct coda_ctx *ctx = fh_to_ctx(fh);
+ struct coda_q_data *q_data;
+ struct v4l2_rect r, *rsel;
- return v4l2_m2m_create_bufs(file, ctx->m2m_ctx, create);
-}
+ q_data = get_q_data(ctx, s->type);
+ if (!q_data)
+ return -EINVAL;
-static int coda_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct coda_ctx *ctx = fh_to_ctx(priv);
+ r.left = 0;
+ r.top = 0;
+ r.width = q_data->width;
+ r.height = q_data->height;
+ rsel = &q_data->rect;
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ rsel = &r;
+ /* fallthrough */
+ case V4L2_SEL_TGT_CROP:
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ rsel = &r;
+ /* fallthrough */
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
-static int coda_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct coda_ctx *ctx = fh_to_ctx(priv);
- int ret;
+ s->r = *rsel;
- /*
- * This indirectly calls __vb2_queue_cancel, which dequeues all buffers.
- * We therefore have to lock it against running hardware in this context,
- * which still needs the buffers.
- */
- mutex_lock(&ctx->buffer_mutex);
- ret = v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
- mutex_unlock(&ctx->buffer_mutex);
-
- return ret;
+ return 0;
}
static int coda_try_decoder_cmd(struct file *file, void *fh,
@@ -856,6 +930,7 @@ static int coda_decoder_cmd(struct file *file, void *fh,
struct v4l2_decoder_cmd *dc)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
+ struct coda_dev *dev = ctx->dev;
int ret;
ret = coda_try_decoder_cmd(file, fh, dc);
@@ -869,6 +944,15 @@ static int coda_decoder_cmd(struct file *file, void *fh,
/* Set the strem-end flag on this context */
ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+ if ((dev->devtype->product == CODA_960) &&
+ coda_isbusy(dev) &&
+ (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
+ /* If this context is currently running, update the hardware flag */
+ coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
+ }
+ ctx->hold = false;
+ v4l2_m2m_try_schedule(ctx->fh.m2m_ctx);
+
return 0;
}
@@ -896,16 +980,18 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_try_fmt_vid_out = coda_try_fmt_vid_out,
.vidioc_s_fmt_vid_out = coda_s_fmt_vid_out,
- .vidioc_reqbufs = coda_reqbufs,
- .vidioc_querybuf = coda_querybuf,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = coda_qbuf,
- .vidioc_expbuf = coda_expbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
.vidioc_dqbuf = coda_dqbuf,
- .vidioc_create_bufs = coda_create_bufs,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
- .vidioc_streamon = coda_streamon,
- .vidioc_streamoff = coda_streamoff,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_g_selection = coda_g_selection,
.vidioc_try_decoder_cmd = coda_try_decoder_cmd,
.vidioc_decoder_cmd = coda_decoder_cmd,
@@ -916,13 +1002,6 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
static int coda_start_decoding(struct coda_ctx *ctx);
-static void coda_skip_run(struct work_struct *work)
-{
- struct coda_ctx *ctx = container_of(work, struct coda_ctx, skip_run);
-
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
-}
-
static inline int coda_get_bitstream_payload(struct coda_ctx *ctx)
{
return kfifo_len(&ctx->bitstream_fifo);
@@ -975,7 +1054,7 @@ static int coda_bitstream_queue(struct coda_ctx *ctx, struct vb2_buffer *src_buf
dma_sync_single_for_device(&ctx->dev->plat_dev->dev, ctx->bitstream.paddr,
ctx->bitstream.size, DMA_TO_DEVICE);
- ctx->qsequence++;
+ src_buf->v4l2_buf.sequence = ctx->qsequence++;
return 0;
}
@@ -1003,7 +1082,7 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
if (ctx == v4l2_m2m_get_curr_priv(ctx->dev->m2m_dev))
coda_kfifo_sync_to_device_write(ctx);
- ctx->prescan_failed = false;
+ ctx->hold = false;
return true;
}
@@ -1011,12 +1090,26 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
static void coda_fill_bitstream(struct coda_ctx *ctx)
{
struct vb2_buffer *src_buf;
+ struct coda_timestamp *ts;
- while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) {
- src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
if (coda_bitstream_try_queue(ctx, src_buf)) {
- src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ /*
+ * Source buffer is queued in the bitstream ringbuffer;
+ * queue the timestamp and mark source buffer as done
+ */
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+
+ ts = kmalloc(sizeof(*ts), GFP_KERNEL);
+ if (ts) {
+ ts->sequence = src_buf->v4l2_buf.sequence;
+ ts->timecode = src_buf->v4l2_buf.timecode;
+ ts->timestamp = src_buf->v4l2_buf.timestamp;
+ list_add_tail(&ts->list, &ctx->timestamp_list);
+ }
+
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
} else {
break;
@@ -1024,6 +1117,27 @@ static void coda_fill_bitstream(struct coda_ctx *ctx)
}
}
+static void coda_set_gdi_regs(struct coda_ctx *ctx)
+{
+ struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+ struct coda_dev *dev = ctx->dev;
+ int i;
+
+ for (i = 0; i < 16; i++)
+ coda_write(dev, tiled_map->xy2ca_map[i],
+ CODA9_GDI_XY2_CAS_0 + 4 * i);
+ for (i = 0; i < 4; i++)
+ coda_write(dev, tiled_map->xy2ba_map[i],
+ CODA9_GDI_XY2_BA_0 + 4 * i);
+ for (i = 0; i < 16; i++)
+ coda_write(dev, tiled_map->xy2ra_map[i],
+ CODA9_GDI_XY2_RAS_0 + 4 * i);
+ coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG);
+ for (i = 0; i < 32; i++)
+ coda_write(dev, tiled_map->rbc2axi_map[i],
+ CODA9_GDI_RBC2_AXI_0 + 4 * i);
+}
+
/*
* Mem-to-mem operations.
*/
@@ -1035,7 +1149,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
u32 stridey, height;
u32 picture_y, picture_cb, picture_cr;
- dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
if (ctx->params.rot_mode & CODA_ROT_90) {
@@ -1056,7 +1170,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
"bitstream payload: %d, skipping\n",
coda_get_bitstream_payload(ctx));
- schedule_work(&ctx->skip_run);
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return -EAGAIN;
}
@@ -1065,13 +1179,16 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
int ret = coda_start_decoding(ctx);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
- schedule_work(&ctx->skip_run);
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return -EAGAIN;
} else {
ctx->initialized = 1;
}
}
+ if (dev->devtype->product == CODA_960)
+ coda_set_gdi_regs(ctx);
+
/* Set rotator output */
picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
@@ -1082,10 +1199,26 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
picture_cb = picture_y + stridey * height;
picture_cr = picture_cb + stridey / 2 * height / 2;
}
- coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
- coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
- coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
- coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+
+ if (dev->devtype->product == CODA_960) {
+ /*
+ * The CODA960 seems to have an internal list of buffers with
+ * 64 entries that includes the registered frame buffers as
+ * well as the rotator buffer output.
+ * ROT_INDEX needs to be < 0x40, but > ctx->num_internal_frames.
+ */
+ coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
+ CODA9_CMD_DEC_PIC_ROT_INDEX);
+ coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
+ coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
+ coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
+ coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
+ } else {
+ coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
+ coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
+ coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
+ coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+ }
coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
CODA_CMD_DEC_PIC_ROT_MODE);
@@ -1095,6 +1228,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
case CODA_7541:
coda_write(dev, CODA_PRE_SCAN_EN, CODA_CMD_DEC_PIC_OPTION);
break;
+ case CODA_960:
+ coda_write(dev, (1 << 10), CODA_CMD_DEC_PIC_OPTION); /* 'hardcode to use interrupt disable mode'? */
+ break;
}
coda_write(dev, 0, CODA_CMD_DEC_PIC_SKIP_NUM);
@@ -1116,8 +1252,8 @@ static void coda_prepare_encode(struct coda_ctx *ctx)
u32 pic_stream_buffer_addr, pic_stream_buffer_size;
u32 dst_fourcc;
- src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
- dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
dst_fourcc = q_data_dst->fourcc;
@@ -1139,6 +1275,9 @@ static void coda_prepare_encode(struct coda_ctx *ctx)
src_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
}
+ if (dev->devtype->product == CODA_960)
+ coda_set_gdi_regs(ctx);
+
/*
* Copy headers at the beginning of the first frame for H.264 only.
* In MPEG4 they are already copied by the coda.
@@ -1205,51 +1344,93 @@ static void coda_prepare_encode(struct coda_ctx *ctx)
switch (q_data_src->fourcc) {
case V4L2_PIX_FMT_YVU420:
/* Switch Cb and Cr for YVU420 format */
- picture_cr = picture_y + q_data_src->width * q_data_src->height;
- picture_cb = picture_cr + q_data_src->width / 2 *
+ picture_cr = picture_y + q_data_src->bytesperline *
+ q_data_src->height;
+ picture_cb = picture_cr + q_data_src->bytesperline / 2 *
q_data_src->height / 2;
break;
case V4L2_PIX_FMT_YUV420:
default:
- picture_cb = picture_y + q_data_src->width * q_data_src->height;
- picture_cr = picture_cb + q_data_src->width / 2 *
+ picture_cb = picture_y + q_data_src->bytesperline *
+ q_data_src->height;
+ picture_cr = picture_cb + q_data_src->bytesperline / 2 *
q_data_src->height / 2;
break;
}
- coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
- coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
- coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+ if (dev->devtype->product == CODA_960) {
+ coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
+ coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
+ coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
+
+ coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
+ coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
+ coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
+ } else {
+ coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
+ coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
+ coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+ }
coda_write(dev, force_ipicture << 1 & 0x2,
CODA_CMD_ENC_PIC_OPTION);
coda_write(dev, pic_stream_buffer_addr, CODA_CMD_ENC_PIC_BB_START);
coda_write(dev, pic_stream_buffer_size / 1024,
CODA_CMD_ENC_PIC_BB_SIZE);
+
+ if (!ctx->streamon_out) {
+ /* After streamoff on the output side, set the stream end flag */
+ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+ coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
+ }
}
static void coda_device_run(void *m2m_priv)
{
struct coda_ctx *ctx = m2m_priv;
struct coda_dev *dev = ctx->dev;
+
+ queue_work(dev->workqueue, &ctx->pic_run_work);
+}
+
+static void coda_free_framebuffers(struct coda_ctx *ctx);
+static void coda_free_context_buffers(struct coda_ctx *ctx);
+
+static void coda_seq_end_work(struct work_struct *work)
+{
+ struct coda_ctx *ctx = container_of(work, struct coda_ctx, seq_end_work);
+ struct coda_dev *dev = ctx->dev;
+
+ mutex_lock(&ctx->buffer_mutex);
+ mutex_lock(&dev->coda_mutex);
+
+ v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
+ "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__);
+ if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
+ v4l2_err(&dev->v4l2_dev,
+ "CODA_COMMAND_SEQ_END failed\n");
+ }
+
+ kfifo_init(&ctx->bitstream_fifo,
+ ctx->bitstream.vaddr, ctx->bitstream.size);
+
+ coda_free_framebuffers(ctx);
+ coda_free_context_buffers(ctx);
+
+ mutex_unlock(&dev->coda_mutex);
+ mutex_unlock(&ctx->buffer_mutex);
+}
+
+static void coda_finish_decode(struct coda_ctx *ctx);
+static void coda_finish_encode(struct coda_ctx *ctx);
+
+static void coda_pic_run_work(struct work_struct *work)
+{
+ struct coda_ctx *ctx = container_of(work, struct coda_ctx, pic_run_work);
+ struct coda_dev *dev = ctx->dev;
int ret;
mutex_lock(&ctx->buffer_mutex);
-
- /*
- * If streamoff dequeued all buffers before we could get the lock,
- * just bail out immediately.
- */
- if ((!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) &&
- ctx->inst_type != CODA_INST_DECODER) ||
- !v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
- v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
- "%d: device_run without buffers\n", ctx->idx);
- mutex_unlock(&ctx->buffer_mutex);
- schedule_work(&ctx->skip_run);
- return;
- }
-
mutex_lock(&dev->coda_mutex);
if (ctx->inst_type == CODA_INST_DECODER) {
@@ -1268,12 +1449,30 @@ static void coda_device_run(void *m2m_priv)
coda_write(dev, ctx->iram_info.axi_sram_use,
CODA7_REG_BIT_AXI_SRAM_USE);
- /* 1 second timeout in case CODA locks up */
- schedule_delayed_work(&dev->timeout, HZ);
-
if (ctx->inst_type == CODA_INST_DECODER)
coda_kfifo_sync_to_device_full(ctx);
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
+
+ if (!wait_for_completion_timeout(&ctx->completion, msecs_to_jiffies(1000))) {
+ dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout\n");
+
+ ctx->hold = true;
+
+ coda_hw_reset(ctx);
+ } else if (!ctx->aborting) {
+ if (ctx->inst_type == CODA_INST_DECODER)
+ coda_finish_decode(ctx);
+ else
+ coda_finish_encode(ctx);
+ }
+
+ if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
+ queue_work(dev->workqueue, &ctx->seq_end_work);
+
+ mutex_unlock(&dev->coda_mutex);
+ mutex_unlock(&ctx->buffer_mutex);
+
+ v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
}
static int coda_job_ready(void *m2m_priv)
@@ -1285,20 +1484,20 @@ static int coda_job_ready(void *m2m_priv)
* and 1 frame are needed. In the decoder case,
* the compressed frame can be in the bitstream.
*/
- if (!v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) &&
+ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
ctx->inst_type != CODA_INST_DECODER) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"not ready: not enough video buffers.\n");
return 0;
}
- if (!v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx)) {
+ if (!v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"not ready: not enough video capture buffers.\n");
return 0;
}
- if (ctx->prescan_failed ||
+ if (ctx->hold ||
((ctx->inst_type == CODA_INST_DECODER) &&
(coda_get_bitstream_payload(ctx) < 512) &&
!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
@@ -1351,6 +1550,32 @@ static struct v4l2_m2m_ops coda_m2m_ops = {
.unlock = coda_unlock,
};
+static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
+{
+ struct gdi_tiled_map *tiled_map = &ctx->tiled_map;
+ int luma_map, chro_map, i;
+
+ memset(tiled_map, 0, sizeof(*tiled_map));
+
+ luma_map = 64;
+ chro_map = 64;
+ tiled_map->map_type = tiled_map_type;
+ for (i = 0; i < 16; i++)
+ tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map;
+ for (i = 0; i < 4; i++)
+ tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map;
+ for (i = 0; i < 16; i++)
+ tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map;
+
+ if (tiled_map_type == GDI_LINEAR_FRAME_MAP) {
+ tiled_map->xy2rbc_config = 0;
+ } else {
+ dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n",
+ tiled_map_type);
+ return;
+ }
+}
+
static void set_default_params(struct coda_ctx *ctx)
{
int max_w;
@@ -1370,10 +1595,19 @@ static void set_default_params(struct coda_ctx *ctx)
ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc;
ctx->q_data[V4L2_M2M_SRC].width = max_w;
ctx->q_data[V4L2_M2M_SRC].height = max_h;
+ ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
ctx->q_data[V4L2_M2M_DST].width = max_w;
ctx->q_data[V4L2_M2M_DST].height = max_h;
+ ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+ ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
+ ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
+ ctx->q_data[V4L2_M2M_DST].rect.width = max_w;
+ ctx->q_data[V4L2_M2M_DST].rect.height = max_h;
+
+ if (ctx->dev->devtype->product == CODA_960)
+ coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP);
}
/*
@@ -1423,6 +1657,7 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
static void coda_buf_queue(struct vb2_buffer *vb)
{
struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct coda_dev *dev = ctx->dev;
struct coda_q_data *q_data;
q_data = get_q_data(ctx, vb->vb2_queue->type);
@@ -1437,29 +1672,24 @@ static void coda_buf_queue(struct vb2_buffer *vb)
* For backwards compatibility, queuing an empty buffer marks
* the stream end
*/
- if (vb2_get_plane_payload(vb, 0) == 0)
+ if (vb2_get_plane_payload(vb, 0) == 0) {
ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
+ if ((dev->devtype->product == CODA_960) &&
+ coda_isbusy(dev) &&
+ (ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX))) {
+ /* if this decoder instance is running, set the stream end flag */
+ coda_write(dev, ctx->bit_stream_param, CODA_REG_BIT_BIT_STREAM_PARAM);
+ }
+ }
mutex_lock(&ctx->bitstream_mutex);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
coda_fill_bitstream(ctx);
mutex_unlock(&ctx->bitstream_mutex);
} else {
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
}
-static void coda_wait_prepare(struct vb2_queue *q)
-{
- struct coda_ctx *ctx = vb2_get_drv_priv(q);
- coda_unlock(ctx);
-}
-
-static void coda_wait_finish(struct vb2_queue *q)
-{
- struct coda_ctx *ctx = vb2_get_drv_priv(q);
- coda_lock(ctx);
-}
-
static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
{
struct coda_dev *dev = ctx->dev;
@@ -1472,7 +1702,8 @@ static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
}
static int coda_alloc_aux_buf(struct coda_dev *dev,
- struct coda_aux_buf *buf, size_t size)
+ struct coda_aux_buf *buf, size_t size,
+ const char *name, struct dentry *parent)
{
buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
GFP_KERNEL);
@@ -1481,13 +1712,23 @@ static int coda_alloc_aux_buf(struct coda_dev *dev,
buf->size = size;
+ if (name && parent) {
+ buf->blob.data = buf->vaddr;
+ buf->blob.size = size;
+ buf->dentry = debugfs_create_blob(name, 0644, parent, &buf->blob);
+ if (!buf->dentry)
+ dev_warn(&dev->plat_dev->dev,
+ "failed to create debugfs entry %s\n", name);
+ }
+
return 0;
}
static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
- struct coda_aux_buf *buf, size_t size)
+ struct coda_aux_buf *buf, size_t size,
+ const char *name)
{
- return coda_alloc_aux_buf(ctx->dev, buf, size);
+ return coda_alloc_aux_buf(ctx->dev, buf, size, name, ctx->debugfs_entry);
}
static void coda_free_aux_buf(struct coda_dev *dev,
@@ -1499,6 +1740,7 @@ static void coda_free_aux_buf(struct coda_dev *dev,
buf->vaddr = NULL;
buf->size = 0;
}
+ debugfs_remove(buf->dentry);
}
static void coda_free_framebuffers(struct coda_ctx *ctx)
@@ -1512,25 +1754,35 @@ static void coda_free_framebuffers(struct coda_ctx *ctx)
static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
{
struct coda_dev *dev = ctx->dev;
- int height = q_data->height;
+ int width, height;
dma_addr_t paddr;
int ysize;
int ret;
int i;
- if (ctx->codec && ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
- height = round_up(height, 16);
- ysize = round_up(q_data->width, 8) * height;
+ if (ctx->codec && (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 ||
+ ctx->codec->dst_fourcc == V4L2_PIX_FMT_H264)) {
+ width = round_up(q_data->width, 16);
+ height = round_up(q_data->height, 16);
+ } else {
+ width = round_up(q_data->width, 8);
+ height = q_data->height;
+ }
+ ysize = width * height;
/* Allocate frame buffers */
for (i = 0; i < ctx->num_internal_frames; i++) {
size_t size;
+ char *name;
- size = q_data->sizeimage;
+ size = ysize + ysize / 2;
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
dev->devtype->product != CODA_DX6)
- ctx->internal_frames[i].size += ysize/4;
- ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], size);
+ size += ysize / 4;
+ name = kasprintf(GFP_KERNEL, "fb%d", i);
+ ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i],
+ size, name);
+ kfree(name);
if (ret < 0) {
coda_free_framebuffers(ctx);
return ret;
@@ -1579,23 +1831,48 @@ static int coda_h264_padding(int size, char *p)
return nal_size;
}
+static phys_addr_t coda_iram_alloc(struct coda_iram_info *iram, size_t size)
+{
+ phys_addr_t ret;
+
+ size = round_up(size, 1024);
+ if (size > iram->remaining)
+ return 0;
+ iram->remaining -= size;
+
+ ret = iram->next_paddr;
+ iram->next_paddr += size;
+
+ return ret;
+}
+
static void coda_setup_iram(struct coda_ctx *ctx)
{
struct coda_iram_info *iram_info = &ctx->iram_info;
struct coda_dev *dev = ctx->dev;
- int ipacdc_size;
- int bitram_size;
- int dbk_size;
- int ovl_size;
int mb_width;
- int me_size;
- int size;
+ int dbk_bits;
+ int bit_bits;
+ int ip_bits;
memset(iram_info, 0, sizeof(*iram_info));
- size = dev->iram_size;
+ iram_info->next_paddr = dev->iram.paddr;
+ iram_info->remaining = dev->iram.size;
- if (dev->devtype->product == CODA_DX6)
+ switch (dev->devtype->product) {
+ case CODA_7541:
+ dbk_bits = CODA7_USE_HOST_DBK_ENABLE | CODA7_USE_DBK_ENABLE;
+ bit_bits = CODA7_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+ ip_bits = CODA7_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+ break;
+ case CODA_960:
+ dbk_bits = CODA9_USE_HOST_DBK_ENABLE | CODA9_USE_DBK_ENABLE;
+ bit_bits = CODA9_USE_HOST_BIT_ENABLE | CODA7_USE_BIT_ENABLE;
+ ip_bits = CODA9_USE_HOST_IP_ENABLE | CODA7_USE_IP_ENABLE;
+ break;
+ default: /* CODA_DX6 */
return;
+ }
if (ctx->inst_type == CODA_INST_ENCODER) {
struct coda_q_data *q_data_src;
@@ -1604,111 +1881,63 @@ static void coda_setup_iram(struct coda_ctx *ctx)
mb_width = DIV_ROUND_UP(q_data_src->width, 16);
/* Prioritize in case IRAM is too small for everything */
- me_size = round_up(round_up(q_data_src->width, 16) * 36 + 2048,
- 1024);
- iram_info->search_ram_size = me_size;
- if (size >= iram_info->search_ram_size) {
- if (dev->devtype->product == CODA_7541)
- iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE;
- iram_info->search_ram_paddr = dev->iram_paddr;
- size -= iram_info->search_ram_size;
- } else {
- pr_err("IRAM is smaller than the search ram size\n");
- goto out;
+ if (dev->devtype->product == CODA_7541) {
+ iram_info->search_ram_size = round_up(mb_width * 16 *
+ 36 + 2048, 1024);
+ iram_info->search_ram_paddr = coda_iram_alloc(iram_info,
+ iram_info->search_ram_size);
+ if (!iram_info->search_ram_paddr) {
+ pr_err("IRAM is smaller than the search ram size\n");
+ goto out;
+ }
+ iram_info->axi_sram_use |= CODA7_USE_HOST_ME_ENABLE |
+ CODA7_USE_ME_ENABLE;
}
/* Only H.264BP and H.263P3 are considered */
- dbk_size = round_up(128 * mb_width, 1024);
- if (size >= dbk_size) {
- iram_info->axi_sram_use |= CODA7_USE_HOST_DBK_ENABLE;
- iram_info->buf_dbk_y_use = dev->iram_paddr +
- iram_info->search_ram_size;
- iram_info->buf_dbk_c_use = iram_info->buf_dbk_y_use +
- dbk_size / 2;
- size -= dbk_size;
- } else {
+ iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 64 * mb_width);
+ iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 64 * mb_width);
+ if (!iram_info->buf_dbk_c_use)
goto out;
- }
+ iram_info->axi_sram_use |= dbk_bits;
- bitram_size = round_up(128 * mb_width, 1024);
- if (size >= bitram_size) {
- iram_info->axi_sram_use |= CODA7_USE_HOST_BIT_ENABLE;
- iram_info->buf_bit_use = iram_info->buf_dbk_c_use +
- dbk_size / 2;
- size -= bitram_size;
- } else {
+ iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
+ if (!iram_info->buf_bit_use)
goto out;
- }
+ iram_info->axi_sram_use |= bit_bits;
- ipacdc_size = round_up(128 * mb_width, 1024);
- if (size >= ipacdc_size) {
- iram_info->axi_sram_use |= CODA7_USE_HOST_IP_ENABLE;
- iram_info->buf_ip_ac_dc_use = iram_info->buf_bit_use +
- bitram_size;
- size -= ipacdc_size;
- }
+ iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
+ if (!iram_info->buf_ip_ac_dc_use)
+ goto out;
+ iram_info->axi_sram_use |= ip_bits;
/* OVL and BTP disabled for encoder */
} else if (ctx->inst_type == CODA_INST_DECODER) {
struct coda_q_data *q_data_dst;
- int mb_height;
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
mb_width = DIV_ROUND_UP(q_data_dst->width, 16);
- mb_height = DIV_ROUND_UP(q_data_dst->height, 16);
- dbk_size = round_up(256 * mb_width, 1024);
- if (size >= dbk_size) {
- iram_info->axi_sram_use |= CODA7_USE_HOST_DBK_ENABLE;
- iram_info->buf_dbk_y_use = dev->iram_paddr;
- iram_info->buf_dbk_c_use = dev->iram_paddr +
- dbk_size / 2;
- size -= dbk_size;
- } else {
+ iram_info->buf_dbk_y_use = coda_iram_alloc(iram_info, 128 * mb_width);
+ iram_info->buf_dbk_c_use = coda_iram_alloc(iram_info, 128 * mb_width);
+ if (!iram_info->buf_dbk_c_use)
goto out;
- }
+ iram_info->axi_sram_use |= dbk_bits;
- bitram_size = round_up(128 * mb_width, 1024);
- if (size >= bitram_size) {
- iram_info->axi_sram_use |= CODA7_USE_HOST_BIT_ENABLE;
- iram_info->buf_bit_use = iram_info->buf_dbk_c_use +
- dbk_size / 2;
- size -= bitram_size;
- } else {
+ iram_info->buf_bit_use = coda_iram_alloc(iram_info, 128 * mb_width);
+ if (!iram_info->buf_bit_use)
goto out;
- }
+ iram_info->axi_sram_use |= bit_bits;
- ipacdc_size = round_up(128 * mb_width, 1024);
- if (size >= ipacdc_size) {
- iram_info->axi_sram_use |= CODA7_USE_HOST_IP_ENABLE;
- iram_info->buf_ip_ac_dc_use = iram_info->buf_bit_use +
- bitram_size;
- size -= ipacdc_size;
- } else {
+ iram_info->buf_ip_ac_dc_use = coda_iram_alloc(iram_info, 128 * mb_width);
+ if (!iram_info->buf_ip_ac_dc_use)
goto out;
- }
+ iram_info->axi_sram_use |= ip_bits;
- ovl_size = round_up(80 * mb_width, 1024);
+ /* OVL and BTP unused as there is no VC1 support yet */
}
out:
- switch (dev->devtype->product) {
- case CODA_DX6:
- break;
- case CODA_7541:
- /* i.MX53 uses secondary AXI for IRAM access */
- if (iram_info->axi_sram_use & CODA7_USE_HOST_BIT_ENABLE)
- iram_info->axi_sram_use |= CODA7_USE_BIT_ENABLE;
- if (iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE)
- iram_info->axi_sram_use |= CODA7_USE_IP_ENABLE;
- if (iram_info->axi_sram_use & CODA7_USE_HOST_DBK_ENABLE)
- iram_info->axi_sram_use |= CODA7_USE_DBK_ENABLE;
- if (iram_info->axi_sram_use & CODA7_USE_HOST_OVL_ENABLE)
- iram_info->axi_sram_use |= CODA7_USE_OVL_ENABLE;
- if (iram_info->axi_sram_use & CODA7_USE_HOST_ME_ENABLE)
- iram_info->axi_sram_use |= CODA7_USE_ME_ENABLE;
- }
-
if (!(iram_info->axi_sram_use & CODA7_USE_HOST_IP_ENABLE))
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"IRAM smaller than needed\n");
@@ -1746,13 +1975,8 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
size_t size;
int ret;
- switch (dev->devtype->product) {
- case CODA_7541:
- size = CODA7_WORK_BUF_SIZE;
- break;
- default:
+ if (dev->devtype->product == CODA_DX6)
return 0;
- }
if (ctx->psbuf.vaddr) {
v4l2_err(&dev->v4l2_dev, "psmembuf still allocated\n");
@@ -1772,7 +1996,7 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
/* worst case slice size */
size = (DIV_ROUND_UP(q_data->width, 16) *
DIV_ROUND_UP(q_data->height, 16)) * 3200 / 8 + 512;
- ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size);
+ ret = coda_alloc_context_buf(ctx, &ctx->slicebuf, size, "slicebuf");
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte slice buffer",
ctx->slicebuf.size);
@@ -1781,14 +2005,18 @@ static int coda_alloc_context_buffers(struct coda_ctx *ctx,
}
if (dev->devtype->product == CODA_7541) {
- ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE);
+ ret = coda_alloc_context_buf(ctx, &ctx->psbuf, CODA7_PS_BUF_SIZE, "psbuf");
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate psmem buffer");
goto err;
}
}
- ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size);
+ size = dev->devtype->workbuf_size;
+ if (dev->devtype->product == CODA_960 &&
+ q_data->fourcc == V4L2_PIX_FMT_H264)
+ size += CODA9_PS_SAVE_SIZE;
+ ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size, "workbuf");
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
ctx->workbuf.size);
@@ -1834,12 +2062,17 @@ static int coda_start_decoding(struct coda_ctx *ctx)
coda_write(dev, bitstream_buf, CODA_CMD_DEC_SEQ_BB_START);
coda_write(dev, bitstream_size / 1024, CODA_CMD_DEC_SEQ_BB_SIZE);
val = 0;
- if (dev->devtype->product == CODA_7541)
+ if ((dev->devtype->product == CODA_7541) ||
+ (dev->devtype->product == CODA_960))
val |= CODA_REORDER_ENABLE;
coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
ctx->params.codec_mode = ctx->codec->mode;
- ctx->params.codec_mode_aux = 0;
+ if (dev->devtype->product == CODA_960 &&
+ src_fourcc == V4L2_PIX_FMT_MPEG4)
+ ctx->params.codec_mode_aux = CODA_MP4_AUX_MPEG4;
+ else
+ ctx->params.codec_mode_aux = 0;
if (src_fourcc == V4L2_PIX_FMT_H264) {
if (dev->devtype->product == CODA_7541) {
coda_write(dev, ctx->psbuf.paddr,
@@ -1847,6 +2080,13 @@ static int coda_start_decoding(struct coda_ctx *ctx)
coda_write(dev, (CODA7_PS_BUF_SIZE / 1024),
CODA_CMD_DEC_SEQ_PS_BB_SIZE);
}
+ if (dev->devtype->product == CODA_960) {
+ coda_write(dev, 0, CODA_CMD_DEC_SEQ_X264_MV_EN);
+ coda_write(dev, 512, CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE);
+ }
+ }
+ if (dev->devtype->product != CODA_960) {
+ coda_write(dev, 0, CODA_CMD_DEC_SEQ_SRC_SIZE);
}
if (coda_command_sync(ctx, CODA_COMMAND_SEQ_INIT)) {
@@ -1888,7 +2128,7 @@ static int coda_start_decoding(struct coda_ctx *ctx)
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%s instance %d now: %dx%d\n",
__func__, ctx->idx, width, height);
- ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED) + 1;
+ ctx->num_internal_frames = coda_read(dev, CODA_RET_DEC_SEQ_FRAME_NEED);
if (ctx->num_internal_frames > CODA_MAX_FRAMEBUFFERS) {
v4l2_err(&dev->v4l2_dev,
"not enough framebuffers to decode (%d < %d)\n",
@@ -1896,6 +2136,21 @@ static int coda_start_decoding(struct coda_ctx *ctx)
return -EINVAL;
}
+ if (src_fourcc == V4L2_PIX_FMT_H264) {
+ u32 left_right;
+ u32 top_bottom;
+
+ left_right = coda_read(dev, CODA_RET_DEC_SEQ_CROP_LEFT_RIGHT);
+ top_bottom = coda_read(dev, CODA_RET_DEC_SEQ_CROP_TOP_BOTTOM);
+
+ q_data_dst->rect.left = (left_right >> 10) & 0x3ff;
+ q_data_dst->rect.top = (top_bottom >> 10) & 0x3ff;
+ q_data_dst->rect.width = width - q_data_dst->rect.left -
+ (left_right & 0x3ff);
+ q_data_dst->rect.height = height - q_data_dst->rect.top -
+ (top_bottom & 0x3ff);
+ }
+
ret = coda_alloc_framebuffers(ctx, q_data_dst, src_fourcc);
if (ret < 0)
return ret;
@@ -1918,6 +2173,20 @@ static int coda_start_decoding(struct coda_ctx *ctx)
CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
coda_write(dev, ctx->iram_info.buf_ovl_use,
CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+ if (dev->devtype->product == CODA_960)
+ coda_write(dev, ctx->iram_info.buf_btp_use,
+ CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+ }
+
+ if (dev->devtype->product == CODA_960) {
+ coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
+
+ coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
+ coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
+ 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
+ 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
+ 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
+ CODA9_CMD_SET_FRAME_CACHE_CONFIG);
}
if (src_fourcc == V4L2_PIX_FMT_H264) {
@@ -1931,8 +2200,16 @@ static int coda_start_decoding(struct coda_ctx *ctx)
int max_mb_x = 1920 / 16;
int max_mb_y = 1088 / 16;
int max_mb_num = max_mb_x * max_mb_y;
+
coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
CODA7_CMD_SET_FRAME_MAX_DEC_SIZE);
+ } else if (dev->devtype->product == CODA_960) {
+ int max_mb_x = 1920 / 16;
+ int max_mb_y = 1088 / 16;
+ int max_mb_num = max_mb_x * max_mb_y;
+
+ coda_write(dev, max_mb_num << 16 | max_mb_x << 8 | max_mb_y,
+ CODA9_CMD_SET_FRAME_MAX_DEC_SIZE);
}
if (coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF)) {
@@ -1948,34 +2225,49 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
int header_code, u8 *header, int *size)
{
struct coda_dev *dev = ctx->dev;
+ size_t bufsize;
int ret;
+ int i;
+
+ if (dev->devtype->product == CODA_960)
+ memset(vb2_plane_vaddr(buf, 0), 0, 64);
coda_write(dev, vb2_dma_contig_plane_dma_addr(buf, 0),
CODA_CMD_ENC_HEADER_BB_START);
- coda_write(dev, vb2_plane_size(buf, 0), CODA_CMD_ENC_HEADER_BB_SIZE);
+ bufsize = vb2_plane_size(buf, 0);
+ if (dev->devtype->product == CODA_960)
+ bufsize /= 1024;
+ coda_write(dev, bufsize, CODA_CMD_ENC_HEADER_BB_SIZE);
coda_write(dev, header_code, CODA_CMD_ENC_HEADER_CODE);
ret = coda_command_sync(ctx, CODA_COMMAND_ENCODE_HEADER);
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
return ret;
}
- *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
- coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+
+ if (dev->devtype->product == CODA_960) {
+ for (i = 63; i > 0; i--)
+ if (((char *)vb2_plane_vaddr(buf, 0))[i] != 0)
+ break;
+ *size = i + 1;
+ } else {
+ *size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
+ coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
+ }
memcpy(header, vb2_plane_vaddr(buf, 0), *size);
return 0;
}
+static int coda_start_encoding(struct coda_ctx *ctx);
+
static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct coda_ctx *ctx = vb2_get_drv_priv(q);
struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
- u32 bitstream_buf, bitstream_size;
struct coda_dev *dev = ctx->dev;
struct coda_q_data *q_data_src, *q_data_dst;
- struct vb2_buffer *buf;
u32 dst_fourcc;
- u32 value;
int ret = 0;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
@@ -2007,13 +2299,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
/* Allow decoder device_run with no new buffers queued */
if (ctx->inst_type == CODA_INST_DECODER)
- v4l2_m2m_set_src_buffered(ctx->m2m_ctx, true);
+ v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
ctx->gopcounter = ctx->params.gop_size - 1;
- buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
- bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- bitstream_size = q_data_dst->sizeimage;
dst_fourcc = q_data_dst->fourcc;
ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
@@ -2032,16 +2321,36 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
mutex_lock(&dev->coda_mutex);
ret = coda_start_decoding(ctx);
mutex_unlock(&dev->coda_mutex);
- if (ret == -EAGAIN) {
+ if (ret == -EAGAIN)
return 0;
- } else if (ret < 0) {
+ else if (ret < 0)
return ret;
- } else {
- ctx->initialized = 1;
- return 0;
- }
+ } else {
+ ret = coda_start_encoding(ctx);
}
+ ctx->initialized = 1;
+ return ret;
+}
+
+static int coda_start_encoding(struct coda_ctx *ctx)
+{
+ struct coda_dev *dev = ctx->dev;
+ struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
+ struct coda_q_data *q_data_src, *q_data_dst;
+ u32 bitstream_buf, bitstream_size;
+ struct vb2_buffer *buf;
+ int gamma, ret, value;
+ u32 dst_fourcc;
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ dst_fourcc = q_data_dst->fourcc;
+
+ buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ bitstream_buf = vb2_dma_contig_plane_dma_addr(buf, 0);
+ bitstream_size = q_data_dst->sizeimage;
+
if (!coda_is_initialized(dev)) {
v4l2_err(v4l2_dev, "coda is not initialized.\n");
return -EFAULT;
@@ -2057,14 +2366,23 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
CODADX6_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
break;
- default:
+ case CODA_960:
+ coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
+ /* fallthrough */
+ case CODA_7541:
coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
CODA7_STREAM_BUF_PIC_RESET, CODA_REG_BIT_STREAM_CTRL);
+ break;
}
+ value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
+ value &= ~(1 << 2 | 0x7 << 9);
+ ctx->frame_mem_ctrl = value;
+ coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
+
if (dev->devtype->product == CODA_DX6) {
/* Configure the coda */
- coda_write(dev, dev->iram_paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
+ coda_write(dev, dev->iram.paddr, CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR);
}
/* Could set rotation here if needed */
@@ -2073,7 +2391,16 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
value = (q_data_src->width & CODADX6_PICWIDTH_MASK) << CODADX6_PICWIDTH_OFFSET;
value |= (q_data_src->height & CODADX6_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
break;
- default:
+ case CODA_7541:
+ if (dst_fourcc == V4L2_PIX_FMT_H264) {
+ value = (round_up(q_data_src->width, 16) &
+ CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
+ value |= (round_up(q_data_src->height, 16) &
+ CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
+ break;
+ }
+ /* fallthrough */
+ case CODA_960:
value = (q_data_src->width & CODA7_PICWIDTH_MASK) << CODA7_PICWIDTH_OFFSET;
value |= (q_data_src->height & CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
}
@@ -2084,12 +2411,28 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
ctx->params.codec_mode = ctx->codec->mode;
switch (dst_fourcc) {
case V4L2_PIX_FMT_MPEG4:
- coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
+ if (dev->devtype->product == CODA_960)
+ coda_write(dev, CODA9_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
+ else
+ coda_write(dev, CODA_STD_MPEG4, CODA_CMD_ENC_SEQ_COD_STD);
coda_write(dev, 0, CODA_CMD_ENC_SEQ_MP4_PARA);
break;
case V4L2_PIX_FMT_H264:
- coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
- coda_write(dev, 0, CODA_CMD_ENC_SEQ_264_PARA);
+ if (dev->devtype->product == CODA_960)
+ coda_write(dev, CODA9_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
+ else
+ coda_write(dev, CODA_STD_H264, CODA_CMD_ENC_SEQ_COD_STD);
+ if (ctx->params.h264_deblk_enabled) {
+ value = ((ctx->params.h264_deblk_alpha &
+ CODA_264PARAM_DEBLKFILTEROFFSETALPHA_MASK) <<
+ CODA_264PARAM_DEBLKFILTEROFFSETALPHA_OFFSET) |
+ ((ctx->params.h264_deblk_beta &
+ CODA_264PARAM_DEBLKFILTEROFFSETBETA_MASK) <<
+ CODA_264PARAM_DEBLKFILTEROFFSETBETA_OFFSET);
+ } else {
+ value = 1 << CODA_264PARAM_DISABLEDEBLK_OFFSET;
+ }
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
break;
default:
v4l2_err(v4l2_dev,
@@ -2121,42 +2464,75 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
/* Rate control enabled */
value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET;
value |= 1 & CODA_RATECONTROL_ENABLE_MASK;
+ if (dev->devtype->product == CODA_960)
+ value |= BIT(31); /* disable autoskip */
} else {
value = 0;
}
coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA);
coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE);
- coda_write(dev, 0, CODA_CMD_ENC_SEQ_INTRA_REFRESH);
+ coda_write(dev, ctx->params.intra_refresh,
+ CODA_CMD_ENC_SEQ_INTRA_REFRESH);
coda_write(dev, bitstream_buf, CODA_CMD_ENC_SEQ_BB_START);
coda_write(dev, bitstream_size / 1024, CODA_CMD_ENC_SEQ_BB_SIZE);
- /* set default gamma */
- value = (CODA_DEFAULT_GAMMA & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET;
- coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_GAMMA);
- if (CODA_DEFAULT_GAMMA > 0) {
- if (dev->devtype->product == CODA_DX6)
- value = 1 << CODADX6_OPTION_GAMMA_OFFSET;
- else
- value = 1 << CODA7_OPTION_GAMMA_OFFSET;
+ value = 0;
+ if (dev->devtype->product == CODA_960)
+ gamma = CODA9_DEFAULT_GAMMA;
+ else
+ gamma = CODA_DEFAULT_GAMMA;
+ if (gamma > 0) {
+ coda_write(dev, (gamma & CODA_GAMMA_MASK) << CODA_GAMMA_OFFSET,
+ CODA_CMD_ENC_SEQ_RC_GAMMA);
+ }
+
+ if (ctx->params.h264_min_qp || ctx->params.h264_max_qp) {
+ coda_write(dev,
+ ctx->params.h264_min_qp << CODA_QPMIN_OFFSET |
+ ctx->params.h264_max_qp << CODA_QPMAX_OFFSET,
+ CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX);
+ }
+ if (dev->devtype->product == CODA_960) {
+ if (ctx->params.h264_max_qp)
+ value |= 1 << CODA9_OPTION_RCQPMAX_OFFSET;
+ if (CODA_DEFAULT_GAMMA > 0)
+ value |= 1 << CODA9_OPTION_GAMMA_OFFSET;
} else {
- value = 0;
+ if (CODA_DEFAULT_GAMMA > 0) {
+ if (dev->devtype->product == CODA_DX6)
+ value |= 1 << CODADX6_OPTION_GAMMA_OFFSET;
+ else
+ value |= 1 << CODA7_OPTION_GAMMA_OFFSET;
+ }
+ if (ctx->params.h264_min_qp)
+ value |= 1 << CODA7_OPTION_RCQPMIN_OFFSET;
+ if (ctx->params.h264_max_qp)
+ value |= 1 << CODA7_OPTION_RCQPMAX_OFFSET;
}
coda_write(dev, value, CODA_CMD_ENC_SEQ_OPTION);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE);
+
coda_setup_iram(ctx);
if (dst_fourcc == V4L2_PIX_FMT_H264) {
- if (dev->devtype->product == CODA_DX6) {
+ switch (dev->devtype->product) {
+ case CODA_DX6:
value = FMO_SLICE_SAVE_BUF_SIZE << 7;
coda_write(dev, value, CODADX6_CMD_ENC_SEQ_FMO);
- } else {
+ break;
+ case CODA_7541:
coda_write(dev, ctx->iram_info.search_ram_paddr,
CODA7_CMD_ENC_SEQ_SEARCH_BASE);
coda_write(dev, ctx->iram_info.search_ram_size,
CODA7_CMD_ENC_SEQ_SEARCH_SIZE);
+ break;
+ case CODA_960:
+ coda_write(dev, 0, CODA9_CMD_ENC_SEQ_ME_OPTION);
+ coda_write(dev, 0, CODA9_CMD_ENC_SEQ_INTRA_WEIGHT);
}
}
@@ -2172,7 +2548,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
goto out;
}
- ctx->num_internal_frames = 2;
+ if (dev->devtype->product == CODA_960)
+ ctx->num_internal_frames = 4;
+ else
+ ctx->num_internal_frames = 2;
ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
if (ret < 0) {
v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
@@ -2180,10 +2559,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
}
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
- coda_write(dev, round_up(q_data_src->width, 8), CODA_CMD_SET_FRAME_BUF_STRIDE);
- if (dev->devtype->product == CODA_7541)
- coda_write(dev, round_up(q_data_src->width, 8),
+ coda_write(dev, q_data_src->bytesperline,
+ CODA_CMD_SET_FRAME_BUF_STRIDE);
+ if (dev->devtype->product == CODA_7541) {
+ coda_write(dev, q_data_src->bytesperline,
CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
+ }
if (dev->devtype->product != CODA_DX6) {
coda_write(dev, ctx->iram_info.buf_bit_use,
CODA7_CMD_SET_FRAME_AXI_BIT_ADDR);
@@ -2195,7 +2576,16 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR);
coda_write(dev, ctx->iram_info.buf_ovl_use,
CODA7_CMD_SET_FRAME_AXI_OVL_ADDR);
+ if (dev->devtype->product == CODA_960) {
+ coda_write(dev, ctx->iram_info.buf_btp_use,
+ CODA9_CMD_SET_FRAME_AXI_BTP_ADDR);
+
+ /* FIXME */
+ coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A);
+ coda_write(dev, ctx->internal_frames[3].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_B);
+ }
}
+
ret = coda_command_sync(ctx, CODA_COMMAND_SET_FRAME_BUF);
if (ret < 0) {
v4l2_err(v4l2_dev, "CODA_COMMAND_SET_FRAME_BUF timeout\n");
@@ -2203,7 +2593,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
}
/* Save stream headers */
- buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
switch (dst_fourcc) {
case V4L2_PIX_FMT_H264:
/*
@@ -2279,6 +2669,17 @@ static void coda_stop_streaming(struct vb2_queue *q)
"%s: output\n", __func__);
ctx->streamon_out = 0;
+ if (ctx->inst_type == CODA_INST_DECODER &&
+ coda_isbusy(dev) && ctx->idx == coda_read(dev, CODA_REG_BIT_RUN_INDEX)) {
+ /* if this decoder instance is running, set the stream end flag */
+ if (dev->devtype->product == CODA_960) {
+ u32 val = coda_read(dev, CODA_REG_BIT_BIT_STREAM_PARAM);
+
+ val |= CODA_BIT_STREAM_END_FLAG;
+ coda_write(dev, val, CODA_REG_BIT_BIT_STREAM_PARAM);
+ ctx->bit_stream_param = val;
+ }
+ }
ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG;
ctx->isequence = 0;
@@ -2288,9 +2689,18 @@ static void coda_stop_streaming(struct vb2_queue *q)
ctx->streamon_cap = 0;
ctx->osequence = 0;
+ ctx->sequence_offset = 0;
}
if (!ctx->streamon_out && !ctx->streamon_cap) {
+ struct coda_timestamp *ts;
+
+ while (!list_empty(&ctx->timestamp_list)) {
+ ts = list_first_entry(&ctx->timestamp_list,
+ struct coda_timestamp, list);
+ list_del(&ts->list);
+ kfree(ts);
+ }
kfifo_init(&ctx->bitstream_fifo,
ctx->bitstream.vaddr, ctx->bitstream.size);
ctx->runcounter = 0;
@@ -2301,10 +2711,10 @@ static struct vb2_ops coda_qops = {
.queue_setup = coda_queue_setup,
.buf_prepare = coda_buf_prepare,
.buf_queue = coda_buf_queue,
- .wait_prepare = coda_wait_prepare,
- .wait_finish = coda_wait_finish,
.start_streaming = coda_start_streaming,
.stop_streaming = coda_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -2340,6 +2750,22 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP:
ctx->params.h264_inter_qp = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_H264_MIN_QP:
+ ctx->params.h264_min_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_MAX_QP:
+ ctx->params.h264_max_qp = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA:
+ ctx->params.h264_deblk_alpha = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA:
+ ctx->params.h264_deblk_beta = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
+ ctx->params.h264_deblk_enabled = (ctrl->val ==
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
+ break;
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP:
ctx->params.mpeg4_intra_qp = ctrl->val;
break;
@@ -2357,6 +2783,9 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
break;
+ case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
+ ctx->params.intra_refresh = ctrl->val;
+ break;
default:
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"Invalid control, id=%d, val=%d\n",
@@ -2384,9 +2813,23 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 60, 1, 16);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 1, 51, 1, 25);
+ V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP, 0, 51, 1, 25);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 1, 51, 1, 25);
+ V4L2_CID_MPEG_VIDEO_H264_P_FRAME_QP, 0, 51, 1, 25);
+ if (ctx->dev->devtype->product != CODA_960) {
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MIN_QP, 0, 51, 1, 12);
+ }
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_MAX_QP, 0, 51, 1, 51);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA, 0, 15, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_BETA, 0, 15, 1, 0);
+ v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED, 0x0,
+ V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP, 1, 31, 1, 2);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@@ -2404,6 +2847,8 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME,
(1 << V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE),
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0);
if (ctx->ctrls.error) {
v4l2_err(&ctx->dev->v4l2_dev, "control initialization error (%d)",
@@ -2427,6 +2872,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &coda_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->dev->dev_mutex;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -2439,6 +2885,7 @@ static int coda_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &coda_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->dev->dev_mutex;
return vb2_queue_init(dst_vq);
}
@@ -2458,6 +2905,7 @@ static int coda_open(struct file *file)
{
struct coda_dev *dev = video_drvdata(file);
struct coda_ctx *ctx = NULL;
+ char *name;
int ret;
int idx;
@@ -2472,7 +2920,13 @@ static int coda_open(struct file *file)
}
set_bit(idx, &dev->instance_mask);
- INIT_WORK(&ctx->skip_run, coda_skip_run);
+ name = kasprintf(GFP_KERNEL, "context%d", idx);
+ ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
+ kfree(name);
+
+ init_completion(&ctx->completion);
+ INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
+ INIT_WORK(&ctx->seq_end_work, coda_seq_end_work);
v4l2_fh_init(&ctx->fh, video_devdata(file));
file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh);
@@ -2480,12 +2934,20 @@ static int coda_open(struct file *file)
ctx->idx = idx;
switch (dev->devtype->product) {
case CODA_7541:
+ case CODA_960:
ctx->reg_idx = 0;
break;
default:
ctx->reg_idx = idx;
}
+ /* Power up and upload firmware if necessary */
+ ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "failed to power up: %d\n", ret);
+ goto err_pm_get;
+ }
+
ret = clk_prepare_enable(dev->clk_per);
if (ret)
goto err_clk_per;
@@ -2495,15 +2957,16 @@ static int coda_open(struct file *file)
goto err_clk_ahb;
set_default_params(ctx);
- ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
&coda_queue_init);
- if (IS_ERR(ctx->m2m_ctx)) {
- ret = PTR_ERR(ctx->m2m_ctx);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
v4l2_err(&dev->v4l2_dev, "%s return error (%d)\n",
__func__, ret);
goto err_ctx_init;
}
+
ret = coda_ctrls_setup(ctx);
if (ret) {
v4l2_err(&dev->v4l2_dev, "failed to setup coda controls\n");
@@ -2512,7 +2975,8 @@ static int coda_open(struct file *file)
ctx->fh.ctrl_handler = &ctx->ctrls;
- ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE);
+ ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
+ "parabuf");
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
goto err_dma_alloc;
@@ -2530,6 +2994,7 @@ static int coda_open(struct file *file)
ctx->bitstream.vaddr, ctx->bitstream.size);
mutex_init(&ctx->bitstream_mutex);
mutex_init(&ctx->buffer_mutex);
+ INIT_LIST_HEAD(&ctx->timestamp_list);
coda_lock(ctx);
list_add(&ctx->list, &dev->instances);
@@ -2548,12 +3013,14 @@ err_dma_writecombine:
err_dma_alloc:
v4l2_ctrl_handler_free(&ctx->ctrls);
err_ctrls_setup:
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
err_ctx_init:
clk_disable_unprepare(dev->clk_ahb);
err_clk_ahb:
clk_disable_unprepare(dev->clk_per);
err_clk_per:
+ pm_runtime_put_sync(&dev->plat_dev->dev);
+err_pm_get:
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask);
@@ -2570,20 +3037,16 @@ static int coda_release(struct file *file)
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
ctx);
+ debugfs_remove_recursive(ctx->debugfs_entry);
+
/* If this instance is running, call .job_abort and wait for it to end */
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
/* In case the instance was not running, we still need to call SEQ_END */
- mutex_lock(&dev->coda_mutex);
- v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
- "%s: sent command 'SEQ_END' to coda\n", __func__);
- if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
- v4l2_err(&dev->v4l2_dev,
- "CODA_COMMAND_SEQ_END failed\n");
- mutex_unlock(&dev->coda_mutex);
- return -ETIMEDOUT;
+ if (ctx->initialized) {
+ queue_work(dev->workqueue, &ctx->seq_end_work);
+ flush_work(&ctx->seq_end_work);
}
- mutex_unlock(&dev->coda_mutex);
coda_free_framebuffers(ctx);
@@ -2601,6 +3064,7 @@ static int coda_release(struct file *file)
v4l2_ctrl_handler_free(&ctx->ctrls);
clk_disable_unprepare(dev->clk_ahb);
clk_disable_unprepare(dev->clk_per);
+ pm_runtime_put_sync(&dev->plat_dev->dev);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
clear_bit(ctx->idx, &dev->instance_mask);
@@ -2609,32 +3073,13 @@ static int coda_release(struct file *file)
return 0;
}
-static unsigned int coda_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct coda_ctx *ctx = fh_to_ctx(file->private_data);
- int ret;
-
- coda_lock(ctx);
- ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
- coda_unlock(ctx);
- return ret;
-}
-
-static int coda_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct coda_ctx *ctx = fh_to_ctx(file->private_data);
-
- return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-}
-
static const struct v4l2_file_operations coda_fops = {
.owner = THIS_MODULE,
.open = coda_open,
.release = coda_release,
- .poll = coda_poll,
+ .poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = coda_mmap,
+ .mmap = v4l2_m2m_fop_mmap,
};
static void coda_finish_decode(struct coda_ctx *ctx)
@@ -2643,14 +3088,16 @@ static void coda_finish_decode(struct coda_ctx *ctx)
struct coda_q_data *q_data_src;
struct coda_q_data *q_data_dst;
struct vb2_buffer *dst_buf;
+ struct coda_timestamp *ts;
int width, height;
int decoded_idx;
int display_idx;
u32 src_fourcc;
int success;
+ u32 err_mb;
u32 val;
- dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
/* Update kfifo out pointer from coda bitstream read pointer */
coda_kfifo_sync_from_device(ctx);
@@ -2693,19 +3140,34 @@ static void coda_finish_decode(struct coda_ctx *ctx)
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- val = coda_read(dev, CODA_RET_DEC_PIC_TYPE);
- if ((val & 0x7) == 0) {
- dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
- dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_PFRAME;
+ /* frame crop information */
+ if (src_fourcc == V4L2_PIX_FMT_H264) {
+ u32 left_right;
+ u32 top_bottom;
+
+ left_right = coda_read(dev, CODA_RET_DEC_PIC_CROP_LEFT_RIGHT);
+ top_bottom = coda_read(dev, CODA_RET_DEC_PIC_CROP_TOP_BOTTOM);
+
+ if (left_right == 0xffffffff && top_bottom == 0xffffffff) {
+ /* Keep current crop information */
+ } else {
+ struct v4l2_rect *rect = &q_data_dst->rect;
+
+ rect->left = left_right >> 16 & 0xffff;
+ rect->top = top_bottom >> 16 & 0xffff;
+ rect->width = width - rect->left -
+ (left_right & 0xffff);
+ rect->height = height - rect->top -
+ (top_bottom & 0xffff);
+ }
} else {
- dst_buf->v4l2_buf.flags |= V4L2_BUF_FLAG_PFRAME;
- dst_buf->v4l2_buf.flags &= ~V4L2_BUF_FLAG_KEYFRAME;
+ /* no cropping */
}
- val = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
- if (val > 0)
+ err_mb = coda_read(dev, CODA_RET_DEC_PIC_ERR_MB);
+ if (err_mb > 0)
v4l2_err(&dev->v4l2_dev,
- "errors in %d macroblocks\n", val);
+ "errors in %d macroblocks\n", err_mb);
if (dev->devtype->product == CODA_7541) {
val = coda_read(dev, CODA_RET_DEC_PIC_OPTION);
@@ -2713,7 +3175,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
/* not enough bitstream data */
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
"prescan failed: %d\n", val);
- ctx->prescan_failed = true;
+ ctx->hold = true;
return;
}
}
@@ -2741,13 +3203,38 @@ static void coda_finish_decode(struct coda_ctx *ctx)
if (decoded_idx == -1) {
/* no frame was decoded, but we might have a display frame */
- if (display_idx < 0 && ctx->display_idx < 0)
- ctx->prescan_failed = true;
+ if (display_idx >= 0 && display_idx < ctx->num_internal_frames)
+ ctx->sequence_offset++;
+ else if (ctx->display_idx < 0)
+ ctx->hold = true;
} else if (decoded_idx == -2) {
/* no frame was decoded, we still return the remaining buffers */
} else if (decoded_idx < 0 || decoded_idx >= ctx->num_internal_frames) {
v4l2_err(&dev->v4l2_dev,
"decoded frame index out of range: %d\n", decoded_idx);
+ } else {
+ ts = list_first_entry(&ctx->timestamp_list,
+ struct coda_timestamp, list);
+ list_del(&ts->list);
+ val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
+ val -= ctx->sequence_offset;
+ if (val != (ts->sequence & 0xffff)) {
+ v4l2_err(&dev->v4l2_dev,
+ "sequence number mismatch (%d(%d) != %d)\n",
+ val, ctx->sequence_offset, ts->sequence);
+ }
+ ctx->frame_timestamps[decoded_idx] = *ts;
+ kfree(ts);
+
+ val = coda_read(dev, CODA_RET_DEC_PIC_TYPE) & 0x7;
+ if (val == 0)
+ ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_KEYFRAME;
+ else if (val == 1)
+ ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_PFRAME;
+ else
+ ctx->frame_types[decoded_idx] = V4L2_BUF_FLAG_BFRAME;
+
+ ctx->frame_errors[decoded_idx] = err_mb;
}
if (display_idx == -1) {
@@ -2755,7 +3242,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
* no more frames to be decoded, but there could still
* be rotator output to dequeue
*/
- ctx->prescan_failed = true;
+ ctx->hold = true;
} else if (display_idx == -3) {
/* possibly prescan failure */
} else if (display_idx < 0 || display_idx >= ctx->num_internal_frames) {
@@ -2767,13 +3254,21 @@ static void coda_finish_decode(struct coda_ctx *ctx)
/* If a frame was copied out, return it */
if (ctx->display_idx >= 0 &&
ctx->display_idx < ctx->num_internal_frames) {
- dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
dst_buf->v4l2_buf.sequence = ctx->osequence++;
+ dst_buf->v4l2_buf.flags &= ~(V4L2_BUF_FLAG_KEYFRAME |
+ V4L2_BUF_FLAG_PFRAME |
+ V4L2_BUF_FLAG_BFRAME);
+ dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
+ ts = &ctx->frame_timestamps[ctx->display_idx];
+ dst_buf->v4l2_buf.timecode = ts->timecode;
+ dst_buf->v4l2_buf.timestamp = ts->timestamp;
+
vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
- v4l2_m2m_buf_done(dst_buf, success ? VB2_BUF_STATE_DONE :
- VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
"job finished: decoding frame (%d) (%s)\n",
@@ -2795,8 +3290,8 @@ static void coda_finish_encode(struct coda_ctx *ctx)
struct coda_dev *dev = ctx->dev;
u32 wr_ptr, start_ptr;
- src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
- dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
/* Get results from the coda */
start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
@@ -2833,6 +3328,8 @@ static void coda_finish_encode(struct coda_ctx *ctx)
dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
ctx->gopcounter--;
@@ -2851,8 +3348,6 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
struct coda_dev *dev = data;
struct coda_ctx *ctx;
- cancel_delayed_work(&dev->timeout);
-
/* read status register to attend the IRQ */
coda_read(dev, CODA_REG_BIT_INT_STATUS);
coda_write(dev, CODA_REG_BIT_INT_CLEAR_SET,
@@ -2868,7 +3363,6 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
if (ctx->aborting) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"task has been aborted\n");
- goto out;
}
if (coda_isbusy(ctx->dev)) {
@@ -2877,60 +3371,15 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
return IRQ_NONE;
}
- if (ctx->inst_type == CODA_INST_DECODER)
- coda_finish_decode(ctx);
- else
- coda_finish_encode(ctx);
-
-out:
- if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) {
- v4l2_dbg(1, coda_debug, &dev->v4l2_dev,
- "%s: sent command 'SEQ_END' to coda\n", __func__);
- if (coda_command_sync(ctx, CODA_COMMAND_SEQ_END)) {
- v4l2_err(&dev->v4l2_dev,
- "CODA_COMMAND_SEQ_END failed\n");
- }
-
- kfifo_init(&ctx->bitstream_fifo,
- ctx->bitstream.vaddr, ctx->bitstream.size);
-
- coda_free_framebuffers(ctx);
- coda_free_context_buffers(ctx);
- }
-
- mutex_unlock(&dev->coda_mutex);
- mutex_unlock(&ctx->buffer_mutex);
-
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
+ complete(&ctx->completion);
return IRQ_HANDLED;
}
-static void coda_timeout(struct work_struct *work)
-{
- struct coda_ctx *ctx;
- struct coda_dev *dev = container_of(to_delayed_work(work),
- struct coda_dev, timeout);
-
- dev_err(&dev->plat_dev->dev, "CODA PIC_RUN timeout, stopping all streams\n");
-
- mutex_lock(&dev->dev_mutex);
- list_for_each_entry(ctx, &dev->instances, list) {
- if (mutex_is_locked(&ctx->buffer_mutex))
- mutex_unlock(&ctx->buffer_mutex);
- v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
- v4l2_m2m_streamoff(NULL, ctx->m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- }
- mutex_unlock(&dev->dev_mutex);
-
- mutex_unlock(&dev->coda_mutex);
- ctx = v4l2_m2m_get_curr_priv(dev->m2m_dev);
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->m2m_ctx);
-}
-
static u32 coda_supported_firmwares[] = {
CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
+ CODA_FIRMWARE_VERNUM(CODA_960, 2, 1, 5),
};
static bool coda_firmware_supported(u32 vernum)
@@ -2945,19 +3394,21 @@ static bool coda_firmware_supported(u32 vernum)
static int coda_hw_init(struct coda_dev *dev)
{
- u16 product, major, minor, release;
u32 data;
u16 *p;
int i, ret;
ret = clk_prepare_enable(dev->clk_per);
if (ret)
- return ret;
+ goto err_clk_per;
ret = clk_prepare_enable(dev->clk_ahb);
if (ret)
goto err_clk_ahb;
+ if (dev->rstc)
+ reset_control_reset(dev->rstc);
+
/*
* Copy the first CODA_ISRAM_SIZE in the internal SRAM.
* The 16-bit chars in the code buffer are in memory access
@@ -2985,7 +3436,8 @@ static int coda_hw_init(struct coda_dev *dev)
coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
/* Tell the BIT where to find everything it needs */
- if (dev->devtype->product == CODA_7541) {
+ if (dev->devtype->product == CODA_960 ||
+ dev->devtype->product == CODA_7541) {
coda_write(dev, dev->tempbuf.paddr,
CODA_REG_BIT_TEMP_BUF_ADDR);
coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM);
@@ -3005,7 +3457,10 @@ static int coda_hw_init(struct coda_dev *dev)
default:
coda_write(dev, CODA7_STREAM_BUF_PIC_FLUSH, CODA_REG_BIT_STREAM_CTRL);
}
- coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
+ if (dev->devtype->product == CODA_960)
+ coda_write(dev, 1 << 12, CODA_REG_BIT_FRAME_MEM_CTRL);
+ else
+ coda_write(dev, 0, CODA_REG_BIT_FRAME_MEM_CTRL);
if (dev->devtype->product != CODA_DX6)
coda_write(dev, 0, CODA7_REG_BIT_AXI_SRAM_USE);
@@ -3022,17 +3477,46 @@ static int coda_hw_init(struct coda_dev *dev)
coda_write(dev, data, CODA_REG_BIT_CODE_RESET);
coda_write(dev, CODA_REG_RUN_ENABLE, CODA_REG_BIT_CODE_RUN);
- /* Load firmware */
+ clk_disable_unprepare(dev->clk_ahb);
+ clk_disable_unprepare(dev->clk_per);
+
+ return 0;
+
+err_clk_ahb:
+ clk_disable_unprepare(dev->clk_per);
+err_clk_per:
+ return ret;
+}
+
+static int coda_check_firmware(struct coda_dev *dev)
+{
+ u16 product, major, minor, release;
+ u32 data;
+ int ret;
+
+ ret = clk_prepare_enable(dev->clk_per);
+ if (ret)
+ goto err_clk_per;
+
+ ret = clk_prepare_enable(dev->clk_ahb);
+ if (ret)
+ goto err_clk_ahb;
+
coda_write(dev, 0, CODA_CMD_FIRMWARE_VERNUM);
coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
coda_write(dev, 0, CODA_REG_BIT_RUN_INDEX);
coda_write(dev, 0, CODA_REG_BIT_RUN_COD_STD);
coda_write(dev, CODA_COMMAND_FIRMWARE_GET, CODA_REG_BIT_RUN_COMMAND);
if (coda_wait_timeout(dev)) {
- clk_disable_unprepare(dev->clk_per);
- clk_disable_unprepare(dev->clk_ahb);
v4l2_err(&dev->v4l2_dev, "firmware get command error\n");
- return -EIO;
+ ret = -EIO;
+ goto err_run_cmd;
+ }
+
+ if (dev->devtype->product == CODA_960) {
+ data = coda_read(dev, CODA9_CMD_FIRMWARE_CODE_REV);
+ v4l2_info(&dev->v4l2_dev, "Firmware code revision: %d\n",
+ data);
}
/* Check we are compatible with the loaded firmware */
@@ -3066,8 +3550,11 @@ static int coda_hw_init(struct coda_dev *dev)
return 0;
+err_run_cmd:
+ clk_disable_unprepare(dev->clk_ahb);
err_clk_ahb:
clk_disable_unprepare(dev->clk_per);
+err_clk_per:
return ret;
}
@@ -3083,7 +3570,8 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
}
/* allocate auxiliary per-device code buffer for the BIT processor */
- ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size);
+ ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size, "codebuf",
+ dev->debugfs_root);
if (ret < 0) {
dev_err(&pdev->dev, "failed to allocate code buffer\n");
return;
@@ -3093,10 +3581,37 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
memcpy(dev->codebuf.vaddr, fw->data, fw->size);
release_firmware(fw);
- ret = coda_hw_init(dev);
- if (ret) {
- v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
- return;
+ if (pm_runtime_enabled(&pdev->dev) && pdev->dev.pm_domain) {
+ /*
+ * Enabling power temporarily will cause coda_hw_init to be
+ * called via coda_runtime_resume by the pm domain.
+ */
+ ret = pm_runtime_get_sync(&dev->plat_dev->dev);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "failed to power on: %d\n",
+ ret);
+ return;
+ }
+
+ ret = coda_check_firmware(dev);
+ if (ret < 0)
+ return;
+
+ pm_runtime_put_sync(&dev->plat_dev->dev);
+ } else {
+ /*
+ * If runtime pm is disabled or pm_domain is not set,
+ * initialize once manually.
+ */
+ ret = coda_hw_init(dev);
+ if (ret < 0) {
+ v4l2_err(&dev->v4l2_dev, "HW initialization failed\n");
+ return;
+ }
+
+ ret = coda_check_firmware(dev);
+ if (ret < 0)
+ return;
}
dev->vfd.fops = &coda_fops,
@@ -3150,20 +3665,45 @@ static int coda_firmware_request(struct coda_dev *dev)
enum coda_platform {
CODA_IMX27,
CODA_IMX53,
+ CODA_IMX6Q,
+ CODA_IMX6DL,
};
static const struct coda_devtype coda_devdata[] = {
[CODA_IMX27] = {
- .firmware = "v4l-codadx6-imx27.bin",
- .product = CODA_DX6,
- .codecs = codadx6_codecs,
- .num_codecs = ARRAY_SIZE(codadx6_codecs),
+ .firmware = "v4l-codadx6-imx27.bin",
+ .product = CODA_DX6,
+ .codecs = codadx6_codecs,
+ .num_codecs = ARRAY_SIZE(codadx6_codecs),
+ .workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
+ .iram_size = 0xb000,
},
[CODA_IMX53] = {
- .firmware = "v4l-coda7541-imx53.bin",
- .product = CODA_7541,
- .codecs = coda7_codecs,
- .num_codecs = ARRAY_SIZE(coda7_codecs),
+ .firmware = "v4l-coda7541-imx53.bin",
+ .product = CODA_7541,
+ .codecs = coda7_codecs,
+ .num_codecs = ARRAY_SIZE(coda7_codecs),
+ .workbuf_size = 128 * 1024,
+ .tempbuf_size = 304 * 1024,
+ .iram_size = 0x14000,
+ },
+ [CODA_IMX6Q] = {
+ .firmware = "v4l-coda960-imx6q.bin",
+ .product = CODA_960,
+ .codecs = coda9_codecs,
+ .num_codecs = ARRAY_SIZE(coda9_codecs),
+ .workbuf_size = 80 * 1024,
+ .tempbuf_size = 204 * 1024,
+ .iram_size = 0x21000,
+ },
+ [CODA_IMX6DL] = {
+ .firmware = "v4l-coda960-imx6dl.bin",
+ .product = CODA_960,
+ .codecs = coda9_codecs,
+ .num_codecs = ARRAY_SIZE(coda9_codecs),
+ .workbuf_size = 80 * 1024,
+ .tempbuf_size = 204 * 1024,
+ .iram_size = 0x20000,
},
};
@@ -3178,6 +3718,8 @@ MODULE_DEVICE_TABLE(platform, coda_platform_ids);
static const struct of_device_id coda_dt_ids[] = {
{ .compatible = "fsl,imx27-vpu", .data = &coda_devdata[CODA_IMX27] },
{ .compatible = "fsl,imx53-vpu", .data = &coda_devdata[CODA_IMX53] },
+ { .compatible = "fsl,imx6q-vpu", .data = &coda_devdata[CODA_IMX6Q] },
+ { .compatible = "fsl,imx6dl-vpu", .data = &coda_devdata[CODA_IMX6DL] },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, coda_dt_ids);
@@ -3204,7 +3746,6 @@ static int coda_probe(struct platform_device *pdev)
spin_lock_init(&dev->irqlock);
INIT_LIST_HEAD(&dev->instances);
- INIT_DELAYED_WORK(&dev->timeout, coda_timeout);
dev->plat_dev = pdev;
dev->clk_per = devm_clk_get(&pdev->dev, "per");
@@ -3229,13 +3770,25 @@ static int coda_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get irq resource\n");
- return -ENOENT;
+ return irq;
}
- if (devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
- IRQF_ONESHOT, dev_name(&pdev->dev), dev) < 0) {
- dev_err(&pdev->dev, "failed to request irq\n");
- return -ENOENT;
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
+ IRQF_ONESHOT, dev_name(&pdev->dev), dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
+ return ret;
+ }
+
+ dev->rstc = devm_reset_control_get_optional(&pdev->dev, NULL);
+ if (IS_ERR(dev->rstc)) {
+ ret = PTR_ERR(dev->rstc);
+ if (ret == -ENOENT || ret == -ENOSYS) {
+ dev->rstc = NULL;
+ } else {
+ dev_err(&pdev->dev, "failed get reset control: %d\n", ret);
+ return ret;
+ }
}
/* Get IRAM pool from device tree or platform data */
@@ -3266,24 +3819,26 @@ static int coda_probe(struct platform_device *pdev)
return -EINVAL;
}
+ dev->debugfs_root = debugfs_create_dir("coda", NULL);
+ if (!dev->debugfs_root)
+ dev_warn(&pdev->dev, "failed to create debugfs root\n");
+
/* allocate auxiliary per-device buffers for the BIT processor */
- switch (dev->devtype->product) {
- case CODA_DX6:
+ if (dev->devtype->product == CODA_DX6) {
ret = coda_alloc_aux_buf(dev, &dev->workbuf,
- CODADX6_WORK_BUF_SIZE);
+ dev->devtype->workbuf_size, "workbuf",
+ dev->debugfs_root);
if (ret < 0) {
dev_err(&pdev->dev, "failed to allocate work buffer\n");
v4l2_device_unregister(&dev->v4l2_dev);
return ret;
}
- break;
- case CODA_7541:
- dev->tempbuf.size = CODA7_TEMP_BUF_SIZE;
- break;
}
- if (dev->tempbuf.size) {
+
+ if (dev->devtype->tempbuf_size) {
ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
- dev->tempbuf.size);
+ dev->devtype->tempbuf_size, "tempbuf",
+ dev->debugfs_root);
if (ret < 0) {
dev_err(&pdev->dev, "failed to allocate temp buffer\n");
v4l2_device_unregister(&dev->v4l2_dev);
@@ -3291,23 +3846,29 @@ static int coda_probe(struct platform_device *pdev)
}
}
- switch (dev->devtype->product) {
- case CODA_DX6:
- dev->iram_size = CODADX6_IRAM_SIZE;
- break;
- case CODA_7541:
- dev->iram_size = CODA7_IRAM_SIZE;
- break;
- }
- dev->iram_vaddr = (unsigned long)gen_pool_dma_alloc(dev->iram_pool,
- dev->iram_size, (dma_addr_t *)&dev->iram_paddr);
- if (!dev->iram_vaddr) {
+ dev->iram.size = dev->devtype->iram_size;
+ dev->iram.vaddr = gen_pool_dma_alloc(dev->iram_pool, dev->iram.size,
+ &dev->iram.paddr);
+ if (!dev->iram.vaddr) {
dev_err(&pdev->dev, "unable to alloc iram\n");
return -ENOMEM;
}
+ dev->iram.blob.data = dev->iram.vaddr;
+ dev->iram.blob.size = dev->iram.size;
+ dev->iram.dentry = debugfs_create_blob("iram", 0644, dev->debugfs_root,
+ &dev->iram.blob);
+
+ dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
+ if (!dev->workqueue) {
+ dev_err(&pdev->dev, "unable to alloc workqueue\n");
+ return -ENOMEM;
+ }
+
platform_set_drvdata(pdev, dev);
+ pm_runtime_enable(&pdev->dev);
+
return coda_firmware_request(dev);
}
@@ -3318,17 +3879,41 @@ static int coda_remove(struct platform_device *pdev)
video_unregister_device(&dev->vfd);
if (dev->m2m_dev)
v4l2_m2m_release(dev->m2m_dev);
+ pm_runtime_disable(&pdev->dev);
if (dev->alloc_ctx)
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
v4l2_device_unregister(&dev->v4l2_dev);
- if (dev->iram_vaddr)
- gen_pool_free(dev->iram_pool, dev->iram_vaddr, dev->iram_size);
+ destroy_workqueue(dev->workqueue);
+ if (dev->iram.vaddr)
+ gen_pool_free(dev->iram_pool, (unsigned long)dev->iram.vaddr,
+ dev->iram.size);
coda_free_aux_buf(dev, &dev->codebuf);
coda_free_aux_buf(dev, &dev->tempbuf);
coda_free_aux_buf(dev, &dev->workbuf);
+ debugfs_remove_recursive(dev->debugfs_root);
return 0;
}
+#ifdef CONFIG_PM_RUNTIME
+static int coda_runtime_resume(struct device *dev)
+{
+ struct coda_dev *cdev = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (dev->pm_domain) {
+ ret = coda_hw_init(cdev);
+ if (ret)
+ v4l2_err(&cdev->v4l2_dev, "HW initialization failed\n");
+ }
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops coda_pm_ops = {
+ SET_RUNTIME_PM_OPS(NULL, coda_runtime_resume, NULL)
+};
+
static struct platform_driver coda_driver = {
.probe = coda_probe,
.remove = coda_remove,
@@ -3336,6 +3921,7 @@ static struct platform_driver coda_driver = {
.name = CODA_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(coda_dt_ids),
+ .pm = &coda_pm_ops,
},
.id_table = coda_platform_ids,
};
diff --git a/drivers/media/platform/coda.h b/drivers/media/platform/coda.h
index 4e32e2edea62..c791275e307b 100644
--- a/drivers/media/platform/coda.h
+++ b/drivers/media/platform/coda.h
@@ -27,6 +27,14 @@
#define CODA_REG_BIT_CODE_RESET 0x014
#define CODA_REG_RESET_ENABLE (1 << 0)
#define CODA_REG_BIT_CUR_PC 0x018
+#define CODA9_REG_BIT_SW_RESET 0x024
+#define CODA9_SW_RESET_BPU_CORE 0x008
+#define CODA9_SW_RESET_BPU_BUS 0x010
+#define CODA9_SW_RESET_VCE_CORE 0x020
+#define CODA9_SW_RESET_VCE_BUS 0x040
+#define CODA9_SW_RESET_GDI_CORE 0x080
+#define CODA9_SW_RESET_GDI_BUS 0x100
+#define CODA9_REG_BIT_SW_RESET_STATUS 0x034
/* Static SW registers */
#define CODA_REG_BIT_CODE_BUF_ADDR 0x100
@@ -39,9 +47,11 @@
#define CODADX6_STREAM_BUF_PIC_FLUSH (1 << 2)
#define CODA7_STREAM_BUF_DYNALLOC_EN (1 << 5)
#define CODADX6_STREAM_BUF_DYNALLOC_EN (1 << 4)
-#define CODA_STREAM_CHKDIS_OFFSET (1 << 1)
+#define CODADX6_STREAM_CHKDIS_OFFSET (1 << 1)
+#define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1)
#define CODA_STREAM_ENDIAN_SELECT (1 << 0)
#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110
+#define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2)
#define CODA_IMAGE_ENDIAN_SELECT (1 << 0)
#define CODA_REG_BIT_BIT_STREAM_PARAM 0x114
#define CODA_BIT_STREAM_END_FLAG (1 << 2)
@@ -52,13 +62,21 @@
#define CODA_REG_BIT_FRM_DIS_FLG(x) (0x150 + 4 * (x))
#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140
#define CODA7_REG_BIT_AXI_SRAM_USE 0x140
+#define CODA9_USE_HOST_BTP_ENABLE (1 << 13)
+#define CODA9_USE_HOST_OVL_ENABLE (1 << 12)
#define CODA7_USE_HOST_ME_ENABLE (1 << 11)
+#define CODA9_USE_HOST_DBK_ENABLE (3 << 10)
#define CODA7_USE_HOST_OVL_ENABLE (1 << 10)
#define CODA7_USE_HOST_DBK_ENABLE (1 << 9)
+#define CODA9_USE_HOST_IP_ENABLE (1 << 9)
#define CODA7_USE_HOST_IP_ENABLE (1 << 8)
+#define CODA9_USE_HOST_BIT_ENABLE (1 << 8)
#define CODA7_USE_HOST_BIT_ENABLE (1 << 7)
+#define CODA9_USE_BTP_ENABLE (1 << 5)
#define CODA7_USE_ME_ENABLE (1 << 4)
+#define CODA9_USE_OVL_ENABLE (1 << 4)
#define CODA7_USE_OVL_ENABLE (1 << 3)
+#define CODA9_USE_DBK_ENABLE (3 << 2)
#define CODA7_USE_DBK_ENABLE (1 << 2)
#define CODA7_USE_IP_ENABLE (1 << 1)
#define CODA7_USE_BIT_ENABLE (1 << 0)
@@ -93,6 +111,18 @@
#define CODA7_MODE_ENCODE_H264 8
#define CODA7_MODE_ENCODE_MP4 11
#define CODA7_MODE_ENCODE_MJPG 13
+#define CODA9_MODE_DECODE_H264 0
+#define CODA9_MODE_DECODE_VC1 1
+#define CODA9_MODE_DECODE_MP2 2
+#define CODA9_MODE_DECODE_MP4 3
+#define CODA9_MODE_DECODE_DV3 3
+#define CODA9_MODE_DECODE_RV 4
+#define CODA9_MODE_DECODE_AVS 5
+#define CODA9_MODE_DECODE_MJPG 6
+#define CODA9_MODE_DECODE_VPX 7
+#define CODA9_MODE_ENCODE_H264 8
+#define CODA9_MODE_ENCODE_MP4 11
+#define CODA9_MODE_ENCODE_MJPG 13
#define CODA_MODE_INVALID 0xffff
#define CODA_REG_BIT_INT_ENABLE 0x170
#define CODA_INT_INTERRUPT_ENABLE (1 << 3)
@@ -129,6 +159,7 @@
#define CODA_CMD_DEC_SEQ_SPP_CHUNK_SIZE 0x1a0
#define CODA7_RET_DEC_SEQ_ASPECT 0x1b0
+#define CODA9_RET_DEC_SEQ_BITRATE 0x1b4
#define CODA_RET_DEC_SEQ_SUCCESS 0x1c0
#define CODA_RET_DEC_SEQ_SRC_FMT 0x1c4 /* SRC_SIZE on CODA7 */
#define CODA_RET_DEC_SEQ_SRC_SIZE 0x1c4
@@ -145,13 +176,19 @@
#define CODA_RET_DEC_SEQ_FRATE_DR 0x1e8
#define CODA_RET_DEC_SEQ_JPG_PARA 0x1e4
#define CODA_RET_DEC_SEQ_JPG_THUMB_IND 0x1e8
+#define CODA9_RET_DEC_SEQ_HEADER_REPORT 0x1ec
/* Decoder Picture Run */
#define CODA_CMD_DEC_PIC_ROT_MODE 0x180
#define CODA_CMD_DEC_PIC_ROT_ADDR_Y 0x184
+#define CODA9_CMD_DEC_PIC_ROT_INDEX 0x184
#define CODA_CMD_DEC_PIC_ROT_ADDR_CB 0x188
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_Y 0x188
#define CODA_CMD_DEC_PIC_ROT_ADDR_CR 0x18c
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_CB 0x18c
#define CODA_CMD_DEC_PIC_ROT_STRIDE 0x190
+#define CODA9_CMD_DEC_PIC_ROT_ADDR_CR 0x190
+#define CODA9_CMD_DEC_PIC_ROT_STRIDE 0x1b8
#define CODA_CMD_DEC_PIC_OPTION 0x194
#define CODA_PRE_SCAN_EN (1 << 0)
@@ -183,25 +220,39 @@
#define CODA_RET_DEC_PIC_CROP_TOP_BOTTOM 0x1e4
#define CODA_RET_DEC_PIC_FRAME_NEED 0x1ec
+#define CODA9_RET_DEC_PIC_VP8_PIC_REPORT 0x1e8
+#define CODA9_RET_DEC_PIC_ASPECT 0x1f0
+#define CODA9_RET_DEC_PIC_VP8_SCALE_INFO 0x1f0
+#define CODA9_RET_DEC_PIC_FRATE_NR 0x1f4
+#define CODA9_RET_DEC_PIC_FRATE_DR 0x1f8
+
/* Encoder Sequence Initialization */
#define CODA_CMD_ENC_SEQ_BB_START 0x180
#define CODA_CMD_ENC_SEQ_BB_SIZE 0x184
#define CODA_CMD_ENC_SEQ_OPTION 0x188
#define CODA7_OPTION_AVCINTRA16X16ONLY_OFFSET 9
+#define CODA9_OPTION_MVC_PREFIX_NAL_OFFSET 9
#define CODA7_OPTION_GAMMA_OFFSET 8
+#define CODA9_OPTION_MVC_PARASET_REFRESH_OFFSET 8
#define CODA7_OPTION_RCQPMAX_OFFSET 7
+#define CODA9_OPTION_GAMMA_OFFSET 7
#define CODADX6_OPTION_GAMMA_OFFSET 7
#define CODA7_OPTION_RCQPMIN_OFFSET 6
+#define CODA9_OPTION_RCQPMAX_OFFSET 6
#define CODA_OPTION_LIMITQP_OFFSET 6
#define CODA_OPTION_RCINTRAQP_OFFSET 5
#define CODA_OPTION_FMO_OFFSET 4
+#define CODA9_OPTION_MVC_INTERVIEW_OFFSET 4
#define CODA_OPTION_AVC_AUD_OFFSET 2
#define CODA_OPTION_SLICEREPORT_OFFSET 1
#define CODA_CMD_ENC_SEQ_COD_STD 0x18c
#define CODA_STD_MPEG4 0
+#define CODA9_STD_H264 0
#define CODA_STD_H263 1
#define CODA_STD_H264 2
#define CODA_STD_MJPG 3
+#define CODA9_STD_MPEG4 3
+
#define CODA_CMD_ENC_SEQ_SRC_SIZE 0x190
#define CODA7_PICWIDTH_OFFSET 16
#define CODA7_PICWIDTH_MASK 0xffff
@@ -268,15 +319,26 @@
#define CODA7_CMD_ENC_SEQ_SEARCH_BASE 0x1b8
#define CODA7_CMD_ENC_SEQ_SEARCH_SIZE 0x1bc
#define CODA7_CMD_ENC_SEQ_INTRA_QP 0x1c4
-#define CODA_CMD_ENC_SEQ_RC_QP_MAX 0x1c8
+#define CODA_CMD_ENC_SEQ_RC_QP_MIN_MAX 0x1c8
+#define CODA_QPMIN_OFFSET 8
+#define CODA_QPMIN_MASK 0x3f
#define CODA_QPMAX_OFFSET 0
#define CODA_QPMAX_MASK 0x3f
#define CODA_CMD_ENC_SEQ_RC_GAMMA 0x1cc
#define CODA_GAMMA_OFFSET 0
#define CODA_GAMMA_MASK 0xffff
+#define CODA_CMD_ENC_SEQ_RC_INTERVAL_MODE 0x1d0
+#define CODA9_CMD_ENC_SEQ_INTRA_WEIGHT 0x1d4
+#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8
#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0
/* Encoder Picture Run */
+#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180
+#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184
+#define CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC 0x1a4
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_Y 0x1a8
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_CB 0x1ac
+#define CODA9_CMD_ENC_PIC_SRC_ADDR_CR 0x1b0
#define CODA_CMD_ENC_PIC_SRC_ADDR_Y 0x180
#define CODA_CMD_ENC_PIC_SRC_ADDR_CB 0x184
#define CODA_CMD_ENC_PIC_SRC_ADDR_CR 0x188
@@ -291,7 +353,11 @@
#define CODA_MIR_VER (0x1 << 2)
#define CODA_MIR_HOR (0x2 << 2)
#define CODA_MIR_VER_HOR (0x3 << 2)
-#define CODA_CMD_ENC_PIC_OPTION 0x194
+#define CODA_CMD_ENC_PIC_OPTION 0x194
+#define CODA_FORCE_IPICTURE BIT(1)
+#define CODA_REPORT_MB_INFO BIT(3)
+#define CODA_REPORT_MV_INFO BIT(4)
+#define CODA_REPORT_SLICE_INFO BIT(5)
#define CODA_CMD_ENC_PIC_BB_START 0x198
#define CODA_CMD_ENC_PIC_BB_SIZE 0x19c
#define CODA_RET_ENC_FRAME_NUM 0x1c0
@@ -306,13 +372,30 @@
#define CODA_CMD_SET_FRAME_BUF_STRIDE 0x184
#define CODA_CMD_SET_FRAME_SLICE_BB_START 0x188
#define CODA_CMD_SET_FRAME_SLICE_BB_SIZE 0x18c
+#define CODA9_CMD_SET_FRAME_SUBSAMP_A 0x188
+#define CODA9_CMD_SET_FRAME_SUBSAMP_B 0x18c
#define CODA7_CMD_SET_FRAME_AXI_BIT_ADDR 0x190
#define CODA7_CMD_SET_FRAME_AXI_IPACDC_ADDR 0x194
#define CODA7_CMD_SET_FRAME_AXI_DBKY_ADDR 0x198
#define CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR 0x19c
#define CODA7_CMD_SET_FRAME_AXI_OVL_ADDR 0x1a0
#define CODA7_CMD_SET_FRAME_MAX_DEC_SIZE 0x1a4
+#define CODA9_CMD_SET_FRAME_AXI_BTP_ADDR 0x1a4
#define CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE 0x1a8
+#define CODA9_CMD_SET_FRAME_CACHE_SIZE 0x1a8
+#define CODA9_CMD_SET_FRAME_CACHE_CONFIG 0x1ac
+#define CODA9_CACHE_BYPASS_OFFSET 28
+#define CODA9_CACHE_DUALCONF_OFFSET 26
+#define CODA9_CACHE_PAGEMERGE_OFFSET 24
+#define CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET 16
+#define CODA9_CACHE_CB_BUFFER_SIZE_OFFSET 8
+#define CODA9_CACHE_CR_BUFFER_SIZE_OFFSET 0
+#define CODA9_CMD_SET_FRAME_SUBSAMP_A_MVC 0x1b0
+#define CODA9_CMD_SET_FRAME_SUBSAMP_B_MVC 0x1b4
+#define CODA9_CMD_SET_FRAME_DP_BUF_BASE 0x1b0
+#define CODA9_CMD_SET_FRAME_DP_BUF_SIZE 0x1b4
+#define CODA9_CMD_SET_FRAME_MAX_DEC_SIZE 0x1b8
+#define CODA9_CMD_SET_FRAME_DELAY 0x1bc
/* Encoder Header */
#define CODA_CMD_ENC_HEADER_CODE 0x180
@@ -322,8 +405,11 @@
#define CODA_HEADER_MP4V_VOL 0
#define CODA_HEADER_MP4V_VOS 1
#define CODA_HEADER_MP4V_VIS 2
+#define CODA9_HEADER_FRAME_CROP (1 << 3)
#define CODA_CMD_ENC_HEADER_BB_START 0x184
#define CODA_CMD_ENC_HEADER_BB_SIZE 0x188
+#define CODA9_CMD_ENC_HEADER_FRAME_CROP_H 0x18c
+#define CODA9_CMD_ENC_HEADER_FRAME_CROP_V 0x190
/* Get Version */
#define CODA_CMD_FIRMWARE_VERNUM 0x1c0
@@ -334,5 +420,28 @@
#define CODA_FIRMWARE_VERNUM(product, major, minor, release) \
((product) << 16 | ((major) << 12) | \
((minor) << 8) | (release))
+#define CODA9_CMD_FIRMWARE_CODE_REV 0x1c4
+
+#define CODA9_GDMA_BASE 0x1000
+#define CODA9_GDI_WPROT_ERR_CLR (CODA9_GDMA_BASE + 0x0a0)
+#define CODA9_GDI_WPROT_RGN_EN (CODA9_GDMA_BASE + 0x0ac)
+
+#define CODA9_GDI_BUS_CTRL (CODA9_GDMA_BASE + 0x0f0)
+#define CODA9_GDI_BUS_STATUS (CODA9_GDMA_BASE + 0x0f4)
+
+#define CODA9_GDI_XY2_CAS_0 (CODA9_GDMA_BASE + 0x800)
+#define CODA9_GDI_XY2_CAS_F (CODA9_GDMA_BASE + 0x83c)
+
+#define CODA9_GDI_XY2_BA_0 (CODA9_GDMA_BASE + 0x840)
+#define CODA9_GDI_XY2_BA_1 (CODA9_GDMA_BASE + 0x844)
+#define CODA9_GDI_XY2_BA_2 (CODA9_GDMA_BASE + 0x848)
+#define CODA9_GDI_XY2_BA_3 (CODA9_GDMA_BASE + 0x84c)
+
+#define CODA9_GDI_XY2_RAS_0 (CODA9_GDMA_BASE + 0x850)
+#define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c)
+
+#define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890)
+#define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0)
+#define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c)
#endif
diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c
index 30fa08405d61..07e98df3d867 100644
--- a/drivers/media/platform/davinci/dm644x_ccdc.c
+++ b/drivers/media/platform/davinci/dm644x_ccdc.c
@@ -581,13 +581,8 @@ void ccdc_config_raw(void)
config_params->alaw.enable)
syn_mode |= CCDC_DATA_PACK_ENABLE;
-#ifdef CONFIG_DM644X_VIDEO_PORT_ENABLE
- /* enable video port */
- val = CCDC_ENABLE_VIDEO_PORT;
-#else
/* disable video port */
val = CCDC_DISABLE_VIDEO_PORT;
-#endif
if (config_params->data_sz == CCDC_DATA_8BITS)
val |= (CCDC_DATA_10BITS & CCDC_FMTCFG_VPIN_MASK)
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index bf5eff99452b..73496d953ba0 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -1709,7 +1709,6 @@ static int register_device(struct vpbe_layer *vpbe_display_layer,
vpbe_display_layer->disp_dev = disp_dev;
/* set the driver data in platform device */
platform_set_drvdata(pdev, disp_dev);
- set_bit(V4L2_FL_USE_FH_PRIO, &vpbe_display_layer->video_dev.flags);
video_set_drvdata(&vpbe_display_layer->video_dev,
vpbe_display_layer);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index a51bda2fb637..ea7661a27479 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -1916,7 +1916,6 @@ static int vpfe_probe(struct platform_device *pdev)
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
"video_dev=%x\n", (int)&vpfe_dev->video_dev);
vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- set_bit(V4L2_FL_USE_FH_PRIO, &vpfe_dev->video_dev->flags);
ret = video_register_device(vpfe_dev->video_dev,
VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 1e4ec697fb10..b054b7eec53d 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -39,32 +39,10 @@ MODULE_VERSION(VPIF_CAPTURE_VERSION);
v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
static int debug = 1;
-static u32 ch0_numbuffers = 3;
-static u32 ch1_numbuffers = 3;
-static u32 ch0_bufsize = 1920 * 1080 * 2;
-static u32 ch1_bufsize = 720 * 576 * 2;
module_param(debug, int, 0644);
-module_param(ch0_numbuffers, uint, S_IRUGO);
-module_param(ch1_numbuffers, uint, S_IRUGO);
-module_param(ch0_bufsize, uint, S_IRUGO);
-module_param(ch1_bufsize, uint, S_IRUGO);
MODULE_PARM_DESC(debug, "Debug level 0-1");
-MODULE_PARM_DESC(ch2_numbuffers, "Channel0 buffer count (default:3)");
-MODULE_PARM_DESC(ch3_numbuffers, "Channel1 buffer count (default:3)");
-MODULE_PARM_DESC(ch2_bufsize, "Channel0 buffer size (default:1920 x 1080 x 2)");
-MODULE_PARM_DESC(ch3_bufsize, "Channel1 buffer size (default:720 x 576 x 2)");
-
-static struct vpif_config_params config_params = {
- .min_numbuffers = 3,
- .numbuffers[0] = 3,
- .numbuffers[1] = 3,
- .min_bufsize[0] = 720 * 480 * 2,
- .min_bufsize[1] = 720 * 480 * 2,
- .channel_bufsize[0] = 1920 * 1080 * 2,
- .channel_bufsize[1] = 720 * 576 * 2,
-};
#define VPIF_DRIVER_NAME "vpif_capture"
@@ -521,10 +499,28 @@ static int vpif_update_std_info(struct channel_obj *ch)
common->width = std_info->width;
common->fmt.fmt.pix.height = std_info->height;
common->height = std_info->height;
+ common->fmt.fmt.pix.sizeimage = common->height * common->width * 2;
common->fmt.fmt.pix.bytesperline = std_info->width;
vpifparams->video_params.hpitch = std_info->width;
vpifparams->video_params.storage_mode = std_info->frm_fmt;
+ if (vid_ch->stdid)
+ common->fmt.fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ common->fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+ if (ch->vpifparams.std_info.frm_fmt)
+ common->fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ else
+ common->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+
+ if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ else
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
+
+ common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
return 0;
}
@@ -600,27 +596,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
ch->vpifparams.video_params.stdid = vpifparams->std_info.stdid;
}
-/**
- * vpif_config_format: configure default frame format in the device
- * ch : ptr to channel object
- */
-static void vpif_config_format(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_config_format\n");
-
- common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
- common->fmt.fmt.pix.sizeimage
- = config_params.channel_bufsize[ch->channel_id];
-
- if (ch->vpifparams.iface.if_type == VPIF_IF_RAW_BAYER)
- common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
- else
- common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
- common->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-}
-
/**
* vpif_get_default_field() - Get default field type based on interface
* @vpif_params - ptr to vpif params
@@ -632,112 +607,6 @@ static inline enum v4l2_field vpif_get_default_field(
V4L2_FIELD_INTERLACED;
}
-/**
- * vpif_check_format() - check given pixel format for compatibility
- * @ch - channel ptr
- * @pixfmt - Given pixel format
- * @update - update the values as per hardware requirement
- *
- * Check the application pixel format for S_FMT and update the input
- * values as per hardware limits for TRY_FMT. The default pixel and
- * field format is selected based on interface type.
- */
-static int vpif_check_format(struct channel_obj *ch,
- struct v4l2_pix_format *pixfmt,
- int update)
-{
- struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
- struct vpif_params *vpif_params = &ch->vpifparams;
- enum v4l2_field field = pixfmt->field;
- u32 sizeimage, hpitch, vpitch;
- int ret = -EINVAL;
-
- vpif_dbg(2, debug, "vpif_check_format\n");
- /**
- * first check for the pixel format. If if_type is Raw bayer,
- * only V4L2_PIX_FMT_SBGGR8 format is supported. Otherwise only
- * V4L2_PIX_FMT_YUV422P is supported
- */
- if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) {
- if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8) {
- if (!update) {
- vpif_dbg(2, debug, "invalid pix format\n");
- goto exit;
- }
- pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
- }
- } else {
- if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P) {
- if (!update) {
- vpif_dbg(2, debug, "invalid pixel format\n");
- goto exit;
- }
- pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P;
- }
- }
-
- if (!(VPIF_VALID_FIELD(field))) {
- if (!update) {
- vpif_dbg(2, debug, "invalid field format\n");
- goto exit;
- }
- /**
- * By default use FIELD_NONE for RAW Bayer capture
- * and FIELD_INTERLACED for other interfaces
- */
- field = vpif_get_default_field(&vpif_params->iface);
- } else if (field == V4L2_FIELD_ANY)
- /* unsupported field. Use default */
- field = vpif_get_default_field(&vpif_params->iface);
-
- /* validate the hpitch */
- hpitch = pixfmt->bytesperline;
- if (hpitch < vpif_params->std_info.width) {
- if (!update) {
- vpif_dbg(2, debug, "invalid hpitch\n");
- goto exit;
- }
- hpitch = vpif_params->std_info.width;
- }
-
- sizeimage = pixfmt->sizeimage;
-
- vpitch = sizeimage / (hpitch * 2);
-
- /* validate the vpitch */
- if (vpitch < vpif_params->std_info.height) {
- if (!update) {
- vpif_dbg(2, debug, "Invalid vpitch\n");
- goto exit;
- }
- vpitch = vpif_params->std_info.height;
- }
-
- /* Check for 8 byte alignment */
- if (!ALIGN(hpitch, 8)) {
- if (!update) {
- vpif_dbg(2, debug, "invalid pitch alignment\n");
- goto exit;
- }
- /* adjust to next 8 byte boundary */
- hpitch = (((hpitch + 7) / 8) * 8);
- }
- /* if update is set, modify the bytesperline and sizeimage */
- if (update) {
- pixfmt->bytesperline = hpitch;
- pixfmt->sizeimage = hpitch * vpitch * 2;
- }
- /**
- * Image width and height is always based on current standard width and
- * height
- */
- pixfmt->width = common->fmt.fmt.pix.width;
- pixfmt->height = common->fmt.fmt.pix.height;
- return 0;
-exit:
- return ret;
-}
-
/**
* vpif_config_addr() - function to configure buffer address in vpif
* @ch - channel ptr
@@ -948,9 +817,6 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
return -EINVAL;
}
- /* Configure the default format information */
- vpif_config_format(ch);
-
/* set standard in the sub device */
ret = v4l2_subdev_call(ch->sd, video, s_std, std_id);
if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {
@@ -977,10 +843,8 @@ static int vpif_enum_input(struct file *file, void *priv,
chan_cfg = &config->chan_config[ch->channel_id];
- if (input->index >= chan_cfg->input_count) {
- vpif_dbg(1, debug, "Invalid input index\n");
+ if (input->index >= chan_cfg->input_count)
return -EINVAL;
- }
memcpy(input, &chan_cfg->inputs[input->index].input,
sizeof(*input));
@@ -1069,8 +933,34 @@ static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
struct channel_obj *ch = video_get_drvdata(vdev);
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
+ struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+ struct vpif_params *vpif_params = &ch->vpifparams;
- return vpif_check_format(ch, pixfmt, 1);
+ /*
+ * to supress v4l-compliance warnings silently correct
+ * the pixelformat
+ */
+ if (vpif_params->iface.if_type == VPIF_IF_RAW_BAYER) {
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_SBGGR8)
+ pixfmt->pixelformat = V4L2_PIX_FMT_SBGGR8;
+ } else {
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
+ pixfmt->pixelformat = V4L2_PIX_FMT_YUV422P;
+ }
+
+ common->fmt.fmt.pix.pixelformat = pixfmt->pixelformat;
+
+ vpif_update_std_info(ch);
+
+ pixfmt->field = common->fmt.fmt.pix.field;
+ pixfmt->colorspace = common->fmt.fmt.pix.colorspace;
+ pixfmt->bytesperline = common->fmt.fmt.pix.width;
+ pixfmt->width = common->fmt.fmt.pix.width;
+ pixfmt->height = common->fmt.fmt.pix.height;
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height * 2;
+ pixfmt->priv = 0;
+
+ return 0;
}
@@ -1108,20 +998,17 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct v4l2_pix_format *pixfmt;
- int ret = 0;
+ int ret;
vpif_dbg(2, debug, "%s\n", __func__);
if (vb2_is_busy(&common->buffer_queue))
return -EBUSY;
- pixfmt = &fmt->fmt.pix;
- /* Check for valid field format */
- ret = vpif_check_format(ch, pixfmt, 0);
-
+ ret = vpif_try_fmt_vid_cap(file, priv, fmt);
if (ret)
return ret;
+
/* store the format in the channel object */
common->fmt = *fmt;
return 0;
@@ -1411,36 +1298,9 @@ static struct v4l2_file_operations vpif_fops = {
*/
static int initialize_vpif(void)
{
- int err = 0, i, j;
+ int err, i, j;
int free_channel_objects_index;
- /* Default number of buffers should be 3 */
- if ((ch0_numbuffers > 0) &&
- (ch0_numbuffers < config_params.min_numbuffers))
- ch0_numbuffers = config_params.min_numbuffers;
- if ((ch1_numbuffers > 0) &&
- (ch1_numbuffers < config_params.min_numbuffers))
- ch1_numbuffers = config_params.min_numbuffers;
-
- /* Set buffer size to min buffers size if it is invalid */
- if (ch0_bufsize < config_params.min_bufsize[VPIF_CHANNEL0_VIDEO])
- ch0_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL0_VIDEO];
- if (ch1_bufsize < config_params.min_bufsize[VPIF_CHANNEL1_VIDEO])
- ch1_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL1_VIDEO];
-
- config_params.numbuffers[VPIF_CHANNEL0_VIDEO] = ch0_numbuffers;
- config_params.numbuffers[VPIF_CHANNEL1_VIDEO] = ch1_numbuffers;
- if (ch0_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL0_VIDEO]
- = ch0_bufsize;
- }
- if (ch1_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL1_VIDEO]
- = ch1_bufsize;
- }
-
/* Allocate memory for six channel objects */
for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
vpif_obj.dev[i] =
@@ -1496,6 +1356,11 @@ static int vpif_probe_complete(void)
if (err)
goto probe_out;
+ /* set initial format */
+ ch->video.stdid = V4L2_STD_525_60;
+ memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));
+ vpif_update_std_info(ch);
+
/* Initialize vb2 queue */
q = &common->buffer_queue;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -1533,7 +1398,6 @@ static int vpif_probe_complete(void)
vdev->vfl_dir = VFL_DIR_RX;
vdev->queue = q;
vdev->lock = &common->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
video_set_drvdata(ch->video_dev, ch);
err = video_register_device(vdev,
VFL_TYPE_GRABBER, (j ? 1 : 0));
@@ -1714,7 +1578,7 @@ static int vpif_remove(struct platform_device *device)
for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
- common = &ch->common[i];
+ common = &ch->common[VPIF_VIDEO_INDEX];
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
video_unregister_device(ch->video_dev);
diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h
index 1ee17824f484..f65d28d38e66 100644
--- a/drivers/media/platform/davinci/vpif_capture.h
+++ b/drivers/media/platform/davinci/vpif_capture.h
@@ -119,15 +119,4 @@ struct vpif_device {
struct vpif_capture_config *config;
};
-struct vpif_config_params {
- u8 min_numbuffers;
- u8 numbuffers[VPIF_CAPTURE_NUM_CHANNELS];
- s8 device_type;
- u32 min_bufsize[VPIF_CAPTURE_NUM_CHANNELS];
- u32 channel_bufsize[VPIF_CAPTURE_NUM_CHANNELS];
- u8 default_device[VPIF_CAPTURE_NUM_CHANNELS];
- u32 video_limit[VPIF_CAPTURE_NUM_CHANNELS];
- u8 max_device_type;
-};
-
#endif /* VPIF_CAPTURE_H */
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index b431b58f39e3..a03ec7381cfe 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -649,7 +649,6 @@ static int vpif_try_fmt_vid_out(struct file *file, void *priv,
pixfmt->width = common->fmt.fmt.pix.width;
pixfmt->height = common->fmt.fmt.pix.height;
pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height * 2;
- pixfmt->priv = 0;
return 0;
}
@@ -1224,7 +1223,6 @@ static int vpif_probe_complete(void)
vdev->vfl_dir = VFL_DIR_TX;
vdev->queue = q;
vdev->lock = &common->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
video_set_drvdata(ch->video_dev, ch);
err = video_register_device(vdev, VFL_TYPE_GRABBER,
(j ? 3 : 2));
@@ -1388,7 +1386,7 @@ static int vpif_remove(struct platform_device *device)
for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
- common = &ch->common[i];
+ common = &ch->common[VPIF_VIDEO_INDEX];
vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
video_unregister_device(ch->video_dev);
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index c21d14fd61db..d36c507a0ba2 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -1002,7 +1002,7 @@ static int deinterlace_probe(struct platform_device *pdev)
dma_cap_mask_t mask;
int ret = 0;
- pcdev = kzalloc(sizeof *pcdev, GFP_KERNEL);
+ pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
if (!pcdev)
return -ENOMEM;
@@ -1012,7 +1012,7 @@ static int deinterlace_probe(struct platform_device *pdev)
dma_cap_set(DMA_INTERLEAVE, mask);
pcdev->dma_chan = dma_request_channel(mask, NULL, pcdev);
if (!pcdev->dma_chan)
- goto free_dev;
+ return -ENODEV;
if (!dma_has_cap(DMA_INTERLEAVE, pcdev->dma_chan->device->cap_mask)) {
v4l2_err(&pcdev->v4l2_dev, "DMA does not support INTERLEAVE\n");
@@ -1078,8 +1078,6 @@ unreg_dev:
v4l2_device_unregister(&pcdev->v4l2_dev);
rel_dma:
dma_release_channel(pcdev->dma_chan);
-free_dev:
- kfree(pcdev);
return ret;
}
@@ -1094,7 +1092,6 @@ static int deinterlace_remove(struct platform_device *pdev)
v4l2_device_unregister(&pcdev->v4l2_dev);
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
dma_release_channel(pcdev->dma_chan);
- kfree(pcdev);
return 0;
}
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
index 0714070ed7fa..c1b03cfd6ded 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -532,7 +532,6 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.priv = 0;
return 0;
}
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 9a726eacb29b..2d177fa58471 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -165,7 +165,6 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix)
pix->pixelformat = omap_formats[ifmt].pixelformat;
pix->field = V4L2_FIELD_ANY;
- pix->priv = 0;
switch (pix->pixelformat) {
case V4L2_PIX_FMT_YUYV:
@@ -1896,7 +1895,6 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
pix->field = V4L2_FIELD_ANY;
pix->bytesperline = pix->width * 2;
pix->sizeimage = pix->bytesperline * pix->height;
- pix->priv = 0;
pix->colorspace = V4L2_COLORSPACE_JPEG;
vout->bpp = RGB565_BPP;
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index deba425e3d8f..f33641384e15 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1172,7 +1172,6 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
goto err_vd_rel;
video_set_drvdata(vfd, vp);
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
v4l2_ctrl_handler_init(&vp->ctrl_handler, 1);
ctrl = v4l2_ctrl_new_std(&vp->ctrl_handler, &s3c_camif_video_ctrl_ops,
@@ -1271,6 +1270,7 @@ static int s3c_camif_subdev_get_fmt(struct v4l2_subdev *sd,
}
mutex_unlock(&camif->lock);
+ mf->field = V4L2_FIELD_NONE;
mf->colorspace = V4L2_COLORSPACE_JPEG;
return 0;
}
@@ -1319,6 +1319,7 @@ static int s3c_camif_subdev_set_fmt(struct v4l2_subdev *sd,
v4l2_dbg(1, debug, sd, "pad%d: code: 0x%x, %ux%u\n",
fmt->pad, mf->code, mf->width, mf->height);
+ mf->field = V4L2_FIELD_NONE;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mutex_lock(&camif->lock);
diff --git a/drivers/media/platform/s5p-jpeg/Makefile b/drivers/media/platform/s5p-jpeg/Makefile
index a1a9169254c3..9e5f214c4667 100644
--- a/drivers/media/platform/s5p-jpeg/Makefile
+++ b/drivers/media/platform/s5p-jpeg/Makefile
@@ -1,2 +1,2 @@
-s5p-jpeg-objs := jpeg-core.o jpeg-hw-exynos4.o jpeg-hw-s5p.o
+s5p-jpeg-objs := jpeg-core.o jpeg-hw-exynos3250.o jpeg-hw-exynos4.o jpeg-hw-s5p.o
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 0dcb796ecad9..e66acbc2a82d 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1,6 +1,6 @@
/* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
*
- * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz
@@ -32,6 +32,7 @@
#include "jpeg-core.h"
#include "jpeg-hw-s5p.h"
#include "jpeg-hw-exynos4.h"
+#include "jpeg-hw-exynos3250.h"
#include "jpeg-regs.h"
static struct s5p_jpeg_fmt sjpeg_formats[] = {
@@ -41,6 +42,7 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.flags = SJPEG_FMT_FLAG_ENC_CAPTURE |
SJPEG_FMT_FLAG_DEC_OUTPUT |
SJPEG_FMT_FLAG_S5P |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
SJPEG_FMT_FLAG_EXYNOS4,
},
{
@@ -69,6 +71,19 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ },
{
.name = "YUV 4:2:2 packed, YCrYCb",
.fourcc = V4L2_PIX_FMT_YVYU,
@@ -82,6 +97,45 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
},
+ {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ },
+ {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ },
+ {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ },
{
.name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
@@ -95,6 +149,32 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
+ {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ },
+ {
+ .name = "RGB565X",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = 16,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ },
{
.name = "RGB565",
.fourcc = V4L2_PIX_FMT_RGB565,
@@ -120,6 +200,19 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
},
+ {
+ .name = "ARGB8888, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .colplanes = 1,
+ .h_align = 2,
+ .v_align = 0,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ },
{
.name = "YUV 4:4:4 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV24,
@@ -185,6 +278,19 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
+ {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = 12,
+ .colplanes = 2,
+ .h_align = 3,
+ .v_align = 3,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ },
{
.name = "YUV 4:2:0 planar, Y/CbCr",
.fourcc = V4L2_PIX_FMT_NV12,
@@ -192,11 +298,25 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.colplanes = 2,
.h_align = 4,
.v_align = 4,
- .flags = SJPEG_FMT_FLAG_DEC_CAPTURE |
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
SJPEG_FMT_FLAG_S5P |
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
+ {
+ .name = "YUV 4:2:0 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .depth = 12,
+ .colplanes = 2,
+ .h_align = 3,
+ .v_align = 3,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ },
{
.name = "YUV 4:2:0 planar, Y/CrCb",
.fourcc = V4L2_PIX_FMT_NV21,
@@ -206,6 +326,7 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.v_align = 1,
.flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
SJPEG_FMT_FLAG_EXYNOS4 |
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
@@ -223,6 +344,19 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
},
+ {
+ .name = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 12,
+ .colplanes = 3,
+ .h_align = 4,
+ .v_align = 4,
+ .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
+ SJPEG_FMT_FLAG_DEC_CAPTURE |
+ SJPEG_FMT_FLAG_EXYNOS3250 |
+ SJPEG_FMT_NON_RGB,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ },
{
.name = "Gray",
.fourcc = V4L2_PIX_FMT_GREY,
@@ -457,6 +591,16 @@ static int exynos4x12_decoded_subsampling[] = {
V4L2_JPEG_CHROMA_SUBSAMPLING_420,
};
+static int exynos3250_decoded_subsampling[] = {
+ V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
+ -1,
+ -1,
+ V4L2_JPEG_CHROMA_SUBSAMPLING_411,
+};
+
static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
{
return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
@@ -471,14 +615,21 @@ static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
{
WARN_ON(ctx->subsampling > 3);
- if (ctx->jpeg->variant->version == SJPEG_S5P) {
+ switch (ctx->jpeg->variant->version) {
+ case SJPEG_S5P:
if (ctx->subsampling > 2)
return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
return ctx->subsampling;
- } else {
+ case SJPEG_EXYNOS3250:
+ if (ctx->subsampling > 3)
+ return V4L2_JPEG_CHROMA_SUBSAMPLING_411;
+ return exynos3250_decoded_subsampling[ctx->subsampling];
+ case SJPEG_EXYNOS4:
if (ctx->subsampling > 2)
return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
return exynos4x12_decoded_subsampling[ctx->subsampling];
+ default:
+ return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
}
}
@@ -646,6 +797,7 @@ static int s5p_jpeg_open(struct file *file)
FMT_TYPE_OUTPUT);
cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
FMT_TYPE_CAPTURE);
+ ctx->scale_factor = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
}
ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
@@ -754,14 +906,14 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
while (notfound) {
c = get_byte(&jpeg_buffer);
if (c == -1)
- break;
+ return false;
if (c != 0xff)
continue;
do
c = get_byte(&jpeg_buffer);
while (c == 0xff);
if (c == -1)
- break;
+ return false;
if (c == 0)
continue;
length = 0;
@@ -981,7 +1133,8 @@ static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
return NULL;
}
-static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
+static void jpeg_bound_align_image(struct s5p_jpeg_ctx *ctx,
+ u32 *w, unsigned int wmin, unsigned int wmax,
unsigned int walign,
u32 *h, unsigned int hmin, unsigned int hmax,
unsigned int halign)
@@ -993,13 +1146,27 @@ static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
w_step = 1 << walign;
h_step = 1 << halign;
+
+ if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250) {
+ /*
+ * Rightmost and bottommost pixels are cropped by the
+ * Exynos3250 JPEG IP for RGB formats, for the specific
+ * width and height values respectively. This assignment
+ * will result in v4l_bound_align_image returning dimensions
+ * reduced by 1 for the aforementioned cases.
+ */
+ if (w_step == 4 && ((width & 3) == 1)) {
+ wmax = width;
+ hmax = height;
+ }
+ }
+
v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
if (*w < width && (*w + w_step) < wmax)
*w += w_step;
if (*h < height && (*h + h_step) < hmax)
*h += h_step;
-
}
static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
@@ -1015,12 +1182,12 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
/* V4L2 specification suggests the driver corrects the format struct
* if any of the dimensions is unsupported */
if (q_type == FMT_TYPE_OUTPUT)
- jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+ jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
S5P_JPEG_MAX_WIDTH, 0,
&pix->height, S5P_JPEG_MIN_HEIGHT,
S5P_JPEG_MAX_HEIGHT, 0);
else
- jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
+ jpeg_bound_align_image(ctx, &pix->width, S5P_JPEG_MIN_WIDTH,
S5P_JPEG_MAX_WIDTH, fmt->h_align,
&pix->height, S5P_JPEG_MIN_HEIGHT,
S5P_JPEG_MAX_HEIGHT, fmt->v_align);
@@ -1142,7 +1309,7 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
else
wh_align = 1;
- jpeg_bound_align_image(&w, S5P_JPEG_MIN_WIDTH,
+ jpeg_bound_align_image(ctx, &w, S5P_JPEG_MIN_WIDTH,
S5P_JPEG_MAX_WIDTH, wh_align,
&h, S5P_JPEG_MIN_HEIGHT,
S5P_JPEG_MAX_HEIGHT, wh_align);
@@ -1150,12 +1317,16 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
return w * h * fmt_depth >> 3;
}
+static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
+ struct v4l2_rect *r);
+
static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
{
struct vb2_queue *vq;
struct s5p_jpeg_q_data *q_data = NULL;
struct v4l2_pix_format *pix = &f->fmt.pix;
struct v4l2_ctrl *ctrl_subs;
+ struct v4l2_rect scale_rect;
unsigned int f_type;
vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
@@ -1200,6 +1371,35 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
if (ctrl_subs)
v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
+ ct->crop_altered = false;
+ }
+
+ /*
+ * For decoding init crop_rect with capture buffer dimmensions which
+ * contain aligned dimensions of the input JPEG image and do it only
+ * if crop rectangle hasn't been altered by the user space e.g. with
+ * S_SELECTION ioctl. For encoding assign output buffer dimensions.
+ */
+ if (!ct->crop_altered &&
+ ((ct->mode == S5P_JPEG_DECODE && f_type == FMT_TYPE_CAPTURE) ||
+ (ct->mode == S5P_JPEG_ENCODE && f_type == FMT_TYPE_OUTPUT))) {
+ ct->crop_rect.width = pix->width;
+ ct->crop_rect.height = pix->height;
+ }
+
+ /*
+ * Prevent downscaling to YUV420 format by more than 2
+ * for Exynos3250 SoC as it produces broken raw image
+ * in such cases.
+ */
+ if (ct->mode == S5P_JPEG_DECODE &&
+ f_type == FMT_TYPE_CAPTURE &&
+ ct->jpeg->variant->version == SJPEG_EXYNOS3250 &&
+ pix->pixelformat == V4L2_PIX_FMT_YUV420 &&
+ ct->scale_factor > 2) {
+ scale_rect.width = ct->out_q.w / 2;
+ scale_rect.height = ct->out_q.h / 2;
+ exynos3250_jpeg_try_downscale(ct, &scale_rect);
}
return 0;
@@ -1229,6 +1429,101 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
}
+static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
+ struct v4l2_rect *r)
+{
+ int w_ratio, h_ratio, scale_factor, cur_ratio, i;
+
+ w_ratio = ctx->out_q.w / r->width;
+ h_ratio = ctx->out_q.h / r->height;
+
+ scale_factor = w_ratio > h_ratio ? w_ratio : h_ratio;
+ scale_factor = clamp_val(scale_factor, 1, 8);
+
+ /* Align scale ratio to the nearest power of 2 */
+ for (i = 0; i <= 3; ++i) {
+ cur_ratio = 1 << i;
+ if (scale_factor <= cur_ratio) {
+ ctx->scale_factor = cur_ratio;
+ break;
+ }
+ }
+
+ r->width = round_down(ctx->out_q.w / ctx->scale_factor, 2);
+ r->height = round_down(ctx->out_q.h / ctx->scale_factor, 2);
+
+ ctx->crop_rect.width = r->width;
+ ctx->crop_rect.height = r->height;
+ ctx->crop_rect.left = 0;
+ ctx->crop_rect.top = 0;
+
+ ctx->crop_altered = true;
+
+ return 0;
+}
+
+/* Return 1 if rectangle a is enclosed in rectangle b, or 0 otherwise. */
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+ if (a->left < b->left || a->top < b->top)
+ return 0;
+ if (a->left + a->width > b->left + b->width)
+ return 0;
+ if (a->top + a->height > b->top + b->height)
+ return 0;
+
+ return 1;
+}
+
+static int exynos3250_jpeg_try_crop(struct s5p_jpeg_ctx *ctx,
+ struct v4l2_rect *r)
+{
+ struct v4l2_rect base_rect;
+ int w_step, h_step;
+
+ switch (ctx->cap_q.fmt->fourcc) {
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ w_step = 1;
+ h_step = 2;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ w_step = 2;
+ h_step = 2;
+ break;
+ default:
+ w_step = 1;
+ h_step = 1;
+ break;
+ }
+
+ base_rect.top = 0;
+ base_rect.left = 0;
+ base_rect.width = ctx->out_q.w;
+ base_rect.height = ctx->out_q.h;
+
+ r->width = round_down(r->width, w_step);
+ r->height = round_down(r->height, h_step);
+ r->left = round_down(r->left, 2);
+ r->top = round_down(r->top, 2);
+
+ if (!enclosed_rectangle(r, &base_rect))
+ return -EINVAL;
+
+ ctx->crop_rect.left = r->left;
+ ctx->crop_rect.top = r->top;
+ ctx->crop_rect.width = r->width;
+ ctx->crop_rect.height = r->height;
+
+ ctx->crop_altered = true;
+
+ return 0;
+}
+
+/*
+ * V4L2 controls
+ */
+
static int s5p_jpeg_g_selection(struct file *file, void *priv,
struct v4l2_selection *s)
{
@@ -1243,27 +1538,53 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv,
case V4L2_SEL_TGT_CROP:
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
s->r.width = ctx->out_q.w;
s->r.height = ctx->out_q.h;
+ s->r.left = 0;
+ s->r.top = 0;
break;
+ case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_PADDED:
- s->r.width = ctx->cap_q.w;
- s->r.height = ctx->cap_q.h;
+ s->r.width = ctx->crop_rect.width;
+ s->r.height = ctx->crop_rect.height;
+ s->r.left = ctx->crop_rect.left;
+ s->r.top = ctx->crop_rect.top;
break;
default:
return -EINVAL;
}
- s->r.left = 0;
- s->r.top = 0;
return 0;
}
/*
* V4L2 controls
*/
+static int s5p_jpeg_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
+ struct v4l2_rect *rect = &s->r;
+ int ret = -EINVAL;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (s->target == V4L2_SEL_TGT_COMPOSE) {
+ if (ctx->mode != S5P_JPEG_DECODE)
+ return -EINVAL;
+ if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
+ ret = exynos3250_jpeg_try_downscale(ctx, rect);
+ } else if (s->target == V4L2_SEL_TGT_CROP) {
+ if (ctx->mode != S5P_JPEG_ENCODE)
+ return -EINVAL;
+ if (ctx->jpeg->variant->version == SJPEG_EXYNOS3250)
+ ret = exynos3250_jpeg_try_crop(ctx, rect);
+ }
+
+ return ret;
+}
static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
@@ -1282,6 +1603,42 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
+static int s5p_jpeg_adjust_subs_ctrl(struct s5p_jpeg_ctx *ctx, int *ctrl_val)
+{
+ switch (ctx->jpeg->variant->version) {
+ case SJPEG_S5P:
+ return 0;
+ case SJPEG_EXYNOS3250:
+ /*
+ * The exynos3250 device can produce JPEG image only
+ * of 4:4:4 subsampling when given RGB32 source image.
+ */
+ if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
+ *ctrl_val = 0;
+ break;
+ case SJPEG_EXYNOS4:
+ /*
+ * The exynos4x12 device requires input raw image fourcc
+ * to be V4L2_PIX_FMT_GREY if gray jpeg format
+ * is to be set.
+ */
+ if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
+ *ctrl_val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY)
+ return -EINVAL;
+ break;
+ }
+
+ /*
+ * The exynos4x12 and exynos3250 devices require resulting
+ * jpeg subsampling not to be lower than the input raw image
+ * subsampling.
+ */
+ if (ctx->out_q.fmt->subsampling > *ctrl_val)
+ *ctrl_val = ctx->out_q.fmt->subsampling;
+
+ return 0;
+}
+
static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
{
struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
@@ -1290,28 +1647,9 @@ static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
spin_lock_irqsave(&ctx->jpeg->slock, flags);
- if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING) {
- if (ctx->jpeg->variant->version == SJPEG_S5P)
- goto error_free;
- /*
- * The exynos4x12 device requires input raw image fourcc
- * to be V4L2_PIX_FMT_GREY if gray jpeg format
- * is to be set.
- */
- if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
- ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
- ret = -EINVAL;
- goto error_free;
- }
- /*
- * The exynos4x12 device requires resulting jpeg subsampling
- * not to be lower than the input raw image subsampling.
- */
- if (ctx->out_q.fmt->subsampling > ctrl->val)
- ctrl->val = ctx->out_q.fmt->subsampling;
- }
+ if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING)
+ ret = s5p_jpeg_adjust_subs_ctrl(ctx, &ctrl->val);
-error_free:
spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
return ret;
}
@@ -1414,6 +1752,7 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
.vidioc_g_selection = s5p_jpeg_g_selection,
+ .vidioc_s_selection = s5p_jpeg_s_selection,
};
/*
@@ -1604,6 +1943,135 @@ static void exynos4_jpeg_device_run(void *priv)
spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
}
+static void exynos3250_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
+{
+ struct s5p_jpeg *jpeg = ctx->jpeg;
+ struct s5p_jpeg_fmt *fmt;
+ struct vb2_buffer *vb;
+ struct s5p_jpeg_addr jpeg_addr;
+ u32 pix_size;
+
+ pix_size = ctx->cap_q.w * ctx->cap_q.h;
+
+ if (ctx->mode == S5P_JPEG_ENCODE) {
+ vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ fmt = ctx->out_q.fmt;
+ } else {
+ vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ fmt = ctx->cap_q.fmt;
+ }
+
+ jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+ if (fmt->colplanes == 2) {
+ jpeg_addr.cb = jpeg_addr.y + pix_size;
+ } else if (fmt->colplanes == 3) {
+ jpeg_addr.cb = jpeg_addr.y + pix_size;
+ if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
+ jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
+ else
+ jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
+ }
+
+ exynos3250_jpeg_imgadr(jpeg->regs, &jpeg_addr);
+}
+
+static void exynos3250_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
+{
+ struct s5p_jpeg *jpeg = ctx->jpeg;
+ struct vb2_buffer *vb;
+ unsigned int jpeg_addr = 0;
+
+ if (ctx->mode == S5P_JPEG_ENCODE)
+ vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ else
+ vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+ jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ exynos3250_jpeg_jpgadr(jpeg->regs, jpeg_addr);
+}
+
+static void exynos3250_jpeg_device_run(void *priv)
+{
+ struct s5p_jpeg_ctx *ctx = priv;
+ struct s5p_jpeg *jpeg = ctx->jpeg;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+ exynos3250_jpeg_reset(jpeg->regs);
+ exynos3250_jpeg_set_dma_num(jpeg->regs);
+ exynos3250_jpeg_poweron(jpeg->regs);
+ exynos3250_jpeg_clk_set(jpeg->regs);
+ exynos3250_jpeg_proc_mode(jpeg->regs, ctx->mode);
+
+ if (ctx->mode == S5P_JPEG_ENCODE) {
+ exynos3250_jpeg_input_raw_fmt(jpeg->regs,
+ ctx->out_q.fmt->fourcc);
+ exynos3250_jpeg_dri(jpeg->regs, ctx->restart_interval);
+
+ /*
+ * JPEG IP allows storing 4 quantization tables
+ * We fill table 0 for luma and table 1 for chroma
+ */
+ s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+ s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+ /* use table 0 for Y */
+ exynos3250_jpeg_qtbl(jpeg->regs, 1, 0);
+ /* use table 1 for Cb and Cr*/
+ exynos3250_jpeg_qtbl(jpeg->regs, 2, 1);
+ exynos3250_jpeg_qtbl(jpeg->regs, 3, 1);
+
+ /* Y, Cb, Cr use Huffman table 0 */
+ exynos3250_jpeg_htbl_ac(jpeg->regs, 1);
+ exynos3250_jpeg_htbl_dc(jpeg->regs, 1);
+ exynos3250_jpeg_htbl_ac(jpeg->regs, 2);
+ exynos3250_jpeg_htbl_dc(jpeg->regs, 2);
+ exynos3250_jpeg_htbl_ac(jpeg->regs, 3);
+ exynos3250_jpeg_htbl_dc(jpeg->regs, 3);
+
+ exynos3250_jpeg_set_x(jpeg->regs, ctx->crop_rect.width);
+ exynos3250_jpeg_set_y(jpeg->regs, ctx->crop_rect.height);
+ exynos3250_jpeg_stride(jpeg->regs, ctx->out_q.fmt->fourcc,
+ ctx->out_q.w);
+ exynos3250_jpeg_offset(jpeg->regs, ctx->crop_rect.left,
+ ctx->crop_rect.top);
+ exynos3250_jpeg_set_img_addr(ctx);
+ exynos3250_jpeg_set_jpeg_addr(ctx);
+ exynos3250_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
+
+ /* ultimately comes from sizeimage from userspace */
+ exynos3250_jpeg_enc_stream_bound(jpeg->regs, ctx->cap_q.size);
+
+ if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565 ||
+ ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565X ||
+ ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB32)
+ exynos3250_jpeg_set_y16(jpeg->regs, true);
+ } else {
+ exynos3250_jpeg_set_img_addr(ctx);
+ exynos3250_jpeg_set_jpeg_addr(ctx);
+ exynos3250_jpeg_stride(jpeg->regs, ctx->cap_q.fmt->fourcc,
+ ctx->cap_q.w);
+ exynos3250_jpeg_offset(jpeg->regs, 0, 0);
+ exynos3250_jpeg_dec_scaling_ratio(jpeg->regs,
+ ctx->scale_factor);
+ exynos3250_jpeg_dec_stream_size(jpeg->regs, ctx->out_q.size);
+ exynos3250_jpeg_output_raw_fmt(jpeg->regs,
+ ctx->cap_q.fmt->fourcc);
+ }
+
+ exynos3250_jpeg_interrupts_enable(jpeg->regs);
+
+ /* JPEG RGB to YCbCr conversion matrix */
+ exynos3250_jpeg_coef(jpeg->regs, ctx->mode);
+
+ exynos3250_jpeg_set_timer(jpeg->regs, EXYNOS3250_IRQ_TIMEOUT);
+ jpeg->irq_status = 0;
+ exynos3250_jpeg_start(jpeg->regs);
+
+ spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+}
+
static int s5p_jpeg_job_ready(void *priv)
{
struct s5p_jpeg_ctx *ctx = priv;
@@ -1621,8 +2089,14 @@ static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
.device_run = s5p_jpeg_device_run,
.job_ready = s5p_jpeg_job_ready,
.job_abort = s5p_jpeg_job_abort,
-}
-;
+};
+
+static struct v4l2_m2m_ops exynos3250_jpeg_m2m_ops = {
+ .device_run = exynos3250_jpeg_device_run,
+ .job_ready = s5p_jpeg_job_ready,
+ .job_abort = s5p_jpeg_job_abort,
+};
+
static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
.device_run = exynos4_jpeg_device_run,
.job_ready = s5p_jpeg_job_ready,
@@ -1895,6 +2369,70 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
return IRQ_HANDLED;
}
+static irqreturn_t exynos3250_jpeg_irq(int irq, void *dev_id)
+{
+ struct s5p_jpeg *jpeg = dev_id;
+ struct s5p_jpeg_ctx *curr_ctx;
+ struct vb2_buffer *src_buf, *dst_buf;
+ unsigned long payload_size = 0;
+ enum vb2_buffer_state state = VB2_BUF_STATE_DONE;
+ bool interrupt_timeout = false;
+ u32 irq_status;
+
+ spin_lock(&jpeg->slock);
+
+ irq_status = exynos3250_jpeg_get_timer_status(jpeg->regs);
+ if (irq_status & EXYNOS3250_TIMER_INT_STAT) {
+ exynos3250_jpeg_clear_timer_status(jpeg->regs);
+ interrupt_timeout = true;
+ dev_err(jpeg->dev, "Interrupt timeout occurred.\n");
+ }
+
+ irq_status = exynos3250_jpeg_get_int_status(jpeg->regs);
+ exynos3250_jpeg_clear_int_status(jpeg->regs, irq_status);
+
+ jpeg->irq_status |= irq_status;
+
+ curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+
+ if (!curr_ctx)
+ goto exit_unlock;
+
+ if ((irq_status & EXYNOS3250_HEADER_STAT) &&
+ (curr_ctx->mode == S5P_JPEG_DECODE)) {
+ exynos3250_jpeg_rstart(jpeg->regs);
+ goto exit_unlock;
+ }
+
+ if (jpeg->irq_status & (EXYNOS3250_JPEG_DONE |
+ EXYNOS3250_WDMA_DONE |
+ EXYNOS3250_RDMA_DONE |
+ EXYNOS3250_RESULT_STAT))
+ payload_size = exynos3250_jpeg_compressed_size(jpeg->regs);
+ else if (interrupt_timeout)
+ state = VB2_BUF_STATE_ERROR;
+ else
+ goto exit_unlock;
+
+ src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+
+ dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
+ dst_buf->v4l2_buf.timestamp = src_buf->v4l2_buf.timestamp;
+
+ v4l2_m2m_buf_done(src_buf, state);
+ if (curr_ctx->mode == S5P_JPEG_ENCODE)
+ vb2_set_plane_payload(dst_buf, 0, payload_size);
+ v4l2_m2m_buf_done(dst_buf, state);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
+
+ curr_ctx->subsampling =
+ exynos3250_jpeg_get_subsampling_mode(jpeg->regs);
+exit_unlock:
+ spin_unlock(&jpeg->slock);
+ return IRQ_HANDLED;
+}
+
static void *jpeg_get_drv_data(struct device *dev);
/*
@@ -1950,6 +2488,10 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
}
dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
+ jpeg->sclk = clk_get(&pdev->dev, "sclk");
+ if (IS_ERR(jpeg->sclk))
+ dev_info(&pdev->dev, "sclk clock not available\n");
+
/* v4l2 device */
ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
if (ret) {
@@ -2057,6 +2599,8 @@ device_register_rollback:
clk_get_rollback:
clk_put(jpeg->clk);
+ if (!IS_ERR(jpeg->sclk))
+ clk_put(jpeg->sclk);
return ret;
}
@@ -2075,10 +2619,15 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
v4l2_m2m_release(jpeg->m2m_dev);
v4l2_device_unregister(&jpeg->v4l2_dev);
- if (!pm_runtime_status_suspended(&pdev->dev))
+ if (!pm_runtime_status_suspended(&pdev->dev)) {
clk_disable_unprepare(jpeg->clk);
+ if (!IS_ERR(jpeg->sclk))
+ clk_disable_unprepare(jpeg->sclk);
+ }
clk_put(jpeg->clk);
+ if (!IS_ERR(jpeg->sclk))
+ clk_put(jpeg->sclk);
return 0;
}
@@ -2088,6 +2637,8 @@ static int s5p_jpeg_runtime_suspend(struct device *dev)
struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
clk_disable_unprepare(jpeg->clk);
+ if (!IS_ERR(jpeg->sclk))
+ clk_disable_unprepare(jpeg->sclk);
return 0;
}
@@ -2102,15 +2653,24 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
if (ret < 0)
return ret;
+ if (!IS_ERR(jpeg->sclk)) {
+ ret = clk_prepare_enable(jpeg->sclk);
+ if (ret < 0)
+ return ret;
+ }
+
spin_lock_irqsave(&jpeg->slock, flags);
/*
- * JPEG IP allows storing two Huffman tables for each component
+ * JPEG IP allows storing two Huffman tables for each component.
* We fill table 0 for each component and do this here only
- * for S5PC210 device as Exynos4x12 requires programming its
- * Huffman tables each time the encoding process is initialized.
+ * for S5PC210 and Exynos3250 SoCs. Exynos4x12 SoC requires
+ * programming its Huffman tables each time the encoding process
+ * is initialized, and thus it is accomplished in the device_run
+ * callback of m2m_ops.
*/
- if (jpeg->variant->version == SJPEG_S5P) {
+ if (jpeg->variant->version == SJPEG_S5P ||
+ jpeg->variant->version == SJPEG_EXYNOS3250) {
s5p_jpeg_set_hdctbl(jpeg->regs);
s5p_jpeg_set_hdctblg(jpeg->regs);
s5p_jpeg_set_hactbl(jpeg->regs);
@@ -2150,6 +2710,13 @@ static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
.fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
};
+static struct s5p_jpeg_variant exynos3250_jpeg_drvdata = {
+ .version = SJPEG_EXYNOS3250,
+ .jpeg_irq = exynos3250_jpeg_irq,
+ .m2m_ops = &exynos3250_jpeg_m2m_ops,
+ .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS3250,
+};
+
static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
.version = SJPEG_EXYNOS4,
.jpeg_irq = exynos4_jpeg_irq,
@@ -2161,9 +2728,12 @@ static const struct of_device_id samsung_jpeg_match[] = {
{
.compatible = "samsung,s5pv210-jpeg",
.data = &s5p_jpeg_drvdata,
+ }, {
+ .compatible = "samsung,exynos3250-jpeg",
+ .data = &exynos3250_jpeg_drvdata,
}, {
.compatible = "samsung,exynos4210-jpeg",
- .data = &s5p_jpeg_drvdata,
+ .data = &exynos4_jpeg_drvdata,
}, {
.compatible = "samsung,exynos4212-jpeg",
.data = &exynos4_jpeg_drvdata,
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index 3e4786329727..764b32de326b 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -35,6 +35,8 @@
#define S5P_JPEG_COEF32 0x6e
#define S5P_JPEG_COEF33 0x13
+#define EXYNOS3250_IRQ_TIMEOUT 0x10000000
+
/* a selection of JPEG markers */
#define TEM 0x01
#define SOF0 0xc0
@@ -49,9 +51,10 @@
#define SJPEG_FMT_FLAG_DEC_CAPTURE (1 << 2)
#define SJPEG_FMT_FLAG_DEC_OUTPUT (1 << 3)
#define SJPEG_FMT_FLAG_S5P (1 << 4)
-#define SJPEG_FMT_FLAG_EXYNOS4 (1 << 5)
-#define SJPEG_FMT_RGB (1 << 6)
-#define SJPEG_FMT_NON_RGB (1 << 7)
+#define SJPEG_FMT_FLAG_EXYNOS3250 (1 << 5)
+#define SJPEG_FMT_FLAG_EXYNOS4 (1 << 6)
+#define SJPEG_FMT_RGB (1 << 7)
+#define SJPEG_FMT_NON_RGB (1 << 8)
#define S5P_JPEG_ENCODE 0
#define S5P_JPEG_DECODE 1
@@ -65,8 +68,9 @@
/* Version numbers */
-#define SJPEG_S5P 1
-#define SJPEG_EXYNOS4 2
+#define SJPEG_S5P 1
+#define SJPEG_EXYNOS3250 2
+#define SJPEG_EXYNOS4 3
enum exynos4_jpeg_result {
OK_ENC_OR_DEC,
@@ -95,8 +99,13 @@ enum exynos4_jpeg_img_quality_level {
* @regs: JPEG IP registers mapping
* @irq: JPEG IP irq
* @clk: JPEG IP clock
+ * @sclk: Exynos3250 JPEG IP special clock
* @dev: JPEG IP struct device
* @alloc_ctx: videobuf2 memory allocator's context
+ * @variant: driver variant to be used
+ * @irq_status interrupt flags set during single encode/decode
+ operation
+
*/
struct s5p_jpeg {
struct mutex lock;
@@ -111,9 +120,11 @@ struct s5p_jpeg {
unsigned int irq;
enum exynos4_jpeg_result irq_ret;
struct clk *clk;
+ struct clk *sclk;
struct device *dev;
void *alloc_ctx;
struct s5p_jpeg_variant *variant;
+ u32 irq_status;
};
struct s5p_jpeg_variant {
@@ -164,9 +175,15 @@ struct s5p_jpeg_q_data {
* @jpeg: JPEG IP device for this context
* @mode: compression (encode) operation or decompression (decode)
* @compr_quality: destination image quality in compression (encode) mode
+ * @restart_interval: JPEG restart interval for JPEG encoding
+ * @subsampling: subsampling of a raw format or a JPEG
* @out_q: source (output) queue information
- * @cap_fmt: destination (capture) queue queue information
+ * @cap_q: destination (capture) queue queue information
+ * @scale_factor: scale factor for JPEG decoding
+ * @crop_rect: a rectangle representing crop area of the output buffer
+ * @fh: V4L2 file handle
* @hdr_parsed: set if header has been parsed during decompression
+ * @crop_altered: set if crop rectangle has been altered by the user space
* @ctrl_handler: controls handler
*/
struct s5p_jpeg_ctx {
@@ -177,8 +194,11 @@ struct s5p_jpeg_ctx {
unsigned short subsampling;
struct s5p_jpeg_q_data out_q;
struct s5p_jpeg_q_data cap_q;
+ unsigned int scale_factor;
+ struct v4l2_rect crop_rect;
struct v4l2_fh fh;
bool hdr_parsed;
+ bool crop_altered;
struct v4l2_ctrl_handler ctrl_handler;
};
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
new file mode 100644
index 000000000000..d26e1f846553
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.c
@@ -0,0 +1,487 @@
+/* linux/drivers/media/platform/exynos3250-jpeg/jpeg-hw.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Jacek Anaszewski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+
+#include "jpeg-core.h"
+#include "jpeg-regs.h"
+#include "jpeg-hw-exynos3250.h"
+
+void exynos3250_jpeg_reset(void __iomem *regs)
+{
+ u32 reg = 0;
+ int count = 1000;
+
+ writel(1, regs + EXYNOS3250_SW_RESET);
+ /* no other way but polling for when JPEG IP becomes operational */
+ while (reg != 0 && --count > 0) {
+ udelay(1);
+ cpu_relax();
+ reg = readl(regs + EXYNOS3250_SW_RESET);
+ }
+
+ reg = 0;
+ count = 1000;
+
+ while (reg != 1 && --count > 0) {
+ writel(1, regs + EXYNOS3250_JPGDRI);
+ udelay(1);
+ cpu_relax();
+ reg = readl(regs + EXYNOS3250_JPGDRI);
+ }
+
+ writel(0, regs + EXYNOS3250_JPGDRI);
+}
+
+void exynos3250_jpeg_poweron(void __iomem *regs)
+{
+ writel(EXYNOS3250_POWER_ON, regs + EXYNOS3250_JPGCLKCON);
+}
+
+void exynos3250_jpeg_set_dma_num(void __iomem *regs)
+{
+ writel(((EXYNOS3250_DMA_MO_COUNT << EXYNOS3250_WDMA_ISSUE_NUM_SHIFT) &
+ EXYNOS3250_WDMA_ISSUE_NUM_MASK) |
+ ((EXYNOS3250_DMA_MO_COUNT << EXYNOS3250_RDMA_ISSUE_NUM_SHIFT) &
+ EXYNOS3250_RDMA_ISSUE_NUM_MASK) |
+ ((EXYNOS3250_DMA_MO_COUNT << EXYNOS3250_ISSUE_GATHER_NUM_SHIFT) &
+ EXYNOS3250_ISSUE_GATHER_NUM_MASK),
+ regs + EXYNOS3250_DMA_ISSUE_NUM);
+}
+
+void exynos3250_jpeg_clk_set(void __iomem *base)
+{
+ u32 reg;
+
+ reg = readl(base + EXYNOS3250_JPGCMOD) & ~EXYNOS3250_HALF_EN_MASK;
+
+ writel(reg | EXYNOS3250_HALF_EN, base + EXYNOS3250_JPGCMOD);
+}
+
+void exynos3250_jpeg_input_raw_fmt(void __iomem *regs, unsigned int fmt)
+{
+ u32 reg;
+
+ reg = readl(regs + EXYNOS3250_JPGCMOD) &
+ EXYNOS3250_MODE_Y16_MASK;
+
+ switch (fmt) {
+ case V4L2_PIX_FMT_RGB32:
+ reg |= EXYNOS3250_MODE_SEL_ARGB8888;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ reg |= EXYNOS3250_MODE_SEL_ARGB8888 | EXYNOS3250_SRC_SWAP_RGB;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ reg |= EXYNOS3250_MODE_SEL_RGB565;
+ break;
+ case V4L2_PIX_FMT_RGB565X:
+ reg |= EXYNOS3250_MODE_SEL_RGB565 | EXYNOS3250_SRC_SWAP_RGB;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ reg |= EXYNOS3250_MODE_SEL_422_1P_LUM_CHR;
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ reg |= EXYNOS3250_MODE_SEL_422_1P_LUM_CHR |
+ EXYNOS3250_SRC_SWAP_UV;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ reg |= EXYNOS3250_MODE_SEL_422_1P_CHR_LUM;
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ reg |= EXYNOS3250_MODE_SEL_422_1P_CHR_LUM |
+ EXYNOS3250_SRC_SWAP_UV;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ reg |= EXYNOS3250_MODE_SEL_420_2P | EXYNOS3250_SRC_NV12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ reg |= EXYNOS3250_MODE_SEL_420_2P | EXYNOS3250_SRC_NV21;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ reg |= EXYNOS3250_MODE_SEL_420_3P;
+ break;
+ default:
+ break;
+
+ }
+
+ writel(reg, regs + EXYNOS3250_JPGCMOD);
+}
+
+void exynos3250_jpeg_set_y16(void __iomem *regs, bool y16)
+{
+ u32 reg;
+
+ reg = readl(regs + EXYNOS3250_JPGCMOD);
+ if (y16)
+ reg |= EXYNOS3250_MODE_Y16;
+ else
+ reg &= ~EXYNOS3250_MODE_Y16_MASK;
+ writel(reg, regs + EXYNOS3250_JPGCMOD);
+}
+
+void exynos3250_jpeg_proc_mode(void __iomem *regs, unsigned int mode)
+{
+ u32 reg, m;
+
+ if (mode == S5P_JPEG_ENCODE)
+ m = EXYNOS3250_PROC_MODE_COMPR;
+ else
+ m = EXYNOS3250_PROC_MODE_DECOMPR;
+ reg = readl(regs + EXYNOS3250_JPGMOD);
+ reg &= ~EXYNOS3250_PROC_MODE_MASK;
+ reg |= m;
+ writel(reg, regs + EXYNOS3250_JPGMOD);
+}
+
+void exynos3250_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
+{
+ u32 reg, m = 0;
+
+ switch (mode) {
+ case V4L2_JPEG_CHROMA_SUBSAMPLING_444:
+ m = EXYNOS3250_SUBSAMPLING_MODE_444;
+ break;
+ case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+ m = EXYNOS3250_SUBSAMPLING_MODE_422;
+ break;
+ case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+ m = EXYNOS3250_SUBSAMPLING_MODE_420;
+ break;
+ }
+
+ reg = readl(regs + EXYNOS3250_JPGMOD);
+ reg &= ~EXYNOS3250_SUBSAMPLING_MODE_MASK;
+ reg |= m;
+ writel(reg, regs + EXYNOS3250_JPGMOD);
+}
+
+unsigned int exynos3250_jpeg_get_subsampling_mode(void __iomem *regs)
+{
+ return readl(regs + EXYNOS3250_JPGMOD) &
+ EXYNOS3250_SUBSAMPLING_MODE_MASK;
+}
+
+void exynos3250_jpeg_dri(void __iomem *regs, unsigned int dri)
+{
+ u32 reg;
+
+ reg = dri & EXYNOS3250_JPGDRI_MASK;
+ writel(reg, regs + EXYNOS3250_JPGDRI);
+}
+
+void exynos3250_jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+{
+ unsigned long reg;
+
+ reg = readl(regs + EXYNOS3250_QHTBL);
+ reg &= ~EXYNOS3250_QT_NUM_MASK(t);
+ reg |= (n << EXYNOS3250_QT_NUM_SHIFT(t)) &
+ EXYNOS3250_QT_NUM_MASK(t);
+ writel(reg, regs + EXYNOS3250_QHTBL);
+}
+
+void exynos3250_jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+{
+ unsigned long reg;
+
+ reg = readl(regs + EXYNOS3250_QHTBL);
+ reg &= ~EXYNOS3250_HT_NUM_AC_MASK(t);
+ /* this driver uses table 0 for all color components */
+ reg |= (0 << EXYNOS3250_HT_NUM_AC_SHIFT(t)) &
+ EXYNOS3250_HT_NUM_AC_MASK(t);
+ writel(reg, regs + EXYNOS3250_QHTBL);
+}
+
+void exynos3250_jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+{
+ unsigned long reg;
+
+ reg = readl(regs + EXYNOS3250_QHTBL);
+ reg &= ~EXYNOS3250_HT_NUM_DC_MASK(t);
+ /* this driver uses table 0 for all color components */
+ reg |= (0 << EXYNOS3250_HT_NUM_DC_SHIFT(t)) &
+ EXYNOS3250_HT_NUM_DC_MASK(t);
+ writel(reg, regs + EXYNOS3250_QHTBL);
+}
+
+void exynos3250_jpeg_set_y(void __iomem *regs, unsigned int y)
+{
+ u32 reg;
+
+ reg = y & EXYNOS3250_JPGY_MASK;
+ writel(reg, regs + EXYNOS3250_JPGY);
+}
+
+void exynos3250_jpeg_set_x(void __iomem *regs, unsigned int x)
+{
+ u32 reg;
+
+ reg = x & EXYNOS3250_JPGX_MASK;
+ writel(reg, regs + EXYNOS3250_JPGX);
+}
+
+unsigned int exynos3250_jpeg_get_y(void __iomem *regs)
+{
+ return readl(regs + EXYNOS3250_JPGY);
+}
+
+unsigned int exynos3250_jpeg_get_x(void __iomem *regs)
+{
+ return readl(regs + EXYNOS3250_JPGX);
+}
+
+void exynos3250_jpeg_interrupts_enable(void __iomem *regs)
+{
+ u32 reg;
+
+ reg = readl(regs + EXYNOS3250_JPGINTSE);
+ reg |= (EXYNOS3250_JPEG_DONE_EN |
+ EXYNOS3250_WDMA_DONE_EN |
+ EXYNOS3250_RDMA_DONE_EN |
+ EXYNOS3250_ENC_STREAM_INT_EN |
+ EXYNOS3250_CORE_DONE_EN |
+ EXYNOS3250_ERR_INT_EN |
+ EXYNOS3250_HEAD_INT_EN);
+ writel(reg, regs + EXYNOS3250_JPGINTSE);
+}
+
+void exynos3250_jpeg_enc_stream_bound(void __iomem *regs, unsigned int size)
+{
+ u32 reg;
+
+ reg = size & EXYNOS3250_ENC_STREAM_BOUND_MASK;
+ writel(reg, regs + EXYNOS3250_ENC_STREAM_BOUND);
+}
+
+void exynos3250_jpeg_output_raw_fmt(void __iomem *regs, unsigned int fmt)
+{
+ u32 reg;
+
+ switch (fmt) {
+ case V4L2_PIX_FMT_RGB32:
+ reg = EXYNOS3250_OUT_FMT_ARGB8888;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ reg = EXYNOS3250_OUT_FMT_ARGB8888 | EXYNOS3250_OUT_SWAP_RGB;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ reg = EXYNOS3250_OUT_FMT_RGB565;
+ break;
+ case V4L2_PIX_FMT_RGB565X:
+ reg = EXYNOS3250_OUT_FMT_RGB565 | EXYNOS3250_OUT_SWAP_RGB;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ reg = EXYNOS3250_OUT_FMT_422_1P_LUM_CHR;
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ reg = EXYNOS3250_OUT_FMT_422_1P_LUM_CHR |
+ EXYNOS3250_OUT_SWAP_UV;
+ break;
+ case V4L2_PIX_FMT_UYVY:
+ reg = EXYNOS3250_OUT_FMT_422_1P_CHR_LUM;
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ reg = EXYNOS3250_OUT_FMT_422_1P_CHR_LUM |
+ EXYNOS3250_OUT_SWAP_UV;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ reg = EXYNOS3250_OUT_FMT_420_2P | EXYNOS3250_OUT_NV12;
+ break;
+ case V4L2_PIX_FMT_NV21:
+ reg = EXYNOS3250_OUT_FMT_420_2P | EXYNOS3250_OUT_NV21;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ reg = EXYNOS3250_OUT_FMT_420_3P;
+ break;
+ default:
+ reg = 0;
+ break;
+ }
+
+ writel(reg, regs + EXYNOS3250_OUTFORM);
+}
+
+void exynos3250_jpeg_jpgadr(void __iomem *regs, unsigned int addr)
+{
+ writel(addr, regs + EXYNOS3250_JPG_JPGADR);
+}
+
+void exynos3250_jpeg_imgadr(void __iomem *regs, struct s5p_jpeg_addr *img_addr)
+{
+ writel(img_addr->y, regs + EXYNOS3250_LUMA_BASE);
+ writel(img_addr->cb, regs + EXYNOS3250_CHROMA_BASE);
+ writel(img_addr->cr, regs + EXYNOS3250_CHROMA_CR_BASE);
+}
+
+void exynos3250_jpeg_stride(void __iomem *regs, unsigned int img_fmt,
+ unsigned int width)
+{
+ u32 reg_luma = 0, reg_cr = 0, reg_cb = 0;
+
+ switch (img_fmt) {
+ case V4L2_PIX_FMT_RGB32:
+ reg_luma = 4 * width;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_YVYU:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_VYUY:
+ reg_luma = 2 * width;
+ break;
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_NV21:
+ reg_luma = width;
+ reg_cb = reg_luma;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ reg_luma = width;
+ reg_cb = reg_cr = reg_luma / 2;
+ break;
+ default:
+ break;
+ }
+
+ writel(reg_luma, regs + EXYNOS3250_LUMA_STRIDE);
+ writel(reg_cb, regs + EXYNOS3250_CHROMA_STRIDE);
+ writel(reg_cr, regs + EXYNOS3250_CHROMA_CR_STRIDE);
+}
+
+void exynos3250_jpeg_offset(void __iomem *regs, unsigned int x_offset,
+ unsigned int y_offset)
+{
+ u32 reg;
+
+ reg = (y_offset << EXYNOS3250_LUMA_YY_OFFSET_SHIFT) &
+ EXYNOS3250_LUMA_YY_OFFSET_MASK;
+ reg |= (x_offset << EXYNOS3250_LUMA_YX_OFFSET_SHIFT) &
+ EXYNOS3250_LUMA_YX_OFFSET_MASK;
+
+ writel(reg, regs + EXYNOS3250_LUMA_XY_OFFSET);
+
+ reg = (y_offset << EXYNOS3250_CHROMA_YY_OFFSET_SHIFT) &
+ EXYNOS3250_CHROMA_YY_OFFSET_MASK;
+ reg |= (x_offset << EXYNOS3250_CHROMA_YX_OFFSET_SHIFT) &
+ EXYNOS3250_CHROMA_YX_OFFSET_MASK;
+
+ writel(reg, regs + EXYNOS3250_CHROMA_XY_OFFSET);
+
+ reg = (y_offset << EXYNOS3250_CHROMA_CR_YY_OFFSET_SHIFT) &
+ EXYNOS3250_CHROMA_CR_YY_OFFSET_MASK;
+ reg |= (x_offset << EXYNOS3250_CHROMA_CR_YX_OFFSET_SHIFT) &
+ EXYNOS3250_CHROMA_CR_YX_OFFSET_MASK;
+
+ writel(reg, regs + EXYNOS3250_CHROMA_CR_XY_OFFSET);
+}
+
+void exynos3250_jpeg_coef(void __iomem *base, unsigned int mode)
+{
+ if (mode == S5P_JPEG_ENCODE) {
+ writel(EXYNOS3250_JPEG_ENC_COEF1,
+ base + EXYNOS3250_JPG_COEF(1));
+ writel(EXYNOS3250_JPEG_ENC_COEF2,
+ base + EXYNOS3250_JPG_COEF(2));
+ writel(EXYNOS3250_JPEG_ENC_COEF3,
+ base + EXYNOS3250_JPG_COEF(3));
+ } else {
+ writel(EXYNOS3250_JPEG_DEC_COEF1,
+ base + EXYNOS3250_JPG_COEF(1));
+ writel(EXYNOS3250_JPEG_DEC_COEF2,
+ base + EXYNOS3250_JPG_COEF(2));
+ writel(EXYNOS3250_JPEG_DEC_COEF3,
+ base + EXYNOS3250_JPG_COEF(3));
+ }
+}
+
+void exynos3250_jpeg_start(void __iomem *regs)
+{
+ writel(1, regs + EXYNOS3250_JSTART);
+}
+
+void exynos3250_jpeg_rstart(void __iomem *regs)
+{
+ writel(1, regs + EXYNOS3250_JRSTART);
+}
+
+unsigned int exynos3250_jpeg_get_int_status(void __iomem *regs)
+{
+ return readl(regs + EXYNOS3250_JPGINTST);
+}
+
+void exynos3250_jpeg_clear_int_status(void __iomem *regs,
+ unsigned int value)
+{
+ return writel(value, regs + EXYNOS3250_JPGINTST);
+}
+
+unsigned int exynos3250_jpeg_operating(void __iomem *regs)
+{
+ return readl(regs + S5P_JPGOPR) & EXYNOS3250_JPGOPR_MASK;
+}
+
+unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs)
+{
+ return readl(regs + EXYNOS3250_JPGCNT) & EXYNOS3250_JPGCNT_MASK;
+}
+
+void exynos3250_jpeg_dec_stream_size(void __iomem *regs,
+ unsigned int size)
+{
+ writel(size & EXYNOS3250_DEC_STREAM_MASK,
+ regs + EXYNOS3250_DEC_STREAM_SIZE);
+}
+
+void exynos3250_jpeg_dec_scaling_ratio(void __iomem *regs,
+ unsigned int sratio)
+{
+ switch (sratio) {
+ case 1:
+ default:
+ sratio = EXYNOS3250_DEC_SCALE_FACTOR_8_8;
+ break;
+ case 2:
+ sratio = EXYNOS3250_DEC_SCALE_FACTOR_4_8;
+ break;
+ case 4:
+ sratio = EXYNOS3250_DEC_SCALE_FACTOR_2_8;
+ break;
+ case 8:
+ sratio = EXYNOS3250_DEC_SCALE_FACTOR_1_8;
+ break;
+ }
+
+ writel(sratio & EXYNOS3250_DEC_SCALE_FACTOR_MASK,
+ regs + EXYNOS3250_DEC_SCALING_RATIO);
+}
+
+void exynos3250_jpeg_set_timer(void __iomem *regs, unsigned int time_value)
+{
+ time_value &= EXYNOS3250_TIMER_INIT_MASK;
+
+ writel(EXYNOS3250_TIMER_INT_STAT | time_value,
+ regs + EXYNOS3250_TIMER_SE);
+}
+
+unsigned int exynos3250_jpeg_get_timer_status(void __iomem *regs)
+{
+ return readl(regs + EXYNOS3250_TIMER_ST);
+}
+
+void exynos3250_jpeg_clear_timer_status(void __iomem *regs)
+{
+ writel(EXYNOS3250_TIMER_INT_STAT, regs + EXYNOS3250_TIMER_ST);
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
new file mode 100644
index 000000000000..b6e3be8b5008
--- /dev/null
+++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
@@ -0,0 +1,60 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos3250.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Jacek Anaszewski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef JPEG_HW_EXYNOS3250_H_
+#define JPEG_HW_EXYNOS3250_H_
+
+#include
+#include
+
+#include "jpeg-regs.h"
+
+void exynos3250_jpeg_reset(void __iomem *regs);
+void exynos3250_jpeg_poweron(void __iomem *regs);
+void exynos3250_jpeg_set_dma_num(void __iomem *regs);
+void exynos3250_jpeg_clk_set(void __iomem *base);
+void exynos3250_jpeg_input_raw_fmt(void __iomem *regs, unsigned int fmt);
+void exynos3250_jpeg_output_raw_fmt(void __iomem *regs, unsigned int fmt);
+void exynos3250_jpeg_set_y16(void __iomem *regs, bool y16);
+void exynos3250_jpeg_proc_mode(void __iomem *regs, unsigned int mode);
+void exynos3250_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode);
+unsigned int exynos3250_jpeg_get_subsampling_mode(void __iomem *regs);
+void exynos3250_jpeg_dri(void __iomem *regs, unsigned int dri);
+void exynos3250_jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n);
+void exynos3250_jpeg_htbl_ac(void __iomem *regs, unsigned int t);
+void exynos3250_jpeg_htbl_dc(void __iomem *regs, unsigned int t);
+void exynos3250_jpeg_set_y(void __iomem *regs, unsigned int y);
+void exynos3250_jpeg_set_x(void __iomem *regs, unsigned int x);
+void exynos3250_jpeg_interrupts_enable(void __iomem *regs);
+void exynos3250_jpeg_enc_stream_bound(void __iomem *regs, unsigned int size);
+void exynos3250_jpeg_outform_raw(void __iomem *regs, unsigned long format);
+void exynos3250_jpeg_jpgadr(void __iomem *regs, unsigned int addr);
+void exynos3250_jpeg_imgadr(void __iomem *regs, struct s5p_jpeg_addr *img_addr);
+void exynos3250_jpeg_stride(void __iomem *regs, unsigned int img_fmt,
+ unsigned int width);
+void exynos3250_jpeg_offset(void __iomem *regs, unsigned int x_offset,
+ unsigned int y_offset);
+void exynos3250_jpeg_coef(void __iomem *base, unsigned int mode);
+void exynos3250_jpeg_start(void __iomem *regs);
+void exynos3250_jpeg_rstart(void __iomem *regs);
+unsigned int exynos3250_jpeg_get_int_status(void __iomem *regs);
+void exynos3250_jpeg_clear_int_status(void __iomem *regs,
+ unsigned int value);
+unsigned int exynos3250_jpeg_operating(void __iomem *regs);
+unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs);
+void exynos3250_jpeg_dec_stream_size(void __iomem *regs, unsigned int size);
+void exynos3250_jpeg_dec_scaling_ratio(void __iomem *regs, unsigned int sratio);
+void exynos3250_jpeg_set_timer(void __iomem *regs, unsigned int time_value);
+unsigned int exynos3250_jpeg_get_timer_status(void __iomem *regs);
+void exynos3250_jpeg_set_timer_status(void __iomem *regs);
+void exynos3250_jpeg_clear_timer_status(void __iomem *regs);
+
+#endif /* JPEG_HW_EXYNOS3250_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-regs.h b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
index 57fb05bb8c77..050fc440248f 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-regs.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-regs.h
@@ -2,7 +2,7 @@
*
* Register definition file for Samsung JPEG codec driver
*
- * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* Author: Andrzej Pietrasiewicz
@@ -373,5 +373,250 @@
/* JPEG AC chrominance (values) Huffman table register */
#define EXYNOS4_HUFF_TBL_HACCV 0x310
+/* Register and bit definitions for Exynos 3250 */
+
+/* JPEG mode register */
+#define EXYNOS3250_JPGMOD 0x00
+#define EXYNOS3250_PROC_MODE_MASK (0x1 << 3)
+#define EXYNOS3250_PROC_MODE_DECOMPR (0x1 << 3)
+#define EXYNOS3250_PROC_MODE_COMPR (0x0 << 3)
+#define EXYNOS3250_SUBSAMPLING_MODE_MASK (0x7 << 0)
+#define EXYNOS3250_SUBSAMPLING_MODE_444 (0x0 << 0)
+#define EXYNOS3250_SUBSAMPLING_MODE_422 (0x1 << 0)
+#define EXYNOS3250_SUBSAMPLING_MODE_420 (0x2 << 0)
+#define EXYNOS3250_SUBSAMPLING_MODE_411 (0x6 << 0)
+#define EXYNOS3250_SUBSAMPLING_MODE_GRAY (0x3 << 0)
+
+/* JPEG operation status register */
+#define EXYNOS3250_JPGOPR 0x04
+#define EXYNOS3250_JPGOPR_MASK 0x01
+
+/* Quantization and Huffman tables register */
+#define EXYNOS3250_QHTBL 0x08
+#define EXYNOS3250_QT_NUM_SHIFT(t) ((((t) - 1) << 1) + 8)
+#define EXYNOS3250_QT_NUM_MASK(t) (0x3 << EXYNOS3250_QT_NUM_SHIFT(t))
+
+/* Huffman tables */
+#define EXYNOS3250_HT_NUM_AC_SHIFT(t) (((t) << 1) - 1)
+#define EXYNOS3250_HT_NUM_AC_MASK(t) (0x1 << EXYNOS3250_HT_NUM_AC_SHIFT(t))
+
+#define EXYNOS3250_HT_NUM_DC_SHIFT(t) (((t) - 1) << 1)
+#define EXYNOS3250_HT_NUM_DC_MASK(t) (0x1 << EXYNOS3250_HT_NUM_DC_SHIFT(t))
+
+/* JPEG restart interval register */
+#define EXYNOS3250_JPGDRI 0x0c
+#define EXYNOS3250_JPGDRI_MASK 0xffff
+
+/* JPEG vertical resolution register */
+#define EXYNOS3250_JPGY 0x10
+#define EXYNOS3250_JPGY_MASK 0xffff
+
+/* JPEG horizontal resolution register */
+#define EXYNOS3250_JPGX 0x14
+#define EXYNOS3250_JPGX_MASK 0xffff
+
+/* JPEG byte count register */
+#define EXYNOS3250_JPGCNT 0x18
+#define EXYNOS3250_JPGCNT_MASK 0xffffff
+
+/* JPEG interrupt mask register */
+#define EXYNOS3250_JPGINTSE 0x1c
+#define EXYNOS3250_JPEG_DONE_EN (1 << 11)
+#define EXYNOS3250_WDMA_DONE_EN (1 << 10)
+#define EXYNOS3250_RDMA_DONE_EN (1 << 9)
+#define EXYNOS3250_ENC_STREAM_INT_EN (1 << 8)
+#define EXYNOS3250_CORE_DONE_EN (1 << 5)
+#define EXYNOS3250_ERR_INT_EN (1 << 4)
+#define EXYNOS3250_HEAD_INT_EN (1 << 3)
+
+/* JPEG interrupt status register */
+#define EXYNOS3250_JPGINTST 0x20
+#define EXYNOS3250_JPEG_DONE (1 << 11)
+#define EXYNOS3250_WDMA_DONE (1 << 10)
+#define EXYNOS3250_RDMA_DONE (1 << 9)
+#define EXYNOS3250_ENC_STREAM_STAT (1 << 8)
+#define EXYNOS3250_RESULT_STAT (1 << 5)
+#define EXYNOS3250_STREAM_STAT (1 << 4)
+#define EXYNOS3250_HEADER_STAT (1 << 3)
+
+/*
+ * Base address of the luma component DMA buffer
+ * of the raw input or output image.
+ */
+#define EXYNOS3250_LUMA_BASE 0x100
+#define EXYNOS3250_SRC_TILE_EN_MASK 0x100
+
+/* Stride of source or destination luma raw image buffer */
+#define EXYNOS3250_LUMA_STRIDE 0x104
+
+/* Horizontal/vertical offset of active region in luma raw image buffer */
+#define EXYNOS3250_LUMA_XY_OFFSET 0x108
+#define EXYNOS3250_LUMA_YY_OFFSET_SHIFT 18
+#define EXYNOS3250_LUMA_YY_OFFSET_MASK (0x1fff << EXYNOS3250_LUMA_YY_OFFSET_SHIFT)
+#define EXYNOS3250_LUMA_YX_OFFSET_SHIFT 2
+#define EXYNOS3250_LUMA_YX_OFFSET_MASK (0x1fff << EXYNOS3250_LUMA_YX_OFFSET_SHIFT)
+
+/*
+ * Base address of the chroma(Cb) component DMA buffer
+ * of the raw input or output image.
+ */
+#define EXYNOS3250_CHROMA_BASE 0x10c
+
+/* Stride of source or destination chroma(Cb) raw image buffer */
+#define EXYNOS3250_CHROMA_STRIDE 0x110
+
+/* Horizontal/vertical offset of active region in chroma(Cb) raw image buffer */
+#define EXYNOS3250_CHROMA_XY_OFFSET 0x114
+#define EXYNOS3250_CHROMA_YY_OFFSET_SHIFT 18
+#define EXYNOS3250_CHROMA_YY_OFFSET_MASK (0x1fff << EXYNOS3250_CHROMA_YY_OFFSET_SHIFT)
+#define EXYNOS3250_CHROMA_YX_OFFSET_SHIFT 2
+#define EXYNOS3250_CHROMA_YX_OFFSET_MASK (0x1fff << EXYNOS3250_CHROMA_YX_OFFSET_SHIFT)
+
+/*
+ * Base address of the chroma(Cr) component DMA buffer
+ * of the raw input or output image.
+ */
+#define EXYNOS3250_CHROMA_CR_BASE 0x118
+
+/* Stride of source or destination chroma(Cr) raw image buffer */
+#define EXYNOS3250_CHROMA_CR_STRIDE 0x11c
+
+/* Horizontal/vertical offset of active region in chroma(Cb) raw image buffer */
+#define EXYNOS3250_CHROMA_CR_XY_OFFSET 0x120
+#define EXYNOS3250_CHROMA_CR_YY_OFFSET_SHIFT 18
+#define EXYNOS3250_CHROMA_CR_YY_OFFSET_MASK (0x1fff << EXYNOS3250_CHROMA_CR_YY_OFFSET_SHIFT)
+#define EXYNOS3250_CHROMA_CR_YX_OFFSET_SHIFT 2
+#define EXYNOS3250_CHROMA_CR_YX_OFFSET_MASK (0x1fff << EXYNOS3250_CHROMA_CR_YX_OFFSET_SHIFT)
+
+/* Raw image data r/w address register */
+#define EXYNOS3250_JPG_IMGADR 0x50
+
+/* Source or destination JPEG file DMA buffer address */
+#define EXYNOS3250_JPG_JPGADR 0x124
+
+/* Coefficients for RGB-to-YCbCr converter register */
+#define EXYNOS3250_JPG_COEF(n) (0x128 + (((n) - 1) << 2))
+#define EXYNOS3250_COEF_SHIFT(j) ((3 - (j)) << 3)
+#define EXYNOS3250_COEF_MASK(j) (0xff << EXYNOS3250_COEF_SHIFT(j))
+
+/* Raw input format setting */
+#define EXYNOS3250_JPGCMOD 0x134
+#define EXYNOS3250_SRC_TILE_EN (0x1 << 10)
+#define EXYNOS3250_SRC_NV_MASK (0x1 << 9)
+#define EXYNOS3250_SRC_NV12 (0x0 << 9)
+#define EXYNOS3250_SRC_NV21 (0x1 << 9)
+#define EXYNOS3250_SRC_BIG_ENDIAN_MASK (0x1 << 8)
+#define EXYNOS3250_SRC_BIG_ENDIAN (0x1 << 8)
+#define EXYNOS3250_MODE_SEL_MASK (0x7 << 5)
+#define EXYNOS3250_MODE_SEL_420_2P (0x0 << 5)
+#define EXYNOS3250_MODE_SEL_422_1P_LUM_CHR (0x1 << 5)
+#define EXYNOS3250_MODE_SEL_RGB565 (0x2 << 5)
+#define EXYNOS3250_MODE_SEL_422_1P_CHR_LUM (0x3 << 5)
+#define EXYNOS3250_MODE_SEL_ARGB8888 (0x4 << 5)
+#define EXYNOS3250_MODE_SEL_420_3P (0x5 << 5)
+#define EXYNOS3250_SRC_SWAP_RGB (0x1 << 3)
+#define EXYNOS3250_SRC_SWAP_UV (0x1 << 2)
+#define EXYNOS3250_MODE_Y16_MASK (0x1 << 1)
+#define EXYNOS3250_MODE_Y16 (0x1 << 1)
+#define EXYNOS3250_HALF_EN_MASK (0x1 << 0)
+#define EXYNOS3250_HALF_EN (0x1 << 0)
+
+/* Power on/off and clock down control */
+#define EXYNOS3250_JPGCLKCON 0x138
+#define EXYNOS3250_CLK_DOWN_READY (0x1 << 1)
+#define EXYNOS3250_POWER_ON (0x1 << 0)
+
+/* Start compression or decompression */
+#define EXYNOS3250_JSTART 0x13c
+
+/* Restart decompression after header analysis */
+#define EXYNOS3250_JRSTART 0x140
+
+/* JPEG SW reset register */
+#define EXYNOS3250_SW_RESET 0x144
+
+/* JPEG timer setting register */
+#define EXYNOS3250_TIMER_SE 0x148
+#define EXYNOS3250_TIMER_INT_EN_SHIFT 31
+#define EXYNOS3250_TIMER_INT_EN (1 << EXYNOS3250_TIMER_INT_EN_SHIFT)
+#define EXYNOS3250_TIMER_INIT_MASK 0x7fffffff
+
+/* JPEG timer status register */
+#define EXYNOS3250_TIMER_ST 0x14c
+#define EXYNOS3250_TIMER_INT_STAT_SHIFT 31
+#define EXYNOS3250_TIMER_INT_STAT (1 << EXYNOS3250_TIMER_INT_STAT_SHIFT)
+#define EXYNOS3250_TIMER_CNT_SHIFT 0
+#define EXYNOS3250_TIMER_CNT_MASK 0x7fffffff
+
+/* Command status register */
+#define EXYNOS3250_COMSTAT 0x150
+#define EXYNOS3250_CUR_PROC_MODE (0x1 << 1)
+#define EXYNOS3250_CUR_COM_MODE (0x1 << 0)
+
+/* JPEG decompression output format register */
+#define EXYNOS3250_OUTFORM 0x154
+#define EXYNOS3250_OUT_ALPHA_MASK (0xff << 24)
+#define EXYNOS3250_OUT_TILE_EN (0x1 << 10)
+#define EXYNOS3250_OUT_NV_MASK (0x1 << 9)
+#define EXYNOS3250_OUT_NV12 (0x0 << 9)
+#define EXYNOS3250_OUT_NV21 (0x1 << 9)
+#define EXYNOS3250_OUT_BIG_ENDIAN_MASK (0x1 << 8)
+#define EXYNOS3250_OUT_BIG_ENDIAN (0x1 << 8)
+#define EXYNOS3250_OUT_SWAP_RGB (0x1 << 7)
+#define EXYNOS3250_OUT_SWAP_UV (0x1 << 6)
+#define EXYNOS3250_OUT_FMT_MASK (0x7 << 0)
+#define EXYNOS3250_OUT_FMT_420_2P (0x0 << 0)
+#define EXYNOS3250_OUT_FMT_422_1P_LUM_CHR (0x1 << 0)
+#define EXYNOS3250_OUT_FMT_422_1P_CHR_LUM (0x3 << 0)
+#define EXYNOS3250_OUT_FMT_420_3P (0x4 << 0)
+#define EXYNOS3250_OUT_FMT_RGB565 (0x5 << 0)
+#define EXYNOS3250_OUT_FMT_ARGB8888 (0x6 << 0)
+
+/* Input JPEG stream byte size for decompression */
+#define EXYNOS3250_DEC_STREAM_SIZE 0x158
+#define EXYNOS3250_DEC_STREAM_MASK 0x1fffffff
+
+/* The upper bound of the byte size of output compressed stream */
+#define EXYNOS3250_ENC_STREAM_BOUND 0x15c
+#define EXYNOS3250_ENC_STREAM_BOUND_MASK 0xffffc0
+
+/* Scale-down ratio when decoding */
+#define EXYNOS3250_DEC_SCALING_RATIO 0x160
+#define EXYNOS3250_DEC_SCALE_FACTOR_MASK 0x3
+#define EXYNOS3250_DEC_SCALE_FACTOR_8_8 0x0
+#define EXYNOS3250_DEC_SCALE_FACTOR_4_8 0x1
+#define EXYNOS3250_DEC_SCALE_FACTOR_2_8 0x2
+#define EXYNOS3250_DEC_SCALE_FACTOR_1_8 0x3
+
+/* Error check */
+#define EXYNOS3250_CRC_RESULT 0x164
+
+/* RDMA and WDMA operation status register */
+#define EXYNOS3250_DMA_OPER_STATUS 0x168
+#define EXYNOS3250_WDMA_OPER_STATUS (0x1 << 1)
+#define EXYNOS3250_RDMA_OPER_STATUS (0x1 << 0)
+
+/* DMA issue gathering number and issue number settings */
+#define EXYNOS3250_DMA_ISSUE_NUM 0x16c
+#define EXYNOS3250_WDMA_ISSUE_NUM_SHIFT 16
+#define EXYNOS3250_WDMA_ISSUE_NUM_MASK (0x7 << EXYNOS3250_WDMA_ISSUE_NUM_SHIFT)
+#define EXYNOS3250_RDMA_ISSUE_NUM_SHIFT 8
+#define EXYNOS3250_RDMA_ISSUE_NUM_MASK (0x7 << EXYNOS3250_RDMA_ISSUE_NUM_SHIFT)
+#define EXYNOS3250_ISSUE_GATHER_NUM_SHIFT 0
+#define EXYNOS3250_ISSUE_GATHER_NUM_MASK (0x7 << EXYNOS3250_ISSUE_GATHER_NUM_SHIFT)
+#define EXYNOS3250_DMA_MO_COUNT 0x7
+
+/* Version register */
+#define EXYNOS3250_VERSION 0x1fc
+
+/* RGB <-> YUV conversion coefficients */
+#define EXYNOS3250_JPEG_ENC_COEF1 0x01352e1e
+#define EXYNOS3250_JPEG_ENC_COEF2 0x00b0ae83
+#define EXYNOS3250_JPEG_ENC_COEF3 0x020cdc13
+
+#define EXYNOS3250_JPEG_DEC_COEF1 0x04a80199
+#define EXYNOS3250_JPEG_DEC_COEF2 0x04a9a064
+#define EXYNOS3250_JPEG_DEC_COEF3 0x04a80102
+
#endif /* JPEG_REGS_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 41723180d10c..d35b0418ab37 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -162,7 +162,7 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
/* Double check if there is at least one instance running.
* If no instance is in memory than no firmware should be present */
if (dev->num_inst > 0) {
- ret = s5p_mfc_reload_firmware(dev);
+ ret = s5p_mfc_load_firmware(dev);
if (ret) {
mfc_err("Failed to reload FW\n");
goto unlock;
@@ -724,7 +724,7 @@ static int s5p_mfc_open(struct file *file)
ret = -ENOMEM;
goto err_alloc;
}
- v4l2_fh_init(&ctx->fh, video_devdata(file));
+ v4l2_fh_init(&ctx->fh, vdev);
file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh);
ctx->dev = dev;
@@ -1351,7 +1351,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = {
.port_num = MFC_NUM_PORTS,
.buf_size = &buf_size_v5,
.buf_align = &mfc_buf_align_v5,
- .fw_name = "s5p-mfc.fw",
+ .fw_name[0] = "s5p-mfc.fw",
};
struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = {
@@ -1378,7 +1378,12 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = {
.port_num = MFC_NUM_PORTS_V6,
.buf_size = &buf_size_v6,
.buf_align = &mfc_buf_align_v6,
- .fw_name = "s5p-mfc-v6.fw",
+ .fw_name[0] = "s5p-mfc-v6.fw",
+ /*
+ * v6-v2 firmware contains bug fixes and interface change
+ * for init buffer command
+ */
+ .fw_name[1] = "s5p-mfc-v6-v2.fw",
};
struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = {
@@ -1405,7 +1410,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = {
.port_num = MFC_NUM_PORTS_V7,
.buf_size = &buf_size_v7,
.buf_align = &mfc_buf_align_v7,
- .fw_name = "s5p-mfc-v7.fw",
+ .fw_name[0] = "s5p-mfc-v7.fw",
};
struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
@@ -1432,7 +1437,7 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = {
.port_num = MFC_NUM_PORTS_V8,
.buf_size = &buf_size_v8,
.buf_align = &mfc_buf_align_v8,
- .fw_name = "s5p-mfc-v8.fw",
+ .fw_name[0] = "s5p-mfc-v8.fw",
};
static struct platform_device_id mfc_driver_ids[] = {
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index b04360cd34f0..01816ffb384b 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -38,6 +38,8 @@
#define MFC_BANK2_ALIGN_ORDER 13
#define MFC_BASE_ALIGN_ORDER 17
+#define MFC_FW_MAX_VERSIONS 2
+
#include
static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b)
@@ -163,6 +165,11 @@ enum s5p_mfc_decode_arg {
MFC_DEC_RES_CHANGE,
};
+enum s5p_mfc_fw_ver {
+ MFC_FW_V1,
+ MFC_FW_V2,
+};
+
#define MFC_BUF_FLAG_USED (1 << 0)
#define MFC_BUF_FLAG_EOS (1 << 1)
@@ -225,7 +232,7 @@ struct s5p_mfc_variant {
u32 version_bit;
struct s5p_mfc_buf_size *buf_size;
struct s5p_mfc_buf_align *buf_align;
- char *fw_name;
+ char *fw_name[MFC_FW_MAX_VERSIONS];
};
/**
@@ -287,6 +294,7 @@ struct s5p_mfc_priv_buf {
* @warn_start: hardware error code from which warnings start
* @mfc_ops: ops structure holding HW operation function pointers
* @mfc_cmds: cmd structure holding HW commands function pointers
+ * @fw_ver: loaded firmware sub-version
*
*/
struct s5p_mfc_dev {
@@ -331,6 +339,7 @@ struct s5p_mfc_dev {
struct s5p_mfc_hw_ops *mfc_ops;
struct s5p_mfc_hw_cmds *mfc_cmds;
const struct s5p_mfc_regs *mfc_regs;
+ enum s5p_mfc_fw_ver fw_ver;
};
/**
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index 6c3f8f743900..ca9f78922832 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -38,8 +38,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev_l, dev->fw_size,
&dev->bank1, GFP_KERNEL);
- if (IS_ERR_OR_NULL(dev->fw_virt_addr)) {
- dev->fw_virt_addr = NULL;
+ if (!dev->fw_virt_addr) {
mfc_err("Allocating bitprocessor buffer failed\n");
return -ENOMEM;
}
@@ -48,7 +47,7 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER,
&bank2_dma_addr, GFP_KERNEL);
- if (IS_ERR(dev->fw_virt_addr)) {
+ if (!bank2_virt) {
mfc_err("Allocating bank2 base failed\n");
dma_free_coherent(dev->mem_dev_l, dev->fw_size,
dev->fw_virt_addr, dev->bank1);
@@ -78,47 +77,23 @@ int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
{
struct firmware *fw_blob;
- int err;
+ int i, err = -EINVAL;
/* Firmare has to be present as a separate file or compiled
* into kernel. */
mfc_debug_enter();
- err = request_firmware((const struct firmware **)&fw_blob,
- dev->variant->fw_name, dev->v4l2_dev.dev);
- if (err != 0) {
- mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
- return -EINVAL;
+ for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) {
+ if (!dev->variant->fw_name[i])
+ continue;
+ err = request_firmware((const struct firmware **)&fw_blob,
+ dev->variant->fw_name[i], dev->v4l2_dev.dev);
+ if (!err) {
+ dev->fw_ver = (enum s5p_mfc_fw_ver) i;
+ break;
+ }
}
- if (fw_blob->size > dev->fw_size) {
- mfc_err("MFC firmware is too big to be loaded\n");
- release_firmware(fw_blob);
- return -ENOMEM;
- }
- if (!dev->fw_virt_addr) {
- mfc_err("MFC firmware is not allocated\n");
- release_firmware(fw_blob);
- return -EINVAL;
- }
- memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size);
- wmb();
- release_firmware(fw_blob);
- mfc_debug_leave();
- return 0;
-}
-/* Reload firmware to MFC */
-int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
-{
- struct firmware *fw_blob;
- int err;
-
- /* Firmare has to be present as a separate file or compiled
- * into kernel. */
- mfc_debug_enter();
-
- err = request_firmware((const struct firmware **)&fw_blob,
- dev->variant->fw_name, dev->v4l2_dev.dev);
if (err != 0) {
mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
return -EINVAL;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 4d93835dec9d..9103258b7df3 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -436,6 +436,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
struct v4l2_pix_format_mplane *pix_mp;
+ struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size;
mfc_debug_enter();
ret = vidioc_try_fmt(file, priv, f);
@@ -459,11 +460,13 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_debug(2, "The codec number is: %d\n", ctx->codec_mode);
pix_mp->height = 0;
pix_mp->width = 0;
- if (pix_mp->plane_fmt[0].sizeimage)
- ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
- else
+ if (pix_mp->plane_fmt[0].sizeimage == 0)
pix_mp->plane_fmt[0].sizeimage = ctx->dec_src_buf_size =
DEF_CPB_SIZE;
+ else if (pix_mp->plane_fmt[0].sizeimage > buf_size->cpb)
+ ctx->dec_src_buf_size = buf_size->cpb;
+ else
+ ctx->dec_src_buf_size = pix_mp->plane_fmt[0].sizeimage;
pix_mp->plane_fmt[0].bytesperline = 0;
ctx->state = MFCINST_INIT;
ret = 0;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 4f5e0ead90c6..c1c12f8d8f68 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -48,6 +48,8 @@
#define WRITEL(data, reg) \
(WARN_ON_ONCE(!(reg)) ? 0 : writel((data), (reg)))
+#define IS_MFCV6_V2(dev) (!IS_MFCV7_PLUS(dev) && dev->fw_ver == MFC_FW_V2)
+
/* Allocate temporary buffers for decoding */
static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx)
{
@@ -1352,7 +1354,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
WRITEL(ctx->display_delay, mfc_regs->d_display_delay);
}
- if (IS_MFCV7_PLUS(dev)) {
+ if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev)) {
WRITEL(reg, mfc_regs->d_dec_options);
reg = 0;
}
@@ -1367,7 +1369,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)
reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6);
- if (IS_MFCV7_PLUS(dev))
+ if (IS_MFCV7_PLUS(dev) || IS_MFCV6_V2(dev))
WRITEL(reg, mfc_regs->d_init_buffer_options);
else
WRITEL(reg, mfc_regs->d_dec_options);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index 11d5f1dada32..b6a8be97a96c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -21,6 +21,8 @@
#include "s5p_mfc_pm.h"
#define MFC_GATE_CLK_NAME "mfc"
+#define MFC_SCLK_NAME "sclk-mfc"
+#define MFC_SCLK_RATE (200 * 1000000)
#define CLK_DEBUG
@@ -50,6 +52,20 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
goto err_p_ip_clk;
}
+ if (dev->variant->version != MFC_VERSION_V6) {
+ pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME);
+ if (IS_ERR(pm->clock)) {
+ mfc_info("Failed to get MFC special clock control\n");
+ } else {
+ clk_set_rate(pm->clock, MFC_SCLK_RATE);
+ ret = clk_prepare_enable(pm->clock);
+ if (ret) {
+ mfc_err("Failed to enable MFC special clock\n");
+ goto err_s_clk;
+ }
+ }
+ }
+
atomic_set(&pm->power, 0);
#ifdef CONFIG_PM_RUNTIME
pm->device = &dev->plat_dev->dev;
@@ -59,6 +75,9 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
atomic_set(&clk_ref, 0);
#endif
return 0;
+
+err_s_clk:
+ clk_put(pm->clock);
err_p_ip_clk:
clk_put(pm->clock_gate);
err_g_ip_clk:
@@ -67,6 +86,11 @@ err_g_ip_clk:
void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
{
+ if (dev->variant->version != MFC_VERSION_V6 &&
+ pm->clock) {
+ clk_disable_unprepare(pm->clock);
+ clk_put(pm->clock);
+ }
clk_unprepare(pm->clock_gate);
clk_put(pm->clock_gate);
#ifdef CONFIG_PM_RUNTIME
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index 8a8dbc8fdfde..b4d2696501e4 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -1109,8 +1109,6 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
.ioctl_ops = &mxr_ioctl_ops,
};
strlcpy(layer->vfd.name, name, sizeof(layer->vfd.name));
- /* let framework control PRIORITY */
- set_bit(V4L2_FL_USE_FH_PRIO, &layer->vfd.flags);
video_set_drvdata(&layer->vfd, layer);
layer->vfd.lock = &layer->mutex;
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index 744e43b480bc..8dc279d4d561 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -425,7 +425,6 @@ static int sh_veu_g_fmt(struct sh_veu_file *veu_file, struct v4l2_format *f)
pix->bytesperline = vfmt->bytesperline;
pix->sizeimage = vfmt->bytesperline * pix->height *
vfmt->fmt->depth / vfmt->fmt->ydepth;
- pix->priv = 0;
dev_dbg(veu->dev, "%s(): type: %d, size %u @ %ux%u, fmt %x\n", __func__,
f->type, pix->sizeimage, pix->width, pix->height, pix->pixelformat);
@@ -473,7 +472,6 @@ static int sh_veu_try_fmt(struct v4l2_format *f, const struct sh_veu_format *fmt
pix->pixelformat = fmt->fourcc;
pix->colorspace = sh_veu_4cc2cspace(pix->pixelformat);
- pix->priv = 0;
pr_debug("%s(): type: %d, size %u\n", __func__, f->type, pix->sizeimage);
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index af39c4665554..6540847f4e1d 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -17,19 +17,6 @@ config SOC_CAMERA_PLATFORM
help
This is a generic SoC camera platform driver, useful for testing
-config MX1_VIDEO
- bool
-
-config VIDEO_MX1
- tristate "i.MX1/i.MXL CMOS Sensor Interface driver"
- depends on BROKEN
- depends on VIDEO_DEV && ARCH_MX1 && SOC_CAMERA
- select FIQ
- select VIDEOBUF_DMA_CONTIG
- select MX1_VIDEO
- ---help---
- This is a v4l2 driver for the i.MX1/i.MXL CMOS Sensor Interface
-
config VIDEO_MX3
tristate "i.MX3x Camera Sensor Interface driver"
depends on VIDEO_DEV && MX3_IPU && SOC_CAMERA
@@ -47,6 +34,7 @@ config VIDEO_PXA27x
config VIDEO_RCAR_VIN
tristate "R-Car Video Input (VIN) support"
depends on VIDEO_DEV && SOC_CAMERA
+ depends on ARCH_SHMOBILE || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select SOC_CAMERA_SCALE_CROP
---help---
@@ -55,12 +43,14 @@ config VIDEO_RCAR_VIN
config VIDEO_SH_MOBILE_CSI2
tristate "SuperH Mobile MIPI CSI-2 Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+ depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
---help---
This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
config VIDEO_SH_MOBILE_CEU
tristate "SuperH Mobile CEU Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
+ depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
select SOC_CAMERA_SCALE_CROP
---help---
@@ -76,7 +66,7 @@ config VIDEO_OMAP1
config VIDEO_MX2
tristate "i.MX27 Camera Sensor Interface driver"
- depends on VIDEO_DEV && SOC_CAMERA && MACH_MX27
+ depends on VIDEO_DEV && SOC_CAMERA && SOC_IMX27
select VIDEOBUF2_DMA_CONTIG
---help---
This is a v4l2 driver for the i.MX27 Camera Sensor Interface
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
index 8aed26d7a64d..2826382dc9f8 100644
--- a/drivers/media/platform/soc_camera/Makefile
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -7,7 +7,6 @@ obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
# soc-camera host drivers have to be linked after camera drivers
obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
-obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 38c723aca438..3408b045b3f1 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#define MAX_BUFFER_NUM 32
@@ -33,6 +34,7 @@
#define VID_LIMIT_BYTES (16 * 1024 * 1024)
#define MIN_FRAME_RATE 15
#define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE)
+#define ISI_DEFAULT_MCLK_FREQ 25000000
/* Frame buffer descriptor */
struct fbd {
@@ -84,7 +86,7 @@ struct atmel_isi {
struct clk *mck;
unsigned int irq;
- struct isi_platform_data *pdata;
+ struct isi_platform_data pdata;
u16 width_flags; /* max 12 bits */
struct list_head video_buffer_list;
@@ -350,7 +352,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK;
/* Enable linked list */
- cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR;
+ cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR;
/* Enable codec path and ISI */
ctrl = ISI_CTRL_CDC | ISI_CTRL_EN;
@@ -795,7 +797,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
/* Make choises, based on platform preferences */
if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (isi->pdata->hsync_act_low)
+ if (isi->pdata.hsync_act_low)
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
else
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
@@ -803,7 +805,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (isi->pdata->vsync_act_low)
+ if (isi->pdata.vsync_act_low)
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
else
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
@@ -811,7 +813,7 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
(common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (isi->pdata->pclk_act_falling)
+ if (isi->pdata.pclk_act_falling)
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
else
common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
@@ -833,9 +835,9 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd)
if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
- if (isi->pdata->has_emb_sync)
+ if (isi->pdata.has_emb_sync)
cfg1 |= ISI_CFG1_EMB_SYNC;
- if (isi->pdata->full_mode)
+ if (isi->pdata.full_mode)
cfg1 |= ISI_CFG1_FULL_MODE;
isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
@@ -876,6 +878,51 @@ static int atmel_isi_remove(struct platform_device *pdev)
return 0;
}
+static int atmel_isi_probe_dt(struct atmel_isi *isi,
+ struct platform_device *pdev)
+{
+ struct device_node *np= pdev->dev.of_node;
+ struct v4l2_of_endpoint ep;
+ int err;
+
+ /* Default settings for ISI */
+ isi->pdata.full_mode = 1;
+ isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ;
+ isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL;
+
+ np = of_graph_get_next_endpoint(np, NULL);
+ if (!np) {
+ dev_err(&pdev->dev, "Could not find the endpoint\n");
+ return -EINVAL;
+ }
+
+ err = v4l2_of_parse_endpoint(np, &ep);
+ if (err) {
+ dev_err(&pdev->dev, "Could not parse the endpoint\n");
+ goto err_probe_dt;
+ }
+
+ switch (ep.bus.parallel.bus_width) {
+ case 8:
+ isi->pdata.data_width_flags = ISI_DATAWIDTH_8;
+ break;
+ case 10:
+ isi->pdata.data_width_flags =
+ ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10;
+ break;
+ default:
+ dev_err(&pdev->dev, "Unsupported bus width: %d\n",
+ ep.bus.parallel.bus_width);
+ err = -EINVAL;
+ goto err_probe_dt;
+ }
+
+err_probe_dt:
+ of_node_put(np);
+
+ return err;
+}
+
static int atmel_isi_probe(struct platform_device *pdev)
{
unsigned int irq;
@@ -887,7 +934,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
struct isi_platform_data *pdata;
pdata = dev->platform_data;
- if (!pdata || !pdata->data_width_flags) {
+ if ((!pdata || !pdata->data_width_flags) && !pdev->dev.of_node) {
dev_err(&pdev->dev,
"No config available for Atmel ISI\n");
return -EINVAL;
@@ -903,7 +950,14 @@ static int atmel_isi_probe(struct platform_device *pdev)
if (IS_ERR(isi->pclk))
return PTR_ERR(isi->pclk);
- isi->pdata = pdata;
+ if (pdata) {
+ memcpy(&isi->pdata, pdata, sizeof(isi->pdata));
+ } else {
+ ret = atmel_isi_probe_dt(isi, pdev);
+ if (ret)
+ return ret;
+ }
+
isi->active = NULL;
spin_lock_init(&isi->lock);
INIT_LIST_HEAD(&isi->video_buffer_list);
@@ -919,7 +973,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
/* Set ISI_MCK's frequency, it should be faster than pixel
* clock.
*/
- ret = clk_set_rate(isi->mck, pdata->mck_hz);
+ ret = clk_set_rate(isi->mck, isi->pdata.mck_hz);
if (ret < 0)
return ret;
}
@@ -953,9 +1007,9 @@ static int atmel_isi_probe(struct platform_device *pdev)
goto err_ioremap;
}
- if (pdata->data_width_flags & ISI_DATAWIDTH_8)
+ if (isi->pdata.data_width_flags & ISI_DATAWIDTH_8)
isi->width_flags = 1 << 7;
- if (pdata->data_width_flags & ISI_DATAWIDTH_10)
+ if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10)
isi->width_flags |= 1 << 9;
isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
@@ -980,6 +1034,11 @@ static int atmel_isi_probe(struct platform_device *pdev)
soc_host->v4l2_dev.dev = &pdev->dev;
soc_host->nr = pdev->id;
+ if (isi->pdata.asd_sizes) {
+ soc_host->asd = isi->pdata.asd;
+ soc_host->asd_sizes = isi->pdata.asd_sizes;
+ }
+
ret = soc_camera_host_register(soc_host);
if (ret) {
dev_err(&pdev->dev, "Unable to register soc camera host\n");
@@ -1000,11 +1059,18 @@ err_alloc_ctx:
return ret;
}
+static const struct of_device_id atmel_isi_of_match[] = {
+ { .compatible = "atmel,at91sam9g45-isi" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, atmel_isi_of_match);
+
static struct platform_driver atmel_isi_driver = {
.remove = atmel_isi_remove,
.driver = {
.name = "atmel_isi",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(atmel_isi_of_match),
},
};
diff --git a/drivers/media/platform/soc_camera/mx1_camera.c b/drivers/media/platform/soc_camera/mx1_camera.c
deleted file mode 100644
index fea3e61476ae..000000000000
--- a/drivers/media/platform/soc_camera/mx1_camera.c
+++ /dev/null
@@ -1,866 +0,0 @@
-/*
- * V4L2 Driver for i.MXL/i.MXL camera (CSI) host
- *
- * Copyright (C) 2008, Paulius Zaleckas
- * Copyright (C) 2009, Darius Augulis
- *
- * Based on PXA SoC camera driver
- * Copyright (C) 2006, Sascha Hauer, Pengutronix
- * Copyright (C) 2008, Guennadi Liakhovetski
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-/*
- * CSI registers
- */
-#define CSICR1 0x00 /* CSI Control Register 1 */
-#define CSISR 0x08 /* CSI Status Register */
-#define CSIRXR 0x10 /* CSI RxFIFO Register */
-
-#define CSICR1_RXFF_LEVEL(x) (((x) & 0x3) << 19)
-#define CSICR1_SOF_POL (1 << 17)
-#define CSICR1_SOF_INTEN (1 << 16)
-#define CSICR1_MCLKDIV(x) (((x) & 0xf) << 12)
-#define CSICR1_MCLKEN (1 << 9)
-#define CSICR1_FCC (1 << 8)
-#define CSICR1_BIG_ENDIAN (1 << 7)
-#define CSICR1_CLR_RXFIFO (1 << 5)
-#define CSICR1_GCLK_MODE (1 << 4)
-#define CSICR1_DATA_POL (1 << 2)
-#define CSICR1_REDGE (1 << 1)
-#define CSICR1_EN (1 << 0)
-
-#define CSISR_SFF_OR_INT (1 << 25)
-#define CSISR_RFF_OR_INT (1 << 24)
-#define CSISR_STATFF_INT (1 << 21)
-#define CSISR_RXFF_INT (1 << 18)
-#define CSISR_SOF_INT (1 << 16)
-#define CSISR_DRDY (1 << 0)
-
-#define DRIVER_VERSION "0.0.2"
-#define DRIVER_NAME "mx1-camera"
-
-#define CSI_IRQ_MASK (CSISR_SFF_OR_INT | CSISR_RFF_OR_INT | \
- CSISR_STATFF_INT | CSISR_RXFF_INT | CSISR_SOF_INT)
-
-#define CSI_BUS_FLAGS (V4L2_MBUS_MASTER | V4L2_MBUS_HSYNC_ACTIVE_HIGH | \
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW | \
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING | \
- V4L2_MBUS_DATA_ACTIVE_HIGH | V4L2_MBUS_DATA_ACTIVE_LOW)
-
-#define MAX_VIDEO_MEM 16 /* Video memory limit in megabytes */
-
-/*
- * Structures
- */
-
-/* buffer for one video frame */
-struct mx1_buffer {
- /* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
- enum v4l2_mbus_pixelcode code;
- int inwork;
-};
-
-/*
- * i.MX1/i.MXL is only supposed to handle one camera on its Camera Sensor
- * Interface. If anyone ever builds hardware to enable more than
- * one camera, they will have to modify this driver too
- */
-struct mx1_camera_dev {
- struct soc_camera_host soc_host;
- struct mx1_camera_pdata *pdata;
- struct mx1_buffer *active;
- struct resource *res;
- struct clk *clk;
- struct list_head capture;
-
- void __iomem *base;
- int dma_chan;
- unsigned int irq;
- unsigned long mclk;
-
- spinlock_t lock;
-};
-
-/*
- * Videobuf operations
- */
-static int mx1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
-{
- struct soc_camera_device *icd = vq->priv_data;
-
- *size = icd->sizeimage;
-
- if (!*count)
- *count = 32;
-
- if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
- *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
-
- dev_dbg(icd->parent, "count=%d, size=%d\n", *count, *size);
-
- return 0;
-}
-
-static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct videobuf_buffer *vb = &buf->vb;
-
- BUG_ON(in_interrupt());
-
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- /*
- * This waits until this buffer is out of danger, i.e., until it is no
- * longer in STATE_QUEUED or STATE_ACTIVE
- */
- videobuf_waiton(vq, vb, 0, 0);
- videobuf_dma_contig_free(vq, vb);
-
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int mx1_videobuf_prepare(struct videobuf_queue *vq,
- struct videobuf_buffer *vb, enum v4l2_field field)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
- int ret;
-
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- /* Added list head initialization on alloc */
- WARN_ON(!list_empty(&vb->queue));
-
- BUG_ON(NULL == icd->current_fmt);
-
- /*
- * I think, in buf_prepare you only have to protect global data,
- * the actual buffer is yours
- */
- buf->inwork = 1;
-
- if (buf->code != icd->current_fmt->code ||
- vb->width != icd->user_width ||
- vb->height != icd->user_height ||
- vb->field != field) {
- buf->code = icd->current_fmt->code;
- vb->width = icd->user_width;
- vb->height = icd->user_height;
- vb->field = field;
- vb->state = VIDEOBUF_NEEDS_INIT;
- }
-
- vb->size = icd->sizeimage;
- if (0 != vb->baddr && vb->bsize < vb->size) {
- ret = -EINVAL;
- goto out;
- }
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- ret = videobuf_iolock(vq, vb, NULL);
- if (ret)
- goto fail;
-
- vb->state = VIDEOBUF_PREPARED;
- }
-
- buf->inwork = 0;
-
- return 0;
-
-fail:
- free_buffer(vq, buf);
-out:
- buf->inwork = 0;
- return ret;
-}
-
-static int mx1_camera_setup_dma(struct mx1_camera_dev *pcdev)
-{
- struct videobuf_buffer *vbuf = &pcdev->active->vb;
- struct device *dev = pcdev->soc_host.icd->parent;
- int ret;
-
- if (unlikely(!pcdev->active)) {
- dev_err(dev, "DMA End IRQ with no active buffer\n");
- return -EFAULT;
- }
-
- /* setup sg list for future DMA */
- ret = imx_dma_setup_single(pcdev->dma_chan,
- videobuf_to_dma_contig(vbuf),
- vbuf->size, pcdev->res->start +
- CSIRXR, DMA_MODE_READ);
- if (unlikely(ret))
- dev_err(dev, "Failed to setup DMA sg list\n");
-
- return ret;
-}
-
-/* Called under spinlock_irqsave(&pcdev->lock, ...) */
-static void mx1_videobuf_queue(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct soc_camera_device *icd = vq->priv_data;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx1_camera_dev *pcdev = ici->priv;
- struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
-
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- list_add_tail(&vb->queue, &pcdev->capture);
-
- vb->state = VIDEOBUF_ACTIVE;
-
- if (!pcdev->active) {
- pcdev->active = buf;
-
- /* setup sg list for future DMA */
- if (!mx1_camera_setup_dma(pcdev)) {
- unsigned int temp;
- /* enable SOF irq */
- temp = __raw_readl(pcdev->base + CSICR1) |
- CSICR1_SOF_INTEN;
- __raw_writel(temp, pcdev->base + CSICR1);
- }
- }
-}
-
-static void mx1_videobuf_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct mx1_buffer *buf = container_of(vb, struct mx1_buffer, vb);
-#ifdef DEBUG
- struct soc_camera_device *icd = vq->priv_data;
- struct device *dev = icd->parent;
-
- dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- switch (vb->state) {
- case VIDEOBUF_ACTIVE:
- dev_dbg(dev, "%s (active)\n", __func__);
- break;
- case VIDEOBUF_QUEUED:
- dev_dbg(dev, "%s (queued)\n", __func__);
- break;
- case VIDEOBUF_PREPARED:
- dev_dbg(dev, "%s (prepared)\n", __func__);
- break;
- default:
- dev_dbg(dev, "%s (unknown)\n", __func__);
- break;
- }
-#endif
-
- free_buffer(vq, buf);
-}
-
-static void mx1_camera_wakeup(struct mx1_camera_dev *pcdev,
- struct videobuf_buffer *vb,
- struct mx1_buffer *buf)
-{
- /* _init is used to debug races, see comment in mx1_camera_reqbufs() */
- list_del_init(&vb->queue);
- vb->state = VIDEOBUF_DONE;
- v4l2_get_timestamp(&vb->ts);
- vb->field_count++;
- wake_up(&vb->done);
-
- if (list_empty(&pcdev->capture)) {
- pcdev->active = NULL;
- return;
- }
-
- pcdev->active = list_entry(pcdev->capture.next,
- struct mx1_buffer, vb.queue);
-
- /* setup sg list for future DMA */
- if (likely(!mx1_camera_setup_dma(pcdev))) {
- unsigned int temp;
-
- /* enable SOF irq */
- temp = __raw_readl(pcdev->base + CSICR1) | CSICR1_SOF_INTEN;
- __raw_writel(temp, pcdev->base + CSICR1);
- }
-}
-
-static void mx1_camera_dma_irq(int channel, void *data)
-{
- struct mx1_camera_dev *pcdev = data;
- struct device *dev = pcdev->soc_host.icd->parent;
- struct mx1_buffer *buf;
- struct videobuf_buffer *vb;
- unsigned long flags;
-
- spin_lock_irqsave(&pcdev->lock, flags);
-
- imx_dma_disable(channel);
-
- if (unlikely(!pcdev->active)) {
- dev_err(dev, "DMA End IRQ with no active buffer\n");
- goto out;
- }
-
- vb = &pcdev->active->vb;
- buf = container_of(vb, struct mx1_buffer, vb);
- WARN_ON(buf->inwork || list_empty(&vb->queue));
- dev_dbg(dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
- vb, vb->baddr, vb->bsize);
-
- mx1_camera_wakeup(pcdev, vb, buf);
-out:
- spin_unlock_irqrestore(&pcdev->lock, flags);
-}
-
-static struct videobuf_queue_ops mx1_videobuf_ops = {
- .buf_setup = mx1_videobuf_setup,
- .buf_prepare = mx1_videobuf_prepare,
- .buf_queue = mx1_videobuf_queue,
- .buf_release = mx1_videobuf_release,
-};
-
-static void mx1_camera_init_videobuf(struct videobuf_queue *q,
- struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx1_camera_dev *pcdev = ici->priv;
-
- videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->parent,
- &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct mx1_buffer), icd, &ici->host_lock);
-}
-
-static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
-{
- unsigned int mclk = pcdev->mclk;
- unsigned long div;
- unsigned long lcdclk;
-
- lcdclk = clk_get_rate(pcdev->clk);
-
- /*
- * We verify platform_mclk_10khz != 0, so if anyone breaks it, here
- * they get a nice Oops
- */
- div = (lcdclk + 2 * mclk - 1) / (2 * mclk) - 1;
-
- dev_dbg(pcdev->soc_host.icd->parent,
- "System clock %lukHz, target freq %dkHz, divisor %lu\n",
- lcdclk / 1000, mclk / 1000, div);
-
- return div;
-}
-
-static void mx1_camera_activate(struct mx1_camera_dev *pcdev)
-{
- unsigned int csicr1 = CSICR1_EN;
-
- dev_dbg(pcdev->soc_host.v4l2_dev.dev, "Activate device\n");
-
- clk_prepare_enable(pcdev->clk);
-
- /* enable CSI before doing anything else */
- __raw_writel(csicr1, pcdev->base + CSICR1);
-
- csicr1 |= CSICR1_MCLKEN | CSICR1_FCC | CSICR1_GCLK_MODE;
- csicr1 |= CSICR1_MCLKDIV(mclk_get_divisor(pcdev));
- csicr1 |= CSICR1_RXFF_LEVEL(2); /* 16 words */
-
- __raw_writel(csicr1, pcdev->base + CSICR1);
-}
-
-static void mx1_camera_deactivate(struct mx1_camera_dev *pcdev)
-{
- dev_dbg(pcdev->soc_host.v4l2_dev.dev, "Deactivate device\n");
-
- /* Disable all CSI interface */
- __raw_writel(0x00, pcdev->base + CSICR1);
-
- clk_disable_unprepare(pcdev->clk);
-}
-
-static int mx1_camera_add_device(struct soc_camera_device *icd)
-{
- dev_info(icd->parent, "MX1 Camera driver attached to camera %d\n",
- icd->devnum);
-
- return 0;
-}
-
-static void mx1_camera_remove_device(struct soc_camera_device *icd)
-{
- dev_info(icd->parent, "MX1 Camera driver detached from camera %d\n",
- icd->devnum);
-}
-
-/*
- * The following two functions absolutely depend on the fact, that
- * there can be only one camera on i.MX1/i.MXL camera sensor interface
- */
-static int mx1_camera_clock_start(struct soc_camera_host *ici)
-{
- struct mx1_camera_dev *pcdev = ici->priv;
-
- mx1_camera_activate(pcdev);
-
- return 0;
-}
-
-static void mx1_camera_clock_stop(struct soc_camera_host *ici)
-{
- struct mx1_camera_dev *pcdev = ici->priv;
- unsigned int csicr1;
-
- /* disable interrupts */
- csicr1 = __raw_readl(pcdev->base + CSICR1) & ~CSI_IRQ_MASK;
- __raw_writel(csicr1, pcdev->base + CSICR1);
-
- /* Stop DMA engine */
- imx_dma_disable(pcdev->dma_chan);
-
- mx1_camera_deactivate(pcdev);
-}
-
-static int mx1_camera_set_bus_param(struct soc_camera_device *icd)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct mx1_camera_dev *pcdev = ici->priv;
- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
- unsigned long common_flags;
- unsigned int csicr1;
- int ret;
-
- /* MX1 supports only 8bit buswidth */
- ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = soc_mbus_config_compatible(&cfg, CSI_BUS_FLAGS);
- if (!common_flags) {
- dev_warn(icd->parent,
- "Flags incompatible: camera 0x%x, host 0x%x\n",
- cfg.flags, CSI_BUS_FLAGS);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- } else {
- common_flags = CSI_BUS_FLAGS;
- }
-
- /* Make choises, based on platform choice */
- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (!pcdev->pdata ||
- pcdev->pdata->flags & MX1_CAMERA_VSYNC_HIGH)
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
- else
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
- }
-
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (!pcdev->pdata ||
- pcdev->pdata->flags & MX1_CAMERA_PCLK_RISING)
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
- else
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
- }
-
- if ((common_flags & V4L2_MBUS_DATA_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)) {
- if (!pcdev->pdata ||
- pcdev->pdata->flags & MX1_CAMERA_DATA_HIGH)
- common_flags &= ~V4L2_MBUS_DATA_ACTIVE_LOW;
- else
- common_flags &= ~V4L2_MBUS_DATA_ACTIVE_HIGH;
- }
-
- cfg.flags = common_flags;
- ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
- if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
- common_flags, ret);
- return ret;
- }
-
- csicr1 = __raw_readl(pcdev->base + CSICR1);
-
- if (common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- csicr1 |= CSICR1_REDGE;
- if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
- csicr1 |= CSICR1_SOF_POL;
- if (common_flags & V4L2_MBUS_DATA_ACTIVE_LOW)
- csicr1 |= CSICR1_DATA_POL;
-
- __raw_writel(csicr1, pcdev->base + CSICR1);
-
- return 0;
-}
-
-static int mx1_camera_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_format_xlate *xlate;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_mbus_framefmt mf;
- int ret, buswidth;
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate) {
- dev_warn(icd->parent, "Format %x not found\n",
- pix->pixelformat);
- return -EINVAL;
- }
-
- buswidth = xlate->host_fmt->bits_per_sample;
- if (buswidth > 8) {
- dev_warn(icd->parent,
- "bits-per-sample %d for format %x unsupported\n",
- buswidth, pix->pixelformat);
- return -EINVAL;
- }
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- if (mf.code != xlate->code)
- return -EINVAL;
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->field = mf.field;
- pix->colorspace = mf.colorspace;
- icd->current_fmt = xlate;
-
- return ret;
-}
-
-static int mx1_camera_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_format_xlate *xlate;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_mbus_framefmt mf;
- int ret;
- /* TODO: limit to mx1 hardware capabilities */
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate) {
- dev_warn(icd->parent, "Format %x not found\n",
- pix->pixelformat);
- return -EINVAL;
- }
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- /* limit to sensor capabilities */
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
- if (ret < 0)
- return ret;
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->field = mf.field;
- pix->colorspace = mf.colorspace;
-
- return 0;
-}
-
-static int mx1_camera_reqbufs(struct soc_camera_device *icd,
- struct v4l2_requestbuffers *p)
-{
- int i;
-
- /*
- * This is for locking debugging only. I removed spinlocks and now I
- * check whether .prepare is ever called on a linked buffer, or whether
- * a dma IRQ can occur for an in-work or unlinked buffer. Until now
- * it hadn't triggered
- */
- for (i = 0; i < p->count; i++) {
- struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i],
- struct mx1_buffer, vb);
- buf->inwork = 0;
- INIT_LIST_HEAD(&buf->vb.queue);
- }
-
- return 0;
-}
-
-static unsigned int mx1_camera_poll(struct file *file, poll_table *pt)
-{
- struct soc_camera_device *icd = file->private_data;
- struct mx1_buffer *buf;
-
- buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer,
- vb.stream);
-
- poll_wait(file, &buf->vb.done, pt);
-
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static int mx1_camera_querycap(struct soc_camera_host *ici,
- struct v4l2_capability *cap)
-{
- /* cap->name is set by the friendly caller:-> */
- strlcpy(cap->card, "i.MX1/i.MXL Camera", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static struct soc_camera_host_ops mx1_soc_camera_host_ops = {
- .owner = THIS_MODULE,
- .add = mx1_camera_add_device,
- .remove = mx1_camera_remove_device,
- .clock_start = mx1_camera_clock_start,
- .clock_stop = mx1_camera_clock_stop,
- .set_bus_param = mx1_camera_set_bus_param,
- .set_fmt = mx1_camera_set_fmt,
- .try_fmt = mx1_camera_try_fmt,
- .init_videobuf = mx1_camera_init_videobuf,
- .reqbufs = mx1_camera_reqbufs,
- .poll = mx1_camera_poll,
- .querycap = mx1_camera_querycap,
-};
-
-static struct fiq_handler fh = {
- .name = "csi_sof"
-};
-
-static int __init mx1_camera_probe(struct platform_device *pdev)
-{
- struct mx1_camera_dev *pcdev;
- struct resource *res;
- struct pt_regs regs;
- struct clk *clk;
- void __iomem *base;
- unsigned int irq;
- int err = 0;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
- err = -ENODEV;
- goto exit;
- }
-
- clk = clk_get(&pdev->dev, "csi_clk");
- if (IS_ERR(clk)) {
- err = PTR_ERR(clk);
- goto exit;
- }
-
- pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
- if (!pcdev) {
- dev_err(&pdev->dev, "Could not allocate pcdev\n");
- err = -ENOMEM;
- goto exit_put_clk;
- }
-
- pcdev->res = res;
- pcdev->clk = clk;
-
- pcdev->pdata = pdev->dev.platform_data;
-
- if (pcdev->pdata)
- pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
-
- if (!pcdev->mclk) {
- dev_warn(&pdev->dev,
- "mclk_10khz == 0! Please, fix your platform data. "
- "Using default 20MHz\n");
- pcdev->mclk = 20000000;
- }
-
- INIT_LIST_HEAD(&pcdev->capture);
- spin_lock_init(&pcdev->lock);
-
- /*
- * Request the regions.
- */
- if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
- err = -EBUSY;
- goto exit_kfree;
- }
-
- base = ioremap(res->start, resource_size(res));
- if (!base) {
- err = -ENOMEM;
- goto exit_release;
- }
- pcdev->irq = irq;
- pcdev->base = base;
-
- /* request dma */
- pcdev->dma_chan = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_HIGH);
- if (pcdev->dma_chan < 0) {
- dev_err(&pdev->dev, "Can't request DMA for MX1 CSI\n");
- err = -EBUSY;
- goto exit_iounmap;
- }
- dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_chan);
-
- imx_dma_setup_handlers(pcdev->dma_chan, mx1_camera_dma_irq, NULL,
- pcdev);
-
- imx_dma_config_channel(pcdev->dma_chan, IMX_DMA_TYPE_FIFO,
- IMX_DMA_MEMSIZE_32, MX1_DMA_REQ_CSI_R, 0);
- /* burst length : 16 words = 64 bytes */
- imx_dma_config_burstlen(pcdev->dma_chan, 0);
-
- /* request irq */
- err = claim_fiq(&fh);
- if (err) {
- dev_err(&pdev->dev, "Camera interrupt register failed\n");
- goto exit_free_dma;
- }
-
- set_fiq_handler(&mx1_camera_sof_fiq_start, &mx1_camera_sof_fiq_end -
- &mx1_camera_sof_fiq_start);
-
- regs.ARM_r8 = (long)MX1_DMA_DIMR;
- regs.ARM_r9 = (long)MX1_DMA_CCR(pcdev->dma_chan);
- regs.ARM_r10 = (long)pcdev->base + CSICR1;
- regs.ARM_fp = (long)pcdev->base + CSISR;
- regs.ARM_sp = 1 << pcdev->dma_chan;
- set_fiq_regs(®s);
-
- mxc_set_irq_fiq(irq, 1);
- enable_fiq(irq);
-
- pcdev->soc_host.drv_name = DRIVER_NAME;
- pcdev->soc_host.ops = &mx1_soc_camera_host_ops;
- pcdev->soc_host.priv = pcdev;
- pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
- pcdev->soc_host.nr = pdev->id;
- err = soc_camera_host_register(&pcdev->soc_host);
- if (err)
- goto exit_free_irq;
-
- dev_info(&pdev->dev, "MX1 Camera driver loaded\n");
-
- return 0;
-
-exit_free_irq:
- disable_fiq(irq);
- mxc_set_irq_fiq(irq, 0);
- release_fiq(&fh);
-exit_free_dma:
- imx_dma_free(pcdev->dma_chan);
-exit_iounmap:
- iounmap(base);
-exit_release:
- release_mem_region(res->start, resource_size(res));
-exit_kfree:
- kfree(pcdev);
-exit_put_clk:
- clk_put(clk);
-exit:
- return err;
-}
-
-static int __exit mx1_camera_remove(struct platform_device *pdev)
-{
- struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
- struct mx1_camera_dev *pcdev = container_of(soc_host,
- struct mx1_camera_dev, soc_host);
- struct resource *res;
-
- imx_dma_free(pcdev->dma_chan);
- disable_fiq(pcdev->irq);
- mxc_set_irq_fiq(pcdev->irq, 0);
- release_fiq(&fh);
-
- clk_put(pcdev->clk);
-
- soc_camera_host_unregister(soc_host);
-
- iounmap(pcdev->base);
-
- res = pcdev->res;
- release_mem_region(res->start, resource_size(res));
-
- kfree(pcdev);
-
- dev_info(&pdev->dev, "MX1 Camera driver unloaded\n");
-
- return 0;
-}
-
-static struct platform_driver mx1_camera_driver = {
- .driver = {
- .name = DRIVER_NAME,
- },
- .remove = __exit_p(mx1_camera_remove),
-};
-
-module_platform_driver_probe(mx1_camera_driver, mx1_camera_probe);
-
-MODULE_DESCRIPTION("i.MX1/i.MXL SoC Camera Host driver");
-MODULE_AUTHOR("Paulius Zaleckas ");
-MODULE_LICENSE("GPL v2");
-MODULE_VERSION(DRIVER_VERSION);
-MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index d4df305fcc18..64dc80ccd6f9 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
#include
@@ -1650,6 +1651,68 @@ static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
.set_bus_param = pxa_camera_set_bus_param,
};
+static int pxa_camera_pdata_from_dt(struct device *dev,
+ struct pxa_camera_dev *pcdev)
+{
+ u32 mclk_rate;
+ struct device_node *np = dev->of_node;
+ struct v4l2_of_endpoint ep;
+ int err = of_property_read_u32(np, "clock-frequency",
+ &mclk_rate);
+ if (!err) {
+ pcdev->platform_flags |= PXA_CAMERA_MCLK_EN;
+ pcdev->mclk = mclk_rate;
+ }
+
+ np = of_graph_get_next_endpoint(np, NULL);
+ if (!np) {
+ dev_err(dev, "could not find endpoint\n");
+ return -EINVAL;
+ }
+
+ err = v4l2_of_parse_endpoint(np, &ep);
+ if (err) {
+ dev_err(dev, "could not parse endpoint\n");
+ goto out;
+ }
+
+ switch (ep.bus.parallel.bus_width) {
+ case 4:
+ pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_4;
+ break;
+ case 5:
+ pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_5;
+ break;
+ case 8:
+ pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_8;
+ break;
+ case 9:
+ pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_9;
+ break;
+ case 10:
+ pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
+ break;
+ default:
+ break;
+ };
+
+ if (ep.bus.parallel.flags & V4L2_MBUS_MASTER)
+ pcdev->platform_flags |= PXA_CAMERA_MASTER;
+ if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ pcdev->platform_flags |= PXA_CAMERA_HSP;
+ if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ pcdev->platform_flags |= PXA_CAMERA_VSP;
+ if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ pcdev->platform_flags |= PXA_CAMERA_PCLK_EN | PXA_CAMERA_PCP;
+ if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
+ pcdev->platform_flags |= PXA_CAMERA_PCLK_EN;
+
+out:
+ of_node_put(np);
+
+ return err;
+}
+
static int pxa_camera_probe(struct platform_device *pdev)
{
struct pxa_camera_dev *pcdev;
@@ -1676,7 +1739,15 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->res = res;
pcdev->pdata = pdev->dev.platform_data;
- pcdev->platform_flags = pcdev->pdata->flags;
+ if (&pdev->dev.of_node && !pcdev->pdata) {
+ err = pxa_camera_pdata_from_dt(&pdev->dev, pcdev);
+ } else {
+ pcdev->platform_flags = pcdev->pdata->flags;
+ pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
+ }
+ if (err < 0)
+ return err;
+
if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
/*
@@ -1693,7 +1764,6 @@ static int pxa_camera_probe(struct platform_device *pdev)
pcdev->width_flags |= 1 << 8;
if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10)
pcdev->width_flags |= 1 << 9;
- pcdev->mclk = pcdev->pdata->mclk_10khz * 10000;
if (!pcdev->mclk) {
dev_warn(&pdev->dev,
"mclk == 0! Please, fix your platform data. "
@@ -1799,10 +1869,17 @@ static const struct dev_pm_ops pxa_camera_pm = {
.resume = pxa_camera_resume,
};
+static const struct of_device_id pxa_camera_of_match[] = {
+ { .compatible = "marvell,pxa270-qci", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, pxa_camera_of_match);
+
static struct platform_driver pxa_camera_driver = {
.driver = {
.name = PXA_CAM_DRV_NAME,
.pm = &pxa_camera_pm,
+ .of_match_table = of_match_ptr(pxa_camera_of_match),
},
.probe = pxa_camera_probe,
.remove = pxa_camera_remove,
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index e594230e84d3..85d579f65f52 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -19,6 +19,8 @@
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -31,6 +33,7 @@
#include
#include
#include
+#include
#include
#include
@@ -126,13 +129,13 @@ struct rcar_vin_priv {
int sequence;
/* State of the VIN module in capturing mode */
enum rcar_vin_state state;
- struct rcar_vin_platform_data *pdata;
struct soc_camera_host ici;
struct list_head capture;
#define MAX_BUFFER_NUM 3
struct vb2_buffer *queue_buf[MAX_BUFFER_NUM];
struct vb2_alloc_ctx *alloc_ctx;
enum v4l2_field field;
+ unsigned int pdata_flags;
unsigned int vb_count;
unsigned int nr_hw_slots;
bool request_to_stop;
@@ -275,12 +278,12 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
break;
case V4L2_MBUS_FMT_YUYV8_2X8:
/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
- vnmc |= priv->pdata->flags & RCAR_VIN_BT656 ?
+ vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ?
VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
break;
case V4L2_MBUS_FMT_YUYV10_2X10:
/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
- vnmc |= priv->pdata->flags & RCAR_VIN_BT656 ?
+ vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ?
VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
break;
default:
@@ -797,7 +800,7 @@ static int rcar_vin_set_bus_param(struct soc_camera_device *icd)
/* Make choises, based on platform preferences */
if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (priv->pdata->flags & RCAR_VIN_HSYNC_ACTIVE_LOW)
+ if (priv->pdata_flags & RCAR_VIN_HSYNC_ACTIVE_LOW)
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
else
common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
@@ -805,7 +808,7 @@ static int rcar_vin_set_bus_param(struct soc_camera_device *icd)
if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
(common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (priv->pdata->flags & RCAR_VIN_VSYNC_ACTIVE_LOW)
+ if (priv->pdata_flags & RCAR_VIN_VSYNC_ACTIVE_LOW)
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
else
common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
@@ -1390,6 +1393,17 @@ static struct soc_camera_host_ops rcar_vin_host_ops = {
.init_videobuf2 = rcar_vin_init_videobuf2,
};
+#ifdef CONFIG_OF
+static struct of_device_id rcar_vin_of_table[] = {
+ { .compatible = "renesas,vin-r8a7791", .data = (void *)RCAR_GEN2 },
+ { .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 },
+ { .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 },
+ { .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 },
+ { },
+};
+MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
+#endif
+
static struct platform_device_id rcar_vin_id_table[] = {
{ "r8a7791-vin", RCAR_GEN2 },
{ "r8a7790-vin", RCAR_GEN2 },
@@ -1402,15 +1416,52 @@ MODULE_DEVICE_TABLE(platform, rcar_vin_id_table);
static int rcar_vin_probe(struct platform_device *pdev)
{
+ const struct of_device_id *match = NULL;
struct rcar_vin_priv *priv;
struct resource *mem;
struct rcar_vin_platform_data *pdata;
+ unsigned int pdata_flags;
int irq, ret;
- pdata = pdev->dev.platform_data;
- if (!pdata || !pdata->flags) {
- dev_err(&pdev->dev, "platform data not set\n");
- return -EINVAL;
+ if (pdev->dev.of_node) {
+ struct v4l2_of_endpoint ep;
+ struct device_node *np;
+
+ match = of_match_device(of_match_ptr(rcar_vin_of_table),
+ &pdev->dev);
+
+ np = of_graph_get_next_endpoint(pdev->dev.of_node, NULL);
+ if (!np) {
+ dev_err(&pdev->dev, "could not find endpoint\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_of_parse_endpoint(np, &ep);
+ if (ret) {
+ dev_err(&pdev->dev, "could not parse endpoint\n");
+ return ret;
+ }
+
+ if (ep.bus_type == V4L2_MBUS_BT656)
+ pdata_flags = RCAR_VIN_BT656;
+ else {
+ pdata_flags = 0;
+ if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
+ pdata_flags |= RCAR_VIN_HSYNC_ACTIVE_LOW;
+ if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ pdata_flags |= RCAR_VIN_VSYNC_ACTIVE_LOW;
+ }
+
+ of_node_put(np);
+
+ dev_dbg(&pdev->dev, "pdata_flags = %08x\n", pdata_flags);
+ } else {
+ pdata = pdev->dev.platform_data;
+ if (!pdata || !pdata->flags) {
+ dev_err(&pdev->dev, "platform data not set\n");
+ return -EINVAL;
+ }
+ pdata_flags = pdata->flags;
}
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1441,12 +1492,18 @@ static int rcar_vin_probe(struct platform_device *pdev)
priv->ici.priv = priv;
priv->ici.v4l2_dev.dev = &pdev->dev;
- priv->ici.nr = pdev->id;
priv->ici.drv_name = dev_name(&pdev->dev);
priv->ici.ops = &rcar_vin_host_ops;
- priv->pdata = pdata;
- priv->chip = pdev->id_entry->driver_data;
+ priv->pdata_flags = pdata_flags;
+ if (!match) {
+ priv->ici.nr = pdev->id;
+ priv->chip = pdev->id_entry->driver_data;
+ } else {
+ priv->ici.nr = of_alias_get_id(pdev->dev.of_node, "vin");
+ priv->chip = (enum chip_id)match->data;
+ };
+
spin_lock_init(&priv->lock);
INIT_LIST_HEAD(&priv->capture);
@@ -1487,6 +1544,7 @@ static struct platform_driver rcar_vin_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rcar_vin_of_table),
},
.id_table = rcar_vin_id_table,
};
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 7fec8cdaf095..f4308fed5431 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -36,6 +36,7 @@
#include
#include
#include
+#include
#include
#include
@@ -1524,14 +1525,14 @@ static int scan_async_group(struct soc_camera_host *ici,
ret = soc_camera_dyn_pdev(&sdesc, sasc);
if (ret < 0)
- return ret;
+ goto eallocpdev;
sasc->sensor = &sasd->asd;
icd = soc_camera_add_pdev(sasc);
if (!icd) {
- platform_device_put(sasc->pdev);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto eaddpdev;
}
sasc->notifier.subdevs = asd;
@@ -1559,7 +1560,11 @@ static int scan_async_group(struct soc_camera_host *ici,
v4l2_clk_unregister(icd->clk);
eclkreg:
icd->clk = NULL;
- platform_device_unregister(sasc->pdev);
+ platform_device_del(sasc->pdev);
+eaddpdev:
+ platform_device_put(sasc->pdev);
+eallocpdev:
+ devm_kfree(ici->v4l2_dev.dev, sasc);
dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
return ret;
@@ -1581,6 +1586,130 @@ static void scan_async_host(struct soc_camera_host *ici)
#define scan_async_host(ici) do {} while (0)
#endif
+#ifdef CONFIG_OF
+
+struct soc_of_info {
+ struct soc_camera_async_subdev sasd;
+ struct soc_camera_async_client sasc;
+ struct v4l2_async_subdev *subdev;
+};
+
+static int soc_of_bind(struct soc_camera_host *ici,
+ struct device_node *ep,
+ struct device_node *remote)
+{
+ struct soc_camera_device *icd;
+ struct soc_camera_desc sdesc = {.host_desc.bus_id = ici->nr,};
+ struct soc_camera_async_client *sasc;
+ struct soc_of_info *info;
+ struct i2c_client *client;
+ char clk_name[V4L2_SUBDEV_NAME_SIZE];
+ int ret;
+
+ /* allocate a new subdev and add match info to it */
+ info = devm_kzalloc(ici->v4l2_dev.dev, sizeof(struct soc_of_info),
+ GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->sasd.asd.match.of.node = remote;
+ info->sasd.asd.match_type = V4L2_ASYNC_MATCH_OF;
+ info->subdev = &info->sasd.asd;
+
+ /* Or shall this be managed by the soc-camera device? */
+ sasc = &info->sasc;
+
+ /* HACK: just need a != NULL */
+ sdesc.host_desc.board_info = ERR_PTR(-ENODATA);
+
+ ret = soc_camera_dyn_pdev(&sdesc, sasc);
+ if (ret < 0)
+ goto eallocpdev;
+
+ sasc->sensor = &info->sasd.asd;
+
+ icd = soc_camera_add_pdev(sasc);
+ if (!icd) {
+ ret = -ENOMEM;
+ goto eaddpdev;
+ }
+
+ sasc->notifier.subdevs = &info->subdev;
+ sasc->notifier.num_subdevs = 1;
+ sasc->notifier.bound = soc_camera_async_bound;
+ sasc->notifier.unbind = soc_camera_async_unbind;
+ sasc->notifier.complete = soc_camera_async_complete;
+
+ icd->sasc = sasc;
+ icd->parent = ici->v4l2_dev.dev;
+
+ client = of_find_i2c_device_by_node(remote);
+
+ if (client)
+ snprintf(clk_name, sizeof(clk_name), "%d-%04x",
+ client->adapter->nr, client->addr);
+ else
+ snprintf(clk_name, sizeof(clk_name), "of-%s",
+ of_node_full_name(remote));
+
+ icd->clk = v4l2_clk_register(&soc_camera_clk_ops, clk_name, "mclk", icd);
+ if (IS_ERR(icd->clk)) {
+ ret = PTR_ERR(icd->clk);
+ goto eclkreg;
+ }
+
+ ret = v4l2_async_notifier_register(&ici->v4l2_dev, &sasc->notifier);
+ if (!ret)
+ return 0;
+eclkreg:
+ icd->clk = NULL;
+ platform_device_del(sasc->pdev);
+eaddpdev:
+ platform_device_put(sasc->pdev);
+eallocpdev:
+ devm_kfree(ici->v4l2_dev.dev, sasc);
+ dev_err(ici->v4l2_dev.dev, "group probe failed: %d\n", ret);
+
+ return ret;
+}
+
+static void scan_of_host(struct soc_camera_host *ici)
+{
+ struct device *dev = ici->v4l2_dev.dev;
+ struct device_node *np = dev->of_node;
+ struct device_node *epn = NULL, *ren;
+ unsigned int i;
+
+ for (i = 0; ; i++) {
+ epn = of_graph_get_next_endpoint(np, epn);
+ if (!epn)
+ break;
+
+ ren = of_graph_get_remote_port(epn);
+ if (!ren) {
+ dev_notice(dev, "no remote for %s\n",
+ of_node_full_name(epn));
+ continue;
+ }
+
+ /* so we now have a remote node to connect */
+ if (!i)
+ soc_of_bind(ici, epn, ren->parent);
+
+ of_node_put(epn);
+ of_node_put(ren);
+
+ if (i) {
+ dev_err(dev, "multiple subdevices aren't supported yet!\n");
+ break;
+ }
+ }
+}
+
+#else
+static inline void scan_of_host(struct soc_camera_host *ici) { }
+#endif
+
/* Called during host-driver probe */
static int soc_camera_probe(struct soc_camera_host *ici,
struct soc_camera_device *icd)
@@ -1832,7 +1961,9 @@ int soc_camera_host_register(struct soc_camera_host *ici)
mutex_init(&ici->host_lock);
mutex_init(&ici->clk_lock);
- if (ici->asd_sizes)
+ if (ici->v4l2_dev.dev->of_node)
+ scan_of_host(ici);
+ else if (ici->asd_sizes)
/*
* No OF, host with a list of subdevices. Don't try to mix
* modes by initialising some groups statically and some
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c
index 470d35336119..91d44ea16f27 100644
--- a/drivers/media/platform/vino.c
+++ b/drivers/media/platform/vino.c
@@ -3147,7 +3147,6 @@ static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
pf->colorspace =
vino_data_formats[tempvcs.data_format].colorspace;
- pf->priv = 0;
return 0;
}
@@ -3175,8 +3174,6 @@ static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
pf->colorspace =
vino_data_formats[vcs->data_format].colorspace;
- pf->priv = 0;
-
spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
@@ -3219,8 +3216,6 @@ static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
pf->colorspace =
vino_data_formats[vcs->data_format].colorspace;
- pf->priv = 0;
-
spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
return 0;
}
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index d00bf3df0f8a..80333714ffa7 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -648,13 +648,13 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
gen_text(dev, vbuf, line++ * 16, 16, str);
snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ",
dev->int32->cur.val,
- dev->int64->cur.val64,
+ *dev->int64->p_cur.p_s64,
dev->bitmask->cur.val);
gen_text(dev, vbuf, line++ * 16, 16, str);
snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
dev->boolean->cur.val,
dev->menu->qmenu[dev->menu->cur.val],
- dev->string->cur.string);
+ dev->string->p_cur.p_char);
gen_text(dev, vbuf, line++ * 16, 16, str);
snprintf(str, sizeof(str), " integer_menu %lld, value %d ",
dev->int_menu->qmenu_int[dev->int_menu->cur.val],
@@ -1014,7 +1014,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
else
f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1236,7 +1235,7 @@ static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
.id = VIVI_CID_CUSTOM_BASE + 2,
.name = "Integer 32 Bits",
.type = V4L2_CTRL_TYPE_INTEGER,
- .min = 0x80000000,
+ .min = -0x80000000LL,
.max = 0x7fffffff,
.step = 1,
};
@@ -1246,6 +1245,9 @@ static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
.id = VIVI_CID_CUSTOM_BASE + 3,
.name = "Integer 64 Bits",
.type = V4L2_CTRL_TYPE_INTEGER64,
+ .min = LLONG_MIN,
+ .max = LLONG_MAX,
+ .step = 1,
};
static const char * const vivi_ctrl_menu_strings[] = {
@@ -1459,7 +1461,6 @@ static int __init vivi_create_instance(int inst)
vfd->debug = debug;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->queue = q;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
/*
* Provide a mutex to v4l2 core. It will be used to protect
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 6ca2cf20d545..12467191dff4 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -36,9 +36,9 @@ struct vsp1_rwpf;
struct vsp1_sru;
struct vsp1_uds;
-#define VPS1_MAX_RPF 5
-#define VPS1_MAX_UDS 3
-#define VPS1_MAX_WPF 4
+#define VSP1_MAX_RPF 5
+#define VSP1_MAX_UDS 3
+#define VSP1_MAX_WPF 4
struct vsp1_device {
struct device *dev;
@@ -55,10 +55,10 @@ struct vsp1_device {
struct vsp1_hsit *hst;
struct vsp1_lif *lif;
struct vsp1_lut *lut;
- struct vsp1_rwpf *rpf[VPS1_MAX_RPF];
+ struct vsp1_rwpf *rpf[VSP1_MAX_RPF];
struct vsp1_sru *sru;
- struct vsp1_uds *uds[VPS1_MAX_UDS];
- struct vsp1_rwpf *wpf[VPS1_MAX_WPF];
+ struct vsp1_uds *uds[VSP1_MAX_UDS];
+ struct vsp1_rwpf *wpf[VSP1_MAX_WPF];
struct list_head entities;
@@ -66,7 +66,7 @@ struct vsp1_device {
struct media_device media_dev;
};
-struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1);
+int vsp1_device_get(struct vsp1_device *vsp1);
void vsp1_device_put(struct vsp1_device *vsp1);
static inline u32 vsp1_read(struct vsp1_device *vsp1, u32 reg)
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index f80695480060..a0c1984c733e 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -18,6 +18,7 @@
#include "vsp1.h"
#include "vsp1_bru.h"
+#include "vsp1_rwpf.h"
#define BRU_MIN_SIZE 4U
#define BRU_MAX_SIZE 8190U
@@ -36,20 +37,48 @@ static inline void vsp1_bru_write(struct vsp1_bru *bru, u32 reg, u32 data)
vsp1_write(bru->entity.vsp1, reg, data);
}
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int bru_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vsp1_bru *bru =
+ container_of(ctrl->handler, struct vsp1_bru, ctrls);
+
+ if (!vsp1_entity_is_streaming(&bru->entity))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BG_COLOR:
+ vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL, ctrl->val |
+ (0xff << VI6_BRU_VIRRPF_COL_A_SHIFT));
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops bru_ctrl_ops = {
+ .s_ctrl = bru_s_ctrl,
+};
+
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Core Operations
*/
-static bool bru_is_input_enabled(struct vsp1_bru *bru, unsigned int input)
-{
- return media_entity_remote_pad(&bru->entity.pads[input]) != NULL;
-}
-
static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
{
+ struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
struct vsp1_bru *bru = to_bru(subdev);
struct v4l2_mbus_framefmt *format;
+ unsigned int flags;
unsigned int i;
+ int ret;
+
+ ret = vsp1_entity_set_streaming(&bru->entity, enable);
+ if (ret < 0)
+ return ret;
if (!enable)
return 0;
@@ -62,18 +91,19 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
* to sane default values for now.
*/
- /* Disable both color data normalization and dithering. */
- vsp1_bru_write(bru, VI6_BRU_INCTRL, 0);
-
- /* Set the background position to cover the whole output image and
- * set its color to opaque black.
+ /* Disable dithering and enable color data normalization unless the
+ * format at the pipeline output is premultiplied.
*/
+ flags = pipe->output ? pipe->output->video.format.flags : 0;
+ vsp1_bru_write(bru, VI6_BRU_INCTRL,
+ flags & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA ?
+ 0 : VI6_BRU_INCTRL_NRM);
+
+ /* Set the background position to cover the whole output image. */
vsp1_bru_write(bru, VI6_BRU_VIRRPF_SIZE,
(format->width << VI6_BRU_VIRRPF_SIZE_HSIZE_SHIFT) |
(format->height << VI6_BRU_VIRRPF_SIZE_VSIZE_SHIFT));
vsp1_bru_write(bru, VI6_BRU_VIRRPF_LOC, 0);
- vsp1_bru_write(bru, VI6_BRU_VIRRPF_COL,
- 0xff << VI6_BRU_VIRRPF_COL_A_SHIFT);
/* Route BRU input 1 as SRC input to the ROP unit and configure the ROP
* unit with a NOP operation to make BRU input 1 available as the
@@ -84,6 +114,7 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
VI6_BRU_ROP_AROP(VI6_ROP_NOP));
for (i = 0; i < 4; ++i) {
+ bool premultiplied = false;
u32 ctrl = 0;
/* Configure all Blend/ROP units corresponding to an enabled BRU
@@ -91,11 +122,15 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
* disabled BRU inputs are used in ROP NOP mode to ignore the
* SRC input.
*/
- if (bru_is_input_enabled(bru, i))
+ if (bru->inputs[i].rpf) {
ctrl |= VI6_BRU_CTRL_RBC;
- else
+
+ premultiplied = bru->inputs[i].rpf->video.format.flags
+ & V4L2_PIX_FMT_FLAG_PREMUL_ALPHA;
+ } else {
ctrl |= VI6_BRU_CTRL_CROP(VI6_ROP_NOP)
| VI6_BRU_CTRL_AROP(VI6_ROP_NOP);
+ }
/* Select the virtual RPF as the Blend/ROP unit A DST input to
* serve as a background color.
@@ -117,10 +152,18 @@ static int bru_s_stream(struct v4l2_subdev *subdev, int enable)
*
* DSTc = DSTc * (1 - SRCa) + SRCc * SRCa
* DSTa = DSTa * (1 - SRCa) + SRCa
+ *
+ * when the SRC input isn't premultiplied, and to
+ *
+ * DSTc = DSTc * (1 - SRCa) + SRCc
+ * DSTa = DSTa * (1 - SRCa) + SRCa
+ *
+ * otherwise.
*/
vsp1_bru_write(bru, VI6_BRU_BLD(i),
VI6_BRU_BLD_CCMDX_255_SRC_A |
- VI6_BRU_BLD_CCMDY_SRC_A |
+ (premultiplied ? VI6_BRU_BLD_CCMDY_COEFY :
+ VI6_BRU_BLD_CCMDY_SRC_A) |
VI6_BRU_BLD_ACMDX_255_SRC_A |
VI6_BRU_BLD_ACMDY_COEFY |
(0xff << VI6_BRU_BLD_COEFY_SHIFT));
@@ -192,7 +235,7 @@ static struct v4l2_rect *bru_get_compose(struct vsp1_bru *bru,
case V4L2_SUBDEV_FORMAT_TRY:
return v4l2_subdev_get_try_crop(fh, pad);
case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &bru->compose[pad];
+ return &bru->inputs[pad].compose;
default:
return NULL;
}
@@ -391,5 +434,19 @@ struct vsp1_bru *vsp1_bru_create(struct vsp1_device *vsp1)
vsp1_entity_init_formats(subdev, NULL);
+ /* Initialize the control handler. */
+ v4l2_ctrl_handler_init(&bru->ctrls, 1);
+ v4l2_ctrl_new_std(&bru->ctrls, &bru_ctrl_ops, V4L2_CID_BG_COLOR,
+ 0, 0xffffff, 1, 0);
+
+ bru->entity.subdev.ctrl_handler = &bru->ctrls;
+
+ if (bru->ctrls.error) {
+ dev_err(vsp1->dev, "bru: failed to initialize controls\n");
+ ret = bru->ctrls.error;
+ vsp1_entity_destroy(&bru->entity);
+ return ERR_PTR(ret);
+ }
+
return bru;
}
diff --git a/drivers/media/platform/vsp1/vsp1_bru.h b/drivers/media/platform/vsp1/vsp1_bru.h
index 37062704dbf6..16b1c6554911 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.h
+++ b/drivers/media/platform/vsp1/vsp1_bru.h
@@ -14,11 +14,13 @@
#define __VSP1_BRU_H__
#include
+#include
#include
#include "vsp1_entity.h"
struct vsp1_device;
+struct vsp1_rwpf;
#define BRU_PAD_SINK(n) (n)
#define BRU_PAD_SOURCE 4
@@ -26,7 +28,12 @@ struct vsp1_device;
struct vsp1_bru {
struct vsp1_entity entity;
- struct v4l2_rect compose[4];
+ struct v4l2_ctrl_handler ctrls;
+
+ struct {
+ struct vsp1_rwpf *rpf;
+ struct v4l2_rect compose;
+ } inputs[4];
};
static inline struct vsp1_bru *to_bru(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index c69ee0657f75..3e6601b5b4de 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -345,36 +345,32 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
* Increment the VSP1 reference count and initialize the device if the first
* reference is taken.
*
- * Return a pointer to the VSP1 device or NULL if an error occurred.
+ * Return 0 on success or a negative error code otherwise.
*/
-struct vsp1_device *vsp1_device_get(struct vsp1_device *vsp1)
+int vsp1_device_get(struct vsp1_device *vsp1)
{
- struct vsp1_device *__vsp1 = vsp1;
- int ret;
+ int ret = 0;
mutex_lock(&vsp1->lock);
if (vsp1->ref_count > 0)
goto done;
ret = clk_prepare_enable(vsp1->clock);
- if (ret < 0) {
- __vsp1 = NULL;
+ if (ret < 0)
goto done;
- }
ret = vsp1_device_init(vsp1);
if (ret < 0) {
clk_disable_unprepare(vsp1->clock);
- __vsp1 = NULL;
goto done;
}
done:
- if (__vsp1)
+ if (!ret)
vsp1->ref_count++;
mutex_unlock(&vsp1->lock);
- return __vsp1;
+ return ret;
}
/*
@@ -440,19 +436,19 @@ static int vsp1_validate_platform_data(struct platform_device *pdev,
return -EINVAL;
}
- if (pdata->rpf_count <= 0 || pdata->rpf_count > VPS1_MAX_RPF) {
+ if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) {
dev_err(&pdev->dev, "invalid number of RPF (%u)\n",
pdata->rpf_count);
return -EINVAL;
}
- if (pdata->uds_count <= 0 || pdata->uds_count > VPS1_MAX_UDS) {
+ if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) {
dev_err(&pdev->dev, "invalid number of UDS (%u)\n",
pdata->uds_count);
return -EINVAL;
}
- if (pdata->wpf_count <= 0 || pdata->wpf_count > VPS1_MAX_WPF) {
+ if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) {
dev_err(&pdev->dev, "invalid number of WPF (%u)\n",
pdata->wpf_count);
return -EINVAL;
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 44167834285d..79af71d5e270 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -20,6 +20,42 @@
#include "vsp1.h"
#include "vsp1_entity.h"
+#include "vsp1_video.h"
+
+bool vsp1_entity_is_streaming(struct vsp1_entity *entity)
+{
+ bool streaming;
+
+ mutex_lock(&entity->lock);
+ streaming = entity->streaming;
+ mutex_unlock(&entity->lock);
+
+ return streaming;
+}
+
+int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming)
+{
+ int ret;
+
+ mutex_lock(&entity->lock);
+ entity->streaming = streaming;
+ mutex_unlock(&entity->lock);
+
+ if (!streaming)
+ return 0;
+
+ if (!entity->subdev.ctrl_handler)
+ return 0;
+
+ ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler);
+ if (ret < 0) {
+ mutex_lock(&entity->lock);
+ entity->streaming = false;
+ mutex_unlock(&entity->lock);
+ }
+
+ return ret;
+}
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
@@ -157,6 +193,8 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
if (i == ARRAY_SIZE(vsp1_routes))
return -EINVAL;
+ mutex_init(&entity->lock);
+
entity->vsp1 = vsp1;
entity->source_pad = num_pads - 1;
@@ -185,7 +223,11 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
void vsp1_entity_destroy(struct vsp1_entity *entity)
{
+ if (entity->video)
+ vsp1_video_cleanup(entity->video);
if (entity->subdev.ctrl_handler)
v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
media_entity_cleanup(&entity->subdev.entity);
+
+ mutex_destroy(&entity->lock);
}
diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h
index 7afbd8a7ba66..aa20aaa58208 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/vsp1/vsp1_entity.h
@@ -14,10 +14,12 @@
#define __VSP1_ENTITY_H__
#include
+#include
#include
struct vsp1_device;
+struct vsp1_video;
enum vsp1_entity_type {
VSP1_ENTITY_BRU,
@@ -68,6 +70,11 @@ struct vsp1_entity {
struct v4l2_subdev subdev;
struct v4l2_mbus_framefmt *formats;
+
+ struct vsp1_video *video;
+
+ struct mutex lock; /* Protects the streaming field */
+ bool streaming;
};
static inline struct vsp1_entity *to_vsp1_entity(struct v4l2_subdev *subdev)
@@ -89,4 +96,7 @@ vsp1_entity_get_pad_format(struct vsp1_entity *entity,
void vsp1_entity_init_formats(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh);
+bool vsp1_entity_is_streaming(struct vsp1_entity *entity);
+int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming);
+
#endif /* __VSP1_ENTITY_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 3e74b44286f6..55f163d32d15 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -336,7 +336,9 @@
*/
#define VI6_SRU_CTRL0 0x2200
+#define VI6_SRU_CTRL0_PARAM0_MASK (0x1ff << 16)
#define VI6_SRU_CTRL0_PARAM0_SHIFT 16
+#define VI6_SRU_CTRL0_PARAM1_MASK (0x1f << 8)
#define VI6_SRU_CTRL0_PARAM1_SHIFT 8
#define VI6_SRU_CTRL0_MODE_UPSCALE (4 << 4)
#define VI6_SRU_CTRL0_PARAM2 (1 << 3)
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index c3d98642a4aa..d14d26b718ef 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -38,6 +38,36 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf, u32 reg, u32 data)
reg + rpf->entity.index * VI6_RPF_OFFSET, data);
}
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int rpf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vsp1_rwpf *rpf =
+ container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
+ struct vsp1_pipeline *pipe;
+
+ if (!vsp1_entity_is_streaming(&rpf->entity))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ALPHA_COMPONENT:
+ vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
+ ctrl->val << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+
+ pipe = to_vsp1_pipeline(&rpf->entity.subdev.entity);
+ vsp1_pipeline_propagate_alpha(pipe, &rpf->entity, ctrl->val);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops rpf_ctrl_ops = {
+ .s_ctrl = rpf_s_ctrl,
+};
+
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Core Operations
*/
@@ -50,6 +80,11 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
const struct v4l2_rect *crop = &rpf->crop;
u32 pstride;
u32 infmt;
+ int ret;
+
+ ret = vsp1_entity_set_streaming(&rpf->entity, enable);
+ if (ret < 0)
+ return ret;
if (!enable)
return 0;
@@ -101,12 +136,13 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
(rpf->location.left << VI6_RPF_LOC_HCOORD_SHIFT) |
(rpf->location.top << VI6_RPF_LOC_VCOORD_SHIFT));
- /* Disable alpha, mask and color key. Set the alpha channel to a fixed
- * value of 255.
+ /* Use the alpha channel (extended to 8 bits) when available or an
+ * alpha value set through the V4L2_CID_ALPHA_COMPONENT control
+ * otherwise. Disable color keying.
*/
- vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_ASEL_FIXED);
- vsp1_rpf_write(rpf, VI6_RPF_VRTCOL_SET,
- 255 << VI6_RPF_VRTCOL_SET_LAYA_SHIFT);
+ vsp1_rpf_write(rpf, VI6_RPF_ALPH_SEL, VI6_RPF_ALPH_SEL_AEXT_EXT |
+ (fmtinfo->alpha ? VI6_RPF_ALPH_SEL_ASEL_PACKED
+ : VI6_RPF_ALPH_SEL_ASEL_FIXED));
vsp1_rpf_write(rpf, VI6_RPF_MSK_CTRL, 0);
vsp1_rpf_write(rpf, VI6_RPF_CKEY_CTRL, 0);
@@ -196,6 +232,20 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
vsp1_entity_init_formats(subdev, NULL);
+ /* Initialize the control handler. */
+ v4l2_ctrl_handler_init(&rpf->ctrls, 1);
+ v4l2_ctrl_new_std(&rpf->ctrls, &rpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
+ 0, 255, 1, 255);
+
+ rpf->entity.subdev.ctrl_handler = &rpf->ctrls;
+
+ if (rpf->ctrls.error) {
+ dev_err(vsp1->dev, "rpf%u: failed to initialize controls\n",
+ index);
+ ret = rpf->ctrls.error;
+ goto error;
+ }
+
/* Initialize the video device. */
video = &rpf->video;
@@ -205,7 +255,9 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
ret = vsp1_video_init(video, &rpf->entity);
if (ret < 0)
- goto error_video;
+ goto error;
+
+ rpf->entity.video = video;
/* Connect the video device to the RPF. */
ret = media_entity_create_link(&rpf->video.video.entity, 0,
@@ -214,13 +266,11 @@ struct vsp1_rwpf *vsp1_rpf_create(struct vsp1_device *vsp1, unsigned int index)
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (ret < 0)
- goto error_link;
+ goto error;
return rpf;
-error_link:
- vsp1_video_cleanup(video);
-error_video:
- media_entity_cleanup(&rpf->entity.subdev.entity);
+error:
+ vsp1_entity_destroy(&rpf->entity);
return ERR_PTR(ret);
}
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index b4fb65e58770..28dd9e7b3838 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -14,6 +14,7 @@
#define __VSP1_RWPF_H__
#include
+#include
#include
#include "vsp1.h"
@@ -26,6 +27,7 @@
struct vsp1_rwpf {
struct vsp1_entity entity;
struct vsp1_video video;
+ struct v4l2_ctrl_handler ctrls;
unsigned int max_width;
unsigned int max_height;
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index aa0e04c56f3f..b7d3c8b9f189 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -42,38 +42,6 @@ static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
#define V4L2_CID_VSP1_SRU_INTENSITY (V4L2_CID_USER_BASE + 1)
-static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vsp1_sru *sru =
- container_of(ctrl->handler, struct vsp1_sru, ctrls);
-
- switch (ctrl->id) {
- case V4L2_CID_VSP1_SRU_INTENSITY:
- sru->intensity = ctrl->val;
- break;
- }
-
- return 0;
-}
-
-static const struct v4l2_ctrl_ops sru_ctrl_ops = {
- .s_ctrl = sru_s_ctrl,
-};
-
-static const struct v4l2_ctrl_config sru_intensity_control = {
- .ops = &sru_ctrl_ops,
- .id = V4L2_CID_VSP1_SRU_INTENSITY,
- .name = "Intensity",
- .type = V4L2_CTRL_TYPE_INTEGER,
- .min = 1,
- .max = 6,
- .step = 1,
-};
-
-/* -----------------------------------------------------------------------------
- * V4L2 Subdevice Core Operations
- */
-
struct vsp1_sru_param {
u32 ctrl0;
u32 ctrl2;
@@ -110,22 +78,66 @@ static const struct vsp1_sru_param vsp1_sru_params[] = {
},
};
+static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vsp1_sru *sru =
+ container_of(ctrl->handler, struct vsp1_sru, ctrls);
+ const struct vsp1_sru_param *param;
+ u32 value;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VSP1_SRU_INTENSITY:
+ param = &vsp1_sru_params[ctrl->val - 1];
+
+ value = vsp1_sru_read(sru, VI6_SRU_CTRL0);
+ value &= ~(VI6_SRU_CTRL0_PARAM0_MASK |
+ VI6_SRU_CTRL0_PARAM1_MASK);
+ value |= param->ctrl0;
+ vsp1_sru_write(sru, VI6_SRU_CTRL0, value);
+
+ vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops sru_ctrl_ops = {
+ .s_ctrl = sru_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config sru_intensity_control = {
+ .ops = &sru_ctrl_ops,
+ .id = V4L2_CID_VSP1_SRU_INTENSITY,
+ .name = "Intensity",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .min = 1,
+ .max = 6,
+ .def = 1,
+ .step = 1,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Core Operations
+ */
+
static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
{
struct vsp1_sru *sru = to_sru(subdev);
- const struct vsp1_sru_param *param;
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- bool upscale;
u32 ctrl0;
+ int ret;
+
+ ret = vsp1_entity_set_streaming(&sru->entity, enable);
+ if (ret < 0)
+ return ret;
if (!enable)
return 0;
input = &sru->entity.formats[SRU_PAD_SINK];
output = &sru->entity.formats[SRU_PAD_SOURCE];
- upscale = input->width != output->width;
- param = &vsp1_sru_params[sru->intensity];
if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32)
ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
@@ -133,10 +145,18 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
else
ctrl0 = VI6_SRU_CTRL0_PARAM3;
- vsp1_sru_write(sru, VI6_SRU_CTRL0, param->ctrl0 | ctrl0 |
- (upscale ? VI6_SRU_CTRL0_MODE_UPSCALE : 0));
+ if (input->width != output->width)
+ ctrl0 |= VI6_SRU_CTRL0_MODE_UPSCALE;
+
+ /* Take the control handler lock to ensure that the CTRL0 value won't be
+ * changed behind our back by a set control operation.
+ */
+ mutex_lock(sru->ctrls.lock);
+ ctrl0 |= vsp1_sru_read(sru, VI6_SRU_CTRL0)
+ & (VI6_SRU_CTRL0_PARAM0_MASK | VI6_SRU_CTRL0_PARAM1_MASK);
+ mutex_unlock(sru->ctrls.lock);
+
vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
- vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
return 0;
}
@@ -348,8 +368,15 @@ struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&sru->ctrls, 1);
v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
- v4l2_ctrl_handler_setup(&sru->ctrls);
+
sru->entity.subdev.ctrl_handler = &sru->ctrls;
+ if (sru->ctrls.error) {
+ dev_err(vsp1->dev, "sru: failed to initialize controls\n");
+ ret = sru->ctrls.error;
+ vsp1_entity_destroy(&sru->entity);
+ return ERR_PTR(ret);
+ }
+
return sru;
}
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h
index 381870b74780..b6768bf3dc47 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.h
+++ b/drivers/media/platform/vsp1/vsp1_sru.h
@@ -28,7 +28,6 @@ struct vsp1_sru {
struct vsp1_entity entity;
struct v4l2_ctrl_handler ctrls;
- unsigned int intensity;
};
static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index 0293bdbb4401..de92ef4944b3 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -45,6 +45,11 @@ static inline void vsp1_uds_write(struct vsp1_uds *uds, u32 reg, u32 data)
* Scaling Computation
*/
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha)
+{
+ vsp1_uds_write(uds, VI6_UDS_ALPVAL, alpha << VI6_UDS_ALPVAL_VAL0_SHIFT);
+}
+
/*
* uds_output_size - Return the output size for an input size and scaling ratio
* @input: input size in pixels
@@ -105,49 +110,56 @@ static unsigned int uds_compute_ratio(unsigned int input, unsigned int output)
return (input - 1) * 4096 / (output - 1);
}
-static void uds_compute_ratios(struct vsp1_uds *uds)
-{
- struct v4l2_mbus_framefmt *input = &uds->entity.formats[UDS_PAD_SINK];
- struct v4l2_mbus_framefmt *output =
- &uds->entity.formats[UDS_PAD_SOURCE];
-
- uds->hscale = uds_compute_ratio(input->width, output->width);
- uds->vscale = uds_compute_ratio(input->height, output->height);
-
- dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n",
- uds->hscale, uds->vscale);
-}
-
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Core Operations
*/
static int uds_s_stream(struct v4l2_subdev *subdev, int enable)
{
- const struct v4l2_mbus_framefmt *format;
struct vsp1_uds *uds = to_uds(subdev);
+ const struct v4l2_mbus_framefmt *output;
+ const struct v4l2_mbus_framefmt *input;
+ unsigned int hscale;
+ unsigned int vscale;
+ bool multitap;
if (!enable)
return 0;
- /* Enable multi-tap scaling. */
- vsp1_uds_write(uds, VI6_UDS_CTRL, VI6_UDS_CTRL_AON | VI6_UDS_CTRL_BC);
+ input = &uds->entity.formats[UDS_PAD_SINK];
+ output = &uds->entity.formats[UDS_PAD_SOURCE];
+
+ hscale = uds_compute_ratio(input->width, output->width);
+ vscale = uds_compute_ratio(input->height, output->height);
+
+ dev_dbg(uds->entity.vsp1->dev, "hscale %u vscale %u\n", hscale, vscale);
+
+ /* Multi-tap scaling can't be enabled along with alpha scaling when
+ * scaling down with a factor lower than or equal to 1/2 in either
+ * direction.
+ */
+ if (uds->scale_alpha && (hscale >= 8192 || vscale >= 8192))
+ multitap = false;
+ else
+ multitap = true;
+
+ vsp1_uds_write(uds, VI6_UDS_CTRL,
+ (uds->scale_alpha ? VI6_UDS_CTRL_AON : 0) |
+ (multitap ? VI6_UDS_CTRL_BC : 0));
vsp1_uds_write(uds, VI6_UDS_PASS_BWIDTH,
- (uds_passband_width(uds->hscale)
+ (uds_passband_width(hscale)
<< VI6_UDS_PASS_BWIDTH_H_SHIFT) |
- (uds_passband_width(uds->vscale)
+ (uds_passband_width(vscale)
<< VI6_UDS_PASS_BWIDTH_V_SHIFT));
/* Set the scaling ratios and the output size. */
- format = &uds->entity.formats[UDS_PAD_SOURCE];
-
vsp1_uds_write(uds, VI6_UDS_SCALE,
- (uds->hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
- (uds->vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
+ (hscale << VI6_UDS_SCALE_HFRAC_SHIFT) |
+ (vscale << VI6_UDS_SCALE_VFRAC_SHIFT));
vsp1_uds_write(uds, VI6_UDS_CLIP_SIZE,
- (format->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
- (format->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
+ (output->width << VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
+ (output->height << VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
return 0;
}
@@ -280,9 +292,6 @@ static int uds_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
uds_try_format(uds, fh, UDS_PAD_SOURCE, format, fmt->which);
}
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- uds_compute_ratios(uds);
-
return 0;
}
diff --git a/drivers/media/platform/vsp1/vsp1_uds.h b/drivers/media/platform/vsp1/vsp1_uds.h
index 479d12df1180..031ac0da1b66 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.h
+++ b/drivers/media/platform/vsp1/vsp1_uds.h
@@ -25,9 +25,7 @@ struct vsp1_device;
struct vsp1_uds {
struct vsp1_entity entity;
-
- unsigned int hscale;
- unsigned int vscale;
+ bool scale_alpha;
};
static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
@@ -37,4 +35,6 @@ static inline struct vsp1_uds *to_uds(struct v4l2_subdev *subdev)
struct vsp1_uds *vsp1_uds_create(struct vsp1_device *vsp1, unsigned int index);
+void vsp1_uds_set_alpha(struct vsp1_uds *uds, unsigned int alpha);
+
#endif /* __VSP1_UDS_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 8a1253e51f04..915a20eb003e 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -31,6 +31,7 @@
#include "vsp1_bru.h"
#include "vsp1_entity.h"
#include "vsp1_rwpf.h"
+#include "vsp1_uds.h"
#include "vsp1_video.h"
#define VSP1_VIDEO_DEF_FORMAT V4L2_PIX_FMT_YUYV
@@ -50,70 +51,85 @@ static const struct vsp1_format_info vsp1_video_formats[] = {
{ V4L2_PIX_FMT_RGB332, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 8, 0, 0 }, false, false, 1, 1 },
- { V4L2_PIX_FMT_RGB444, V4L2_MBUS_FMT_ARGB8888_1X32,
+ 1, { 8, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ARGB444, V4L2_MBUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XRGB444, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1 },
- { V4L2_PIX_FMT_RGB555, V4L2_MBUS_FMT_ARGB8888_1X32,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_ARGB555, V4L2_MBUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS,
+ 1, { 16, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XRGB555, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1 },
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_RGB565, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
- 1, { 16, 0, 0 }, false, false, 1, 1 },
+ 1, { 16, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_BGR24, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 24, 0, 0 }, false, false, 1, 1 },
+ 1, { 24, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_RGB24, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 24, 0, 0 }, false, false, 1, 1 },
- { V4L2_PIX_FMT_BGR32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ 1, { 24, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ABGR32, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
- 1, { 32, 0, 0 }, false, false, 1, 1 },
- { V4L2_PIX_FMT_RGB32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ 1, { 32, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XBGR32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
+ { V4L2_PIX_FMT_ARGB32, V4L2_MBUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 32, 0, 0 }, false, false, 1, 1 },
+ 1, { 32, 0, 0 }, false, false, 1, 1, true },
+ { V4L2_PIX_FMT_XRGB32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
+ VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
+ 1, { 32, 0, 0 }, false, false, 1, 1, false },
{ V4L2_PIX_FMT_UYVY, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, false, false, 2, 1 },
+ 1, { 16, 0, 0 }, false, false, 2, 1, false },
{ V4L2_PIX_FMT_VYUY, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, false, true, 2, 1 },
+ 1, { 16, 0, 0 }, false, true, 2, 1, false },
{ V4L2_PIX_FMT_YUYV, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, true, false, 2, 1 },
+ 1, { 16, 0, 0 }, true, false, 2, 1, false },
{ V4L2_PIX_FMT_YVYU, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 1, { 16, 0, 0 }, true, true, 2, 1 },
+ 1, { 16, 0, 0 }, true, true, 2, 1, false },
{ V4L2_PIX_FMT_NV12M, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, false, 2, 2 },
+ 2, { 8, 16, 0 }, false, false, 2, 2, false },
{ V4L2_PIX_FMT_NV21M, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, true, 2, 2 },
+ 2, { 8, 16, 0 }, false, true, 2, 2, false },
{ V4L2_PIX_FMT_NV16M, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, false, 2, 1 },
+ 2, { 8, 16, 0 }, false, false, 2, 1, false },
{ V4L2_PIX_FMT_NV61M, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 2, { 8, 16, 0 }, false, true, 2, 1 },
+ 2, { 8, 16, 0 }, false, true, 2, 1, false },
{ V4L2_PIX_FMT_YUV420M, V4L2_MBUS_FMT_AYUV8_1X32,
VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
- 3, { 8, 8, 8 }, false, false, 2, 2 },
+ 3, { 8, 8, 8 }, false, false, 2, 2, false },
};
/*
@@ -181,11 +197,29 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
struct v4l2_pix_format_mplane *pix,
const struct vsp1_format_info **fmtinfo)
{
+ static const u32 xrgb_formats[][2] = {
+ { V4L2_PIX_FMT_RGB444, V4L2_PIX_FMT_XRGB444 },
+ { V4L2_PIX_FMT_RGB555, V4L2_PIX_FMT_XRGB555 },
+ { V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_XBGR32 },
+ { V4L2_PIX_FMT_RGB32, V4L2_PIX_FMT_XRGB32 },
+ };
+
const struct vsp1_format_info *info;
unsigned int width = pix->width;
unsigned int height = pix->height;
unsigned int i;
+ /* Backward compatibility: replace deprecated RGB formats by their XRGB
+ * equivalent. This selects the format older userspace applications want
+ * while still exposing the new format.
+ */
+ for (i = 0; i < ARRAY_SIZE(xrgb_formats); ++i) {
+ if (xrgb_formats[i][0] == pix->pixelformat) {
+ pix->pixelformat = xrgb_formats[i][1];
+ break;
+ }
+ }
+
/* Retrieve format information and select the default format if the
* requested format isn't supported.
*/
@@ -273,13 +307,14 @@ vsp1_video_format_adjust(struct vsp1_video *video,
* Pipeline Management
*/
-static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
+static int vsp1_pipeline_validate_branch(struct vsp1_pipeline *pipe,
+ struct vsp1_rwpf *input,
struct vsp1_rwpf *output)
{
struct vsp1_entity *entity;
unsigned int entities = 0;
struct media_pad *pad;
- bool uds_found = false;
+ bool bru_found = false;
input->location.left = 0;
input->location.top = 0;
@@ -301,10 +336,15 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
*/
if (entity->type == VSP1_ENTITY_BRU) {
struct vsp1_bru *bru = to_bru(&entity->subdev);
- struct v4l2_rect *rect = &bru->compose[pad->index];
+ struct v4l2_rect *rect =
+ &bru->inputs[pad->index].compose;
+
+ bru->inputs[pad->index].rpf = input;
input->location.left = rect->left;
input->location.top = rect->top;
+
+ bru_found = true;
}
/* We've reached the WPF, we're done. */
@@ -319,9 +359,12 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
/* UDS can't be chained. */
if (entity->type == VSP1_ENTITY_UDS) {
- if (uds_found)
+ if (pipe->uds)
return -EPIPE;
- uds_found = true;
+
+ pipe->uds = entity;
+ pipe->uds_input = bru_found ? pipe->bru
+ : &input->entity;
}
/* Follow the source link. The link setup operations ensure
@@ -340,6 +383,27 @@ static int vsp1_pipeline_validate_branch(struct vsp1_rwpf *input,
return 0;
}
+static void __vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
+{
+ if (pipe->bru) {
+ struct vsp1_bru *bru = to_bru(&pipe->bru->subdev);
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(bru->inputs); ++i)
+ bru->inputs[i].rpf = NULL;
+ }
+
+ INIT_LIST_HEAD(&pipe->entities);
+ pipe->state = VSP1_PIPELINE_STOPPED;
+ pipe->buffers_ready = 0;
+ pipe->num_video = 0;
+ pipe->num_inputs = 0;
+ pipe->output = NULL;
+ pipe->bru = NULL;
+ pipe->lif = NULL;
+ pipe->uds = NULL;
+}
+
static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
struct vsp1_video *video)
{
@@ -395,7 +459,7 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
* contains no loop and that all branches end at the output WPF.
*/
for (i = 0; i < pipe->num_inputs; ++i) {
- ret = vsp1_pipeline_validate_branch(pipe->inputs[i],
+ ret = vsp1_pipeline_validate_branch(pipe, pipe->inputs[i],
pipe->output);
if (ret < 0)
goto error;
@@ -404,13 +468,7 @@ static int vsp1_pipeline_validate(struct vsp1_pipeline *pipe,
return 0;
error:
- INIT_LIST_HEAD(&pipe->entities);
- pipe->buffers_ready = 0;
- pipe->num_video = 0;
- pipe->num_inputs = 0;
- pipe->output = NULL;
- pipe->bru = NULL;
- pipe->lif = NULL;
+ __vsp1_pipeline_cleanup(pipe);
return ret;
}
@@ -441,16 +499,8 @@ static void vsp1_pipeline_cleanup(struct vsp1_pipeline *pipe)
mutex_lock(&pipe->lock);
/* If we're the last user clean up the pipeline. */
- if (--pipe->use_count == 0) {
- INIT_LIST_HEAD(&pipe->entities);
- pipe->state = VSP1_PIPELINE_STOPPED;
- pipe->buffers_ready = 0;
- pipe->num_video = 0;
- pipe->num_inputs = 0;
- pipe->output = NULL;
- pipe->bru = NULL;
- pipe->lif = NULL;
- }
+ if (--pipe->use_count == 0)
+ __vsp1_pipeline_cleanup(pipe);
mutex_unlock(&pipe->lock);
}
@@ -471,7 +521,8 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
int ret;
spin_lock_irqsave(&pipe->irqlock, flags);
- pipe->state = VSP1_PIPELINE_STOPPING;
+ if (pipe->state == VSP1_PIPELINE_RUNNING)
+ pipe->state = VSP1_PIPELINE_STOPPING;
spin_unlock_irqrestore(&pipe->irqlock, flags);
ret = wait_event_timeout(pipe->wq, pipe->state == VSP1_PIPELINE_STOPPED,
@@ -479,7 +530,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe)
ret = ret == 0 ? -ETIMEDOUT : 0;
list_for_each_entry(entity, &pipe->entities, list_pipe) {
- if (entity->route)
+ if (entity->route && entity->route->reg)
vsp1_write(entity->vsp1, entity->route->reg,
VI6_DPR_NODE_UNUSED);
@@ -576,6 +627,7 @@ static void vsp1_video_frame_end(struct vsp1_pipeline *pipe,
void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
{
+ enum vsp1_pipeline_state state;
unsigned long flags;
unsigned int i;
@@ -591,11 +643,13 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
spin_lock_irqsave(&pipe->irqlock, flags);
+ state = pipe->state;
+ pipe->state = VSP1_PIPELINE_STOPPED;
+
/* If a stop has been requested, mark the pipeline as stopped and
* return.
*/
- if (pipe->state == VSP1_PIPELINE_STOPPING) {
- pipe->state = VSP1_PIPELINE_STOPPED;
+ if (state == VSP1_PIPELINE_STOPPING) {
wake_up(&pipe->wq);
goto done;
}
@@ -608,6 +662,47 @@ done:
spin_unlock_irqrestore(&pipe->irqlock, flags);
}
+/*
+ * Propagate the alpha value through the pipeline.
+ *
+ * As the UDS has restricted scaling capabilities when the alpha component needs
+ * to be scaled, we disable alpha scaling when the UDS input has a fixed alpha
+ * value. The UDS then outputs a fixed alpha value which needs to be programmed
+ * from the input RPF alpha.
+ */
+void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
+ struct vsp1_entity *input,
+ unsigned int alpha)
+{
+ struct vsp1_entity *entity;
+ struct media_pad *pad;
+
+ pad = media_entity_remote_pad(&input->pads[RWPF_PAD_SOURCE]);
+
+ while (pad) {
+ if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+ break;
+
+ entity = to_vsp1_entity(media_entity_to_v4l2_subdev(pad->entity));
+
+ /* The BRU background color has a fixed alpha value set to 255,
+ * the output alpha value is thus always equal to 255.
+ */
+ if (entity->type == VSP1_ENTITY_BRU)
+ alpha = 255;
+
+ if (entity->type == VSP1_ENTITY_UDS) {
+ struct vsp1_uds *uds = to_uds(&entity->subdev);
+
+ vsp1_uds_set_alpha(uds, alpha);
+ break;
+ }
+
+ pad = &entity->pads[entity->source_pad];
+ pad = media_entity_remote_pad(pad);
+ }
+}
+
/* -----------------------------------------------------------------------------
* videobuf2 Queue Operations
*/
@@ -654,8 +749,6 @@ static int vsp1_video_buffer_prepare(struct vb2_buffer *vb)
if (vb->num_planes < format->num_planes)
return -EINVAL;
- buf->video = video;
-
for (i = 0; i < vb->num_planes; ++i) {
buf->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i);
buf->length[i] = vb2_plane_size(vb, i);
@@ -717,6 +810,25 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
mutex_lock(&pipe->lock);
if (pipe->stream_count == pipe->num_video - 1) {
+ if (pipe->uds) {
+ struct vsp1_uds *uds = to_uds(&pipe->uds->subdev);
+
+ /* If a BRU is present in the pipeline before the UDS,
+ * the alpha component doesn't need to be scaled as the
+ * BRU output alpha value is fixed to 255. Otherwise we
+ * need to scale the alpha component only when available
+ * at the input RPF.
+ */
+ if (pipe->uds_input->type == VSP1_ENTITY_BRU) {
+ uds->scale_alpha = false;
+ } else {
+ struct vsp1_rwpf *rpf =
+ to_rwpf(&pipe->uds_input->subdev);
+
+ uds->scale_alpha = rpf->video.fmtinfo->alpha;
+ }
+ }
+
list_for_each_entry(entity, &pipe->entities, list_pipe) {
vsp1_entity_route_setup(entity);
@@ -744,6 +856,7 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
{
struct vsp1_video *video = vb2_get_drv_priv(vq);
struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
+ struct vsp1_video_buffer *buffer;
unsigned long flags;
int ret;
@@ -761,6 +874,8 @@ static void vsp1_video_stop_streaming(struct vb2_queue *vq)
/* Remove all buffers from the IRQ queue. */
spin_lock_irqsave(&video->irqlock, flags);
+ list_for_each_entry(buffer, &video->irqqueue, queue)
+ vb2_buffer_done(&buffer->buf, VB2_BUF_STATE_ERROR);
INIT_LIST_HEAD(&video->irqqueue);
spin_unlock_irqrestore(&video->irqlock, flags);
}
@@ -950,8 +1065,8 @@ static int vsp1_video_open(struct file *file)
file->private_data = vfh;
- if (!vsp1_device_get(video->vsp1)) {
- ret = -EBUSY;
+ ret = vsp1_device_get(video->vsp1);
+ if (ret < 0) {
v4l2_fh_del(vfh);
kfree(vfh);
}
diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h
index c04d48fa2999..fd2851a82e00 100644
--- a/drivers/media/platform/vsp1/vsp1_video.h
+++ b/drivers/media/platform/vsp1/vsp1_video.h
@@ -33,6 +33,7 @@ struct vsp1_video;
* @swap_uv: the U and V components are swapped (V comes before U)
* @hsub: horizontal subsampling factor
* @vsub: vertical subsampling factor
+ * @alpha: has an alpha channel
*/
struct vsp1_format_info {
u32 fourcc;
@@ -45,6 +46,7 @@ struct vsp1_format_info {
bool swap_uv;
unsigned int hsub;
unsigned int vsub;
+ bool alpha;
};
enum vsp1_pipeline_state {
@@ -73,10 +75,12 @@ struct vsp1_pipeline {
unsigned int num_video;
unsigned int num_inputs;
- struct vsp1_rwpf *inputs[VPS1_MAX_RPF];
+ struct vsp1_rwpf *inputs[VSP1_MAX_RPF];
struct vsp1_rwpf *output;
struct vsp1_entity *bru;
struct vsp1_entity *lif;
+ struct vsp1_entity *uds;
+ struct vsp1_entity *uds_input;
struct list_head entities;
};
@@ -90,7 +94,6 @@ static inline struct vsp1_pipeline *to_vsp1_pipeline(struct media_entity *e)
}
struct vsp1_video_buffer {
- struct vsp1_video *video;
struct vb2_buffer buf;
struct list_head queue;
@@ -142,4 +145,8 @@ void vsp1_video_cleanup(struct vsp1_video *video);
void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe);
+void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
+ struct vsp1_entity *input,
+ unsigned int alpha);
+
#endif /* __VSP1_VIDEO_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 1294340dcb36..6e057762c933 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -38,23 +38,57 @@ static inline void vsp1_wpf_write(struct vsp1_rwpf *wpf, u32 reg, u32 data)
reg + wpf->entity.index * VI6_WPF_OFFSET, data);
}
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+static int wpf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct vsp1_rwpf *wpf =
+ container_of(ctrl->handler, struct vsp1_rwpf, ctrls);
+ u32 value;
+
+ if (!vsp1_entity_is_streaming(&wpf->entity))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_ALPHA_COMPONENT:
+ value = vsp1_wpf_read(wpf, VI6_WPF_OUTFMT);
+ value &= ~VI6_WPF_OUTFMT_PDV_MASK;
+ value |= ctrl->val << VI6_WPF_OUTFMT_PDV_SHIFT;
+ vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, value);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops wpf_ctrl_ops = {
+ .s_ctrl = wpf_s_ctrl,
+};
+
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Core Operations
*/
static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
{
+ struct vsp1_pipeline *pipe = to_vsp1_pipeline(&subdev->entity);
struct vsp1_rwpf *wpf = to_rwpf(subdev);
- struct vsp1_pipeline *pipe =
- to_vsp1_pipeline(&wpf->entity.subdev.entity);
struct vsp1_device *vsp1 = wpf->entity.vsp1;
const struct v4l2_rect *crop = &wpf->crop;
unsigned int i;
u32 srcrpf = 0;
u32 outfmt = 0;
+ int ret;
+
+ ret = vsp1_entity_set_streaming(&wpf->entity, enable);
+ if (ret < 0)
+ return ret;
if (!enable) {
vsp1_write(vsp1, VI6_WPF_IRQ_ENB(wpf->entity.index), 0);
+ vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, 0);
return 0;
}
@@ -99,6 +133,8 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
outfmt = fmtinfo->hwfmt << VI6_WPF_OUTFMT_WRFMT_SHIFT;
+ if (fmtinfo->alpha)
+ outfmt |= VI6_WPF_OUTFMT_PXA;
if (fmtinfo->swap_yc)
outfmt |= VI6_WPF_OUTFMT_SPYCS;
if (fmtinfo->swap_uv)
@@ -111,7 +147,13 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
wpf->entity.formats[RWPF_PAD_SOURCE].code)
outfmt |= VI6_WPF_OUTFMT_CSC;
+ /* Take the control handler lock to ensure that the PDV value won't be
+ * changed behind our back by a set control operation.
+ */
+ mutex_lock(wpf->ctrls.lock);
+ outfmt |= vsp1_wpf_read(wpf, VI6_WPF_OUTFMT) & VI6_WPF_OUTFMT_PDV_MASK;
vsp1_wpf_write(wpf, VI6_WPF_OUTFMT, outfmt);
+ mutex_unlock(wpf->ctrls.lock);
vsp1_write(vsp1, VI6_DPR_WPF_FPORCH(wpf->entity.index),
VI6_DPR_WPF_FPORCH_FP_WPFN);
@@ -207,6 +249,20 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
vsp1_entity_init_formats(subdev, NULL);
+ /* Initialize the control handler. */
+ v4l2_ctrl_handler_init(&wpf->ctrls, 1);
+ v4l2_ctrl_new_std(&wpf->ctrls, &wpf_ctrl_ops, V4L2_CID_ALPHA_COMPONENT,
+ 0, 255, 1, 255);
+
+ wpf->entity.subdev.ctrl_handler = &wpf->ctrls;
+
+ if (wpf->ctrls.error) {
+ dev_err(vsp1->dev, "wpf%u: failed to initialize controls\n",
+ index);
+ ret = wpf->ctrls.error;
+ goto error;
+ }
+
/* Initialize the video device. */
video = &wpf->video;
@@ -216,7 +272,9 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
ret = vsp1_video_init(video, &wpf->entity);
if (ret < 0)
- goto error_video;
+ goto error;
+
+ wpf->entity.video = video;
/* Connect the video device to the WPF. All connections are immutable
* except for the WPF0 source link if a LIF is present.
@@ -229,15 +287,13 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
RWPF_PAD_SOURCE,
&wpf->video.video.entity, 0, flags);
if (ret < 0)
- goto error_link;
+ goto error;
wpf->entity.sink = &wpf->video.video.entity;
return wpf;
-error_link:
- vsp1_video_cleanup(video);
-error_video:
- media_entity_cleanup(&wpf->entity.subdev.entity);
+error:
+ vsp1_entity_destroy(&wpf->entity);
return ERR_PTR(ret);
}
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 142c2ee64d31..2262b8139ca1 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -390,7 +390,6 @@ static int usb_dsbr100_probe(struct usb_interface *intf,
radio->videodev.release = video_device_release_empty;
radio->videodev.lock = &radio->v4l2_lock;
radio->videodev.ctrl_handler = &radio->hdl;
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
radio->usbdev = interface_to_usbdev(intf);
radio->curfreq = FREQ_MIN * FREQ_MUL;
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index d719e59e2179..82affaedf067 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -650,7 +650,6 @@ static int __init cadet_init(void)
dev->vdev.ioctl_ops = &cadet_ioctl_ops;
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
video_set_drvdata(&dev->vdev, dev);
res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index 6ff350831d56..c309ee45a08e 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -253,7 +253,6 @@ static int radio_isa_common_probe(struct radio_isa_card *isa,
isa->vdev.fops = &radio_isa_fops;
isa->vdev.ioctl_ops = &radio_isa_ioctl_ops;
isa->vdev.release = video_device_release_empty;
- set_bit(V4L2_FL_USE_FH_PRIO, &isa->vdev.flags);
video_set_drvdata(&isa->vdev, isa);
isa->freq = FREQ_LOW;
isa->stereo = drv->has_stereo;
diff --git a/drivers/media/radio/radio-keene.c b/drivers/media/radio/radio-keene.c
index 3d127825eceb..0c5d2db3b828 100644
--- a/drivers/media/radio/radio-keene.c
+++ b/drivers/media/radio/radio-keene.c
@@ -265,7 +265,7 @@ static int keene_s_ctrl(struct v4l2_ctrl *ctrl)
return keene_cmd_set(radio);
case V4L2_CID_AUDIO_COMPRESSION_GAIN:
- radio->tx = db2tx[(ctrl->val - ctrl->minimum) / ctrl->step];
+ radio->tx = db2tx[(ctrl->val - (s32)ctrl->minimum) / (s32)ctrl->step];
return keene_cmd_set(radio);
}
return -EINVAL;
@@ -380,7 +380,6 @@ static int usb_keene_probe(struct usb_interface *intf,
usb_set_intfdata(intf, &radio->v4l2_dev);
video_set_drvdata(&radio->vdev, radio);
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
/* at least 11ms is needed in order to settle hardware */
msleep(20);
diff --git a/drivers/media/radio/radio-ma901.c b/drivers/media/radio/radio-ma901.c
index a85b064cb7be..b3000ef85ee7 100644
--- a/drivers/media/radio/radio-ma901.c
+++ b/drivers/media/radio/radio-ma901.c
@@ -411,7 +411,6 @@ static int usb_ma901radio_probe(struct usb_interface *intf,
radio->vdev.ioctl_ops = &usb_ma901radio_ioctl_ops;
radio->vdev.release = video_device_release_empty;
radio->vdev.lock = &radio->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index a7e93d7477dd..998919e97dfe 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -1,20 +1,35 @@
-/* Miro PCM20 radio driver for Linux radio support
+/*
+ * Miro PCM20 radio driver for Linux radio support
* (c) 1998 Ruurd Reitsma
* Thanks to Norberto Pellici for the ACI device interface specification
* The API part is based on the radiotrack driver by M. Kirkwood
* This driver relies on the aci mixer provided by the snd-miro
* ALSA driver.
* Look there for further info...
- */
-
-/* What ever you think about the ACI, version 0x07 is not very well!
- * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions... Robert
+ *
+ * From the original miro RDS sources:
+ *
+ * (c) 2001 Robert Siemer
+ *
+ * Many thanks to Fred Seidel , the
+ * designer of the RDS decoder hardware. With his help
+ * I was able to code this driver.
+ * Thanks also to Norberto Pellicci, Dominic Mounteney
+ * and www.teleauskunft.de
+ * for good hints on finding Fred. It was somewhat hard
+ * to locate him here in Germany... [:
+ *
+ * This code has been reintroduced and converted to use
+ * the new V4L2 RDS API by:
+ *
+ * Hans Verkuil
*/
#include
#include
+#include
#include
+#include
#include
#include
#include
@@ -22,6 +37,22 @@
#include
#include
+#define RDS_DATASHIFT 2 /* Bit 2 */
+#define RDS_DATAMASK (1 << RDS_DATASHIFT)
+#define RDS_BUSYMASK 0x10 /* Bit 4 */
+#define RDS_CLOCKMASK 0x08 /* Bit 3 */
+#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
+
+#define RDS_STATUS 0x01
+#define RDS_STATIONNAME 0x02
+#define RDS_TEXT 0x03
+#define RDS_ALTFREQ 0x04
+#define RDS_TIMEDATE 0x05
+#define RDS_PI_CODE 0x06
+#define RDS_PTYTATP 0x07
+#define RDS_RESET 0x08
+#define RDS_RXVALUE 0x09
+
static int radio_nr = -1;
module_param(radio_nr, int, 0);
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
@@ -30,6 +61,14 @@ struct pcm20 {
struct v4l2_device v4l2_dev;
struct video_device vdev;
struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *rds_pty;
+ struct v4l2_ctrl *rds_ps_name;
+ struct v4l2_ctrl *rds_radio_test;
+ struct v4l2_ctrl *rds_ta;
+ struct v4l2_ctrl *rds_tp;
+ struct v4l2_ctrl *rds_ms;
+ /* thread for periodic RDS status checking */
+ struct task_struct *kthread;
unsigned long freq;
u32 audmode;
struct snd_miro_aci *aci;
@@ -41,6 +80,103 @@ static struct pcm20 pcm20_card = {
.audmode = V4L2_TUNER_MODE_STEREO,
};
+
+static int rds_waitread(struct snd_miro_aci *aci)
+{
+ u8 byte;
+ int i = 2000;
+
+ do {
+ byte = inb(aci->aci_port + ACI_REG_RDS);
+ i--;
+ } while ((byte & RDS_BUSYMASK) && i);
+
+ /*
+ * It's magic, but without this the data that you read later on
+ * is unreliable and full of bit errors. With this 1 usec delay
+ * everything is fine.
+ */
+ udelay(1);
+ return i ? byte : -1;
+}
+
+static int rds_rawwrite(struct snd_miro_aci *aci, u8 byte)
+{
+ if (rds_waitread(aci) >= 0) {
+ outb(byte, aci->aci_port + ACI_REG_RDS);
+ return 0;
+ }
+ return -1;
+}
+
+static int rds_write(struct snd_miro_aci *aci, u8 byte)
+{
+ u8 sendbuffer[8];
+ int i;
+
+ for (i = 7; i >= 0; i--)
+ sendbuffer[7 - i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
+ sendbuffer[0] |= RDS_CLOCKMASK;
+
+ for (i = 0; i < 8; i++)
+ rds_rawwrite(aci, sendbuffer[i]);
+ return 0;
+}
+
+static int rds_readcycle_nowait(struct snd_miro_aci *aci)
+{
+ outb(0, aci->aci_port + ACI_REG_RDS);
+ return rds_waitread(aci);
+}
+
+static int rds_readcycle(struct snd_miro_aci *aci)
+{
+ if (rds_rawwrite(aci, 0) < 0)
+ return -1;
+ return rds_waitread(aci);
+}
+
+static int rds_ack(struct snd_miro_aci *aci)
+{
+ int i = rds_readcycle(aci);
+
+ if (i < 0)
+ return -1;
+ if (i & RDS_DATAMASK)
+ return 0; /* ACK */
+ return 1; /* NACK */
+}
+
+static int rds_cmd(struct snd_miro_aci *aci, u8 cmd, u8 databuffer[], u8 datasize)
+{
+ int i, j;
+
+ rds_write(aci, cmd);
+
+ /* RDS_RESET doesn't need further processing */
+ if (cmd == RDS_RESET)
+ return 0;
+ if (rds_ack(aci))
+ return -EIO;
+ if (datasize == 0)
+ return 0;
+
+ /* to be able to use rds_readcycle_nowait()
+ I have to waitread() here */
+ if (rds_waitread(aci) < 0)
+ return -1;
+
+ memset(databuffer, 0, datasize);
+
+ for (i = 0; i < 8 * datasize; i++) {
+ j = rds_readcycle_nowait(aci);
+ if (j < 0)
+ return -EIO;
+ databuffer[i / 8] |= RDS_DATA(j) << (7 - (i % 8));
+ }
+ return 0;
+}
+
static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
{
unsigned char freql;
@@ -54,17 +190,10 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
freql = freq & 0xff;
freqh = freq >> 8;
+ rds_cmd(aci, RDS_RESET, NULL, 0);
return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
}
-static const struct v4l2_file_operations pcm20_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .poll = v4l2_ctrl_poll,
- .release = v4l2_fh_release,
- .unlocked_ioctl = video_ioctl2,
-};
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *v)
{
@@ -73,16 +202,31 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
strlcpy(v->card, "Miro PCM20", sizeof(v->card));
snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
+static bool sanitize(char *p, int size)
+{
+ int i;
+ bool ret = true;
+
+ for (i = 0; i < size; i++) {
+ if (p[i] < 32) {
+ p[i] = ' ';
+ ret = false;
+ }
+ }
+ return ret;
+}
+
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
struct pcm20 *dev = video_drvdata(file);
int res;
+ u8 buf;
if (v->index)
return -EINVAL;
@@ -97,8 +241,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTEREO, -1, -1);
v->rxsubchans = (res & 0x40) ? V4L2_TUNER_SUB_MONO :
V4L2_TUNER_SUB_STEREO;
- v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
v->audmode = dev->audmode;
+ res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
+ if (res >= 0 && buf)
+ v->rxsubchans |= V4L2_TUNER_SUB_RDS;
return 0;
}
@@ -157,6 +305,115 @@ static int pcm20_s_ctrl(struct v4l2_ctrl *ctrl)
return -EINVAL;
}
+static int pcm20_thread(void *data)
+{
+ struct pcm20 *dev = data;
+ const unsigned no_rds_start_counter = 5;
+ const unsigned sleep_msecs = 2000;
+ unsigned no_rds_counter = no_rds_start_counter;
+
+ for (;;) {
+ char text_buffer[66];
+ u8 buf;
+ int res;
+
+ msleep_interruptible(sleep_msecs);
+
+ if (kthread_should_stop())
+ break;
+
+ res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
+ if (res)
+ continue;
+ if (buf == 0) {
+ if (no_rds_counter == 0)
+ continue;
+ no_rds_counter--;
+ if (no_rds_counter)
+ continue;
+
+ /*
+ * No RDS seen for no_rds_start_counter * sleep_msecs
+ * milliseconds, clear all RDS controls to their
+ * default values.
+ */
+ v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, "");
+ v4l2_ctrl_s_ctrl(dev->rds_ms, 1);
+ v4l2_ctrl_s_ctrl(dev->rds_ta, 0);
+ v4l2_ctrl_s_ctrl(dev->rds_tp, 0);
+ v4l2_ctrl_s_ctrl(dev->rds_pty, 0);
+ v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, "");
+ continue;
+ }
+ no_rds_counter = no_rds_start_counter;
+
+ res = rds_cmd(dev->aci, RDS_STATUS, &buf, 1);
+ if (res)
+ continue;
+ if ((buf >> 3) & 1) {
+ res = rds_cmd(dev->aci, RDS_STATIONNAME, text_buffer, 8);
+ text_buffer[8] = 0;
+ if (!res && sanitize(text_buffer, 8))
+ v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, text_buffer);
+ }
+ if ((buf >> 6) & 1) {
+ u8 pty;
+
+ res = rds_cmd(dev->aci, RDS_PTYTATP, &pty, 1);
+ if (!res) {
+ v4l2_ctrl_s_ctrl(dev->rds_ms, !!(pty & 0x01));
+ v4l2_ctrl_s_ctrl(dev->rds_ta, !!(pty & 0x02));
+ v4l2_ctrl_s_ctrl(dev->rds_tp, !!(pty & 0x80));
+ v4l2_ctrl_s_ctrl(dev->rds_pty, (pty >> 2) & 0x1f);
+ }
+ }
+ if ((buf >> 4) & 1) {
+ res = rds_cmd(dev->aci, RDS_TEXT, text_buffer, 65);
+ text_buffer[65] = 0;
+ if (!res && sanitize(text_buffer + 1, 64))
+ v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, text_buffer + 1);
+ }
+ }
+ return 0;
+}
+
+static int pcm20_open(struct file *file)
+{
+ struct pcm20 *dev = video_drvdata(file);
+ int res = v4l2_fh_open(file);
+
+ if (!res && v4l2_fh_is_singular_file(file) &&
+ IS_ERR_OR_NULL(dev->kthread)) {
+ dev->kthread = kthread_run(pcm20_thread, dev, "%s",
+ dev->v4l2_dev.name);
+ if (IS_ERR(dev->kthread)) {
+ v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+ v4l2_fh_release(file);
+ return PTR_ERR(dev->kthread);
+ }
+ }
+ return res;
+}
+
+static int pcm20_release(struct file *file)
+{
+ struct pcm20 *dev = video_drvdata(file);
+
+ if (v4l2_fh_is_singular_file(file) && !IS_ERR_OR_NULL(dev->kthread)) {
+ kthread_stop(dev->kthread);
+ dev->kthread = NULL;
+ }
+ return v4l2_fh_release(file);
+}
+
+static const struct v4l2_file_operations pcm20_fops = {
+ .owner = THIS_MODULE,
+ .open = pcm20_open,
+ .poll = v4l2_ctrl_poll,
+ .release = pcm20_release,
+ .unlocked_ioctl = video_ioctl2,
+};
+
static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_g_tuner = vidioc_g_tuner,
@@ -195,9 +452,21 @@ static int __init pcm20_init(void)
}
hdl = &dev->ctrl_handler;
- v4l2_ctrl_handler_init(hdl, 1);
+ v4l2_ctrl_handler_init(hdl, 7);
v4l2_ctrl_new_std(hdl, &pcm20_ctrl_ops,
V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ dev->rds_pty = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_RDS_RX_PTY, 0, 0x1f, 1, 0);
+ dev->rds_ps_name = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
+ dev->rds_radio_test = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
+ dev->rds_ta = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+ dev->rds_tp = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+ dev->rds_ms = v4l2_ctrl_new_std(hdl, NULL,
+ V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
v4l2_dev->ctrl_handler = hdl;
if (hdl->error) {
res = hdl->error;
@@ -210,7 +479,6 @@ static int __init pcm20_init(void)
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
dev->vdev.lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags);
video_set_drvdata(&dev->vdev, dev);
snd_aci_cmd(dev->aci, ACI_SET_TUNERMONO,
dev->audmode == V4L2_TUNER_MODE_MONO, -1);
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index a360227ca3ab..c2927fd12615 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -32,7 +32,7 @@
* achievements (specifications given).
* Also, Faidon Liambotis wrote nice driver for this radio
* in 2007. He allowed to use his driver to improve current mr800 radio driver.
- * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492
+ * http://www.spinics.net/lists/linux-usb-devel/msg10109.html
*
* Version 0.01: First working version.
* It's required to blacklist AverMedia USB Radio
@@ -558,7 +558,6 @@ static int usb_amradio_probe(struct usb_interface *intf,
radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops;
radio->vdev.release = video_device_release_empty;
radio->vdev.lock = &radio->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
index 7b3bdbb1be73..bfb3a6d051ba 100644
--- a/drivers/media/radio/radio-raremono.c
+++ b/drivers/media/radio/radio-raremono.c
@@ -361,7 +361,6 @@ static int usb_raremono_probe(struct usb_interface *intf,
usb_set_intfdata(intf, &radio->v4l2_dev);
video_set_drvdata(&radio->vdev, radio);
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
raremono_cmd_main(radio, BAND_FM, 95160);
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 6f4318ff0db3..d7ce8fe6b5ae 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -344,7 +344,6 @@ static int __init fmi_init(void)
fmi->vdev.fops = &fmi_fops;
fmi->vdev.ioctl_ops = &fmi_ioctl_ops;
fmi->vdev.release = video_device_release_empty;
- set_bit(V4L2_FL_USE_FH_PRIO, &fmi->vdev.flags);
video_set_drvdata(&fmi->vdev, fmi);
mutex_init(&fmi->lock);
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 2fd9009f8663..633022b45f33 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -1470,7 +1470,6 @@ static int si476x_radio_probe(struct platform_device *pdev)
video_set_drvdata(&radio->videodev, radio);
platform_set_drvdata(pdev, radio);
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
v4l2_ctrl_handler_init(&radio->ctrl_handler,
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 3ed1f5669f79..925049654c5b 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -478,7 +478,6 @@ static int tea5764_i2c_probe(struct i2c_client *client,
video_set_drvdata(&radio->vdev, radio);
radio->vdev.lock = &radio->mutex;
radio->vdev.v4l2_dev = v4l2_dev;
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
/* initialize and power off the chip */
tea5764_i2c_read(radio);
diff --git a/drivers/media/radio/radio-tea5777.c b/drivers/media/radio/radio-tea5777.c
index e2455970725a..83fe7ab358df 100644
--- a/drivers/media/radio/radio-tea5777.c
+++ b/drivers/media/radio/radio-tea5777.c
@@ -570,7 +570,6 @@ int radio_tea5777_init(struct radio_tea5777 *tea, struct module *owner)
tea->fops = tea575x_fops;
tea->fops.owner = owner;
tea->vd.fops = &tea->fops;
- set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
tea->vd.ctrl_handler = &tea->ctrl_handler;
v4l2_ctrl_handler_init(&tea->ctrl_handler, 1);
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 0817964d9172..b9285e6584af 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -126,7 +126,6 @@ static int timbradio_probe(struct platform_device *pdev)
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
tr->video_dev.lock = &tr->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &tr->video_dev.flags);
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 07ef40595efd..494fac061306 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -680,7 +680,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->videodev.lock = &radio->lock;
radio->videodev.v4l2_dev = &radio->v4l2_dev;
radio->videodev.release = video_device_release_empty;
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->videodev.flags);
video_set_drvdata(&radio->videodev, radio);
/* get device and chip versions */
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index ba4cfc946868..a47502a330f0 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -196,7 +196,6 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
rsdev->radio_dev = radio_si4713_vdev_template;
rsdev->radio_dev.v4l2_dev = &rsdev->v4l2_dev;
rsdev->radio_dev.ctrl_handler = sd->ctrl_handler;
- set_bit(V4L2_FL_USE_FH_PRIO, &rsdev->radio_dev.flags);
/* Serialize all access to the si4713 */
rsdev->radio_dev.lock = &rsdev->lock;
video_set_drvdata(&rsdev->radio_dev, rsdev);
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
index 86502b2786d0..a77319dcba05 100644
--- a/drivers/media/radio/si4713/radio-usb-si4713.c
+++ b/drivers/media/radio/si4713/radio-usb-si4713.c
@@ -492,7 +492,6 @@ static int usb_si4713_probe(struct usb_interface *intf,
radio->vdev.vfl_dir = VFL_DIR_TX;
video_set_drvdata(&radio->vdev, radio);
- set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
if (retval < 0) {
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index 07d5153811e8..b5765557ea3d 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -957,6 +957,41 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
*bit = 5;
*mask = 0x1F << 5;
break;
+ case V4L2_CID_RDS_TX_DYNAMIC_PTY:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 15;
+ *mask = 1 << 15;
+ break;
+ case V4L2_CID_RDS_TX_COMPRESSED:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 14;
+ *mask = 1 << 14;
+ break;
+ case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 13;
+ *mask = 1 << 13;
+ break;
+ case V4L2_CID_RDS_TX_MONO_STEREO:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 12;
+ *mask = 1 << 12;
+ break;
+ case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 10;
+ *mask = 1 << 10;
+ break;
+ case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 4;
+ *mask = 1 << 4;
+ break;
+ case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+ *property = SI4713_TX_RDS_PS_MISC;
+ *bit = 3;
+ *mask = 1 << 3;
+ break;
case V4L2_CID_AUDIO_LIMITER_ENABLED:
*property = SI4713_TX_ACOMP_ENABLE;
*bit = 1;
@@ -1098,11 +1133,11 @@ static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_RDS_TX_PS_NAME:
- ret = si4713_set_rds_ps_name(sdev, ctrl->string);
+ ret = si4713_set_rds_ps_name(sdev, ctrl->p_new.p_char);
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
- ret = si4713_set_rds_radio_text(sdev, ctrl->string);
+ ret = si4713_set_rds_radio_text(sdev, ctrl->p_new.p_char);
break;
case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
@@ -1122,6 +1157,17 @@ static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
}
break;
+ case V4L2_CID_RDS_TX_ALT_FREQS_ENABLE:
+ case V4L2_CID_RDS_TX_ALT_FREQS:
+ if (sdev->rds_alt_freqs_enable->val) {
+ val = sdev->rds_alt_freqs->p_new.p_u32[0];
+ val = val / 100 - 876 + 0xe101;
+ } else {
+ val = 0xe0e0;
+ }
+ ret = si4713_write_property(sdev, SI4713_TX_RDS_PS_AF, val);
+ break;
+
default:
ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
&mask, &property, &mul, &table, &size);
@@ -1355,6 +1401,17 @@ static const struct v4l2_subdev_ops si4713_subdev_ops = {
.tuner = &si4713_subdev_tuner_ops,
};
+static const struct v4l2_ctrl_config si4713_alt_freqs_ctrl = {
+ .id = V4L2_CID_RDS_TX_ALT_FREQS,
+ .type = V4L2_CTRL_TYPE_U32,
+ .min = 87600,
+ .max = 107900,
+ .step = 100,
+ .def = 87600,
+ .dims = { 1 },
+ .elem_size = sizeof(u32),
+};
+
/*
* I2C driver interface
*/
@@ -1410,6 +1467,23 @@ static int si4713_probe(struct i2c_client *client,
V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, DEFAULT_RDS_PI);
sdev->rds_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_PTY, 0, 31, 1, DEFAULT_RDS_PTY);
+ sdev->rds_compressed = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0);
+ sdev->rds_art_head = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0);
+ sdev->rds_stereo = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1);
+ sdev->rds_tp = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+ sdev->rds_ta = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+ sdev->rds_ms = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1);
+ sdev->rds_dyn_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0);
+ sdev->rds_alt_freqs_enable = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+ V4L2_CID_RDS_TX_ALT_FREQS_ENABLE, 0, 1, 1, 0);
+ sdev->rds_alt_freqs = v4l2_ctrl_new_custom(hdl, &si4713_alt_freqs_ctrl, NULL);
sdev->rds_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
V4L2_CID_RDS_TX_DEVIATION, 0, MAX_RDS_DEVIATION,
10, DEFAULT_RDS_DEVIATION);
@@ -1476,7 +1550,7 @@ static int si4713_probe(struct i2c_client *client,
rval = hdl->error;
goto free_ctrls;
}
- v4l2_ctrl_cluster(20, &sdev->mute);
+ v4l2_ctrl_cluster(29, &sdev->mute);
sdev->sd.ctrl_handler = hdl;
if (client->irq) {
diff --git a/drivers/media/radio/si4713/si4713.h b/drivers/media/radio/si4713/si4713.h
index 4837cf6e0e1b..ed700e387605 100644
--- a/drivers/media/radio/si4713/si4713.h
+++ b/drivers/media/radio/si4713/si4713.h
@@ -211,6 +211,15 @@ struct si4713_device {
struct v4l2_ctrl *rds_pi;
struct v4l2_ctrl *rds_deviation;
struct v4l2_ctrl *rds_pty;
+ struct v4l2_ctrl *rds_compressed;
+ struct v4l2_ctrl *rds_art_head;
+ struct v4l2_ctrl *rds_stereo;
+ struct v4l2_ctrl *rds_ta;
+ struct v4l2_ctrl *rds_tp;
+ struct v4l2_ctrl *rds_ms;
+ struct v4l2_ctrl *rds_dyn_pty;
+ struct v4l2_ctrl *rds_alt_freqs_enable;
+ struct v4l2_ctrl *rds_alt_freqs;
struct v4l2_ctrl *compression_enabled;
struct v4l2_ctrl *compression_threshold;
struct v4l2_ctrl *compression_gain;
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
index 7c14060a40b8..f1a0867789fe 100644
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -523,7 +523,6 @@ int snd_tea575x_init(struct snd_tea575x *tea, struct module *owner)
tea->fops = tea575x_fops;
tea->fops.owner = owner;
tea->vd.fops = &tea->fops;
- set_bit(V4L2_FL_USE_FH_PRIO, &tea->vd.flags);
/* disable hw_freq_seek if we can't use it */
if (tea->cannot_read_data)
v4l2_disable_ioctl(&tea->vd, VIDIOC_S_HW_FREQ_SEEK);
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8fbd377e6311..5e626af8e313 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -84,18 +84,6 @@ config IR_SONY_DECODER
Enable this option if you have an infrared remote control which
uses the Sony protocol, and you need software decoding support.
-config IR_RC5_SZ_DECODER
- tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
- depends on RC_CORE
- select BITREVERSE
- default y
-
- ---help---
- Enable this option if you have IR with RC-5 (streamzap) protocol,
- and if the IR is decoded in software. (The Streamzap PC Remote
- uses an IR protocol that is almost standard RC-5, but not quite,
- as it uses an additional bit).
-
config IR_SANYO_DECODER
tristate "Enable IR raw decoder for the Sanyo protocol"
depends on RC_CORE
@@ -125,6 +113,16 @@ config IR_MCE_KBD_DECODER
Enable this option if you have a Microsoft Remote Keyboard for
Windows Media Center Edition, which you would like to use with
a raw IR receiver in your system.
+
+config IR_XMP_DECODER
+ tristate "Enable IR raw decoder for the XMP protocol"
+ depends on RC_CORE
+ select BITREVERSE
+ default y
+
+ ---help---
+ Enable this option if you have IR with XMP protocol, and
+ if the IR is decoded in software
endif #RC_DECODERS
menuconfig RC_DEVICES
@@ -343,4 +341,14 @@ config RC_ST
If you're not sure, select N here.
+config IR_SUNXI
+ tristate "SUNXI IR remote control"
+ depends on RC_CORE
+ depends on ARCH_SUNXI
+ ---help---
+ Say Y if you want to use sunXi internal IR Controller
+
+ To compile this driver as a module, choose M here: the module will
+ be called sunxi-ir.
+
endif #RC_DEVICES
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index f8b54ff46601..9f9843a1af5f 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -1,4 +1,4 @@
-rc-core-objs := rc-main.o ir-raw.o
+rc-core-objs := rc-main.o rc-ir-raw.o
obj-y += keymaps/
@@ -9,11 +9,11 @@ obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
-obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o
obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o
obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o
obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
+obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o
@@ -32,4 +32,5 @@ obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
obj-$(CONFIG_IR_IGUANA) += iguanair.o
obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
obj-$(CONFIG_RC_ST) += st_rc.o
+obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o
obj-$(CONFIG_IR_IMG) += img-ir/
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 2df7c5516013..a35631891cc0 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -279,46 +279,42 @@ struct ati_remote {
/* "Kinds" of messages sent from the hardware to the driver. */
#define KIND_END 0
-#define KIND_LITERAL 1 /* Simply pass to input system */
+#define KIND_LITERAL 1 /* Simply pass to input system as EV_KEY */
#define KIND_FILTERED 2 /* Add artificial key-up events, drop keyrepeats */
-#define KIND_LU 3 /* Directional keypad diagonals - left up, */
-#define KIND_RU 4 /* right up, */
-#define KIND_LD 5 /* left down, */
-#define KIND_RD 6 /* right down */
-#define KIND_ACCEL 7 /* Directional keypad - left, right, up, down.*/
+#define KIND_ACCEL 3 /* Translate to EV_REL mouse-move events */
/* Translation table from hardware messages to input events. */
static const struct {
- short kind;
- unsigned char data;
- int type;
- unsigned int code;
- int value;
+ unsigned char kind;
+ unsigned char data; /* Raw key code from remote */
+ unsigned short code; /* Input layer translation */
} ati_remote_tbl[] = {
- /* Directional control pad axes */
- {KIND_ACCEL, 0x70, EV_REL, REL_X, -1}, /* left */
- {KIND_ACCEL, 0x71, EV_REL, REL_X, 1}, /* right */
- {KIND_ACCEL, 0x72, EV_REL, REL_Y, -1}, /* up */
- {KIND_ACCEL, 0x73, EV_REL, REL_Y, 1}, /* down */
- /* Directional control pad diagonals */
- {KIND_LU, 0x74, EV_REL, 0, 0}, /* left up */
- {KIND_RU, 0x75, EV_REL, 0, 0}, /* right up */
- {KIND_LD, 0x77, EV_REL, 0, 0}, /* left down */
- {KIND_RD, 0x76, EV_REL, 0, 0}, /* right down */
+ /* Directional control pad axes. Code is xxyy */
+ {KIND_ACCEL, 0x70, 0xff00}, /* left */
+ {KIND_ACCEL, 0x71, 0x0100}, /* right */
+ {KIND_ACCEL, 0x72, 0x00ff}, /* up */
+ {KIND_ACCEL, 0x73, 0x0001}, /* down */
- /* "Mouse button" buttons */
- {KIND_LITERAL, 0x78, EV_KEY, BTN_LEFT, 1}, /* left btn down */
- {KIND_LITERAL, 0x79, EV_KEY, BTN_LEFT, 0}, /* left btn up */
- {KIND_LITERAL, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
- {KIND_LITERAL, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
+ /* Directional control pad diagonals */
+ {KIND_ACCEL, 0x74, 0xffff}, /* left up */
+ {KIND_ACCEL, 0x75, 0x01ff}, /* right up */
+ {KIND_ACCEL, 0x77, 0xff01}, /* left down */
+ {KIND_ACCEL, 0x76, 0x0101}, /* right down */
+
+ /* "Mouse button" buttons. The code below uses the fact that the
+ * lsbit of the raw code is a down/up indicator. */
+ {KIND_LITERAL, 0x78, BTN_LEFT}, /* left btn down */
+ {KIND_LITERAL, 0x79, BTN_LEFT}, /* left btn up */
+ {KIND_LITERAL, 0x7c, BTN_RIGHT},/* right btn down */
+ {KIND_LITERAL, 0x7d, BTN_RIGHT},/* right btn up */
/* Artificial "doubleclick" events are generated by the hardware.
* They are mapped to the "side" and "extra" mouse buttons here. */
- {KIND_FILTERED, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
- {KIND_FILTERED, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
+ {KIND_FILTERED, 0x7a, BTN_SIDE}, /* left dblclick */
+ {KIND_FILTERED, 0x7e, BTN_EXTRA},/* right dblclick */
/* Non-mouse events are handled by rc-core */
- {KIND_END, 0x00, EV_MAX + 1, 0, 0}
+ {KIND_END, 0x00, 0}
};
/*
@@ -493,7 +489,6 @@ static void ati_remote_input_report(struct urb *urb)
unsigned char *data= ati_remote->inbuf;
struct input_dev *dev = ati_remote->idev;
int index = -1;
- int acc;
int remote_num;
unsigned char scancode;
u32 wheel_keycode = KEY_RESERVED;
@@ -507,8 +502,9 @@ static void ati_remote_input_report(struct urb *urb)
*/
/* Deal with strange looking inputs */
- if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
- ((data[3] & 0x0f) != 0x00) ) {
+ if ( urb->actual_length != 4 || data[0] != 0x14 ||
+ data[1] != (unsigned char)(data[2] + data[3] + 0xD5) ||
+ (data[3] & 0x0f) != 0x00) {
ati_remote_dump(&urb->dev->dev, data, urb->actual_length);
return;
}
@@ -524,9 +520,9 @@ static void ati_remote_input_report(struct urb *urb)
remote_num = (data[3] >> 4) & 0x0f;
if (channel_mask & (1 << (remote_num + 1))) {
dbginfo(&ati_remote->interface->dev,
- "Masked input from channel 0x%02x: data %02x,%02x, "
+ "Masked input from channel 0x%02x: data %02x, "
"mask= 0x%02lx\n",
- remote_num, data[1], data[2], channel_mask);
+ remote_num, data[2], channel_mask);
return;
}
@@ -566,16 +562,16 @@ static void ati_remote_input_report(struct urb *urb)
}
if (index >= 0 && ati_remote_tbl[index].kind == KIND_LITERAL) {
- input_event(dev, ati_remote_tbl[index].type,
- ati_remote_tbl[index].code,
- ati_remote_tbl[index].value);
- input_sync(dev);
+ /*
+ * The lsbit of the raw key code is a down/up flag.
+ * Invert it to match the input layer's conventions.
+ */
+ input_event(dev, EV_KEY, ati_remote_tbl[index].code,
+ !(data[2] & 1));
ati_remote->old_jiffies = jiffies;
- return;
- }
- if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) {
+ } else if (index < 0 || ati_remote_tbl[index].kind == KIND_FILTERED) {
unsigned long now = jiffies;
/* Filter duplicate events which happen "too close" together. */
@@ -588,12 +584,11 @@ static void ati_remote_input_report(struct urb *urb)
ati_remote->first_jiffies = now;
}
- ati_remote->old_data = data[2];
ati_remote->old_jiffies = now;
- /* Ensure we skip at least the 4 first duplicate events (generated
- * by a single keypress), and continue skipping until repeat_delay
- * msecs have passed
+ /* Ensure we skip at least the 4 first duplicate events
+ * (generated by a single keypress), and continue skipping
+ * until repeat_delay msecs have passed.
*/
if (ati_remote->repeat_count > 0 &&
(ati_remote->repeat_count < 5 ||
@@ -601,7 +596,10 @@ static void ati_remote_input_report(struct urb *urb)
msecs_to_jiffies(repeat_delay))))
return;
- if (index < 0) {
+ if (index >= 0) {
+ input_event(dev, EV_KEY, ati_remote_tbl[index].code, 1);
+ input_event(dev, EV_KEY, ati_remote_tbl[index].code, 0);
+ } else {
/* Not a mouse event, hand it to rc-core. */
int count = 1;
@@ -622,61 +620,37 @@ static void ati_remote_input_report(struct urb *urb)
* it would cause ghost repeats which would be a
* regression for this driver.
*/
- rc_keydown_notimeout(ati_remote->rdev, scancode,
- data[2]);
+ rc_keydown_notimeout(ati_remote->rdev, RC_TYPE_OTHER,
+ scancode, data[2]);
rc_keyup(ati_remote->rdev);
}
- return;
+ goto nosync;
}
- input_event(dev, ati_remote_tbl[index].type,
- ati_remote_tbl[index].code, 1);
- input_sync(dev);
- input_event(dev, ati_remote_tbl[index].type,
- ati_remote_tbl[index].code, 0);
- input_sync(dev);
-
- } else {
+ } else if (ati_remote_tbl[index].kind == KIND_ACCEL) {
+ signed char dx = ati_remote_tbl[index].code >> 8;
+ signed char dy = ati_remote_tbl[index].code & 255;
/*
* Other event kinds are from the directional control pad, and
* have an acceleration factor applied to them. Without this
* acceleration, the control pad is mostly unusable.
*/
- acc = ati_remote_compute_accel(ati_remote);
-
- switch (ati_remote_tbl[index].kind) {
- case KIND_ACCEL:
- input_event(dev, ati_remote_tbl[index].type,
- ati_remote_tbl[index].code,
- ati_remote_tbl[index].value * acc);
- break;
- case KIND_LU:
- input_report_rel(dev, REL_X, -acc);
- input_report_rel(dev, REL_Y, -acc);
- break;
- case KIND_RU:
- input_report_rel(dev, REL_X, acc);
- input_report_rel(dev, REL_Y, -acc);
- break;
- case KIND_LD:
- input_report_rel(dev, REL_X, -acc);
- input_report_rel(dev, REL_Y, acc);
- break;
- case KIND_RD:
- input_report_rel(dev, REL_X, acc);
- input_report_rel(dev, REL_Y, acc);
- break;
- default:
- dev_dbg(&ati_remote->interface->dev,
- "ati_remote kind=%d\n",
- ati_remote_tbl[index].kind);
- }
- input_sync(dev);
-
+ int acc = ati_remote_compute_accel(ati_remote);
+ if (dx)
+ input_report_rel(dev, REL_X, dx * acc);
+ if (dy)
+ input_report_rel(dev, REL_Y, dy * acc);
ati_remote->old_jiffies = jiffies;
- ati_remote->old_data = data[2];
+
+ } else {
+ dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+ ati_remote_tbl[index].kind);
+ return;
}
+ input_sync(dev);
+nosync:
+ ati_remote->old_data = data[2];
}
/*
@@ -763,8 +737,9 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
BIT_MASK(BTN_RIGHT) | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA);
idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
- if (ati_remote_tbl[i].type == EV_KEY)
- set_bit(ati_remote_tbl[i].code, idev->keybit);
+ if (ati_remote_tbl[i].kind == KIND_LITERAL ||
+ ati_remote_tbl[i].kind == KIND_FILTERED)
+ __set_bit(ati_remote_tbl[i].code, idev->keybit);
input_set_drvdata(idev, ati_remote);
@@ -784,7 +759,7 @@ static void ati_remote_rc_init(struct ati_remote *ati_remote)
rdev->priv = ati_remote;
rdev->driver_type = RC_DRIVER_SCANCODE;
- rc_set_allowed_protocols(rdev, RC_BIT_OTHER);
+ rdev->allowed_protocols = RC_BIT_OTHER;
rdev->driver_name = "ati_remote";
rdev->open = ati_remote_rc_open;
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index fc9d23f2ed3f..d16d9b496b92 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -1059,7 +1059,7 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
learning_mode_force = false;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
rdev->priv = dev;
rdev->open = ene_open;
rdev->close = ene_close;
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 46b66e59438f..f0a1f7d31ee6 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -541,7 +541,7 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
/* Set up the rc device */
rdev->priv = fintek;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
rdev->open = fintek_open;
rdev->close = fintek_close;
rdev->input_name = FINTEK_DESCRIPTION;
@@ -686,12 +686,12 @@ static struct pnp_driver fintek_driver = {
.shutdown = fintek_shutdown,
};
-static int fintek_init(void)
+static int __init fintek_init(void)
{
return pnp_register_driver(&fintek_driver);
}
-static void fintek_exit(void)
+static void __exit fintek_exit(void)
{
pnp_unregister_driver(&fintek_driver);
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index 29b5f89813b4..59853085bc88 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -145,9 +145,9 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
rcdev->dev.parent = &pdev->dev;
rcdev->driver_name = GPIO_IR_DRIVER_NAME;
if (pdata->allowed_protos)
- rc_set_allowed_protocols(rcdev, pdata->allowed_protos);
+ rcdev->allowed_protocols = pdata->allowed_protos;
else
- rc_set_allowed_protocols(rcdev, RC_BIT_ALL);
+ rcdev->allowed_protocols = RC_BIT_ALL;
rcdev->map_name = pdata->map_name ?: RC_MAP_EMPTY;
gpio_dev->rcdev = rcdev;
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 627ddfd61980..ee60e17fba05 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -495,7 +495,7 @@ static int iguanair_probe(struct usb_interface *intf,
usb_to_input_id(ir->udev, &rc->input_id);
rc->dev.parent = &intf->dev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rc, RC_BIT_ALL);
+ rc->allowed_protocols = RC_BIT_ALL;
rc->priv = ir;
rc->open = iguanair_open;
rc->close = iguanair_close;
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
index 6b7834834fb8..a0cac2f09109 100644
--- a/drivers/media/rc/img-ir/img-ir-core.c
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -3,6 +3,11 @@
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
* This contains core img-ir code for setting up the driver. The two interfaces
* (raw and hardware decode) are handled separately.
*/
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 0127dd257a57..bfb282a714e8 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -3,6 +3,11 @@
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
* This ties into the input subsystem using the RC-core. Protocol support is
* provided in separate modules which provide the parameters and scancode
* translation functions to set up the hardware decoder and interpret the
@@ -507,7 +512,7 @@ unlock:
static int img_ir_set_normal_filter(struct rc_dev *dev,
struct rc_scancode_filter *sc_filter)
{
- return img_ir_set_filter(dev, RC_FILTER_NORMAL, sc_filter);
+ return img_ir_set_filter(dev, RC_FILTER_NORMAL, sc_filter);
}
static int img_ir_set_wakeup_filter(struct rc_dev *dev,
@@ -551,8 +556,8 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
hw->mode = IMG_IR_M_NORMAL;
/* clear the wakeup scancode filter */
- rdev->scancode_filters[RC_FILTER_WAKEUP].data = 0;
- rdev->scancode_filters[RC_FILTER_WAKEUP].mask = 0;
+ rdev->scancode_wakeup_filter.data = 0;
+ rdev->scancode_wakeup_filter.mask = 0;
/* clear raw filters */
_img_ir_set_filter(priv, NULL);
@@ -656,8 +661,8 @@ success:
wakeup_protocols = *ir_type;
if (!hw->decoder || !hw->decoder->filter)
wakeup_protocols = 0;
- rc_set_allowed_wakeup_protocols(rdev, wakeup_protocols);
- rc_set_enabled_wakeup_protocols(rdev, wakeup_protocols);
+ rdev->allowed_wakeup_protocols = wakeup_protocols;
+ rdev->enabled_wakeup_protocols = wakeup_protocols;
return 0;
}
@@ -671,9 +676,9 @@ static void img_ir_set_protocol(struct img_ir_priv *priv, u64 proto)
spin_unlock_irq(&rdev->rc_map.lock);
mutex_lock(&rdev->lock);
- rc_set_enabled_protocols(rdev, proto);
- rc_set_allowed_wakeup_protocols(rdev, proto);
- rc_set_enabled_wakeup_protocols(rdev, proto);
+ rdev->enabled_protocols = proto;
+ rdev->allowed_wakeup_protocols = proto;
+ rdev->enabled_wakeup_protocols = proto;
mutex_unlock(&rdev->lock);
}
@@ -790,9 +795,11 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
struct img_ir_priv_hw *hw = &priv->hw;
const struct img_ir_decoder *dec = hw->decoder;
int ret = IMG_IR_SCANCODE;
- int scancode;
+ u32 scancode;
+ enum rc_type protocol = RC_TYPE_UNKNOWN;
+
if (dec->scancode)
- ret = dec->scancode(len, raw, &scancode, hw->enabled_protocols);
+ ret = dec->scancode(len, raw, &protocol, &scancode, hw->enabled_protocols);
else if (len >= 32)
scancode = (u32)raw;
else if (len < 32)
@@ -801,7 +808,7 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
len, (unsigned long long)raw);
if (ret == IMG_IR_SCANCODE) {
dev_dbg(priv->dev, "decoded scan code %#x\n", scancode);
- rc_keydown(hw->rdev, scancode, 0);
+ rc_keydown(hw->rdev, protocol, scancode, 0);
img_ir_end_repeat(priv);
} else if (ret == IMG_IR_REPEATCODE) {
if (hw->mode == IMG_IR_M_REPEATING) {
@@ -996,7 +1003,7 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
}
rdev->priv = priv;
rdev->map_name = RC_MAP_EMPTY;
- rc_set_allowed_protocols(rdev, img_ir_allowed_protos(priv));
+ rdev->allowed_protocols = img_ir_allowed_protos(priv);
rdev->input_name = "IMG Infrared Decoder";
rdev->s_filter = img_ir_set_normal_filter;
rdev->s_wakeup_filter = img_ir_set_wakeup_filter;
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h
index 6c9a94a81190..3e40ce87b898 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.h
+++ b/drivers/media/rc/img-ir/img-ir-hw.h
@@ -2,6 +2,11 @@
* ImgTec IR Hardware Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#ifndef _IMG_IR_HW_H_
@@ -157,7 +162,8 @@ struct img_ir_decoder {
struct img_ir_control control;
/* scancode logic */
- int (*scancode)(int len, u64 raw, int *scancode, u64 protocols);
+ int (*scancode)(int len, u64 raw, enum rc_type *protocol,
+ u32 *scancode, u64 enabled_protocols);
int (*filter)(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols);
};
diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c
index 10209d200efb..a60dda8bf706 100644
--- a/drivers/media/rc/img-ir/img-ir-jvc.c
+++ b/drivers/media/rc/img-ir/img-ir-jvc.c
@@ -2,12 +2,18 @@
* ImgTec IR Decoder setup for JVC protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#include "img-ir-hw.h"
/* Convert JVC data to a scancode */
-static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol,
+ u32 *scancode, u64 enabled_protocols)
{
unsigned int cust, data;
@@ -17,6 +23,7 @@ static int img_ir_jvc_scancode(int len, u64 raw, int *scancode, u64 protocols)
cust = (raw >> 0) & 0xff;
data = (raw >> 8) & 0xff;
+ *protocol = RC_TYPE_JVC;
*scancode = cust << 8 | data;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
index 751d9d945269..739897549b5b 100644
--- a/drivers/media/rc/img-ir/img-ir-nec.c
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -2,13 +2,19 @@
* ImgTec IR Decoder setup for NEC protocol.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#include "img-ir-hw.h"
#include
/* Convert NEC data to a scancode */
-static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
+ u32 *scancode, u64 enabled_protocols)
{
unsigned int addr, addr_inv, data, data_inv;
/* a repeat code has no data */
@@ -40,6 +46,7 @@ static int img_ir_nec_scancode(int len, u64 raw, int *scancode, u64 protocols)
*scancode = addr << 8 |
data;
}
+ *protocol = RC_TYPE_NEC;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-raw.c b/drivers/media/rc/img-ir/img-ir-raw.c
index cfb01d9e571a..33f37ed87ad2 100644
--- a/drivers/media/rc/img-ir/img-ir-raw.c
+++ b/drivers/media/rc/img-ir/img-ir-raw.c
@@ -3,6 +3,11 @@
*
* Copyright 2010-2014 Imagination Technologies Ltd.
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
* This ties into the input subsystem using the RC-core in raw mode. Raw IR
* signal edges are reported and decoded by generic software decoders.
*/
diff --git a/drivers/media/rc/img-ir/img-ir-raw.h b/drivers/media/rc/img-ir/img-ir-raw.h
index 9802ffd51b9a..4c9b7676e6fc 100644
--- a/drivers/media/rc/img-ir/img-ir-raw.h
+++ b/drivers/media/rc/img-ir/img-ir-raw.h
@@ -2,6 +2,11 @@
* ImgTec IR Raw Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#ifndef _IMG_IR_RAW_H_
diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c
index c2c763e08a41..6b0653ecdf5a 100644
--- a/drivers/media/rc/img-ir/img-ir-sanyo.c
+++ b/drivers/media/rc/img-ir/img-ir-sanyo.c
@@ -3,6 +3,11 @@
*
* Copyright 2012-2014 Imagination Technologies Ltd.
*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
* From ir-sanyo-decoder.c:
*
* This protocol uses the NEC protocol timings. However, data is formatted as:
@@ -18,7 +23,8 @@
#include "img-ir-hw.h"
/* Convert Sanyo data to a scancode */
-static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol,
+ u32 *scancode, u64 enabled_protocols)
{
unsigned int addr, addr_inv, data, data_inv;
/* a repeat code has no data */
@@ -38,6 +44,7 @@ static int img_ir_sanyo_scancode(int len, u64 raw, int *scancode, u64 protocols)
return -EINVAL;
/* Normal Sanyo */
+ *protocol = RC_TYPE_SANYO;
*scancode = addr << 8 | data;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c
index 3397cc5a6794..3300a38802ac 100644
--- a/drivers/media/rc/img-ir/img-ir-sharp.c
+++ b/drivers/media/rc/img-ir/img-ir-sharp.c
@@ -2,12 +2,18 @@
* ImgTec IR Decoder setup for Sharp protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#include "img-ir-hw.h"
/* Convert Sharp data to a scancode */
-static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol,
+ u32 *scancode, u64 enabled_protocols)
{
unsigned int addr, cmd, exp, chk;
@@ -26,6 +32,7 @@ static int img_ir_sharp_scancode(int len, u64 raw, int *scancode, u64 protocols)
/* probably the second half of the message */
return -EINVAL;
+ *protocol = RC_TYPE_SHARP;
*scancode = addr << 8 | cmd;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c
index 993409a51a71..3a0f17b0752c 100644
--- a/drivers/media/rc/img-ir/img-ir-sony.c
+++ b/drivers/media/rc/img-ir/img-ir-sony.c
@@ -2,40 +2,49 @@
* ImgTec IR Decoder setup for Sony (SIRC) protocol.
*
* Copyright 2012-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#include "img-ir-hw.h"
/* Convert Sony data to a scancode */
-static int img_ir_sony_scancode(int len, u64 raw, int *scancode, u64 protocols)
+static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol,
+ u32 *scancode, u64 enabled_protocols)
{
unsigned int dev, subdev, func;
switch (len) {
case 12:
- if (!(protocols & RC_BIT_SONY12))
+ if (!(enabled_protocols & RC_BIT_SONY12))
return -EINVAL;
func = raw & 0x7f; /* first 7 bits */
raw >>= 7;
dev = raw & 0x1f; /* next 5 bits */
subdev = 0;
+ *protocol = RC_TYPE_SONY12;
break;
case 15:
- if (!(protocols & RC_BIT_SONY15))
+ if (!(enabled_protocols & RC_BIT_SONY15))
return -EINVAL;
func = raw & 0x7f; /* first 7 bits */
raw >>= 7;
dev = raw & 0xff; /* next 8 bits */
subdev = 0;
+ *protocol = RC_TYPE_SONY15;
break;
case 20:
- if (!(protocols & RC_BIT_SONY20))
+ if (!(enabled_protocols & RC_BIT_SONY20))
return -EINVAL;
func = raw & 0x7f; /* first 7 bits */
raw >>= 7;
dev = raw & 0x1f; /* next 5 bits */
raw >>= 5;
subdev = raw & 0xff; /* next 8 bits */
+ *protocol = RC_TYPE_SONY20;
break;
default:
return -EINVAL;
diff --git a/drivers/media/rc/img-ir/img-ir.h b/drivers/media/rc/img-ir/img-ir.h
index afb189394af9..2ddf56083182 100644
--- a/drivers/media/rc/img-ir/img-ir.h
+++ b/drivers/media/rc/img-ir/img-ir.h
@@ -2,6 +2,11 @@
* ImgTec IR Decoder found in PowerDown Controller.
*
* Copyright 2010-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
*/
#ifndef _IMG_IR_H_
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 6f24e77b1488..7115e68ba697 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -78,11 +78,11 @@ static int display_open(struct inode *inode, struct file *file);
static int display_close(struct inode *inode, struct file *file);
/* VFD write operation */
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos);
/* LCD file_operations override function prototypes */
-static ssize_t lcd_write(struct file *file, const char *buf,
+static ssize_t lcd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos);
/*** G L O B A L S ***/
@@ -825,7 +825,7 @@ static struct attribute_group imon_rf_attr_group = {
* than 32 bytes are provided spaces will be appended to
* generate a full screen.
*/
-static ssize_t vfd_write(struct file *file, const char *buf,
+static ssize_t vfd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos)
{
int i;
@@ -912,7 +912,7 @@ exit:
* display whatever diacritics you need, and so on), but it's also
* a lot more complicated than most LCDs...
*/
-static ssize_t lcd_write(struct file *file, const char *buf,
+static ssize_t lcd_write(struct file *file, const char __user *buf,
size_t n_bytes, loff_t *pos)
{
int retval = 0;
@@ -1017,7 +1017,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type)
unsigned char ir_proto_packet[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
- if (*rc_type && !rc_protocols_allowed(rc, *rc_type))
+ if (*rc_type && !(*rc_type & rc->allowed_protocols))
dev_warn(dev, "Looks like you're trying to use an IR protocol "
"this device does not support\n");
@@ -1579,7 +1579,10 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type == 0)
rc_keyup(ictx->rdev);
else {
- rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle);
+ if (ictx->rc_type == RC_BIT_RC6_MCE)
+ rc_keydown(ictx->rdev,
+ ictx->rc_type == RC_BIT_RC6_MCE ? RC_TYPE_RC6_MCE : RC_TYPE_OTHER,
+ ictx->rc_scancode, ictx->rc_toggle);
spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
spin_unlock_irqrestore(&ictx->kc_lock, flags);
@@ -1867,8 +1870,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
rdev->priv = ictx;
rdev->driver_type = RC_DRIVER_SCANCODE;
- /* iMON PAD or MCE */
- rc_set_allowed_protocols(rdev, RC_BIT_OTHER | RC_BIT_RC6_MCE);
+ rdev->allowed_protocols = RC_BIT_OTHER | RC_BIT_RC6_MCE; /* iMON PAD or MCE */
rdev->change_protocol = imon_ir_change_protocol;
rdev->driver_name = MOD_NAME;
@@ -1881,7 +1883,7 @@ static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
if (ictx->product == 0xffdc) {
imon_get_ffdc_type(ictx);
- rc_set_allowed_protocols(rdev, ictx->rc_type);
+ rdev->allowed_protocols = ictx->rc_type;
}
imon_set_display_type(ictx);
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 4ea62a1dcfda..30bcf188d377 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -47,7 +47,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct jvc_dec *data = &dev->raw->jvc;
- if (!rc_protocols_enabled(dev, RC_BIT_JVC))
+ if (!(dev->enabled_protocols & RC_BIT_JVC))
return 0;
if (!is_timing_event(ev)) {
@@ -140,7 +140,7 @@ again:
scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
(bitrev8((data->bits >> 0) & 0xff) << 0);
IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
- rc_keydown(dev, scancode, data->toggle);
+ rc_keydown(dev, RC_TYPE_JVC, scancode, data->toggle);
data->first = false;
data->old_bits = data->bits;
} else if (data->bits == data->old_bits) {
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index d731da6c414d..ed2c8a1ed8ca 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -35,7 +35,7 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct lirc_codec *lirc = &dev->raw->lirc;
int sample;
- if (!rc_protocols_enabled(dev, RC_BIT_LIRC))
+ if (!(dev->enabled_protocols & RC_BIT_LIRC))
return 0;
if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index 0c55f794c8cf..9f3c9b59f30c 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -216,7 +216,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
unsigned long delay;
- if (!rc_protocols_enabled(dev, RC_BIT_MCE_KBD))
+ if (!(dev->enabled_protocols & RC_BIT_MCE_KBD))
return 0;
if (!is_timing_event(ev)) {
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 35c42e5e270b..7b81fec0820f 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -52,7 +52,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
u8 address, not_address, command, not_command;
bool send_32bits = false;
- if (!rc_protocols_enabled(dev, RC_BIT_NEC))
+ if (!(dev->enabled_protocols & RC_BIT_NEC))
return 0;
if (!is_timing_event(ev)) {
@@ -189,7 +189,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
if (data->is_nec_x)
data->necx_repeat = true;
- rc_keydown(dev, scancode, 0);
+ rc_keydown(dev, RC_TYPE_NEC, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 4295d9b250c8..2ef763928ca4 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -1,6 +1,7 @@
-/* ir-rc5-decoder.c - handle RC5(x) IR Pulse/Space protocol
+/* ir-rc5-decoder.c - decoder for RC5(x) and StreamZap protocols
*
* Copyright (C) 2010 by Mauro Carvalho Chehab
+ * Copyright (C) 2010 by Jarod Wilson
*
* 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
@@ -13,23 +14,22 @@
*/
/*
- * This code handles 14 bits RC5 protocols and 20 bits RC5x protocols.
- * There are other variants that use a different number of bits.
- * This is currently unsupported.
- * It considers a carrier of 36 kHz, with a total of 14/20 bits, where
- * the first two bits are start bits, and a third one is a filing bit
+ * This decoder handles the 14 bit RC5 protocol, 15 bit "StreamZap" protocol
+ * and 20 bit RC5x protocol.
*/
#include "rc-core-priv.h"
#include
#define RC5_NBITS 14
+#define RC5_SZ_NBITS 15
#define RC5X_NBITS 20
#define CHECK_RC5X_NBITS 8
#define RC5_UNIT 888888 /* ns */
#define RC5_BIT_START (1 * RC5_UNIT)
#define RC5_BIT_END (1 * RC5_UNIT)
#define RC5X_SPACE (4 * RC5_UNIT)
+#define RC5_TRAILER (10 * RC5_UNIT) /* In reality, approx 100 */
enum rc5_state {
STATE_INACTIVE,
@@ -51,8 +51,9 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct rc5_dec *data = &dev->raw->rc5;
u8 toggle;
u32 scancode;
+ enum rc_type protocol;
- if (!rc_protocols_enabled(dev, RC_BIT_RC5 | RC_BIT_RC5X))
+ if (!(dev->enabled_protocols & (RC_BIT_RC5 | RC_BIT_RC5X)))
return 0;
if (!is_timing_event(ev)) {
@@ -65,7 +66,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
goto out;
again:
- IR_dprintk(2, "RC5(x) decode started at state %i (%uus %s)\n",
+ IR_dprintk(2, "RC5(x/sz) decode started at state %i (%uus %s)\n",
data->state, TO_US(ev.duration), TO_STR(ev.pulse));
if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
@@ -79,12 +80,15 @@ again:
data->state = STATE_BIT_START;
data->count = 1;
- /* We just need enough bits to get to STATE_CHECK_RC5X */
- data->wanted_bits = RC5X_NBITS;
decrease_duration(&ev, RC5_BIT_START);
goto again;
case STATE_BIT_START:
+ if (!ev.pulse && geq_margin(ev.duration, RC5_TRAILER, RC5_UNIT / 2)) {
+ data->state = STATE_FINISHED;
+ goto again;
+ }
+
if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
break;
@@ -99,9 +103,7 @@ again:
if (!is_transition(&ev, &dev->raw->prev_ev))
break;
- if (data->count == data->wanted_bits)
- data->state = STATE_FINISHED;
- else if (data->count == CHECK_RC5X_NBITS)
+ if (data->count == CHECK_RC5X_NBITS)
data->state = STATE_CHECK_RC5X;
else
data->state = STATE_BIT_START;
@@ -111,13 +113,10 @@ again:
case STATE_CHECK_RC5X:
if (!ev.pulse && geq_margin(ev.duration, RC5X_SPACE, RC5_UNIT / 2)) {
- /* RC5X */
- data->wanted_bits = RC5X_NBITS;
+ data->is_rc5x = true;
decrease_duration(&ev, RC5X_SPACE);
- } else {
- /* RC5 */
- data->wanted_bits = RC5_NBITS;
- }
+ } else
+ data->is_rc5x = false;
data->state = STATE_BIT_START;
goto again;
@@ -125,10 +124,10 @@ again:
if (ev.pulse)
break;
- if (data->wanted_bits == RC5X_NBITS) {
+ if (data->is_rc5x && data->count == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
- if (!rc_protocols_enabled(dev, RC_BIT_RC5X)) {
+ if (!(dev->enabled_protocols & RC_BIT_RC5X)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -138,14 +137,12 @@ again:
toggle = (data->bits & 0x20000) ? 1 : 0;
command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 16 | command << 8 | xdata;
+ protocol = RC_TYPE_RC5X;
- IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
- scancode, toggle);
-
- } else {
+ } else if (!data->is_rc5x && data->count == RC5_NBITS) {
/* RC5 */
u8 command, system;
- if (!rc_protocols_enabled(dev, RC_BIT_RC5)) {
+ if (!(dev->enabled_protocols & RC_BIT_RC5)) {
data->state = STATE_INACTIVE;
return 0;
}
@@ -154,25 +151,41 @@ again:
toggle = (data->bits & 0x00800) ? 1 : 0;
command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 8 | command;
+ protocol = RC_TYPE_RC5;
- IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
- scancode, toggle);
- }
+ } else if (!data->is_rc5x && data->count == RC5_SZ_NBITS) {
+ /* RC5 StreamZap */
+ u8 command, system;
+ if (!(dev->enabled_protocols & RC_BIT_RC5_SZ)) {
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+ command = (data->bits & 0x0003F) >> 0;
+ system = (data->bits & 0x02FC0) >> 6;
+ toggle = (data->bits & 0x01000) ? 1 : 0;
+ scancode = system << 6 | command;
+ protocol = RC_TYPE_RC5_SZ;
- rc_keydown(dev, scancode, toggle);
+ } else
+ break;
+
+ IR_dprintk(1, "RC5(x/sz) scancode 0x%06x (p: %u, t: %u)\n",
+ scancode, protocol, toggle);
+
+ rc_keydown(dev, protocol, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
out:
- IR_dprintk(1, "RC5(x) decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ IR_dprintk(1, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
+ data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
static struct ir_raw_handler rc5_handler = {
- .protocols = RC_BIT_RC5 | RC_BIT_RC5X,
+ .protocols = RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ,
.decode = ir_rc5_decode,
};
@@ -180,7 +193,7 @@ static int __init ir_rc5_decode_init(void)
{
ir_raw_handler_register(&rc5_handler);
- printk(KERN_INFO "IR RC5(x) protocol handler initialized\n");
+ printk(KERN_INFO "IR RC5(x/sz) protocol handler initialized\n");
return 0;
}
@@ -193,6 +206,6 @@ module_init(ir_rc5_decode_init);
module_exit(ir_rc5_decode_exit);
MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_AUTHOR("Mauro Carvalho Chehab and Jarod Wilson");
MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("RC5(x) IR protocol decoder");
+MODULE_DESCRIPTION("RC5(x/sz) IR protocol decoder");
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
deleted file mode 100644
index dc18b7434db8..000000000000
--- a/drivers/media/rc/ir-rc5-sz-decoder.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab
- * Copyright (C) 2010 by Jarod Wilson
- *
- * 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 of the License.
- *
- * 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.
- */
-
-/*
- * This code handles the 15 bit RC5-ish protocol used by the Streamzap
- * PC Remote.
- * It considers a carrier of 36 kHz, with a total of 15 bits, where
- * the first two bits are start bits, and a third one is a filing bit
- */
-
-#include "rc-core-priv.h"
-#include
-
-#define RC5_SZ_NBITS 15
-#define RC5_UNIT 888888 /* ns */
-#define RC5_BIT_START (1 * RC5_UNIT)
-#define RC5_BIT_END (1 * RC5_UNIT)
-
-enum rc5_sz_state {
- STATE_INACTIVE,
- STATE_BIT_START,
- STATE_BIT_END,
- STATE_FINISHED,
-};
-
-/**
- * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
- * @dev: the struct rc_dev descriptor of the device
- * @ev: the struct ir_raw_event descriptor of the pulse/space
- *
- * This function returns -EINVAL if the pulse violates the state machine
- */
-static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
-{
- struct rc5_sz_dec *data = &dev->raw->rc5_sz;
- u8 toggle, command, system;
- u32 scancode;
-
- if (!rc_protocols_enabled(dev, RC_BIT_RC5_SZ))
- return 0;
-
- if (!is_timing_event(ev)) {
- if (ev.reset)
- data->state = STATE_INACTIVE;
- return 0;
- }
-
- if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
- goto out;
-
-again:
- IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
-
- if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
- return 0;
-
- switch (data->state) {
-
- case STATE_INACTIVE:
- if (!ev.pulse)
- break;
-
- data->state = STATE_BIT_START;
- data->count = 1;
- data->wanted_bits = RC5_SZ_NBITS;
- decrease_duration(&ev, RC5_BIT_START);
- goto again;
-
- case STATE_BIT_START:
- if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
- break;
-
- data->bits <<= 1;
- if (!ev.pulse)
- data->bits |= 1;
- data->count++;
- data->state = STATE_BIT_END;
- return 0;
-
- case STATE_BIT_END:
- if (!is_transition(&ev, &dev->raw->prev_ev))
- break;
-
- if (data->count == data->wanted_bits)
- data->state = STATE_FINISHED;
- else
- data->state = STATE_BIT_START;
-
- decrease_duration(&ev, RC5_BIT_END);
- goto again;
-
- case STATE_FINISHED:
- if (ev.pulse)
- break;
-
- /* RC5-sz */
- command = (data->bits & 0x0003F) >> 0;
- system = (data->bits & 0x02FC0) >> 6;
- toggle = (data->bits & 0x01000) ? 1 : 0;
- scancode = system << 6 | command;
-
- IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
- scancode, toggle);
-
- rc_keydown(dev, scancode, toggle);
- data->state = STATE_INACTIVE;
- return 0;
- }
-
-out:
- IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
- data->state = STATE_INACTIVE;
- return -EINVAL;
-}
-
-static struct ir_raw_handler rc5_sz_handler = {
- .protocols = RC_BIT_RC5_SZ,
- .decode = ir_rc5_sz_decode,
-};
-
-static int __init ir_rc5_sz_decode_init(void)
-{
- ir_raw_handler_register(&rc5_sz_handler);
-
- printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
- return 0;
-}
-
-static void __exit ir_rc5_sz_decode_exit(void)
-{
- ir_raw_handler_unregister(&rc5_sz_handler);
-}
-
-module_init(ir_rc5_sz_decode_init);
-module_exit(ir_rc5_sz_decode_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jarod Wilson ");
-MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
-MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index cfbd64e3999c..f1f098e22f7e 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -88,10 +88,11 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct rc6_dec *data = &dev->raw->rc6;
u32 scancode;
u8 toggle;
+ enum rc_type protocol;
- if (!rc_protocols_enabled(dev, RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 |
- RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 |
- RC_BIT_RC6_MCE))
+ if (!(dev->enabled_protocols &
+ (RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 |
+ RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE)))
return 0;
if (!is_timing_event(ev)) {
@@ -233,9 +234,11 @@ again:
case RC6_MODE_0:
scancode = data->body;
toggle = data->toggle;
+ protocol = RC_TYPE_RC6_0;
IR_dprintk(1, "RC6(0) scancode 0x%04x (toggle: %u)\n",
scancode, toggle);
break;
+
case RC6_MODE_6A:
if (data->count > CHAR_BIT * sizeof data->body) {
IR_dprintk(1, "RC6 too many (%u) data bits\n",
@@ -244,23 +247,39 @@ again:
}
scancode = data->body;
- if (data->count == RC6_6A_32_NBITS &&
- (scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
- /* MCE RC */
- toggle = (scancode & RC6_6A_MCE_TOGGLE_MASK) ? 1 : 0;
- scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
- } else {
+ switch (data->count) {
+ case 20:
+ protocol = RC_TYPE_RC6_6A_20;
toggle = 0;
+ break;
+ case 24:
+ protocol = RC_BIT_RC6_6A_24;
+ toggle = 0;
+ break;
+ case 32:
+ if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
+ protocol = RC_TYPE_RC6_MCE;
+ scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
+ toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
+ } else {
+ protocol = RC_BIT_RC6_6A_32;
+ toggle = 0;
+ }
+ break;
+ default:
+ IR_dprintk(1, "RC6(6A) unsupported length\n");
+ goto out;
}
- IR_dprintk(1, "RC6(6A) scancode 0x%08x (toggle: %u)\n",
- scancode, toggle);
+
+ IR_dprintk(1, "RC6(6A) proto 0x%04x, scancode 0x%08x (toggle: %u)\n",
+ protocol, scancode, toggle);
break;
default:
IR_dprintk(1, "RC6 unknown mode\n");
goto out;
}
- rc_keydown(dev, scancode, toggle);
+ rc_keydown(dev, protocol, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index eb715f04dc27..ad1dc6ae21fc 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -58,7 +58,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
u32 scancode;
u8 address, command, not_command;
- if (!rc_protocols_enabled(dev, RC_BIT_SANYO))
+ if (!(dev->enabled_protocols & RC_BIT_SANYO))
return 0;
if (!is_timing_event(ev)) {
@@ -167,7 +167,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
scancode = address << 8 | command;
IR_dprintk(1, "SANYO scancode: 0x%06x\n", scancode);
- rc_keydown(dev, scancode, 0);
+ rc_keydown(dev, RC_TYPE_SANYO, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index 66d20394ceaa..b7acdbae8159 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -48,7 +48,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
struct sharp_dec *data = &dev->raw->sharp;
u32 msg, echo, address, command, scancode;
- if (!rc_protocols_enabled(dev, RC_BIT_SHARP))
+ if (!(dev->enabled_protocols & RC_BIT_SHARP))
return 0;
if (!is_timing_event(ev)) {
@@ -162,7 +162,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
scancode = address << 8 | command;
IR_dprintk(1, "Sharp scancode 0x%04x\n", scancode);
- rc_keydown(dev, scancode, 0);
+ rc_keydown(dev, RC_TYPE_SHARP, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 599c19a73360..d12dc3da5931 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -42,11 +42,12 @@ enum sony_state {
static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
struct sony_dec *data = &dev->raw->sony;
+ enum rc_type protocol;
u32 scancode;
u8 device, subdevice, function;
- if (!rc_protocols_enabled(dev, RC_BIT_SONY12 | RC_BIT_SONY15 |
- RC_BIT_SONY20))
+ if (!(dev->enabled_protocols &
+ (RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20)))
return 0;
if (!is_timing_event(ev)) {
@@ -124,31 +125,34 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
- if (!rc_protocols_enabled(dev, RC_BIT_SONY12)) {
+ if (!(dev->enabled_protocols & RC_BIT_SONY12)) {
data->state = STATE_INACTIVE;
return 0;
}
device = bitrev8((data->bits << 3) & 0xF8);
subdevice = 0;
function = bitrev8((data->bits >> 4) & 0xFE);
+ protocol = RC_TYPE_SONY12;
break;
case 15:
- if (!rc_protocols_enabled(dev, RC_BIT_SONY15)) {
+ if (!(dev->enabled_protocols & RC_BIT_SONY15)) {
data->state = STATE_INACTIVE;
return 0;
}
device = bitrev8((data->bits >> 0) & 0xFF);
subdevice = 0;
function = bitrev8((data->bits >> 7) & 0xFE);
+ protocol = RC_TYPE_SONY15;
break;
case 20:
- if (!rc_protocols_enabled(dev, RC_BIT_SONY20)) {
+ if (!(dev->enabled_protocols & RC_BIT_SONY20)) {
data->state = STATE_INACTIVE;
return 0;
}
device = bitrev8((data->bits >> 5) & 0xF8);
subdevice = bitrev8((data->bits >> 0) & 0xFF);
function = bitrev8((data->bits >> 12) & 0xFE);
+ protocol = RC_TYPE_SONY20;
break;
default:
IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
@@ -157,7 +161,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
scancode = device << 16 | subdevice << 8 | function;
IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
- rc_keydown(dev, scancode, 0);
+ rc_keydown(dev, protocol, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c
new file mode 100644
index 000000000000..1017d4816e8d
--- /dev/null
+++ b/drivers/media/rc/ir-xmp-decoder.c
@@ -0,0 +1,225 @@
+/* ir-xmp-decoder.c - handle XMP IR Pulse/Space protocol
+ *
+ * Copyright (C) 2014 by Marcel Mol
+ *
+ * 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 of the License.
+ *
+ * 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.
+ *
+ * - Based on info from http://www.hifi-remote.com
+ * - Ignore Toggle=9 frames
+ * - Ignore XMP-1 XMP-2 difference, always store 16 bit OBC
+ */
+
+#include
+#include
+#include "rc-core-priv.h"
+
+#define XMP_UNIT 136000 /* ns */
+#define XMP_LEADER 210000 /* ns */
+#define XMP_NIBBLE_PREFIX 760000 /* ns */
+#define XMP_HALFFRAME_SPACE 13800000 /* ns */
+#define XMP_TRAILER_SPACE 20000000 /* should be 80ms but not all dureation supliers can go that high */
+
+enum xmp_state {
+ STATE_INACTIVE,
+ STATE_LEADER_PULSE,
+ STATE_NIBBLE_SPACE,
+};
+
+/**
+ * ir_xmp_decode() - Decode one XMP pulse or space
+ * @dev: the struct rc_dev descriptor of the device
+ * @duration: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+ struct xmp_dec *data = &dev->raw->xmp;
+
+ if (!(dev->enabled_protocols & RC_BIT_XMP))
+ return 0;
+
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ IR_dprintk(2, "XMP decode started at state %d %d (%uus %s)\n",
+ data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+
+ switch (data->state) {
+
+ case STATE_INACTIVE:
+ if (!ev.pulse)
+ break;
+
+ if (eq_margin(ev.duration, XMP_LEADER, XMP_UNIT / 2)) {
+ data->count = 0;
+ data->state = STATE_NIBBLE_SPACE;
+ }
+
+ return 0;
+
+ case STATE_LEADER_PULSE:
+ if (!ev.pulse)
+ break;
+
+ if (eq_margin(ev.duration, XMP_LEADER, XMP_UNIT / 2))
+ data->state = STATE_NIBBLE_SPACE;
+
+ return 0;
+
+ case STATE_NIBBLE_SPACE:
+ if (ev.pulse)
+ break;
+
+ if (geq_margin(ev.duration, XMP_TRAILER_SPACE, XMP_NIBBLE_PREFIX)) {
+ int divider, i;
+ u8 addr, subaddr, subaddr2, toggle, oem, obc1, obc2, sum1, sum2;
+ u32 *n;
+ u32 scancode;
+
+ if (data->count != 16) {
+ IR_dprintk(2, "received TRAILER period at index %d: %u\n",
+ data->count, ev.duration);
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+ }
+
+ n = data->durations;
+ /*
+ * the 4th nibble should be 15 so base the divider on this
+ * to transform durations into nibbles. Substract 2000 from
+ * the divider to compensate for fluctuations in the signal
+ */
+ divider = (n[3] - XMP_NIBBLE_PREFIX) / 15 - 2000;
+ if (divider < 50) {
+ IR_dprintk(2, "divider to small %d.\n", divider);
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+ }
+
+ /* convert to nibbles and do some sanity checks */
+ for (i = 0; i < 16; i++)
+ n[i] = (n[i] - XMP_NIBBLE_PREFIX) / divider;
+ sum1 = (15 + n[0] + n[1] + n[2] + n[3] +
+ n[4] + n[5] + n[6] + n[7]) % 16;
+ sum2 = (15 + n[8] + n[9] + n[10] + n[11] +
+ n[12] + n[13] + n[14] + n[15]) % 16;
+
+ if (sum1 != 15 || sum2 != 15) {
+ IR_dprintk(2, "checksum errors sum1=0x%X sum2=0x%X\n",
+ sum1, sum2);
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+ }
+
+ subaddr = n[0] << 4 | n[2];
+ subaddr2 = n[8] << 4 | n[11];
+ oem = n[4] << 4 | n[5];
+ addr = n[6] << 4 | n[7];
+ toggle = n[10];
+ obc1 = n[12] << 4 | n[13];
+ obc2 = n[14] << 4 | n[15];
+ if (subaddr != subaddr2) {
+ IR_dprintk(2, "subaddress nibbles mismatch 0x%02X != 0x%02X\n",
+ subaddr, subaddr2);
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+ }
+ if (oem != 0x44)
+ IR_dprintk(1, "Warning: OEM nibbles 0x%02X. Expected 0x44\n",
+ oem);
+
+ scancode = addr << 24 | subaddr << 16 |
+ obc1 << 8 | obc2;
+ IR_dprintk(1, "XMP scancode 0x%06x\n", scancode);
+
+ if (toggle == 0) {
+ rc_keydown(dev, RC_TYPE_XMP, scancode, 0);
+ } else {
+ rc_repeat(dev);
+ IR_dprintk(1, "Repeat last key\n");
+ }
+ data->state = STATE_INACTIVE;
+
+ return 0;
+
+ } else if (geq_margin(ev.duration, XMP_HALFFRAME_SPACE, XMP_NIBBLE_PREFIX)) {
+ /* Expect 8 or 16 nibble pulses. 16 in case of 'final' frame */
+ if (data->count == 16) {
+ IR_dprintk(2, "received half frame pulse at index %d. Probably a final frame key-up event: %u\n",
+ data->count, ev.duration);
+ /*
+ * TODO: for now go back to half frame position
+ * so trailer can be found and key press
+ * can be handled.
+ */
+ data->count = 8;
+ }
+
+ else if (data->count != 8)
+ IR_dprintk(2, "received half frame pulse at index %d: %u\n",
+ data->count, ev.duration);
+ data->state = STATE_LEADER_PULSE;
+
+ return 0;
+
+ } else if (geq_margin(ev.duration, XMP_NIBBLE_PREFIX, XMP_UNIT)) {
+ /* store nibble raw data, decode after trailer */
+ if (data->count == 16) {
+ IR_dprintk(2, "to many pulses (%d) ignoring: %u\n",
+ data->count, ev.duration);
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+ }
+ data->durations[data->count] = ev.duration;
+ data->count++;
+ data->state = STATE_LEADER_PULSE;
+
+ return 0;
+
+ }
+
+ break;
+ }
+
+ IR_dprintk(1, "XMP decode failed at count %d state %d (%uus %s)\n",
+ data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+}
+
+static struct ir_raw_handler xmp_handler = {
+ .protocols = RC_BIT_XMP,
+ .decode = ir_xmp_decode,
+};
+
+static int __init ir_xmp_decode_init(void)
+{
+ ir_raw_handler_register(&xmp_handler);
+
+ printk(KERN_INFO "IR XMP protocol handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_xmp_decode_exit(void)
+{
+ ir_raw_handler_unregister(&xmp_handler);
+}
+
+module_init(ir_xmp_decode_init);
+module_exit(ir_xmp_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marcel Mol ");
+MODULE_AUTHOR("MESA Consulting (http://www.mesa.nl)");
+MODULE_DESCRIPTION("XMP IR protocol decoder");
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index ab24cc6d3655..447fe35862dc 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -1563,7 +1563,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
/* set up ir-core props */
rdev->priv = itdev;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
rdev->open = ite_open;
rdev->close = ite_close;
rdev->s_idle = ite_s_idle;
@@ -1709,12 +1709,12 @@ static struct pnp_driver ite_driver = {
.shutdown = ite_shutdown,
};
-static int ite_init(void)
+static int __init ite_init(void)
{
return pnp_register_driver(&ite_driver);
}
-static void ite_exit(void)
+static void __exit ite_exit(void)
{
pnp_unregister_driver(&ite_driver);
}
diff --git a/drivers/media/rc/keymaps/rc-ati-x10.c b/drivers/media/rc/keymaps/rc-ati-x10.c
index 81506440eded..4bdc709ec54d 100644
--- a/drivers/media/rc/keymaps/rc-ati-x10.c
+++ b/drivers/media/rc/keymaps/rc-ati-x10.c
@@ -26,7 +26,42 @@
#include
#include
+/*
+ * Intended usage comments below are from vendor-supplied
+ * Source: ATI REMOTE WONDER™ Installation Guide
+ * http://www2.ati.com/manuals/remctrl.pdf
+ *
+ * Scancodes were in strict left-right, top-bottom order on the
+ * original ATI Remote Wonder, but were moved on later models.
+ *
+ * Keys A-F are intended to be user-programmable.
+ */
+
static struct rc_map_table ati_x10[] = {
+ /* keyboard - Above the cursor pad */
+ { 0x00, KEY_A },
+ { 0x01, KEY_B },
+ { 0x02, KEY_POWER }, /* Power */
+
+ { 0x03, KEY_TV }, /* TV */
+ { 0x04, KEY_DVD }, /* DVD */
+ { 0x05, KEY_WWW }, /* WEB */
+ { 0x06, KEY_BOOKMARKS }, /* "book": Open Media Library */
+ { 0x07, KEY_EDIT }, /* "hand": Toggle left mouse button (grab) */
+
+ /* Mouse emulation pad goes here, handled by driver separately */
+
+ { 0x09, KEY_VOLUMEDOWN }, /* VOL + */
+ { 0x08, KEY_VOLUMEUP }, /* VOL - */
+ { 0x0a, KEY_MUTE }, /* MUTE */
+ { 0x0b, KEY_CHANNELUP }, /* CH + */
+ { 0x0c, KEY_CHANNELDOWN },/* CH - */
+
+ /*
+ * We could use KEY_NUMERIC_x for these, but the X11 protocol
+ * has problems with keycodes greater than 255, so avoid those high
+ * keycodes in default maps.
+ */
{ 0x0d, KEY_1 },
{ 0x0e, KEY_2 },
{ 0x0f, KEY_3 },
@@ -36,46 +71,45 @@ static struct rc_map_table ati_x10[] = {
{ 0x13, KEY_7 },
{ 0x14, KEY_8 },
{ 0x15, KEY_9 },
+ { 0x16, KEY_MENU }, /* "menu": DVD root menu */
+ /* KEY_NUMERIC_STAR? */
{ 0x17, KEY_0 },
- { 0x00, KEY_A },
- { 0x01, KEY_B },
- { 0x19, KEY_C },
- { 0x1b, KEY_D },
- { 0x21, KEY_E },
- { 0x23, KEY_F },
+ { 0x18, KEY_SETUP }, /* "check": DVD setup menu */
+ /* KEY_NUMERIC_POUND? */
- { 0x18, KEY_KPENTER }, /* "check" */
- { 0x16, KEY_MENU }, /* "menu" */
- { 0x02, KEY_POWER }, /* Power */
- { 0x03, KEY_TV }, /* TV */
- { 0x04, KEY_DVD }, /* DVD */
- { 0x05, KEY_WWW }, /* WEB */
- { 0x06, KEY_BOOKMARKS }, /* "book" */
- { 0x07, KEY_EDIT }, /* "hand" */
- { 0x1c, KEY_COFFEE }, /* "timer" */
- { 0x20, KEY_FRONT }, /* "max" */
- { 0x1d, KEY_LEFT }, /* left */
- { 0x1f, KEY_RIGHT }, /* right */
- { 0x22, KEY_DOWN }, /* down */
+ /* DVD navigation buttons */
+ { 0x19, KEY_C },
{ 0x1a, KEY_UP }, /* up */
+ { 0x1b, KEY_D },
+
+ { 0x1c, KEY_PROPS }, /* "timer" Should be Data On Screen */
+ /* Symbol is "circle nailed to box" */
+ { 0x1d, KEY_LEFT }, /* left */
{ 0x1e, KEY_OK }, /* "OK" */
- { 0x09, KEY_VOLUMEDOWN }, /* VOL + */
- { 0x08, KEY_VOLUMEUP }, /* VOL - */
- { 0x0a, KEY_MUTE }, /* MUTE */
- { 0x0b, KEY_CHANNELUP }, /* CH + */
- { 0x0c, KEY_CHANNELDOWN },/* CH - */
+ { 0x1f, KEY_RIGHT }, /* right */
+ { 0x20, KEY_SCREEN }, /* "max" (X11 warning: 0x177) */
+ /* Should be AC View Toggle, but
+ that's not in .
+ KEY_ZOOM (0x174)? */
+ { 0x21, KEY_E },
+ { 0x22, KEY_DOWN }, /* down */
+ { 0x23, KEY_F },
+ /* Play/stop/pause buttons */
+ { 0x24, KEY_REWIND }, /* (<<) Rewind */
+ { 0x25, KEY_PLAY }, /* ( >) Play (KEY_PLAYCD?) */
+ { 0x26, KEY_FASTFORWARD }, /* (>>) Fast forward */
+
{ 0x27, KEY_RECORD }, /* ( o) red */
- { 0x25, KEY_PLAY }, /* ( >) */
- { 0x24, KEY_REWIND }, /* (<<) */
- { 0x26, KEY_FORWARD }, /* (>>) */
- { 0x28, KEY_STOP }, /* ([]) */
- { 0x29, KEY_PAUSE }, /* ('') */
- { 0x2b, KEY_PREVIOUS }, /* (<-) */
+ { 0x28, KEY_STOPCD }, /* ([]) Stop (KEY_STOP is something else!) */
+ { 0x29, KEY_PAUSE }, /* ('') Pause (KEY_PAUSECD?) */
+
+ /* Extra keys, not on the original ATI remote */
{ 0x2a, KEY_NEXT }, /* (>+) */
- { 0x2d, KEY_INFO }, /* PLAYING */
+ { 0x2b, KEY_PREVIOUS }, /* (<-) */
+ { 0x2d, KEY_INFO }, /* PLAYING (X11 warning: 0x166) */
{ 0x2e, KEY_HOME }, /* TOP */
{ 0x2f, KEY_END }, /* END */
- { 0x30, KEY_SELECT }, /* SELECT */
+ { 0x30, KEY_SELECT }, /* SELECT (X11 warning: 0x161) */
};
static struct rc_map_list ati_x10_map = {
diff --git a/drivers/media/rc/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index d6519f8ac95a..520a96f2ff86 100644
--- a/drivers/media/rc/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -30,8 +30,8 @@ static struct rc_map_table behold[] = {
/* 0x1c 0x12 *
* TV/FM POWER *
* */
- { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
- { 0x6b8612, KEY_POWER },
+ { 0x866b1c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
+ { 0x866b12, KEY_POWER },
/* 0x01 0x02 0x03 *
* 1 2 3 *
@@ -42,28 +42,28 @@ static struct rc_map_table behold[] = {
* 0x07 0x08 0x09 *
* 7 8 9 *
* */
- { 0x6b8601, KEY_1 },
- { 0x6b8602, KEY_2 },
- { 0x6b8603, KEY_3 },
- { 0x6b8604, KEY_4 },
- { 0x6b8605, KEY_5 },
- { 0x6b8606, KEY_6 },
- { 0x6b8607, KEY_7 },
- { 0x6b8608, KEY_8 },
- { 0x6b8609, KEY_9 },
+ { 0x866b01, KEY_1 },
+ { 0x866b02, KEY_2 },
+ { 0x866b03, KEY_3 },
+ { 0x866b04, KEY_4 },
+ { 0x866b05, KEY_5 },
+ { 0x866b06, KEY_6 },
+ { 0x866b07, KEY_7 },
+ { 0x866b08, KEY_8 },
+ { 0x866b09, KEY_9 },
/* 0x0a 0x00 0x17 *
* RECALL 0 MODE *
* */
- { 0x6b860a, KEY_AGAIN },
- { 0x6b8600, KEY_0 },
- { 0x6b8617, KEY_MODE },
+ { 0x866b0a, KEY_AGAIN },
+ { 0x866b00, KEY_0 },
+ { 0x866b17, KEY_MODE },
/* 0x14 0x10 *
* ASPECT FULLSCREEN *
* */
- { 0x6b8614, KEY_SCREEN },
- { 0x6b8610, KEY_ZOOM },
+ { 0x866b14, KEY_SCREEN },
+ { 0x866b10, KEY_ZOOM },
/* 0x0b *
* Up *
@@ -74,17 +74,17 @@ static struct rc_map_table behold[] = {
* 0x015 *
* Down *
* */
- { 0x6b860b, KEY_CHANNELUP },
- { 0x6b8618, KEY_VOLUMEDOWN },
- { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */
- { 0x6b860c, KEY_VOLUMEUP },
- { 0x6b8615, KEY_CHANNELDOWN },
+ { 0x866b0b, KEY_CHANNELUP },
+ { 0x866b18, KEY_VOLUMEDOWN },
+ { 0x866b16, KEY_OK }, /* XXX KEY_ENTER */
+ { 0x866b0c, KEY_VOLUMEUP },
+ { 0x866b15, KEY_CHANNELDOWN },
/* 0x11 0x0d *
* MUTE INFO *
* */
- { 0x6b8611, KEY_MUTE },
- { 0x6b860d, KEY_INFO },
+ { 0x866b11, KEY_MUTE },
+ { 0x866b0d, KEY_INFO },
/* 0x0f 0x1b 0x1a *
* RECORD PLAY/PAUSE STOP *
@@ -93,26 +93,26 @@ static struct rc_map_table behold[] = {
*TELETEXT AUDIO SOURCE *
* RED YELLOW *
* */
- { 0x6b860f, KEY_RECORD },
- { 0x6b861b, KEY_PLAYPAUSE },
- { 0x6b861a, KEY_STOP },
- { 0x6b860e, KEY_TEXT },
- { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */
- { 0x6b861e, KEY_VIDEO },
+ { 0x866b0f, KEY_RECORD },
+ { 0x866b1b, KEY_PLAYPAUSE },
+ { 0x866b1a, KEY_STOP },
+ { 0x866b0e, KEY_TEXT },
+ { 0x866b1f, KEY_RED }, /*XXX KEY_AUDIO */
+ { 0x866b1e, KEY_VIDEO },
/* 0x1d 0x13 0x19 *
* SLEEP PREVIEW DVB *
* GREEN BLUE *
* */
- { 0x6b861d, KEY_SLEEP },
- { 0x6b8613, KEY_GREEN },
- { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */
+ { 0x866b1d, KEY_SLEEP },
+ { 0x866b13, KEY_GREEN },
+ { 0x866b19, KEY_BLUE }, /* XXX KEY_SAT */
/* 0x58 0x5c *
* FREEZE SNAPSHOT *
* */
- { 0x6b8658, KEY_SLOW },
- { 0x6b865c, KEY_CAMERA },
+ { 0x866b58, KEY_SLOW },
+ { 0x866b5c, KEY_CAMERA },
};
diff --git a/drivers/media/rc/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
index 8ec881adb7cf..4c50f33c7c41 100644
--- a/drivers/media/rc/keymaps/rc-nebula.c
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -14,68 +14,68 @@
#include
static struct rc_map_table nebula[] = {
- { 0x00, KEY_0 },
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
- { 0x0a, KEY_TV },
- { 0x0b, KEY_AUX },
- { 0x0c, KEY_DVD },
- { 0x0d, KEY_POWER },
- { 0x0e, KEY_CAMERA }, /* labelled 'Picture' */
- { 0x0f, KEY_AUDIO },
- { 0x10, KEY_INFO },
- { 0x11, KEY_F13 }, /* 16:9 */
- { 0x12, KEY_F14 }, /* 14:9 */
- { 0x13, KEY_EPG },
- { 0x14, KEY_EXIT },
- { 0x15, KEY_MENU },
- { 0x16, KEY_UP },
- { 0x17, KEY_DOWN },
- { 0x18, KEY_LEFT },
- { 0x19, KEY_RIGHT },
- { 0x1a, KEY_ENTER },
- { 0x1b, KEY_CHANNELUP },
- { 0x1c, KEY_CHANNELDOWN },
- { 0x1d, KEY_VOLUMEUP },
- { 0x1e, KEY_VOLUMEDOWN },
- { 0x1f, KEY_RED },
- { 0x20, KEY_GREEN },
- { 0x21, KEY_YELLOW },
- { 0x22, KEY_BLUE },
- { 0x23, KEY_SUBTITLE },
- { 0x24, KEY_F15 }, /* AD */
- { 0x25, KEY_TEXT },
- { 0x26, KEY_MUTE },
- { 0x27, KEY_REWIND },
- { 0x28, KEY_STOP },
- { 0x29, KEY_PLAY },
- { 0x2a, KEY_FASTFORWARD },
- { 0x2b, KEY_F16 }, /* chapter */
- { 0x2c, KEY_PAUSE },
- { 0x2d, KEY_PLAY },
- { 0x2e, KEY_RECORD },
- { 0x2f, KEY_F17 }, /* picture in picture */
- { 0x30, KEY_KPPLUS }, /* zoom in */
- { 0x31, KEY_KPMINUS }, /* zoom out */
- { 0x32, KEY_F18 }, /* capture */
- { 0x33, KEY_F19 }, /* web */
- { 0x34, KEY_EMAIL },
- { 0x35, KEY_PHONE },
- { 0x36, KEY_PC },
+ { 0x0000, KEY_0 },
+ { 0x0001, KEY_1 },
+ { 0x0002, KEY_2 },
+ { 0x0003, KEY_3 },
+ { 0x0004, KEY_4 },
+ { 0x0005, KEY_5 },
+ { 0x0006, KEY_6 },
+ { 0x0007, KEY_7 },
+ { 0x0008, KEY_8 },
+ { 0x0009, KEY_9 },
+ { 0x000a, KEY_TV },
+ { 0x000b, KEY_AUX },
+ { 0x000c, KEY_DVD },
+ { 0x000d, KEY_POWER },
+ { 0x000e, KEY_CAMERA }, /* labelled 'Picture' */
+ { 0x000f, KEY_AUDIO },
+ { 0x0010, KEY_INFO },
+ { 0x0011, KEY_F13 }, /* 16:9 */
+ { 0x0012, KEY_F14 }, /* 14:9 */
+ { 0x0013, KEY_EPG },
+ { 0x0014, KEY_EXIT },
+ { 0x0015, KEY_MENU },
+ { 0x0016, KEY_UP },
+ { 0x0017, KEY_DOWN },
+ { 0x0018, KEY_LEFT },
+ { 0x0019, KEY_RIGHT },
+ { 0x001a, KEY_ENTER },
+ { 0x001b, KEY_CHANNELUP },
+ { 0x001c, KEY_CHANNELDOWN },
+ { 0x001d, KEY_VOLUMEUP },
+ { 0x001e, KEY_VOLUMEDOWN },
+ { 0x001f, KEY_RED },
+ { 0x0020, KEY_GREEN },
+ { 0x0021, KEY_YELLOW },
+ { 0x0022, KEY_BLUE },
+ { 0x0023, KEY_SUBTITLE },
+ { 0x0024, KEY_F15 }, /* AD */
+ { 0x0025, KEY_TEXT },
+ { 0x0026, KEY_MUTE },
+ { 0x0027, KEY_REWIND },
+ { 0x0028, KEY_STOP },
+ { 0x0029, KEY_PLAY },
+ { 0x002a, KEY_FASTFORWARD },
+ { 0x002b, KEY_F16 }, /* chapter */
+ { 0x002c, KEY_PAUSE },
+ { 0x002d, KEY_PLAY },
+ { 0x002e, KEY_RECORD },
+ { 0x002f, KEY_F17 }, /* picture in picture */
+ { 0x0030, KEY_KPPLUS }, /* zoom in */
+ { 0x0031, KEY_KPMINUS }, /* zoom out */
+ { 0x0032, KEY_F18 }, /* capture */
+ { 0x0033, KEY_F19 }, /* web */
+ { 0x0034, KEY_EMAIL },
+ { 0x0035, KEY_PHONE },
+ { 0x0036, KEY_PC },
};
static struct rc_map_list nebula_map = {
.map = {
.scan = nebula,
.size = ARRAY_SIZE(nebula),
- .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_NEBULA,
}
};
diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c
index f9a07578d985..23c061174ed7 100644
--- a/drivers/media/rc/keymaps/rc-streamzap.c
+++ b/drivers/media/rc/keymaps/rc-streamzap.c
@@ -15,9 +15,7 @@
static struct rc_map_table streamzap[] = {
/*
* The Streamzap remote is almost, but not quite, RC-5, as it has an extra
- * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
- * an additional RC-5-sz decoder is being deployed to support it, but it
- * may be possible to merge it back with the standard RC-5 decoder.
+ * bit in it.
*/
{ 0x28c0, KEY_NUMERIC_0 },
{ 0x28c1, KEY_NUMERIC_1 },
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index d5c1df3c9db1..45b0894288e5 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -187,6 +187,7 @@
#define VENDOR_CONEXANT 0x0572
#define VENDOR_TWISTEDMELON 0x2596
#define VENDOR_HAUPPAUGE 0x2040
+#define VENDOR_PCTV 0x2013
enum mceusb_model_type {
MCE_GEN2 = 0, /* Most boards */
@@ -240,7 +241,6 @@ static const struct mceusb_model mceusb_model[] = {
* remotes, but we should have something handy,
* to allow testing it
*/
- .rc_map = RC_MAP_HAUPPAUGE,
.name = "Conexant Hybrid TV (cx231xx) MCE IR",
},
[CX_HYBRID_TV] = {
@@ -248,7 +248,6 @@ static const struct mceusb_model mceusb_model[] = {
.name = "Conexant Hybrid TV (cx231xx) MCE IR",
},
[HAUPPAUGE_CX_HYBRID_TV] = {
- .rc_map = RC_MAP_HAUPPAUGE,
.no_tx = 1, /* eeprom says it has no tx */
.name = "Conexant Hybrid TV (cx231xx) MCE IR no TX",
},
@@ -396,6 +395,13 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Hauppauge WINTV-HVR-HVR 930C-HD - based on cx231xx */
{ USB_DEVICE(VENDOR_HAUPPAUGE, 0xb130),
.driver_info = HAUPPAUGE_CX_HYBRID_TV },
+ { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb131),
+ .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+ { USB_DEVICE(VENDOR_PCTV, 0x0259),
+ .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+ { USB_DEVICE(VENDOR_PCTV, 0x025e),
+ .driver_info = HAUPPAUGE_CX_HYBRID_TV },
+
/* Terminating entry */
{ }
};
@@ -1192,8 +1198,10 @@ static void mceusb_flash_led(struct mceusb_dev *ir)
mce_async_out(ir, FLASH_LED, sizeof(FLASH_LED));
}
-static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
+static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir,
+ struct usb_interface *intf)
{
+ struct usb_device *udev = usb_get_dev(interface_to_usbdev(intf));
struct device *dev = ir->dev;
struct rc_dev *rc;
int ret;
@@ -1219,7 +1227,7 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->dev.parent = dev;
rc->priv = ir;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rc, RC_BIT_ALL);
+ rc->allowed_protocols = RC_BIT_ALL;
rc->timeout = MS_TO_NS(100);
if (!ir->flags.no_tx) {
rc->s_tx_mask = mceusb_set_tx_mask;
@@ -1227,8 +1235,19 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->tx_ir = mceusb_tx_ir;
}
rc->driver_name = DRIVER_NAME;
- rc->map_name = mceusb_model[ir->model].rc_map ?
- mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
+
+ switch (le16_to_cpu(udev->descriptor.idVendor)) {
+ case VENDOR_HAUPPAUGE:
+ rc->map_name = RC_MAP_HAUPPAUGE;
+ break;
+ case VENDOR_PCTV:
+ rc->map_name = RC_MAP_PINNACLE_PCTV_HD;
+ break;
+ default:
+ rc->map_name = RC_MAP_RC6_MCE;
+ }
+ if (mceusb_model[ir->model].rc_map)
+ rc->map_name = mceusb_model[ir->model].rc_map;
ret = rc_register_device(rc);
if (ret < 0) {
@@ -1343,7 +1362,7 @@ static int mceusb_dev_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
- ir->rc = mceusb_init_rc_dev(ir);
+ ir->rc = mceusb_init_rc_dev(ir, intf);
if (!ir->rc)
goto rc_dev_fail;
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index d244e1a83f43..7f4fd859bba5 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -1044,7 +1044,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
/* Set up the rc device */
rdev->priv = nvt;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
rdev->open = nvt_open;
rdev->close = nvt_close;
rdev->tx_ir = nvt_tx_ir;
@@ -1221,12 +1221,12 @@ static struct pnp_driver nvt_driver = {
.shutdown = nvt_shutdown,
};
-static int nvt_init(void)
+static int __init nvt_init(void)
{
return pnp_register_driver(&nvt_driver);
}
-static void nvt_exit(void)
+static void __exit nvt_exit(void)
{
pnp_unregister_driver(&nvt_driver);
}
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index da536c93c978..b68d4f762734 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -54,7 +54,7 @@ struct ir_raw_event_ctrl {
int state;
u32 bits;
unsigned count;
- unsigned wanted_bits;
+ bool is_rc5x;
} rc5;
struct rc6_dec {
int state;
@@ -77,12 +77,6 @@ struct ir_raw_event_ctrl {
bool first;
bool toggle;
} jvc;
- struct rc5_sz_dec {
- int state;
- u32 bits;
- unsigned count;
- unsigned wanted_bits;
- } rc5_sz;
struct sanyo_dec {
int state;
unsigned count;
@@ -116,6 +110,11 @@ struct ir_raw_event_ctrl {
bool send_timeout_reports;
} lirc;
+ struct xmp_dec {
+ int state;
+ unsigned count;
+ u32 durations[16];
+ } xmp;
};
/* macros for IR decoders */
@@ -231,5 +230,12 @@ static inline void load_mce_kbd_decode(void) { }
static inline void load_lirc_codec(void) { }
#endif
+/* from ir-xmp-decoder.c */
+#ifdef CONFIG_IR_XMP_DECODER_MODULE
+#define load_xmp_decode() request_module_nowait("ir-xmp-decoder")
+#else
+static inline void load_xmp_decode(void) { }
+#endif
+
#endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/rc-ir-raw.c
similarity index 97%
rename from drivers/media/rc/ir-raw.c
rename to drivers/media/rc/rc-ir-raw.c
index 763c9d131d0f..e8fff2add265 100644
--- a/drivers/media/rc/ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -1,4 +1,4 @@
-/* ir-raw.c - handle IR pulse/space events
+/* rc-ir-raw.c - handle IR pulse/space events
*
* Copyright (C) 2010 by Mauro Carvalho Chehab
*
@@ -240,6 +240,12 @@ ir_raw_get_allowed_protocols(void)
return protocols;
}
+static int change_protocol(struct rc_dev *dev, u64 *rc_type)
+{
+ /* the caller will update dev->enabled_protocols */
+ return 0;
+}
+
/*
* Used to (un)register raw event clients
*/
@@ -256,7 +262,8 @@ int ir_raw_event_register(struct rc_dev *dev)
return -ENOMEM;
dev->raw->dev = dev;
- rc_set_enabled_protocols(dev, ~0);
+ dev->enabled_protocols = ~0;
+ dev->change_protocol = change_protocol;
rc = kfifo_alloc(&dev->raw->kfifo,
sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
GFP_KERNEL);
@@ -355,6 +362,7 @@ void ir_raw_init(void)
load_sharp_decode();
load_mce_kbd_decode();
load_lirc_codec();
+ load_xmp_decode();
/* If needed, we may later add some init code. In this case,
it is needed to change the CONFIG_MODULE test at rc-core.h
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index 0a88e0cf964f..63dace8198b0 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -195,7 +195,7 @@ static int __init loop_init(void)
rc->map_name = RC_MAP_EMPTY;
rc->priv = &loopdev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rc, RC_BIT_ALL);
+ rc->allowed_protocols = RC_BIT_ALL;
rc->timeout = 100 * 1000 * 1000; /* 100 ms */
rc->min_timeout = 1;
rc->max_timeout = UINT_MAX;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 970b93d6f399..a7991c7d010a 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -285,8 +285,8 @@ static unsigned int ir_establish_scancode(struct rc_dev *dev,
* IR tables from other remotes. So, we support specifying a mask to
* indicate the valid bits of the scancodes.
*/
- if (dev->scanmask)
- scancode &= dev->scanmask;
+ if (dev->scancode_mask)
+ scancode &= dev->scancode_mask;
/* First check if we already have a mapping for this ir command */
for (i = 0; i < rc_map->len; i++) {
@@ -623,6 +623,7 @@ EXPORT_SYMBOL_GPL(rc_repeat);
/**
* ir_do_keydown() - internal function to process a keypress
* @dev: the struct rc_dev descriptor of the device
+ * @protocol: the protocol of the keypress
* @scancode: the scancode of the keypress
* @keycode: the keycode of the keypress
* @toggle: the toggle value of the keypress
@@ -630,12 +631,13 @@ EXPORT_SYMBOL_GPL(rc_repeat);
* This function is used internally to register a keypress, it must be
* called with keylock held.
*/
-static void ir_do_keydown(struct rc_dev *dev, int scancode,
- u32 keycode, u8 toggle)
+static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol,
+ u32 scancode, u32 keycode, u8 toggle)
{
bool new_event = (!dev->keypressed ||
+ dev->last_protocol != protocol ||
dev->last_scancode != scancode ||
- dev->last_toggle != toggle);
+ dev->last_toggle != toggle);
if (new_event && dev->keypressed)
ir_do_keyup(dev, false);
@@ -645,13 +647,14 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
if (new_event && keycode != KEY_RESERVED) {
/* Register a keypress */
dev->keypressed = true;
+ dev->last_protocol = protocol;
dev->last_scancode = scancode;
dev->last_toggle = toggle;
dev->last_keycode = keycode;
IR_dprintk(1, "%s: key down event, "
- "key 0x%04x, scancode 0x%04x\n",
- dev->input_name, keycode, scancode);
+ "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n",
+ dev->input_name, keycode, protocol, scancode);
input_report_key(dev->input_dev, keycode, 1);
led_trigger_event(led_feedback, LED_FULL);
@@ -663,20 +666,21 @@ static void ir_do_keydown(struct rc_dev *dev, int scancode,
/**
* rc_keydown() - generates input event for a key press
* @dev: the struct rc_dev descriptor of the device
- * @scancode: the scancode that we're seeking
+ * @protocol: the protocol for the keypress
+ * @scancode: the scancode for the keypress
* @toggle: the toggle value (protocol dependent, if the protocol doesn't
* support toggle values, this should be set to zero)
*
* This routine is used to signal that a key has been pressed on the
* remote control.
*/
-void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle)
+void rc_keydown(struct rc_dev *dev, enum rc_type protocol, u32 scancode, u8 toggle)
{
unsigned long flags;
u32 keycode = rc_g_keycode_from_table(dev, scancode);
spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keydown(dev, scancode, keycode, toggle);
+ ir_do_keydown(dev, protocol, scancode, keycode, toggle);
if (dev->keypressed) {
dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
@@ -690,20 +694,22 @@ EXPORT_SYMBOL_GPL(rc_keydown);
* rc_keydown_notimeout() - generates input event for a key press without
* an automatic keyup event at a later time
* @dev: the struct rc_dev descriptor of the device
- * @scancode: the scancode that we're seeking
+ * @protocol: the protocol for the keypress
+ * @scancode: the scancode for the keypress
* @toggle: the toggle value (protocol dependent, if the protocol doesn't
* support toggle values, this should be set to zero)
*
* This routine is used to signal that a key has been pressed on the
* remote control. The driver must manually call rc_keyup() at a later stage.
*/
-void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
+void rc_keydown_notimeout(struct rc_dev *dev, enum rc_type protocol,
+ u32 scancode, u8 toggle)
{
unsigned long flags;
u32 keycode = rc_g_keycode_from_table(dev, scancode);
spin_lock_irqsave(&dev->keylock, flags);
- ir_do_keydown(dev, scancode, keycode, toggle);
+ ir_do_keydown(dev, protocol, scancode, keycode, toggle);
spin_unlock_irqrestore(&dev->keylock, flags);
}
EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
@@ -794,6 +800,7 @@ static struct {
{ RC_BIT_SHARP, "sharp" },
{ RC_BIT_MCE_KBD, "mce_kbd" },
{ RC_BIT_LIRC, "lirc" },
+ { RC_BIT_XMP, "xmp" },
};
/**
@@ -824,7 +831,7 @@ struct rc_filter_attribute {
/**
* show_protocols() - shows the current/wakeup IR protocol(s)
* @device: the device descriptor
- * @mattr: the device attribute struct (unused)
+ * @mattr: the device attribute struct
* @buf: a pointer to the output buffer
*
* This routine is a callback routine for input read the IR protocol type(s).
@@ -850,20 +857,20 @@ static ssize_t show_protocols(struct device *device,
mutex_lock(&dev->lock);
- enabled = dev->enabled_protocols[fattr->type];
- if (dev->driver_type == RC_DRIVER_SCANCODE ||
- fattr->type == RC_FILTER_WAKEUP)
- allowed = dev->allowed_protocols[fattr->type];
- else if (dev->raw)
- allowed = ir_raw_get_allowed_protocols();
- else {
- mutex_unlock(&dev->lock);
- return -ENODEV;
+ if (fattr->type == RC_FILTER_NORMAL) {
+ enabled = dev->enabled_protocols;
+ allowed = dev->allowed_protocols;
+ if (dev->raw && !allowed)
+ allowed = ir_raw_get_allowed_protocols();
+ } else {
+ enabled = dev->enabled_wakeup_protocols;
+ allowed = dev->allowed_wakeup_protocols;
}
- IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
- (long long)allowed,
- (long long)enabled);
+ mutex_unlock(&dev->lock);
+
+ IR_dprintk(1, "%s: allowed - 0x%llx, enabled - 0x%llx\n",
+ __func__, (long long)allowed, (long long)enabled);
for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
if (allowed & enabled & proto_names[i].type)
@@ -879,62 +886,29 @@ static ssize_t show_protocols(struct device *device,
tmp--;
*tmp = '\n';
- mutex_unlock(&dev->lock);
-
return tmp + 1 - buf;
}
/**
- * store_protocols() - changes the current/wakeup IR protocol(s)
- * @device: the device descriptor
- * @mattr: the device attribute struct (unused)
- * @buf: a pointer to the input buffer
- * @len: length of the input buffer
+ * parse_protocol_change() - parses a protocol change request
+ * @protocols: pointer to the bitmask of current protocols
+ * @buf: pointer to the buffer with a list of changes
*
- * This routine is for changing the IR protocol type.
- * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols.
- * Writing "+proto" will add a protocol to the list of enabled protocols.
- * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "+proto" will add a protocol to the protocol mask.
+ * Writing "-proto" will remove a protocol from protocol mask.
* Writing "proto" will enable only "proto".
* Writing "none" will disable all protocols.
- * Returns -EINVAL if an invalid protocol combination or unknown protocol name
- * is used, otherwise @len.
- *
- * dev->lock is taken to guard against races between device
- * registration, store_protocols and show_protocols.
+ * Returns the number of changes performed or a negative error code.
*/
-static ssize_t store_protocols(struct device *device,
- struct device_attribute *mattr,
- const char *data,
- size_t len)
+static int parse_protocol_change(u64 *protocols, const char *buf)
{
- struct rc_dev *dev = to_rc_dev(device);
- struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
- bool enable, disable;
const char *tmp;
- u64 old_type, type;
+ unsigned count = 0;
+ bool enable, disable;
u64 mask;
- int rc, i, count = 0;
- ssize_t ret;
- int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
- int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
- struct rc_scancode_filter local_filter, *filter;
+ int i;
- /* Device is being removed */
- if (!dev)
- return -EINVAL;
-
- mutex_lock(&dev->lock);
-
- if (dev->driver_type != RC_DRIVER_SCANCODE && !dev->raw) {
- IR_dprintk(1, "Protocol switching not supported\n");
- ret = -EINVAL;
- goto out;
- }
- old_type = dev->enabled_protocols[fattr->type];
- type = old_type;
-
- while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+ while ((tmp = strsep((char **)&buf, " \n")) != NULL) {
if (!*tmp)
break;
@@ -960,76 +934,124 @@ static ssize_t store_protocols(struct device *device,
if (i == ARRAY_SIZE(proto_names)) {
IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
count++;
if (enable)
- type |= mask;
+ *protocols |= mask;
else if (disable)
- type &= ~mask;
+ *protocols &= ~mask;
else
- type = mask;
+ *protocols = mask;
}
if (!count) {
IR_dprintk(1, "Protocol not specified\n");
- ret = -EINVAL;
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+/**
+ * store_protocols() - changes the current/wakeup IR protocol(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is for changing the IR protocol type.
+ * It is trigged by writing to /sys/class/rc/rc?/[wakeup_]protocols.
+ * See parse_protocol_change() for the valid commands.
+ * Returns @len on success or a negative error code.
+ *
+ * dev->lock is taken to guard against races between device
+ * registration, store_protocols and show_protocols.
+ */
+static ssize_t store_protocols(struct device *device,
+ struct device_attribute *mattr,
+ const char *buf, size_t len)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ struct rc_filter_attribute *fattr = to_rc_filter_attr(mattr);
+ u64 *current_protocols;
+ int (*change_protocol)(struct rc_dev *dev, u64 *rc_type);
+ struct rc_scancode_filter *filter;
+ int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
+ u64 old_protocols, new_protocols;
+ ssize_t rc;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (fattr->type == RC_FILTER_NORMAL) {
+ IR_dprintk(1, "Normal protocol change requested\n");
+ current_protocols = &dev->enabled_protocols;
+ change_protocol = dev->change_protocol;
+ filter = &dev->scancode_filter;
+ set_filter = dev->s_filter;
+ } else {
+ IR_dprintk(1, "Wakeup protocol change requested\n");
+ current_protocols = &dev->enabled_wakeup_protocols;
+ change_protocol = dev->change_wakeup_protocol;
+ filter = &dev->scancode_wakeup_filter;
+ set_filter = dev->s_wakeup_filter;
+ }
+
+ if (!change_protocol) {
+ IR_dprintk(1, "Protocol switching not supported\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&dev->lock);
+
+ old_protocols = *current_protocols;
+ new_protocols = old_protocols;
+ rc = parse_protocol_change(&new_protocols, buf);
+ if (rc < 0)
+ goto out;
+
+ rc = change_protocol(dev, &new_protocols);
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+ (long long)new_protocols);
goto out;
}
- change_protocol = (fattr->type == RC_FILTER_NORMAL)
- ? dev->change_protocol : dev->change_wakeup_protocol;
- if (change_protocol) {
- rc = change_protocol(dev, &type);
- if (rc < 0) {
- IR_dprintk(1, "Error setting protocols to 0x%llx\n",
- (long long)type);
- ret = -EINVAL;
- goto out;
- }
+ if (new_protocols == old_protocols) {
+ rc = len;
+ goto out;
}
- dev->enabled_protocols[fattr->type] = type;
- IR_dprintk(1, "Current protocol(s): 0x%llx\n",
- (long long)type);
+ *current_protocols = new_protocols;
+ IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols);
/*
* If the protocol is changed the filter needs updating.
* Try setting the same filter with the new protocol (if any).
* Fall back to clearing the filter.
*/
- filter = &dev->scancode_filters[fattr->type];
- set_filter = (fattr->type == RC_FILTER_NORMAL)
- ? dev->s_filter : dev->s_wakeup_filter;
+ if (set_filter && filter->mask) {
+ if (new_protocols)
+ rc = set_filter(dev, filter);
+ else
+ rc = -1;
- if (set_filter && old_type != type && filter->mask) {
- local_filter = *filter;
- if (!type) {
- /* no protocol => clear filter */
- ret = -1;
- } else {
- /* hardware filtering => try setting, otherwise clear */
- ret = set_filter(dev, &local_filter);
+ if (rc < 0) {
+ filter->data = 0;
+ filter->mask = 0;
+ set_filter(dev, filter);
}
- if (ret < 0) {
- /* clear the filter */
- local_filter.data = 0;
- local_filter.mask = 0;
- set_filter(dev, &local_filter);
- }
-
- /* commit the new filter */
- *filter = local_filter;
}
- ret = len;
+ rc = len;
out:
mutex_unlock(&dev->lock);
- return ret;
+ return rc;
}
/**
@@ -1055,20 +1077,23 @@ static ssize_t show_filter(struct device *device,
{
struct rc_dev *dev = to_rc_dev(device);
struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
+ struct rc_scancode_filter *filter;
u32 val;
/* Device is being removed */
if (!dev)
return -EINVAL;
- mutex_lock(&dev->lock);
- if ((fattr->type == RC_FILTER_NORMAL && !dev->s_filter) ||
- (fattr->type == RC_FILTER_WAKEUP && !dev->s_wakeup_filter))
- val = 0;
- else if (fattr->mask)
- val = dev->scancode_filters[fattr->type].mask;
+ if (fattr->type == RC_FILTER_NORMAL)
+ filter = &dev->scancode_filter;
else
- val = dev->scancode_filters[fattr->type].data;
+ filter = &dev->scancode_wakeup_filter;
+
+ mutex_lock(&dev->lock);
+ if (fattr->mask)
+ val = filter->mask;
+ else
+ val = filter->data;
mutex_unlock(&dev->lock);
return sprintf(buf, "%#x\n", val);
@@ -1095,15 +1120,15 @@ static ssize_t show_filter(struct device *device,
*/
static ssize_t store_filter(struct device *device,
struct device_attribute *attr,
- const char *buf,
- size_t count)
+ const char *buf, size_t len)
{
struct rc_dev *dev = to_rc_dev(device);
struct rc_filter_attribute *fattr = to_rc_filter_attr(attr);
- struct rc_scancode_filter local_filter, *filter;
+ struct rc_scancode_filter new_filter, *filter;
int ret;
unsigned long val;
int (*set_filter)(struct rc_dev *dev, struct rc_scancode_filter *filter);
+ u64 *enabled_protocols;
/* Device is being removed */
if (!dev)
@@ -1113,38 +1138,42 @@ static ssize_t store_filter(struct device *device,
if (ret < 0)
return ret;
- /* Can the scancode filter be set? */
- set_filter = (fattr->type == RC_FILTER_NORMAL) ? dev->s_filter :
- dev->s_wakeup_filter;
+ if (fattr->type == RC_FILTER_NORMAL) {
+ set_filter = dev->s_filter;
+ enabled_protocols = &dev->enabled_protocols;
+ filter = &dev->scancode_filter;
+ } else {
+ set_filter = dev->s_wakeup_filter;
+ enabled_protocols = &dev->enabled_wakeup_protocols;
+ filter = &dev->scancode_wakeup_filter;
+ }
+
if (!set_filter)
return -EINVAL;
mutex_lock(&dev->lock);
- /* Tell the driver about the new filter */
- filter = &dev->scancode_filters[fattr->type];
- local_filter = *filter;
+ new_filter = *filter;
if (fattr->mask)
- local_filter.mask = val;
+ new_filter.mask = val;
else
- local_filter.data = val;
+ new_filter.data = val;
- if (!dev->enabled_protocols[fattr->type] && local_filter.mask) {
+ if (!*enabled_protocols && val) {
/* refuse to set a filter unless a protocol is enabled */
ret = -EINVAL;
goto unlock;
}
- ret = set_filter(dev, &local_filter);
+ ret = set_filter(dev, &new_filter);
if (ret < 0)
goto unlock;
- /* Success, commit the new filter */
- *filter = local_filter;
+ *filter = new_filter;
unlock:
mutex_unlock(&dev->lock);
- return (ret < 0) ? ret : count;
+ return (ret < 0) ? ret : len;
}
static void rc_dev_release(struct device *device)
@@ -1315,7 +1344,7 @@ int rc_register_device(struct rc_dev *dev)
dev->dev.groups = dev->sysfs_groups;
dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp;
if (dev->s_filter)
- dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp;
+ dev->sysfs_groups[attr++] = &rc_dev_filter_attr_grp;
if (dev->s_wakeup_filter)
dev->sysfs_groups[attr++] = &rc_dev_wakeup_filter_attr_grp;
if (dev->change_wakeup_protocol)
@@ -1395,7 +1424,7 @@ int rc_register_device(struct rc_dev *dev)
rc = dev->change_protocol(dev, &rc_type);
if (rc < 0)
goto out_raw;
- dev->enabled_protocols[RC_FILTER_NORMAL] = rc_type;
+ dev->enabled_protocols = rc_type;
}
mutex_unlock(&dev->lock);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 79abbc8d9600..795b394a5d84 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -878,7 +878,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->dev.parent = dev;
rc->priv = rr3;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rc, RC_BIT_ALL);
+ rc->allowed_protocols = RC_BIT_ALL;
rc->timeout = US_TO_NS(2750);
rc->tx_ir = redrat3_transmit_ir;
rc->s_tx_carrier = redrat3_set_tx_carrier;
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 22e4c1f28ab4..5c151351afa4 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -287,7 +287,7 @@ static int st_rc_probe(struct platform_device *pdev)
st_rc_hardware_init(rc_dev);
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
/* rx sampling rate is 10Mhz */
rdev->rx_resolution = 100;
rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index bd5e4ff9e0ba..80c4feeb01ea 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -63,13 +63,6 @@ MODULE_DEVICE_TABLE(usb, streamzap_table);
/* number of samples buffered */
#define SZ_BUF_LEN 128
-/* from ir-rc5-sz-decoder.c */
-#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
-#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
-#else
-#define load_rc5_sz_decode() {}
-#endif
-
enum StreamzapDecoderState {
PulseSpace,
FullPulse,
@@ -316,7 +309,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
rdev->dev.parent = dev;
rdev->priv = sz;
rdev->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rdev, RC_BIT_ALL);
+ rdev->allowed_protocols = RC_BIT_ALL;
rdev->driver_name = DRIVER_NAME;
rdev->map_name = RC_MAP_STREAMZAP;
@@ -452,9 +445,6 @@ static int streamzap_probe(struct usb_interface *intf,
dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
usbdev->bus->busnum, usbdev->devnum);
- /* Load the streamzap not-quite-rc5 decoder too */
- load_rc5_sz_decode();
-
return 0;
rc_dev_fail:
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
new file mode 100644
index 000000000000..bcee8e1a4e9e
--- /dev/null
+++ b/drivers/media/rc/sunxi-cir.c
@@ -0,0 +1,318 @@
+/*
+ * Driver for Allwinner sunXi IR controller
+ *
+ * Copyright (C) 2014 Alexsey Shestacov
+ * Copyright (C) 2014 Alexander Bersenev
+ *
+ * Based on sun5i-ir.c:
+ * Copyright (C) 2007-2012 Daniel Wang
+ * Allwinner Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#define SUNXI_IR_DEV "sunxi-ir"
+
+/* Registers */
+/* IR Control */
+#define SUNXI_IR_CTL_REG 0x00
+/* Global Enable */
+#define REG_CTL_GEN BIT(0)
+/* RX block enable */
+#define REG_CTL_RXEN BIT(1)
+/* CIR mode */
+#define REG_CTL_MD (BIT(4) | BIT(5))
+
+/* Rx Config */
+#define SUNXI_IR_RXCTL_REG 0x10
+/* Pulse Polarity Invert flag */
+#define REG_RXCTL_RPPI BIT(2)
+
+/* Rx Data */
+#define SUNXI_IR_RXFIFO_REG 0x20
+
+/* Rx Interrupt Enable */
+#define SUNXI_IR_RXINT_REG 0x2C
+/* Rx FIFO Overflow */
+#define REG_RXINT_ROI_EN BIT(0)
+/* Rx Packet End */
+#define REG_RXINT_RPEI_EN BIT(1)
+/* Rx FIFO Data Available */
+#define REG_RXINT_RAI_EN BIT(4)
+
+/* Rx FIFO available byte level */
+#define REG_RXINT_RAL(val) (((val) << 8) & (GENMASK(11, 8)))
+
+/* Rx Interrupt Status */
+#define SUNXI_IR_RXSTA_REG 0x30
+/* RX FIFO Get Available Counter */
+#define REG_RXSTA_GET_AC(val) (((val) >> 8) & (GENMASK(5, 0)))
+/* Clear all interrupt status value */
+#define REG_RXSTA_CLEARALL 0xff
+
+/* IR Sample Config */
+#define SUNXI_IR_CIR_REG 0x34
+/* CIR_REG register noise threshold */
+#define REG_CIR_NTHR(val) (((val) << 2) & (GENMASK(7, 2)))
+/* CIR_REG register idle threshold */
+#define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8)))
+
+/* Hardware supported fifo size */
+#define SUNXI_IR_FIFO_SIZE 16
+/* How many messages in FIFO trigger IRQ */
+#define TRIGGER_LEVEL 8
+/* Required frequency for IR0 or IR1 clock in CIR mode */
+#define SUNXI_IR_BASE_CLK 8000000
+/* Frequency after IR internal divider */
+#define SUNXI_IR_CLK (SUNXI_IR_BASE_CLK / 64)
+/* Sample period in ns */
+#define SUNXI_IR_SAMPLE (1000000000ul / SUNXI_IR_CLK)
+/* Noise threshold in samples */
+#define SUNXI_IR_RXNOISE 1
+/* Idle Threshold in samples */
+#define SUNXI_IR_RXIDLE 20
+/* Time after which device stops sending data in ms */
+#define SUNXI_IR_TIMEOUT 120
+
+struct sunxi_ir {
+ spinlock_t ir_lock;
+ struct rc_dev *rc;
+ void __iomem *base;
+ int irq;
+ struct clk *clk;
+ struct clk *apb_clk;
+ const char *map_name;
+};
+
+static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
+{
+ unsigned long status;
+ unsigned char dt;
+ unsigned int cnt, rc;
+ struct sunxi_ir *ir = dev_id;
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ spin_lock(&ir->ir_lock);
+
+ status = readl(ir->base + SUNXI_IR_RXSTA_REG);
+
+ /* clean all pending statuses */
+ writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
+
+ if (status & REG_RXINT_RAI_EN) {
+ /* How many messages in fifo */
+ rc = REG_RXSTA_GET_AC(status);
+ /* Sanity check */
+ rc = rc > SUNXI_IR_FIFO_SIZE ? SUNXI_IR_FIFO_SIZE : rc;
+ /* If we have data */
+ for (cnt = 0; cnt < rc; cnt++) {
+ /* for each bit in fifo */
+ dt = readb(ir->base + SUNXI_IR_RXFIFO_REG);
+ rawir.pulse = (dt & 0x80) != 0;
+ rawir.duration = ((dt & 0x7f) + 1) * SUNXI_IR_SAMPLE;
+ ir_raw_event_store_with_filter(ir->rc, &rawir);
+ }
+ }
+
+ if (status & REG_RXINT_ROI_EN) {
+ ir_raw_event_reset(ir->rc);
+ } else if (status & REG_RXINT_RPEI_EN) {
+ ir_raw_event_set_idle(ir->rc, true);
+ ir_raw_event_handle(ir->rc);
+ }
+
+ spin_unlock(&ir->ir_lock);
+
+ return IRQ_HANDLED;
+}
+
+static int sunxi_ir_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ unsigned long tmp = 0;
+
+ struct device *dev = &pdev->dev;
+ struct device_node *dn = dev->of_node;
+ struct resource *res;
+ struct sunxi_ir *ir;
+
+ ir = devm_kzalloc(dev, sizeof(struct sunxi_ir), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
+
+ /* Clock */
+ ir->apb_clk = devm_clk_get(dev, "apb");
+ if (IS_ERR(ir->apb_clk)) {
+ dev_err(dev, "failed to get a apb clock.\n");
+ return PTR_ERR(ir->apb_clk);
+ }
+ ir->clk = devm_clk_get(dev, "ir");
+ if (IS_ERR(ir->clk)) {
+ dev_err(dev, "failed to get a ir clock.\n");
+ return PTR_ERR(ir->clk);
+ }
+
+ ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK);
+ if (ret) {
+ dev_err(dev, "set ir base clock failed!\n");
+ return ret;
+ }
+
+ if (clk_prepare_enable(ir->apb_clk)) {
+ dev_err(dev, "try to enable apb_ir_clk failed\n");
+ return -EINVAL;
+ }
+
+ if (clk_prepare_enable(ir->clk)) {
+ dev_err(dev, "try to enable ir_clk failed\n");
+ ret = -EINVAL;
+ goto exit_clkdisable_apb_clk;
+ }
+
+ /* IO */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ir->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ir->base)) {
+ dev_err(dev, "failed to map registers\n");
+ ret = PTR_ERR(ir->base);
+ goto exit_clkdisable_clk;
+ }
+
+ ir->rc = rc_allocate_device();
+ if (!ir->rc) {
+ dev_err(dev, "failed to allocate device\n");
+ ret = -ENOMEM;
+ goto exit_clkdisable_clk;
+ }
+
+ ir->rc->priv = ir;
+ ir->rc->input_name = SUNXI_IR_DEV;
+ ir->rc->input_phys = "sunxi-ir/input0";
+ ir->rc->input_id.bustype = BUS_HOST;
+ ir->rc->input_id.vendor = 0x0001;
+ ir->rc->input_id.product = 0x0001;
+ ir->rc->input_id.version = 0x0100;
+ ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL);
+ ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
+ ir->rc->dev.parent = dev;
+ ir->rc->driver_type = RC_DRIVER_IR_RAW;
+ ir->rc->allowed_protocols = RC_BIT_ALL;
+ ir->rc->rx_resolution = SUNXI_IR_SAMPLE;
+ ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT);
+ ir->rc->driver_name = SUNXI_IR_DEV;
+
+ ret = rc_register_device(ir->rc);
+ if (ret) {
+ dev_err(dev, "failed to register rc device\n");
+ goto exit_free_dev;
+ }
+
+ platform_set_drvdata(pdev, ir);
+
+ /* IRQ */
+ ir->irq = platform_get_irq(pdev, 0);
+ if (ir->irq < 0) {
+ dev_err(dev, "no irq resource\n");
+ ret = ir->irq;
+ goto exit_free_dev;
+ }
+
+ ret = devm_request_irq(dev, ir->irq, sunxi_ir_irq, 0, SUNXI_IR_DEV, ir);
+ if (ret) {
+ dev_err(dev, "failed request irq\n");
+ goto exit_free_dev;
+ }
+
+ /* Enable CIR Mode */
+ writel(REG_CTL_MD, ir->base+SUNXI_IR_CTL_REG);
+
+ /* Set noise threshold and idle threshold */
+ writel(REG_CIR_NTHR(SUNXI_IR_RXNOISE)|REG_CIR_ITHR(SUNXI_IR_RXIDLE),
+ ir->base + SUNXI_IR_CIR_REG);
+
+ /* Invert Input Signal */
+ writel(REG_RXCTL_RPPI, ir->base + SUNXI_IR_RXCTL_REG);
+
+ /* Clear All Rx Interrupt Status */
+ writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
+
+ /*
+ * Enable IRQ on overflow, packet end, FIFO available with trigger
+ * level
+ */
+ writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
+ REG_RXINT_RAI_EN | REG_RXINT_RAL(TRIGGER_LEVEL - 1),
+ ir->base + SUNXI_IR_RXINT_REG);
+
+ /* Enable IR Module */
+ tmp = readl(ir->base + SUNXI_IR_CTL_REG);
+ writel(tmp | REG_CTL_GEN | REG_CTL_RXEN, ir->base + SUNXI_IR_CTL_REG);
+
+ dev_info(dev, "initialized sunXi IR driver\n");
+ return 0;
+
+exit_free_dev:
+ rc_free_device(ir->rc);
+exit_clkdisable_clk:
+ clk_disable_unprepare(ir->clk);
+exit_clkdisable_apb_clk:
+ clk_disable_unprepare(ir->apb_clk);
+
+ return ret;
+}
+
+static int sunxi_ir_remove(struct platform_device *pdev)
+{
+ unsigned long flags;
+ struct sunxi_ir *ir = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(ir->clk);
+ clk_disable_unprepare(ir->apb_clk);
+
+ spin_lock_irqsave(&ir->ir_lock, flags);
+ /* disable IR IRQ */
+ writel(0, ir->base + SUNXI_IR_RXINT_REG);
+ /* clear All Rx Interrupt Status */
+ writel(REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
+ /* disable IR */
+ writel(0, ir->base + SUNXI_IR_CTL_REG);
+ spin_unlock_irqrestore(&ir->ir_lock, flags);
+
+ rc_unregister_device(ir->rc);
+ return 0;
+}
+
+static const struct of_device_id sunxi_ir_match[] = {
+ { .compatible = "allwinner,sun4i-a10-ir", },
+ {},
+};
+
+static struct platform_driver sunxi_ir_driver = {
+ .probe = sunxi_ir_probe,
+ .remove = sunxi_ir_remove,
+ .driver = {
+ .name = SUNXI_IR_DEV,
+ .owner = THIS_MODULE,
+ .of_match_table = sunxi_ir_match,
+ },
+};
+
+module_platform_driver(sunxi_ir_driver);
+
+MODULE_DESCRIPTION("Allwinner sunXi IR controller driver");
+MODULE_AUTHOR("Alexsey Shestacov ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index c5be38e2a2fe..bc214e2b3a36 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -318,7 +318,7 @@ static int ttusbir_probe(struct usb_interface *intf,
usb_to_input_id(tt->udev, &rc->input_id);
rc->dev.parent = &intf->dev;
rc->driver_type = RC_DRIVER_IR_RAW;
- rc_set_allowed_protocols(rc, RC_BIT_ALL);
+ rc->allowed_protocols = RC_BIT_ALL;
rc->priv = tt;
rc->driver_name = DRIVER_NAME;
rc->map_name = RC_MAP_TT_1500;
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index a8b981f5ce2e..d839f73f6a05 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -1082,7 +1082,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
data->dev->dev.parent = &device->dev;
data->dev->timeout = MS_TO_NS(100);
data->dev->rx_resolution = US_TO_NS(2);
- rc_set_allowed_protocols(data->dev, RC_BIT_ALL);
+ data->dev->allowed_protocols = RC_BIT_ALL;
err = rc_register_device(data->dev);
if (err)
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index 22b6b8bb1d93..d79fd1ce5a18 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -1,7 +1,7 @@
# Analog TV tuners, auto-loaded via tuner.ko
config MEDIA_TUNER
tristate
- depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C
+ depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT) && I2C
default y
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
@@ -16,7 +16,7 @@ config MEDIA_TUNER
menu "Customize TV tuners"
visible if !MEDIA_SUBDRV_AUTOSELECT
- depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT
+ depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT
config MEDIA_TUNER_SIMPLE
tristate "Simple tuner support"
@@ -71,6 +71,13 @@ config MEDIA_TUNER_TEA5767
help
Say Y here to include support for the Philips TEA5767 radio tuner.
+config MEDIA_TUNER_MSI001
+ tristate "Mirics MSi001"
+ depends on MEDIA_SUPPORT && SPI && VIDEO_V4L2
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Mirics MSi001 silicon tuner driver.
+
config MEDIA_TUNER_MT20XX
tristate "Microtune 2032 / 2050 tuners"
depends on MEDIA_SUPPORT && I2C
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index a6ff0c628dfa..5591699755ba 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o
obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o
obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o
obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o
+obj-$(CONFIG_MEDIA_TUNER_MSI001) += msi001.o
obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o
obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o
obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o
diff --git a/drivers/staging/media/msi3101/msi001.c b/drivers/media/tuners/msi001.c
similarity index 99%
rename from drivers/staging/media/msi3101/msi001.c
rename to drivers/media/tuners/msi001.c
index bd0b93cb6c53..ee99e372c943 100644
--- a/drivers/staging/media/msi3101/msi001.c
+++ b/drivers/media/tuners/msi001.c
@@ -381,7 +381,7 @@ static int msi001_s_ctrl(struct v4l2_ctrl *ctrl)
int ret;
dev_dbg(&s->spi->dev,
- "%s: id=%d name=%s val=%d min=%d max=%d step=%d\n",
+ "%s: id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
__func__, ctrl->id, ctrl->name, ctrl->val,
ctrl->minimum, ctrl->maximum, ctrl->step);
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index 96ccfebce7ca..a759742cae7b 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -1545,7 +1545,7 @@ static int r820t_imr_cross(struct r820t_priv *priv,
cross[i].value = rc;
if (cross[i].value < tmp.value)
- memcpy(&tmp, &cross[i], sizeof(tmp));
+ tmp = cross[i];
}
if ((tmp.phase_y & 0x1f) == 1) { /* y-direction */
@@ -2300,7 +2300,6 @@ struct dvb_frontend *r820t_attach(struct dvb_frontend *fe,
case 0:
/* memory allocation failure */
goto err_no_gate;
- break;
case 1:
/* new tuner instance */
priv->cfg = cfg;
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index fa4cc7b880aa..6c53edb73a63 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -1,5 +1,5 @@
/*
- * Silicon Labs Si2157 silicon tuner driver
+ * Silicon Labs Si2157/2158 silicon tuner driver
*
* Copyright (C) 2014 Antti Palosaari
*
@@ -16,53 +16,57 @@
#include "si2157_priv.h"
+static const struct dvb_tuner_ops si2157_ops;
+
/* execute firmware command */
static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
{
int ret;
- u8 buf[1];
unsigned long timeout;
mutex_lock(&s->i2c_mutex);
- if (cmd->len) {
+ if (cmd->wlen) {
/* write cmd and args for firmware */
- ret = i2c_master_send(s->client, cmd->args, cmd->len);
+ ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
if (ret < 0) {
goto err_mutex_unlock;
- } else if (ret != cmd->len) {
+ } else if (ret != cmd->wlen) {
ret = -EREMOTEIO;
goto err_mutex_unlock;
}
}
- /* wait cmd execution terminate */
- #define TIMEOUT 80
- timeout = jiffies + msecs_to_jiffies(TIMEOUT);
- while (!time_after(jiffies, timeout)) {
- ret = i2c_master_recv(s->client, buf, 1);
- if (ret < 0) {
- goto err_mutex_unlock;
- } else if (ret != 1) {
- ret = -EREMOTEIO;
- goto err_mutex_unlock;
+ if (cmd->rlen) {
+ /* wait cmd execution terminate */
+ #define TIMEOUT 80
+ timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+ while (!time_after(jiffies, timeout)) {
+ ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != cmd->rlen) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* firmware ready? */
+ if ((cmd->args[0] >> 7) & 0x01)
+ break;
}
- /* firmware ready? */
- if ((buf[0] >> 7) & 0x01)
- break;
+ dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
+ __func__,
+ jiffies_to_msecs(jiffies) -
+ (jiffies_to_msecs(timeout) - TIMEOUT));
+
+ if (!((cmd->args[0] >> 7) & 0x01)) {
+ ret = -ETIMEDOUT;
+ goto err_mutex_unlock;
+ }
}
- dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", __func__,
- jiffies_to_msecs(jiffies) -
- (jiffies_to_msecs(timeout) - TIMEOUT));
-
- if (!((buf[0] >> 7) & 0x01)) {
- ret = -ETIMEDOUT;
- goto err_mutex_unlock;
- } else {
- ret = 0;
- }
+ ret = 0;
err_mutex_unlock:
mutex_unlock(&s->i2c_mutex);
@@ -78,23 +82,133 @@ err:
static int si2157_init(struct dvb_frontend *fe)
{
struct si2157 *s = fe->tuner_priv;
+ int ret, len, remaining;
+ struct si2157_cmd cmd;
+ const struct firmware *fw = NULL;
+ u8 *fw_file;
+ unsigned int chip_id;
dev_dbg(&s->client->dev, "%s:\n", __func__);
+ /* configure? */
+ memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
+ cmd.wlen = 15;
+ cmd.rlen = 1;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* query chip revision */
+ memcpy(cmd.args, "\x02", 1);
+ cmd.wlen = 1;
+ cmd.rlen = 13;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ chip_id = cmd.args[1] << 24 | cmd.args[2] << 16 | cmd.args[3] << 8 |
+ cmd.args[4] << 0;
+
+ #define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
+ #define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
+
+ switch (chip_id) {
+ case SI2158_A20:
+ fw_file = SI2158_A20_FIRMWARE;
+ break;
+ case SI2157_A30:
+ goto skip_fw_download;
+ 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],
+ 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, si2157_ops.info.name);
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_file, &s->client->dev);
+ if (ret) {
+ dev_err(&s->client->dev, "%s: firmware file '%s' not found\n",
+ KBUILD_MODNAME, fw_file);
+ goto err;
+ }
+
+ /* firmware should be n chunks of 17 bytes */
+ if (fw->size % 17 != 0) {
+ dev_err(&s->client->dev, "%s: firmware file '%s' is invalid\n",
+ KBUILD_MODNAME, fw_file);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
+ KBUILD_MODNAME, fw_file);
+
+ for (remaining = fw->size; remaining > 0; remaining -= 17) {
+ len = fw->data[fw->size - remaining];
+ memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
+ cmd.wlen = len;
+ cmd.rlen = 1;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret) {
+ dev_err(&s->client->dev,
+ "%s: firmware download failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err;
+ }
+ }
+
+ release_firmware(fw);
+ fw = NULL;
+
+skip_fw_download:
+ /* reboot the tuner with new firmware? */
+ memcpy(cmd.args, "\x01\x01", 2);
+ cmd.wlen = 2;
+ cmd.rlen = 1;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
s->active = true;
return 0;
+err:
+ if (fw)
+ release_firmware(fw);
+
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
}
static int si2157_sleep(struct dvb_frontend *fe)
{
struct si2157 *s = fe->tuner_priv;
+ int ret;
+ struct si2157_cmd cmd;
dev_dbg(&s->client->dev, "%s:\n", __func__);
s->active = false;
+ memcpy(cmd.args, "\x13", 1);
+ cmd.wlen = 1;
+ cmd.rlen = 0;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
}
static int si2157_set_params(struct dvb_frontend *fe)
@@ -103,6 +217,7 @@ static int si2157_set_params(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
struct si2157_cmd cmd;
+ u8 bandwidth, delivery_system;
dev_dbg(&s->client->dev,
"%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
@@ -114,50 +229,46 @@ static int si2157_set_params(struct dvb_frontend *fe)
goto err;
}
- /* configure? */
- cmd.args[0] = 0xc0;
- cmd.args[1] = 0x00;
- cmd.args[2] = 0x0c;
- cmd.args[3] = 0x00;
- cmd.args[4] = 0x00;
- cmd.args[5] = 0x01;
- cmd.args[6] = 0x01;
- cmd.args[7] = 0x01;
- cmd.args[8] = 0x01;
- cmd.args[9] = 0x01;
- cmd.args[10] = 0x01;
- cmd.args[11] = 0x02;
- cmd.args[12] = 0x00;
- cmd.args[13] = 0x00;
- cmd.args[14] = 0x01;
- cmd.len = 15;
- ret = si2157_cmd_execute(s, &cmd);
- if (ret)
- goto err;
+ if (c->bandwidth_hz <= 6000000)
+ bandwidth = 0x06;
+ else if (c->bandwidth_hz <= 7000000)
+ bandwidth = 0x07;
+ else if (c->bandwidth_hz <= 8000000)
+ bandwidth = 0x08;
+ else
+ bandwidth = 0x0f;
- cmd.args[0] = 0x02;
- cmd.len = 1;
- ret = si2157_cmd_execute(s, &cmd);
- if (ret)
- goto err;
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
+ delivery_system = 0x20;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ delivery_system = 0x30;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
- cmd.args[0] = 0x01;
- cmd.args[1] = 0x01;
- cmd.len = 2;
+ memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6);
+ cmd.args[4] = delivery_system | bandwidth;
+ if (s->inversion)
+ cmd.args[5] = 0x01;
+ cmd.wlen = 6;
+ cmd.rlen = 1;
ret = si2157_cmd_execute(s, &cmd);
if (ret)
goto err;
/* set frequency */
- cmd.args[0] = 0x41;
- cmd.args[1] = 0x00;
- cmd.args[2] = 0x00;
- cmd.args[3] = 0x00;
+ memcpy(cmd.args, "\x41\x00\x00\x00\x00\x00\x00\x00", 8);
cmd.args[4] = (c->frequency >> 0) & 0xff;
cmd.args[5] = (c->frequency >> 8) & 0xff;
cmd.args[6] = (c->frequency >> 16) & 0xff;
cmd.args[7] = (c->frequency >> 24) & 0xff;
- cmd.len = 8;
+ cmd.wlen = 8;
+ cmd.rlen = 1;
ret = si2157_cmd_execute(s, &cmd);
if (ret)
goto err;
@@ -168,9 +279,15 @@ err:
return ret;
}
-static const struct dvb_tuner_ops si2157_tuner_ops = {
+static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ *frequency = 5000000; /* default value of property 0x0706 */
+ return 0;
+}
+
+static const struct dvb_tuner_ops si2157_ops = {
.info = {
- .name = "Silicon Labs Si2157",
+ .name = "Silicon Labs Si2157/Si2158",
.frequency_min = 110000000,
.frequency_max = 862000000,
},
@@ -178,6 +295,7 @@ static const struct dvb_tuner_ops si2157_tuner_ops = {
.init = si2157_init,
.sleep = si2157_sleep,
.set_params = si2157_set_params,
+ .get_if_frequency = si2157_get_if_frequency,
};
static int si2157_probe(struct i2c_client *client,
@@ -198,22 +316,24 @@ static int si2157_probe(struct i2c_client *client,
s->client = client;
s->fe = cfg->fe;
+ s->inversion = cfg->inversion;
mutex_init(&s->i2c_mutex);
/* check if the tuner is there */
- cmd.len = 0;
+ cmd.wlen = 0;
+ cmd.rlen = 1;
ret = si2157_cmd_execute(s, &cmd);
if (ret)
goto err;
fe->tuner_priv = s;
- memcpy(&fe->ops.tuner_ops, &si2157_tuner_ops,
+ memcpy(&fe->ops.tuner_ops, &si2157_ops,
sizeof(struct dvb_tuner_ops));
i2c_set_clientdata(client, s);
dev_info(&s->client->dev,
- "%s: Silicon Labs Si2157 successfully attached\n",
+ "%s: Silicon Labs Si2157/Si2158 successfully attached\n",
KBUILD_MODNAME);
return 0;
err:
@@ -255,6 +375,7 @@ static struct i2c_driver si2157_driver = {
module_i2c_driver(si2157_driver);
-MODULE_DESCRIPTION("Silicon Labs Si2157 silicon tuner driver");
+MODULE_DESCRIPTION("Silicon Labs Si2157/Si2158 silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari ");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index f469a092b66b..6da4d5d1c817 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -1,5 +1,5 @@
/*
- * Silicon Labs Si2157 silicon tuner driver
+ * Silicon Labs Si2157/2158 silicon tuner driver
*
* Copyright (C) 2014 Antti Palosaari
*
@@ -29,6 +29,11 @@ struct si2157_config {
* frontend
*/
struct dvb_frontend *fe;
+
+ /*
+ * Spectral Inversion
+ */
+ bool inversion;
};
#endif
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index 6cc6c6fdab7a..3ddab5e6b500 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -1,5 +1,5 @@
/*
- * Silicon Labs Si2157 silicon tuner driver
+ * Silicon Labs Si2157/2158 silicon tuner driver
*
* Copyright (C) 2014 Antti Palosaari
*
@@ -17,6 +17,7 @@
#ifndef SI2157_PRIV_H
#define SI2157_PRIV_H
+#include
#include "si2157.h"
/* state struct */
@@ -25,13 +26,17 @@ struct si2157 {
struct i2c_client *client;
struct dvb_frontend *fe;
bool active;
+ bool inversion;
};
/* firmare command struct */
#define SI2157_ARGLEN 30
struct si2157_cmd {
u8 args[SI2157_ARGLEN];
- unsigned len;
+ unsigned wlen;
+ unsigned rlen;
};
+#define SI2158_A20_FIRMWARE "dvb-tuner-si2158-a20-01.fw"
+
#endif
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c
index 6ef93ee1fdcb..565eeebb3aeb 100644
--- a/drivers/media/tuners/tuner-xc2028.c
+++ b/drivers/media/tuners/tuner-xc2028.c
@@ -1489,7 +1489,6 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
case 0:
/* memory allocation failure */
goto fail;
- break;
case 1:
/* new tuner instance */
priv->ctrl.max_len = 13;
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c
index 2018befabb5a..f9ab79e3432d 100644
--- a/drivers/media/tuners/xc4000.c
+++ b/drivers/media/tuners/xc4000.c
@@ -93,7 +93,7 @@ struct xc4000_priv {
struct firmware_description *firm;
int firm_size;
u32 if_khz;
- u32 freq_hz;
+ u32 freq_hz, freq_offset;
u32 bandwidth;
u8 video_standard;
u8 rf_mode;
@@ -116,6 +116,7 @@ struct xc4000_priv {
#define XC4000_AUDIO_STD_MONO 32
#define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw"
+#define XC4000_DEFAULT_FIRMWARE_NEW "dvb-fe-xc4000-1.4.1.fw"
/* Misc Defines */
#define MAX_TV_STANDARD 24
@@ -730,13 +731,25 @@ static int xc4000_fwupload(struct dvb_frontend *fe)
char name[33];
const char *fname;
- if (firmware_name[0] != '\0')
+ if (firmware_name[0] != '\0') {
fname = firmware_name;
- else
- fname = XC4000_DEFAULT_FIRMWARE;
- dprintk(1, "Reading firmware %s\n", fname);
- rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent);
+ dprintk(1, "Reading custom firmware %s\n", fname);
+ rc = request_firmware(&fw, fname,
+ priv->i2c_props.adap->dev.parent);
+ } else {
+ fname = XC4000_DEFAULT_FIRMWARE_NEW;
+ dprintk(1, "Trying to read firmware %s\n", fname);
+ rc = request_firmware(&fw, fname,
+ priv->i2c_props.adap->dev.parent);
+ if (rc == -ENOENT) {
+ fname = XC4000_DEFAULT_FIRMWARE;
+ dprintk(1, "Trying to read firmware %s\n", fname);
+ rc = request_firmware(&fw, fname,
+ priv->i2c_props.adap->dev.parent);
+ }
+ }
+
if (rc < 0) {
if (rc == -ENOENT)
printk(KERN_ERR "Error: firmware %s not found.\n", fname);
@@ -746,6 +759,8 @@ static int xc4000_fwupload(struct dvb_frontend *fe)
return rc;
}
+ dprintk(1, "Loading Firmware: %s\n", fname);
+
p = fw->data;
endp = p + fw->size;
@@ -1157,14 +1172,14 @@ static int xc4000_set_params(struct dvb_frontend *fe)
case SYS_ATSC:
dprintk(1, "%s() VSB modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_AIR;
- priv->freq_hz = c->frequency - 1750000;
+ priv->freq_offset = 1750000;
priv->video_standard = XC4000_DTV6;
type = DTV6;
break;
case SYS_DVBC_ANNEX_B:
dprintk(1, "%s() QAM modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_CABLE;
- priv->freq_hz = c->frequency - 1750000;
+ priv->freq_offset = 1750000;
priv->video_standard = XC4000_DTV6;
type = DTV6;
break;
@@ -1173,23 +1188,23 @@ static int xc4000_set_params(struct dvb_frontend *fe)
dprintk(1, "%s() OFDM\n", __func__);
if (bw == 0) {
if (c->frequency < 400000000) {
- priv->freq_hz = c->frequency - 2250000;
+ priv->freq_offset = 2250000;
} else {
- priv->freq_hz = c->frequency - 2750000;
+ priv->freq_offset = 2750000;
}
priv->video_standard = XC4000_DTV7_8;
type = DTV78;
} else if (bw <= 6000000) {
priv->video_standard = XC4000_DTV6;
- priv->freq_hz = c->frequency - 1750000;
+ priv->freq_offset = 1750000;
type = DTV6;
} else if (bw <= 7000000) {
priv->video_standard = XC4000_DTV7;
- priv->freq_hz = c->frequency - 2250000;
+ priv->freq_offset = 2250000;
type = DTV7;
} else {
priv->video_standard = XC4000_DTV8;
- priv->freq_hz = c->frequency - 2750000;
+ priv->freq_offset = 2750000;
type = DTV8;
}
priv->rf_mode = XC_RF_MODE_AIR;
@@ -1200,6 +1215,8 @@ static int xc4000_set_params(struct dvb_frontend *fe)
goto fail;
}
+ priv->freq_hz = c->frequency - priv->freq_offset;
+
dprintk(1, "%s() frequency=%d (compensated)\n",
__func__, priv->freq_hz);
@@ -1520,7 +1537,7 @@ static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq)
{
struct xc4000_priv *priv = fe->tuner_priv;
- *freq = priv->freq_hz;
+ *freq = priv->freq_hz + priv->freq_offset;
if (debug) {
mutex_lock(&priv->lock);
@@ -1668,7 +1685,6 @@ struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe,
switch (instance) {
case 0:
goto fail;
- break;
case 1:
/* new tuner instance */
priv->bandwidth = 6000000;
@@ -1755,3 +1771,5 @@ EXPORT_SYMBOL(xc4000_attach);
MODULE_AUTHOR("Steven Toth, Davide Ferri");
MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver");
MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE_NEW);
+MODULE_FIRMWARE(XC4000_DEFAULT_FIRMWARE);
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index 2b3d514be672..e135760f7d48 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -56,7 +56,7 @@ struct xc5000_priv {
u32 if_khz;
u16 xtal_khz;
- u32 freq_hz;
+ u32 freq_hz, freq_offset;
u32 bandwidth;
u8 video_standard;
u8 rf_mode;
@@ -625,48 +625,30 @@ static int xc_set_xtal(struct dvb_frontend *fe)
return ret;
}
-static int xc5000_fwupload(struct dvb_frontend *fe)
+static int xc5000_fwupload(struct dvb_frontend *fe,
+ const struct xc5000_fw_cfg *desired_fw,
+ const struct firmware *fw)
{
struct xc5000_priv *priv = fe->tuner_priv;
- const struct firmware *fw;
int ret;
- const struct xc5000_fw_cfg *desired_fw =
- xc5000_assign_firmware(priv->chip_id);
+
+ /* request the firmware, this will block and timeout */
+ dprintk(1, "waiting for firmware upload (%s)...\n",
+ desired_fw->name);
+
priv->pll_register_no = desired_fw->pll_reg;
priv->init_status_supported = desired_fw->init_status_supported;
priv->fw_checksum_supported = desired_fw->fw_checksum_supported;
- /* request the firmware, this will block and timeout */
- printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n",
- desired_fw->name);
- ret = request_firmware(&fw, desired_fw->name,
- priv->i2c_props.adap->dev.parent);
- if (ret) {
- printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
- goto out;
- } else {
- printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
- fw->size);
- ret = 0;
- }
+ dprintk(1, "firmware uploading...\n");
+ ret = xc_load_i2c_sequence(fe, fw->data);
+ if (!ret) {
+ ret = xc_set_xtal(fe);
+ dprintk(1, "Firmware upload complete...\n");
+ } else
+ printk(KERN_ERR "xc5000: firmware upload failed...\n");
- if (fw->size != desired_fw->size) {
- printk(KERN_ERR "xc5000: firmware incorrect size\n");
- ret = -EINVAL;
- } else {
- printk(KERN_INFO "xc5000: firmware uploading...\n");
- ret = xc_load_i2c_sequence(fe, fw->data);
- if (0 == ret)
- ret = xc_set_xtal(fe);
- if (0 == ret)
- printk(KERN_INFO "xc5000: firmware upload complete...\n");
- else
- printk(KERN_ERR "xc5000: firmware upload failed...\n");
- }
-
-out:
- release_firmware(fw);
return ret;
}
@@ -749,13 +731,13 @@ static int xc5000_set_params(struct dvb_frontend *fe)
case SYS_ATSC:
dprintk(1, "%s() VSB modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_AIR;
- priv->freq_hz = freq - 1750000;
+ priv->freq_offset = 1750000;
priv->video_standard = DTV6;
break;
case SYS_DVBC_ANNEX_B:
dprintk(1, "%s() QAM modulation\n", __func__);
priv->rf_mode = XC_RF_MODE_CABLE;
- priv->freq_hz = freq - 1750000;
+ priv->freq_offset = 1750000;
priv->video_standard = DTV6;
break;
case SYS_ISDBT:
@@ -770,15 +752,15 @@ static int xc5000_set_params(struct dvb_frontend *fe)
switch (bw) {
case 6000000:
priv->video_standard = DTV6;
- priv->freq_hz = freq - 1750000;
+ priv->freq_offset = 1750000;
break;
case 7000000:
priv->video_standard = DTV7;
- priv->freq_hz = freq - 2250000;
+ priv->freq_offset = 2250000;
break;
case 8000000:
priv->video_standard = DTV8;
- priv->freq_hz = freq - 2750000;
+ priv->freq_offset = 2750000;
break;
default:
printk(KERN_ERR "xc5000 bandwidth not set!\n");
@@ -792,15 +774,15 @@ static int xc5000_set_params(struct dvb_frontend *fe)
priv->rf_mode = XC_RF_MODE_CABLE;
if (bw <= 6000000) {
priv->video_standard = DTV6;
- priv->freq_hz = freq - 1750000;
+ priv->freq_offset = 1750000;
b = 6;
} else if (bw <= 7000000) {
priv->video_standard = DTV7;
- priv->freq_hz = freq - 2250000;
+ priv->freq_offset = 2250000;
b = 7;
} else {
priv->video_standard = DTV7_8;
- priv->freq_hz = freq - 2750000;
+ priv->freq_offset = 2750000;
b = 8;
}
dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__,
@@ -811,6 +793,8 @@ static int xc5000_set_params(struct dvb_frontend *fe)
return -EINVAL;
}
+ priv->freq_hz = freq - priv->freq_offset;
+
dprintk(1, "%s() frequency=%d (compensated to %d)\n",
__func__, freq, priv->freq_hz);
@@ -1061,7 +1045,7 @@ static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq)
{
struct xc5000_priv *priv = fe->tuner_priv;
dprintk(1, "%s()\n", __func__);
- *freq = priv->freq_hz;
+ *freq = priv->freq_hz + priv->freq_offset;
return 0;
}
@@ -1099,42 +1083,65 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
{
struct xc5000_priv *priv = fe->tuner_priv;
- int ret = 0;
+ const struct xc5000_fw_cfg *desired_fw = xc5000_assign_firmware(priv->chip_id);
+ const struct firmware *fw;
+ int ret, i;
u16 pll_lock_status;
u16 fw_ck;
cancel_delayed_work(&priv->timer_sleep);
- if (force || xc5000_is_firmware_loaded(fe) != 0) {
+ if (!force && xc5000_is_firmware_loaded(fe) == 0)
+ return 0;
-fw_retry:
+ ret = request_firmware(&fw, desired_fw->name,
+ priv->i2c_props.adap->dev.parent);
+ if (ret) {
+ printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
+ return ret;
+ }
- ret = xc5000_fwupload(fe);
+ dprintk(1, "firmware read %Zu bytes.\n", fw->size);
+
+ if (fw->size != desired_fw->size) {
+ printk(KERN_ERR "xc5000: Firmware file with incorrect size\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* Try up to 5 times to load firmware */
+ for (i = 0; i < 5; i++) {
+ if (i)
+ printk(KERN_CONT " - retrying to upload firmware.\n");
+
+ ret = xc5000_fwupload(fe, desired_fw, fw);
if (ret != 0)
- return ret;
+ goto err;
msleep(20);
if (priv->fw_checksum_supported) {
- if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)
- != 0) {
- dprintk(1, "%s() FW checksum reading failed.\n",
- __func__);
- goto fw_retry;
+ if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)) {
+ printk(KERN_ERR
+ "xc5000: FW checksum reading failed.");
+ continue;
}
- if (fw_ck == 0) {
- dprintk(1, "%s() FW checksum failed = 0x%04x\n",
- __func__, fw_ck);
- goto fw_retry;
+ if (!fw_ck) {
+ printk(KERN_ERR
+ "xc5000: FW checksum failed = 0x%04x.",
+ fw_ck);
+ continue;
}
}
/* Start the tuner self-calibration process */
- ret |= xc_initialize(priv);
-
- if (ret != 0)
- goto fw_retry;
+ ret = xc_initialize(priv);
+ if (ret) {
+ printk(KERN_ERR
+ "xc5000: Can't request Self-callibration.");
+ continue;
+ }
/* Wait for calibration to complete.
* We could continue but XC5000 will clock stretch subsequent
@@ -1144,15 +1151,17 @@ fw_retry:
msleep(100);
if (priv->init_status_supported) {
- if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != 0) {
- dprintk(1, "%s() FW failed reading init status.\n",
- __func__);
- goto fw_retry;
+ if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck)) {
+ printk(KERN_ERR
+ "xc5000: FW failed reading init status.");
+ continue;
}
- if (fw_ck == 0) {
- dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck);
- goto fw_retry;
+ if (!fw_ck) {
+ printk(KERN_ERR
+ "xc5000: FW init status failed = 0x%04x.",
+ fw_ck);
+ continue;
}
}
@@ -1161,15 +1170,27 @@ fw_retry:
&pll_lock_status);
if (pll_lock_status > 63) {
/* PLL is unlocked, force reload of the firmware */
- printk(KERN_ERR "xc5000: PLL not running after fwload.\n");
- goto fw_retry;
+ printk(KERN_ERR
+ "xc5000: PLL not running after fwload.");
+ continue;
}
}
/* Default to "CABLE" mode */
- ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+ ret = xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE);
+ if (!ret)
+ break;
+ printk(KERN_ERR "xc5000: can't set to cable mode.");
}
+err:
+ if (!ret)
+ printk(KERN_INFO "xc5000: Firmware %s loaded and running.\n",
+ desired_fw->name);
+ else
+ printk(KERN_CONT " - too many retries. Giving up\n");
+
+ release_firmware(fw);
return ret;
}
@@ -1302,7 +1323,6 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
switch (instance) {
case 0:
goto fail;
- break;
case 1:
/* new tuner instance */
priv->bandwidth = 6000000;
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig
index 39d824e2bb69..94d51e092db3 100644
--- a/drivers/media/usb/Kconfig
+++ b/drivers/media/usb/Kconfig
@@ -27,6 +27,7 @@ source "drivers/media/usb/hdpvr/Kconfig"
source "drivers/media/usb/tlg2300/Kconfig"
source "drivers/media/usb/usbvision/Kconfig"
source "drivers/media/usb/stk1160/Kconfig"
+source "drivers/media/usb/go7007/Kconfig"
endif
if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
@@ -52,5 +53,11 @@ if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT)
source "drivers/media/usb/em28xx/Kconfig"
endif
+if MEDIA_SDR_SUPPORT
+ comment "Software defined radio USB devices"
+source "drivers/media/usb/msi2500/Kconfig"
+source "drivers/media/usb/airspy/Kconfig"
+endif
+
endif #MEDIA_USB_SUPPORT
endif #USB
diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile
index 7ac4b143dce8..f438efffefc5 100644
--- a/drivers/media/usb/Makefile
+++ b/drivers/media/usb/Makefile
@@ -9,6 +9,8 @@ obj-y += zr364xx/ stkwebcam/ s2255/
obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_USB_PWC) += pwc/
+obj-$(CONFIG_USB_MSI2500) += msi2500/
+obj-$(CONFIG_USB_AIRSPY) += airspy/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_AU0828) += au0828/
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
@@ -20,3 +22,4 @@ obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_TM6000) += tm6000/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
obj-$(CONFIG_VIDEO_USBTV) += usbtv/
+obj-$(CONFIG_VIDEO_GO7007) += go7007/
diff --git a/drivers/media/usb/airspy/Kconfig b/drivers/media/usb/airspy/Kconfig
new file mode 100644
index 000000000000..10b204cf4dbc
--- /dev/null
+++ b/drivers/media/usb/airspy/Kconfig
@@ -0,0 +1,10 @@
+config USB_AIRSPY
+ tristate "AirSpy"
+ depends on VIDEO_V4L2
+ select VIDEOBUF2_VMALLOC
+ ---help---
+ This is a video4linux2 driver for AirSpy SDR device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called airspy
+
diff --git a/drivers/media/usb/airspy/Makefile b/drivers/media/usb/airspy/Makefile
new file mode 100644
index 000000000000..8d8e61c1a349
--- /dev/null
+++ b/drivers/media/usb/airspy/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_USB_AIRSPY) += airspy.o
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
new file mode 100644
index 000000000000..cb0e515d80ae
--- /dev/null
+++ b/drivers/media/usb/airspy/airspy.c
@@ -0,0 +1,1132 @@
+/*
+ * AirSpy SDR driver
+ *
+ * Copyright (C) 2014 Antti Palosaari
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+/* AirSpy USB API commands (from AirSpy Library) */
+enum {
+ CMD_INVALID = 0x00,
+ CMD_RECEIVER_MODE = 0x01,
+ CMD_SI5351C_WRITE = 0x02,
+ CMD_SI5351C_READ = 0x03,
+ CMD_R820T_WRITE = 0x04,
+ CMD_R820T_READ = 0x05,
+ CMD_SPIFLASH_ERASE = 0x06,
+ CMD_SPIFLASH_WRITE = 0x07,
+ CMD_SPIFLASH_READ = 0x08,
+ CMD_BOARD_ID_READ = 0x09,
+ CMD_VERSION_STRING_READ = 0x0a,
+ CMD_BOARD_PARTID_SERIALNO_READ = 0x0b,
+ CMD_SET_SAMPLE_RATE = 0x0c,
+ CMD_SET_FREQ = 0x0d,
+ CMD_SET_LNA_GAIN = 0x0e,
+ CMD_SET_MIXER_GAIN = 0x0f,
+ CMD_SET_VGA_GAIN = 0x10,
+ CMD_SET_LNA_AGC = 0x11,
+ CMD_SET_MIXER_AGC = 0x12,
+ CMD_SET_PACKING = 0x13,
+};
+
+/*
+ * bEndpointAddress 0x81 EP 1 IN
+ * Transfer Type Bulk
+ * wMaxPacketSize 0x0200 1x 512 bytes
+ */
+#define MAX_BULK_BUFS (6)
+#define BULK_BUFFER_SIZE (128 * 512)
+
+static const struct v4l2_frequency_band bands[] = {
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 20000000,
+ .rangehigh = 20000000,
+ },
+};
+
+static const struct v4l2_frequency_band bands_rf[] = {
+ {
+ .tuner = 1,
+ .type = V4L2_TUNER_RF,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 24000000,
+ .rangehigh = 1750000000,
+ },
+};
+
+/* stream formats */
+struct airspy_format {
+ char *name;
+ u32 pixelformat;
+ u32 buffersize;
+};
+
+/* format descriptions for capture and preview */
+static struct airspy_format formats[] = {
+ {
+ .name = "Real U12LE",
+ .pixelformat = V4L2_SDR_FMT_RU12LE,
+ .buffersize = BULK_BUFFER_SIZE,
+ },
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
+/* intermediate buffers with raw data from the USB device */
+struct airspy_frame_buf {
+ struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */
+ struct list_head list;
+};
+
+struct airspy {
+#define POWER_ON (1 << 1)
+#define URB_BUF (1 << 2)
+#define USB_STATE_URB_BUF (1 << 3)
+ unsigned long flags;
+
+ struct usb_device *udev;
+ struct video_device vdev;
+ struct v4l2_device v4l2_dev;
+
+ /* videobuf2 queue and queued buffers list */
+ struct vb2_queue vb_queue;
+ struct list_head queued_bufs;
+ spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+ unsigned sequence; /* Buffer sequence counter */
+ unsigned int vb_full; /* vb is full and packets dropped */
+
+ /* Note if taking both locks v4l2_lock must always be locked first! */
+ struct mutex v4l2_lock; /* Protects everything else */
+ struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */
+
+ struct urb *urb_list[MAX_BULK_BUFS];
+ int buf_num;
+ unsigned long buf_size;
+ u8 *buf_list[MAX_BULK_BUFS];
+ dma_addr_t dma_addr[MAX_BULK_BUFS];
+ int urbs_initialized;
+ int urbs_submitted;
+
+ /* USB control message buffer */
+ #define BUF_SIZE 24
+ u8 buf[BUF_SIZE];
+
+ /* Current configuration */
+ unsigned int f_adc;
+ unsigned int f_rf;
+ u32 pixelformat;
+ u32 buffersize;
+
+ /* Controls */
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *lna_gain_auto;
+ struct v4l2_ctrl *lna_gain;
+ struct v4l2_ctrl *mixer_gain_auto;
+ struct v4l2_ctrl *mixer_gain;
+ struct v4l2_ctrl *if_gain;
+
+ /* Sample rate calc */
+ unsigned long jiffies_next;
+ unsigned int sample;
+ unsigned int sample_measured;
+};
+
+#define airspy_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \
+ char *_direction; \
+ if (_t & USB_DIR_IN) \
+ _direction = "<<<"; \
+ else \
+ _direction = ">>>"; \
+ dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \
+ "%s %*ph\n", __func__, _t, _r, _v & 0xff, _v >> 8, \
+ _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \
+ _l, _b); \
+}
+
+/* execute firmware command */
+static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index,
+ u8 *data, u16 size)
+{
+ int ret;
+ unsigned int pipe;
+ u8 requesttype;
+
+ switch (request) {
+ case CMD_RECEIVER_MODE:
+ case CMD_SET_FREQ:
+ pipe = usb_sndctrlpipe(s->udev, 0);
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
+ break;
+ case CMD_BOARD_ID_READ:
+ case CMD_VERSION_STRING_READ:
+ case CMD_BOARD_PARTID_SERIALNO_READ:
+ case CMD_SET_LNA_GAIN:
+ case CMD_SET_MIXER_GAIN:
+ case CMD_SET_VGA_GAIN:
+ case CMD_SET_LNA_AGC:
+ case CMD_SET_MIXER_AGC:
+ pipe = usb_rcvctrlpipe(s->udev, 0);
+ requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
+ break;
+ default:
+ dev_err(&s->udev->dev, "Unknown command %02x\n", request);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* write request */
+ if (!(requesttype & USB_DIR_IN))
+ memcpy(s->buf, data, size);
+
+ ret = usb_control_msg(s->udev, pipe, request, requesttype, value,
+ index, s->buf, size, 1000);
+ airspy_dbg_usb_control_msg(s->udev, request, requesttype, value,
+ index, s->buf, size);
+ if (ret < 0) {
+ dev_err(&s->udev->dev,
+ "usb_control_msg() failed %d request %02x\n",
+ ret, request);
+ goto err;
+ }
+
+ /* read request */
+ if (requesttype & USB_DIR_IN)
+ memcpy(data, s->buf, size);
+
+ return 0;
+err:
+ return ret;
+}
+
+/* Private functions */
+static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s)
+{
+ unsigned long flags = 0;
+ struct airspy_frame_buf *buf = NULL;
+
+ spin_lock_irqsave(&s->queued_bufs_lock, flags);
+ if (list_empty(&s->queued_bufs))
+ goto leave;
+
+ buf = list_entry(s->queued_bufs.next,
+ struct airspy_frame_buf, list);
+ list_del(&buf->list);
+leave:
+ spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+ return buf;
+}
+
+static unsigned int airspy_convert_stream(struct airspy *s,
+ void *dst, void *src, unsigned int src_len)
+{
+ unsigned int dst_len;
+
+ if (s->pixelformat == V4L2_SDR_FMT_RU12LE) {
+ memcpy(dst, src, src_len);
+ dst_len = src_len;
+ } else {
+ dst_len = 0;
+ }
+
+ /* calculate samping rate and output it in 10 seconds intervals */
+ if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+ #define MSECS 10000UL
+ 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 sample rate=%lu\n",
+ src_len, samples, MSECS,
+ samples * 1000UL / MSECS);
+ }
+
+ /* total number of samples */
+ s->sample += src_len / 2;
+
+ return dst_len;
+}
+
+/*
+ * This gets called for the bulk stream pipe. This is done in interrupt
+ * time, so it has to be fast, not crash, and not stall. Neat.
+ */
+static void airspy_urb_complete(struct urb *urb)
+{
+ struct airspy *s = urb->context;
+ struct airspy_frame_buf *fbuf;
+
+ dev_dbg_ratelimited(&s->udev->dev,
+ "%s: status=%d length=%d/%d errors=%d\n",
+ __func__, urb->status, urb->actual_length,
+ urb->transfer_buffer_length, urb->error_count);
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ dev_err_ratelimited(&s->udev->dev, "URB failed %d\n",
+ urb->status);
+ break;
+ }
+
+ if (likely(urb->actual_length > 0)) {
+ void *ptr;
+ unsigned int len;
+ /* get free framebuffer */
+ fbuf = airspy_get_next_fill_buf(s);
+ if (unlikely(fbuf == NULL)) {
+ s->vb_full++;
+ dev_notice_ratelimited(&s->udev->dev,
+ "videobuf is full, %d packets dropped\n",
+ s->vb_full);
+ goto skip;
+ }
+
+ /* fill framebuffer */
+ ptr = vb2_plane_vaddr(&fbuf->vb, 0);
+ len = airspy_convert_stream(s, ptr, urb->transfer_buffer,
+ urb->actual_length);
+ vb2_set_plane_payload(&fbuf->vb, 0, len);
+ v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
+ fbuf->vb.v4l2_buf.sequence = s->sequence++;
+ vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+ }
+skip:
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int airspy_kill_urbs(struct airspy *s)
+{
+ int i;
+
+ for (i = s->urbs_submitted - 1; i >= 0; i--) {
+ dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i);
+ /* stop the URB */
+ usb_kill_urb(s->urb_list[i]);
+ }
+ s->urbs_submitted = 0;
+
+ return 0;
+}
+
+static int airspy_submit_urbs(struct airspy *s)
+{
+ int i, ret;
+
+ for (i = 0; i < s->urbs_initialized; i++) {
+ dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i);
+ ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
+ if (ret) {
+ dev_err(&s->udev->dev,
+ "Could not submit URB no. %d - get them all back\n",
+ i);
+ airspy_kill_urbs(s);
+ return ret;
+ }
+ s->urbs_submitted++;
+ }
+
+ return 0;
+}
+
+static int airspy_free_stream_bufs(struct airspy *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);
+ usb_free_coherent(s->udev, s->buf_size,
+ s->buf_list[s->buf_num],
+ s->dma_addr[s->buf_num]);
+ }
+ }
+ s->flags &= ~USB_STATE_URB_BUF;
+
+ return 0;
+}
+
+static int airspy_alloc_stream_bufs(struct airspy *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);
+
+ 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);
+ airspy_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],
+ (long long)s->dma_addr[s->buf_num]);
+ s->flags |= USB_STATE_URB_BUF;
+ }
+
+ return 0;
+}
+
+static int airspy_free_urbs(struct airspy *s)
+{
+ int i;
+
+ airspy_kill_urbs(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);
+ /* free the URBs */
+ usb_free_urb(s->urb_list[i]);
+ }
+ }
+ s->urbs_initialized = 0;
+
+ return 0;
+}
+
+static int airspy_alloc_urbs(struct airspy *s)
+{
+ int i, j;
+
+ /* allocate the URBs */
+ for (i = 0; i < MAX_BULK_BUFS; i++) {
+ dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, 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__);
+ for (j = 0; j < i; j++)
+ usb_free_urb(s->urb_list[j]);
+ return -ENOMEM;
+ }
+ usb_fill_bulk_urb(s->urb_list[i],
+ s->udev,
+ usb_rcvbulkpipe(s->udev, 0x81),
+ s->buf_list[i],
+ BULK_BUFFER_SIZE,
+ airspy_urb_complete, s);
+
+ s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ s->urb_list[i]->transfer_dma = s->dma_addr[i];
+ s->urbs_initialized++;
+ }
+
+ return 0;
+}
+
+/* Must be called with vb_queue_lock hold */
+static void airspy_cleanup_queued_bufs(struct airspy *s)
+{
+ unsigned long flags = 0;
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ spin_lock_irqsave(&s->queued_bufs_lock, flags);
+ while (!list_empty(&s->queued_bufs)) {
+ struct airspy_frame_buf *buf;
+ buf = list_entry(s->queued_bufs.next,
+ struct airspy_frame_buf, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+}
+
+/* The user yanked out the cable... */
+static void airspy_disconnect(struct usb_interface *intf)
+{
+ struct v4l2_device *v = usb_get_intfdata(intf);
+ struct airspy *s = container_of(v, struct airspy, v4l2_dev);
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ mutex_lock(&s->vb_queue_lock);
+ mutex_lock(&s->v4l2_lock);
+ /* No need to keep the urbs around after disconnection */
+ s->udev = NULL;
+ v4l2_device_disconnect(&s->v4l2_dev);
+ video_unregister_device(&s->vdev);
+ mutex_unlock(&s->v4l2_lock);
+ mutex_unlock(&s->vb_queue_lock);
+
+ v4l2_device_put(&s->v4l2_dev);
+}
+
+/* Videobuf2 operations */
+static int airspy_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct airspy *s = vb2_get_drv_priv(vq);
+
+ dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *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]);
+ return 0;
+}
+
+static void airspy_buf_queue(struct vb2_buffer *vb)
+{
+ struct airspy *s = vb2_get_drv_priv(vb->vb2_queue);
+ struct airspy_frame_buf *buf =
+ container_of(vb, struct airspy_frame_buf, vb);
+ unsigned long flags = 0;
+
+ /* Check the device has not disconnected between prep and queuing */
+ if (unlikely(!s->udev)) {
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ spin_lock_irqsave(&s->queued_bufs_lock, flags);
+ list_add_tail(&buf->list, &s->queued_bufs);
+ spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+}
+
+static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct airspy *s = vb2_get_drv_priv(vq);
+ int ret;
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (!s->udev)
+ return -ENODEV;
+
+ mutex_lock(&s->v4l2_lock);
+
+ set_bit(POWER_ON, &s->flags);
+
+ s->sequence = 0;
+
+ ret = airspy_alloc_stream_bufs(s);
+ if (ret)
+ goto err;
+
+ ret = airspy_alloc_urbs(s);
+ if (ret)
+ goto err;
+
+ ret = airspy_submit_urbs(s);
+ if (ret)
+ goto err;
+
+ /* start hardware streaming */
+ ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0);
+ if (ret)
+ goto err;
+err:
+ mutex_unlock(&s->v4l2_lock);
+
+ return ret;
+}
+
+static void airspy_stop_streaming(struct vb2_queue *vq)
+{
+ struct airspy *s = vb2_get_drv_priv(vq);
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ mutex_lock(&s->v4l2_lock);
+
+ /* stop hardware streaming */
+ airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0);
+
+ airspy_kill_urbs(s);
+ airspy_free_urbs(s);
+ airspy_free_stream_bufs(s);
+
+ airspy_cleanup_queued_bufs(s);
+
+ clear_bit(POWER_ON, &s->flags);
+
+ mutex_unlock(&s->v4l2_lock);
+}
+
+static struct vb2_ops airspy_vb2_ops = {
+ .queue_setup = airspy_queue_setup,
+ .buf_queue = airspy_buf_queue,
+ .start_streaming = airspy_start_streaming,
+ .stop_streaming = airspy_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+static int airspy_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ struct airspy *s = video_drvdata(file);
+
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
+ strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
+ usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct airspy *s = video_drvdata(file);
+
+ dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index);
+
+ if (f->index >= NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ f->pixelformat = formats[f->index].pixelformat;
+
+ return 0;
+}
+
+static int airspy_g_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct airspy *s = video_drvdata(file);
+
+ dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+ (char *)&s->pixelformat);
+
+ f->fmt.sdr.pixelformat = s->pixelformat;
+ f->fmt.sdr.buffersize = s->buffersize;
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+
+ return 0;
+}
+
+static int airspy_s_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct airspy *s = video_drvdata(file);
+ struct vb2_queue *q = &s->vb_queue;
+ int i;
+
+ dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+ (char *)&f->fmt.sdr.pixelformat);
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+ s->pixelformat = formats[i].pixelformat;
+ s->buffersize = formats[i].buffersize;
+ f->fmt.sdr.buffersize = formats[i].buffersize;
+ return 0;
+ }
+ }
+
+ s->pixelformat = formats[0].pixelformat;
+ s->buffersize = formats[0].buffersize;
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
+ f->fmt.sdr.buffersize = formats[0].buffersize;
+
+ return 0;
+}
+
+static int airspy_try_fmt_sdr_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct airspy *s = video_drvdata(file);
+ int i;
+
+ dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
+ (char *)&f->fmt.sdr.pixelformat);
+
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+ f->fmt.sdr.buffersize = formats[i].buffersize;
+ return 0;
+ }
+ }
+
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
+ f->fmt.sdr.buffersize = formats[0].buffersize;
+
+ return 0;
+}
+
+static int airspy_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *v)
+{
+ struct airspy *s = video_drvdata(file);
+ int ret;
+
+ dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+
+ if (v->index == 0)
+ ret = 0;
+ else if (v->index == 1)
+ ret = 0;
+ else
+ ret = -EINVAL;
+
+ return ret;
+}
+
+static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+{
+ struct airspy *s = video_drvdata(file);
+ int ret;
+
+ dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index);
+
+ if (v->index == 0) {
+ strlcpy(v->name, "AirSpy ADC", sizeof(v->name));
+ v->type = V4L2_TUNER_ADC;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = bands[0].rangelow;
+ v->rangehigh = bands[0].rangehigh;
+ ret = 0;
+ } else if (v->index == 1) {
+ strlcpy(v->name, "AirSpy RF", sizeof(v->name));
+ v->type = V4L2_TUNER_RF;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = bands_rf[0].rangelow;
+ v->rangehigh = bands_rf[0].rangehigh;
+ ret = 0;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int airspy_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct airspy *s = video_drvdata(file);
+ int ret = 0;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
+ __func__, f->tuner, f->type);
+
+ if (f->tuner == 0) {
+ f->type = V4L2_TUNER_ADC;
+ f->frequency = s->f_adc;
+ ret = 0;
+ } else if (f->tuner == 1) {
+ f->type = V4L2_TUNER_RF;
+ f->frequency = s->f_rf;
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int airspy_s_frequency(struct file *file, void *priv,
+ const struct v4l2_frequency *f)
+{
+ struct airspy *s = video_drvdata(file);
+ int ret;
+ u8 buf[4];
+
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
+ __func__, f->tuner, f->type, f->frequency);
+
+ if (f->tuner == 0) {
+ s->f_adc = clamp_t(unsigned int, f->frequency,
+ bands[0].rangelow,
+ bands[0].rangehigh);
+ dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
+ __func__, s->f_adc);
+ ret = 0;
+ } else if (f->tuner == 1) {
+ s->f_rf = clamp_t(unsigned int, f->frequency,
+ bands_rf[0].rangelow,
+ bands_rf[0].rangehigh);
+ dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
+ __func__, s->f_rf);
+ buf[0] = (s->f_rf >> 0) & 0xff;
+ buf[1] = (s->f_rf >> 8) & 0xff;
+ buf[2] = (s->f_rf >> 16) & 0xff;
+ buf[3] = (s->f_rf >> 24) & 0xff;
+ ret = airspy_ctrl_msg(s, CMD_SET_FREQ, 0, 0, buf, 4);
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int airspy_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
+{
+ struct airspy *s = video_drvdata(file);
+ int ret;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
+ __func__, band->tuner, band->type, band->index);
+
+ if (band->tuner == 0) {
+ if (band->index >= ARRAY_SIZE(bands)) {
+ ret = -EINVAL;
+ } else {
+ *band = bands[band->index];
+ ret = 0;
+ }
+ } else if (band->tuner == 1) {
+ if (band->index >= ARRAY_SIZE(bands_rf)) {
+ ret = -EINVAL;
+ } else {
+ *band = bands_rf[band->index];
+ ret = 0;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ioctl_ops airspy_ioctl_ops = {
+ .vidioc_querycap = airspy_querycap,
+
+ .vidioc_enum_fmt_sdr_cap = airspy_enum_fmt_sdr_cap,
+ .vidioc_g_fmt_sdr_cap = airspy_g_fmt_sdr_cap,
+ .vidioc_s_fmt_sdr_cap = airspy_s_fmt_sdr_cap,
+ .vidioc_try_fmt_sdr_cap = airspy_try_fmt_sdr_cap,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_g_tuner = airspy_g_tuner,
+ .vidioc_s_tuner = airspy_s_tuner,
+
+ .vidioc_g_frequency = airspy_g_frequency,
+ .vidioc_s_frequency = airspy_s_frequency,
+ .vidioc_enum_freq_bands = airspy_enum_freq_bands,
+
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+};
+
+static const struct v4l2_file_operations airspy_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static struct video_device airspy_template = {
+ .name = "AirSpy SDR",
+ .release = video_device_release_empty,
+ .fops = &airspy_fops,
+ .ioctl_ops = &airspy_ioctl_ops,
+};
+
+static void airspy_video_release(struct v4l2_device *v)
+{
+ struct airspy *s = container_of(v, struct airspy, v4l2_dev);
+
+ v4l2_ctrl_handler_free(&s->hdl);
+ v4l2_device_unregister(&s->v4l2_dev);
+ kfree(s);
+}
+
+static int airspy_set_lna_gain(struct airspy *s)
+{
+ int ret;
+ u8 u8tmp;
+
+ dev_dbg(&s->udev->dev, "%s: lna auto=%d->%d val=%d->%d\n",
+ __func__, s->lna_gain_auto->cur.val,
+ s->lna_gain_auto->val, s->lna_gain->cur.val,
+ s->lna_gain->val);
+
+ ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val,
+ &u8tmp, 1);
+ if (ret)
+ goto err;
+
+ if (s->lna_gain_auto->val == false) {
+ ret = airspy_ctrl_msg(s, CMD_SET_LNA_GAIN, 0, s->lna_gain->val,
+ &u8tmp, 1);
+ if (ret)
+ goto err;
+ }
+err:
+ if (ret)
+ dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int airspy_set_mixer_gain(struct airspy *s)
+{
+ int ret;
+ u8 u8tmp;
+
+ dev_dbg(&s->udev->dev, "%s: mixer auto=%d->%d val=%d->%d\n",
+ __func__, s->mixer_gain_auto->cur.val,
+ s->mixer_gain_auto->val, s->mixer_gain->cur.val,
+ s->mixer_gain->val);
+
+ ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val,
+ &u8tmp, 1);
+ if (ret)
+ goto err;
+
+ if (s->mixer_gain_auto->val == false) {
+ ret = airspy_ctrl_msg(s, CMD_SET_MIXER_GAIN, 0,
+ s->mixer_gain->val, &u8tmp, 1);
+ if (ret)
+ goto err;
+ }
+err:
+ if (ret)
+ dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int airspy_set_if_gain(struct airspy *s)
+{
+ int ret;
+ u8 u8tmp;
+
+ dev_dbg(&s->udev->dev, "%s: val=%d->%d\n",
+ __func__, s->if_gain->cur.val, s->if_gain->val);
+
+ ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val,
+ &u8tmp, 1);
+ if (ret)
+ goto err;
+err:
+ if (ret)
+ dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret);
+
+ return ret;
+}
+
+static int airspy_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct airspy *s = container_of(ctrl->handler, struct airspy, hdl);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_LNA_GAIN:
+ ret = airspy_set_lna_gain(s);
+ break;
+ case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:
+ case V4L2_CID_RF_TUNER_MIXER_GAIN:
+ ret = airspy_set_mixer_gain(s);
+ break;
+ case V4L2_CID_RF_TUNER_IF_GAIN:
+ ret = airspy_set_if_gain(s);
+ break;
+ default:
+ dev_dbg(&s->udev->dev, "%s: unknown ctrl: id=%d name=%s\n",
+ __func__, ctrl->id, ctrl->name);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops airspy_ctrl_ops = {
+ .s_ctrl = airspy_s_ctrl,
+};
+
+static int airspy_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct airspy *s = NULL;
+ int ret;
+ u8 u8tmp, buf[BUF_SIZE];
+
+ s = kzalloc(sizeof(struct airspy), GFP_KERNEL);
+ if (s == NULL) {
+ dev_err(&udev->dev,
+ "Could not allocate memory for airspy state\n");
+ return -ENOMEM;
+ }
+
+ mutex_init(&s->v4l2_lock);
+ mutex_init(&s->vb_queue_lock);
+ spin_lock_init(&s->queued_bufs_lock);
+ INIT_LIST_HEAD(&s->queued_bufs);
+ s->udev = udev;
+ s->f_adc = bands[0].rangelow;
+ s->f_rf = bands_rf[0].rangelow;
+ s->pixelformat = formats[0].pixelformat;
+ s->buffersize = formats[0].buffersize;
+
+ /* Detect device */
+ ret = airspy_ctrl_msg(s, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
+ if (ret == 0)
+ ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0,
+ buf, BUF_SIZE);
+ if (ret) {
+ dev_err(&s->udev->dev, "Could not detect board\n");
+ goto err_free_mem;
+ }
+
+ buf[BUF_SIZE - 1] = '\0';
+
+ dev_info(&s->udev->dev, "Board ID: %02x\n", u8tmp);
+ dev_info(&s->udev->dev, "Firmware version: %s\n", buf);
+
+ /* Init videobuf2 queue structure */
+ s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+ s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ s->vb_queue.drv_priv = s;
+ s->vb_queue.buf_struct_size = sizeof(struct airspy_frame_buf);
+ s->vb_queue.ops = &airspy_vb2_ops;
+ s->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(&s->vb_queue);
+ if (ret) {
+ dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
+ goto err_free_mem;
+ }
+
+ /* Init video_device structure */
+ s->vdev = airspy_template;
+ s->vdev.queue = &s->vb_queue;
+ s->vdev.queue->lock = &s->vb_queue_lock;
+ video_set_drvdata(&s->vdev, s);
+
+ /* Register the v4l2_device structure */
+ s->v4l2_dev.release = airspy_video_release;
+ ret = v4l2_device_register(&intf->dev, &s->v4l2_dev);
+ if (ret) {
+ dev_err(&s->udev->dev,
+ "Failed to register v4l2-device (%d)\n", ret);
+ goto err_free_mem;
+ }
+
+ /* Register controls */
+ v4l2_ctrl_handler_init(&s->hdl, 5);
+ s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
+ V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 0);
+ s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
+ V4L2_CID_RF_TUNER_LNA_GAIN, 0, 14, 1, 8);
+ v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false);
+ s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
+ V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 0);
+ s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
+ V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 15, 1, 8);
+ v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false);
+ s->if_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops,
+ V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0);
+ if (s->hdl.error) {
+ ret = s->hdl.error;
+ dev_err(&s->udev->dev, "Could not initialize controls\n");
+ goto err_free_controls;
+ }
+
+ v4l2_ctrl_handler_setup(&s->hdl);
+
+ s->v4l2_dev.ctrl_handler = &s->hdl;
+ s->vdev.v4l2_dev = &s->v4l2_dev;
+ s->vdev.lock = &s->v4l2_lock;
+
+ ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
+ if (ret) {
+ dev_err(&s->udev->dev,
+ "Failed to register as video device (%d)\n",
+ ret);
+ goto err_unregister_v4l2_dev;
+ }
+ dev_info(&s->udev->dev, "Registered as %s\n",
+ video_device_node_name(&s->vdev));
+ dev_notice(&s->udev->dev,
+ "%s: SDR API is still slightly experimental and functionality changes may follow\n",
+ KBUILD_MODNAME);
+ return 0;
+
+err_free_controls:
+ v4l2_ctrl_handler_free(&s->hdl);
+err_unregister_v4l2_dev:
+ v4l2_device_unregister(&s->v4l2_dev);
+err_free_mem:
+ kfree(s);
+ return ret;
+}
+
+/* USB device ID list */
+static struct usb_device_id airspy_id_table[] = {
+ { USB_DEVICE(0x1d50, 0x60a1) }, /* AirSpy */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, airspy_id_table);
+
+/* USB subsystem interface */
+static struct usb_driver airspy_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = airspy_probe,
+ .disconnect = airspy_disconnect,
+ .id_table = airspy_id_table,
+};
+
+module_usb_driver(airspy_driver);
+
+MODULE_AUTHOR("Antti Palosaari ");
+MODULE_DESCRIPTION("AirSpy SDR");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
index 953a37c613b1..1d410ac8f9a8 100644
--- a/drivers/media/usb/au0828/Kconfig
+++ b/drivers/media/usb/au0828/Kconfig
@@ -20,9 +20,17 @@ config VIDEO_AU0828_V4L2
bool "Auvitek AU0828 v4l2 analog video support"
depends on VIDEO_AU0828 && VIDEO_V4L2
select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT
+ select VIDEO_TUNER
default y
---help---
This is a video4linux driver for Auvitek's USB device.
Choose Y here to include support for v4l2 analog video
capture within the au0828 driver.
+
+config VIDEO_AU0828_RC
+ bool "AU0828 Remote Controller support"
+ depends on RC_CORE
+ depends on VIDEO_AU0828
+ ---help---
+ Enables Remote Controller support on au0828 driver.
diff --git a/drivers/media/usb/au0828/Makefile b/drivers/media/usb/au0828/Makefile
index be3bdf698022..3dc7539a5c4e 100644
--- a/drivers/media/usb/au0828/Makefile
+++ b/drivers/media/usb/au0828/Makefile
@@ -4,6 +4,10 @@ ifeq ($(CONFIG_VIDEO_AU0828_V4L2),y)
au0828-objs += au0828-video.o au0828-vbi.o
endif
+ifeq ($(CONFIG_VIDEO_AU0828_RC),y)
+ au0828-objs += au0828-input.o
+endif
+
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
ccflags-y += -Idrivers/media/tuners
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index 7fdadf9bc90b..2c6b7da137ed 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -46,7 +46,7 @@ struct au0828_board au0828_boards[] = {
.name = "Hauppauge HVR850",
.tuner_type = TUNER_XC5000,
.tuner_addr = 0x61,
- .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
.input = {
{
.type = AU0828_VMUX_TELEVISION,
@@ -71,13 +71,14 @@ struct au0828_board au0828_boards[] = {
.name = "Hauppauge HVR950Q",
.tuner_type = TUNER_XC5000,
.tuner_addr = 0x61,
+ .has_ir_i2c = 1,
/* The au0828 hardware i2c implementation does not properly
support the xc5000's i2c clock stretching. So we need to
lower the clock frequency enough where the 15us clock
stretch fits inside of a normal clock cycle, or else the
au0828 fails to set the STOP bit. A 30 KHz clock puts the
clock pulse width at 18us */
- .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
.input = {
{
.type = AU0828_VMUX_TELEVISION,
@@ -108,7 +109,7 @@ struct au0828_board au0828_boards[] = {
.name = "DViCO FusionHDTV USB",
.tuner_type = UNSET,
.tuner_addr = ADDR_UNSET,
- .i2c_clk_divider = AU0828_I2C_CLK_20KHZ,
+ .i2c_clk_divider = AU0828_I2C_CLK_250KHZ,
},
[AU0828_BOARD_HAUPPAUGE_WOODBURY] = {
.name = "Hauppauge Woodbury",
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index ab45a6f9dcc9..56025e689442 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -32,10 +32,12 @@
* 2 = USB handling
* 4 = I2C related
* 8 = Bridge related
+ * 16 = IR related
*/
int au0828_debug;
module_param_named(debug, au0828_debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
+MODULE_PARM_DESC(debug,
+ "set debug bitmask: 1=general, 2=USB, 4=I2C, 8=bridge, 16=IR");
static unsigned int disable_usb_speed_check;
module_param(disable_usb_speed_check, int, 0444);
@@ -151,6 +153,9 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
dprintk(1, "%s()\n", __func__);
+#ifdef CONFIG_VIDEO_AU0828_RC
+ au0828_rc_unregister(dev);
+#endif
/* Digital TV */
au0828_dvb_unregister(dev);
@@ -261,9 +266,15 @@ static int au0828_usb_probe(struct usb_interface *interface,
pr_err("%s() au0282_dev_register failed\n",
__func__);
+#ifdef CONFIG_VIDEO_AU0828_RC
+ /* Remote controller */
+ au0828_rc_register(dev);
+#endif
- /* Store the pointer to the au0828_dev so it can be accessed in
- au0828_usb_disconnect */
+ /*
+ * Store the pointer to the au0828_dev so it can be accessed in
+ * au0828_usb_disconnect
+ */
usb_set_intfdata(interface, dev);
printk(KERN_INFO "Registered device AU0828 [%s]\n",
@@ -279,6 +290,8 @@ static struct usb_driver au0828_usb_driver = {
.probe = au0828_usb_probe,
.disconnect = au0828_usb_disconnect,
.id_table = au0828_usb_id_table,
+
+ /* FIXME: Add suspend and resume functions */
};
static int __init au0828_init(void)
@@ -298,6 +311,10 @@ static int __init au0828_init(void)
printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
__func__);
+ if (au0828_debug & 16)
+ printk(KERN_INFO "%s() IR Debugging is enabled\n",
+ __func__);
+
printk(KERN_INFO "au0828 driver loaded\n");
ret = usb_register(&au0828_usb_driver);
@@ -318,4 +335,4 @@ module_exit(au0828_exit);
MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
MODULE_AUTHOR("Steven Toth ");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.2");
+MODULE_VERSION("0.0.3");
diff --git a/drivers/media/usb/au0828/au0828-i2c.c b/drivers/media/usb/au0828/au0828-i2c.c
index 17ec3651b10e..daaeaf1b089c 100644
--- a/drivers/media/usb/au0828/au0828-i2c.c
+++ b/drivers/media/usb/au0828/au0828-i2c.c
@@ -141,25 +141,27 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
{
int i, strobe = 0;
struct au0828_dev *dev = i2c_adap->algo_data;
+ u8 i2c_speed = dev->board.i2c_clk_divider;
dprintk(4, "%s()\n", __func__);
au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
- /* Set the I2C clock */
if (((dev->board.tuner_type == TUNER_XC5000) ||
(dev->board.tuner_type == TUNER_XC5000C)) &&
- (dev->board.tuner_addr == msg->addr) &&
- (msg->len == 64)) {
- /* Hack to speed up firmware load. The xc5000 lets us do up
- to 400 KHz when in firmware download mode */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
- AU0828_I2C_CLK_250KHZ);
- } else {
- /* Use the i2c clock speed in the board configuration */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
- dev->board.i2c_clk_divider);
+ (dev->board.tuner_addr == msg->addr)) {
+ /*
+ * Due to I2C clock stretch, we need to use a lower speed
+ * on xc5000 for commands. However, firmware transfer can
+ * speed up to 400 KHz.
+ */
+ if (msg->len == 64)
+ i2c_speed = AU0828_I2C_CLK_250KHZ;
+ else
+ i2c_speed = AU0828_I2C_CLK_20KHZ;
}
+ /* Set the I2C clock */
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, i2c_speed);
/* Hardware needs 8 bit addresses */
au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
@@ -228,15 +230,24 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
const struct i2c_msg *msg, int joined)
{
struct au0828_dev *dev = i2c_adap->algo_data;
+ u8 i2c_speed = dev->board.i2c_clk_divider;
int i;
dprintk(4, "%s()\n", __func__);
au0828_write(dev, AU0828_I2C_MULTIBYTE_MODE_2FF, 0x01);
+ /*
+ * Due to xc5000c clock stretch, we cannot use full speed at
+ * readings from xc5000, as otherwise they'll fail.
+ */
+ if (((dev->board.tuner_type == TUNER_XC5000) ||
+ (dev->board.tuner_type == TUNER_XC5000C)) &&
+ (dev->board.tuner_addr == msg->addr))
+ i2c_speed = AU0828_I2C_CLK_20KHZ;
+
/* Set the I2C clock */
- au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202,
- dev->board.i2c_clk_divider);
+ au0828_write(dev, AU0828_I2C_CLK_DIVIDER_202, i2c_speed);
/* Hardware needs 8 bit addresses */
au0828_write(dev, AU0828_I2C_DEST_ADDR_203, msg->addr << 1);
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c
new file mode 100644
index 000000000000..fd0d3a90ce7d
--- /dev/null
+++ b/drivers/media/usb/au0828/au0828-input.c
@@ -0,0 +1,386 @@
+/*
+ handle au0828 IR remotes via linux kernel input layer.
+
+ Copyright (C) 2014 Mauro Carvalho Chehab
+ Copyright (c) 2014 Samsung Electronics Co., Ltd.
+
+ Based on em28xx-input.c.
+
+ 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
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "au0828.h"
+
+struct au0828_rc {
+ struct au0828_dev *dev;
+ struct rc_dev *rc;
+ char name[32];
+ char phys[32];
+
+ /* poll decoder */
+ int polling;
+ struct delayed_work work;
+
+ /* i2c slave address of external device (if used) */
+ u16 i2c_dev_addr;
+
+ int (*get_key_i2c)(struct au0828_rc *ir);
+};
+
+/*
+ * AU8522 has a builtin IR receiver. Add functions to get IR from it
+ */
+
+static int au8522_rc_write(struct au0828_rc *ir, u16 reg, u8 data)
+{
+ int rc;
+ char buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
+ struct i2c_msg msg = { .addr = ir->i2c_dev_addr, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+
+ rc = i2c_transfer(ir->dev->i2c_client.adapter, &msg, 1);
+
+ if (rc < 0)
+ return rc;
+
+ return (rc == 1) ? 0 : -EIO;
+}
+
+static int au8522_rc_read(struct au0828_rc *ir, u16 reg, int val,
+ char *buf, int size)
+{
+ int rc;
+ char obuf[3];
+ struct i2c_msg msg[2] = { { .addr = ir->i2c_dev_addr, .flags = 0,
+ .buf = obuf, .len = 2 },
+ { .addr = ir->i2c_dev_addr, .flags = I2C_M_RD,
+ .buf = buf, .len = size } };
+
+ obuf[0] = 0x40 | reg >> 8;
+ obuf[1] = reg & 0xff;
+ if (val >= 0) {
+ obuf[2] = val;
+ msg[0].len++;
+ }
+
+ rc = i2c_transfer(ir->dev->i2c_client.adapter, msg, 2);
+
+ if (rc < 0)
+ return rc;
+
+ return (rc == 2) ? 0 : -EIO;
+}
+
+static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
+{
+ int rc;
+ char buf;
+
+ rc = au8522_rc_read(ir, reg, -1, &buf, 1);
+ if (rc < 0)
+ return rc;
+
+ buf = (buf & ~mask) | (value & mask);
+
+ return au8522_rc_write(ir, reg, buf);
+}
+
+#define au8522_rc_set(ir, reg, bit) au8522_rc_andor(ir, (reg), (bit), (bit))
+#define au8522_rc_clear(ir, reg, bit) au8522_rc_andor(ir, (reg), (bit), 0)
+
+/* Remote Controller time units */
+
+#define AU8522_UNIT 200000 /* ns */
+#define NEC_START_SPACE (4500000 / AU8522_UNIT)
+#define NEC_START_PULSE (562500 * 16)
+#define RC5_START_SPACE (4 * AU8522_UNIT)
+#define RC5_START_PULSE 888888
+
+static int au0828_get_key_au8522(struct au0828_rc *ir)
+{
+ unsigned char buf[40];
+ DEFINE_IR_RAW_EVENT(rawir);
+ int i, j, rc;
+ int prv_bit, bit, width;
+ bool first = true;
+
+ /* Check IR int */
+ rc = au8522_rc_read(ir, 0xe1, -1, buf, 1);
+ if (rc < 0 || !(buf[0] & (1 << 4)))
+ return 0;
+
+ /* Something arrived. Get the data */
+ rc = au8522_rc_read(ir, 0xe3, 0x11, buf, sizeof(buf));
+
+
+ if (rc < 0)
+ return rc;
+
+ /* Disable IR */
+ au8522_rc_clear(ir, 0xe0, 1 << 4);
+
+ usleep_range(45000, 46000);
+
+ /* Enable IR */
+ au8522_rc_set(ir, 0xe0, 1 << 4);
+
+ dprintk(16, "RC data received: %*ph\n", 40, buf);
+
+ prv_bit = (buf[0] >> 7) & 0x01;
+ width = 0;
+ for (i = 0; i < sizeof(buf); i++) {
+ for (j = 7; j >= 0; j--) {
+ bit = (buf[i] >> j) & 0x01;
+ if (bit == prv_bit) {
+ width++;
+ continue;
+ }
+
+ /*
+ * Fix an au8522 bug: the first pulse event
+ * is lost. So, we need to fake it, based on the
+ * protocol. That means that not all raw decoders
+ * will work, as we need to add a hack for each
+ * protocol, based on the first space.
+ * So, we only support RC5 and NEC.
+ */
+
+ if (first) {
+ first = false;
+
+ init_ir_raw_event(&rawir);
+ rawir.pulse = true;
+ if (width > NEC_START_SPACE - 2 &&
+ width < NEC_START_SPACE + 2) {
+ /* NEC protocol */
+ rawir.duration = NEC_START_PULSE;
+ dprintk(16, "Storing NEC start %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+ } else {
+ /* RC5 protocol */
+ rawir.duration = RC5_START_PULSE;
+ dprintk(16, "Storing RC5 start %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+ }
+ ir_raw_event_store(ir->rc, &rawir);
+ }
+
+ init_ir_raw_event(&rawir);
+ rawir.pulse = prv_bit ? false : true;
+ rawir.duration = AU8522_UNIT * width;
+ dprintk(16, "Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+ ir_raw_event_store(ir->rc, &rawir);
+
+ width = 1;
+ prv_bit = bit;
+ }
+ }
+
+ init_ir_raw_event(&rawir);
+ rawir.pulse = prv_bit ? false : true;
+ rawir.duration = AU8522_UNIT * width;
+ dprintk(16, "Storing end %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+ ir_raw_event_store(ir->rc, &rawir);
+
+ ir_raw_event_handle(ir->rc);
+
+ return 1;
+}
+
+/*
+ * Generic IR code
+ */
+
+static void au0828_rc_work(struct work_struct *work)
+{
+ struct au0828_rc *ir = container_of(work, struct au0828_rc, work.work);
+ int rc;
+
+ rc = ir->get_key_i2c(ir);
+ if (rc < 0)
+ pr_info("Error while getting RC scancode\n");
+
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+}
+
+static int au0828_rc_start(struct rc_dev *rc)
+{
+ struct au0828_rc *ir = rc->priv;
+
+ INIT_DELAYED_WORK(&ir->work, au0828_rc_work);
+
+ /* Enable IR */
+ au8522_rc_set(ir, 0xe0, 1 << 4);
+
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+
+ return 0;
+}
+
+static void au0828_rc_stop(struct rc_dev *rc)
+{
+ struct au0828_rc *ir = rc->priv;
+
+ /* Disable IR */
+ au8522_rc_clear(ir, 0xe0, 1 << 4);
+
+ cancel_delayed_work_sync(&ir->work);
+}
+
+static int au0828_probe_i2c_ir(struct au0828_dev *dev)
+{
+ int i = 0;
+ const unsigned short addr_list[] = {
+ 0x47, I2C_CLIENT_END
+ };
+
+ while (addr_list[i] != I2C_CLIENT_END) {
+ if (i2c_probe_func_quick_read(dev->i2c_client.adapter,
+ addr_list[i]) == 1)
+ return addr_list[i];
+ i++;
+ }
+
+ return -ENODEV;
+}
+
+int au0828_rc_register(struct au0828_dev *dev)
+{
+ struct au0828_rc *ir;
+ struct rc_dev *rc;
+ int err = -ENOMEM;
+ u16 i2c_rc_dev_addr = 0;
+
+ if (!dev->board.has_ir_i2c)
+ return 0;
+
+ i2c_rc_dev_addr = au0828_probe_i2c_ir(dev);
+ if (!i2c_rc_dev_addr)
+ return -ENODEV;
+
+ ir = kzalloc(sizeof(*ir), GFP_KERNEL);
+ rc = rc_allocate_device();
+ if (!ir || !rc)
+ goto error;
+
+ /* record handles to ourself */
+ ir->dev = dev;
+ dev->ir = ir;
+ ir->rc = rc;
+
+ rc->priv = ir;
+ rc->open = au0828_rc_start;
+ rc->close = au0828_rc_stop;
+
+ if (dev->board.has_ir_i2c) { /* external i2c device */
+ switch (dev->boardnr) {
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ rc->map_name = RC_MAP_HAUPPAUGE;
+ ir->get_key_i2c = au0828_get_key_au8522;
+ break;
+ default:
+ err = -ENODEV;
+ goto error;
+ }
+
+ ir->i2c_dev_addr = i2c_rc_dev_addr;
+ }
+
+ /* This is how often we ask the chip for IR information */
+ ir->polling = 100; /* ms */
+
+ /* init input device */
+ snprintf(ir->name, sizeof(ir->name), "au0828 IR (%s)",
+ dev->board.name);
+
+ usb_make_path(dev->usbdev, ir->phys, sizeof(ir->phys));
+ strlcat(ir->phys, "/input0", sizeof(ir->phys));
+
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_USB;
+ rc->input_id.version = 1;
+ rc->input_id.vendor = le16_to_cpu(dev->usbdev->descriptor.idVendor);
+ rc->input_id.product = le16_to_cpu(dev->usbdev->descriptor.idProduct);
+ rc->dev.parent = &dev->usbdev->dev;
+ rc->driver_name = "au0828-input";
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protocols = RC_BIT_NEC | RC_BIT_RC5;
+
+ /* all done */
+ err = rc_register_device(rc);
+ if (err)
+ goto error;
+
+ pr_info("Remote controller %s initalized\n", ir->name);
+
+ return 0;
+
+error:
+ dev->ir = NULL;
+ rc_free_device(rc);
+ kfree(ir);
+ return err;
+}
+
+void au0828_rc_unregister(struct au0828_dev *dev)
+{
+ struct au0828_rc *ir = dev->ir;
+
+ /* skip detach on non attached boards */
+ if (!ir)
+ return;
+
+ if (ir->rc)
+ rc_unregister_device(ir->rc);
+
+ /* done */
+ kfree(ir);
+ dev->ir = NULL;
+}
+
+int au0828_rc_suspend(struct au0828_dev *dev)
+{
+ struct au0828_rc *ir = dev->ir;
+
+ if (!ir)
+ return 0;
+
+ cancel_delayed_work_sync(&ir->work);
+
+ return 0;
+}
+
+int au0828_rc_resume(struct au0828_dev *dev)
+{
+ struct au0828_rc *ir = dev->ir;
+
+ if (!ir)
+ return 0;
+
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
+
+ return 0;
+}
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 9038194513c5..98f7ea1d6d63 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -787,23 +787,40 @@ static int au0828_i2s_init(struct au0828_dev *dev)
/*
* Auvitek au0828 analog stream enable
- * Please set interface0 to AS5 before enable the stream
*/
static int au0828_analog_stream_enable(struct au0828_dev *d)
{
+ struct usb_interface *iface;
+ int ret, h, w;
+
dprintk(1, "au0828_analog_stream_enable called\n");
+
+ iface = usb_ifnum_to_if(d->usbdev, 0);
+ if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) {
+ dprintk(1, "Changing intf#0 to alt 5\n");
+ /* set au0828 interface0 to AS5 here again */
+ ret = usb_set_interface(d->usbdev, 0, 5);
+ if (ret < 0) {
+ printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
+ return -EBUSY;
+ }
+ }
+
+ h = d->height / 2 + 2;
+ w = d->width * 2;
+
au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00);
au0828_writereg(d, 0x106, 0x00);
/* set x position */
au0828_writereg(d, 0x110, 0x00);
au0828_writereg(d, 0x111, 0x00);
- au0828_writereg(d, 0x114, 0xa0);
- au0828_writereg(d, 0x115, 0x05);
+ au0828_writereg(d, 0x114, w & 0xff);
+ au0828_writereg(d, 0x115, w >> 8);
/* set y position */
au0828_writereg(d, 0x112, 0x00);
au0828_writereg(d, 0x113, 0x00);
- au0828_writereg(d, 0x116, 0xf2);
- au0828_writereg(d, 0x117, 0x00);
+ au0828_writereg(d, 0x116, h & 0xff);
+ au0828_writereg(d, 0x117, h >> 8);
au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3);
return 0;
@@ -1002,15 +1019,6 @@ static int au0828_v4l2_open(struct file *filp)
return -ERESTARTSYS;
}
if (dev->users == 0) {
- /* set au0828 interface0 to AS5 here again */
- ret = usb_set_interface(dev->usbdev, 0, 5);
- if (ret < 0) {
- mutex_unlock(&dev->lock);
- printk(KERN_INFO "Au0828 can't set alternate to 5!\n");
- kfree(fh);
- return -EBUSY;
- }
-
au0828_analog_stream_enable(dev);
au0828_analog_stream_reset(dev);
@@ -1252,13 +1260,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
}
}
- /* set au0828 interface0 to AS5 here again */
- ret = usb_set_interface(dev->usbdev, 0, 5);
- if (ret < 0) {
- printk(KERN_INFO "Au0828 can't set alt setting to 5!\n");
- return -EBUSY;
- }
-
au0828_analog_stream_enable(dev);
return 0;
@@ -1364,9 +1365,11 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
i2c_gate_ctrl(dev, 1);
- /* FIXME: when we support something other than NTSC, we are going to
- have to make the au0828 bridge adjust the size of its capture
- buffer, which is currently hardcoded at 720x480 */
+ /*
+ * FIXME: when we support something other than 60Hz standards,
+ * we are going to have to make the au0828 bridge adjust the size
+ * of its capture buffer, which is currently hardcoded at 720x480
+ */
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm);
@@ -1723,6 +1726,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
dev->vid_timeout_running = 0;
del_timer_sync(&dev->vid_timeout);
+ au0828_analog_stream_disable(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
rc = au0828_stream_interrupt(dev);
if (rc != 0)
@@ -1915,7 +1919,7 @@ static const struct video_device au0828_video_template = {
.fops = &au0828_v4l_fops,
.release = video_device_release,
.ioctl_ops = &video_ioctl_ops,
- .tvnorms = V4L2_STD_NTSC_M,
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
};
/**************************************************************************/
@@ -1928,7 +1932,8 @@ int au0828_analog_register(struct au0828_dev *dev,
struct usb_endpoint_descriptor *endpoint;
int i, ret;
- dprintk(1, "au0828_analog_register called!\n");
+ dprintk(1, "au0828_analog_register called for intf#%d!\n",
+ interface->cur_altsetting->desc.bInterfaceNumber);
/* set au0828 usb interface0 to as5 */
retval = usb_set_interface(dev->usbdev,
@@ -1952,6 +1957,9 @@ int au0828_analog_register(struct au0828_dev *dev,
dev->max_pkt_size = (tmp & 0x07ff) *
(((tmp & 0x1800) >> 11) + 1);
dev->isoc_in_endpointaddr = endpoint->bEndpointAddress;
+ dprintk(1,
+ "Found isoc endpoint 0x%02x, max size = %d\n",
+ dev->isoc_in_endpointaddr, dev->max_pkt_size);
}
}
if (!(dev->isoc_in_endpointaddr)) {
@@ -2008,14 +2016,12 @@ int au0828_analog_register(struct au0828_dev *dev,
*dev->vdev = au0828_video_template;
dev->vdev->v4l2_dev = &dev->v4l2_dev;
dev->vdev->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags);
strcpy(dev->vdev->name, "au0828a video");
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
dev->vbi_dev->v4l2_dev = &dev->v4l2_dev;
dev->vbi_dev->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags);
strcpy(dev->vbi_dev->name, "au0828a vbi");
/* Register the v4l2 device */
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 7112b9d956fa..96bec05d7dac 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -88,6 +88,7 @@ struct au0828_board {
unsigned int tuner_type;
unsigned char tuner_addr;
unsigned char i2c_clk_divider;
+ unsigned char has_ir_i2c:1;
struct au0828_input input[AU0828_MAX_INPUT];
};
@@ -213,6 +214,10 @@ struct au0828_dev {
struct v4l2_device v4l2_dev;
struct v4l2_ctrl_handler v4l2_ctrl_hdl;
#endif
+#ifdef CONFIG_VIDEO_AU0828_RC
+ struct au0828_rc *ir;
+#endif
+
int users;
unsigned int resources; /* resources in use */
struct video_device *vdev;
@@ -319,3 +324,9 @@ extern struct videobuf_queue_ops au0828_vbi_qops;
do { if (au0828_debug & level)\
printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
} while (0)
+
+/* au0828-input.c */
+int au0828_rc_register(struct au0828_dev *dev);
+void au0828_rc_unregister(struct au0828_dev *dev);
+int au0828_rc_suspend(struct au0828_dev *dev);
+int au0828_rc_resume(struct au0828_dev *dev);
diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c
index d5d42b6e94be..9caea8344547 100644
--- a/drivers/media/usb/cpia2/cpia2_v4l.c
+++ b/drivers/media/usb/cpia2/cpia2_v4l.c
@@ -1169,7 +1169,6 @@ int cpia2_register_camera(struct camera_data *cam)
cam->vdev.lock = &cam->v4l2_lock;
cam->vdev.ctrl_handler = hdl;
cam->vdev.v4l2_dev = &cam->v4l2_dev;
- set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags);
reset_camera_struct_v4l(cam);
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
index f14c5e89a567..569aa298c03f 100644
--- a/drivers/media/usb/cx231xx/Kconfig
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -47,6 +47,8 @@ config VIDEO_CX231XX_DVB
select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 30a0c69fb42f..459bb0e98971 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1563,7 +1563,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->ts1.width;
f->fmt.pix.height = dev->ts1.height;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.priv = 0;
dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n",
dev->ts1.width, dev->ts1.height);
dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
@@ -1582,7 +1581,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = mpeglines * mpeglinesize;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.priv = 0;
dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
dev->ts1.width, dev->ts1.height);
dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
@@ -1923,7 +1921,6 @@ static struct video_device *cx231xx_video_dev_alloc(
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->lock = &dev->lock;
vfd->release = video_device_release;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl;
video_set_drvdata(vfd, dev);
if (dev->tuner_type == TUNER_ABSENT) {
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 89de00bf4f82..a428c10e1a16 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -352,6 +352,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 2ee03e4ddd86..8039b769f258 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -704,6 +704,84 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
+ [CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx] = {
+ .name = "Hauppauge WinTV 930C-HD (1113xx) / PCTV QuatroStick 521e",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x0e,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
+ [CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx] = {
+ .name = "Hauppauge WinTV 930C-HD (1114xx) / PCTV QuatroStick 522e",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x0e,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -733,10 +811,20 @@ struct usb_device_id cx231xx_id_table[] = {
.driver_info = CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC},
{USB_DEVICE(0x2040, 0xb120),
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+ {USB_DEVICE(0x2040, 0xb130),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
+ {USB_DEVICE(0x2040, 0xb131),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
{USB_DEVICE(0x2040, 0xb140),
.driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
{USB_DEVICE(0x2040, 0xc200),
.driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2},
+ /* PCTV QuatroStick 521e */
+ {USB_DEVICE(0x2013, 0x0259),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx},
+ /* PCTV QuatroStick 522e */
+ {USB_DEVICE(0x2013, 0x025e),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx},
{USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001),
.driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
{USB_DEVICE(USB_VID_PIXELVIEW, 0x5014),
@@ -886,6 +974,50 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
}
+static int read_eeprom(struct cx231xx *dev, u8 *eedata, int len)
+{
+ int ret = 0;
+ u8 addr = 0xa0 >> 1;
+ u8 start_offset = 0;
+ int len_todo = len;
+ u8 *eedata_cur = eedata;
+ int i;
+ struct i2c_msg msg_write = { .addr = addr, .flags = 0,
+ .buf = &start_offset, .len = 1 };
+ struct i2c_msg msg_read = { .addr = addr, .flags = I2C_M_RD };
+
+ /* mutex_lock(&dev->i2c_lock); */
+ cx231xx_enable_i2c_port_3(dev, false);
+
+ /* start reading at offset 0 */
+ ret = i2c_transfer(&dev->i2c_bus[1].i2c_adap, &msg_write, 1);
+ if (ret < 0) {
+ cx231xx_err("Can't read eeprom\n");
+ return ret;
+ }
+
+ while (len_todo > 0) {
+ msg_read.len = (len_todo > 64) ? 64 : len_todo;
+ msg_read.buf = eedata_cur;
+
+ ret = i2c_transfer(&dev->i2c_bus[1].i2c_adap, &msg_read, 1);
+ if (ret < 0) {
+ cx231xx_err("Can't read eeprom\n");
+ return ret;
+ }
+ eedata_cur += msg_read.len;
+ len_todo -= msg_read.len;
+ }
+
+ cx231xx_enable_i2c_port_3(dev, true);
+ /* mutex_unlock(&dev->i2c_lock); */
+
+ for (i = 0; i + 15 < len; i += 16)
+ cx231xx_info("i2c eeprom %02x: %*ph\n", i, 16, &eedata[i]);
+
+ return 0;
+}
+
void cx231xx_card_setup(struct cx231xx *dev)
{
@@ -917,6 +1049,21 @@ void cx231xx_card_setup(struct cx231xx *dev)
else
cx231xx_config_tuner(dev);
}
+
+ switch (dev->model) {
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ {
+ struct tveeprom tvee;
+ static u8 eeprom[256];
+
+ read_eeprom(dev, eeprom, sizeof(eeprom));
+ tveeprom_hauppauge_analog(&dev->i2c_bus[1].i2c_client,
+ &tvee, eeprom + 0xc0);
+ break;
+ }
+ }
+
}
/*
@@ -964,12 +1111,6 @@ void cx231xx_release_resources(struct cx231xx *dev)
/* Mark device as unused */
clear_bit(dev->devno, &cx231xx_devused);
-
- kfree(dev->video_mode.alt_max_pkt_size);
- kfree(dev->vbi_mode.alt_max_pkt_size);
- kfree(dev->sliced_cc_mode.alt_max_pkt_size);
- kfree(dev->ts1_mode.alt_max_pkt_size);
- kfree(dev);
}
/*
@@ -1003,7 +1144,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
dev->cx231xx_gpio_i2c_write = cx231xx_gpio_i2c_write;
/* Query cx231xx to find what pcb config it is related to */
- initialize_cx231xx(dev);
+ retval = initialize_cx231xx(dev);
+ if (retval < 0) {
+ cx231xx_errdev("Failed to read PCB config\n");
+ return retval;
+ }
/*To workaround error number=-71 on EP0 for VideoGrabber,
need set alt here.*/
@@ -1121,6 +1266,117 @@ static void flush_request_modules(struct cx231xx *dev)
#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
+static int cx231xx_init_v4l2(struct cx231xx *dev,
+ struct usb_device *udev,
+ struct usb_interface *interface,
+ int isoc_pipe)
+{
+ struct usb_interface *uif;
+ int i, idx;
+
+ /* Video Init */
+
+ /* compute alternate max packet sizes for video */
+ idx = dev->current_pcb_config.hs_config_info[0].interface_info.video_index + 1;
+ if (idx >= dev->max_iad_interface_count) {
+ cx231xx_errdev("Video PCB interface #%d doesn't exist\n", idx);
+ return -ENODEV;
+ }
+
+ uif = udev->actconfig->interface[idx];
+
+ dev->video_mode.end_point_addr = uif->altsetting[0].endpoint[isoc_pipe].desc.bEndpointAddress;
+ dev->video_mode.num_alt = uif->num_altsetting;
+
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->video_mode.end_point_addr,
+ dev->video_mode.num_alt);
+
+ dev->video_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->video_mode.num_alt, GFP_KERNEL);
+ if (dev->video_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->video_mode.num_alt; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
+ dev->video_mode.alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->video_mode.alt_max_pkt_size[i]);
+ }
+
+ /* VBI Init */
+
+ idx = dev->current_pcb_config.hs_config_info[0].interface_info.vanc_index + 1;
+ if (idx >= dev->max_iad_interface_count) {
+ cx231xx_errdev("VBI PCB interface #%d doesn't exist\n", idx);
+ return -ENODEV;
+ }
+ uif = udev->actconfig->interface[idx];
+
+ dev->vbi_mode.end_point_addr =
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
+
+ dev->vbi_mode.num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->vbi_mode.end_point_addr,
+ dev->vbi_mode.num_alt);
+
+ /* compute alternate max packet sizes for vbi */
+ dev->vbi_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->vbi_mode.num_alt, GFP_KERNEL);
+ if (dev->vbi_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->vbi_mode.num_alt; i++) {
+ u16 tmp =
+ le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+ desc.wMaxPacketSize);
+ dev->vbi_mode.alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->vbi_mode.alt_max_pkt_size[i]);
+ }
+
+ /* Sliced CC VBI init */
+
+ /* compute alternate max packet sizes for sliced CC */
+ idx = dev->current_pcb_config.hs_config_info[0].interface_info.hanc_index + 1;
+ if (idx >= dev->max_iad_interface_count) {
+ cx231xx_errdev("Sliced CC PCB interface #%d doesn't exist\n", idx);
+ return -ENODEV;
+ }
+ uif = udev->actconfig->interface[idx];
+
+ dev->sliced_cc_mode.end_point_addr =
+ uif->altsetting[0].endpoint[isoc_pipe].desc.
+ bEndpointAddress;
+
+ dev->sliced_cc_mode.num_alt = uif->num_altsetting;
+ cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->sliced_cc_mode.end_point_addr,
+ dev->sliced_cc_mode.num_alt);
+ dev->sliced_cc_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->sliced_cc_mode.num_alt, GFP_KERNEL);
+
+ if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
+ cx231xx_errdev("out of memory!\n");
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
+ u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
+ desc.wMaxPacketSize);
+ dev->sliced_cc_mode.alt_max_pkt_size[i] =
+ (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
+ cx231xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->sliced_cc_mode.alt_max_pkt_size[i]);
+ }
+
+ return 0;
+}
+
/*
* cx231xx_usb_probe()
* checks for supported devices
@@ -1135,6 +1391,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
int nr = 0, ifnum;
int i, isoc_pipe = 0;
char *speed;
+ u8 idx;
struct usb_interface_assoc_descriptor *assoc_desc;
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
@@ -1157,16 +1414,16 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
}
} while (test_and_set_bit(nr, &cx231xx_devused));
+ udev = usb_get_dev(interface_to_usbdev(interface));
+
/* allocate memory for our device state and initialize it */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ dev = devm_kzalloc(&udev->dev, sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
cx231xx_err(DRIVER_NAME ": out of memory!\n");
clear_bit(nr, &cx231xx_devused);
return -ENOMEM;
}
- udev = usb_get_dev(interface_to_usbdev(interface));
-
snprintf(dev->name, 29, "cx231xx #%d", nr);
dev->devno = nr;
dev->model = id->driver_info;
@@ -1185,8 +1442,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
dev->vbi_or_sliced_cc_mode = 0;
/* get maximum no.of IAD interfaces */
- assoc_desc = udev->actconfig->intf_assoc[0];
- dev->max_iad_interface_count = assoc_desc->bInterfaceCount;
+ dev->max_iad_interface_count = udev->config->desc.bNumInterfaces;
/* init CIR module TBD */
@@ -1238,120 +1494,31 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
- /*
- * AV device initialization - only done at the last interface
- */
-
/* Create v4l2 device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
cx231xx_errdev("v4l2_device_register failed\n");
- retval = -EIO;
goto err_v4l2;
}
+
/* allocate device struct */
retval = cx231xx_init_dev(dev, udev, nr);
if (retval)
goto err_init;
- /* compute alternate max packet sizes for video */
- uif = udev->actconfig->interface[dev->current_pcb_config.
- hs_config_info[0].interface_info.video_index + 1];
-
- dev->video_mode.end_point_addr = uif->altsetting[0].
- endpoint[isoc_pipe].desc.bEndpointAddress;
-
- dev->video_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->video_mode.end_point_addr,
- dev->video_mode.num_alt);
- dev->video_mode.alt_max_pkt_size =
- kmalloc(32 * dev->video_mode.num_alt, GFP_KERNEL);
-
- if (dev->video_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
- retval = -ENOMEM;
- goto err_video_alt;
- }
-
- for (i = 0; i < dev->video_mode.num_alt; i++) {
- u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
- desc.wMaxPacketSize);
- dev->video_mode.alt_max_pkt_size[i] =
- (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->video_mode.alt_max_pkt_size[i]);
- }
-
- /* compute alternate max packet sizes for vbi */
- uif = udev->actconfig->interface[dev->current_pcb_config.
- hs_config_info[0].interface_info.
- vanc_index + 1];
-
- dev->vbi_mode.end_point_addr =
- uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress;
-
- dev->vbi_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->vbi_mode.end_point_addr,
- dev->vbi_mode.num_alt);
- dev->vbi_mode.alt_max_pkt_size =
- kmalloc(32 * dev->vbi_mode.num_alt, GFP_KERNEL);
-
- if (dev->vbi_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
- retval = -ENOMEM;
- goto err_vbi_alt;
- }
-
- for (i = 0; i < dev->vbi_mode.num_alt; i++) {
- u16 tmp =
- le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
- desc.wMaxPacketSize);
- dev->vbi_mode.alt_max_pkt_size[i] =
- (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->vbi_mode.alt_max_pkt_size[i]);
- }
-
- /* compute alternate max packet sizes for sliced CC */
- uif = udev->actconfig->interface[dev->current_pcb_config.
- hs_config_info[0].interface_info.
- hanc_index + 1];
-
- dev->sliced_cc_mode.end_point_addr =
- uif->altsetting[0].endpoint[isoc_pipe].desc.
- bEndpointAddress;
-
- dev->sliced_cc_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->sliced_cc_mode.end_point_addr,
- dev->sliced_cc_mode.num_alt);
- dev->sliced_cc_mode.alt_max_pkt_size =
- kmalloc(32 * dev->sliced_cc_mode.num_alt, GFP_KERNEL);
-
- if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
- retval = -ENOMEM;
- goto err_sliced_cc_alt;
- }
-
- for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
- u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
- desc.wMaxPacketSize);
- dev->sliced_cc_mode.alt_max_pkt_size[i] =
- (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->sliced_cc_mode.alt_max_pkt_size[i]);
- }
+ retval = cx231xx_init_v4l2(dev, udev, interface, isoc_pipe);
+ if (retval)
+ goto err_init;
if (dev->current_pcb_config.ts1_source != 0xff) {
/* compute alternate max packet sizes for TS1 */
- uif = udev->actconfig->interface[dev->current_pcb_config.
- hs_config_info[0].
- interface_info.
- ts1_index + 1];
+ idx = dev->current_pcb_config.hs_config_info[0].interface_info.ts1_index + 1;
+ if (idx >= dev->max_iad_interface_count) {
+ cx231xx_errdev("TS1 PCB interface #%d doesn't exist\n", idx);
+ retval = -ENODEV;
+ goto err_video_alt;
+ }
+ uif = udev->actconfig->interface[idx];
dev->ts1_mode.end_point_addr =
uif->altsetting[0].endpoint[isoc_pipe].
@@ -1361,13 +1528,12 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
dev->ts1_mode.end_point_addr,
dev->ts1_mode.num_alt);
- dev->ts1_mode.alt_max_pkt_size =
- kmalloc(32 * dev->ts1_mode.num_alt, GFP_KERNEL);
+ dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->ts1_mode.num_alt, GFP_KERNEL);
if (dev->ts1_mode.alt_max_pkt_size == NULL) {
cx231xx_errdev("out of memory!\n");
retval = -ENOMEM;
- goto err_ts1_alt;
+ goto err_video_alt;
}
for (i = 0; i < dev->ts1_mode.num_alt; i++) {
@@ -1394,12 +1560,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
request_modules(dev);
return 0;
-err_ts1_alt:
- kfree(dev->sliced_cc_mode.alt_max_pkt_size);
-err_sliced_cc_alt:
- kfree(dev->vbi_mode.alt_max_pkt_size);
-err_vbi_alt:
- kfree(dev->video_mode.alt_max_pkt_size);
err_video_alt:
/* cx231xx_uninit_dev: */
cx231xx_close_extension(dev);
@@ -1415,7 +1575,6 @@ err_v4l2:
err_if:
usb_put_dev(udev);
clear_bit(dev->devno, &cx231xx_devused);
- kfree(dev);
return retval;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 4ba3ce09b713..513194aa6561 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -726,6 +726,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
break;
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
errCode = cx231xx_set_power_mode(dev,
POLARIS_AVMODE_DIGITAL);
break;
@@ -744,6 +745,7 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
case CX231XX_BOARD_CNXT_RDE_253S:
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
@@ -1379,6 +1381,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
case CX231XX_BOARD_CNXT_RDE_253S:
case CX231XX_BOARD_CNXT_RDU_253S:
case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_PAL:
case CX231XX_BOARD_HAUPPAUGE_USB2_FM_NTSC:
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 4504bc6a700b..1fa79741d199 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -32,7 +32,9 @@
#include "tda18271.h"
#include "s5h1411.h"
#include "lgdt3305.h"
+#include "si2165.h"
#include "mb86a20s.h"
+#include "si2157.h"
MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
MODULE_AUTHOR("Srinivasa Deevi ");
@@ -67,6 +69,7 @@ struct cx231xx_dvb {
struct dmx_frontend fe_hw;
struct dmx_frontend fe_mem;
struct dvb_net net;
+ struct i2c_client *i2c_client_tuner;
};
static struct s5h1432_config dvico_s5h1432_config = {
@@ -151,6 +154,18 @@ static struct tda18271_config pv_tda18271_config = {
.small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
+static const struct si2165_config hauppauge_930C_HD_1113xx_si2165_config = {
+ .i2c_addr = 0x64,
+ .chip_mode = SI2165_MODE_PLL_XTAL,
+ .ref_freq_Hz = 16000000,
+};
+
+static const struct si2165_config pctv_quatro_stick_1114xx_si2165_config = {
+ .i2c_addr = 0x64,
+ .chip_mode = SI2165_MODE_PLL_EXT,
+ .ref_freq_Hz = 24000000,
+};
+
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
{
char *errmsg = "Unknown";
@@ -549,11 +564,18 @@ fail_adapter:
static void unregister_dvb(struct cx231xx_dvb *dvb)
{
+ struct i2c_client *client;
dvb_net_release(&dvb->net);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
+ client = dvb->i2c_client_tuner;
+ /* remove I2C tuner */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
dvb_unregister_frontend(dvb->frontend);
dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
@@ -704,6 +726,89 @@ static int dvb_init(struct cx231xx *dev)
&hcw_tda18271_config);
break;
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx:
+
+ dev->dvb->frontend = dvb_attach(si2165_attach,
+ &hauppauge_930C_HD_1113xx_si2165_config,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap
+ );
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach SI2165 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &hcw_tda18271_config);
+
+ dev->cx231xx_reset_analog_tuner = NULL;
+ break;
+
+ case CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx:
+ {
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2157_config si2157_config;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ dev->dvb->frontend = dvb_attach(si2165_attach,
+ &pctv_quatro_stick_1114xx_si2165_config,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap
+ );
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach SI2165 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ dev->dvb->frontend->ops.i2c_gate_ctrl = 0;
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = dev->dvb->frontend;
+ si2157_config.inversion = true;
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module("si2157");
+
+ client = i2c_new_device(
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ dvb_frontend_detach(dev->dvb->frontend);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ dvb_frontend_detach(dev->dvb->frontend);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dev->cx231xx_reset_analog_tuner = NULL;
+
+ dev->dvb->i2c_client_tuner = client;
+ break;
+ }
+
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 46d52fac8680..05f0434919d4 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -21,11 +21,12 @@
#include "cx231xx.h"
#include
#include
+#include
#define MODULE_NAME "cx231xx-input"
-static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
- u32 *ir_raw)
+static int get_key_isdbt(struct IR_i2c *ir, enum rc_type *protocol,
+ u32 *pscancode, u8 *toggle)
{
int rc;
u8 cmd, scancode;
@@ -46,21 +47,14 @@ static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
if (cmd == 0xff)
return 0;
- scancode =
- ((cmd & 0x01) ? 0x80 : 0) |
- ((cmd & 0x02) ? 0x40 : 0) |
- ((cmd & 0x04) ? 0x20 : 0) |
- ((cmd & 0x08) ? 0x10 : 0) |
- ((cmd & 0x10) ? 0x08 : 0) |
- ((cmd & 0x20) ? 0x04 : 0) |
- ((cmd & 0x40) ? 0x02 : 0) |
- ((cmd & 0x80) ? 0x01 : 0);
+ scancode = bitrev8(cmd);
dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
cmd, scancode);
- *ir_key = scancode;
- *ir_raw = scancode;
+ *protocol = RC_TYPE_OTHER;
+ *pscancode = scancode;
+ *toggle = 0;
return 1;
}
@@ -97,7 +91,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
dev->init_data.get_key = get_key_isdbt;
dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name;
/* The i2c micro-controller only outputs the cmd part of NEC protocol */
- dev->init_data.rc_dev->scanmask = 0xff;
+ dev->init_data.rc_dev->scancode_mask = 0xff;
dev->init_data.rc_dev->driver_name = "cx231xx";
dev->init_data.type = RC_BIT_NEC;
info.addr = 0x30;
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
index 2a34ceee4802..3052c4c20229 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
@@ -654,8 +654,9 @@ static struct pcb_config cx231xx_Scenario[] = {
/*****************************************************************/
-u32 initialize_cx231xx(struct cx231xx *dev)
+int initialize_cx231xx(struct cx231xx *dev)
{
+ int retval;
u32 config_info = 0;
struct pcb_config *p_pcb_info;
u8 usb_speed = 1; /* from register,1--HS, 0--FS */
@@ -670,7 +671,10 @@ u32 initialize_cx231xx(struct cx231xx *dev)
/* read board config register to find out which
pcb config it is related to */
- cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT, data, 4);
+ retval = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
+ data, 4);
+ if (retval < 0)
+ return retval;
config_info = le32_to_cpu(*((__le32 *)data));
usb_speed = (u8) (config_info & 0x1);
@@ -767,7 +771,7 @@ u32 initialize_cx231xx(struct cx231xx *dev)
cx231xx_info("bad senario!!!!!\n");
cx231xx_info("config_info=%x\n",
(config_info & SELFPOWER_MASK));
- return 1;
+ return -ENODEV;
}
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
index b3c6190e0c69..4511dc5d199c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.h
@@ -221,6 +221,6 @@ enum INDEX_PCB_CONFIG{
/***************************************************************************/
struct cx231xx;
-u32 initialize_cx231xx(struct cx231xx *p_dev);
+int initialize_cx231xx(struct cx231xx *p_dev);
#endif
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 1f8751379e24..3b3ada6562ca 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -208,7 +208,7 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
- int i, rc = 1;
+ int i;
unsigned char *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
u8 sav_eav = 0;
@@ -299,13 +299,12 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
bytes_parsed = 0;
}
- return rc;
+ return 1;
}
static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
- int rc = 1;
unsigned char *p_buffer;
u32 bytes_parsed = 0, buffer_size = 0;
u8 sav_eav = 0;
@@ -379,7 +378,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
bytes_parsed = 0;
}
- return rc;
+ return 1;
}
@@ -886,7 +885,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -931,7 +929,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- f->fmt.pix.priv = 0;
return 0;
}
@@ -1620,7 +1617,7 @@ static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner
*/
static int cx231xx_v4l2_open(struct file *filp)
{
- int errCode = 0, radio = 0;
+ int radio = 0;
struct video_device *vdev = video_devdata(filp);
struct cx231xx *dev = video_drvdata(filp);
struct cx231xx_fh *fh;
@@ -1718,7 +1715,7 @@ static int cx231xx_v4l2_open(struct file *filp)
mutex_unlock(&dev->lock);
v4l2_fh_add(&fh->fh);
- return errCode;
+ return 0;
}
/*
@@ -2066,7 +2063,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
vfd->release = video_device_release;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index babca7fb85e2..aeb1bf42b88d 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -73,6 +73,8 @@
#define CX231XX_BOARD_ELGATO_VIDEO_CAPTURE_V2 16
#define CX231XX_BOARD_OTG102 17
#define CX231XX_BOARD_KWORLD_UB445_USB_HYBRID 18
+#define CX231XX_BOARD_HAUPPAUGE_930C_HD_1113xx 19
+#define CX231XX_BOARD_HAUPPAUGE_930C_HD_1114xx 20
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 037e519bbaa2..66645b02c854 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -129,6 +129,7 @@ config DVB_USB_RTL28XXU
depends on DVB_USB_V2 && I2C_MUX
select DVB_RTL2830
select DVB_RTL2832
+ select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT)
select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index da47d2392f2a..5ca738ab44e0 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -1213,7 +1213,7 @@ static int af9015_rc_query(struct dvb_usb_device *d)
if ((state->rc_repeat != buf[6] || buf[0]) &&
!memcmp(&buf[12], state->rc_last, 4)) {
dev_dbg(&d->udev->dev, "%s: key repeated\n", __func__);
- rc_keydown(d->rc_dev, state->rc_keycode, 0);
+ rc_repeat(d->rc_dev);
state->rc_repeat = buf[6];
return ret;
}
@@ -1233,18 +1233,22 @@ static int af9015_rc_query(struct dvb_usb_device *d)
if (buf[14] == (u8) ~buf[15]) {
if (buf[12] == (u8) ~buf[13]) {
/* NEC */
- state->rc_keycode = buf[12] << 8 | buf[14];
+ state->rc_keycode = RC_SCANCODE_NEC(buf[12],
+ buf[14]);
} else {
/* NEC extended*/
- state->rc_keycode = buf[12] << 16 |
- buf[13] << 8 | buf[14];
+ state->rc_keycode = RC_SCANCODE_NECX(buf[12] << 8 |
+ buf[13],
+ buf[14]);
}
} else {
/* 32 bit NEC */
- state->rc_keycode = buf[12] << 24 | buf[13] << 16 |
- buf[14] << 8 | buf[15];
+ state->rc_keycode = RC_SCANCODE_NEC32(buf[12] << 24 |
+ buf[13] << 16 |
+ buf[14] << 8 |
+ buf[15]);
}
- rc_keydown(d->rc_dev, state->rc_keycode, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, state->rc_keycode, 0);
} else {
dev_dbg(&d->udev->dev, "%s: no key press\n", __func__);
/* Invalidate last keypress */
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 7b9b75f60774..75ec1c659fdd 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -799,6 +799,25 @@ static int af9035_read_config(struct dvb_usb_device *d)
addr += 0x10; /* shift for the 2nd tuner params */
}
+ /*
+ * These AVerMedia devices has a bad EEPROM content :-(
+ * Override some wrong values here.
+ */
+ if (le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) {
+ switch (le16_to_cpu(d->udev->descriptor.idProduct)) {
+ case USB_PID_AVERMEDIA_A835B_1835:
+ case USB_PID_AVERMEDIA_A835B_2835:
+ case USB_PID_AVERMEDIA_A835B_3835:
+ dev_info(&d->udev->dev,
+ "%s: overriding tuner from %02x to %02x\n",
+ KBUILD_MODNAME, state->af9033_config[0].tuner,
+ AF9033_TUNER_IT9135_60);
+
+ state->af9033_config[0].tuner = AF9033_TUNER_IT9135_60;
+ break;
+ }
+ }
+
skip_eeprom:
/* get demod clock */
ret = af9035_rd_reg(d, 0x00d800, &tmp);
@@ -1313,19 +1332,20 @@ static int af9035_rc_query(struct dvb_usb_device *d)
if ((buf[2] + buf[3]) == 0xff) {
if ((buf[0] + buf[1]) == 0xff) {
/* NEC standard 16bit */
- key = buf[0] << 8 | buf[2];
+ key = RC_SCANCODE_NEC(buf[0], buf[2]);
} else {
/* NEC extended 24bit */
- key = buf[0] << 16 | buf[1] << 8 | buf[2];
+ key = RC_SCANCODE_NECX(buf[0] << 8 | buf[1], buf[2]);
}
} else {
/* NEC full code 32bit */
- key = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
+ key = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
+ buf[2] << 8 | buf[3]);
}
dev_dbg(&d->udev->dev, "%s: %*ph\n", __func__, 4, buf);
- rc_keydown(d->rc_dev, key, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, key, 0);
return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index eeab79bdd2aa..e4a2382196f0 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -1038,7 +1038,8 @@ static int anysee_rc_query(struct dvb_usb_device *d)
if (ircode[0]) {
dev_dbg(&d->udev->dev, "%s: key pressed %02x\n", __func__,
ircode[1]);
- rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC,
+ RC_SCANCODE_NEC(0x08, ircode[1]), 0);
}
return 0;
diff --git a/drivers/media/usb/dvb-usb-v2/az6007.c b/drivers/media/usb/dvb-usb-v2/az6007.c
index c3c4b98733bf..935dbaa80ef0 100644
--- a/drivers/media/usb/dvb-usb-v2/az6007.c
+++ b/drivers/media/usb/dvb-usb-v2/az6007.c
@@ -207,24 +207,27 @@ static int az6007_streaming_ctrl(struct dvb_frontend *fe, int onoff)
static int az6007_rc_query(struct dvb_usb_device *d)
{
struct az6007_device_state *st = d_to_priv(d);
- unsigned code = 0;
+ unsigned code;
az6007_read(d, AZ6007_READ_IR, 0, 0, st->data, 10);
if (st->data[1] == 0x44)
return 0;
- if ((st->data[1] ^ st->data[2]) == 0xff)
- code = st->data[1];
- else
- code = st->data[1] << 8 | st->data[2];
+ if ((st->data[3] ^ st->data[4]) == 0xff) {
+ if ((st->data[1] ^ st->data[2]) == 0xff)
+ code = RC_SCANCODE_NEC(st->data[1], st->data[3]);
+ else
+ code = RC_SCANCODE_NECX(st->data[1] << 8 | st->data[2],
+ st->data[3]);
+ } else {
+ code = RC_SCANCODE_NEC32(st->data[1] << 24 |
+ st->data[2] << 16 |
+ st->data[3] << 8 |
+ st->data[4]);
+ }
- if ((st->data[3] ^ st->data[4]) == 0xff)
- code = code << 8 | st->data[3];
- else
- code = code << 16 | st->data[3] << 8 | st->data[4];
-
- rc_keydown(d->rc_dev, code, st->data[5]);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, code, st->data[5]);
return 0;
}
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index f296394bb7c5..2e90310be2af 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -164,7 +164,7 @@ static int dvb_usbv2_remote_init(struct dvb_usb_device *d)
dev->driver_name = (char *) d->props->driver_name;
dev->map_name = d->rc.map_name;
dev->driver_type = d->rc.driver_type;
- rc_set_allowed_protocols(dev, d->rc.allowed_protos);
+ dev->allowed_protocols = d->rc.allowed_protos;
dev->change_protocol = d->rc.change_protocol;
dev->priv = d;
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index f674dc024d06..e332af731187 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -125,14 +125,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define TUNER_RS2000 0x4
struct lme2510_state {
+ unsigned long int_urb_due;
u8 id;
u8 tuner_config;
u8 signal_lock;
u8 signal_level;
u8 signal_sn;
u8 time_key;
- u8 last_key;
- u8 key_timeout;
u8 i2c_talk_onoff;
u8 i2c_gate;
u8 i2c_tuner_gate_w;
@@ -287,14 +286,13 @@ static void lme2510_int_response(struct urb *lme_urb)
case 0xaa:
debug_data_snipet(1, "INT Remote data snipet", ibuf);
if ((ibuf[4] + ibuf[5]) == 0xff) {
- key = ibuf[5];
- key += (ibuf[3] > 0)
- ? (ibuf[3] ^ 0xff) << 8 : 0;
- key += (ibuf[2] ^ 0xff) << 16;
+ key = RC_SCANCODE_NECX((ibuf[2] ^ 0xff) << 8 |
+ (ibuf[3] > 0) ? (ibuf[3] ^ 0xff) : 0,
+ ibuf[5]);
deb_info(1, "INT Key =%08x", key);
if (adap_to_d(adap)->rc_dev != NULL)
rc_keydown(adap_to_d(adap)->rc_dev,
- key, 0);
+ RC_TYPE_NEC, key, 0);
}
break;
case 0xbb:
@@ -323,7 +321,7 @@ static void lme2510_int_response(struct urb *lme_urb)
}
break;
case TUNER_RS2000:
- if (ibuf[1] == 0x3 && ibuf[6] == 0xff)
+ if (ibuf[2] & 0x1)
st->signal_lock = 0xff;
else
st->signal_lock = 0x00;
@@ -343,7 +341,12 @@ static void lme2510_int_response(struct urb *lme_urb)
break;
}
}
+
usb_submit_urb(lme_urb, GFP_ATOMIC);
+
+ /* interrupt urb is due every 48 msecs while streaming
+ * add 12msecs for system lag */
+ st->int_urb_due = jiffies + msecs_to_jiffies(60);
}
static int lme2510_int_read(struct dvb_usb_adapter *adap)
@@ -584,14 +587,13 @@ static int lme2510_msg(struct dvb_usb_device *d,
switch (wbuf[3]) {
case 0x8c:
rbuf[0] = 0x55;
- rbuf[1] = 0xff;
- if (st->last_key == st->time_key) {
- st->key_timeout++;
- if (st->key_timeout > 5)
- rbuf[1] = 0;
- } else
- st->key_timeout = 0;
- st->last_key = st->time_key;
+ rbuf[1] = st->signal_lock;
+
+ /* If int_urb_due overdue
+ * set rbuf[1] to 0 to clear lock */
+ if (time_after(jiffies, st->int_urb_due))
+ rbuf[1] = 0;
+
break;
default:
lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index c7304fa8ab73..b8a707e57b99 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -129,7 +129,7 @@ int mxl111sf_write_reg_mask(struct mxl111sf_state *state,
u8 addr, u8 mask, u8 data)
{
int ret;
- u8 val;
+ u8 val = 0;
if (mask != 0xff) {
ret = mxl111sf_read_reg(state, addr, &val);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index a676e4452847..27b1e0397e71 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1287,19 +1287,19 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
if (buf[2] == (u8) ~buf[3]) {
if (buf[0] == (u8) ~buf[1]) {
/* NEC standard (16 bit) */
- rc_code = buf[0] << 8 | buf[2];
+ rc_code = RC_SCANCODE_NEC(buf[0], buf[2]);
} else {
/* NEC extended (24 bit) */
- rc_code = buf[0] << 16 |
- buf[1] << 8 | buf[2];
+ rc_code = RC_SCANCODE_NECX(buf[0] << 8 | buf[1],
+ buf[2]);
}
} else {
/* NEC full (32 bit) */
- rc_code = buf[0] << 24 | buf[1] << 16 |
- buf[2] << 8 | buf[3];
+ rc_code = RC_SCANCODE_NEC32(buf[0] << 24 | buf[1] << 16 |
+ buf[2] << 8 | buf[3]);
}
- rc_keydown(d->rc_dev, rc_code, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0);
ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
if (ret)
@@ -1541,6 +1541,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Peak DVB-T USB", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U,
&rtl2832u_props, "Sveon STV20", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV21,
+ &rtl2832u_props, "Sveon STV21", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27,
&rtl2832u_props, "Sveon STV27", NULL) },
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index c5d95662e2e1..10aef2188fbe 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -117,10 +117,12 @@ config DVB_USB_CXUSB
select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
select DVB_ATBM8830 if MEDIA_SUBDRV_AUTOSELECT
select DVB_LGS8GXX if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MAX2165 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -128,6 +130,7 @@ config DVB_USB_CXUSB
Medion MD95700 hybrid USB2.0 device.
DViCO FusionHDTV (Bluebird) USB2.0 devices
+ TechnoTrend TVStick CT2-4400
config DVB_USB_M920X
tristate "Uli m920x DVB-T USB2.0 support"
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index a1c641e18362..16bc579d1404 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -42,9 +42,11 @@
#include "dib0070.h"
#include "lgs8gxx.h"
#include "atbm8830.h"
+#include "si2168.h"
+#include "si2157.h"
/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE 64
+#define MAX_XFER_SIZE 80
/* debug */
static int dvb_usb_cxusb_debug;
@@ -144,6 +146,22 @@ static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
}
}
+static int cxusb_tt_ct2_4400_gpio_tuner(struct dvb_usb_device *d, int onoff)
+{
+ u8 o[2], i;
+ int rc;
+
+ o[0] = 0x83;
+ o[1] = onoff;
+ rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
+
+ if (rc) {
+ deb_info("gpio_write failed.\n");
+ return -EIO;
+ }
+ return 0;
+}
+
/* I2C */
static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
@@ -505,6 +523,30 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
return 0;
}
+static int cxusb_tt_ct2_4400_rc_query(struct dvb_usb_device *d)
+{
+ u8 i[2];
+ int ret;
+ u32 cmd, keycode;
+ u8 rc5_cmd, rc5_addr, rc5_toggle;
+
+ ret = cxusb_ctrl_msg(d, 0x10, NULL, 0, i, 2);
+ if (ret)
+ return ret;
+
+ cmd = (i[0] << 8) | i[1];
+
+ if (cmd != 0xffff) {
+ rc5_cmd = cmd & 0x3F; /* bits 1-6 for command */
+ rc5_addr = (cmd & 0x07C0) >> 6; /* bits 7-11 for address */
+ rc5_toggle = (cmd & 0x0800) >> 11; /* bit 12 for toggle */
+ keycode = (rc5_addr << 8) | rc5_cmd;
+ rc_keydown(d->rc_dev, RC_BIT_RC5, keycode, rc5_toggle);
+ }
+
+ return 0;
+}
+
static struct rc_map_table rc_map_dvico_mce_table[] = {
{ 0xfe02, KEY_TV },
{ 0xfe0e, KEY_MP3 },
@@ -1070,8 +1112,15 @@ static struct dib7000p_config cxusb_dualdig4_rev2_config = {
.hostbus_diversity = 1,
};
+struct dib0700_adapter_state {
+ int (*set_param_save)(struct dvb_frontend *);
+ struct dib7000p_ops dib7000p_ops;
+};
+
static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
if (usb_set_interface(adap->dev->udev, 0, 1) < 0)
err("set interface failed");
@@ -1079,14 +1128,17 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
- &cxusb_dualdig4_rev2_config) < 0) {
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ &cxusb_dualdig4_rev2_config) < 0) {
printk(KERN_WARNING "Unable to enumerate dib7000p\n");
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
- &cxusb_dualdig4_rev2_config);
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
+ &cxusb_dualdig4_rev2_config);
if (adap->fe_adap[0].fe == NULL)
return -EIO;
@@ -1095,7 +1147,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
{
- return dib7000p_set_gpio(fe, 8, 0, !onoff);
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ return state->dib7000p_ops.set_gpio(fe, 8, 0, !onoff);
}
static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
@@ -1110,10 +1165,6 @@ static struct dib0070_config dib7070p_dib0070_config = {
.clock_khz = 12000,
};
-struct dib0700_adapter_state {
- int (*set_param_save) (struct dvb_frontend *);
-};
-
static int dib7070_set_param_override(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -1128,7 +1179,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe)
case BAND_UHF: offset = 550; break;
}
- dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+ state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
return state->set_param_save(fe);
}
@@ -1136,8 +1187,14 @@ static int dib7070_set_param_override(struct dvb_frontend *fe)
static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c =
- dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+ struct i2c_adapter *tun_i2c;
+
+ /*
+ * No need to call dvb7000p_attach here, as it was called
+ * already, as frontend_attach method is called first, and
+ * tuner_attach is only called on sucess.
+ */
+ tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
DIBX000_I2C_INTERFACE_TUNER, 1);
if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
@@ -1286,6 +1343,74 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
+static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct cxusb_state *st = d->priv;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client_demod;
+ struct i2c_client *client_tuner;
+ struct i2c_board_info info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+
+ /* reset the tuner */
+ if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) {
+ err("clear tuner gpio failed");
+ return -EIO;
+ }
+ msleep(100);
+ if (cxusb_tt_ct2_4400_gpio_tuner(d, 1) < 0) {
+ err("set tuner gpio failed");
+ return -EIO;
+ }
+ msleep(100);
+
+ /* attach frontend */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &adap->fe_adap[0].fe;
+ 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(&d->i2c_adap, &info);
+ if (client_demod == NULL || client_demod->dev.driver == NULL)
+ return -ENODEV;
+
+ if (!try_module_get(client_demod->dev.driver->owner)) {
+ i2c_unregister_device(client_demod);
+ return -ENODEV;
+ }
+
+ st->i2c_client_demod = client_demod;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = adap->fe_adap[0].fe;
+ 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);
+ return -ENODEV;
+ }
+ 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);
+ return -ENODEV;
+ }
+
+ st->i2c_client_tuner = client_tuner;
+
+ return 0;
+}
+
/*
* DViCO has shipped two devices with the same USB ID, but only one of them
* needs a firmware download. Check the device class details to see if they
@@ -1367,6 +1492,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
+static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties;
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -1397,12 +1523,37 @@ static int cxusb_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &cxusb_tt_ct2_4400_properties,
+ THIS_MODULE, NULL, adapter_nr) ||
0)
return 0;
return -EINVAL;
}
+static void cxusb_disconnect(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ struct cxusb_state *st = d->priv;
+ struct i2c_client *client;
+
+ /* remove I2C client for tuner */
+ client = st->i2c_client_tuner;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ /* remove I2C client for demodulator */
+ client = st->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ dvb_usb_device_exit(intf);
+}
+
static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
@@ -1424,6 +1575,7 @@ static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
+ { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2070,10 +2222,63 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
}
};
+static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .num_frontends = 1,
+ .fe = {{
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ /* both frontend and tuner attached in the
+ same function */
+ .frontend_attach = cxusb_tt_ct2_4400_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 8,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+ } },
+ },
+ },
+
+ .i2c_algo = &cxusb_i2c_algo,
+ .generic_bulk_ctrl_endpoint = 0x01,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+
+ .rc.core = {
+ .rc_codes = RC_MAP_TT_1500,
+ .allowed_protos = RC_BIT_RC5,
+ .rc_query = cxusb_tt_ct2_4400_rc_query,
+ .rc_interval = 150,
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ {
+ "TechnoTrend TVStick CT2-4400",
+ { NULL },
+ { &cxusb_table[20], NULL },
+ },
+ }
+};
+
static struct usb_driver cxusb_driver = {
.name = "dvb_usb_cxusb",
.probe = cxusb_probe,
- .disconnect = dvb_usb_device_exit,
+ .disconnect = cxusb_disconnect,
.id_table = cxusb_table,
};
diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h
index 1a51eafd31b9..527ff7905e15 100644
--- a/drivers/media/usb/dvb-usb/cxusb.h
+++ b/drivers/media/usb/dvb-usb/cxusb.h
@@ -30,6 +30,8 @@
struct cxusb_state {
u8 gpio_write_state[3];
+ struct i2c_client *i2c_client_demod;
+ struct i2c_client *i2c_client_tuner;
};
#endif
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index c14285fa8271..50856dbf5496 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -658,13 +658,8 @@ out:
struct dib0700_rc_response {
u8 report_id;
u8 data_state;
- union {
- u16 system16;
- struct {
- u8 not_system;
- u8 system;
- };
- };
+ u8 system;
+ u8 not_system;
u8 data;
u8 not_data;
};
@@ -674,6 +669,7 @@ static void dib0700_rc_urb_completion(struct urb *purb)
{
struct dvb_usb_device *d = purb->context;
struct dib0700_rc_response *poll_reply;
+ enum rc_type protocol;
u32 uninitialized_var(keycode);
u8 toggle;
@@ -707,44 +703,55 @@ static void dib0700_rc_urb_completion(struct urb *purb)
switch (d->props.rc.core.protocol) {
case RC_BIT_NEC:
+ protocol = RC_TYPE_NEC;
toggle = 0;
/* NEC protocol sends repeat code as 0 0 0 FF */
- if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
- && (poll_reply->not_data == 0xff)) {
+ if (poll_reply->system == 0x00 &&
+ poll_reply->not_system == 0x00 &&
+ poll_reply->data == 0x00 &&
+ poll_reply->not_data == 0xff) {
poll_reply->data_state = 2;
break;
}
- if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+ if ((poll_reply->data ^ poll_reply->not_data) != 0xff) {
+ deb_data("NEC32 protocol\n");
+ keycode = RC_SCANCODE_NEC32(poll_reply->system << 24 |
+ poll_reply->not_system << 16 |
+ poll_reply->data << 8 |
+ poll_reply->not_data);
+ } else if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
deb_data("NEC extended protocol\n");
- /* NEC extended code - 24 bits */
- keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
+ keycode = RC_SCANCODE_NECX(poll_reply->system << 8 |
+ poll_reply->not_system,
+ poll_reply->data);
+
} else {
deb_data("NEC normal protocol\n");
- /* normal NEC code - 16 bits */
- keycode = poll_reply->system << 8 | poll_reply->data;
+ keycode = RC_SCANCODE_NEC(poll_reply->system,
+ poll_reply->data);
}
break;
default:
deb_data("RC5 protocol\n");
- /* RC5 Protocol */
+ protocol = RC_TYPE_RC5;
toggle = poll_reply->report_id;
- keycode = poll_reply->system << 8 | poll_reply->data;
+ keycode = RC_SCANCODE_RC5(poll_reply->system, poll_reply->data);
break;
}
if ((poll_reply->data + poll_reply->not_data) != 0xff) {
/* Key failed integrity check */
- err("key failed integrity check: %04x %02x %02x",
- poll_reply->system,
+ err("key failed integrity check: %02x %02x %02x %02x",
+ poll_reply->system, poll_reply->not_system,
poll_reply->data, poll_reply->not_data);
goto resubmit;
}
- rc_keydown(d->rc_dev, keycode, toggle);
+ rc_keydown(d->rc_dev, protocol, keycode, toggle);
resubmit:
/* Clean the buffer before we requeue */
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 10e0db8d1850..ce47d3f1c850 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -32,6 +32,8 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif
struct dib0700_adapter_state {
int (*set_param_save) (struct dvb_frontend *);
const struct firmware *frontend_firmware;
+ struct dib7000p_ops dib7000p_ops;
+ struct dib8000_ops dib8000_ops;
};
/* Hauppauge Nova-T 500 (aka Bristol)
@@ -262,6 +264,11 @@ static struct mt2266_config stk7700d_mt2266_config[2] = {
static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
if (adap->id == 0) {
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(10);
@@ -272,16 +279,16 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
msleep(10);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
stk7700d_dib7000p_mt2266_config)
!= 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
}
- adap->fe_adap[0].fe =
- dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
0x80 + (adap->id << 1),
&stk7700d_dib7000p_mt2266_config[adap->id]);
@@ -290,6 +297,11 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap)
static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
if (adap->id == 0) {
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(10);
@@ -301,16 +313,16 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
stk7700d_dib7000p_mt2266_config)
!= 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
}
- adap->fe_adap[0].fe =
- dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
0x80 + (adap->id << 1),
&stk7700d_dib7000p_mt2266_config[adap->id]);
@@ -320,7 +332,10 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap)
static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
{
struct i2c_adapter *tun_i2c;
- tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ struct dib0700_adapter_state *state = adap->priv;
+
+ tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
+ DIBX000_I2C_INTERFACE_TUNER, 1);
return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c,
&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;
}
@@ -397,12 +412,14 @@ static int stk7700ph_xc3028_callback(void *ptr, int component,
int command, int arg)
{
struct dvb_usb_adapter *adap = ptr;
+ struct dib0700_adapter_state *state = adap->priv;
switch (command) {
case XC2028_TUNER_RESET:
/* Send the tuner in then out of reset */
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10);
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
+ msleep(10);
+ state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
break;
case XC2028_RESET_CLK:
break;
@@ -428,12 +445,16 @@ static struct xc2028_config stk7700ph_xc3028_config = {
static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
{
struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX))
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
else
- dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(20);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
@@ -445,14 +466,15 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
msleep(10);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
&stk7700ph_dib7700_xc3028_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
__func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
&stk7700ph_dib7700_xc3028_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
@@ -461,8 +483,9 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
{
struct i2c_adapter *tun_i2c;
+ struct dib0700_adapter_state *state = adap->priv;
- tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+ tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
DIBX000_I2C_INTERFACE_TUNER, 1);
stk7700ph_xc3028_config.i2c_adap = tun_i2c;
@@ -489,7 +512,8 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
{
u8 key[4];
- u32 keycode;
+ enum rc_type protocol;
+ u32 scancode;
u8 toggle;
int i;
struct dib0700_state *st = d->priv;
@@ -516,28 +540,29 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */
- d->last_event = 0;
switch (d->props.rc.core.protocol) {
case RC_BIT_NEC:
/* NEC protocol sends repeat code as 0 0 0 FF */
if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
- (key[3] == 0xff))
- keycode = d->last_event;
- else {
- keycode = key[3-2] << 8 | key[3-3];
- d->last_event = keycode;
+ (key[3] == 0xff)) {
+ rc_repeat(d->rc_dev);
+ return 0;
}
- rc_keydown(d->rc_dev, keycode, 0);
+ protocol = RC_TYPE_NEC;
+ scancode = RC_SCANCODE_NEC(key[3-2], key[3-3]);
+ toggle = 0;
break;
+
default:
/* RC-5 protocol changes toggle bit on new keypress */
- keycode = key[3-2] << 8 | key[3-3];
+ protocol = RC_TYPE_RC5;
+ scancode = RC_SCANCODE_RC5(key[3-2], key[3-3]);
toggle = key[3-1];
- rc_keydown(d->rc_dev, keycode, toggle);
-
break;
}
+
+ rc_keydown(d->rc_dev, protocol, scancode, toggle);
return 0;
}
@@ -673,6 +698,11 @@ static struct dib7000p_config stk7700p_dib7000p_config = {
static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
/* unless there is no real power management in DVB - we leave the device on GPIO6 */
dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
@@ -689,11 +719,13 @@ static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
st->mt2060_if1[0] = 1220;
- if (dib7000pc_detection(&adap->dev->i2c_adap)) {
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
+ if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap)) {
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config);
st->is_dib7000pc = 1;
- } else
+ } else {
+ memset(&state->dib7000p_ops, 0, sizeof(state->dib7000p_ops));
adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config);
+ }
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -707,14 +739,16 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap;
struct dib0700_state *st = adap->dev->priv;
struct i2c_adapter *tun_i2c;
+ struct dib0700_adapter_state *state = adap->priv;
s8 a;
int if1=1220;
+
if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) &&
adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) {
if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a;
}
if (st->is_dib7000pc)
- tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
else
tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
@@ -767,14 +801,20 @@ static struct dibx000_agc_config dib7070_agc_config = {
static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff)
{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
deb_info("reset: %d", onoff);
- return dib7000p_set_gpio(fe, 8, 0, !onoff);
+ return state->dib7000p_ops.set_gpio(fe, 8, 0, !onoff);
}
static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
deb_info("sleep: %d", onoff);
- return dib7000p_set_gpio(fe, 9, 0, onoff);
+ return state->dib7000p_ops.set_gpio(fe, 9, 0, onoff);
}
static struct dib0070_config dib7070p_dib0070_config[2] = {
@@ -818,7 +858,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe)
default: offset = 550; break;
}
deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
- dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+ state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
return state->set_param_save(fe);
}
@@ -832,39 +872,39 @@ static int dib7770_set_param_override(struct dvb_frontend *fe)
u8 band = BAND_OF_FREQUENCY(p->frequency/1000);
switch (band) {
case BAND_VHF:
- dib7000p_set_gpio(fe, 0, 0, 1);
+ state->dib7000p_ops.set_gpio(fe, 0, 0, 1);
offset = 850;
break;
case BAND_UHF:
default:
- dib7000p_set_gpio(fe, 0, 0, 0);
+ state->dib7000p_ops.set_gpio(fe, 0, 0, 0);
offset = 250;
break;
}
deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe));
- dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
+ state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe));
return state->set_param_save(fe);
}
static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap)
{
- struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+ struct dib0700_adapter_state *st = adap->priv;
+ struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
DIBX000_I2C_INTERFACE_TUNER, 1);
- if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
- &dib7770p_dib0070_config) == NULL)
- return -ENODEV;
+ if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c,
+ &dib7770p_dib0070_config) == NULL)
+ return -ENODEV;
- st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
- adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override;
- return 0;
+ st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
+ adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override;
+ return 0;
}
static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
if (adap->id == 0) {
if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL)
@@ -882,28 +922,33 @@ static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap)
static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index,
u16 pid, int onoff)
{
+ struct dib0700_adapter_state *state = adapter->priv;
struct dib0700_state *st = adapter->dev->priv;
+
if (st->is_dib7000pc)
- return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+ return state->dib7000p_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}
static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
{
struct dib0700_state *st = adapter->dev->priv;
+ struct dib0700_adapter_state *state = adapter->priv;
if (st->is_dib7000pc)
- return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+ return state->dib7000p_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}
static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
{
- return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+ struct dib0700_adapter_state *state = adapter->priv;
+ return state->dib7000p_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}
static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
{
- return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+ struct dib0700_adapter_state *state = adapter->priv;
+ return state->dib7000p_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}
static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = {
@@ -936,6 +981,11 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
@@ -954,14 +1004,15 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
&dib7070p_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
__func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
&dib7070p_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -988,6 +1039,11 @@ static struct dib7000p_config dib7770p_dib7000p_config = {
static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
@@ -1006,14 +1062,15 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
&dib7770p_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
__func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80,
&dib7770p_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -1161,12 +1218,18 @@ static struct dib8000_config dib807x_dib8000_config[2] = {
static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff)
{
- return dib8000_set_gpio(fe, 5, 0, !onoff);
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ return state->dib8000_ops.set_gpio(fe, 5, 0, !onoff);
}
static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff)
{
- return dib8000_set_gpio(fe, 0, 0, onoff);
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ return state->dib8000_ops.set_gpio(fe, 0, 0, onoff);
}
static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = {
@@ -1223,7 +1286,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe)
offset += 250; break;
}
deb_info("WBD for DiB8000: %d\n", offset);
- dib8000_set_wbd_ref(fe, offset);
+ state->dib8000_ops.set_wbd_ref(fe, offset);
return state->set_param_save(fe);
}
@@ -1231,7 +1294,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe)
static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe,
+ struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe,
DIBX000_I2C_INTERFACE_TUNER, 1);
if (adap->id == 0) {
@@ -1252,18 +1315,27 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
u16 pid, int onoff)
{
- return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
+ struct dib0700_adapter_state *state = adapter->priv;
+
+ return state->dib8000_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff);
}
static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
int onoff)
{
- return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
+ struct dib0700_adapter_state *state = adapter->priv;
+
+ return state->dib8000_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff);
}
/* STK807x */
static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(10);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -1279,10 +1351,10 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
0x80, 0);
- adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80,
&dib807x_dib8000_config[0]);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
@@ -1291,6 +1363,11 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap)
/* STK807xPVR */
static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
msleep(30);
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
@@ -1309,9 +1386,9 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
/* initialize IC 0 */
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0);
- adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80,
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80,
&dib807x_dib8000_config[0]);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
@@ -1319,10 +1396,15 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap)
static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
{
- /* initialize IC 1 */
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);
+ struct dib0700_adapter_state *state = adap->priv;
- adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82,
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
+
+ /* initialize IC 1 */
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0);
+
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82,
&dib807x_dib8000_config[1]);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
@@ -1331,104 +1413,121 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
/* STK8096GP */
static struct dibx000_agc_config dib8090_agc_config[2] = {
{
- BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
+ .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
* P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
* P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
- (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+ .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
- 787,
- 10,
+ .inv_gain = 787,
+ .time_stabiliz = 10,
- 0,
- 118,
+ .alpha_level = 0,
+ .thlock = 118,
- 0,
- 3530,
- 1,
- 5,
+ .wbd_inv = 0,
+ .wbd_ref = 3530,
+ .wbd_sel = 1,
+ .wbd_alpha = 5,
- 65535,
- 0,
+ .agc1_max = 65535,
+ .agc1_min = 0,
- 65535,
- 0,
+ .agc2_max = 65535,
+ .agc2_min = 0,
- 0,
- 32,
- 114,
- 143,
- 144,
- 114,
- 227,
- 116,
- 117,
+ .agc1_pt1 = 0,
+ .agc1_pt2 = 32,
+ .agc1_pt3 = 114,
+ .agc1_slope1 = 143,
+ .agc1_slope2 = 144,
+ .agc2_pt1 = 114,
+ .agc2_pt2 = 227,
+ .agc2_slope1 = 116,
+ .agc2_slope2 = 117,
- 28,
- 26,
- 31,
- 51,
+ .alpha_mant = 28,
+ .alpha_exp = 26,
+ .beta_mant = 31,
+ .beta_exp = 51,
- 0,
+ .perform_agc_softsplit = 0,
},
{
- BAND_CBAND,
+ .band_caps = BAND_CBAND,
/* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
* P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
* P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
- (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
+ .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
| (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
- 787,
- 10,
+ .inv_gain = 787,
+ .time_stabiliz = 10,
- 0,
- 118,
+ .alpha_level = 0,
+ .thlock = 118,
- 0,
- 3530,
- 1,
- 5,
+ .wbd_inv = 0,
+ .wbd_ref = 3530,
+ .wbd_sel = 1,
+ .wbd_alpha = 5,
- 0,
- 0,
+ .agc1_max = 0,
+ .agc1_min = 0,
- 65535,
- 0,
+ .agc2_max = 65535,
+ .agc2_min = 0,
- 0,
- 32,
- 114,
- 143,
- 144,
- 114,
- 227,
- 116,
- 117,
+ .agc1_pt1 = 0,
+ .agc1_pt2 = 32,
+ .agc1_pt3 = 114,
+ .agc1_slope1 = 143,
+ .agc1_slope2 = 144,
+ .agc2_pt1 = 114,
+ .agc2_pt2 = 227,
+ .agc2_slope1 = 116,
+ .agc2_slope2 = 117,
- 28,
- 26,
- 31,
- 51,
+ .alpha_mant = 28,
+ .alpha_exp = 26,
+ .beta_mant = 31,
+ .beta_exp = 51,
- 0,
+ .perform_agc_softsplit = 0,
}
};
static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
- 54000, 13500,
- 1, 18, 3, 1, 0,
- 0, 0, 1, 1, 2,
- (3 << 14) | (1 << 12) | (599 << 0),
- (0 << 25) | 0,
- 20199727,
- 12000000,
+ .internal = 54000,
+ .sampling = 13500,
+
+ .pll_prediv = 1,
+ .pll_ratio = 18,
+ .pll_range = 3,
+ .pll_reset = 1,
+ .pll_bypass = 0,
+
+ .enable_refdiv = 0,
+ .bypclk_div = 0,
+ .IO_CLK_en_core = 1,
+ .ADClkSrc = 1,
+ .modulo = 2,
+
+ .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0),
+
+ .ifreq = (0 << 25) | 0,
+ .timf = 20199727,
+
+ .xtal_hz = 12000000,
};
static int dib8090_get_adc_power(struct dvb_frontend *fe)
{
- return dib8000_get_adc_power(fe, 1);
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ return state->dib8000_ops.get_adc_power(fe, 1);
}
static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart)
@@ -1551,10 +1650,10 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
default:
deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency);
case BAND_VHF:
- dib8000_set_gpio(fe, 3, 0, 1);
+ state->dib8000_ops.set_gpio(fe, 3, 0, 1);
break;
case BAND_UHF:
- dib8000_set_gpio(fe, 3, 0, 0);
+ state->dib8000_ops.set_gpio(fe, 3, 0, 0);
break;
}
@@ -1568,7 +1667,7 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
}
/** Update PLL if needed ratio **/
- dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+ state->dib8000_ops.update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
/** Get optimize PLL ratio to remove spurious **/
pll_ratio = dib8090_compute_pll_parameters(fe);
@@ -1582,14 +1681,14 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
timf = 18179756;
/** Update ratio **/
- dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);
+ state->dib8000_ops.update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio);
- dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf);
+ state->dib8000_ops.ctrl_timf(fe, DEMOD_TIMF_SET, timf);
if (band != BAND_CBAND) {
/* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */
target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2;
- dib8000_set_wbd_ref(fe, target);
+ state->dib8000_ops.set_wbd_ref(fe, target);
}
if (band == BAND_CBAND) {
@@ -1601,18 +1700,18 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
msleep(ret);
tune_state = dib0090_get_tune_state(fe);
if (tune_state == CT_AGC_STEP_0)
- dib8000_set_gpio(fe, 6, 0, 1);
+ state->dib8000_ops.set_gpio(fe, 6, 0, 1);
else if (tune_state == CT_AGC_STEP_1) {
dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain);
if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */
- dib8000_set_gpio(fe, 6, 0, 0);
+ state->dib8000_ops.set_gpio(fe, 6, 0, 0);
}
} while (tune_state < CT_AGC_STOP);
deb_info("switching to PWM AGC\n");
dib0090_pwm_gain_reset(fe);
- dib8000_pwm_agc_reset(fe);
- dib8000_set_tune_state(fe, CT_DEMOD_START);
+ state->dib8000_ops.pwm_agc_reset(fe);
+ state->dib8000_ops.set_tune_state(fe, CT_DEMOD_START);
} else {
/* for everything else than CBAND we are using standard AGC */
deb_info("not tuning in CBAND - standard AGC startup\n");
@@ -1625,7 +1724,7 @@ static int dib8096_set_param_override(struct dvb_frontend *fe)
static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
return -ENODEV;
@@ -1637,6 +1736,11 @@ static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(10);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -1652,9 +1756,9 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0);
- adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -1663,16 +1767,16 @@ static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c;
- struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1);
+ struct dvb_frontend *fe_slave = st->dib8000_ops.get_slave_frontend(adap->fe_adap[0].fe, 1);
if (fe_slave) {
- tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
+ tun_i2c = st->dib8000_ops.get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
return -ENODEV;
fe_slave->dvb = adap->fe_adap[0].fe->dvb;
fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
}
- tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+ tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
return -ENODEV;
@@ -1685,6 +1789,10 @@ static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_frontend *fe_slave;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
msleep(20);
@@ -1703,14 +1811,18 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
msleep(20);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0);
- adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
if (adap->fe_adap[0].fe == NULL)
return -ENODEV;
- fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
- dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
+ /* Needed to increment refcount */
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
+
+ fe_slave = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
+ state->dib8000_ops.set_slave_frontend(adap->fe_adap[0].fe, fe_slave);
return fe_slave == NULL ? -ENODEV : 0;
}
@@ -1845,7 +1957,7 @@ static struct dib0090_wbd_slope dib8096p_wbd_table[] = {
{ 0xFFFF, 0, 0, 0, 0, 0},
};
-static const struct dib0090_config tfe8096p_dib0090_config = {
+static struct dib0090_config tfe8096p_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
.io.pll_range = 0,
@@ -1853,8 +1965,6 @@ static const struct dib0090_config tfe8096p_dib0090_config = {
.io.pll_loopdiv = 6,
.io.adc_clock_ratio = 0,
.io.pll_int_loop_filt = 0,
- .reset = dib8096p_tuner_sleep,
- .sleep = dib8096p_tuner_sleep,
.freq_offset_khz_uhf = -143,
.freq_offset_khz_vhf = -143,
@@ -1871,8 +1981,6 @@ static const struct dib0090_config tfe8096p_dib0090_config = {
.fref_clock_ratio = 1,
- .wbd = dib8096p_wbd_table,
-
.ls_cfg_pad_drv = 0,
.data_tx_drv = 0,
.low_if = NULL,
@@ -1983,15 +2091,15 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe)
/* dib0090_get_wbd_target is returning any possible
temperature compensated wbd-target */
target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
- dib8000_set_wbd_ref(fe, target);
+ state->dib8000_ops.set_wbd_ref(fe, target);
if (dib8096p_get_best_sampling(fe, &adc) == 0) {
pll.pll_ratio = adc.pll_loopdiv;
pll.pll_prediv = adc.pll_prediv;
dib0700_set_i2c_speed(adap->dev, 200);
- dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
- dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+ state->dib8000_ops.update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0);
+ state->dib8000_ops.ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
dib0700_set_i2c_speed(adap->dev, 1000);
}
return 0;
@@ -2001,6 +2109,10 @@ static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
u32 fw_version;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib8000_attach, &state->dib8000_ops))
+ return -ENODEV;
dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
if (fw_version >= 0x10200)
@@ -2021,10 +2133,10 @@ static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
msleep(20);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);
+ state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1);
- adap->fe_adap[0].fe = dvb_attach(dib8000_attach,
- &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config);
+ adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap,
+ 0x80, &tfe8096p_dib8000_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -2032,13 +2144,17 @@ static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap)
static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe);
+ struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_tuner(adap->fe_adap[0].fe);
+
+ tfe8096p_dib0090_config.reset = st->dib8000_ops.tuner_sleep;
+ tfe8096p_dib0090_config.sleep = st->dib8000_ops.tuner_sleep;
+ tfe8096p_dib0090_config.wbd = dib8096p_wbd_table;
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
&tfe8096p_dib0090_config) == NULL)
return -ENODEV;
- dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ st->dib8000_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup;
@@ -2479,14 +2595,14 @@ static int dib7090_agc_startup(struct dvb_frontend *fe)
memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
dib0090_pwm_gain_reset(fe);
target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2;
- dib7000p_set_wbd_ref(fe, target);
+ state->dib7000p_ops.set_wbd_ref(fe, target);
if (dib7090p_get_best_sampling(fe, &adc) == 0) {
pll.pll_ratio = adc.pll_loopdiv;
pll.pll_prediv = adc.pll_prediv;
- dib7000p_update_pll(fe, &pll);
- dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+ state->dib7000p_ops.update_pll(fe, &pll);
+ state->dib7000p_ops.ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
}
return 0;
}
@@ -2501,14 +2617,17 @@ static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart)
static int tfe7790p_update_lna(struct dvb_frontend *fe, u16 agc_global)
{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
deb_info("update LNA: agc global=%i", agc_global);
if (agc_global < 25000) {
- dib7000p_set_gpio(fe, 8, 0, 0);
- dib7000p_set_agc1_min(fe, 0);
+ state->dib7000p_ops.set_gpio(fe, 8, 0, 0);
+ state->dib7000p_ops.set_agc1_min(fe, 0);
} else {
- dib7000p_set_gpio(fe, 8, 0, 1);
- dib7000p_set_agc1_min(fe, 32768);
+ state->dib7000p_ops.set_gpio(fe, 8, 0, 1);
+ state->dib7000p_ops.set_agc1_min(fe, 32768);
}
return 0;
@@ -2644,13 +2763,16 @@ static struct dib7000p_config nim7090_dib7000p_config = {
static int tfe7090p_pvr_update_lna(struct dvb_frontend *fe, u16 agc_global)
{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
deb_info("TFE7090P-PVR update LNA: agc global=%i", agc_global);
if (agc_global < 25000) {
- dib7000p_set_gpio(fe, 5, 0, 0);
- dib7000p_set_agc1_min(fe, 0);
+ state->dib7000p_ops.set_gpio(fe, 5, 0, 0);
+ state->dib7000p_ops.set_agc1_min(fe, 0);
} else {
- dib7000p_set_gpio(fe, 5, 0, 1);
- dib7000p_set_agc1_min(fe, 32768);
+ state->dib7000p_ops.set_gpio(fe, 5, 0, 1);
+ state->dib7000p_ops.set_agc1_min(fe, 32768);
}
return 0;
@@ -2714,7 +2836,7 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
}
};
-static const struct dib0090_config nim7090_dib0090_config = {
+static struct dib0090_config nim7090_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
.io.pll_range = 0,
@@ -2722,14 +2844,10 @@ static const struct dib0090_config nim7090_dib0090_config = {
.io.pll_loopdiv = 6,
.io.adc_clock_ratio = 0,
.io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
.freq_offset_khz_uhf = 0,
.freq_offset_khz_vhf = 0,
- .get_adc_power = dib7090_get_adc_power,
-
.clkouttobamse = 1,
.analog_output = 0,
@@ -2776,7 +2894,7 @@ static struct dib7000p_config tfe7790p_dib7000p_config = {
.enMpegOutput = 1,
};
-static const struct dib0090_config tfe7790p_dib0090_config = {
+static struct dib0090_config tfe7790p_dib0090_config = {
.io.clock_khz = 12000,
.io.pll_bypass = 0,
.io.pll_range = 0,
@@ -2784,14 +2902,10 @@ static const struct dib0090_config tfe7790p_dib0090_config = {
.io.pll_loopdiv = 6,
.io.adc_clock_ratio = 0,
.io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
.freq_offset_khz_uhf = 0,
.freq_offset_khz_vhf = 0,
- .get_adc_power = dib7090_get_adc_power,
-
.clkouttobamse = 1,
.analog_output = 0,
@@ -2813,7 +2927,7 @@ static const struct dib0090_config tfe7790p_dib0090_config = {
.force_crystal_mode = 1,
};
-static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
+static struct dib0090_config tfe7090pvr_dib0090_config[2] = {
{
.io.clock_khz = 12000,
.io.pll_bypass = 0,
@@ -2822,14 +2936,10 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
.io.pll_loopdiv = 6,
.io.adc_clock_ratio = 0,
.io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
.freq_offset_khz_uhf = 50,
.freq_offset_khz_vhf = 70,
- .get_adc_power = dib7090_get_adc_power,
-
.clkouttobamse = 1,
.analog_output = 0,
@@ -2854,14 +2964,10 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
.io.pll_loopdiv = 6,
.io.adc_clock_ratio = 0,
.io.pll_int_loop_filt = 0,
- .reset = dib7090_tuner_sleep,
- .sleep = dib7090_tuner_sleep,
.freq_offset_khz_uhf = -50,
.freq_offset_khz_vhf = -70,
- .get_adc_power = dib7090_get_adc_power,
-
.clkouttobamse = 1,
.analog_output = 0,
@@ -2883,6 +2989,11 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
msleep(20);
dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
@@ -2895,11 +3006,12 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
msleep(20);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -2907,12 +3019,16 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+ struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe);
+
+ nim7090_dib0090_config.reset = st->dib7000p_ops.tuner_sleep,
+ nim7090_dib0090_config.sleep = st->dib7000p_ops.tuner_sleep,
+ nim7090_dib0090_config.get_adc_power = st->dib7000p_ops.get_adc_power;
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL)
return -ENODEV;
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
@@ -2922,6 +3038,10 @@ static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
/* The TFE7090 requires the dib0700 to not be in master mode */
st->disable_streaming_master_mode = 1;
@@ -2939,17 +3059,18 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
/* initialize IC 0 */
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
dib0700_set_i2c_speed(adap->dev, 340);
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
if (adap->fe_adap[0].fe == NULL)
return -ENODEV;
- dib7090_slave_reset(adap->fe_adap[0].fe);
+ state->dib7000p_ops.slave_reset(adap->fe_adap[0].fe);
return 0;
}
@@ -2957,19 +3078,24 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
{
struct i2c_adapter *i2c;
+ struct dib0700_adapter_state *state = adap->priv;
if (adap->dev->adapter[0].fe_adap[0].fe == NULL) {
err("the master dib7090 has to be initialized first");
return -ENODEV; /* the master device has not been initialized */
}
- i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
- if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__);
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
+ i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
+ if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
dib0700_set_i2c_speed(adap->dev, 200);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
@@ -2978,12 +3104,16 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+ struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe);
+
+ tfe7090pvr_dib0090_config[0].reset = st->dib7000p_ops.tuner_sleep;
+ tfe7090pvr_dib0090_config[0].sleep = st->dib7000p_ops.tuner_sleep;
+ tfe7090pvr_dib0090_config[0].get_adc_power = st->dib7000p_ops.get_adc_power;
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
return -ENODEV;
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
@@ -2993,12 +3123,16 @@ static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
- struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+ struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe);
+
+ tfe7090pvr_dib0090_config[1].reset = st->dib7000p_ops.tuner_sleep;
+ tfe7090pvr_dib0090_config[1].sleep = st->dib7000p_ops.tuner_sleep;
+ tfe7090pvr_dib0090_config[1].get_adc_power = st->dib7000p_ops.get_adc_power;
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
return -ENODEV;
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
@@ -3008,6 +3142,10 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
/* The TFE7790P requires the dib0700 to not be in master mode */
st->disable_streaming_master_mode = 1;
@@ -3024,13 +3162,14 @@ static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap)
msleep(20);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap,
1, 0x10, &tfe7790p_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
__func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap,
0x80, &tfe7790p_dib7000p_config);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
@@ -3040,13 +3179,18 @@ static int tfe7790p_tuner_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c =
- dib7090_get_i2c_tuner(adap->fe_adap[0].fe);
+ st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe);
+
+
+ tfe7790p_dib0090_config.reset = st->dib7000p_ops.tuner_sleep;
+ tfe7790p_dib0090_config.sleep = st->dib7000p_ops.tuner_sleep;
+ tfe7790p_dib0090_config.get_adc_power = st->dib7000p_ops.get_adc_power;
if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c,
&tfe7790p_dib0090_config) == NULL)
return -ENODEV;
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup;
@@ -3103,25 +3247,36 @@ static void stk7070pd_init(struct dvb_usb_device *dev)
static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap)
{
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
stk7070pd_init(adap->dev);
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18,
stk7070pd_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
__func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
{
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
+
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]);
return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
}
@@ -3164,6 +3319,10 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *dev = adap->dev;
struct dib0700_state *st = dev->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
if (adap->id == 0) {
stk7070pd_init(dev);
@@ -3173,15 +3332,16 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap)
dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0);
dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1);
- if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18,
+ if (state->dib7000p_ops.i2c_enumeration(&dev->i2c_adap, 2, 18,
stk7070pd_dib7000p_config) != 0) {
- err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n",
__func__);
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&dev->i2c_adap,
adap->id == 0 ? 0x80 : 0x82,
&stk7070pd_dib7000p_config[adap->id]);
@@ -3291,12 +3451,13 @@ static int dib0700_xc4000_tuner_callback(void *priv, int component,
int command, int arg)
{
struct dvb_usb_adapter *adap = priv;
+ struct dib0700_adapter_state *state = adap->priv;
if (command == XC4000_TUNER_RESET) {
/* Reset the tuner */
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
+ state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 0);
msleep(10);
- dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
+ state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1);
} else {
err("xc4000: unknown tuner callback command: %d\n", command);
return -EINVAL;
@@ -3374,6 +3535,10 @@ static struct dib7000p_config pctv_340e_config = {
static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib0700_state *st = adap->dev->priv;
+ struct dib0700_adapter_state *state = adap->priv;
+
+ if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops))
+ return -ENODEV;
/* Power Supply on */
dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
@@ -3397,12 +3562,13 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap)
msleep(500);
- if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
+ if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) {
/* Demodulator not found for some reason? */
+ dvb_detach(&state->dib7000p_ops);
return -ENODEV;
}
- adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12,
+ adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x12,
&pctv_340e_config);
st->is_dib7000pc = 1;
@@ -3420,9 +3586,10 @@ static struct xc4000_config dib7000p_xc4000_tunerconfig = {
static int xc4000_tuner_attach(struct dvb_usb_adapter *adap)
{
struct i2c_adapter *tun_i2c;
+ struct dib0700_adapter_state *state = adap->priv;
/* The xc4000 is not on the main i2c bus */
- tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe,
+ tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe,
DIBX000_I2C_INTERFACE_TUNER, 1);
if (tun_i2c == NULL) {
printk(KERN_ERR "Could not reach tuner i2c bus\n");
@@ -3636,6 +3803,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
}},
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
},
},
diff --git a/drivers/media/usb/dvb-usb/dibusb.h b/drivers/media/usb/dvb-usb/dibusb.h
index e47c321b3ffc..32ab1392313f 100644
--- a/drivers/media/usb/dvb-usb/dibusb.h
+++ b/drivers/media/usb/dvb-usb/dibusb.h
@@ -36,7 +36,7 @@
/*
* i2c read
- * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
+ * bulk write: 0x02 ((7bit i2c_addr << 1) | 0x01) register_bytes length_word
* bulk read: byte_buffer (length_word bytes)
*/
#define DIBUSB_REQ_I2C_READ 0x02
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-remote.c b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
index 4058aea9272f..7b5dae3077f6 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-remote.c
@@ -272,7 +272,7 @@ static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
dev->driver_name = d->props.rc.core.module_name;
dev->map_name = d->props.rc.core.rc_codes;
dev->change_protocol = d->props.rc.core.change_protocol;
- rc_set_allowed_protocols(dev, d->props.rc.core.allowed_protos);
+ dev->allowed_protocols = d->props.rc.core.allowed_protos;
dev->driver_type = d->props.rc.core.driver_type;
usb_to_input_id(d->udev, &dev->input_id);
dev->input_name = "IR-receiver inside an USB DVB receiver";
diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c
index ae0f56a32e4d..2add8c507ec9 100644
--- a/drivers/media/usb/dvb-usb/dw2102.c
+++ b/drivers/media/usb/dvb-usb/dw2102.c
@@ -1109,6 +1109,7 @@ static struct ds3000_config su3000_ds3000_config = {
static struct cxd2820r_config cxd2820r_config = {
.i2c_address = 0x6c, /* (0xd8 >> 1) */
.ts_mode = 0x38,
+ .ts_clock_inv = 1,
};
static struct tda18271_config tda18271_config = {
@@ -1387,20 +1388,27 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
static int t220_frontend_attach(struct dvb_usb_adapter *d)
{
- u8 obuf[3] = { 0xe, 0x80, 0 };
+ u8 obuf[3] = { 0xe, 0x87, 0 };
u8 ibuf[] = { 0 };
if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
err("command 0x0e transfer failed.");
obuf[0] = 0xe;
- obuf[1] = 0x83;
+ obuf[1] = 0x86;
+ obuf[2] = 1;
+
+ if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+ err("command 0x0e transfer failed.");
+
+ obuf[0] = 0xe;
+ obuf[1] = 0x80;
obuf[2] = 0;
if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
err("command 0x0e transfer failed.");
- msleep(100);
+ msleep(50);
obuf[0] = 0xe;
obuf[1] = 0x80;
@@ -1482,7 +1490,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d)
if (msg.buf[0] != 0xff) {
deb_rc("%s: rc code: %x, %x\n",
__func__, key[0], key[1]);
- rc_keydown(d->rc_dev, key[0], 1);
+ rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, key[0], 0);
}
}
@@ -1503,7 +1511,7 @@ static int prof_rc_query(struct dvb_usb_device *d)
if (msg.buf[0] != 0xff) {
deb_rc("%s: rc code: %x, %x\n",
__func__, key[0], key[1]);
- rc_keydown(d->rc_dev, key[0]^0xff, 1);
+ rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, key[0]^0xff, 0);
}
}
@@ -1524,7 +1532,8 @@ static int su3000_rc_query(struct dvb_usb_device *d)
if (msg.buf[0] != 0xff) {
deb_rc("%s: rc code: %x, %x\n",
__func__, key[0], key[1]);
- rc_keydown(d->rc_dev, key[1] << 8 | key[0], 1);
+ rc_keydown(d->rc_dev, RC_TYPE_RC5,
+ RC_SCANCODE_RC5(key[1], key[0]), 0);
}
}
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index 0306cb778df4..abf8ab2e02e5 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -245,7 +245,7 @@ static int m920x_rc_core_query(struct dvb_usb_device *d)
else if (state == REMOTE_KEY_REPEAT)
rc_repeat(d->rc_dev);
else
- rc_keydown(d->rc_dev, rc_state[1], 0);
+ rc_keydown(d->rc_dev, RC_TYPE_UNKNOWN, rc_state[1], 0);
out:
kfree(rc_state);
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index 449a99605a87..bdfe8963591c 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -565,12 +565,12 @@ static int pctv452e_rc_query(struct dvb_usb_device *d)
if ((rx[3] == 9) && (rx[12] & 0x01)) {
/* got a "press" event */
- state->last_rc_key = (rx[7] << 8) | rx[6];
+ state->last_rc_key = RC_SCANCODE_RC5(rx[7], rx[6]);
if (debug > 2)
info("%s: cmd=0x%02x sys=0x%02x\n",
__func__, rx[6], rx[7]);
- rc_keydown(d->rc_dev, state->last_rc_key, 0);
+ rc_keydown(d->rc_dev, RC_TYPE_RC5, state->last_rc_key, 0);
} else if (state->last_rc_key) {
rc_keyup(d->rc_dev);
state->last_rc_key = 0;
@@ -927,7 +927,7 @@ static struct dvb_usb_device_properties pctv452e_properties = {
.rc.core = {
.rc_codes = RC_MAP_DIB0700_RC5_TABLE,
- .allowed_protos = RC_BIT_UNKNOWN,
+ .allowed_protos = RC_BIT_RC5,
.rc_query = pctv452e_rc_query,
.rc_interval = 100,
},
@@ -980,7 +980,7 @@ static struct dvb_usb_device_properties tt_connect_s2_3600_properties = {
.rc.core = {
.rc_codes = RC_MAP_TT_1500,
- .allowed_protos = RC_BIT_UNKNOWN,
+ .allowed_protos = RC_BIT_RC5,
.rc_query = pctv452e_rc_query,
.rc_interval = 100,
},
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index d947e0379008..6b0b8b6b9e2a 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -710,7 +710,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = {
.isoc = {
.framesperurb = 32,
.framesize = 2048,
- .interval = 3,
+ .interval = 1,
}
}
},
diff --git a/drivers/media/usb/dvb-usb/ttusb2.c b/drivers/media/usb/dvb-usb/ttusb2.c
index 2ce3d19c58ef..f10717311e05 100644
--- a/drivers/media/usb/dvb-usb/ttusb2.c
+++ b/drivers/media/usb/dvb-usb/ttusb2.c
@@ -438,9 +438,9 @@ static int tt3650_rc_query(struct dvb_usb_device *d)
if (rx[8] & 0x01) {
/* got a "press" event */
- st->last_rc_key = (rx[3] << 8) | rx[2];
+ st->last_rc_key = RC_SCANCODE_RC5(rx[3], rx[2]);
deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
- rc_keydown(d->rc_dev, st->last_rc_key, rx[1]);
+ rc_keydown(d->rc_dev, RC_TYPE_RC5, st->last_rc_key, rx[1]);
} else if (st->last_rc_key) {
rc_keyup(d->rc_dev);
st->last_rc_key = 0;
@@ -747,7 +747,7 @@ static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
.rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */
.rc_codes = RC_MAP_TT_1500,
.rc_query = tt3650_rc_query,
- .allowed_protos = RC_BIT_UNKNOWN,
+ .allowed_protos = RC_BIT_RC5,
},
.num_adapters = 1,
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 12d4c0326e31..6d2ea9afd57b 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -366,7 +366,7 @@ int em28xx_init_camera(struct em28xx *dev)
v4l2->sensor_xtal = 4300000;
pdata.xtal = v4l2->sensor_xtal;
if (NULL ==
- v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
+ v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
&mt9v011_info, NULL)) {
ret = -ENODEV;
break;
@@ -423,7 +423,7 @@ int em28xx_init_camera(struct em28xx *dev)
v4l2->sensor_yres = 480;
subdev =
- v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
+ v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap,
&ov2640_info, NULL);
if (NULL == subdev) {
ret = -ENODEV;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 15ad47045553..a7e24848f6c8 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2280,6 +2280,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2875),
.driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2885), /* MSI Digivox Trio */
+ .driver_info = EM2884_BOARD_TERRATEC_H5 },
{ USB_DEVICE(0xeb1a, 0xe300),
.driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
{ USB_DEVICE(0xeb1a, 0xe303),
@@ -3522,7 +3524,6 @@ static struct usb_driver em28xx_usb_driver = {
.disconnect = em28xx_usb_disconnect,
.suspend = em28xx_usb_suspend,
.resume = em28xx_usb_resume,
- .reset_resume = em28xx_usb_resume,
.id_table = em28xx_id_table,
};
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index a121ed9561fd..3a3e243edf89 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1213,9 +1213,17 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0] = dvb_attach(lgdt3305_attach,
&em2870_lgdt3304_dev,
&dev->i2c_adap[dev->def_i2c_bus]);
- if (dvb->fe[0] != NULL)
- dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap[dev->def_i2c_bus], &kworld_a340_config);
+ if (!dvb->fe[0]) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ &kworld_a340_config)) {
+ dvb_frontend_detach(dvb->fe[0]);
+ result = -EINVAL;
+ goto out_free;
+ }
break;
case EM28174_BOARD_PCTV_290E:
/* set default GPIO0 for LNA, used if GPIOLIB is undefined */
@@ -1545,6 +1553,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->i2c_client_demod = client;
/* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
si2157_config.fe = dvb->fe[0];
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2157", I2C_NAME_SIZE);
@@ -1645,10 +1654,14 @@ static int em28xx_dvb_fini(struct em28xx *dev)
if (dev->disconnected) {
/* We cannot tell the device to sleep
* once it has been unplugged. */
- if (dvb->fe[0])
+ if (dvb->fe[0]) {
prevent_sleep(&dvb->fe[0]->ops);
- if (dvb->fe[1])
+ dvb->fe[0]->exit = DVB_FE_DEVICE_REMOVED;
+ }
+ if (dvb->fe[1]) {
prevent_sleep(&dvb->fe[1]->ops);
+ dvb->fe[1]->exit = DVB_FE_DEVICE_REMOVED;
+ }
}
/* remove I2C tuner */
@@ -1712,7 +1725,6 @@ static int em28xx_dvb_resume(struct em28xx *dev)
em28xx_info("Resuming DVB extension");
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
- struct i2c_client *client = dvb->i2c_client_tuner;
if (dvb->fe[0]) {
ret = dvb_frontend_resume(dvb->fe[0]);
@@ -1723,22 +1735,6 @@ static int em28xx_dvb_resume(struct em28xx *dev)
ret = dvb_frontend_resume(dvb->fe[1]);
em28xx_info("fe1 resume %d", ret);
}
- /* remove I2C tuner */
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
- /* remove I2C demod */
- client = dvb->i2c_client_demod;
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
- em28xx_unregister_dvb(dvb);
- kfree(dvb);
- dev->dvb = NULL;
}
return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index b58d4ebf6419..1048c1a23fb6 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -501,6 +501,12 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
int addr, rc, i;
u8 reg;
+ /* prevent i2c xfer attempts after device is disconnected
+ some fe's try to do i2c writes/reads from their release
+ interfaces when called in disconnect path */
+ if (dev->disconnected)
+ return -ENODEV;
+
rc = rt_mutex_trylock(&dev->i2c_bus_lock);
if (rc < 0)
return rc;
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 56ef49df4f8d..ed843bd221ea 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -27,6 +27,7 @@
#include
#include
#include
+#include
#include "em28xx.h"
@@ -53,6 +54,7 @@ struct em28xx_ir_poll_result {
unsigned int toggle_bit:1;
unsigned int read_count:7;
+ enum rc_type protocol;
u32 scancode;
};
@@ -72,7 +74,7 @@ struct em28xx_IR {
/* i2c slave address of external device (if used) */
u16 i2c_dev_addr;
- int (*get_key_i2c)(struct i2c_client *, u32 *);
+ int (*get_key_i2c)(struct i2c_client *ir, enum rc_type *protocol, u32 *scancode);
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
};
@@ -80,7 +82,8 @@ struct em28xx_IR {
I2C IR based get keycodes - should be used with ir-kbd-i2c
**********************************************************/
-static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
+static int em28xx_get_key_terratec(struct i2c_client *i2c_dev,
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char b;
@@ -98,14 +101,15 @@ static int em28xx_get_key_terratec(struct i2c_client *i2c_dev, u32 *ir_key)
/* keep old data */
return 1;
- *ir_key = b;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = b;
return 1;
}
-static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
+static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev,
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char buf[2];
- u16 code;
int size;
/* poll IR chip */
@@ -127,26 +131,13 @@ static int em28xx_get_key_em_haup(struct i2c_client *i2c_dev, u32 *ir_key)
* So, the code translation is not complete. Yet, it is enough to
* work with the provided RC5 IR.
*/
- code =
- ((buf[0] & 0x01) ? 0x0020 : 0) | /* 0010 0000 */
- ((buf[0] & 0x02) ? 0x0010 : 0) | /* 0001 0000 */
- ((buf[0] & 0x04) ? 0x0008 : 0) | /* 0000 1000 */
- ((buf[0] & 0x08) ? 0x0004 : 0) | /* 0000 0100 */
- ((buf[0] & 0x10) ? 0x0002 : 0) | /* 0000 0010 */
- ((buf[0] & 0x20) ? 0x0001 : 0) | /* 0000 0001 */
- ((buf[1] & 0x08) ? 0x1000 : 0) | /* 0001 0000 */
- ((buf[1] & 0x10) ? 0x0800 : 0) | /* 0000 1000 */
- ((buf[1] & 0x20) ? 0x0400 : 0) | /* 0000 0100 */
- ((buf[1] & 0x40) ? 0x0200 : 0) | /* 0000 0010 */
- ((buf[1] & 0x80) ? 0x0100 : 0); /* 0000 0001 */
-
- /* return key */
- *ir_key = code;
+ *protocol = RC_TYPE_RC5;
+ *scancode = (bitrev8(buf[1]) & 0x1f) << 8 | bitrev8(buf[0]) >> 2;
return 1;
}
static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
- u32 *ir_key)
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char buf[3];
@@ -158,13 +149,13 @@ static int em28xx_get_key_pinnacle_usb_grey(struct i2c_client *i2c_dev,
if (buf[0] != 0x00)
return 0;
- *ir_key = buf[2]&0x3f;
-
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = buf[2] & 0x3f;
return 1;
}
static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
- u32 *ir_key)
+ enum rc_type *protocol, u32 *scancode)
{
unsigned char subaddr, keydetect, key;
@@ -184,7 +175,8 @@ static int em28xx_get_key_winfast_usbii_deluxe(struct i2c_client *i2c_dev,
if (key == 0x00)
return 0;
- *ir_key = key;
+ *protocol = RC_TYPE_UNKNOWN;
+ *scancode = key;
return 1;
}
@@ -215,7 +207,22 @@ static int default_polling_getkey(struct em28xx_IR *ir,
poll_result->read_count = (msg[0] & 0x7f);
/* Remote Control Address/Data (Regs 0x46/0x47) */
- poll_result->scancode = msg[1] << 8 | msg[2];
+ switch (ir->rc_type) {
+ case RC_BIT_RC5:
+ poll_result->protocol = RC_TYPE_RC5;
+ poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
+ break;
+
+ case RC_BIT_NEC:
+ poll_result->protocol = RC_TYPE_NEC;
+ poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[2]);
+ break;
+
+ default:
+ poll_result->protocol = RC_TYPE_UNKNOWN;
+ poll_result->scancode = msg[1] << 8 | msg[2];
+ break;
+ }
return 0;
}
@@ -247,25 +254,32 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
*/
switch (ir->rc_type) {
case RC_BIT_RC5:
- poll_result->scancode = msg[1] << 8 | msg[2];
+ poll_result->protocol = RC_TYPE_RC5;
+ poll_result->scancode = RC_SCANCODE_RC5(msg[1], msg[2]);
break;
+
case RC_BIT_NEC:
- if ((msg[3] ^ msg[4]) != 0xff) /* 32 bits NEC */
- poll_result->scancode = (msg[1] << 24) |
- (msg[2] << 16) |
- (msg[3] << 8) |
- msg[4];
- else if ((msg[1] ^ msg[2]) != 0xff) /* 24 bits NEC */
- poll_result->scancode = (msg[1] << 16) |
- (msg[2] << 8) |
- msg[3];
- else /* Normal NEC */
- poll_result->scancode = msg[1] << 8 | msg[3];
- break;
- case RC_BIT_RC6_0:
+ poll_result->protocol = RC_TYPE_RC5;
poll_result->scancode = msg[1] << 8 | msg[2];
+ if ((msg[3] ^ msg[4]) != 0xff) /* 32 bits NEC */
+ poll_result->scancode = RC_SCANCODE_NEC32((msg[1] << 24) |
+ (msg[2] << 16) |
+ (msg[3] << 8) |
+ (msg[4]));
+ else if ((msg[1] ^ msg[2]) != 0xff) /* 24 bits NEC */
+ poll_result->scancode = RC_SCANCODE_NECX(msg[1] << 8 |
+ msg[2], msg[3]);
+ else /* Normal NEC */
+ poll_result->scancode = RC_SCANCODE_NEC(msg[1], msg[3]);
break;
+
+ case RC_BIT_RC6_0:
+ poll_result->protocol = RC_TYPE_RC6_0;
+ poll_result->scancode = RC_SCANCODE_RC6_0(msg[1], msg[2]);
+ break;
+
default:
+ poll_result->protocol = RC_TYPE_UNKNOWN;
poll_result->scancode = (msg[1] << 24) | (msg[2] << 16) |
(msg[3] << 8) | msg[4];
break;
@@ -281,22 +295,24 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
static int em28xx_i2c_ir_handle_key(struct em28xx_IR *ir)
{
struct em28xx *dev = ir->dev;
- static u32 ir_key;
+ static u32 scancode;
+ enum rc_type protocol;
int rc;
struct i2c_client client;
client.adapter = &ir->dev->i2c_adap[dev->def_i2c_bus];
client.addr = ir->i2c_dev_addr;
- rc = ir->get_key_i2c(&client, &ir_key);
+ rc = ir->get_key_i2c(&client, &protocol, &scancode);
if (rc < 0) {
dprintk("ir->get_key_i2c() failed: %d\n", rc);
return rc;
}
if (rc) {
- dprintk("%s: keycode = 0x%04x\n", __func__, ir_key);
- rc_keydown(ir->rc, ir_key, 0);
+ dprintk("%s: proto = 0x%04x, scancode = 0x%04x\n",
+ __func__, protocol, scancode);
+ rc_keydown(ir->rc, protocol, scancode, 0);
}
return 0;
}
@@ -319,10 +335,12 @@ static void em28xx_ir_handle_key(struct em28xx_IR *ir)
poll_result.scancode);
if (ir->full_code)
rc_keydown(ir->rc,
+ poll_result.protocol,
poll_result.scancode,
poll_result.toggle_bit);
else
rc_keydown(ir->rc,
+ RC_TYPE_UNKNOWN,
poll_result.scancode & 0xff,
poll_result.toggle_bit);
@@ -727,7 +745,7 @@ static int em28xx_ir_init(struct em28xx *dev)
case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2:
rc->map_name = RC_MAP_HAUPPAUGE;
ir->get_key_i2c = em28xx_get_key_em_haup;
- rc_set_allowed_protocols(rc, RC_BIT_RC5);
+ rc->allowed_protocols = RC_BIT_RC5;
break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
rc->map_name = RC_MAP_WINFAST_USBII_DELUXE;
@@ -743,7 +761,7 @@ static int em28xx_ir_init(struct em28xx *dev)
switch (dev->chip_id) {
case CHIP_ID_EM2860:
case CHIP_ID_EM2883:
- rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC);
+ rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC;
ir->get_key = default_polling_getkey;
break;
case CHIP_ID_EM2884:
@@ -751,8 +769,8 @@ static int em28xx_ir_init(struct em28xx *dev)
case CHIP_ID_EM28174:
case CHIP_ID_EM28178:
ir->get_key = em2874_polling_getkey;
- rc_set_allowed_protocols(rc, RC_BIT_RC5 | RC_BIT_NEC |
- RC_BIT_RC6_0);
+ rc->allowed_protocols = RC_BIT_RC5 | RC_BIT_NEC |
+ RC_BIT_RC6_0;
break;
default:
err = -ENODEV;
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index f6b49c98e2c9..90dec2955f1c 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1227,8 +1227,7 @@ static void scale_to_size(struct em28xx *dev,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
f->fmt.pix.width = v4l2->width;
@@ -1261,8 +1260,7 @@ static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned int width = f->fmt.pix.width;
unsigned int height = f->fmt.pix.height;
@@ -1355,8 +1353,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
*norm = dev->v4l2->norm;
@@ -1365,8 +1362,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, video, querystd, norm);
@@ -1375,8 +1371,7 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct v4l2_format f;
@@ -1408,8 +1403,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
int rc = 0;
@@ -1427,8 +1421,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev,
@@ -1450,8 +1443,7 @@ static const char *iname[] = {
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
unsigned int n;
n = i->index;
@@ -1479,8 +1471,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
*i = dev->ctl_input;
@@ -1489,8 +1480,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (i >= MAX_EM28XX_INPUT)
return -EINVAL;
@@ -1503,8 +1493,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
switch (a->index) {
case EM28XX_AMUX_VIDEO:
@@ -1543,8 +1532,7 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (a->index >= MAX_EM28XX_INPUT)
return -EINVAL;
@@ -1563,8 +1551,7 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
@@ -1578,8 +1565,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 em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
@@ -1591,8 +1577,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 em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
@@ -1606,8 +1591,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
struct v4l2_frequency new_freq = *f;
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
@@ -1624,8 +1608,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
static int vidioc_g_chip_info(struct file *file, void *priv,
struct v4l2_dbg_chip_info *chip)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
if (chip->match.addr > 1)
return -EINVAL;
@@ -1652,8 +1635,7 @@ static int em28xx_reg_len(int reg)
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
int ret;
if (reg->match.addr > 1)
@@ -1693,8 +1675,7 @@ static int vidioc_g_register(struct file *file, void *priv,
static int vidioc_s_register(struct file *file, void *priv,
const struct v4l2_dbg_register *reg)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
__le16 buf;
if (reg->match.addr > 1)
@@ -1715,8 +1696,7 @@ static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
@@ -1761,8 +1741,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_enum_framesizes(struct file *file, void *priv,
struct v4l2_frmsizeenum *fsize)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_fmt *fmt;
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
@@ -1806,8 +1785,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
format->fmt.vbi.samples_per_line = v4l2->vbi_width;
@@ -1840,7 +1818,7 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
static int radio_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+ struct em28xx *dev = video_drvdata(file);
if (unlikely(t->index > 0))
return -EINVAL;
@@ -1855,7 +1833,7 @@ static int radio_g_tuner(struct file *file, void *priv,
static int radio_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct em28xx *dev = ((struct em28xx_fh *)priv)->dev;
+ struct em28xx *dev = video_drvdata(file);
if (0 != t->index)
return -EINVAL;
@@ -1890,7 +1868,7 @@ static int em28xx_v4l2_open(struct file *filp)
struct em28xx *dev = video_drvdata(filp);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
enum v4l2_buf_type fh_type = 0;
- struct em28xx_fh *fh;
+ int ret;
switch (vdev->vfl_type) {
case VFL_TYPE_GRABBER:
@@ -1905,24 +1883,23 @@ static int em28xx_v4l2_open(struct file *filp)
return -EINVAL;
}
- em28xx_videodbg("open dev=%s type=%s users=%d\n",
- video_device_node_name(vdev), v4l2_type_names[fh_type],
- v4l2->users);
+ em28xx_videodbg("open dev=%s type=%s\n",
+ video_device_node_name(vdev), v4l2_type_names[fh_type]);
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
- if (!fh) {
- em28xx_errdev("em28xx-video.c: Out of memory?!\n");
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
- v4l2_fh_init(&fh->fh, vdev);
- fh->dev = dev;
- fh->type = fh_type;
- filp->private_data = fh;
- if (v4l2->users == 0) {
+ ret = v4l2_fh_open(filp);
+ if (ret) {
+ em28xx_errdev("%s: v4l2_fh_open() returned error %d\n",
+ __func__, ret);
+ mutex_unlock(&dev->lock);
+ return ret;
+ }
+
+ if (v4l2_fh_is_singular_file(filp)) {
+ em28xx_videodbg("first opened filehandle, initializing device\n");
+
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
if (vdev->vfl_type != VFL_TYPE_RADIO)
@@ -1933,6 +1910,8 @@ static int em28xx_v4l2_open(struct file *filp)
* of some i2c devices
*/
em28xx_wake_i2c(dev);
+ } else {
+ em28xx_videodbg("further filehandles are already opened\n");
}
if (vdev->vfl_type == VFL_TYPE_RADIO) {
@@ -1942,10 +1921,8 @@ static int em28xx_v4l2_open(struct file *filp)
kref_get(&dev->ref);
kref_get(&v4l2->ref);
- v4l2->users++;
mutex_unlock(&dev->lock);
- v4l2_fh_add(&fh->fh);
return 0;
}
@@ -2046,17 +2023,15 @@ static int em28xx_v4l2_resume(struct em28xx *dev)
*/
static int em28xx_v4l2_close(struct file *filp)
{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
+ struct em28xx *dev = video_drvdata(filp);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
int errCode;
- em28xx_videodbg("users=%d\n", v4l2->users);
-
- vb2_fop_release(filp);
mutex_lock(&dev->lock);
- if (v4l2->users == 1) {
+ if (v4l2_fh_is_singular_file(filp)) {
+ em28xx_videodbg("last opened filehandle, shutting down device\n");
+
/* No sense to try to write to the device */
if (dev->disconnected)
goto exit;
@@ -2075,10 +2050,12 @@ static int em28xx_v4l2_close(struct file *filp)
em28xx_errdev("cannot change alternate number to "
"0 (error=%i)\n", errCode);
}
+ } else {
+ em28xx_videodbg("further opened filehandles left\n");
}
exit:
- v4l2->users--;
+ vb2_fop_release(filp);
kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
kref_put(&dev->ref, em28xx_free_device);
@@ -2208,7 +2185,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
- set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
if (dev->board.is_webcam)
vfd->tvnorms = 0;
@@ -2552,7 +2528,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock;
/* disable inapplicable ioctls */
- v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_PARM);
if (dev->tuner_type == TUNER_ABSENT) {
v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER);
v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index b4c837d77e5d..84ef8efdb148 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -524,7 +524,6 @@ struct em28xx_v4l2 {
int sensor_yres;
int sensor_xtal;
- int users; /* user count for exclusive use */
int streaming_users; /* number of actively streaming users */
u32 frequency; /* selected tuner frequency */
@@ -576,13 +575,6 @@ struct em28xx_audio {
struct em28xx;
-struct em28xx_fh {
- struct v4l2_fh fh;
- struct em28xx *dev;
-
- enum v4l2_buf_type type;
-};
-
enum em28xx_i2c_algo_type {
EM28XX_I2C_ALGO_EM28XX = 0,
EM28XX_I2C_ALGO_EM2800,
diff --git a/drivers/staging/media/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig
similarity index 100%
rename from drivers/staging/media/go7007/Kconfig
rename to drivers/media/usb/go7007/Kconfig
diff --git a/drivers/staging/media/go7007/Makefile b/drivers/media/usb/go7007/Makefile
similarity index 68%
rename from drivers/staging/media/go7007/Makefile
rename to drivers/media/usb/go7007/Makefile
index 9c6ad4a263ec..e99287c3b828 100644
--- a/drivers/staging/media/go7007/Makefile
+++ b/drivers/media/usb/go7007/Makefile
@@ -8,8 +8,4 @@ go7007-y := go7007-v4l2.o go7007-driver.o go7007-i2c.o go7007-fw.o \
s2250-y := s2250-board.o
-# Uncomment when the saa7134 patches get into upstream
-#obj-$(CONFIG_VIDEO_SAA7134) += saa7134-go7007.o
-#ccflags-$(CONFIG_VIDEO_SAA7134:m=y) += -Idrivers/media/pci/saa7134
-
ccflags-$(CONFIG_VIDEO_GO7007_LOADER:m=y) += -Idrivers/media/common
diff --git a/drivers/staging/media/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c
similarity index 86%
rename from drivers/staging/media/go7007/go7007-driver.c
rename to drivers/media/usb/go7007/go7007-driver.c
index 6f1beca86b2b..95cffb771a62 100644
--- a/drivers/staging/media/go7007/go7007-driver.c
+++ b/drivers/media/usb/go7007/go7007-driver.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include
@@ -32,6 +28,7 @@
#include
#include
#include
+#include
#include "go7007-priv.h"
@@ -224,7 +221,7 @@ static int init_i2c_module(struct i2c_adapter *adapter, const struct go_i2c *con
return 0;
}
- printk(KERN_INFO "go7007: probing for module i2c:%s failed\n", i2c->type);
+ pr_info("go7007: probing for module i2c:%s failed\n", i2c->type);
return -EINVAL;
}
@@ -332,20 +329,33 @@ EXPORT_SYMBOL(go7007_register_encoder);
int go7007_start_encoder(struct go7007 *go)
{
u8 *fw;
- int fw_len, rv = 0, i;
+ int fw_len, rv = 0, i, x, y;
u16 intr_val, intr_data;
go->modet_enable = 0;
- if (!go->dvd_mode)
- for (i = 0; i < 4; ++i) {
- if (go->modet[i].enable) {
- go->modet_enable = 1;
- continue;
+ for (i = 0; i < 4; i++)
+ go->modet[i].enable = 0;
+
+ switch (v4l2_ctrl_g_ctrl(go->modet_mode)) {
+ case V4L2_DETECT_MD_MODE_GLOBAL:
+ memset(go->modet_map, 0, sizeof(go->modet_map));
+ go->modet[0].enable = 1;
+ go->modet_enable = 1;
+ break;
+ case V4L2_DETECT_MD_MODE_REGION_GRID:
+ for (y = 0; y < go->height / 16; y++) {
+ for (x = 0; x < go->width / 16; x++) {
+ int idx = y * go->width / 16 + x;
+
+ go->modet[go->modet_map[idx]].enable = 1;
}
- go->modet[i].pixel_threshold = 32767;
- go->modet[i].motion_threshold = 32767;
- go->modet[i].mb_threshold = 32767;
}
+ go->modet_enable = 1;
+ break;
+ }
+
+ if (go->dvd_mode)
+ go->modet_enable = 0;
if (go7007_construct_fw_image(go, &fw, &fw_len) < 0)
return -1;
@@ -383,44 +393,89 @@ static inline void store_byte(struct go7007_buffer *vb, u8 byte)
}
}
+static void go7007_set_motion_regions(struct go7007 *go, struct go7007_buffer *vb,
+ u32 motion_regions)
+{
+ if (motion_regions != go->modet_event_status) {
+ struct v4l2_event ev = {
+ .type = V4L2_EVENT_MOTION_DET,
+ .u.motion_det = {
+ .flags = V4L2_EVENT_MD_FL_HAVE_FRAME_SEQ,
+ .frame_sequence = vb->vb.v4l2_buf.sequence,
+ .region_mask = motion_regions,
+ },
+ };
+
+ v4l2_event_queue(&go->vdev, &ev);
+ go->modet_event_status = motion_regions;
+ }
+}
+
+/*
+ * Determine regions with motion and send a motion detection event
+ * in case of changes.
+ */
+static void go7007_motion_regions(struct go7007 *go, struct go7007_buffer *vb)
+{
+ u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
+ unsigned motion[4] = { 0, 0, 0, 0 };
+ u32 motion_regions = 0;
+ unsigned stride = (go->width + 7) >> 3;
+ unsigned x, y;
+ int i;
+
+ for (i = 0; i < 216; ++i)
+ store_byte(vb, go->active_map[i]);
+ for (y = 0; y < go->height / 16; y++) {
+ for (x = 0; x < go->width / 16; x++) {
+ if (!(go->active_map[y * stride + (x >> 3)] & (1 << (x & 7))))
+ continue;
+ motion[go->modet_map[y * (go->width / 16) + x]]++;
+ }
+ }
+ motion_regions = ((motion[0] > 0) << 0) |
+ ((motion[1] > 0) << 1) |
+ ((motion[2] > 0) << 2) |
+ ((motion[3] > 0) << 3);
+ *bytesused -= 216;
+ go7007_set_motion_regions(go, vb, motion_regions);
+}
+
/*
* Deliver the last video buffer and get a new one to start writing to.
*/
static struct go7007_buffer *frame_boundary(struct go7007 *go, struct go7007_buffer *vb)
{
- struct go7007_buffer *vb_tmp = NULL;
u32 *bytesused = &vb->vb.v4l2_planes[0].bytesused;
- int i;
+ struct go7007_buffer *vb_tmp = NULL;
- if (vb) {
- if (vb->modet_active) {
- if (*bytesused + 216 < GO7007_BUF_SIZE) {
- for (i = 0; i < 216; ++i)
- store_byte(vb, go->active_map[i]);
- *bytesused -= 216;
- } else
- vb->modet_active = 0;
- }
- vb->vb.v4l2_buf.sequence = go->next_seq++;
- v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp);
- vb_tmp = vb;
+ if (vb == NULL) {
spin_lock(&go->spinlock);
- list_del(&vb->list);
- if (list_empty(&go->vidq_active))
- vb = NULL;
- else
- vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list);
- go->active_buf = vb;
+ if (!list_empty(&go->vidq_active))
+ vb = go->active_buf =
+ list_first_entry(&go->vidq_active, struct go7007_buffer, list);
spin_unlock(&go->spinlock);
- vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE);
+ go->next_seq++;
return vb;
}
+
+ vb->vb.v4l2_buf.sequence = go->next_seq++;
+ if (vb->modet_active && *bytesused + 216 < GO7007_BUF_SIZE)
+ go7007_motion_regions(go, vb);
+ else
+ go7007_set_motion_regions(go, vb, 0);
+
+ v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp);
+ vb_tmp = vb;
spin_lock(&go->spinlock);
- if (!list_empty(&go->vidq_active))
- vb = go->active_buf =
- list_first_entry(&go->vidq_active, struct go7007_buffer, list);
+ list_del(&vb->list);
+ if (list_empty(&go->vidq_active))
+ vb = NULL;
+ else
+ vb = list_first_entry(&go->vidq_active, struct go7007_buffer, list);
+ go->active_buf = vb;
spin_unlock(&go->spinlock);
- go->next_seq++;
+ vb2_buffer_done(&vb_tmp->vb, VB2_BUF_STATE_DONE);
return vb;
}
diff --git a/drivers/staging/media/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c
similarity index 97%
rename from drivers/staging/media/go7007/go7007-fw.c
rename to drivers/media/usb/go7007/go7007-fw.c
index 814ce08bc44d..5f4c9b9e899a 100644
--- a/drivers/staging/media/go7007/go7007-fw.c
+++ b/drivers/media/usb/go7007/go7007-fw.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
/*
@@ -1432,22 +1428,26 @@ static int audio_to_package(struct go7007 *go, __le16 *code, int space)
static int modet_to_package(struct go7007 *go, __le16 *code, int space)
{
+ bool has_modet0 = go->modet[0].enable;
+ bool has_modet1 = go->modet[1].enable;
+ bool has_modet2 = go->modet[2].enable;
+ bool has_modet3 = go->modet[3].enable;
int ret, mb, i, addr, cnt = 0;
u16 pack[32];
u16 thresholds[] = {
0x200e, 0,
- 0xbf82, go->modet[0].pixel_threshold,
- 0xbf83, go->modet[1].pixel_threshold,
- 0xbf84, go->modet[2].pixel_threshold,
- 0xbf85, go->modet[3].pixel_threshold,
- 0xbf86, go->modet[0].motion_threshold,
- 0xbf87, go->modet[1].motion_threshold,
- 0xbf88, go->modet[2].motion_threshold,
- 0xbf89, go->modet[3].motion_threshold,
- 0xbf8a, go->modet[0].mb_threshold,
- 0xbf8b, go->modet[1].mb_threshold,
- 0xbf8c, go->modet[2].mb_threshold,
- 0xbf8d, go->modet[3].mb_threshold,
+ 0xbf82, has_modet0 ? go->modet[0].pixel_threshold : 32767,
+ 0xbf83, has_modet1 ? go->modet[1].pixel_threshold : 32767,
+ 0xbf84, has_modet2 ? go->modet[2].pixel_threshold : 32767,
+ 0xbf85, has_modet3 ? go->modet[3].pixel_threshold : 32767,
+ 0xbf86, has_modet0 ? go->modet[0].motion_threshold : 32767,
+ 0xbf87, has_modet1 ? go->modet[1].motion_threshold : 32767,
+ 0xbf88, has_modet2 ? go->modet[2].motion_threshold : 32767,
+ 0xbf89, has_modet3 ? go->modet[3].motion_threshold : 32767,
+ 0xbf8a, has_modet0 ? go->modet[0].mb_threshold : 32767,
+ 0xbf8b, has_modet1 ? go->modet[1].mb_threshold : 32767,
+ 0xbf8c, has_modet2 ? go->modet[2].mb_threshold : 32767,
+ 0xbf8d, has_modet3 ? go->modet[3].mb_threshold : 32767,
0xbf8e, 0,
0xbf8f, 0,
0, 0,
diff --git a/drivers/staging/media/go7007/go7007-i2c.c b/drivers/media/usb/go7007/go7007-i2c.c
similarity index 96%
rename from drivers/staging/media/go7007/go7007-i2c.c
rename to drivers/media/usb/go7007/go7007-i2c.c
index 4cf4c0d65085..55addfa855d4 100644
--- a/drivers/staging/media/go7007/go7007-i2c.c
+++ b/drivers/media/usb/go7007/go7007-i2c.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/go7007/go7007-loader.c b/drivers/media/usb/go7007/go7007-loader.c
similarity index 94%
rename from drivers/staging/media/go7007/go7007-loader.c
rename to drivers/media/usb/go7007/go7007-loader.c
index 491d0e697f5a..042f78a31283 100644
--- a/drivers/staging/media/go7007/go7007-loader.c
+++ b/drivers/media/usb/go7007/go7007-loader.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include
diff --git a/drivers/staging/media/go7007/go7007-priv.h b/drivers/media/usb/go7007/go7007-priv.h
similarity index 90%
rename from drivers/staging/media/go7007/go7007-priv.h
rename to drivers/media/usb/go7007/go7007-priv.h
index 6e16af720504..2251c3f99d1d 100644
--- a/drivers/staging/media/go7007/go7007-priv.h
+++ b/drivers/media/usb/go7007/go7007-priv.h
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
/*
@@ -75,6 +71,20 @@ struct go7007;
#define GO7007_AUDIO_I2S_MASTER (1<<16)
#define GO7007_AUDIO_OKI_MODE (1<<17)
+#define GO7007_CID_CUSTOM_BASE (V4L2_CID_DETECT_CLASS_BASE + 0x1000)
+#define V4L2_CID_PIXEL_THRESHOLD0 (GO7007_CID_CUSTOM_BASE+1)
+#define V4L2_CID_MOTION_THRESHOLD0 (GO7007_CID_CUSTOM_BASE+2)
+#define V4L2_CID_MB_THRESHOLD0 (GO7007_CID_CUSTOM_BASE+3)
+#define V4L2_CID_PIXEL_THRESHOLD1 (GO7007_CID_CUSTOM_BASE+4)
+#define V4L2_CID_MOTION_THRESHOLD1 (GO7007_CID_CUSTOM_BASE+5)
+#define V4L2_CID_MB_THRESHOLD1 (GO7007_CID_CUSTOM_BASE+6)
+#define V4L2_CID_PIXEL_THRESHOLD2 (GO7007_CID_CUSTOM_BASE+7)
+#define V4L2_CID_MOTION_THRESHOLD2 (GO7007_CID_CUSTOM_BASE+8)
+#define V4L2_CID_MB_THRESHOLD2 (GO7007_CID_CUSTOM_BASE+9)
+#define V4L2_CID_PIXEL_THRESHOLD3 (GO7007_CID_CUSTOM_BASE+10)
+#define V4L2_CID_MOTION_THRESHOLD3 (GO7007_CID_CUSTOM_BASE+11)
+#define V4L2_CID_MB_THRESHOLD3 (GO7007_CID_CUSTOM_BASE+12)
+
struct go7007_board_info {
unsigned int flags;
int hpi_buffer_cap;
@@ -168,6 +178,7 @@ struct go7007 {
struct v4l2_ctrl *mpeg_video_aspect_ratio;
struct v4l2_ctrl *mpeg_video_b_frames;
struct v4l2_ctrl *mpeg_video_rep_seqheader;
+ struct v4l2_ctrl *modet_mode;
enum { STATUS_INIT, STATUS_ONLINE, STATUS_SHUTDOWN } status;
spinlock_t spinlock;
struct mutex hw_lock;
@@ -216,6 +227,7 @@ struct go7007 {
} modet[4];
unsigned char modet_map[1624];
unsigned char active_map[216];
+ u32 modet_event_status;
/* Video streaming */
struct mutex queue_lock;
diff --git a/drivers/staging/media/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c
similarity index 99%
rename from drivers/staging/media/go7007/go7007-usb.c
rename to drivers/media/usb/go7007/go7007-usb.c
index 2f62be905cd1..ece27ece8115 100644
--- a/drivers/staging/media/go7007/go7007-usb.c
+++ b/drivers/media/usb/go7007/go7007-usb.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
similarity index 80%
rename from drivers/staging/media/go7007/go7007-v4l2.c
rename to drivers/media/usb/go7007/go7007-v4l2.c
index da7b5493e13e..ec799b4d88be 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include
@@ -36,7 +32,6 @@
#include
#include
-#include "go7007.h"
#include "go7007-priv.h"
#define call_all(dev, o, f, args...) \
@@ -189,7 +184,7 @@ static void set_formatting(struct go7007 *go)
static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
{
int sensor_height = 0, sensor_width = 0;
- int width, height, i;
+ int width, height;
if (fmt != NULL && !valid_pixelformat(fmt->fmt.pix.pixelformat))
return -EINVAL;
@@ -253,10 +248,6 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
go->height = height;
go->encoder_h_offset = go->board_info->sensor_h_offset;
go->encoder_v_offset = go->board_info->sensor_v_offset;
- for (i = 0; i < 4; ++i)
- go->modet[i].enable = 0;
- for (i = 0; i < 1624; ++i)
- go->modet_map[i] = 0;
if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
struct v4l2_mbus_framefmt mbus_fmt;
@@ -286,64 +277,6 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
return 0;
}
-#if 0
-static int clip_to_modet_map(struct go7007 *go, int region,
- struct v4l2_clip *clip_list)
-{
- struct v4l2_clip clip, *clip_ptr;
- int x, y, mbnum;
-
- /* Check if coordinates are OK and if any macroblocks are already
- * used by other regions (besides 0) */
- clip_ptr = clip_list;
- while (clip_ptr) {
- if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
- return -EFAULT;
- if (clip.c.left < 0 || (clip.c.left & 0xF) ||
- clip.c.width <= 0 || (clip.c.width & 0xF))
- return -EINVAL;
- if (clip.c.left + clip.c.width > go->width)
- return -EINVAL;
- if (clip.c.top < 0 || (clip.c.top & 0xF) ||
- clip.c.height <= 0 || (clip.c.height & 0xF))
- return -EINVAL;
- if (clip.c.top + clip.c.height > go->height)
- return -EINVAL;
- for (y = 0; y < clip.c.height; y += 16)
- for (x = 0; x < clip.c.width; x += 16) {
- mbnum = (go->width >> 4) *
- ((clip.c.top + y) >> 4) +
- ((clip.c.left + x) >> 4);
- if (go->modet_map[mbnum] != 0 &&
- go->modet_map[mbnum] != region)
- return -EBUSY;
- }
- clip_ptr = clip.next;
- }
-
- /* Clear old region macroblocks */
- for (mbnum = 0; mbnum < 1624; ++mbnum)
- if (go->modet_map[mbnum] == region)
- go->modet_map[mbnum] = 0;
-
- /* Claim macroblocks in this list */
- clip_ptr = clip_list;
- while (clip_ptr) {
- if (copy_from_user(&clip, clip_ptr, sizeof(clip)))
- return -EFAULT;
- for (y = 0; y < clip.c.height; y += 16)
- for (x = 0; x < clip.c.width; x += 16) {
- mbnum = (go->width >> 4) *
- ((clip.c.top + y) >> 4) +
- ((clip.c.left + x) >> 4);
- go->modet_map[mbnum] = region;
- }
- clip_ptr = clip.next;
- }
- return 0;
-}
-#endif
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -495,6 +428,7 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
mutex_lock(&go->hw_lock);
go->next_seq = 0;
go->active_buf = NULL;
+ go->modet_event_status = 0;
q->streaming = 1;
if (go7007_start_encoder(go) < 0)
ret = -EIO;
@@ -850,41 +784,76 @@ static int vidioc_log_status(struct file *file, void *priv)
return call_all(&go->v4l2_dev, core, log_status);
}
-/* FIXME:
- Those ioctls are private, and not needed, since several standard
- extended controls already provide streaming control.
- So, those ioctls should be converted into vidioc_g_ext_ctrls()
- and vidioc_s_ext_ctrls()
- */
+static int vidioc_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
-#if 0
- case GO7007IOC_S_MD_PARAMS:
- {
- struct go7007_md_params *mdp = arg;
-
- if (mdp->region > 3)
- return -EINVAL;
- if (mdp->trigger > 0) {
- go->modet[mdp->region].pixel_threshold =
- mdp->pixel_threshold >> 1;
- go->modet[mdp->region].motion_threshold =
- mdp->motion_threshold >> 1;
- go->modet[mdp->region].mb_threshold =
- mdp->trigger >> 1;
- go->modet[mdp->region].enable = 1;
- } else
- go->modet[mdp->region].enable = 0;
- /* fall-through */
+ switch (sub->type) {
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ case V4L2_EVENT_MOTION_DET:
+ /* Allow for up to 30 events (1 second for NTSC) to be
+ * stored. */
+ return v4l2_event_subscribe(fh, sub, 30, NULL);
}
- case GO7007IOC_S_MD_REGION:
- {
- struct go7007_md_region *region = arg;
+ return -EINVAL;
+}
- if (region->region < 1 || region->region > 3)
- return -EINVAL;
- return clip_to_modet_map(go, region->region, region->clips);
+
+static int go7007_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct go7007 *go =
+ container_of(ctrl->handler, struct go7007, hdl);
+ unsigned y;
+ u8 *mt;
+
+ switch (ctrl->id) {
+ case V4L2_CID_PIXEL_THRESHOLD0:
+ go->modet[0].pixel_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MOTION_THRESHOLD0:
+ go->modet[0].motion_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MB_THRESHOLD0:
+ go->modet[0].mb_threshold = ctrl->val;
+ break;
+ case V4L2_CID_PIXEL_THRESHOLD1:
+ go->modet[1].pixel_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MOTION_THRESHOLD1:
+ go->modet[1].motion_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MB_THRESHOLD1:
+ go->modet[1].mb_threshold = ctrl->val;
+ break;
+ case V4L2_CID_PIXEL_THRESHOLD2:
+ go->modet[2].pixel_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MOTION_THRESHOLD2:
+ go->modet[2].motion_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MB_THRESHOLD2:
+ go->modet[2].mb_threshold = ctrl->val;
+ break;
+ case V4L2_CID_PIXEL_THRESHOLD3:
+ go->modet[3].pixel_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MOTION_THRESHOLD3:
+ go->modet[3].motion_threshold = ctrl->val;
+ break;
+ case V4L2_CID_MB_THRESHOLD3:
+ go->modet[3].mb_threshold = ctrl->val;
+ break;
+ case V4L2_CID_DETECT_MD_REGION_GRID:
+ mt = go->modet_map;
+ for (y = 0; y < go->height / 16; y++, mt += go->width / 16)
+ memcpy(mt, ctrl->p_new.p_u8 + y * (720 / 16), go->width / 16);
+ break;
+ default:
+ return -EINVAL;
}
-#endif
+ return 0;
+}
static struct v4l2_file_operations go7007_fops = {
.owner = THIS_MODULE,
@@ -926,7 +895,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
.vidioc_log_status = vidioc_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_subscribe_event = vidioc_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -938,12 +907,144 @@ static struct video_device go7007_template = {
.tvnorms = V4L2_STD_ALL,
};
+static const struct v4l2_ctrl_ops go7007_ctrl_ops = {
+ .s_ctrl = go7007_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold0_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_PIXEL_THRESHOLD0,
+ .name = "Pixel Threshold Region 0",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 20,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold0_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MOTION_THRESHOLD0,
+ .name = "Motion Threshold Region 0",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 80,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold0_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MB_THRESHOLD0,
+ .name = "MB Threshold Region 0",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 200,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold1_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_PIXEL_THRESHOLD1,
+ .name = "Pixel Threshold Region 1",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 20,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold1_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MOTION_THRESHOLD1,
+ .name = "Motion Threshold Region 1",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 80,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold1_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MB_THRESHOLD1,
+ .name = "MB Threshold Region 1",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 200,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold2_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_PIXEL_THRESHOLD2,
+ .name = "Pixel Threshold Region 2",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 20,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold2_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MOTION_THRESHOLD2,
+ .name = "Motion Threshold Region 2",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 80,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold2_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MB_THRESHOLD2,
+ .name = "MB Threshold Region 2",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 200,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_pixel_threshold3_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_PIXEL_THRESHOLD3,
+ .name = "Pixel Threshold Region 3",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 20,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_motion_threshold3_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MOTION_THRESHOLD3,
+ .name = "Motion Threshold Region 3",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 80,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_threshold3_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_MB_THRESHOLD3,
+ .name = "MB Threshold Region 3",
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .def = 200,
+ .max = 32767,
+ .step = 1,
+};
+
+static const struct v4l2_ctrl_config go7007_mb_regions_ctrl = {
+ .ops = &go7007_ctrl_ops,
+ .id = V4L2_CID_DETECT_MD_REGION_GRID,
+ .dims = { 576 / 16, 720 / 16 },
+ .max = 3,
+ .step = 1,
+};
+
int go7007_v4l2_ctrl_init(struct go7007 *go)
{
struct v4l2_ctrl_handler *hdl = &go->hdl;
struct v4l2_ctrl *ctrl;
- v4l2_ctrl_handler_init(hdl, 13);
+ v4l2_ctrl_handler_init(hdl, 22);
go->mpeg_video_gop_size = v4l2_ctrl_new_std(hdl, NULL,
V4L2_CID_MPEG_VIDEO_GOP_SIZE, 0, 34, 1, 15);
go->mpeg_video_gop_closure = v4l2_ctrl_new_std(hdl, NULL,
@@ -968,6 +1069,24 @@ int go7007_v4l2_ctrl_init(struct go7007 *go)
V4L2_JPEG_ACTIVE_MARKER_DHT);
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold0_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold0_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold0_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold1_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold1_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold1_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold2_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold2_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold2_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_pixel_threshold3_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_motion_threshold3_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_mb_threshold3_ctrl, NULL);
+ v4l2_ctrl_new_custom(hdl, &go7007_mb_regions_ctrl, NULL);
+ go->modet_mode = v4l2_ctrl_new_std_menu(hdl, NULL,
+ V4L2_CID_DETECT_MD_MODE,
+ V4L2_DETECT_MD_MODE_REGION_GRID,
+ 1 << V4L2_DETECT_MD_MODE_THRESHOLD_GRID,
+ V4L2_DETECT_MD_MODE_DISABLED);
if (hdl->error) {
int rv = hdl->error;
@@ -1001,7 +1120,6 @@ int go7007_v4l2_init(struct go7007 *go)
*vdev = go7007_template;
vdev->lock = &go->serialize_lock;
vdev->queue = &go->vidq;
- set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
video_set_drvdata(vdev, go);
vdev->v4l2_dev = &go->v4l2_dev;
if (!v4l2_device_has_op(&go->v4l2_dev, video, querystd))
diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/media/usb/go7007/s2250-board.c
similarity index 98%
rename from drivers/staging/media/go7007/s2250-board.c
rename to drivers/media/usb/go7007/s2250-board.c
index eaa2b0990a1b..bb846680bcd4 100644
--- a/drivers/staging/media/go7007/s2250-board.c
+++ b/drivers/media/usb/go7007/s2250-board.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include
@@ -573,11 +569,12 @@ static int s2250_probe(struct i2c_client *client,
if (mutex_lock_interruptible(&usb->i2c_lock) == 0) {
data = kzalloc(16, GFP_KERNEL);
if (data != NULL) {
- int rc;
- rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
+ int rc = go7007_usb_vendor_request(go, 0x41, 0, 0,
data, 16, 1);
+
if (rc > 0) {
u8 mask;
+
data[0] = 0;
mask = 1<<5;
data[0] &= ~mask;
diff --git a/drivers/staging/media/go7007/snd-go7007.c b/drivers/media/usb/go7007/snd-go7007.c
similarity index 97%
rename from drivers/staging/media/go7007/snd-go7007.c
rename to drivers/media/usb/go7007/snd-go7007.c
index 9eb2a20ae40a..d22d7d574672 100644
--- a/drivers/staging/media/go7007/snd-go7007.c
+++ b/drivers/media/usb/go7007/snd-go7007.c
@@ -9,10 +9,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*/
#include