Opening and Closing DevicesFor compatibility reasons the character device file names
-recommended for V4L2 video capture, overlay, radio, teletext and raw
+recommended for V4L2 video capture, overlay, radio and raw
vbi capture devices did not change from those used by V4L. They are
listed in and below in .
+ The teletext devices (minor range 192-223) have been removed in
+V4L2 and no longer exist. There is no hardware available anymore for handling
+pure teletext. Instead raw or sliced VBI is used.
+
The V4L videodev module automatically
assigns minor numbers to drivers in load order, depending on the
registered device type. We recommend that V4L2 drivers by default
@@ -65,13 +69,6 @@ not compatible with V4L or V4L2. ,
/dev/radio6364-127
-
- Teletext decoder
- /dev/vtx,
-/dev/vtx0 to
-/dev/vtx31
- 192-223
- Raw VBI capture/dev/vbi,
@@ -2345,6 +2342,17 @@ more information.
+
+ V4L2 in Linux 2.6.37
+
+
+ Remove the vtx (videotext/teletext) API. This API was no longer
+used and no hardware exists to verify the API. Nor were any userspace applications found
+that used it. It was originally scheduled for removal in 2.6.35.
+
+
+
+ Relation of V4L2 to other Linux multimedia APIs
diff --git a/Documentation/DocBook/v4l/controls.xml b/Documentation/DocBook/v4l/controls.xml
index 8408caaee276..2fae3e87ce73 100644
--- a/Documentation/DocBook/v4l/controls.xml
+++ b/Documentation/DocBook/v4l/controls.xml
@@ -311,11 +311,18 @@ minimum value disables backlight compensation.
bits 8-15 Green color information, bits 16-23 Blue color
information and bits 24-31 must be zero.
+
+ V4L2_CID_ILLUMINATORS_1
+ V4L2_CID_ILLUMINATORS_2
+ boolean
+ Switch on or off the illuminator 1 or 2 of the device
+ (usually a microscope).
+ V4L2_CID_LASTP1End of the predefined control IDs (currently
-V4L2_CID_BG_COLOR + 1).
+V4L2_CID_ILLUMINATORS_2 + 1).
V4L2_CID_PRIVATE_BASE
@@ -357,9 +364,6 @@ enumerate_menu (void)
querymenu.index++) {
if (0 == ioctl (fd, &VIDIOC-QUERYMENU;, &querymenu)) {
printf (" %s\n", querymenu.name);
- } else {
- perror ("VIDIOC_QUERYMENU");
- exit (EXIT_FAILURE);
}
}
}
diff --git a/Documentation/DocBook/v4l/dev-rds.xml b/Documentation/DocBook/v4l/dev-rds.xml
index 0869d701b1e5..360d2737e649 100644
--- a/Documentation/DocBook/v4l/dev-rds.xml
+++ b/Documentation/DocBook/v4l/dev-rds.xml
@@ -3,15 +3,16 @@
The Radio Data System transmits supplementary
information in binary format, for example the station name or travel
information, on an inaudible audio subcarrier of a radio program. This
-interface is aimed at devices capable of receiving and decoding RDS
+interface is aimed at devices capable of receiving and/or transmitting RDS
information.For more information see the core RDS standard
and the RBDS standard .Note that the RBDS standard as is used in the USA is almost identical
-to the RDS standard. Any RDS decoder can also handle RBDS. Only some of the fields
-have slightly different meanings. See the RBDS standard for more information.
+to the RDS standard. Any RDS decoder/encoder can also handle RBDS. Only some of the
+fields have slightly different meanings. See the RBDS standard for more
+information.
The RBDS standard also specifies support for MMBS (Modified Mobile Search).
This is a proprietary format which seems to be discontinued. The RDS interface does not
@@ -21,16 +22,25 @@ be needed, then please contact the linux-media mailing list: &v4l-ml;.Querying Capabilities
- Devices supporting the RDS capturing API
-set the V4L2_CAP_RDS_CAPTURE flag in
+ Devices supporting the RDS capturing API set
+the V4L2_CAP_RDS_CAPTURE flag in
the capabilities field of &v4l2-capability;
-returned by the &VIDIOC-QUERYCAP; ioctl.
-Any tuner that supports RDS will set the
-V4L2_TUNER_CAP_RDS flag in the capability
-field of &v4l2-tuner;.
-Whether an RDS signal is present can be detected by looking at
-the rxsubchans field of &v4l2-tuner;: the
-V4L2_TUNER_SUB_RDS will be set if RDS data was detected.
+returned by the &VIDIOC-QUERYCAP; ioctl. Any tuner that supports RDS
+will set the V4L2_TUNER_CAP_RDS flag in
+the capability field of &v4l2-tuner;. If
+the driver only passes RDS blocks without interpreting the data
+the V4L2_TUNER_SUB_RDS_BLOCK_IO flag has to be
+set, see Reading RDS data.
+For future use the
+flag V4L2_TUNER_SUB_RDS_CONTROLS has also been
+defined. However, a driver for a radio tuner with this capability does
+not yet exist, so if you are planning to write such a driver you
+should discuss this on the linux-media mailing list: &v4l-ml;.
+
+ Whether an RDS signal is present can be detected by looking
+at the rxsubchans field of &v4l2-tuner;:
+the V4L2_TUNER_SUB_RDS will be set if RDS data
+was detected.Devices supporting the RDS output API
set the V4L2_CAP_RDS_OUTPUT flag in
@@ -40,16 +50,31 @@ Any modulator that supports RDS will set the
V4L2_TUNER_CAP_RDS flag in the capability
field of &v4l2-modulator;.
In order to enable the RDS transmission one must set the V4L2_TUNER_SUB_RDS
-bit in the txsubchans field of &v4l2-modulator;.
-
+bit in the txsubchans field of &v4l2-modulator;.
+If the driver only passes RDS blocks without interpreting the data
+the V4L2_TUNER_SUB_RDS_BLOCK_IO flag has to be set. If the
+tuner is capable of handling RDS entities like program identification codes and radio
+text, the flag V4L2_TUNER_SUB_RDS_CONTROLS should be set,
+see Writing RDS data and
+FM Transmitter Control Reference.
-
+ Reading RDS dataRDS data can be read from the radio device
-with the &func-read; function. The data is packed in groups of three bytes,
+with the &func-read; function. The data is packed in groups of three bytes.
+
+
+
+ Writing RDS data
+
+ RDS data can be written to the radio device
+with the &func-write; function. The data is packed in groups of three bytes,
as follows:
+
+
+
struct
v4l2_rds_data
@@ -111,48 +136,57 @@ as follows:
V4L2_RDS_BLOCK_MSK
+ 7Mask for bits 0-2 to get the block ID.V4L2_RDS_BLOCK_A
+ 0Block A.V4L2_RDS_BLOCK_B
+ 1Block B.V4L2_RDS_BLOCK_C
+ 2Block C.V4L2_RDS_BLOCK_D
+ 3Block D.V4L2_RDS_BLOCK_C_ALT
+ 4Block C'.V4L2_RDS_BLOCK_INVALID
+ read-only7An invalid block.V4L2_RDS_BLOCK_CORRECTED
+ read-only0x40A bit error was detected but corrected.V4L2_RDS_BLOCK_ERROR
+ read-only0x80
- An incorrectable error occurred.
+ An uncorrectable error occurred.
diff --git a/Documentation/DocBook/v4l/dev-teletext.xml b/Documentation/DocBook/v4l/dev-teletext.xml
index 76184e8ed618..414b1cfff9f4 100644
--- a/Documentation/DocBook/v4l/dev-teletext.xml
+++ b/Documentation/DocBook/v4l/dev-teletext.xml
@@ -1,35 +1,32 @@
Teletext Interface
- This interface aims at devices receiving and demodulating
+ This interface was aimed at devices receiving and demodulating
Teletext data [, ], evaluating the
Teletext packages and storing formatted pages in cache memory. Such
devices are usually implemented as microcontrollers with serial
-interface (I2C) and can be found on older
+interface (I2C) and could be found on old
TV cards, dedicated Teletext decoding cards and home-brew devices
connected to the PC parallel port.
- The Teletext API was designed by Martin Buck. It is defined in
+ The Teletext API was designed by Martin Buck. It was defined in
the kernel header file linux/videotext.h, the
specification is available from
ftp://ftp.gwdg.de/pub/linux/misc/videotext/. (Videotext is the name of
-the German public television Teletext service.) Conventional character
-device file names are /dev/vtx and
-/dev/vttuner, with device number 83, 0 and 83, 16
-respectively. A similar interface exists for the Philips SAA5249
-Teletext decoder [specification?] with character device file names
-/dev/tlkN, device number 102, N.
+the German public television Teletext service.)Eventually the Teletext API was integrated into the V4L API
with character device file names /dev/vtx0 to
/dev/vtx31, device major number 81, minor numbers
-192 to 223. For reference the V4L Teletext API specification is
-reproduced here in full: "Teletext interfaces talk the existing VTX
-API." Teletext devices with major number 83 and 102 will be removed in
-Linux 2.6.
+192 to 223.
- There are no plans to replace the Teletext API or to integrate
-it into V4L2. Please write to the linux-media mailing list: &v4l-ml;
-when the need arises.
+ However, teletext decoders were quickly replaced by more
+generic VBI demodulators and those dedicated teletext decoders no longer exist.
+For many years the vtx devices were still around, even though nobody used
+them. So the decision was made to finally remove support for the Teletext API in
+kernel 2.6.37.
+
+ Modern devices all use the raw or
+sliced VBI API.V4L2_PIX_FMT_BGR666'BGRH'
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb10.xml b/Documentation/DocBook/v4l/pixfmt-srggb10.xml
new file mode 100644
index 000000000000..7b274092e60c
--- /dev/null
+++ b/Documentation/DocBook/v4l/pixfmt-srggb10.xml
@@ -0,0 +1,90 @@
+
+
+ V4L2_PIX_FMT_SRGGB10 ('RG10'),
+ V4L2_PIX_FMT_SGRBG10 ('BA10'),
+ V4L2_PIX_FMT_SGBRG10 ('GB10'),
+ V4L2_PIX_FMT_SBGGR10 ('BG10'),
+
+ &manvol;
+
+
+ V4L2_PIX_FMT_SRGGB10
+ V4L2_PIX_FMT_SGRBG10
+ V4L2_PIX_FMT_SGBRG10
+ V4L2_PIX_FMT_SBGGR10
+ 10-bit Bayer formats expanded to 16 bits
+
+
+ Description
+
+ The following four pixel formats are raw sRGB / Bayer formats with
+10 bits per colour. Each colour component is stored in a 16-bit word, with 6
+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
+as GRGR... BGBG..., RGRG... GBGB..., etc. Below is an example of one of these
+formats
+
+
+ V4L2_PIX_FMT_SBGGR10 4 × 4
+pixel image
+
+
+ Byte Order.
+ Each cell is one byte, high 6 bits in high bytes are 0.
+
+
+
+
+
+ start + 0:
+ B00low
+ B00high
+ G01low
+ G01high
+ B02low
+ B02high
+ G03low
+ G03high
+
+
+ start + 8:
+ G10low
+ G10high
+ R11low
+ R11high
+ G12low
+ G12high
+ R13low
+ R13high
+
+
+ start + 16:
+ B20low
+ B20high
+ G21low
+ G21high
+ B22low
+ B22high
+ G23low
+ G23high
+
+
+ start + 24:
+ G30low
+ G30high
+ R31low
+ R31high
+ G32low
+ G32high
+ R33low
+ R33high
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/v4l/pixfmt-srggb8.xml b/Documentation/DocBook/v4l/pixfmt-srggb8.xml
new file mode 100644
index 000000000000..2570e3be3cf1
--- /dev/null
+++ b/Documentation/DocBook/v4l/pixfmt-srggb8.xml
@@ -0,0 +1,67 @@
+
+
+ V4L2_PIX_FMT_SRGGB8 ('RGGB')
+ &manvol;
+
+
+ V4L2_PIX_FMT_SRGGB8
+ Bayer RGB format
+
+
+ Description
+
+ This is commonly the native format of digital cameras,
+reflecting the arrangement of sensors on the CCD device. Only one red,
+green or blue value is given for each pixel. Missing components must
+be interpolated from neighbouring pixels. From left to right the first
+row consists of a red and green value, the second row of a green and
+blue value. This scheme repeats to the right and down for every two
+columns and rows.
+
+
+ V4L2_PIX_FMT_SRGGB8 4 × 4
+pixel image
+
+
+ Byte Order.
+ Each cell is one byte.
+
+
+
+
+
+ start + 0:
+ R00
+ G01
+ R02
+ G03
+
+
+ start + 4:
+ G10
+ B11
+ G12
+ B13
+
+
+ start + 8:
+ R20
+ G21
+ R22
+ G23
+
+
+ start + 12:
+ G30
+ B31
+ G32
+ B33
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/v4l/pixfmt-y10.xml b/Documentation/DocBook/v4l/pixfmt-y10.xml
new file mode 100644
index 000000000000..d065043db8d8
--- /dev/null
+++ b/Documentation/DocBook/v4l/pixfmt-y10.xml
@@ -0,0 +1,79 @@
+
+
+ V4L2_PIX_FMT_Y10 ('Y10 ')
+ &manvol;
+
+
+ V4L2_PIX_FMT_Y10
+ Grey-scale image
+
+
+ Description
+
+ This is a grey-scale image with a depth of 10 bits per pixel. Pixels
+are stored in 16-bit words with unused high bits padded with 0. The least
+significant byte is stored at lower memory addresses (little-endian).
+
+
+ V4L2_PIX_FMT_Y10 4 × 4
+pixel image
+
+
+ Byte Order.
+ Each cell is one byte.
+
+
+
+
+
+ start + 0:
+ Y'00low
+ Y'00high
+ Y'01low
+ Y'01high
+ Y'02low
+ Y'02high
+ Y'03low
+ Y'03high
+
+
+ start + 8:
+ Y'10low
+ Y'10high
+ Y'11low
+ Y'11high
+ Y'12low
+ Y'12high
+ Y'13low
+ Y'13high
+
+
+ start + 16:
+ Y'20low
+ Y'20high
+ Y'21low
+ Y'21high
+ Y'22low
+ Y'22high
+ Y'23low
+ Y'23high
+
+
+ start + 24:
+ Y'30low
+ Y'30high
+ Y'31low
+ Y'31high
+ Y'32low
+ Y'32high
+ Y'33low
+ Y'33high
+
+
+
+
+
+
+
+
+
diff --git a/Documentation/DocBook/v4l/pixfmt.xml b/Documentation/DocBook/v4l/pixfmt.xml
index c4ad0a8e42dc..d7c467187095 100644
--- a/Documentation/DocBook/v4l/pixfmt.xml
+++ b/Documentation/DocBook/v4l/pixfmt.xml
@@ -566,7 +566,9 @@ access the palette, this must be done with ioctls of the Linux framebuffer API.<
&sub-sbggr8;
&sub-sgbrg8;
&sub-sgrbg8;
+ &sub-srggb8;
&sub-sbggr16;
+ &sub-srggb10;
@@ -589,6 +591,7 @@ information.
&sub-packed-yuv;
&sub-grey;
+ &sub-y10;
&sub-y16;
&sub-yuyv;
&sub-uyvy;
@@ -685,6 +688,11 @@ http://www.ivtvdriver.org/The format is documented in the
kernel sources in the file Documentation/video4linux/cx2341x/README.hm12
+
+ V4L2_PIX_FMT_CPIA1
+ 'CPIA'
+ YUV format used by the gspca cpia1 driver.
+ V4L2_PIX_FMT_SPCA501'S501'
@@ -705,11 +713,6 @@ kernel sources in the file Documentation/video4linux/cx2341x/README.hm
'S561'Compressed GBRG Bayer format used by the gspca driver.
-
- V4L2_PIX_FMT_SGRBG10
- 'DA10'
- 10 bit raw Bayer, expanded to 16 bits.
- V4L2_PIX_FMT_SGRBG10DPCM8'DB10'
@@ -770,6 +773,11 @@ kernel sources in the file Documentation/video4linux/cx2341x/README.hm
'S920'YUV 4:2:0 format of the gspca sn9c20x driver.
+
+ V4L2_PIX_FMT_SN9C2028
+ 'SONX'
+ Compressed GBRG bayer format of the gspca sn9c2028 driver.
+ V4L2_PIX_FMT_STV0680'S680'
@@ -787,6 +795,20 @@ http://www.thedirks.org/winnov/
'TM60'Used by Trident tm6000
+
+ V4L2_PIX_FMT_CIT_YYVYUY
+ 'CITV'
+ Used by xirlink CIT, found at IBM webcams.
+ Uses one line of Y then 1 line of VYUY
+
+
+
+ V4L2_PIX_FMT_KONICA420
+ 'KONI'
+ Used by Konica webcams.
+ YUV420 planar in blocks of 256 pixels.
+
+ V4L2_PIX_FMT_YYUV'YYUV'
diff --git a/Documentation/DocBook/v4l/v4l2.xml b/Documentation/DocBook/v4l/v4l2.xml
index 7c3c098d5d08..839e93e875ae 100644
--- a/Documentation/DocBook/v4l/v4l2.xml
+++ b/Documentation/DocBook/v4l/v4l2.xml
@@ -99,6 +99,7 @@ Remote Controller chapter.
200720082009
+ 2010Bill Dirks, Michael H. Schimek, Hans Verkuil, Martin
Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab
@@ -110,9 +111,16 @@ Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab
+
+ 2.6.37
+ 2010-08-06
+ hv
+ Removed obsolete vtx (videotext) API.
+
+
2.6.332009-12-03
diff --git a/Documentation/DocBook/v4l/videodev2.h.xml b/Documentation/DocBook/v4l/videodev2.h.xml
index 865b06d9e679..325b23b6964c 100644
--- a/Documentation/DocBook/v4l/videodev2.h.xml
+++ b/Documentation/DocBook/v4l/videodev2.h.xml
@@ -154,23 +154,13 @@ enum v4l2_buf_type {
V4L2_BUF_TYPE_VBI_OUTPUT = 5,
V4L2_BUF_TYPE_SLICED_VBI_CAPTURE = 6,
V4L2_BUF_TYPE_SLICED_VBI_OUTPUT = 7,
-#if 1 /*KEEP*/
+#if 1
/* Experimental */
V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY = 8,
#endif
V4L2_BUF_TYPE_PRIVATE = 0x80,
};
-enum v4l2_ctrl_type {
- V4L2_CTRL_TYPE_INTEGER = 1,
- V4L2_CTRL_TYPE_BOOLEAN = 2,
- V4L2_CTRL_TYPE_MENU = 3,
- V4L2_CTRL_TYPE_BUTTON = 4,
- V4L2_CTRL_TYPE_INTEGER64 = 5,
- V4L2_CTRL_TYPE_CTRL_CLASS = 6,
- V4L2_CTRL_TYPE_STRING = 7,
-};
-
enum v4l2_tuner_type {
V4L2_TUNER_RADIO = 1,
V4L2_TUNER_ANALOG_TV = 2,
@@ -288,6 +278,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */
#define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */
#define V4L2_PIX_FMT_RGB565X v4l2_fourcc('R', 'G', 'B', 'R') /* 16 RGB-5-6-5 BE */
+#define V4L2_PIX_FMT_BGR666 v4l2_fourcc('B', 'G', 'R', 'H') /* 18 BGR-6-6-6 */
#define V4L2_PIX_FMT_BGR24 v4l2_fourcc('B', 'G', 'R', '3') /* 24 BGR-8-8-8 */
#define V4L2_PIX_FMT_RGB24 v4l2_fourcc('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */
@@ -295,6 +286,9 @@ struct v4l2_pix_format {
/* Grey formats */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G', 'R', 'E', 'Y') /* 8 Greyscale */
+#define V4L2_PIX_FMT_Y4 v4l2_fourcc('Y', '0', '4', ' ') /* 4 Greyscale */
+#define V4L2_PIX_FMT_Y6 v4l2_fourcc('Y', '0', '6', ' ') /* 6 Greyscale */
+#define V4L2_PIX_FMT_Y10 v4l2_fourcc('Y', '1', '0', ' ') /* 10 Greyscale */
#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y', '1', '6', ' ') /* 16 Greyscale */
/* Palette formats */
@@ -330,7 +324,11 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B', 'A', '8', '1') /* 8 BGBG.. GRGR.. */
#define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G', 'B', 'R', 'G') /* 8 GBGB.. RGRG.. */
#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') /* 8 GRGR.. BGBG.. */
-#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10bit raw bayer */
+#define V4L2_PIX_FMT_SRGGB8 v4l2_fourcc('R', 'G', 'G', 'B') /* 8 RGRG.. GBGB.. */
+#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0') /* 10 BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0') /* 10 GBGB.. RGRG.. */
+#define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0') /* 10 GRGR.. BGBG.. */
+#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0') /* 10 RGRG.. GBGB.. */
/* 10bit raw bayer DPCM compressed to 8 bits */
#define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
/*
@@ -346,6 +344,7 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M', 'P', 'E', 'G') /* MPEG-1/2/4 */
/* Vendor-specific formats */
+#define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W', 'N', 'V', 'A') /* Winnov hw compress */
#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S', '9', '1', '0') /* SN9C10x compression */
#define V4L2_PIX_FMT_SN9C20X_I420 v4l2_fourcc('S', '9', '2', '0') /* SN9C20x YUV 4:2:0 */
@@ -358,12 +357,15 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */
#define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */
#define V4L2_PIX_FMT_MR97310A v4l2_fourcc('M', '3', '1', '0') /* compressed BGGR bayer */
+#define V4L2_PIX_FMT_SN9C2028 v4l2_fourcc('S', 'O', 'N', 'X') /* compressed GBRG bayer */
#define V4L2_PIX_FMT_SQ905C v4l2_fourcc('9', '0', '5', 'C') /* compressed RGGB bayer */
#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */
#define V4L2_PIX_FMT_OV511 v4l2_fourcc('O', '5', '1', '1') /* ov511 JPEG */
#define V4L2_PIX_FMT_OV518 v4l2_fourcc('O', '5', '1', '8') /* ov518 JPEG */
-#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
#define V4L2_PIX_FMT_STV0680 v4l2_fourcc('S', '6', '8', '0') /* stv0680 bayer */
+#define V4L2_PIX_FMT_TM6000 v4l2_fourcc('T', 'M', '6', '0') /* tm5600/tm60x0 */
+#define V4L2_PIX_FMT_CIT_YYVYUY v4l2_fourcc('C', 'I', 'T', 'V') /* one line of Y then 1 line of VYUY */
+#define V4L2_PIX_FMT_KONICA420 v4l2_fourcc('K', 'O', 'N', 'I') /* YUV420 planar in blocks of 256 pixels */
/*
* F O R M A T E N U M E R A T I O N
@@ -380,7 +382,7 @@ struct v4l2_fmtdesc {
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
#define V4L2_FMT_FLAG_EMULATED 0x0002
-#if 1 /*KEEP*/
+#if 1
/* Experimental Frame Size and frame rate enumeration */
/*
* F R A M E S I Z E E N U M E R A T I O N
@@ -544,6 +546,8 @@ struct v4l2_buffer {
#define V4L2_BUF_FLAG_KEYFRAME 0x0008 /* Image is a keyframe (I-frame) */
#define V4L2_BUF_FLAG_PFRAME 0x0010 /* Image is a P-frame */
#define V4L2_BUF_FLAG_BFRAME 0x0020 /* Image is a B-frame */
+/* Buffer is ready, but the data contained within is corrupted. */
+#define V4L2_BUF_FLAG_ERROR 0x0040
#define V4L2_BUF_FLAG_TIMECODE 0x0100 /* timecode field is valid */
#define V4L2_BUF_FLAG_INPUT 0x0200 /* input field is valid */
@@ -934,6 +938,16 @@ struct v4l2_ext_controls {
#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+enum v4l2_ctrl_type {
+ V4L2_CTRL_TYPE_INTEGER = 1,
+ V4L2_CTRL_TYPE_BOOLEAN = 2,
+ V4L2_CTRL_TYPE_MENU = 3,
+ V4L2_CTRL_TYPE_BUTTON = 4,
+ V4L2_CTRL_TYPE_INTEGER64 = 5,
+ V4L2_CTRL_TYPE_CTRL_CLASS = 6,
+ V4L2_CTRL_TYPE_STRING = 7,
+};
+
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
struct v4l2_queryctrl {
__u32 id;
@@ -1018,21 +1032,27 @@ enum v4l2_colorfx {
V4L2_COLORFX_NONE = 0,
V4L2_COLORFX_BW = 1,
V4L2_COLORFX_SEPIA = 2,
- V4L2_COLORFX_NEGATIVE = 3,
- V4L2_COLORFX_EMBOSS = 4,
- V4L2_COLORFX_SKETCH = 5,
- V4L2_COLORFX_SKY_BLUE = 6,
+ V4L2_COLORFX_NEGATIVE = 3,
+ V4L2_COLORFX_EMBOSS = 4,
+ V4L2_COLORFX_SKETCH = 5,
+ V4L2_COLORFX_SKY_BLUE = 6,
V4L2_COLORFX_GRASS_GREEN = 7,
V4L2_COLORFX_SKIN_WHITEN = 8,
- V4L2_COLORFX_VIVID = 9.
+ V4L2_COLORFX_VIVID = 9,
};
#define V4L2_CID_AUTOBRIGHTNESS (V4L2_CID_BASE+32)
#define V4L2_CID_BAND_STOP_FILTER (V4L2_CID_BASE+33)
#define V4L2_CID_ROTATE (V4L2_CID_BASE+34)
#define V4L2_CID_BG_COLOR (V4L2_CID_BASE+35)
+
+#define V4L2_CID_CHROMA_GAIN (V4L2_CID_BASE+36)
+
+#define V4L2_CID_ILLUMINATORS_1 (V4L2_CID_BASE+37)
+#define V4L2_CID_ILLUMINATORS_2 (V4L2_CID_BASE+38)
+
/* last CID + 1 */
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+36)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+39)
/* MPEG-class control IDs defined by V4L2 */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1349,6 +1369,8 @@ struct v4l2_modulator {
#define V4L2_TUNER_CAP_SAP 0x0020
#define V4L2_TUNER_CAP_LANG1 0x0040
#define V4L2_TUNER_CAP_RDS 0x0080
+#define V4L2_TUNER_CAP_RDS_BLOCK_IO 0x0100
+#define V4L2_TUNER_CAP_RDS_CONTROLS 0x0200
/* Flags for the 'rxsubchans' field */
#define V4L2_TUNER_SUB_MONO 0x0001
@@ -1378,7 +1400,8 @@ struct v4l2_hw_freq_seek {
enum v4l2_tuner_type type;
__u32 seek_upward;
__u32 wrap_around;
- __u32 reserved[8];
+ __u32 spacing;
+ __u32 reserved[7];
};
/*
@@ -1433,7 +1456,7 @@ struct v4l2_audioout {
*
* NOTE: EXPERIMENTAL API
*/
-#if 1 /*KEEP*/
+#if 1
#define V4L2_ENC_IDX_FRAME_I (0)
#define V4L2_ENC_IDX_FRAME_P (1)
#define V4L2_ENC_IDX_FRAME_B (2)
@@ -1625,6 +1648,38 @@ struct v4l2_streamparm {
} parm;
};
+/*
+ * E V E N T S
+ */
+
+#define V4L2_EVENT_ALL 0
+#define V4L2_EVENT_VSYNC 1
+#define V4L2_EVENT_EOS 2
+#define V4L2_EVENT_PRIVATE_START 0x08000000
+
+/* Payload for V4L2_EVENT_VSYNC */
+struct v4l2_event_vsync {
+ /* Can be V4L2_FIELD_ANY, _NONE, _TOP or _BOTTOM */
+ __u8 field;
+} __attribute__ ((packed));
+
+struct v4l2_event {
+ __u32 type;
+ union {
+ struct v4l2_event_vsync vsync;
+ __u8 data[64];
+ } u;
+ __u32 pending;
+ __u32 sequence;
+ struct timespec timestamp;
+ __u32 reserved[9];
+};
+
+struct v4l2_event_subscription {
+ __u32 type;
+ __u32 reserved[7];
+};
+
/*
* A D V A N C E D D E B U G G I N G
*
@@ -1720,7 +1775,7 @@ struct v4l2_dbg_chip_ident {
#define VIDIOC_G_EXT_CTRLS _IOWR('V', 71, struct v4l2_ext_controls)
#define VIDIOC_S_EXT_CTRLS _IOWR('V', 72, struct v4l2_ext_controls)
#define VIDIOC_TRY_EXT_CTRLS _IOWR('V', 73, struct v4l2_ext_controls)
-#if 1 /*KEEP*/
+#if 1
#define VIDIOC_ENUM_FRAMESIZES _IOWR('V', 74, struct v4l2_frmsizeenum)
#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR('V', 75, struct v4l2_frmivalenum)
#define VIDIOC_G_ENC_INDEX _IOR('V', 76, struct v4l2_enc_idx)
@@ -1728,7 +1783,7 @@ struct v4l2_dbg_chip_ident {
#define VIDIOC_TRY_ENCODER_CMD _IOWR('V', 78, struct v4l2_encoder_cmd)
#endif
-#if 1 /*KEEP*/
+#if 1
/* Experimental, meant for debugging, testing and internal use.
Only implemented if CONFIG_VIDEO_ADV_DEBUG is defined.
You must be root to use these ioctls. Never use these in applications! */
@@ -1747,6 +1802,9 @@ struct v4l2_dbg_chip_ident {
#define VIDIOC_QUERY_DV_PRESET _IOR('V', 86, struct v4l2_dv_preset)
#define VIDIOC_S_DV_TIMINGS _IOWR('V', 87, struct v4l2_dv_timings)
#define VIDIOC_G_DV_TIMINGS _IOWR('V', 88, struct v4l2_dv_timings)
+#define VIDIOC_DQEVENT _IOR('V', 89, struct v4l2_event)
+#define VIDIOC_SUBSCRIBE_EVENT _IOW('V', 90, struct v4l2_event_subscription)
+#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 91, struct v4l2_event_subscription)
/* Reminder: when adding new ioctls please add support for them to
drivers/media/video/v4l2-compat-ioctl32.c as well! */
diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
index 3c6784e132f3..d733721a7519 100644
--- a/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
+++ b/Documentation/DocBook/v4l/vidioc-g-dv-preset.xml
@@ -16,8 +16,7 @@
int ioctlint fdint request
- &v4l2-dv-preset;
-*argp
+ struct v4l2_dv_preset *argp
diff --git a/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml b/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
index ecc19576bb8f..d5ec6abf0ce2 100644
--- a/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
+++ b/Documentation/DocBook/v4l/vidioc-g-dv-timings.xml
@@ -16,8 +16,7 @@
int ioctlint fdint request
- &v4l2-dv-timings;
-*argp
+ struct v4l2_dv_timings *argp
diff --git a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
index 402229ee06f6..d272f7ab91b8 100644
--- a/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
+++ b/Documentation/DocBook/v4l/vidioc-query-dv-preset.xml
@@ -16,7 +16,7 @@ input
int ioctlint fdint request
- &v4l2-dv-preset; *argp
+ struct v4l2_dv_preset *argp
diff --git a/Documentation/DocBook/v4l/vidioc-querycap.xml b/Documentation/DocBook/v4l/vidioc-querycap.xml
index 6ab7e25b31b6..d499da93a450 100644
--- a/Documentation/DocBook/v4l/vidioc-querycap.xml
+++ b/Documentation/DocBook/v4l/vidioc-querycap.xml
@@ -184,7 +184,7 @@ data.
V4L2_CAP_RDS_CAPTURE0x00000100
- The device supports the RDS interface.
+ The device supports the RDS capture interface.V4L2_CAP_VIDEO_OUTPUT_OVERLAY
@@ -205,6 +205,11 @@ driver capabilities.
The device supports the &VIDIOC-S-HW-FREQ-SEEK; ioctl for
hardware frequency seeking.
+
+ V4L2_CAP_RDS_OUTPUT
+ 0x00000800
+ The device supports the RDS output interface.
+ V4L2_CAP_TUNER0x00010000
diff --git a/Documentation/DocBook/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/v4l/vidioc-queryctrl.xml
index 8e0e055ac934..0d5e8283cf32 100644
--- a/Documentation/DocBook/v4l/vidioc-queryctrl.xml
+++ b/Documentation/DocBook/v4l/vidioc-queryctrl.xml
@@ -103,8 +103,12 @@ structure. The driver fills the rest of the structure or returns an
index is invalid. Menu items are enumerated
by calling VIDIOC_QUERYMENU with successive
index values from &v4l2-queryctrl;
-minimum (0) to
-maximum, inclusive.
+minimum to
+maximum, inclusive. Note that it is possible
+for VIDIOC_QUERYMENU to return an &EINVAL; for some
+indices between minimum and maximum.
+In that case that particular menu item is not supported by this driver. Also note that
+the minimum value is not necessarily 0.
See also the examples in .
@@ -139,7 +143,7 @@ string. This information is intended for the user.
minimumMinimum value, inclusive. This field gives a lower
bound for V4L2_CTRL_TYPE_INTEGER controls and the
-lowest valid index (always 0) for V4L2_CTRL_TYPE_MENU controls.
+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
@@ -279,7 +283,7 @@ values which are actually different on the hardware.V4L2_CTRL_TYPE_MENU
- 0
+ ≥ 01N-1The control has a menu of N choices. The names of
@@ -405,8 +409,10 @@ writing a value will cause the device to carry out a given action
EINVALThe &v4l2-queryctrl; id
-is invalid. The &v4l2-querymenu; id or
-index is invalid.
+is invalid. The &v4l2-querymenu; id is
+invalid or index is out of range (less than
+minimum or greater than maximum)
+or this particular menu item is not supported by the driver.
diff --git a/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml b/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml
index 14b3ec7ed75b..c30dcc4232c0 100644
--- a/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml
+++ b/Documentation/DocBook/v4l/vidioc-s-hw-freq-seek.xml
@@ -51,7 +51,8 @@
Start a hardware frequency seek from the current frequency.
To do this applications initialize the tuner,
-type, seek_upward and
+type, seek_upward,
+spacing and
wrap_around fields, and zero out the
reserved array of a &v4l2-hw-freq-seek; and
call the VIDIOC_S_HW_FREQ_SEEK ioctl with a pointer
@@ -89,7 +90,12 @@ field and the &v4l2-tuner; index field.__u32
- reserved[8]
+ spacing
+ If non-zero, defines the hardware seek resolution in Hz. The driver selects the nearest value that is supported by the device. If spacing is zero a reasonable default value is used.
+
+
+ __u32
+ reserved[7]Reserved for future extensions. Drivers and
applications must set the array to zero.
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 170cc1e7e135..eccffe715229 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -1496,9 +1496,6 @@ Your cooperation is appreciated.
64 = /dev/radio0 Radio device
...
127 = /dev/radio63 Radio device
- 192 = /dev/vtx0 Teletext device
- ...
- 223 = /dev/vtx31 Teletext device
224 = /dev/vbi0 Vertical blank interrupt
...
255 = /dev/vbi31 Vertical blank interrupt
diff --git a/Documentation/dvb/get_dvb_firmware b/Documentation/dvb/get_dvb_firmware
index 350959f4e41b..59690de8ebfe 100644
--- a/Documentation/dvb/get_dvb_firmware
+++ b/Documentation/dvb/get_dvb_firmware
@@ -26,7 +26,8 @@ use IO::Handle;
"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
"or51211", "or51132_qam", "or51132_vsb", "bluebird",
"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
- "af9015", "ngene", "az6027");
+ "af9015", "ngene", "az6027", "lme2510_lg", "lme2510c_s7395",
+ "lme2510c_s7395_old");
# Check args
syntax() if (scalar(@ARGV) != 1);
@@ -584,6 +585,49 @@ sub az6027{
$firmware;
}
+
+sub lme2510_lg {
+ my $sourcefile = "LMEBDA_DVBS.sys";
+ my $hash = "fc6017ad01e79890a97ec53bea157ed2";
+ my $outfile = "dvb-usb-lme2510-lg.fw";
+ my $hasho = "caa065d5fdbd2c09ad57b399bbf55cad";
+
+ checkstandard();
+
+ verify($sourcefile, $hash);
+ extract($sourcefile, 4168, 3841, $outfile);
+ verify($outfile, $hasho);
+ $outfile;
+}
+
+sub lme2510c_s7395 {
+ my $sourcefile = "US2A0D.sys";
+ my $hash = "b0155a8083fb822a3bd47bc360e74601";
+ my $outfile = "dvb-usb-lme2510c-s7395.fw";
+ my $hasho = "3a3cf1aeebd17b6ddc04cebe131e94cf";
+
+ checkstandard();
+
+ verify($sourcefile, $hash);
+ extract($sourcefile, 37248, 3720, $outfile);
+ verify($outfile, $hasho);
+ $outfile;
+}
+
+sub lme2510c_s7395_old {
+ my $sourcefile = "LMEBDA_DVBS7395C.sys";
+ my $hash = "7572ae0eb9cdf91baabd7c0ba9e09b31";
+ my $outfile = "dvb-usb-lme2510c-s7395.fw";
+ my $hasho = "90430c5b435eb5c6f88fd44a9d950674";
+
+ checkstandard();
+
+ verify($sourcefile, $hash);
+ extract($sourcefile, 4208, 3881, $outfile);
+ verify($outfile, $hasho);
+ $outfile;
+}
+
# ---------------------------------------------------------------
# Utilities
diff --git a/Documentation/dvb/lmedm04.txt b/Documentation/dvb/lmedm04.txt
new file mode 100644
index 000000000000..e175784b89bf
--- /dev/null
+++ b/Documentation/dvb/lmedm04.txt
@@ -0,0 +1,58 @@
+To extract firmware for the DM04/QQBOX you need to copy the
+following file(s) to this directory.
+
+for DM04+/QQBOX LME2510C (Sharp 7395 Tuner)
+-------------------------------------------
+
+The Sharp 7395 driver can be found in windows/system32/driver
+
+US2A0D.sys (dated 17 Mar 2009)
+
+
+and run
+./get_dvb_firmware lme2510c_s7395
+
+ will produce
+ dvb-usb-lme2510c-s7395.fw
+
+An alternative but older firmware can be found on the driver
+disk DVB-S_EN_3.5A in BDADriver/driver
+
+LMEBDA_DVBS7395C.sys (dated 18 Jan 2008)
+
+and run
+./get_dvb_firmware lme2510c_s7395_old
+
+ will produce
+ dvb-usb-lme2510c-s7395.fw
+
+--------------------------------------------------------------------
+
+The LG firmware can be found on the driver
+disk DM04+_5.1A[LG] in BDADriver/driver
+
+for DM04 LME2510 (LG Tuner)
+---------------------------
+
+LMEBDA_DVBS.sys (dated 13 Nov 2007)
+
+and run
+./get_dvb_firmware lme2510_lg
+
+ will produce
+ dvb-usb-lme2510-lg.fw
+
+
+Other LG firmware can be extracted manually from US280D.sys
+only found in windows/system32/driver.
+
+dd if=US280D.sys ibs=1 skip=42616 count=3668 of=dvb-usb-lme2510-lg.fw
+
+for DM04 LME2510C (LG Tuner)
+---------------------------
+
+dd if=US280D.sys ibs=1 skip=35200 count=3850 of=dvb-usb-lme2510c-lg.fw
+
+---------------------------------------------------------------------
+
+Copy the firmware file(s) to /lib/firmware
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index f3da8c0a3af2..d8f36f984faa 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -98,7 +98,7 @@ Who: Pavel Machek
---------------------------
What: Video4Linux API 1 ioctls and from Video devices.
-When: July 2009
+When: kernel 2.6.38
Files: include/linux/videodev.h
Check: include/linux/videodev.h
Why: V4L1 AP1 was replaced by V4L2 API during migration from 2.4 to 2.6
@@ -116,6 +116,21 @@ Who: Mauro Carvalho Chehab
---------------------------
+What: Video4Linux obsolete drivers using V4L1 API
+When: kernel 2.6.38
+Files: drivers/staging/cpia/* drivers/staging/stradis/*
+Check: drivers/staging/cpia/cpia.c drivers/staging/stradis/stradis.c
+Why: There are some drivers still using V4L1 API, despite all efforts we've done
+ to migrate. Those drivers are for obsolete hardware that the old maintainer
+ didn't care (or not have the hardware anymore), and that no other developer
+ could find any hardware to buy. They probably have no practical usage today,
+ and people with such old hardware could probably keep using an older version
+ of the kernel. Those drivers will be moved to staging on 2.6.37 and, if nobody
+ care enough to port and test them with V4L2 API, they'll be removed on 2.6.38.
+Who: Mauro Carvalho Chehab
+
+---------------------------
+
What: sys_sysctl
When: September 2010
Option: CONFIG_SYSCTL_SYSCALL
@@ -470,29 +485,6 @@ When: April 2011
Why: Superseded by xt_CT
Who: Netfilter developer team
----------------------------
-
-What: video4linux /dev/vtx teletext API support
-When: 2.6.35
-Files: drivers/media/video/saa5246a.c drivers/media/video/saa5249.c
- include/linux/videotext.h
-Why: The vtx device nodes have been superseded by vbi device nodes
- for many years. No applications exist that use the vtx support.
- Of the two i2c drivers that actually support this API the saa5249
- has been impossible to use for a year now and no known hardware
- that supports this device exists. The saa5246a is theoretically
- supported by the old mxb boards, but it never actually worked.
-
- In summary: there is no hardware that can use this API and there
- are no applications actually implementing this API.
-
- The vtx support still reserves minors 192-223 and we would really
- like to reuse those for upcoming new functionality. In the unlikely
- event that new hardware appears that wants to use the functionality
- provided by the vtx API, then that functionality should be build
- around the sliced VBI API instead.
-Who: Hans Verkuil
-
----------------------------
What: IRQF_DISABLED
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 33223ff121d8..10f5af8b73f7 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -278,7 +278,6 @@ Code Seq#(hex) Include File Comments
'z' 10-4F drivers/s390/crypto/zcrypt_api.h conflict!
0x80 00-1F linux/fb.h
-0x81 00-1F linux/videotext.h
0x88 00-3F media/ovcamchip.h
0x89 00-06 arch/x86/include/asm/sockios.h
0x89 0B-DF linux/sockios.h
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index f2510541373b..42517d9121de 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -83,3 +83,4 @@
82 -> WinFast DTV2000 H rev. J [107d:6f2b]
83 -> Prof 7301 DVB-S/S2 [b034:3034]
84 -> Samsung SMT 7020 DVB-S [18ac:dc00,18ac:dccd]
+ 85 -> Twinhan VP-1027 DVB-S [1822:0023]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index 5c568757c301..ac2616a62fc3 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -31,6 +31,7 @@
30 -> Videology 20K14XUSB USB2.0 (em2820/em2840)
31 -> Usbgear VD204v9 (em2821)
32 -> Supercomp USB 2.0 TV (em2821)
+ 33 -> Elgato Video Capture (em2860) [0fd9:0033]
34 -> Terratec Cinergy A Hybrid XS (em2860) [0ccd:004f]
35 -> Typhoon DVD Maker (em2860)
36 -> NetGMBH Cam (em2860)
@@ -45,7 +46,7 @@
45 -> Pinnacle PCTV DVB-T (em2870)
46 -> Compro, VideoMate U3 (em2870) [185b:2870]
47 -> KWorld DVB-T 305U (em2880) [eb1a:e305]
- 48 -> KWorld DVB-T 310U (em2880) [eb1a:e310]
+ 48 -> KWorld DVB-T 310U (em2880)
49 -> MSI DigiVox A/D (em2880) [eb1a:e310]
50 -> MSI DigiVox A/D II (em2880) [eb1a:e320]
51 -> Terratec Hybrid XS Secam (em2880) [0ccd:004c]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 4000c29fcfb6..8d9afc7d8014 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -126,7 +126,7 @@
125 -> Beholder BeholdTV 409 [0000:4090]
126 -> Beholder BeholdTV 505 FM [5ace:5050]
127 -> Beholder BeholdTV 507 FM / BeholdTV 509 FM [5ace:5070,5ace:5090]
-128 -> Beholder BeholdTV Columbus TVFM [0000:5201]
+128 -> Beholder BeholdTV Columbus TV/FM [0000:5201]
129 -> Beholder BeholdTV 607 FM [5ace:6070]
130 -> Beholder BeholdTV M6 [5ace:6190]
131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022]
diff --git a/Documentation/video4linux/bttv/MAKEDEV b/Documentation/video4linux/bttv/MAKEDEV
index 9d112f7fd5f7..093c0cd18042 100644
--- a/Documentation/video4linux/bttv/MAKEDEV
+++ b/Documentation/video4linux/bttv/MAKEDEV
@@ -19,7 +19,6 @@ function makedev () {
echo "*** new device names ***"
makedev video 0
makedev radio 64
-makedev vtx 192
makedev vbi 224
#echo "*** old device names (for compatibility only) ***"
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt
index 56ba7bba7168..6a562eeeb4cd 100644
--- a/Documentation/video4linux/gspca.txt
+++ b/Documentation/video4linux/gspca.txt
@@ -302,12 +302,14 @@ sonixj 0c45:60fb Surfer NoName
sonixj 0c45:60fc LG-LIC300
sonixj 0c45:60fe Microdia Audio
sonixj 0c45:6100 PC Camera (SN9C128)
+sonixj 0c45:6102 PC Camera (SN9C128)
sonixj 0c45:610a PC Camera (SN9C128)
sonixj 0c45:610b PC Camera (SN9C128)
sonixj 0c45:610c PC Camera (SN9C128)
sonixj 0c45:610e PC Camera (SN9C128)
sonixj 0c45:6128 Microdia/Sonix SNP325
sonixj 0c45:612a Avant Camera
+sonixj 0c45:612b Speed-Link REFLECT2
sonixj 0c45:612c Typhoon Rasy Cam 1.3MPix
sonixj 0c45:6130 Sonix Pccam
sonixj 0c45:6138 Sn9c120 Mo4000
diff --git a/Documentation/video4linux/v4l2-framework.txt b/Documentation/video4linux/v4l2-framework.txt
index e831aaca66f8..f22f35c271f3 100644
--- a/Documentation/video4linux/v4l2-framework.txt
+++ b/Documentation/video4linux/v4l2-framework.txt
@@ -44,8 +44,8 @@ All drivers have the following structure:
2) A way of initializing and commanding sub-devices (if any).
-3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX, /dev/radioX and
- /dev/vtxX) and keeping track of device-node specific data.
+3) Creating V4L2 device nodes (/dev/videoX, /dev/vbiX and /dev/radioX)
+ and keeping track of device-node specific data.
4) Filehandle-specific structs containing per-filehandle data;
@@ -192,6 +192,11 @@ You also need a way to go from the low-level struct to v4l2_subdev. For the
common i2c_client struct the i2c_set_clientdata() call is used to store a
v4l2_subdev pointer, for other busses you may have to use other methods.
+Bridges might also need to store per-subdev private data, such as a pointer to
+bridge-specific per-subdev private data. The v4l2_subdev structure provides
+host private data for that purpose that can be accessed with
+v4l2_get_subdev_hostdata() and v4l2_set_subdev_hostdata().
+
From the bridge driver perspective you load the sub-device module and somehow
obtain the v4l2_subdev pointer. For i2c devices this is easy: you call
i2c_get_clientdata(). For other busses something similar needs to be done.
@@ -448,6 +453,10 @@ You should also set these fields:
- ioctl_ops: if you use the v4l2_ioctl_ops to simplify ioctl maintenance
(highly recommended to use this and it might become compulsory in the
future!), then set this to your v4l2_ioctl_ops struct.
+- lock: leave to NULL if you want to do all the locking in the driver.
+ Otherwise you give it a pointer to a struct mutex_lock and before any
+ of the v4l2_file_operations is called this lock will be taken by the
+ core and released afterwards.
- parent: you only set this if v4l2_device was registered with NULL as
the parent device struct. This only happens in cases where one hardware
device has multiple PCI devices that all share the same v4l2_device core.
@@ -464,6 +473,22 @@ If you use v4l2_ioctl_ops, then you should set either .unlocked_ioctl or
The v4l2_file_operations struct is a subset of file_operations. The main
difference is that the inode argument is omitted since it is never used.
+v4l2_file_operations and locking
+--------------------------------
+
+You can set a pointer to a mutex_lock in struct video_device. Usually this
+will be either a top-level mutex or a mutex per device node. If you want
+finer-grained locking then you have to set it to NULL and do you own locking.
+
+If a lock is specified then all file operations will be serialized on that
+lock. If you use videobuf then you must pass the same lock to the videobuf
+queue initialize function: if videobuf has to wait for a frame to arrive, then
+it will temporarily unlock the lock and relock it afterwards. If your driver
+also waits in the code, then you should do the same to allow other processes
+to access the device node while the first process is waiting for something.
+
+The implementation of a hotplug disconnect should also take the lock before
+calling v4l2_device_disconnect.
video_device registration
-------------------------
@@ -483,7 +508,6 @@ types exist:
VFL_TYPE_GRABBER: videoX for video input/output devices
VFL_TYPE_VBI: vbiX for vertical blank data (i.e. closed captions, teletext)
VFL_TYPE_RADIO: radioX for radio tuners
-VFL_TYPE_VTX: vtxX for teletext devices (deprecated, don't use)
The last argument gives you a certain amount of control over the device
device node number used (i.e. the X in videoX). Normally you will pass -1
@@ -547,9 +571,8 @@ from /dev).
After video_unregister_device() returns no new opens can be done. However,
in the case of USB devices some application might still have one of these
-device nodes open. So after the unregister all file operations will return
-an error as well, except for the ioctl and unlocked_ioctl file operations:
-those will still be passed on since some buffer ioctls may still be needed.
+device nodes open. So after the unregister all file operations (except
+release, of course) will return an error as well.
When the last user of the video device node exits, then the vdev->release()
callback is called and you can do the final cleanup there.
diff --git a/arch/arm/mach-mx3/mach-pcm037.c b/arch/arm/mach-mx3/mach-pcm037.c
index 86e86c1300d5..2ff3f661a48e 100644
--- a/arch/arm/mach-mx3/mach-pcm037.c
+++ b/arch/arm/mach-mx3/mach-pcm037.c
@@ -311,7 +311,6 @@ static struct soc_camera_link iclink_mt9v022 = {
.bus_id = 0, /* Must match with the camera ID */
.board_info = &pcm037_i2c_camera[1],
.i2c_adapter_id = 2,
- .module_name = "mt9v022",
};
static struct soc_camera_link iclink_mt9t031 = {
@@ -319,7 +318,6 @@ static struct soc_camera_link iclink_mt9t031 = {
.power = pcm037_camera_power,
.board_info = &pcm037_i2c_camera[0],
.i2c_adapter_id = 2,
- .module_name = "mt9t031",
};
static struct i2c_board_info pcm037_i2c_devices[] = {
diff --git a/arch/arm/mach-mx3/mx31moboard-marxbot.c b/arch/arm/mach-mx3/mx31moboard-marxbot.c
index 0551eb39d97e..18069cb7d068 100644
--- a/arch/arm/mach-mx3/mx31moboard-marxbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-marxbot.c
@@ -179,7 +179,6 @@ static struct soc_camera_link base_iclink = {
.reset = marxbot_basecam_reset,
.board_info = &marxbot_i2c_devices[0],
.i2c_adapter_id = 0,
- .module_name = "mt9t031",
};
static struct platform_device marxbot_camera[] = {
diff --git a/arch/arm/mach-mx3/mx31moboard-smartbot.c b/arch/arm/mach-mx3/mx31moboard-smartbot.c
index 417757e78c65..04760a53005a 100644
--- a/arch/arm/mach-mx3/mx31moboard-smartbot.c
+++ b/arch/arm/mach-mx3/mx31moboard-smartbot.c
@@ -88,7 +88,6 @@ static struct soc_camera_link base_iclink = {
.reset = smartbot_cam_reset,
.board_info = &smartbot_i2c_devices[0],
.i2c_adapter_id = 0,
- .module_name = "mt9t031",
};
static struct platform_device smartbot_camera[] = {
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index ab48bb81b570..ed0dbfdb22ed 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -1015,7 +1015,6 @@ static struct soc_camera_link iclink = {
.power = em_x270_sensor_power,
.board_info = &em_x270_i2c_cam_info[0],
.i2c_adapter_id = 0,
- .module_name = "mt9m111",
};
static struct platform_device em_x270_camera = {
diff --git a/arch/arm/mach-pxa/ezx.c b/arch/arm/mach-pxa/ezx.c
index 80a9352d43f3..142c711f4cda 100644
--- a/arch/arm/mach-pxa/ezx.c
+++ b/arch/arm/mach-pxa/ezx.c
@@ -755,7 +755,6 @@ static struct soc_camera_link a780_iclink = {
.flags = SOCAM_SENSOR_INVERT_PCLK,
.i2c_adapter_id = 0,
.board_info = &a780_camera_i2c_board_info,
- .module_name = "mt9m111",
.power = a780_camera_power,
.reset = a780_camera_reset,
};
@@ -1024,7 +1023,6 @@ static struct soc_camera_link a910_iclink = {
.bus_id = 0,
.i2c_adapter_id = 0,
.board_info = &a910_camera_i2c_board_info,
- .module_name = "mt9m111",
.power = a910_camera_power,
.reset = a910_camera_reset,
};
diff --git a/arch/arm/mach-pxa/mioa701.c b/arch/arm/mach-pxa/mioa701.c
index 0c31fabfc7fd..f5fb915e1315 100644
--- a/arch/arm/mach-pxa/mioa701.c
+++ b/arch/arm/mach-pxa/mioa701.c
@@ -711,7 +711,6 @@ static struct soc_camera_link iclink = {
.bus_id = 0, /* Match id in pxa27x_device_camera in device.c */
.board_info = &mioa701_i2c_devices[0],
.i2c_adapter_id = 0,
- .module_name = "mt9m111",
};
struct i2c_pxa_platform_data i2c_pdata = {
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index f56ae1008759..f33647a8e0b7 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -453,7 +453,6 @@ static struct soc_camera_link iclink[] = {
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
- .module_name = "mt9v022",
}, {
.bus_id = 0, /* Must match with the camera ID */
.board_info = &pcm990_camera_i2c[1],
@@ -461,7 +460,6 @@ static struct soc_camera_link iclink[] = {
.query_bus_param = pcm990_camera_query_bus_param,
.set_bus_param = pcm990_camera_set_bus_param,
.free_bus = pcm990_camera_free_bus,
- .module_name = "mt9m001",
},
};
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 3da116f47f01..881a3a5f5647 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -481,7 +481,6 @@ static struct soc_camera_link ov7725_link = {
.power = ov7725_power,
.board_info = &ap325rxa_i2c_camera[0],
.i2c_adapter_id = 0,
- .module_name = "ov772x",
.priv = &ov7725_info,
};
diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c
index 71a3368ab1fc..ddc7e4e4d2a0 100644
--- a/arch/sh/boards/mach-ecovec24/setup.c
+++ b/arch/sh/boards/mach-ecovec24/setup.c
@@ -620,7 +620,6 @@ static struct soc_camera_link tw9910_link = {
.bus_id = 1,
.power = tw9910_power,
.board_info = &i2c_camera[0],
- .module_name = "tw9910",
.priv = &tw9910_info,
};
@@ -644,7 +643,6 @@ static struct soc_camera_link mt9t112_link1 = {
.power = mt9t112_power1,
.bus_id = 0,
.board_info = &i2c_camera[1],
- .module_name = "mt9t112",
.priv = &mt9t112_info1,
};
@@ -667,7 +665,6 @@ static struct soc_camera_link mt9t112_link2 = {
.power = mt9t112_power2,
.bus_id = 1,
.board_info = &i2c_camera[2],
- .module_name = "mt9t112",
.priv = &mt9t112_info2,
};
@@ -793,7 +790,6 @@ static struct sh_vou_pdata sh_vou_pdata = {
.flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
.board_info = &ak8813,
.i2c_adap = 0,
- .module_name = "ak881x",
};
static struct resource sh_vou_resources[] = {
diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c
index 68994a163f6c..1742849db648 100644
--- a/arch/sh/boards/mach-kfr2r09/setup.c
+++ b/arch/sh/boards/mach-kfr2r09/setup.c
@@ -333,7 +333,6 @@ static struct soc_camera_link rj54n1_link = {
.power = camera_power,
.board_info = &kfr2r09_i2c_camera,
.i2c_adapter_id = 1,
- .module_name = "rj54n1cb0c",
.priv = &rj54n1_priv,
};
diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c
index 662debe4ead2..03af84842559 100644
--- a/arch/sh/boards/mach-migor/setup.c
+++ b/arch/sh/boards/mach-migor/setup.c
@@ -450,7 +450,6 @@ static struct soc_camera_link ov7725_link = {
.power = ov7725_power,
.board_info = &migor_i2c_camera[0],
.i2c_adapter_id = 0,
- .module_name = "ov772x",
.priv = &ov7725_info,
};
@@ -463,7 +462,6 @@ static struct soc_camera_link tw9910_link = {
.power = tw9910_power,
.board_info = &migor_i2c_camera[1],
.i2c_adapter_id = 0,
- .module_name = "tw9910",
.priv = &tw9910_info,
};
diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c
index 552ebd9ba82b..8cc1d7295d85 100644
--- a/arch/sh/boards/mach-se/7724/setup.c
+++ b/arch/sh/boards/mach-se/7724/setup.c
@@ -550,7 +550,6 @@ static struct sh_vou_pdata sh_vou_pdata = {
.flags = SH_VOU_HSYNC_LOW | SH_VOU_VSYNC_LOW,
.board_info = &ak8813,
.i2c_adap = 0,
- .module_name = "ak881x",
};
static struct resource sh_vou_resources[] = {
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
index 490c57cc4cfe..aa4163eb7a83 100644
--- a/drivers/media/IR/Kconfig
+++ b/drivers/media/IR/Kconfig
@@ -79,6 +79,18 @@ 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 IR_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_LIRC_CODEC
tristate "Enable IR to LIRC bridge"
depends on IR_CORE
@@ -89,6 +101,20 @@ config IR_LIRC_CODEC
Enable this option to pass raw IR to and from userspace via
the LIRC interface.
+config IR_ENE
+ tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
+ depends on PNP
+ depends on IR_CORE
+ ---help---
+ Say Y here to enable support for integrated infrared receiver
+ /transceiver made by ENE.
+
+ You can see if you have it by looking at lspnp output.
+ Output should include ENE0100 ENE0200 or something similar.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ene_ir.
+
config IR_IMON
tristate "SoundGraph iMON Receiver and Display"
depends on USB_ARCH_HAS_HCD
@@ -113,19 +139,18 @@ config IR_MCEUSB
To compile this driver as a module, choose M here: the
module will be called mceusb.
-config IR_ENE
- tristate "ENE eHome Receiver/Transciever (pnp id: ENE0100/ENE02xxx)"
+config IR_NUVOTON
+ tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP
depends on IR_CORE
---help---
Say Y here to enable support for integrated infrared receiver
- /transciever made by ENE.
-
- You can see if you have it by looking at lspnp output.
- Output should include ENE0100 ENE0200 or something similiar.
+ /transciever made by Nuvoton (formerly Winbond). This chip is
+ found in the ASRock ION 330HT, as well as assorted Intel
+ DP55-series motherboards (and of course, possibly others).
To compile this driver as a module, choose M here: the
- module will be called ene_ir.
+ module will be called nuvoton-cir.
config IR_STREAMZAP
tristate "Streamzap PC Remote IR Receiver"
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
index 53676838fe97..f9574adab82a 100644
--- a/drivers/media/IR/Makefile
+++ b/drivers/media/IR/Makefile
@@ -11,10 +11,12 @@ 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_LIRC_CODEC) += ir-lirc-codec.o
# stand-alone IR receivers/transmitters
obj-$(CONFIG_IR_IMON) += imon.o
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
+obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
obj-$(CONFIG_IR_ENE) += ene_ir.o
obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
diff --git a/drivers/media/IR/ene_ir.c b/drivers/media/IR/ene_ir.c
index 5447750f5e38..7637babcd262 100644
--- a/drivers/media/IR/ene_ir.c
+++ b/drivers/media/IR/ene_ir.c
@@ -1,5 +1,5 @@
/*
- * driver for ENE KB3926 B/C/D CIR (pnp id: ENE0XXX)
+ * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX)
*
* Copyright (C) 2010 Maxim Levitsky
*
@@ -17,6 +17,17 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
+ *
+ * Special thanks to:
+ * Sami R. for lot of help in debugging and therefore
+ * bringing to life support for transmission & learning mode.
+ *
+ * Charlie Andrews for lots of help in
+ * bringing up the support of new firmware buffer that is popular
+ * on latest notebooks
+ *
+ * ENE for partial device documentation
+ *
*/
#include
@@ -31,51 +42,59 @@
#include
#include "ene_ir.h"
-
-static int sample_period = -1;
-static int enable_idle = 1;
-static int input = 1;
+static int sample_period;
+static bool learning_mode_force;
static int debug;
-static int txsim;
+static bool txsim;
-static int ene_irq_status(struct ene_device *dev);
-
-/* read a hardware register */
-static u8 ene_hw_read_reg(struct ene_device *dev, u16 reg)
+static void ene_set_reg_addr(struct ene_device *dev, u16 reg)
{
- u8 retval;
outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
- retval = inb(dev->hw_io + ENE_IO);
+}
- ene_dbg_verbose("reg %04x == %02x", reg, retval);
+/* read a hardware register */
+static u8 ene_read_reg(struct ene_device *dev, u16 reg)
+{
+ u8 retval;
+ ene_set_reg_addr(dev, reg);
+ retval = inb(dev->hw_io + ENE_IO);
+ dbg_regs("reg %04x == %02x", reg, retval);
return retval;
}
/* write a hardware register */
-static void ene_hw_write_reg(struct ene_device *dev, u16 reg, u8 value)
+static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value)
{
- outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
- outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+ dbg_regs("reg %04x <- %02x", reg, value);
+ ene_set_reg_addr(dev, reg);
outb(value, dev->hw_io + ENE_IO);
-
- ene_dbg_verbose("reg %04x <- %02x", reg, value);
}
-/* change specific bits in hardware register */
-static void ene_hw_write_reg_mask(struct ene_device *dev,
- u16 reg, u8 value, u8 mask)
+/* Set bits in hardware register */
+static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
{
- u8 regvalue;
+ dbg_regs("reg %04x |= %02x", reg, mask);
+ ene_set_reg_addr(dev, reg);
+ outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO);
+}
- outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
- outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+/* Clear bits in hardware register */
+static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
+{
+ dbg_regs("reg %04x &= ~%02x ", reg, mask);
+ ene_set_reg_addr(dev, reg);
+ outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO);
+}
- regvalue = inb(dev->hw_io + ENE_IO) & ~mask;
- regvalue |= (value & mask);
- outb(regvalue, dev->hw_io + ENE_IO);
-
- ene_dbg_verbose("reg %04x <- %02x (mask=%02x)", reg, value, mask);
+/* A helper to set/clear a bit in register according to boolean variable */
+static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask,
+ bool set)
+{
+ if (set)
+ ene_set_reg_mask(dev, reg, mask);
+ else
+ ene_clear_reg_mask(dev, reg, mask);
}
/* detect hardware features */
@@ -83,194 +102,378 @@ static int ene_hw_detect(struct ene_device *dev)
{
u8 chip_major, chip_minor;
u8 hw_revision, old_ver;
- u8 tmp;
- u8 fw_capabilities;
- int pll_freq;
+ u8 fw_reg2, fw_reg1;
- tmp = ene_hw_read_reg(dev, ENE_HW_UNK);
- ene_hw_write_reg(dev, ENE_HW_UNK, tmp & ~ENE_HW_UNK_CLR);
+ ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
+ chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR);
+ chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR);
+ ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
- chip_major = ene_hw_read_reg(dev, ENE_HW_VER_MAJOR);
- chip_minor = ene_hw_read_reg(dev, ENE_HW_VER_MINOR);
+ hw_revision = ene_read_reg(dev, ENE_ECHV);
+ old_ver = ene_read_reg(dev, ENE_HW_VER_OLD);
- ene_hw_write_reg(dev, ENE_HW_UNK, tmp);
- hw_revision = ene_hw_read_reg(dev, ENE_HW_VERSION);
- old_ver = ene_hw_read_reg(dev, ENE_HW_VER_OLD);
+ dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) +
+ (ene_read_reg(dev, ENE_PLLFRL) >> 4);
- pll_freq = (ene_hw_read_reg(dev, ENE_PLLFRH) << 4) +
- (ene_hw_read_reg(dev, ENE_PLLFRL) >> 4);
-
- if (pll_freq != 1000)
- dev->rx_period_adjust = 4;
- else
- dev->rx_period_adjust = 2;
-
-
- ene_printk(KERN_NOTICE, "PLL freq = %d\n", pll_freq);
+ if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD)
+ dev->rx_period_adjust =
+ dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4;
if (hw_revision == 0xFF) {
-
- ene_printk(KERN_WARNING, "device seems to be disabled\n");
- ene_printk(KERN_WARNING,
- "send a mail to lirc-list@lists.sourceforge.net\n");
- ene_printk(KERN_WARNING, "please attach output of acpidump\n");
+ ene_warn("device seems to be disabled");
+ ene_warn("send a mail to lirc-list@lists.sourceforge.net");
+ ene_warn("please attach output of acpidump and dmidecode");
return -ENODEV;
}
+ ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x",
+ chip_major, chip_minor, old_ver, hw_revision);
+
+ ene_notice("PLL freq = %d", dev->pll_freq);
+
if (chip_major == 0x33) {
- ene_printk(KERN_WARNING, "chips 0x33xx aren't supported\n");
+ ene_warn("chips 0x33xx aren't supported");
return -ENODEV;
}
if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
dev->hw_revision = ENE_HW_C;
+ ene_notice("KB3926C detected");
} else if (old_ver == 0x24 && hw_revision == 0xC0) {
dev->hw_revision = ENE_HW_B;
- ene_printk(KERN_NOTICE, "KB3926B detected\n");
+ ene_notice("KB3926B detected");
} else {
dev->hw_revision = ENE_HW_D;
- ene_printk(KERN_WARNING,
- "unknown ENE chip detected, assuming KB3926D\n");
- ene_printk(KERN_WARNING,
- "driver support might be not complete");
-
+ ene_notice("KB3926D or higher detected");
}
- ene_printk(KERN_DEBUG,
- "chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x\n",
- chip_major, chip_minor, old_ver, hw_revision);
-
/* detect features hardware supports */
if (dev->hw_revision < ENE_HW_C)
return 0;
- fw_capabilities = ene_hw_read_reg(dev, ENE_FW2);
- ene_dbg("Firmware capabilities: %02x", fw_capabilities);
+ fw_reg1 = ene_read_reg(dev, ENE_FW1);
+ fw_reg2 = ene_read_reg(dev, ENE_FW2);
- dev->hw_gpio40_learning = fw_capabilities & ENE_FW2_GP40_AS_LEARN;
- dev->hw_learning_and_tx_capable = fw_capabilities & ENE_FW2_LEARNING;
+ ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2);
- dev->hw_fan_as_normal_input = dev->hw_learning_and_tx_capable &&
- (fw_capabilities & ENE_FW2_FAN_AS_NRML_IN);
+ dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A);
+ dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING);
+ dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF);
- ene_printk(KERN_NOTICE, "hardware features:\n");
- ene_printk(KERN_NOTICE,
- "learning and transmit %s, gpio40_learn %s, fan_in %s\n",
- dev->hw_learning_and_tx_capable ? "on" : "off",
- dev->hw_gpio40_learning ? "on" : "off",
- dev->hw_fan_as_normal_input ? "on" : "off");
+ if (dev->hw_learning_and_tx_capable)
+ dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT);
+
+ ene_notice("Hardware features:");
if (dev->hw_learning_and_tx_capable) {
- ene_printk(KERN_WARNING,
- "Device supports transmitting, but that support is\n");
- ene_printk(KERN_WARNING,
- "lightly tested. Please test it and mail\n");
- ene_printk(KERN_WARNING,
- "lirc-list@lists.sourceforge.net\n");
+ ene_notice("* Supports transmitting & learning mode");
+ ene_notice(" This feature is rare and therefore,");
+ ene_notice(" you are welcome to test it,");
+ ene_notice(" and/or contact the author via:");
+ ene_notice(" lirc-list@lists.sourceforge.net");
+ ene_notice(" or maximlevitsky@gmail.com");
+
+ ene_notice("* Uses GPIO %s for IR raw input",
+ dev->hw_use_gpio_0a ? "40" : "0A");
+
+ if (dev->hw_fan_input)
+ ene_notice("* Uses unused fan feedback input as source"
+ " of demodulated IR data");
}
+
+ if (!dev->hw_fan_input)
+ ene_notice("* Uses GPIO %s for IR demodulated input",
+ dev->hw_use_gpio_0a ? "0A" : "40");
+
+ if (dev->hw_extra_buffer)
+ ene_notice("* Uses new style input buffer");
return 0;
}
-/* this enables/disables IR input via gpio40*/
-static void ene_enable_gpio40_receive(struct ene_device *dev, int enable)
+/* Read properities of hw sample buffer */
+static void ene_rx_setup_hw_buffer(struct ene_device *dev)
{
- ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, enable ?
- 0 : ENE_CIR_CONF2_GPIO40DIS,
- ENE_CIR_CONF2_GPIO40DIS);
-}
+ u16 tmp;
-/* this enables/disables IR via standard input */
-static void ene_enable_normal_receive(struct ene_device *dev, int enable)
-{
- ene_hw_write_reg(dev, ENE_CIR_CONF1, enable ? ENE_CIR_CONF1_RX_ON : 0);
-}
+ ene_rx_read_hw_pointer(dev);
+ dev->r_pointer = dev->w_pointer;
-/* this enables/disables IR input via unused fan tachtometer input */
-static void ene_enable_fan_receive(struct ene_device *dev, int enable)
-{
- if (!enable)
- ene_hw_write_reg(dev, ENE_FAN_AS_IN1, 0);
- else {
- ene_hw_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
- ene_hw_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
+ if (!dev->hw_extra_buffer) {
+ dev->buffer_len = ENE_FW_PACKET_SIZE * 2;
+ return;
}
- dev->rx_fan_input_inuse = enable;
+
+ tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER);
+ tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8;
+ dev->extra_buf1_address = tmp;
+
+ dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2);
+
+ tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3);
+ tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8;
+ dev->extra_buf2_address = tmp;
+
+ dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5);
+
+ dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8;
+
+ ene_notice("Hardware uses 2 extended buffers:");
+ ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address,
+ dev->extra_buf1_len);
+ ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address,
+ dev->extra_buf2_len);
+
+ ene_notice("Total buffer len = %d", dev->buffer_len);
+
+ if (dev->buffer_len > 64 || dev->buffer_len < 16)
+ goto error;
+
+ if (dev->extra_buf1_address > 0xFBFC ||
+ dev->extra_buf1_address < 0xEC00)
+ goto error;
+
+ if (dev->extra_buf2_address > 0xFBFC ||
+ dev->extra_buf2_address < 0xEC00)
+ goto error;
+
+ if (dev->r_pointer > dev->buffer_len)
+ goto error;
+
+ ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+ return;
+error:
+ ene_warn("Error validating extra buffers, device probably won't work");
+ dev->hw_extra_buffer = false;
+ ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
}
+/* Restore the pointers to extra buffers - to make module reload work*/
+static void ene_rx_restore_hw_buffer(struct ene_device *dev)
+{
+ if (!dev->hw_extra_buffer)
+ return;
+
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0,
+ dev->extra_buf1_address & 0xFF);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1,
+ dev->extra_buf1_address >> 8);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len);
+
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3,
+ dev->extra_buf2_address & 0xFF);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4,
+ dev->extra_buf2_address >> 8);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5,
+ dev->extra_buf2_len);
+ ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+}
+
+/* Read hardware write pointer */
+static void ene_rx_read_hw_pointer(struct ene_device *dev)
+{
+ if (dev->hw_extra_buffer)
+ dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER);
+ else
+ dev->w_pointer = ene_read_reg(dev, ENE_FW2)
+ & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE;
+
+ dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x",
+ dev->w_pointer, dev->r_pointer);
+}
+
+/* Gets address of next sample from HW ring buffer */
+static int ene_rx_get_sample_reg(struct ene_device *dev)
+{
+ int r_pointer;
+
+ if (dev->r_pointer == dev->w_pointer) {
+ dbg_verbose("RB: hit end, try update w_pointer");
+ ene_rx_read_hw_pointer(dev);
+ }
+
+ if (dev->r_pointer == dev->w_pointer) {
+ dbg_verbose("RB: end of data at %d", dev->r_pointer);
+ return 0;
+ }
+
+ dbg_verbose("RB: reading at offset %d", dev->r_pointer);
+ r_pointer = dev->r_pointer;
+
+ dev->r_pointer++;
+ if (dev->r_pointer == dev->buffer_len)
+ dev->r_pointer = 0;
+
+ dbg_verbose("RB: next read will be from offset %d", dev->r_pointer);
+
+ if (r_pointer < 8) {
+ dbg_verbose("RB: read at main buffer at %d", r_pointer);
+ return ENE_FW_SAMPLE_BUFFER + r_pointer;
+ }
+
+ r_pointer -= 8;
+
+ if (r_pointer < dev->extra_buf1_len) {
+ dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer);
+ return dev->extra_buf1_address + r_pointer;
+ }
+
+ r_pointer -= dev->extra_buf1_len;
+
+ if (r_pointer < dev->extra_buf2_len) {
+ dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer);
+ return dev->extra_buf2_address + r_pointer;
+ }
+
+ dbg("attempt to read beyong ring bufer end");
+ return 0;
+}
+
/* Sense current received carrier */
-static int ene_rx_sense_carrier(struct ene_device *dev)
+void ene_rx_sense_carrier(struct ene_device *dev)
{
- int period = ene_hw_read_reg(dev, ENE_RX_CARRIER);
- int carrier;
- ene_dbg("RX: hardware carrier period = %02x", period);
+ DEFINE_IR_RAW_EVENT(ev);
- if (!(period & ENE_RX_CARRIER_VALID))
- return 0;
+ int carrier, duty_cycle;
+ int period = ene_read_reg(dev, ENE_CIRCAR_PRD);
+ int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD);
- period &= ~ENE_RX_CARRIER_VALID;
+ if (!(period & ENE_CIRCAR_PRD_VALID))
+ return;
+
+ period &= ~ENE_CIRCAR_PRD_VALID;
if (!period)
- return 0;
+ return;
+
+ dbg("RX: hardware carrier period = %02x", period);
+ dbg("RX: hardware carrier pulse period = %02x", hperiod);
carrier = 2000000 / period;
- ene_dbg("RX: sensed carrier = %d Hz", carrier);
- return carrier;
+ duty_cycle = (hperiod * 100) / period;
+ dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
+ carrier, duty_cycle);
+ if (dev->carrier_detect_enabled) {
+ ev.carrier_report = true;
+ ev.carrier = carrier;
+ ev.duty_cycle = duty_cycle;
+ ir_raw_event_store(dev->idev, &ev);
+ }
}
-/* determine which input to use*/
-static void ene_rx_set_inputs(struct ene_device *dev)
+/* this enables/disables the CIR RX engine */
+static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable)
{
- int learning_mode = dev->learning_enabled;
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+ ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable);
+}
- ene_dbg("RX: setup receiver, learning mode = %d", learning_mode);
+/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/
+static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a)
+{
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a);
+}
- ene_enable_normal_receive(dev, 1);
-
- /* old hardware doesn't support learning mode for sure */
- if (dev->hw_revision <= ENE_HW_B)
+/*
+ * this enables alternative input via fan tachometer sensor and bypasses
+ * the hw CIR engine
+ */
+static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable)
+{
+ if (!dev->hw_fan_input)
return;
- /* receiver not learning capable, still set gpio40 correctly */
- if (!dev->hw_learning_and_tx_capable) {
- ene_enable_gpio40_receive(dev, !dev->hw_gpio40_learning);
- return;
+ if (!enable)
+ ene_write_reg(dev, ENE_FAN_AS_IN1, 0);
+ else {
+ ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+ ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
}
+}
+
+/* setup the receiver for RX*/
+static void ene_rx_setup(struct ene_device *dev)
+{
+ bool learning_mode = dev->learning_mode_enabled ||
+ dev->carrier_detect_enabled;
+ int sample_period_adjust = 0;
+
+ dbg("RX: setup receiver, learning mode = %d", learning_mode);
+
+
+ /* This selects RLC input and clears CFG2 settings */
+ ene_write_reg(dev, ENE_CIRCFG2, 0x00);
+
+ /* set sample period*/
+ if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD)
+ sample_period_adjust =
+ dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2;
+
+ ene_write_reg(dev, ENE_CIRRLC_CFG,
+ (sample_period + sample_period_adjust) |
+ ENE_CIRRLC_CFG_OVERFLOW);
+ /* revB doesn't support inputs */
+ if (dev->hw_revision < ENE_HW_C)
+ goto select_timeout;
- /* enable learning mode */
if (learning_mode) {
- ene_enable_gpio40_receive(dev, dev->hw_gpio40_learning);
- /* fan input is not used for learning */
- if (dev->hw_fan_as_normal_input)
- ene_enable_fan_receive(dev, 0);
+ WARN_ON(!dev->hw_learning_and_tx_capable);
- /* disable learning mode */
+ /* Enable the opposite of the normal input
+ That means that if GPIO40 is normally used, use GPIO0A
+ and vice versa.
+ This input will carry non demodulated
+ signal, and we will tell the hw to demodulate it itself */
+ ene_rx_select_input(dev, !dev->hw_use_gpio_0a);
+ dev->rx_fan_input_inuse = false;
+
+ /* Enable carrier demodulation */
+ ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+
+ /* Enable carrier detection */
+ ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63);
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT,
+ dev->carrier_detect_enabled || debug);
} else {
- if (dev->hw_fan_as_normal_input) {
- ene_enable_fan_receive(dev, 1);
- ene_enable_normal_receive(dev, 0);
- } else
- ene_enable_gpio40_receive(dev,
- !dev->hw_gpio40_learning);
+ if (dev->hw_fan_input)
+ dev->rx_fan_input_inuse = true;
+ else
+ ene_rx_select_input(dev, dev->hw_use_gpio_0a);
+
+ /* Disable carrier detection & demodulation */
+ ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+ ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT);
}
- /* set few additional settings for this mode */
- ene_hw_write_reg_mask(dev, ENE_CIR_CONF1, learning_mode ?
- ENE_CIR_CONF1_LEARN1 : 0, ENE_CIR_CONF1_LEARN1);
-
- ene_hw_write_reg_mask(dev, ENE_CIR_CONF2, learning_mode ?
- ENE_CIR_CONF2_LEARN2 : 0, ENE_CIR_CONF2_LEARN2);
-
+select_timeout:
if (dev->rx_fan_input_inuse) {
- dev->props->rx_resolution = ENE_SAMPLE_PERIOD_FAN * 1000;
+ dev->props->rx_resolution = MS_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
- dev->props->timeout =
- ENE_FAN_VALUE_MASK * ENE_SAMPLE_PERIOD_FAN * 1000;
+ /* Fan input doesn't support timeouts, it just ends the
+ input with a maximum sample */
+ dev->props->min_timeout = dev->props->max_timeout =
+ MS_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
+ ENE_FW_SAMPLE_PERIOD_FAN);
} else {
- dev->props->rx_resolution = sample_period * 1000;
- dev->props->timeout = ENE_MAXGAP * 1000;
+ dev->props->rx_resolution = MS_TO_NS(sample_period);
+
+ /* Theoreticly timeout is unlimited, but we cap it
+ * because it was seen that on one device, it
+ * would stop sending spaces after around 250 msec.
+ * Besides, this is close to 2^32 anyway and timeout is u32.
+ */
+ dev->props->min_timeout = MS_TO_NS(127 * sample_period);
+ dev->props->max_timeout = MS_TO_NS(200000);
}
+
+ if (dev->hw_learning_and_tx_capable)
+ dev->props->tx_resolution = MS_TO_NS(sample_period);
+
+ if (dev->props->timeout > dev->props->max_timeout)
+ dev->props->timeout = dev->props->max_timeout;
+ if (dev->props->timeout < dev->props->min_timeout)
+ dev->props->timeout = dev->props->min_timeout;
}
/* Enable the device for receive */
@@ -278,145 +481,157 @@ static void ene_rx_enable(struct ene_device *dev)
{
u8 reg_value;
+ /* Enable system interrupt */
if (dev->hw_revision < ENE_HW_C) {
- ene_hw_write_reg(dev, ENEB_IRQ, dev->irq << 1);
- ene_hw_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+ ene_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+ ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
} else {
- reg_value = ene_hw_read_reg(dev, ENEC_IRQ) & 0xF0;
- reg_value |= ENEC_IRQ_UNK_EN;
- reg_value &= ~ENEC_IRQ_STATUS;
- reg_value |= (dev->irq & ENEC_IRQ_MASK);
- ene_hw_write_reg(dev, ENEC_IRQ, reg_value);
- ene_hw_write_reg(dev, ENE_TX_UNK1, 0x63);
+ reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0;
+ reg_value |= ENE_IRQ_UNK_EN;
+ reg_value &= ~ENE_IRQ_STATUS;
+ reg_value |= (dev->irq & ENE_IRQ_MASK);
+ ene_write_reg(dev, ENE_IRQ, reg_value);
}
- ene_hw_write_reg(dev, ENE_CIR_CONF2, 0x00);
- ene_rx_set_inputs(dev);
-
- /* set sampling period */
- ene_hw_write_reg(dev, ENE_CIR_SAMPLE_PERIOD, sample_period);
+ /* Enable inputs */
+ ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse);
+ ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse);
/* ack any pending irqs - just in case */
ene_irq_status(dev);
/* enable firmware bits */
- ene_hw_write_reg_mask(dev, ENE_FW1,
- ENE_FW1_ENABLE | ENE_FW1_IRQ,
- ENE_FW1_ENABLE | ENE_FW1_IRQ);
+ ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
/* enter idle mode */
- ir_raw_event_set_idle(dev->idev, 1);
- ir_raw_event_reset(dev->idev);
-
+ ir_raw_event_set_idle(dev->idev, true);
+ dev->rx_enabled = true;
}
/* Disable the device receiver */
static void ene_rx_disable(struct ene_device *dev)
{
/* disable inputs */
- ene_enable_normal_receive(dev, 0);
-
- if (dev->hw_fan_as_normal_input)
- ene_enable_fan_receive(dev, 0);
+ ene_rx_enable_cir_engine(dev, false);
+ ene_rx_enable_fan_input(dev, false);
/* disable hardware IRQ and firmware flag */
- ene_hw_write_reg_mask(dev, ENE_FW1, 0, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+ ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
- ir_raw_event_set_idle(dev->idev, 1);
- ir_raw_event_reset(dev->idev);
+ ir_raw_event_set_idle(dev->idev, true);
+ dev->rx_enabled = false;
}
+/* This resets the receiver. Usefull to stop stream of spaces at end of
+ * transmission
+ */
+static void ene_rx_reset(struct ene_device *dev)
+{
+ ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+ ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+}
+
+/* Set up the TX carrier frequency and duty cycle */
+static void ene_tx_set_carrier(struct ene_device *dev)
+{
+ u8 tx_puls_width;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+ ENE_CIRCFG_TX_CARR, dev->tx_period > 0);
+
+ if (!dev->tx_period)
+ goto unlock;
+
+ BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0);
+
+ tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle);
+
+ if (!tx_puls_width)
+ tx_puls_width = 1;
+
+ dbg("TX: pulse distance = %d * 500 ns", dev->tx_period);
+ dbg("TX: pulse width = %d * 500 ns", tx_puls_width);
+
+ ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL);
+ ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width);
+unlock:
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
+
+/* Enable/disable transmitters */
+static void ene_tx_set_transmitters(struct ene_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41,
+ !!(dev->transmitter_mask & 0x01));
+ ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D,
+ !!(dev->transmitter_mask & 0x02));
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
/* prepare transmission */
-static void ene_tx_prepare(struct ene_device *dev)
+static void ene_tx_enable(struct ene_device *dev)
{
- u8 conf1;
+ u8 conf1 = ene_read_reg(dev, ENE_CIRCFG);
+ u8 fwreg2 = ene_read_reg(dev, ENE_FW2);
- conf1 = ene_hw_read_reg(dev, ENE_CIR_CONF1);
dev->saved_conf1 = conf1;
+ /* Show information about currently connected transmitter jacks */
+ if (fwreg2 & ENE_FW2_EMMITER1_CONN)
+ dbg("TX: Transmitter #1 is connected");
+
+ if (fwreg2 & ENE_FW2_EMMITER2_CONN)
+ dbg("TX: Transmitter #2 is connected");
+
+ if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN)))
+ ene_warn("TX: transmitter cable isn't connected!");
+
+ /* disable receive on revc */
if (dev->hw_revision == ENE_HW_C)
- conf1 &= ~ENE_CIR_CONF1_TX_CLEAR;
+ conf1 &= ~ENE_CIRCFG_RX_EN;
/* Enable TX engine */
- conf1 |= ENE_CIR_CONF1_TX_ON;
-
- /* Set carrier */
- if (dev->tx_period) {
-
- /* NOTE: duty cycle handling is just a guess, it might
- not be aviable. Default values were tested */
- int tx_period_in500ns = dev->tx_period * 2;
-
- int tx_pulse_width_in_500ns =
- tx_period_in500ns / (100 / dev->tx_duty_cycle);
-
- if (!tx_pulse_width_in_500ns)
- tx_pulse_width_in_500ns = 1;
-
- ene_dbg("TX: pulse distance = %d * 500 ns", tx_period_in500ns);
- ene_dbg("TX: pulse width = %d * 500 ns",
- tx_pulse_width_in_500ns);
-
- ene_hw_write_reg(dev, ENE_TX_PERIOD, ENE_TX_PERIOD_UNKBIT |
- tx_period_in500ns);
-
- ene_hw_write_reg(dev, ENE_TX_PERIOD_PULSE,
- tx_pulse_width_in_500ns);
-
- conf1 |= ENE_CIR_CONF1_TX_CARR;
- } else
- conf1 &= ~ENE_CIR_CONF1_TX_CARR;
-
- ene_hw_write_reg(dev, ENE_CIR_CONF1, conf1);
-
+ conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ;
+ ene_write_reg(dev, ENE_CIRCFG, conf1);
}
/* end transmission */
-static void ene_tx_complete(struct ene_device *dev)
+static void ene_tx_disable(struct ene_device *dev)
{
- ene_hw_write_reg(dev, ENE_CIR_CONF1, dev->saved_conf1);
+ ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
dev->tx_buffer = NULL;
}
-/* set transmit mask */
-static void ene_tx_hw_set_transmiter_mask(struct ene_device *dev)
-{
- u8 txport1 = ene_hw_read_reg(dev, ENE_TX_PORT1) & ~ENE_TX_PORT1_EN;
- u8 txport2 = ene_hw_read_reg(dev, ENE_TX_PORT2) & ~ENE_TX_PORT2_EN;
-
- if (dev->transmitter_mask & 0x01)
- txport1 |= ENE_TX_PORT1_EN;
-
- if (dev->transmitter_mask & 0x02)
- txport2 |= ENE_TX_PORT2_EN;
-
- ene_hw_write_reg(dev, ENE_TX_PORT1, txport1);
- ene_hw_write_reg(dev, ENE_TX_PORT2, txport2);
-}
/* TX one sample - must be called with dev->hw_lock*/
static void ene_tx_sample(struct ene_device *dev)
{
u8 raw_tx;
u32 sample;
+ bool pulse = dev->tx_sample_pulse;
if (!dev->tx_buffer) {
- ene_dbg("TX: attempt to transmit NULL buffer");
+ ene_warn("TX: BUG: attempt to transmit NULL buffer");
return;
}
/* Grab next TX sample */
if (!dev->tx_sample) {
-again:
- if (dev->tx_pos == dev->tx_len + 1) {
+
+ if (dev->tx_pos == dev->tx_len) {
if (!dev->tx_done) {
- ene_dbg("TX: no more data to send");
- dev->tx_done = 1;
+ dbg("TX: no more data to send");
+ dev->tx_done = true;
goto exit;
} else {
- ene_dbg("TX: last sample sent by hardware");
- ene_tx_complete(dev);
+ dbg("TX: last sample sent by hardware");
+ ene_tx_disable(dev);
complete(&dev->tx_complete);
return;
}
@@ -425,23 +640,23 @@ again:
sample = dev->tx_buffer[dev->tx_pos++];
dev->tx_sample_pulse = !dev->tx_sample_pulse;
- ene_dbg("TX: sample %8d (%s)", sample, dev->tx_sample_pulse ?
- "pulse" : "space");
+ dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
- dev->tx_sample = DIV_ROUND_CLOSEST(sample, ENE_TX_SMPL_PERIOD);
-
- /* guard against too short samples */
if (!dev->tx_sample)
- goto again;
+ dev->tx_sample = 1;
}
- raw_tx = min(dev->tx_sample , (unsigned int)ENE_TX_SMLP_MASK);
+ raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
dev->tx_sample -= raw_tx;
- if (dev->tx_sample_pulse)
- raw_tx |= ENE_TX_PULSE_MASK;
+ dbg("TX: sample %8d (%s)", raw_tx * sample_period,
+ pulse ? "pulse" : "space");
+ if (pulse)
+ raw_tx |= ENE_CIRRLC_OUT_PULSE;
+
+ ene_write_reg(dev,
+ dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
- ene_hw_write_reg(dev, ENE_TX_INPUT1 + dev->tx_reg, raw_tx);
dev->tx_reg = !dev->tx_reg;
exit:
/* simulate TX done interrupt */
@@ -466,76 +681,59 @@ static int ene_irq_status(struct ene_device *dev)
{
u8 irq_status;
u8 fw_flags1, fw_flags2;
- int cur_rx_pointer;
int retval = 0;
- fw_flags2 = ene_hw_read_reg(dev, ENE_FW2);
- cur_rx_pointer = !!(fw_flags2 & ENE_FW2_BUF_HIGH);
+ fw_flags2 = ene_read_reg(dev, ENE_FW2);
if (dev->hw_revision < ENE_HW_C) {
- irq_status = ene_hw_read_reg(dev, ENEB_IRQ_STATUS);
+ irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS);
if (!(irq_status & ENEB_IRQ_STATUS_IR))
return 0;
- ene_hw_write_reg(dev, ENEB_IRQ_STATUS,
- irq_status & ~ENEB_IRQ_STATUS_IR);
- dev->rx_pointer = cur_rx_pointer;
+ ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR);
return ENE_IRQ_RX;
}
- irq_status = ene_hw_read_reg(dev, ENEC_IRQ);
-
- if (!(irq_status & ENEC_IRQ_STATUS))
+ irq_status = ene_read_reg(dev, ENE_IRQ);
+ if (!(irq_status & ENE_IRQ_STATUS))
return 0;
/* original driver does that twice - a workaround ? */
- ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
- ene_hw_write_reg(dev, ENEC_IRQ, irq_status & ~ENEC_IRQ_STATUS);
+ ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
+ ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
- /* clear unknown flag in F8F9 */
- if (fw_flags2 & ENE_FW2_IRQ_CLR)
- ene_hw_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_IRQ_CLR);
+ /* check RX interrupt */
+ if (fw_flags2 & ENE_FW2_RXIRQ) {
+ retval |= ENE_IRQ_RX;
+ ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ);
+ }
- /* check if this is a TX interrupt */
- fw_flags1 = ene_hw_read_reg(dev, ENE_FW1);
+ /* check TX interrupt */
+ fw_flags1 = ene_read_reg(dev, ENE_FW1);
if (fw_flags1 & ENE_FW1_TXIRQ) {
- ene_hw_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+ ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
retval |= ENE_IRQ_TX;
}
- /* Check if this is RX interrupt */
- if (dev->rx_pointer != cur_rx_pointer) {
- retval |= ENE_IRQ_RX;
- dev->rx_pointer = cur_rx_pointer;
-
- } else if (!(retval & ENE_IRQ_TX)) {
- ene_dbg("RX: interrupt without change in RX pointer(%d)",
- dev->rx_pointer);
- retval |= ENE_IRQ_RX;
- }
-
- if ((retval & ENE_IRQ_RX) && (retval & ENE_IRQ_TX))
- ene_dbg("both RX and TX interrupt at same time");
-
return retval;
}
/* interrupt handler */
static irqreturn_t ene_isr(int irq, void *data)
{
- u16 hw_value;
- int i, hw_sample;
- int pulse;
- int irq_status;
+ u16 hw_value, reg;
+ int hw_sample, irq_status;
+ bool pulse;
unsigned long flags;
- int carrier = 0;
irqreturn_t retval = IRQ_NONE;
struct ene_device *dev = (struct ene_device *)data;
- struct ir_raw_event ev;
-
+ DEFINE_IR_RAW_EVENT(ev);
spin_lock_irqsave(&dev->hw_lock, flags);
+
+ dbg_verbose("ISR called");
+ ene_rx_read_hw_pointer(dev);
irq_status = ene_irq_status(dev);
if (!irq_status)
@@ -544,9 +742,9 @@ static irqreturn_t ene_isr(int irq, void *data)
retval = IRQ_HANDLED;
if (irq_status & ENE_IRQ_TX) {
-
+ dbg_verbose("TX interrupt");
if (!dev->hw_learning_and_tx_capable) {
- ene_dbg("TX interrupt on unsupported device!");
+ dbg("TX interrupt on unsupported device!");
goto unlock;
}
ene_tx_sample(dev);
@@ -555,48 +753,57 @@ static irqreturn_t ene_isr(int irq, void *data)
if (!(irq_status & ENE_IRQ_RX))
goto unlock;
+ dbg_verbose("RX interrupt");
- if (dev->carrier_detect_enabled || debug)
- carrier = ene_rx_sense_carrier(dev);
-#if 0
- /* TODO */
- if (dev->carrier_detect_enabled && carrier)
- ir_raw_event_report_frequency(dev->idev, carrier);
-#endif
+ if (dev->hw_learning_and_tx_capable)
+ ene_rx_sense_carrier(dev);
- for (i = 0; i < ENE_SAMPLES_SIZE; i++) {
- hw_value = ene_hw_read_reg(dev,
- ENE_SAMPLE_BUFFER + dev->rx_pointer * 4 + i);
+ /* On hardware that don't support extra buffer we need to trust
+ the interrupt and not track the read pointer */
+ if (!dev->hw_extra_buffer)
+ dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0;
+
+ while (1) {
+
+ reg = ene_rx_get_sample_reg(dev);
+
+ dbg_verbose("next sample to read at: %04x", reg);
+ if (!reg)
+ break;
+
+ hw_value = ene_read_reg(dev, reg);
if (dev->rx_fan_input_inuse) {
+
+ int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER;
+
/* read high part of the sample */
- hw_value |= ene_hw_read_reg(dev,
- ENE_SAMPLE_BUFFER_FAN +
- dev->rx_pointer * 4 + i) << 8;
- pulse = hw_value & ENE_FAN_SMPL_PULS_MSK;
+ hw_value |= ene_read_reg(dev, reg + offset) << 8;
+ pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS;
/* clear space bit, and other unused bits */
- hw_value &= ENE_FAN_VALUE_MASK;
- hw_sample = hw_value * ENE_SAMPLE_PERIOD_FAN;
+ hw_value &= ENE_FW_SMPL_BUF_FAN_MSK;
+ hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN;
} else {
- pulse = !(hw_value & ENE_SAMPLE_SPC_MASK);
- hw_value &= ENE_SAMPLE_VALUE_MASK;
+ pulse = !(hw_value & ENE_FW_SAMPLE_SPACE);
+ hw_value &= ~ENE_FW_SAMPLE_SPACE;
hw_sample = hw_value * sample_period;
if (dev->rx_period_adjust) {
- hw_sample *= (100 - dev->rx_period_adjust);
- hw_sample /= 100;
+ hw_sample *= 100;
+ hw_sample /= (100 + dev->rx_period_adjust);
}
}
- /* no more data */
- if (!(hw_value))
- break;
- ene_dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
+ if (!dev->hw_extra_buffer && !hw_sample) {
+ dev->r_pointer = dev->w_pointer;
+ continue;
+ }
+ dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
- ev.duration = hw_sample * 1000;
+ ev.duration = MS_TO_NS(hw_sample);
ev.pulse = pulse;
ir_raw_event_store_with_filter(dev->idev, &ev);
}
@@ -608,19 +815,26 @@ unlock:
}
/* Initialize default settings */
-static void ene_setup_settings(struct ene_device *dev)
+static void ene_setup_default_settings(struct ene_device *dev)
{
dev->tx_period = 32;
- dev->tx_duty_cycle = 25; /*%*/
- dev->transmitter_mask = 3;
+ dev->tx_duty_cycle = 50; /*%*/
+ dev->transmitter_mask = 0x03;
+ dev->learning_mode_enabled = learning_mode_force;
- /* Force learning mode if (input == 2), otherwise
- let user set it with LIRC_SET_REC_CARRIER */
- dev->learning_enabled =
- (input == 2 && dev->hw_learning_and_tx_capable);
+ /* Set reasonable default timeout */
+ dev->props->timeout = MS_TO_NS(150000);
+}
- dev->rx_pointer = -1;
+/* Upload all hardware settings at once. Used at load and resume time */
+static void ene_setup_hw_settings(struct ene_device *dev)
+{
+ if (dev->hw_learning_and_tx_capable) {
+ ene_tx_set_carrier(dev);
+ ene_tx_set_transmitters(dev);
+ }
+ ene_rx_setup(dev);
}
/* outside interface: called on first open*/
@@ -630,8 +844,6 @@ static int ene_open(void *data)
unsigned long flags;
spin_lock_irqsave(&dev->hw_lock, flags);
- dev->in_use = 1;
- ene_setup_settings(dev);
ene_rx_enable(dev);
spin_unlock_irqrestore(&dev->hw_lock, flags);
return 0;
@@ -645,7 +857,6 @@ static void ene_close(void *data)
spin_lock_irqsave(&dev->hw_lock, flags);
ene_rx_disable(dev);
- dev->in_use = 0;
spin_unlock_irqrestore(&dev->hw_lock, flags);
}
@@ -653,19 +864,17 @@ static void ene_close(void *data)
static int ene_set_tx_mask(void *data, u32 tx_mask)
{
struct ene_device *dev = (struct ene_device *)data;
- unsigned long flags;
- ene_dbg("TX: attempt to set transmitter mask %02x", tx_mask);
+ dbg("TX: attempt to set transmitter mask %02x", tx_mask);
/* invalid txmask */
- if (!tx_mask || tx_mask & ~0x3) {
- ene_dbg("TX: invalid mask");
+ if (!tx_mask || tx_mask & ~0x03) {
+ dbg("TX: invalid mask");
/* return count of transmitters */
return 2;
}
- spin_lock_irqsave(&dev->hw_lock, flags);
dev->transmitter_mask = tx_mask;
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ ene_tx_set_transmitters(dev);
return 0;
}
@@ -673,66 +882,76 @@ static int ene_set_tx_mask(void *data, u32 tx_mask)
static int ene_set_tx_carrier(void *data, u32 carrier)
{
struct ene_device *dev = (struct ene_device *)data;
- unsigned long flags;
- u32 period = 1000000 / carrier; /* (1 / freq) (* # usec in 1 sec) */
+ u32 period = 2000000 / carrier;
- ene_dbg("TX: attempt to set tx carrier to %d kHz", carrier);
+ dbg("TX: attempt to set tx carrier to %d kHz", carrier);
- if (period && (period > ENE_TX_PERIOD_MAX ||
- period < ENE_TX_PERIOD_MIN)) {
+ if (period && (period > ENE_CIRMOD_PRD_MAX ||
+ period < ENE_CIRMOD_PRD_MIN)) {
- ene_dbg("TX: out of range %d-%d carrier, "
- "falling back to 32 kHz",
- 1000 / ENE_TX_PERIOD_MIN,
- 1000 / ENE_TX_PERIOD_MAX);
-
- period = 32; /* this is just a coincidence!!! */
+ dbg("TX: out of range %d-%d kHz carrier",
+ 2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX);
+ return -1;
}
- ene_dbg("TX: set carrier to %d kHz", carrier);
- spin_lock_irqsave(&dev->hw_lock, flags);
dev->tx_period = period;
- spin_unlock_irqrestore(&dev->hw_lock, flags);
+ ene_tx_set_carrier(dev);
return 0;
}
+/*outside interface : set tx duty cycle */
+static int ene_set_tx_duty_cycle(void *data, u32 duty_cycle)
+{
+ struct ene_device *dev = (struct ene_device *)data;
+ dbg("TX: setting duty cycle to %d%%", duty_cycle);
+ dev->tx_duty_cycle = duty_cycle;
+ ene_tx_set_carrier(dev);
+ return 0;
+}
/* outside interface: enable learning mode */
static int ene_set_learning_mode(void *data, int enable)
{
struct ene_device *dev = (struct ene_device *)data;
unsigned long flags;
- if (enable == dev->learning_enabled)
+ if (enable == dev->learning_mode_enabled)
return 0;
spin_lock_irqsave(&dev->hw_lock, flags);
- dev->learning_enabled = enable;
- ene_rx_set_inputs(dev);
+ dev->learning_mode_enabled = enable;
+ ene_rx_disable(dev);
+ ene_rx_setup(dev);
+ ene_rx_enable(dev);
spin_unlock_irqrestore(&dev->hw_lock, flags);
return 0;
}
-/* outside interface: set rec carrier */
-static int ene_set_rec_carrier(void *data, u32 min, u32 max)
+static int ene_set_carrier_report(void *data, int enable)
{
struct ene_device *dev = (struct ene_device *)data;
- ene_set_learning_mode(dev,
- max > ENE_NORMAL_RX_HI || min < ENE_NORMAL_RX_LOW);
+ unsigned long flags;
+
+ if (enable == dev->carrier_detect_enabled)
+ return 0;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ dev->carrier_detect_enabled = enable;
+ ene_rx_disable(dev);
+ ene_rx_setup(dev);
+ ene_rx_enable(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
return 0;
}
/* outside interface: enable or disable idle mode */
-static void ene_rx_set_idle(void *data, int idle)
+static void ene_set_idle(void *data, bool idle)
{
- struct ene_device *dev = (struct ene_device *)data;
- ene_dbg("%sabling idle mode", idle ? "en" : "dis");
-
- ene_hw_write_reg_mask(dev, ENE_CIR_SAMPLE_PERIOD,
- (enable_idle && idle) ? 0 : ENE_CIR_SAMPLE_OVERFLOW,
- ENE_CIR_SAMPLE_OVERFLOW);
+ if (idle) {
+ ene_rx_reset((struct ene_device *)data);
+ dbg("RX: end of data");
+ }
}
-
/* outside interface: transmit */
static int ene_transmit(void *data, int *buf, u32 n)
{
@@ -747,12 +966,11 @@ static int ene_transmit(void *data, int *buf, u32 n)
dev->tx_sample = 0;
dev->tx_sample_pulse = 0;
- ene_dbg("TX: %d samples", dev->tx_len);
+ dbg("TX: %d samples", dev->tx_len);
spin_lock_irqsave(&dev->hw_lock, flags);
- ene_tx_hw_set_transmiter_mask(dev);
- ene_tx_prepare(dev);
+ ene_tx_enable(dev);
/* Transmit first two samples */
ene_tx_sample(dev);
@@ -761,16 +979,15 @@ static int ene_transmit(void *data, int *buf, u32 n)
spin_unlock_irqrestore(&dev->hw_lock, flags);
if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) {
- ene_dbg("TX: timeout");
+ dbg("TX: timeout");
spin_lock_irqsave(&dev->hw_lock, flags);
- ene_tx_complete(dev);
+ ene_tx_disable(dev);
spin_unlock_irqrestore(&dev->hw_lock, flags);
} else
- ene_dbg("TX: done");
+ dbg("TX: done");
return n;
}
-
/* probe entry */
static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
{
@@ -785,121 +1002,103 @@ static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
if (!input_dev || !ir_props || !dev)
- goto error;
+ goto error1;
/* validate resources */
error = -ENODEV;
if (!pnp_port_valid(pnp_dev, 0) ||
- pnp_port_len(pnp_dev, 0) < ENE_MAX_IO)
+ pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
goto error;
if (!pnp_irq_valid(pnp_dev, 0))
goto error;
- dev->hw_io = pnp_port_start(pnp_dev, 0);
- dev->irq = pnp_irq(pnp_dev, 0);
spin_lock_init(&dev->hw_lock);
/* claim the resources */
error = -EBUSY;
- if (!request_region(dev->hw_io, ENE_MAX_IO, ENE_DRIVER_NAME))
+ dev->hw_io = pnp_port_start(pnp_dev, 0);
+ if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
+ dev->hw_io = -1;
+ dev->irq = -1;
goto error;
+ }
+ dev->irq = pnp_irq(pnp_dev, 0);
if (request_irq(dev->irq, ene_isr,
- IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev))
+ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
+ dev->irq = -1;
goto error;
+ }
pnp_set_drvdata(pnp_dev, dev);
dev->pnp_dev = pnp_dev;
+ /* don't allow too short/long sample periods */
+ if (sample_period < 5 || sample_period > 0x7F)
+ sample_period = ENE_DEFAULT_SAMPLE_PERIOD;
+
/* detect hardware version and features */
error = ene_hw_detect(dev);
if (error)
goto error;
- ene_setup_settings(dev);
-
if (!dev->hw_learning_and_tx_capable && txsim) {
- dev->hw_learning_and_tx_capable = 1;
+ dev->hw_learning_and_tx_capable = true;
setup_timer(&dev->tx_sim_timer, ene_tx_irqsim,
(long unsigned int)dev);
- ene_printk(KERN_WARNING,
- "Simulation of TX activated\n");
+ ene_warn("Simulation of TX activated");
}
+ if (!dev->hw_learning_and_tx_capable)
+ learning_mode_force = false;
+
ir_props->driver_type = RC_DRIVER_IR_RAW;
ir_props->allowed_protos = IR_TYPE_ALL;
ir_props->priv = dev;
ir_props->open = ene_open;
ir_props->close = ene_close;
- ir_props->min_timeout = ENE_MINGAP * 1000;
- ir_props->max_timeout = ENE_MAXGAP * 1000;
- ir_props->timeout = ENE_MAXGAP * 1000;
-
- if (dev->hw_revision == ENE_HW_B)
- ir_props->s_idle = ene_rx_set_idle;
-
+ ir_props->s_idle = ene_set_idle;
dev->props = ir_props;
dev->idev = input_dev;
- /* don't allow too short/long sample periods */
- if (sample_period < 5 || sample_period > 0x7F)
- sample_period = -1;
-
- /* choose default sample period */
- if (sample_period == -1) {
-
- sample_period = 50;
-
- /* on revB, hardware idle mode eats first sample
- if we set too low sample period */
- if (dev->hw_revision == ENE_HW_B && enable_idle)
- sample_period = 75;
- }
-
- ir_props->rx_resolution = sample_period * 1000;
-
if (dev->hw_learning_and_tx_capable) {
-
ir_props->s_learning_mode = ene_set_learning_mode;
-
- if (input == 0)
- ir_props->s_rx_carrier_range = ene_set_rec_carrier;
-
init_completion(&dev->tx_complete);
ir_props->tx_ir = ene_transmit;
ir_props->s_tx_mask = ene_set_tx_mask;
ir_props->s_tx_carrier = ene_set_tx_carrier;
- ir_props->tx_resolution = ENE_TX_SMPL_PERIOD * 1000;
- /* ir_props->s_carrier_report = ene_set_carrier_report; */
+ ir_props->s_tx_duty_cycle = ene_set_tx_duty_cycle;
+ ir_props->s_carrier_report = ene_set_carrier_report;
}
+ ene_rx_setup_hw_buffer(dev);
+ ene_setup_default_settings(dev);
+ ene_setup_hw_settings(dev);
- device_set_wakeup_capable(&pnp_dev->dev, 1);
- device_set_wakeup_enable(&pnp_dev->dev, 1);
+ device_set_wakeup_capable(&pnp_dev->dev, true);
+ device_set_wakeup_enable(&pnp_dev->dev, true);
if (dev->hw_learning_and_tx_capable)
input_dev->name = "ENE eHome Infrared Remote Transceiver";
else
input_dev->name = "ENE eHome Infrared Remote Receiver";
-
error = -ENODEV;
if (ir_input_register(input_dev, RC_MAP_RC6_MCE, ir_props,
ENE_DRIVER_NAME))
goto error;
-
- ene_printk(KERN_NOTICE, "driver has been succesfully loaded\n");
+ ene_notice("driver has been succesfully loaded");
return 0;
error:
- if (dev->irq)
+ if (dev && dev->irq >= 0)
free_irq(dev->irq, dev);
- if (dev->hw_io)
- release_region(dev->hw_io, ENE_MAX_IO);
-
+ if (dev && dev->hw_io >= 0)
+ release_region(dev->hw_io, ENE_IO_SIZE);
+error1:
input_free_device(input_dev);
kfree(ir_props);
kfree(dev);
@@ -914,10 +1113,11 @@ static void ene_remove(struct pnp_dev *pnp_dev)
spin_lock_irqsave(&dev->hw_lock, flags);
ene_rx_disable(dev);
+ ene_rx_restore_hw_buffer(dev);
spin_unlock_irqrestore(&dev->hw_lock, flags);
free_irq(dev->irq, dev);
- release_region(dev->hw_io, ENE_MAX_IO);
+ release_region(dev->hw_io, ENE_IO_SIZE);
ir_input_unregister(dev->idev);
kfree(dev->props);
kfree(dev);
@@ -927,28 +1127,29 @@ static void ene_remove(struct pnp_dev *pnp_dev)
static void ene_enable_wake(struct ene_device *dev, int enable)
{
enable = enable && device_may_wakeup(&dev->pnp_dev->dev);
-
- ene_dbg("wake on IR %s", enable ? "enabled" : "disabled");
-
- ene_hw_write_reg_mask(dev, ENE_FW1, enable ?
- ENE_FW1_WAKE : 0, ENE_FW1_WAKE);
+ dbg("wake on IR %s", enable ? "enabled" : "disabled");
+ ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable);
}
#ifdef CONFIG_PM
static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
{
struct ene_device *dev = pnp_get_drvdata(pnp_dev);
- ene_enable_wake(dev, 1);
+ ene_enable_wake(dev, true);
+
+ /* TODO: add support for wake pattern */
return 0;
}
static int ene_resume(struct pnp_dev *pnp_dev)
{
struct ene_device *dev = pnp_get_drvdata(pnp_dev);
- if (dev->in_use)
+ ene_setup_hw_settings(dev);
+
+ if (dev->rx_enabled)
ene_rx_enable(dev);
- ene_enable_wake(dev, 0);
+ ene_enable_wake(dev, false);
return 0;
}
#endif
@@ -956,7 +1157,7 @@ static int ene_resume(struct pnp_dev *pnp_dev)
static void ene_shutdown(struct pnp_dev *pnp_dev)
{
struct ene_device *dev = pnp_get_drvdata(pnp_dev);
- ene_enable_wake(dev, 1);
+ ene_enable_wake(dev, true);
}
static const struct pnp_device_id ene_ids[] = {
@@ -994,18 +1195,11 @@ static void ene_exit(void)
module_param(sample_period, int, S_IRUGO);
MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)");
-module_param(enable_idle, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(enable_idle,
- "Enables turning off signal sampling after long inactivity time; "
- "if disabled might help detecting input signal (default: enabled)"
- " (KB3926B only)");
-
-module_param(input, bool, S_IRUGO);
-MODULE_PARM_DESC(input, "select which input to use "
- "0 - auto, 1 - standard, 2 - wideband(KB3926C+)");
+module_param(learning_mode_force, bool, S_IRUGO);
+MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default");
module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Enable debug (debug=2 verbose debug output)");
+MODULE_PARM_DESC(debug, "Debug level");
module_param(txsim, bool, S_IRUGO);
MODULE_PARM_DESC(txsim,
@@ -1013,8 +1207,8 @@ MODULE_PARM_DESC(txsim,
MODULE_DEVICE_TABLE(pnp, ene_ids);
MODULE_DESCRIPTION
- ("Infrared input driver for KB3926B/KB3926C/KB3926D "
- "(aka ENE0100/ENE0200/ENE0201) CIR port");
+ ("Infrared input driver for KB3926B/C/D/E/F "
+ "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port");
MODULE_AUTHOR("Maxim Levitsky");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/IR/ene_ir.h b/drivers/media/IR/ene_ir.h
index 54c76af0d033..f5870667a433 100644
--- a/drivers/media/IR/ene_ir.h
+++ b/drivers/media/IR/ene_ir.h
@@ -1,5 +1,5 @@
/*
- * driver for ENE KB3926 B/C/D CIR (also known as ENE0XXX)
+ * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX)
*
* Copyright (C) 2010 Maxim Levitsky
*
@@ -26,43 +26,50 @@
#define ENE_ADDR_HI 1 /* hi byte of register address */
#define ENE_ADDR_LO 2 /* low byte of register address */
#define ENE_IO 3 /* read/write window */
-#define ENE_MAX_IO 4
+#define ENE_IO_SIZE 4
-/* 8 bytes of samples, divided in 2 halfs*/
-#define ENE_SAMPLE_BUFFER 0xF8F0 /* regular sample buffer */
-#define ENE_SAMPLE_SPC_MASK 0x80 /* sample is space */
-#define ENE_SAMPLE_VALUE_MASK 0x7F
-#define ENE_SAMPLE_OVERFLOW 0x7F
-#define ENE_SAMPLES_SIZE 4
+/* 8 bytes of samples, divided in 2 packets*/
+#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */
+#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */
+#define ENE_FW_PACKET_SIZE 4
-/* fan input sample buffer */
-#define ENE_SAMPLE_BUFFER_FAN 0xF8FB /* this buffer holds high byte of */
- /* each sample of normal buffer */
-#define ENE_FAN_SMPL_PULS_MSK 0x8000 /* this bit of combined sample */
- /* if set, says that sample is pulse */
-#define ENE_FAN_VALUE_MASK 0x0FFF /* mask for valid bits of the value */
-
-/* first firmware register */
-#define ENE_FW1 0xF8F8
+/* first firmware flag register */
+#define ENE_FW1 0xF8F8 /* flagr */
#define ENE_FW1_ENABLE 0x01 /* enable fw processing */
#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */
+#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/
+#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/
+#define ENE_FW1_LED_ON 0x10 /* turn on a led */
+
+#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */
#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */
#define ENE_FW1_IRQ 0x80 /* enable interrupt */
-/* second firmware register */
-#define ENE_FW2 0xF8F9
-#define ENE_FW2_BUF_HIGH 0x01 /* which half of the buffer to read */
-#define ENE_FW2_IRQ_CLR 0x04 /* clear this on IRQ */
-#define ENE_FW2_GP40_AS_LEARN 0x08 /* normal input is used as */
- /* learning input */
-#define ENE_FW2_FAN_AS_NRML_IN 0x40 /* fan is used as normal input */
+/* second firmware flag register */
+#define ENE_FW2 0xF8F9 /* flagw */
+#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */
+#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/
+#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */
+#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */
+#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */
+
+#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/
#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */
+/* firmware RX pointer for new style buffer */
+#define ENE_FW_RX_POINTER 0xF8FA
+
+/* high parts of samples for fan input (8 samples)*/
+#define ENE_FW_SMPL_BUF_FAN 0xF8FB
+#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */
+#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */
+#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
+
/* transmitter ports */
-#define ENE_TX_PORT2 0xFC01 /* this enables one or both */
-#define ENE_TX_PORT2_EN 0x20 /* TX ports */
-#define ENE_TX_PORT1 0xFC08
-#define ENE_TX_PORT1_EN 0x02
+#define ENE_GPIOFS1 0xFC01
+#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */
+#define ENE_GPIOFS8 0xFC08
+#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */
/* IRQ registers block (for revision B) */
#define ENEB_IRQ 0xFD09 /* IRQ number */
@@ -70,98 +77,100 @@
#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */
-/* fan as input settings - only if learning capable */
+/* fan as input settings */
#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */
#define ENE_FAN_AS_IN1_EN 0xCD
#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */
#define ENE_FAN_AS_IN2_EN 0x03
-#define ENE_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
/* IRQ registers block (for revision C,D) */
-#define ENEC_IRQ 0xFE9B /* new irq settings register */
-#define ENEC_IRQ_MASK 0x0F /* irq number mask */
-#define ENEC_IRQ_UNK_EN 0x10 /* always enabled */
-#define ENEC_IRQ_STATUS 0x20 /* irq status and ACK */
+#define ENE_IRQ 0xFE9B /* new irq settings register */
+#define ENE_IRQ_MASK 0x0F /* irq number mask */
+#define ENE_IRQ_UNK_EN 0x10 /* always enabled */
+#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */
-/* CIR block settings */
-#define ENE_CIR_CONF1 0xFEC0
-#define ENE_CIR_CONF1_TX_CLEAR 0x01 /* clear that on revC */
- /* while transmitting */
-#define ENE_CIR_CONF1_RX_ON 0x07 /* normal receiver enabled */
-#define ENE_CIR_CONF1_LEARN1 0x08 /* enabled on learning mode */
-#define ENE_CIR_CONF1_TX_ON 0x30 /* enabled on transmit */
-#define ENE_CIR_CONF1_TX_CARR 0x80 /* send TX carrier or not */
+/* CIR Config register #1 */
+#define ENE_CIRCFG 0xFEC0
+#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */
+#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */
+#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */
+#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */
-#define ENE_CIR_CONF2 0xFEC1 /* unknown setting = 0 */
-#define ENE_CIR_CONF2_LEARN2 0x10 /* set on enable learning */
-#define ENE_CIR_CONF2_GPIO40DIS 0x20 /* disable input via gpio40 */
+#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */
+#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */
+#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */
+#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */
-#define ENE_CIR_SAMPLE_PERIOD 0xFEC8 /* sample period in us */
-#define ENE_CIR_SAMPLE_OVERFLOW 0x80 /* interrupt on overflows if set */
+/* CIR config register #2 */
+#define ENE_CIRCFG2 0xFEC1
+#define ENE_CIRCFG2_RLC 0x00
+#define ENE_CIRCFG2_RC5 0x01
+#define ENE_CIRCFG2_RC6 0x02
+#define ENE_CIRCFG2_NEC 0x03
+#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */
+#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */
+#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */
+#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */
+
+/* Knobs for protocol decoding - will document when/if will use them */
+#define ENE_CIRPF 0xFEC2
+#define ENE_CIRHIGH 0xFEC3
+#define ENE_CIRBIT 0xFEC4
+#define ENE_CIRSTART 0xFEC5
+#define ENE_CIRSTART2 0xFEC6
+
+/* Actual register which contains RLC RX data - read by firmware */
+#define ENE_CIRDAT_IN 0xFEC7
-/* Two byte tx buffer */
-#define ENE_TX_INPUT1 0xFEC9
-#define ENE_TX_INPUT2 0xFECA
-#define ENE_TX_PULSE_MASK 0x80 /* Transmitted sample is pulse */
-#define ENE_TX_SMLP_MASK 0x7F
-#define ENE_TX_SMPL_PERIOD 50 /* transmit sample period - fixed */
+/* RLC configuration - sample period (1us resulution) + idle mode */
+#define ENE_CIRRLC_CFG 0xFEC8
+#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */
+#define ENE_DEFAULT_SAMPLE_PERIOD 50
+
+/* Two byte RLC TX buffer */
+#define ENE_CIRRLC_OUT0 0xFEC9
+#define ENE_CIRRLC_OUT1 0xFECA
+#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */
+#define ENE_CIRRLC_OUT_MASK 0x7F
-/* Unknown TX setting - TX sample period ??? */
-#define ENE_TX_UNK1 0xFECB /* set to 0x63 */
+/* Carrier detect setting
+ * Low nibble - number of carrier pulses to average
+ * High nibble - number of initial carrier pulses to discard
+ */
+#define ENE_CIRCAR_PULS 0xFECB
-/* Current received carrier period */
-#define ENE_RX_CARRIER 0xFECC /* RX period (500 ns) */
-#define ENE_RX_CARRIER_VALID 0x80 /* Register content valid */
+/* detected RX carrier period (resolution: 500 ns) */
+#define ENE_CIRCAR_PRD 0xFECC
+#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */
+/* detected RX carrier pulse width (resolution: 500 ns) */
+#define ENE_CIRCAR_HPRD 0xFECD
-/* TX period (1/carrier) */
-#define ENE_TX_PERIOD 0xFECE /* TX period (500 ns) */
-#define ENE_TX_PERIOD_UNKBIT 0x80 /* This bit set on transmit*/
-#define ENE_TX_PERIOD_PULSE 0xFECF /* TX pulse period (500 ns)*/
+/* TX period (resolution: 500 ns, minimum 2)*/
+#define ENE_CIRMOD_PRD 0xFECE
+#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/
+
+#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */
+#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */
+
+/* TX pulse width (resolution: 500 ns)*/
+#define ENE_CIRMOD_HPRD 0xFECF
/* Hardware versions */
-#define ENE_HW_VERSION 0xFF00 /* hardware revision */
+#define ENE_ECHV 0xFF00 /* hardware revision */
#define ENE_PLLFRH 0xFF16
#define ENE_PLLFRL 0xFF17
+#define ENE_DEFAULT_PLL_FREQ 1000
-#define ENE_HW_UNK 0xFF1D
-#define ENE_HW_UNK_CLR 0x04
-#define ENE_HW_VER_MAJOR 0xFF1E /* chip version */
-#define ENE_HW_VER_MINOR 0xFF1F
+#define ENE_ECSTS 0xFF1D
+#define ENE_ECSTS_RSRVD 0x04
+
+#define ENE_ECVER_MAJOR 0xFF1E /* chip version */
+#define ENE_ECVER_MINOR 0xFF1F
#define ENE_HW_VER_OLD 0xFD00
-/* Normal/Learning carrier ranges - only valid if we have learning input*/
-/* TODO: test */
-#define ENE_NORMAL_RX_LOW 34
-#define ENE_NORMAL_RX_HI 38
-
-/* Tx carrier range */
-/* Hardware might be able to do more, but this range is enough for
- all purposes */
-#define ENE_TX_PERIOD_MAX 32 /* corresponds to 29.4 kHz */
-#define ENE_TX_PERIOD_MIN 16 /* corrsponds to 62.5 kHz */
-
-
-
-/* Minimal and maximal gaps */
-
-/* Normal case:
- Minimal gap is 0x7F * sample period
- Maximum gap depends on hardware.
- For KB3926B, it is unlimited, for newer models its around
- 250000, after which HW stops sending samples, and that is
- not possible to change */
-
-/* Fan case:
- Both minimal and maximal gaps are same, and equal to 0xFFF * 0x61
- And there is nothing to change this setting
-*/
-
-#define ENE_MAXGAP 250000
-#define ENE_MINGAP (127 * sample_period)
-
/******************************************************************************/
#define ENE_DRIVER_NAME "ene_ir"
@@ -171,46 +180,60 @@
#define ENE_HW_B 1 /* 3926B */
#define ENE_HW_C 2 /* 3926C */
-#define ENE_HW_D 3 /* 3926D */
+#define ENE_HW_D 3 /* 3926D or later */
#define ene_printk(level, text, ...) \
- printk(level ENE_DRIVER_NAME ": " text, ## __VA_ARGS__)
+ printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
-#define ene_dbg(text, ...) \
- if (debug) \
- printk(KERN_DEBUG \
- ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
+#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
+#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
-#define ene_dbg_verbose(text, ...) \
- if (debug > 1) \
- printk(KERN_DEBUG \
- ENE_DRIVER_NAME ": " text "\n" , ## __VA_ARGS__)
+#define __dbg(level, format, ...) \
+ do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG ENE_DRIVER_NAME \
+ ": " format "\n", ## __VA_ARGS__); \
+ } while (0)
+
+
+#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__)
+#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__)
+
+#define MS_TO_NS(msec) ((msec) * 1000)
struct ene_device {
struct pnp_dev *pnp_dev;
struct input_dev *idev;
struct ir_dev_props *props;
- int in_use;
/* hw IO settings */
- unsigned long hw_io;
+ long hw_io;
int irq;
spinlock_t hw_lock;
/* HW features */
int hw_revision; /* hardware revision */
- bool hw_learning_and_tx_capable; /* learning capable */
- bool hw_gpio40_learning; /* gpio40 is learning */
- bool hw_fan_as_normal_input; /* fan input is used as */
- /* regular input */
+ bool hw_use_gpio_0a; /* gpio0a is demodulated input*/
+ bool hw_extra_buffer; /* hardware has 'extra buffer' */
+ bool hw_fan_input; /* fan input is IR data source */
+ bool hw_learning_and_tx_capable; /* learning & tx capable */
+ int pll_freq;
+ int buffer_len;
+
+ /* Extra RX buffer location */
+ int extra_buf1_address;
+ int extra_buf1_len;
+ int extra_buf2_address;
+ int extra_buf2_len;
+
/* HW state*/
- int rx_pointer; /* hw pointer to rx buffer */
+ int r_pointer; /* pointer to next sample to read */
+ int w_pointer; /* pointer to next sample hw will write */
bool rx_fan_input_inuse; /* is fan input in use for rx*/
int tx_reg; /* current reg used for TX */
u8 saved_conf1; /* saved FEC0 reg */
-
- /* TX sample handling */
unsigned int tx_sample; /* current sample for TX */
bool tx_sample_pulse; /* current sample is pulse */
@@ -229,7 +252,11 @@ struct ene_device {
int transmitter_mask;
/* RX settings */
- bool learning_enabled; /* learning input enabled */
+ bool learning_mode_enabled; /* learning input enabled */
bool carrier_detect_enabled; /* carrier detect enabled */
int rx_period_adjust;
+ bool rx_enabled;
};
+
+static int ene_irq_status(struct ene_device *dev);
+static void ene_rx_read_hw_pointer(struct ene_device *dev);
diff --git a/drivers/media/IR/imon.c b/drivers/media/IR/imon.c
index faed5a332c71..bc118066bc38 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/IR/imon.c
@@ -1,7 +1,7 @@
/*
* imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
*
- * Copyright(C) 2009 Jarod Wilson
+ * Copyright(C) 2010 Jarod Wilson
* Portions based on the original lirc_imon driver,
* Copyright(C) 2004 Venky Raju(dev@venky.ws)
*
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
#include
#include
#include
@@ -44,7 +46,7 @@
#define MOD_AUTHOR "Jarod Wilson "
#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
#define MOD_NAME "imon"
-#define MOD_VERSION "0.9.1"
+#define MOD_VERSION "0.9.2"
#define DISPLAY_MINOR_BASE 144
#define DEVICE_NAME "lcd%d"
@@ -121,21 +123,26 @@ struct imon_context {
u16 vendor; /* usb vendor ID */
u16 product; /* usb product ID */
- struct input_dev *idev; /* input device for remote */
+ struct input_dev *rdev; /* input device for remote */
+ struct input_dev *idev; /* input device for panel & IR mouse */
struct input_dev *touch; /* input device for touchscreen */
+ spinlock_t kc_lock; /* make sure we get keycodes right */
u32 kc; /* current input keycode */
u32 last_keycode; /* last reported input keycode */
+ u32 rc_scancode; /* the computed remote scancode */
+ u8 rc_toggle; /* the computed remote toggle bit */
u64 ir_type; /* iMON or MCE (RC6) IR protocol? */
- u8 mce_toggle_bit; /* last mce toggle bit */
bool release_code; /* some keys send a release code */
u8 display_type; /* store the display type */
bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */
+ char name_rdev[128]; /* rc input device name */
+ char phys_rdev[64]; /* rc input device phys path */
+
char name_idev[128]; /* input device name */
char phys_idev[64]; /* input device phys path */
- struct timer_list itimer; /* input device timer, need for rc6 */
char name_touch[128]; /* touch screen name */
char phys_touch[64]; /* touch screen phys path */
@@ -289,6 +296,9 @@ static const struct {
{ 0x000100000000ffeell, KEY_VOLUMEUP },
{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
{ 0x000000000100ffeell, KEY_MUTE },
+ /* 0xffdc iMON MCE VFD */
+ { 0x00010000ffffffeell, KEY_VOLUMEUP },
+ { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
/* iMON Knob values */
{ 0x000100ffffffffeell, KEY_VOLUMEUP },
{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
@@ -307,7 +317,7 @@ MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
static bool debug;
module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
static int display_type;
@@ -365,15 +375,14 @@ static int display_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
interface = usb_find_interface(&imon_driver, subminor);
if (!interface) {
- err("%s: could not find interface for minor %d",
- __func__, subminor);
+ pr_err("could not find interface for minor %d\n", subminor);
retval = -ENODEV;
goto exit;
}
ictx = usb_get_intfdata(interface);
if (!ictx) {
- err("%s: no context found for minor %d", __func__, subminor);
+ pr_err("no context found for minor %d\n", subminor);
retval = -ENODEV;
goto exit;
}
@@ -381,10 +390,10 @@ static int display_open(struct inode *inode, struct file *file)
mutex_lock(&ictx->lock);
if (!ictx->display_supported) {
- err("%s: display not supported by device", __func__);
+ pr_err("display not supported by device\n");
retval = -ENODEV;
} else if (ictx->display_isopen) {
- err("%s: display port is already open", __func__);
+ pr_err("display port is already open\n");
retval = -EBUSY;
} else {
ictx->display_isopen = true;
@@ -411,17 +420,17 @@ static int display_close(struct inode *inode, struct file *file)
ictx = file->private_data;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
mutex_lock(&ictx->lock);
if (!ictx->display_supported) {
- err("%s: display not supported by device", __func__);
+ pr_err("display not supported by device\n");
retval = -ENODEV;
} else if (!ictx->display_isopen) {
- err("%s: display is not open", __func__);
+ pr_err("display is not open\n");
retval = -EIO;
} else {
ictx->display_isopen = false;
@@ -500,19 +509,19 @@ static int send_packet(struct imon_context *ictx)
if (retval) {
ictx->tx.busy = false;
smp_rmb(); /* ensure later readers know we're not busy */
- err("%s: error submitting urb(%d)", __func__, retval);
+ pr_err("error submitting urb(%d)\n", retval);
} else {
/* Wait for transmission to complete (or abort) */
mutex_unlock(&ictx->lock);
retval = wait_for_completion_interruptible(
&ictx->tx.finished);
if (retval)
- err("%s: task interrupted", __func__);
+ pr_err("task interrupted\n");
mutex_lock(&ictx->lock);
retval = ictx->tx.status;
if (retval)
- err("%s: packet tx failed (%d)", __func__, retval);
+ pr_err("packet tx failed (%d)\n", retval);
}
kfree(control_req);
@@ -544,12 +553,12 @@ static int send_associate_24g(struct imon_context *ictx)
0x00, 0x00, 0x00, 0x20 };
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
if (!ictx->dev_present_intf0) {
- err("%s: no iMON device present", __func__);
+ pr_err("no iMON device present\n");
return -ENODEV;
}
@@ -577,7 +586,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
int i;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
@@ -638,8 +647,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
retval = send_packet(ictx);
if (retval) {
- err("%s: send_packet failed for packet %d",
- __func__, i);
+ pr_err("send_packet failed for packet %d\n", i);
break;
}
}
@@ -778,7 +786,7 @@ static struct attribute *imon_display_sysfs_entries[] = {
NULL
};
-static struct attribute_group imon_display_attribute_group = {
+static struct attribute_group imon_display_attr_group = {
.attrs = imon_display_sysfs_entries
};
@@ -787,7 +795,7 @@ static struct attribute *imon_rf_sysfs_entries[] = {
NULL
};
-static struct attribute_group imon_rf_attribute_group = {
+static struct attribute_group imon_rf_attr_group = {
.attrs = imon_rf_sysfs_entries
};
@@ -815,20 +823,20 @@ static ssize_t vfd_write(struct file *file, const char *buf,
ictx = file->private_data;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
mutex_lock(&ictx->lock);
if (!ictx->dev_present_intf0) {
- err("%s: no iMON device present", __func__);
+ pr_err("no iMON device present\n");
retval = -ENODEV;
goto exit;
}
if (n_bytes <= 0 || n_bytes > 32) {
- err("%s: invalid payload size", __func__);
+ pr_err("invalid payload size\n");
retval = -EINVAL;
goto exit;
}
@@ -854,8 +862,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
retval = send_packet(ictx);
if (retval) {
- err("%s: send packet failed for packet #%d",
- __func__, seq/2);
+ pr_err("send packet failed for packet #%d\n", seq / 2);
goto exit;
} else {
seq += 2;
@@ -869,8 +876,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
ictx->usb_tx_buf[7] = (unsigned char) seq;
retval = send_packet(ictx);
if (retval)
- err("%s: send packet failed for packet #%d",
- __func__, seq / 2);
+ pr_err("send packet failed for packet #%d\n", seq / 2);
exit:
mutex_unlock(&ictx->lock);
@@ -899,21 +905,20 @@ static ssize_t lcd_write(struct file *file, const char *buf,
ictx = file->private_data;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
mutex_lock(&ictx->lock);
if (!ictx->display_supported) {
- err("%s: no iMON display present", __func__);
+ pr_err("no iMON display present\n");
retval = -ENODEV;
goto exit;
}
if (n_bytes != 8) {
- err("%s: invalid payload size: %d (expecting 8)",
- __func__, (int) n_bytes);
+ pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes);
retval = -EINVAL;
goto exit;
}
@@ -925,7 +930,7 @@ static ssize_t lcd_write(struct file *file, const char *buf,
retval = send_packet(ictx);
if (retval) {
- err("%s: send packet failed!", __func__);
+ pr_err("send packet failed!\n");
goto exit;
} else {
dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
@@ -957,17 +962,6 @@ static void usb_tx_callback(struct urb *urb)
complete(&ictx->tx.finished);
}
-/**
- * mce/rc6 keypresses have no distinct release code, use timer
- */
-static void imon_mce_timeout(unsigned long data)
-{
- struct imon_context *ictx = (struct imon_context *)data;
-
- input_report_key(ictx->idev, ictx->last_keycode, 0);
- input_sync(ictx->idev);
-}
-
/**
* report touchscreen input
*/
@@ -1008,14 +1002,11 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
ir_proto_packet[0] = 0x01;
pad_mouse = false;
- init_timer(&ictx->itimer);
- ictx->itimer.data = (unsigned long)ictx;
- ictx->itimer.function = imon_mce_timeout;
break;
case IR_TYPE_UNKNOWN:
case IR_TYPE_OTHER:
dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
- if (pad_stabilize)
+ if (pad_stabilize && !nomouse)
pad_mouse = true;
else {
dev_dbg(dev, "PAD stabilize functionality disabled\n");
@@ -1027,7 +1018,7 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
default:
dev_warn(dev, "Unsupported IR protocol specified, overriding "
"to iMON IR protocol\n");
- if (pad_stabilize)
+ if (pad_stabilize && !nomouse)
pad_mouse = true;
else {
dev_dbg(dev, "PAD stabilize functionality disabled\n");
@@ -1149,20 +1140,21 @@ static int stabilize(int a, int b, u16 timeout, u16 threshold)
return result;
}
-static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
+static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
{
- u32 scancode = be32_to_cpu(hw_code);
u32 keycode;
u32 release;
bool is_release_code = false;
/* Look for the initial press of a button */
- keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+ keycode = ir_g_keycode_from_table(ictx->rdev, scancode);
+ ictx->rc_toggle = 0x0;
+ ictx->rc_scancode = scancode;
/* Look for the release of a button */
if (keycode == KEY_RESERVED) {
release = scancode & ~0x4000;
- keycode = ir_g_keycode_from_table(ictx->idev, release);
+ keycode = ir_g_keycode_from_table(ictx->rdev, release);
if (keycode != KEY_RESERVED)
is_release_code = true;
}
@@ -1172,9 +1164,8 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
return keycode;
}
-static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
+static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
{
- u32 scancode = be32_to_cpu(hw_code);
u32 keycode;
#define MCE_KEY_MASK 0x7000
@@ -1188,18 +1179,21 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
* but we can't or them into all codes, as some keys are decoded in
* a different way w/o the same use of the toggle bit...
*/
- if ((scancode >> 24) & 0x80)
+ if (scancode & 0x80000000)
scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
- keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+ ictx->rc_scancode = scancode;
+ keycode = ir_g_keycode_from_table(ictx->rdev, scancode);
+
+ /* not used in mce mode, but make sure we know its false */
+ ictx->release_code = false;
return keycode;
}
-static u32 imon_panel_key_lookup(u64 hw_code)
+static u32 imon_panel_key_lookup(u64 code)
{
int i;
- u64 code = be64_to_cpu(hw_code);
u32 keycode = KEY_RESERVED;
for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
@@ -1219,6 +1213,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
u8 right_shift = 1;
bool mouse_input = true;
int dir = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ictx->kc_lock, flags);
/* newer iMON device PAD or mouse button */
if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
@@ -1250,6 +1247,8 @@ static bool imon_mouse_event(struct imon_context *ictx,
} else
mouse_input = false;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
if (mouse_input) {
dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
@@ -1264,7 +1263,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
buf[1] >> right_shift & 0x1);
}
input_sync(ictx->idev);
+ spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
}
return mouse_input;
@@ -1286,8 +1287,8 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
int dir = 0;
char rel_x = 0x00, rel_y = 0x00;
u16 timeout, threshold;
- u64 temp_key;
- u32 remote_key;
+ u32 scancode = KEY_RESERVED;
+ unsigned long flags;
/*
* The imon directional pad functions more like a touchpad. Bytes 3 & 4
@@ -1311,26 +1312,36 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
+ spin_lock_irqsave(&ictx->kc_lock,
+ flags);
ictx->kc = KEY_UNKNOWN;
+ spin_unlock_irqrestore(&ictx->kc_lock,
+ flags);
return;
}
buf[2] = dir & 0xFF;
buf[3] = (dir >> 8) & 0xFF;
- memcpy(&temp_key, buf, sizeof(temp_key));
- remote_key = (u32) (le64_to_cpu(temp_key)
- & 0xffffffff);
- ictx->kc = imon_remote_key_lookup(ictx,
- remote_key);
+ scancode = be32_to_cpu(*((u32 *)buf));
}
} else {
+ /*
+ * Hack alert: instead of using keycodes, we have
+ * to use hard-coded scancodes here...
+ */
if (abs(rel_y) > abs(rel_x)) {
buf[2] = (rel_y > 0) ? 0x7F : 0x80;
buf[3] = 0;
- ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+ if (rel_y > 0)
+ scancode = 0x01007f00; /* KEY_DOWN */
+ else
+ scancode = 0x01008000; /* KEY_UP */
} else {
buf[2] = 0;
buf[3] = (rel_x > 0) ? 0x7F : 0x80;
- ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+ if (rel_x > 0)
+ scancode = 0x0100007f; /* KEY_RIGHT */
+ else
+ scancode = 0x01000080; /* KEY_LEFT */
}
}
@@ -1367,34 +1378,56 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
+ spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->kc = KEY_UNKNOWN;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
}
buf[2] = dir & 0xFF;
buf[3] = (dir >> 8) & 0xFF;
- memcpy(&temp_key, buf, sizeof(temp_key));
- remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
- ictx->kc = imon_remote_key_lookup(ictx, remote_key);
+ scancode = be32_to_cpu(*((u32 *)buf));
} else {
+ /*
+ * Hack alert: instead of using keycodes, we have
+ * to use hard-coded scancodes here...
+ */
if (abs(rel_y) > abs(rel_x)) {
buf[2] = (rel_y > 0) ? 0x7F : 0x80;
buf[3] = 0;
- ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+ if (rel_y > 0)
+ scancode = 0x01007f00; /* KEY_DOWN */
+ else
+ scancode = 0x01008000; /* KEY_UP */
} else {
buf[2] = 0;
buf[3] = (rel_x > 0) ? 0x7F : 0x80;
- ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+ if (rel_x > 0)
+ scancode = 0x0100007f; /* KEY_RIGHT */
+ else
+ scancode = 0x01000080; /* KEY_LEFT */
}
}
}
+
+ if (scancode) {
+ spin_lock_irqsave(&ictx->kc_lock, flags);
+ ictx->kc = imon_remote_key_lookup(ictx, scancode);
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+ }
}
+/**
+ * figure out if these is a press or a release. We don't actually
+ * care about repeats, as those will be auto-generated within the IR
+ * subsystem for repeating scancodes.
+ */
static int imon_parse_press_type(struct imon_context *ictx,
unsigned char *buf, u8 ktype)
{
int press_type = 0;
- int rep_delay = ictx->idev->rep[REP_DELAY];
- int rep_period = ictx->idev->rep[REP_PERIOD];
+ unsigned long flags;
+
+ spin_lock_irqsave(&ictx->kc_lock, flags);
/* key release of 0x02XXXXXX key */
if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
@@ -1410,22 +1443,10 @@ static int imon_parse_press_type(struct imon_context *ictx,
buf[2] == 0x81 && buf[3] == 0xb7)
ictx->kc = ictx->last_keycode;
- /* mce-specific button handling */
+ /* mce-specific button handling, no keyup events */
else if (ktype == IMON_KEY_MCE) {
- /* initial press */
- if (ictx->kc != ictx->last_keycode
- || buf[2] != ictx->mce_toggle_bit) {
- ictx->last_keycode = ictx->kc;
- ictx->mce_toggle_bit = buf[2];
- press_type = 1;
- mod_timer(&ictx->itimer,
- jiffies + msecs_to_jiffies(rep_delay));
- /* repeat */
- } else {
- press_type = 2;
- mod_timer(&ictx->itimer,
- jiffies + msecs_to_jiffies(rep_period));
- }
+ ictx->rc_toggle = buf[2];
+ press_type = 1;
/* incoherent or irrelevant data */
} else if (ictx->kc == KEY_RESERVED)
@@ -1439,6 +1460,8 @@ static int imon_parse_press_type(struct imon_context *ictx,
else
press_type = 1;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
return press_type;
}
@@ -1451,41 +1474,45 @@ static void imon_incoming_packet(struct imon_context *ictx,
int len = urb->actual_length;
unsigned char *buf = urb->transfer_buffer;
struct device *dev = ictx->dev;
+ unsigned long flags;
u32 kc;
bool norelease = false;
int i;
- u64 temp_key;
- u64 panel_key = 0;
- u32 remote_key = 0;
- struct input_dev *idev = NULL;
+ u64 scancode;
+ struct input_dev *rdev = NULL;
+ struct ir_input_dev *irdev = NULL;
int press_type = 0;
int msec;
struct timeval t;
static struct timeval prev_time = { 0, 0 };
- u8 ktype = IMON_KEY_IMON;
+ u8 ktype;
- idev = ictx->idev;
+ rdev = ictx->rdev;
+ irdev = input_get_drvdata(rdev);
/* filter out junk data on the older 0xffdc imon devices */
if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
return;
/* Figure out what key was pressed */
- memcpy(&temp_key, buf, sizeof(temp_key));
if (len == 8 && buf[7] == 0xee) {
+ scancode = be64_to_cpu(*((u64 *)buf));
ktype = IMON_KEY_PANEL;
- panel_key = le64_to_cpu(temp_key);
- kc = imon_panel_key_lookup(panel_key);
+ kc = imon_panel_key_lookup(scancode);
} else {
- remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
+ scancode = be32_to_cpu(*((u32 *)buf));
if (ictx->ir_type == IR_TYPE_RC6) {
+ ktype = IMON_KEY_IMON;
if (buf[0] == 0x80)
ktype = IMON_KEY_MCE;
- kc = imon_mce_key_lookup(ictx, remote_key);
- } else
- kc = imon_remote_key_lookup(ictx, remote_key);
+ kc = imon_mce_key_lookup(ictx, scancode);
+ } else {
+ ktype = IMON_KEY_IMON;
+ kc = imon_remote_key_lookup(ictx, scancode);
+ }
}
+ spin_lock_irqsave(&ictx->kc_lock, flags);
/* keyboard/mouse mode toggle button */
if (kc == KEY_KEYBOARD && !ictx->release_code) {
ictx->last_keycode = kc;
@@ -1493,6 +1520,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
dev_dbg(dev, "toggling to %s mode\n",
ictx->pad_mouse ? "mouse" : "keyboard");
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
} else {
ictx->pad_mouse = 0;
@@ -1501,11 +1529,13 @@ static void imon_incoming_packet(struct imon_context *ictx,
}
ictx->kc = kc;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
/* send touchscreen events through input subsystem if touchpad data */
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
buf[7] == 0x86) {
imon_touch_event(ictx, buf);
+ return;
/* look for mouse events with pad in mouse mode */
} else if (ictx->pad_mouse) {
@@ -1533,36 +1563,55 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type < 0)
goto not_input_data;
+ spin_lock_irqsave(&ictx->kc_lock, flags);
if (ictx->kc == KEY_UNKNOWN)
goto unknown_key;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
- /* KEY_MUTE repeats from MCE and knob need to be suppressed */
- if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode)
- && (buf[7] == 0xee || ktype == IMON_KEY_MCE)) {
+ if (ktype != IMON_KEY_PANEL) {
+ if (press_type == 0)
+ ir_keyup(irdev);
+ else {
+ ir_keydown(rdev, 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);
+ }
+ return;
+ }
+
+ /* Only panel type events left to process now */
+ spin_lock_irqsave(&ictx->kc_lock, flags);
+
+ /* KEY_MUTE repeats from knob need to be suppressed */
+ if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
do_gettimeofday(&t);
msec = tv2int(&t, &prev_time);
prev_time = t;
- if (msec < idev->rep[REP_DELAY])
+ if (msec < ictx->idev->rep[REP_DELAY]) {
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
+ }
}
+ kc = ictx->kc;
- input_report_key(idev, ictx->kc, press_type);
- input_sync(idev);
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
- /* panel keys and some remote keys don't generate a release */
- if (panel_key || norelease) {
- input_report_key(idev, ictx->kc, 0);
- input_sync(idev);
- }
+ input_report_key(ictx->idev, kc, press_type);
+ input_sync(ictx->idev);
- ictx->last_keycode = ictx->kc;
+ /* panel keys don't generate a release */
+ input_report_key(ictx->idev, kc, 0);
+ input_sync(ictx->idev);
+
+ ictx->last_keycode = kc;
return;
unknown_key:
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
- (panel_key ? be64_to_cpu(panel_key) :
- be32_to_cpu(remote_key)));
+ (long long)scancode);
return;
not_input_data:
@@ -1653,31 +1702,205 @@ static void usb_rx_callback_intf1(struct urb *urb)
usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
}
+/*
+ * The 0x15c2:0xffdc device ID was used for umpteen different imon
+ * devices, and all of them constantly spew interrupts, even when there
+ * is no actual data to report. However, byte 6 of this buffer looks like
+ * its unique across device variants, so we're trying to key off that to
+ * figure out which display type (if any) and what IR protocol the device
+ * actually supports. These devices have their IR protocol hard-coded into
+ * their firmware, they can't be changed on the fly like the newer hardware.
+ */
+static void imon_get_ffdc_type(struct imon_context *ictx)
+{
+ u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
+ u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
+ u64 allowed_protos = IR_TYPE_OTHER;
+
+ switch (ffdc_cfg_byte) {
+ /* iMON Knob, no display, iMON IR + vol knob */
+ case 0x21:
+ dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
+ ictx->display_supported = false;
+ break;
+ /* iMON 2.4G LT (usb stick), no display, iMON RF */
+ case 0x4e:
+ dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
+ ictx->display_supported = false;
+ ictx->rf_device = true;
+ break;
+ /* iMON VFD, no IR (does have vol knob tho) */
+ case 0x35:
+ dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ /* iMON VFD, iMON IR */
+ case 0x24:
+ case 0x85:
+ dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ /* iMON VFD, MCE IR */
+ case 0x9e:
+ dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ allowed_protos = IR_TYPE_RC6;
+ break;
+ /* iMON LCD, MCE IR */
+ case 0x9f:
+ dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
+ detected_display_type = IMON_DISPLAY_TYPE_LCD;
+ allowed_protos = IR_TYPE_RC6;
+ break;
+ default:
+ dev_info(ictx->dev, "Unknown 0xffdc device, "
+ "defaulting to VFD and iMON IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ }
+
+ printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
+
+ ictx->display_type = detected_display_type;
+ ictx->props->allowed_protos = allowed_protos;
+ ictx->ir_type = allowed_protos;
+}
+
+static void imon_set_display_type(struct imon_context *ictx)
+{
+ u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
+
+ /*
+ * Try to auto-detect the type of display if the user hasn't set
+ * it by hand via the display_type modparam. Default is VFD.
+ */
+
+ if (display_type == IMON_DISPLAY_TYPE_AUTO) {
+ switch (ictx->product) {
+ case 0xffdc:
+ /* set in imon_get_ffdc_type() */
+ configured_display_type = ictx->display_type;
+ break;
+ case 0x0034:
+ case 0x0035:
+ configured_display_type = IMON_DISPLAY_TYPE_VGA;
+ break;
+ case 0x0038:
+ case 0x0039:
+ case 0x0045:
+ configured_display_type = IMON_DISPLAY_TYPE_LCD;
+ break;
+ case 0x003c:
+ case 0x0041:
+ case 0x0042:
+ case 0x0043:
+ configured_display_type = IMON_DISPLAY_TYPE_NONE;
+ ictx->display_supported = false;
+ break;
+ case 0x0036:
+ case 0x0044:
+ default:
+ configured_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ }
+ } else {
+ configured_display_type = display_type;
+ if (display_type == IMON_DISPLAY_TYPE_NONE)
+ ictx->display_supported = false;
+ else
+ ictx->display_supported = true;
+ dev_info(ictx->dev, "%s: overriding display type to %d via "
+ "modparam\n", __func__, display_type);
+ }
+
+ ictx->display_type = configured_display_type;
+}
+
+static struct input_dev *imon_init_rdev(struct imon_context *ictx)
+{
+ struct input_dev *rdev;
+ struct ir_dev_props *props;
+ int ret;
+ char *ir_codes = NULL;
+ const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x88 };
+
+ rdev = input_allocate_device();
+ props = kzalloc(sizeof(*props), GFP_KERNEL);
+ if (!rdev || !props) {
+ dev_err(ictx->dev, "remote control dev allocation failed\n");
+ goto out;
+ }
+
+ snprintf(ictx->name_rdev, sizeof(ictx->name_rdev),
+ "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+ usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev,
+ sizeof(ictx->phys_rdev));
+ strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev));
+
+ rdev->name = ictx->name_rdev;
+ rdev->phys = ictx->phys_rdev;
+ usb_to_input_id(ictx->usbdev_intf0, &rdev->id);
+ rdev->dev.parent = ictx->dev;
+ rdev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP);
+ input_set_drvdata(rdev, ictx);
+
+ props->priv = ictx;
+ props->driver_type = RC_DRIVER_SCANCODE;
+ props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6; /* iMON PAD or MCE */
+ props->change_protocol = imon_ir_change_protocol;
+ ictx->props = props;
+
+ /* Enable front-panel buttons and/or knobs */
+ memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
+ ret = send_packet(ictx);
+ /* Not fatal, but warn about it */
+ if (ret)
+ dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
+
+ if (ictx->product == 0xffdc)
+ imon_get_ffdc_type(ictx);
+
+ imon_set_display_type(ictx);
+
+ if (ictx->ir_type == IR_TYPE_RC6)
+ ir_codes = RC_MAP_IMON_MCE;
+ else
+ ir_codes = RC_MAP_IMON_PAD;
+
+ ret = ir_input_register(rdev, ir_codes, props, MOD_NAME);
+ if (ret < 0) {
+ dev_err(ictx->dev, "remote input dev register failed\n");
+ goto out;
+ }
+
+ return rdev;
+
+out:
+ kfree(props);
+ input_free_device(rdev);
+ return NULL;
+}
+
static struct input_dev *imon_init_idev(struct imon_context *ictx)
{
struct input_dev *idev;
- struct ir_dev_props *props;
int ret, i;
idev = input_allocate_device();
if (!idev) {
- dev_err(ictx->dev, "remote input dev allocation failed\n");
- goto idev_alloc_failed;
- }
-
- props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
- if (!props) {
- dev_err(ictx->dev, "remote ir dev props allocation failed\n");
- goto props_alloc_failed;
+ dev_err(ictx->dev, "input dev allocation failed\n");
+ goto out;
}
snprintf(ictx->name_idev, sizeof(ictx->name_idev),
- "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+ "iMON Panel, Knob and Mouse(%04x:%04x)",
+ ictx->vendor, ictx->product);
idev->name = ictx->name_idev;
usb_make_path(ictx->usbdev_intf0, ictx->phys_idev,
sizeof(ictx->phys_idev));
- strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev));
+ strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev));
idev->phys = ictx->phys_idev;
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
@@ -1693,30 +1916,20 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
__set_bit(kc, idev->keybit);
}
- props->priv = ictx;
- props->driver_type = RC_DRIVER_SCANCODE;
- /* IR_TYPE_OTHER maps to iMON PAD remote, IR_TYPE_RC6 to MCE remote */
- props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6;
- props->change_protocol = imon_ir_change_protocol;
- ictx->props = props;
-
usb_to_input_id(ictx->usbdev_intf0, &idev->id);
idev->dev.parent = ictx->dev;
+ input_set_drvdata(idev, ictx);
- ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME);
+ ret = input_register_device(idev);
if (ret < 0) {
- dev_err(ictx->dev, "remote input dev register failed\n");
- goto idev_register_failed;
+ dev_err(ictx->dev, "input dev register failed\n");
+ goto out;
}
return idev;
-idev_register_failed:
- kfree(props);
-props_alloc_failed:
+out:
input_free_device(idev);
-idev_alloc_failed:
-
return NULL;
}
@@ -1738,7 +1951,7 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx)
usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
sizeof(ictx->phys_touch));
- strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch));
+ strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch));
touch->phys = ictx->phys_touch;
touch->evbit[0] =
@@ -1850,7 +2063,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
/* Input endpoint is mandatory */
if (!ir_ep_found)
- err("%s: no valid input (IR) endpoint found.", __func__);
+ pr_err("no valid input (IR) endpoint found\n");
ictx->tx_control = tx_control;
@@ -1888,6 +2101,7 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
}
mutex_init(&ictx->lock);
+ spin_lock_init(&ictx->kc_lock);
mutex_lock(&ictx->lock);
@@ -1913,6 +2127,12 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
goto idev_setup_failed;
}
+ ictx->rdev = imon_init_rdev(ictx);
+ if (!ictx->rdev) {
+ dev_err(dev, "%s: rc device setup failed\n", __func__);
+ goto rdev_setup_failed;
+ }
+
usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
usb_rcvintpipe(ictx->usbdev_intf0,
ictx->rx_endpoint_intf0->bEndpointAddress),
@@ -1922,15 +2142,16 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
if (ret) {
- err("%s: usb_submit_urb failed for intf0 (%d)",
- __func__, ret);
+ pr_err("usb_submit_urb failed for intf0 (%d)\n", ret);
goto urb_submit_failed;
}
return ictx;
urb_submit_failed:
- ir_input_unregister(ictx->idev);
+ ir_input_unregister(ictx->rdev);
+rdev_setup_failed:
+ input_unregister_device(ictx->idev);
idev_setup_failed:
find_endpoint_failed:
mutex_unlock(&ictx->lock);
@@ -1954,7 +2175,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
- err("%s: usb_alloc_urb failed for IR urb", __func__);
+ pr_err("usb_alloc_urb failed for IR urb\n");
goto rx_urb_alloc_failed;
}
@@ -1992,8 +2213,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
if (ret) {
- err("%s: usb_submit_urb failed for intf1 (%d)",
- __func__, ret);
+ pr_err("usb_submit_urb failed for intf1 (%d)\n", ret);
goto urb_submit_failed;
}
@@ -2012,116 +2232,6 @@ rx_urb_alloc_failed:
return NULL;
}
-/*
- * The 0x15c2:0xffdc device ID was used for umpteen different imon
- * devices, and all of them constantly spew interrupts, even when there
- * is no actual data to report. However, byte 6 of this buffer looks like
- * its unique across device variants, so we're trying to key off that to
- * figure out which display type (if any) and what IR protocol the device
- * actually supports. These devices have their IR protocol hard-coded into
- * their firmware, they can't be changed on the fly like the newer hardware.
- */
-static void imon_get_ffdc_type(struct imon_context *ictx)
-{
- u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
- u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
- u64 allowed_protos = IR_TYPE_OTHER;
-
- switch (ffdc_cfg_byte) {
- /* iMON Knob, no display, iMON IR + vol knob */
- case 0x21:
- dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
- ictx->display_supported = false;
- break;
- /* iMON 2.4G LT (usb stick), no display, iMON RF */
- case 0x4e:
- dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
- ictx->display_supported = false;
- ictx->rf_device = true;
- break;
- /* iMON VFD, no IR (does have vol knob tho) */
- case 0x35:
- dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
- detected_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- /* iMON VFD, iMON IR */
- case 0x24:
- case 0x85:
- dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
- detected_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- /* iMON LCD, MCE IR */
- case 0x9e:
- case 0x9f:
- dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
- detected_display_type = IMON_DISPLAY_TYPE_LCD;
- allowed_protos = IR_TYPE_RC6;
- break;
- default:
- dev_info(ictx->dev, "Unknown 0xffdc device, "
- "defaulting to VFD and iMON IR");
- detected_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- }
-
- printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
-
- ictx->display_type = detected_display_type;
- ictx->props->allowed_protos = allowed_protos;
- ictx->ir_type = allowed_protos;
-}
-
-static void imon_set_display_type(struct imon_context *ictx,
- struct usb_interface *intf)
-{
- u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
-
- /*
- * Try to auto-detect the type of display if the user hasn't set
- * it by hand via the display_type modparam. Default is VFD.
- */
-
- if (display_type == IMON_DISPLAY_TYPE_AUTO) {
- switch (ictx->product) {
- case 0xffdc:
- /* set in imon_get_ffdc_type() */
- configured_display_type = ictx->display_type;
- break;
- case 0x0034:
- case 0x0035:
- configured_display_type = IMON_DISPLAY_TYPE_VGA;
- break;
- case 0x0038:
- case 0x0039:
- case 0x0045:
- configured_display_type = IMON_DISPLAY_TYPE_LCD;
- break;
- case 0x003c:
- case 0x0041:
- case 0x0042:
- case 0x0043:
- configured_display_type = IMON_DISPLAY_TYPE_NONE;
- ictx->display_supported = false;
- break;
- case 0x0036:
- case 0x0044:
- default:
- configured_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- }
- } else {
- configured_display_type = display_type;
- if (display_type == IMON_DISPLAY_TYPE_NONE)
- ictx->display_supported = false;
- else
- ictx->display_supported = true;
- dev_info(ictx->dev, "%s: overriding display type to %d via "
- "modparam\n", __func__, display_type);
- }
-
- ictx->display_type = configured_display_type;
-}
-
static void imon_init_display(struct imon_context *ictx,
struct usb_interface *intf)
{
@@ -2130,8 +2240,7 @@ static void imon_init_display(struct imon_context *ictx,
dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
/* set up sysfs entry for built-in clock */
- ret = sysfs_create_group(&intf->dev.kobj,
- &imon_display_attribute_group);
+ ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group);
if (ret)
dev_err(ictx->dev, "Could not create display sysfs "
"entries(%d)", ret);
@@ -2162,8 +2271,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
struct imon_context *ictx = NULL;
struct imon_context *first_if_ctx = NULL;
u16 vendor, product;
- const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x88 };
code_length = BUF_CHUNK_SIZE * 8;
@@ -2185,7 +2292,7 @@ static int __devinit imon_probe(struct usb_interface *interface,
if (ifnum == 0) {
ictx = imon_init_intf0(interface);
if (!ictx) {
- err("%s: failed to initialize context!\n", __func__);
+ pr_err("failed to initialize context!\n");
ret = -ENODEV;
goto fail;
}
@@ -2194,7 +2301,7 @@ static int __devinit imon_probe(struct usb_interface *interface,
/* this is the secondary interface on the device */
ictx = imon_init_intf1(interface, first_if_ctx);
if (!ictx) {
- err("%s: failed to attach to context!\n", __func__);
+ pr_err("failed to attach to context!\n");
ret = -ENODEV;
goto fail;
}
@@ -2204,39 +2311,18 @@ static int __devinit imon_probe(struct usb_interface *interface,
usb_set_intfdata(interface, ictx);
if (ifnum == 0) {
- /* Enable front-panel buttons and/or knobs */
- memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
- ret = send_packet(ictx);
- /* Not fatal, but warn about it */
- if (ret)
- dev_info(dev, "failed to enable panel buttons "
- "and/or knobs\n");
-
- if (product == 0xffdc)
- imon_get_ffdc_type(ictx);
-
- imon_set_display_type(ictx, interface);
-
if (product == 0xffdc && ictx->rf_device) {
sysfs_err = sysfs_create_group(&interface->dev.kobj,
- &imon_rf_attribute_group);
+ &imon_rf_attr_group);
if (sysfs_err)
- err("%s: Could not create RF sysfs entries(%d)",
- __func__, sysfs_err);
+ pr_err("Could not create RF sysfs entries(%d)\n",
+ sysfs_err);
}
if (ictx->display_supported)
imon_init_display(ictx, interface);
}
- /* set IR protocol/remote type */
- ret = imon_ir_change_protocol(ictx, ictx->ir_type);
- if (ret) {
- dev_warn(dev, "%s: failed to set IR protocol, falling back "
- "to standard iMON protocol mode\n", __func__);
- ictx->ir_type = IR_TYPE_OTHER;
- }
-
dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
"usb<%d:%d> initialized\n", vendor, product, ifnum,
usbdev->bus->busnum, usbdev->devnum);
@@ -2275,10 +2361,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
* sysfs_remove_group is safe to call even if sysfs_create_group
* hasn't been called
*/
- sysfs_remove_group(&interface->dev.kobj,
- &imon_display_attribute_group);
- sysfs_remove_group(&interface->dev.kobj,
- &imon_rf_attribute_group);
+ sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group);
+ sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group);
usb_set_intfdata(interface, NULL);
@@ -2291,7 +2375,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
if (ifnum == 0) {
ictx->dev_present_intf0 = false;
usb_kill_urb(ictx->rx_urb_intf0);
- ir_input_unregister(ictx->idev);
+ input_unregister_device(ictx->idev);
+ ir_input_unregister(ictx->rdev);
if (ictx->display_supported) {
if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
usb_deregister_dev(interface, &imon_lcd_class);
@@ -2311,11 +2396,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
mutex_unlock(&ictx->lock);
if (!ictx->display_isopen)
free_imon_context(ictx);
- } else {
- if (ictx->ir_type == IR_TYPE_RC6)
- del_timer_sync(&ictx->itimer);
+ } else
mutex_unlock(&ictx->lock);
- }
mutex_unlock(&driver_lock);
@@ -2372,7 +2454,7 @@ static int __init imon_init(void)
rc = usb_register(&imon_driver);
if (rc) {
- err("%s: usb register failed(%d)", __func__, rc);
+ pr_err("usb register failed(%d)\n", rc);
rc = -ENODEV;
}
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/IR/ir-core-priv.h
index a85a8c7c905a..81c936bd793f 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/IR/ir-core-priv.h
@@ -17,6 +17,7 @@
#define _IR_RAW_EVENT
#include
+#include
#include
struct ir_raw_handler {
@@ -33,6 +34,7 @@ struct ir_raw_handler {
struct ir_raw_event_ctrl {
struct list_head list; /* to keep track of raw clients */
struct task_struct *thread;
+ spinlock_t lock;
struct kfifo kfifo; /* fifo for the pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
@@ -76,10 +78,22 @@ 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 lirc_codec {
struct ir_input_dev *ir_dev;
struct lirc_driver *drv;
int carrier_low;
+
+ ktime_t gap_start;
+ u64 gap_duration;
+ bool gap;
+ bool send_timeout_reports;
+
} lirc;
};
@@ -107,13 +121,19 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
ev->duration -= duration;
}
+/* Returns true if event is normal pulse/space event */
+static inline bool is_timing_event(struct ir_raw_event ev)
+{
+ return !ev.carrier_report && !ev.reset;
+}
+
#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
-#define IS_RESET(ev) (ev.duration == 0)
/*
* Routines from ir-sysfs.c - Meant to be called only internally inside
* ir-core
*/
+int ir_register_input(struct input_dev *input_dev);
int ir_register_class(struct input_dev *input_dev);
void ir_unregister_class(struct input_dev *input_dev);
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/IR/ir-jvc-decoder.c
index 77a89c4de014..63dca6e5458b 100644
--- a/drivers/media/IR/ir-jvc-decoder.c
+++ b/drivers/media/IR/ir-jvc-decoder.c
@@ -50,8 +50,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_JVC))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
index c06b4d50a3dc..9186b45132ed 100644
--- a/drivers/media/IR/ir-keytable.c
+++ b/drivers/media/IR/ir-keytable.c
@@ -435,7 +435,7 @@ EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
* This routine is used to signal that a key has been released on the
* remote control. It reports a keyup input event via input_report_key().
*/
-static void ir_keyup(struct ir_input_dev *ir)
+void ir_keyup(struct ir_input_dev *ir)
{
if (!ir->keypressed)
return;
@@ -445,6 +445,7 @@ static void ir_keyup(struct ir_input_dev *ir)
input_sync(ir->input_dev);
ir->keypressed = false;
}
+EXPORT_SYMBOL_GPL(ir_keyup);
/**
* ir_timer_keyup() - generates a keyup event after a timeout
@@ -640,6 +641,10 @@ int __ir_input_register(struct input_dev *input_dev,
goto out_event;
}
+ rc = ir_register_input(input_dev);
+ if (rc < 0)
+ goto out_event;
+
IR_dprintk(1, "Registered input device on %s for %s remote%s.\n",
driver_name, rc_tab->name,
(ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_IR_RAW) ?
diff --git a/drivers/media/IR/ir-lirc-codec.c b/drivers/media/IR/ir-lirc-codec.c
index 1983cd3f3994..9fc0db9d344d 100644
--- a/drivers/media/IR/ir-lirc-codec.c
+++ b/drivers/media/IR/ir-lirc-codec.c
@@ -32,6 +32,7 @@
static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct lirc_codec *lirc = &ir_dev->raw->lirc;
int sample;
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_LIRC))
@@ -40,21 +41,57 @@ static int ir_lirc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!ir_dev->raw->lirc.drv || !ir_dev->raw->lirc.drv->rbuf)
return -EINVAL;
- if (IS_RESET(ev))
+ /* Packet start */
+ if (ev.reset)
return 0;
- IR_dprintk(2, "LIRC data transfer started (%uus %s)\n",
- TO_US(ev.duration), TO_STR(ev.pulse));
+ /* Carrier reports */
+ if (ev.carrier_report) {
+ sample = LIRC_FREQUENCY(ev.carrier);
- sample = ev.duration / 1000;
- if (ev.pulse)
- sample |= PULSE_BIT;
+ /* Packet end */
+ } else if (ev.timeout) {
+
+ if (lirc->gap)
+ return 0;
+
+ lirc->gap_start = ktime_get();
+ lirc->gap = true;
+ lirc->gap_duration = ev.duration;
+
+ if (!lirc->send_timeout_reports)
+ return 0;
+
+ sample = LIRC_TIMEOUT(ev.duration / 1000);
+
+ /* Normal sample */
+ } else {
+
+ if (lirc->gap) {
+ int gap_sample;
+
+ lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
+ lirc->gap_start));
+
+ /* Convert to ms and cap by LIRC_VALUE_MASK */
+ do_div(lirc->gap_duration, 1000);
+ lirc->gap_duration = min(lirc->gap_duration,
+ (u64)LIRC_VALUE_MASK);
+
+ gap_sample = LIRC_SPACE(lirc->gap_duration);
+ lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
+ (unsigned char *) &gap_sample);
+ lirc->gap = false;
+ }
+
+ sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
+ LIRC_SPACE(ev.duration / 1000);
+ }
lirc_buffer_write(ir_dev->raw->lirc.drv->rbuf,
(unsigned char *) &sample);
wake_up(&ir_dev->raw->lirc.drv->rbuf->wait_poll);
-
return 0;
}
@@ -102,7 +139,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
struct ir_input_dev *ir_dev;
int ret = 0;
void *drv_data;
- unsigned long val = 0;
+ __u32 val = 0, tmp;
lirc = lirc_get_pdata(filep);
if (!lirc)
@@ -115,7 +152,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
drv_data = ir_dev->props->priv;
if (_IOC_DIR(cmd) & _IOC_WRITE) {
- ret = get_user(val, (unsigned long *)arg);
+ ret = get_user(val, (__u32 *)arg);
if (ret)
return ret;
}
@@ -130,22 +167,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
case LIRC_SET_SEND_MODE:
if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
return -EINVAL;
- break;
+ return 0;
/* TX settings */
case LIRC_SET_TRANSMITTER_MASK:
- if (ir_dev->props->s_tx_mask)
- ret = ir_dev->props->s_tx_mask(drv_data, (u32)val);
- else
+ if (!ir_dev->props->s_tx_mask)
return -EINVAL;
- break;
+
+ return ir_dev->props->s_tx_mask(drv_data, val);
case LIRC_SET_SEND_CARRIER:
- if (ir_dev->props->s_tx_carrier)
- ir_dev->props->s_tx_carrier(drv_data, (u32)val);
- else
+ if (!ir_dev->props->s_tx_carrier)
return -EINVAL;
- break;
+
+ return ir_dev->props->s_tx_carrier(drv_data, val);
case LIRC_SET_SEND_DUTY_CYCLE:
if (!ir_dev->props->s_tx_duty_cycle)
@@ -154,39 +189,42 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
if (val <= 0 || val >= 100)
return -EINVAL;
- ir_dev->props->s_tx_duty_cycle(ir_dev->props->priv, val);
- break;
+ return ir_dev->props->s_tx_duty_cycle(drv_data, val);
/* RX settings */
case LIRC_SET_REC_CARRIER:
- if (ir_dev->props->s_rx_carrier_range)
- ret = ir_dev->props->s_rx_carrier_range(
- ir_dev->props->priv,
- ir_dev->raw->lirc.carrier_low, val);
- else
+ if (!ir_dev->props->s_rx_carrier_range)
return -ENOSYS;
- if (!ret)
- ir_dev->raw->lirc.carrier_low = 0;
- break;
+ if (val <= 0)
+ return -EINVAL;
+
+ return ir_dev->props->s_rx_carrier_range(drv_data,
+ ir_dev->raw->lirc.carrier_low, val);
case LIRC_SET_REC_CARRIER_RANGE:
- if (val >= 0)
- ir_dev->raw->lirc.carrier_low = val;
- break;
+ if (val <= 0)
+ return -EINVAL;
+ ir_dev->raw->lirc.carrier_low = val;
+ return 0;
case LIRC_GET_REC_RESOLUTION:
val = ir_dev->props->rx_resolution;
break;
case LIRC_SET_WIDEBAND_RECEIVER:
- if (ir_dev->props->s_learning_mode)
- return ir_dev->props->s_learning_mode(
- ir_dev->props->priv, !!val);
- else
+ if (!ir_dev->props->s_learning_mode)
return -ENOSYS;
+ return ir_dev->props->s_learning_mode(drv_data, !!val);
+
+ case LIRC_SET_MEASURE_CARRIER_MODE:
+ if (!ir_dev->props->s_carrier_report)
+ return -ENOSYS;
+
+ return ir_dev->props->s_carrier_report(drv_data, !!val);
+
/* Generic timeout support */
case LIRC_GET_MIN_TIMEOUT:
if (!ir_dev->props->max_timeout)
@@ -201,10 +239,20 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
break;
case LIRC_SET_REC_TIMEOUT:
- if (val < ir_dev->props->min_timeout ||
- val > ir_dev->props->max_timeout)
- return -EINVAL;
- ir_dev->props->timeout = val * 1000;
+ if (!ir_dev->props->max_timeout)
+ return -ENOSYS;
+
+ tmp = val * 1000;
+
+ if (tmp < ir_dev->props->min_timeout ||
+ tmp > ir_dev->props->max_timeout)
+ return -EINVAL;
+
+ ir_dev->props->timeout = tmp;
+ break;
+
+ case LIRC_SET_REC_TIMEOUT_REPORTS:
+ lirc->send_timeout_reports = !!val;
break;
default:
@@ -212,7 +260,7 @@ static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
}
if (_IOC_DIR(cmd) & _IOC_READ)
- ret = put_user(val, (unsigned long *)arg);
+ ret = put_user(val, (__u32 *)arg);
return ret;
}
@@ -231,6 +279,9 @@ static struct file_operations lirc_fops = {
.owner = THIS_MODULE,
.write = ir_lirc_transmit_ir,
.unlocked_ioctl = ir_lirc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ir_lirc_ioctl,
+#endif
.read = lirc_dev_fop_read,
.poll = lirc_dev_fop_poll,
.open = lirc_dev_fop_open,
@@ -278,6 +329,10 @@ static int ir_lirc_register(struct input_dev *input_dev)
if (ir_dev->props->s_learning_mode)
features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
+ if (ir_dev->props->s_carrier_report)
+ features |= LIRC_CAN_MEASURE_CARRIER;
+
+
if (ir_dev->props->max_timeout)
features |= LIRC_CAN_SET_REC_TIMEOUT;
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/IR/ir-nec-decoder.c
index d597421d6547..70993f79c8a2 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/IR/ir-nec-decoder.c
@@ -54,8 +54,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_NEC))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
index 8e0e1b1f8c87..a06a07e4e0b1 100644
--- a/drivers/media/IR/ir-raw-event.c
+++ b/drivers/media/IR/ir-raw-event.c
@@ -39,22 +39,34 @@ static int ir_raw_event_thread(void *data)
struct ir_raw_event ev;
struct ir_raw_handler *handler;
struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
+ int retval;
while (!kthread_should_stop()) {
- try_to_freeze();
- mutex_lock(&ir_raw_handler_lock);
+ spin_lock_irq(&raw->lock);
+ retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev)) {
- list_for_each_entry(handler, &ir_raw_handler_list, list)
- handler->decode(raw->input_dev, ev);
- raw->prev_ev = ev;
+ if (!retval) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (kthread_should_stop())
+ set_current_state(TASK_RUNNING);
+
+ spin_unlock_irq(&raw->lock);
+ schedule();
+ continue;
}
- mutex_unlock(&ir_raw_handler_lock);
+ spin_unlock_irq(&raw->lock);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
+
+ BUG_ON(retval != sizeof(ev));
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ handler->decode(raw->input_dev, ev);
+ raw->prev_ev = ev;
+ mutex_unlock(&ir_raw_handler_lock);
}
return 0;
@@ -77,7 +89,7 @@ int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
if (!ir->raw)
return -EINVAL;
- IR_dprintk(2, "sample: (05%dus %s)\n",
+ IR_dprintk(2, "sample: (%05dus %s)\n",
TO_US(ev->duration), TO_STR(ev->pulse));
if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
@@ -162,7 +174,7 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
if (ir->idle && !ev->pulse)
return 0;
else if (ir->idle)
- ir_raw_event_set_idle(input_dev, 0);
+ ir_raw_event_set_idle(input_dev, false);
if (!raw->this_ev.duration) {
raw->this_ev = *ev;
@@ -175,48 +187,35 @@ int ir_raw_event_store_with_filter(struct input_dev *input_dev,
/* Enter idle mode if nessesary */
if (!ev->pulse && ir->props->timeout &&
- raw->this_ev.duration >= ir->props->timeout)
- ir_raw_event_set_idle(input_dev, 1);
+ raw->this_ev.duration >= ir->props->timeout) {
+ ir_raw_event_set_idle(input_dev, true);
+ }
return 0;
}
EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
-void ir_raw_event_set_idle(struct input_dev *input_dev, int idle)
+/**
+ * ir_raw_event_set_idle() - hint the ir core if device is receiving
+ * IR data or not
+ * @input_dev: the struct input_dev device descriptor
+ * @idle: the hint value
+ */
+void ir_raw_event_set_idle(struct input_dev *input_dev, bool idle)
{
struct ir_input_dev *ir = input_get_drvdata(input_dev);
struct ir_raw_event_ctrl *raw = ir->raw;
- ktime_t now;
- u64 delta;
- if (!ir->props)
+ if (!ir->props || !ir->raw)
return;
- if (!ir->raw)
- goto out;
+ IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
if (idle) {
- IR_dprintk(2, "enter idle mode\n");
- raw->last_event = ktime_get();
- } else {
- IR_dprintk(2, "exit idle mode\n");
-
- now = ktime_get();
- delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
-
- WARN_ON(raw->this_ev.pulse);
-
- raw->this_ev.duration =
- min(raw->this_ev.duration + delta,
- (u64)IR_MAX_DURATION);
-
+ raw->this_ev.timeout = true;
ir_raw_event_store(input_dev, &raw->this_ev);
-
- if (raw->this_ev.duration == IR_MAX_DURATION)
- ir_raw_event_reset(input_dev);
-
- raw->this_ev.duration = 0;
+ init_ir_raw_event(&raw->this_ev);
}
-out:
+
if (ir->props->s_idle)
ir->props->s_idle(ir->props->priv, idle);
ir->idle = idle;
@@ -232,11 +231,14 @@ EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
void ir_raw_event_handle(struct input_dev *input_dev)
{
struct ir_input_dev *ir = input_get_drvdata(input_dev);
+ unsigned long flags;
if (!ir->raw)
return;
+ spin_lock_irqsave(&ir->raw->lock, flags);
wake_up_process(ir->raw->thread);
+ spin_unlock_irqrestore(&ir->raw->lock, flags);
}
EXPORT_SYMBOL_GPL(ir_raw_event_handle);
@@ -275,6 +277,7 @@ int ir_raw_event_register(struct input_dev *input_dev)
return rc;
}
+ spin_lock_init(&ir->raw->lock);
ir->raw->thread = kthread_run(ir_raw_event_thread, ir->raw,
"rc%u", (unsigned int)ir->devno);
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/IR/ir-rc5-decoder.c
index df4770d978ad..572ed4ca8c68 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/IR/ir-rc5-decoder.c
@@ -55,8 +55,9 @@ static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC5))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/IR/ir-rc5-sz-decoder.c b/drivers/media/IR/ir-rc5-sz-decoder.c
new file mode 100644
index 000000000000..7c413501a3f7
--- /dev/null
+++ b/drivers/media/IR/ir-rc5-sz-decoder.c
@@ -0,0 +1,154 @@
+/* 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 "ir-core-priv.h"
+
+#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
+ * @input_dev: the struct input_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 input_dev *input_dev, struct ir_raw_event ev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct rc5_sz_dec *data = &ir_dev->raw->rc5_sz;
+ u8 toggle, command, system;
+ u32 scancode;
+
+ if (!(ir_dev->raw->enabled_protocols & IR_TYPE_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, &ir_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);
+
+ ir_keydown(input_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 = IR_TYPE_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/IR/ir-rc6-decoder.c b/drivers/media/IR/ir-rc6-decoder.c
index f1624b8279bc..d25da91f44ff 100644
--- a/drivers/media/IR/ir-rc6-decoder.c
+++ b/drivers/media/IR/ir-rc6-decoder.c
@@ -85,8 +85,9 @@ static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_RC6))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/IR/ir-sony-decoder.c
index b9074f07c7a0..2d15730822bc 100644
--- a/drivers/media/IR/ir-sony-decoder.c
+++ b/drivers/media/IR/ir-sony-decoder.c
@@ -48,8 +48,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!(ir_dev->raw->enabled_protocols & IR_TYPE_SONY))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
index 46d42467f9b4..38423a8da871 100644
--- a/drivers/media/IR/ir-sysfs.c
+++ b/drivers/media/IR/ir-sysfs.c
@@ -43,6 +43,7 @@ static struct {
{ IR_TYPE_RC6, "rc-6" },
{ IR_TYPE_JVC, "jvc" },
{ IR_TYPE_SONY, "sony" },
+ { IR_TYPE_RC5_SZ, "rc-5-sz" },
{ IR_TYPE_LIRC, "lirc" },
};
@@ -67,6 +68,10 @@ static ssize_t show_protocols(struct device *d,
char *tmp = buf;
int i;
+ /* Device is being removed */
+ if (!ir_dev)
+ return -EINVAL;
+
if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE) {
enabled = ir_dev->rc_tab.ir_type;
allowed = ir_dev->props->allowed_protos;
@@ -122,6 +127,10 @@ static ssize_t store_protocols(struct device *d,
int rc, i, count = 0;
unsigned long flags;
+ /* Device is being removed */
+ if (!ir_dev)
+ return -EINVAL;
+
if (ir_dev->props && ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
type = ir_dev->rc_tab.ir_type;
else if (ir_dev->raw)
@@ -256,8 +265,6 @@ static struct device_type rc_dev_type = {
*/
int ir_register_class(struct input_dev *input_dev)
{
- int rc;
- const char *path;
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
int devno = find_first_zero_bit(&ir_core_dev_number,
IRRCV_NUM_DEVICES);
@@ -266,17 +273,28 @@ int ir_register_class(struct input_dev *input_dev)
return devno;
ir_dev->dev.type = &rc_dev_type;
+ ir_dev->devno = devno;
ir_dev->dev.class = &ir_input_class;
ir_dev->dev.parent = input_dev->dev.parent;
+ input_dev->dev.parent = &ir_dev->dev;
dev_set_name(&ir_dev->dev, "rc%d", devno);
dev_set_drvdata(&ir_dev->dev, ir_dev);
- rc = device_register(&ir_dev->dev);
- if (rc)
- return rc;
+ return device_register(&ir_dev->dev);
+};
+
+/**
+ * ir_register_input - registers ir input device with input subsystem
+ * @input_dev: the struct input_dev descriptor of the device
+ */
+
+int ir_register_input(struct input_dev *input_dev)
+{
+ struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ int rc;
+ const char *path;
- input_dev->dev.parent = &ir_dev->dev;
rc = input_register_device(input_dev);
if (rc < 0) {
device_del(&ir_dev->dev);
@@ -292,11 +310,9 @@ int ir_register_class(struct input_dev *input_dev)
path ? path : "N/A");
kfree(path);
- ir_dev->devno = devno;
- set_bit(devno, &ir_core_dev_number);
-
+ set_bit(ir_dev->devno, &ir_core_dev_number);
return 0;
-};
+}
/**
* ir_unregister_class() - removes the sysfs for sysfs for
@@ -309,6 +325,7 @@ void ir_unregister_class(struct input_dev *input_dev)
{
struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ input_set_drvdata(input_dev, NULL);
clear_bit(ir_dev->devno, &ir_core_dev_number);
input_unregister_device(input_dev);
device_del(&ir_dev->dev);
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/IR/keymaps/Makefile
index 950e5d953c6f..3194d391bbd4 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/IR/keymaps/Makefile
@@ -1,4 +1,6 @@
obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
+ rc-alink-dtu-m.o \
+ rc-anysee.o \
rc-apac-viewcomp.o \
rc-asus-pc39.o \
rc-ati-tv-wonder-hd-600.o \
@@ -8,7 +10,9 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-avermedia-dvbt.o \
rc-avermedia-m135a.o \
rc-avermedia-m733a-rm-k6.o \
+ rc-avermedia-rm-ks.o \
rc-avertv-303.o \
+ rc-azurewave-ad-tu700.o \
rc-behold.o \
rc-behold-columbus.o \
rc-budget-ci-old.o \
@@ -16,6 +20,8 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-cinergy.o \
rc-dib0700-nec.o \
rc-dib0700-rc5.o \
+ rc-digitalnow-tinytwin.o \
+ rc-digittrade.o \
rc-dm1105-nec.o \
rc-dntv-live-dvb-t.o \
rc-dntv-live-dvbt-pro.o \
@@ -38,8 +44,12 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-kaiomy.o \
rc-kworld-315u.o \
rc-kworld-plus-tv-analog.o \
+ rc-leadtek-y04g0051.o \
rc-lirc.o \
+ rc-lme2510.o \
rc-manli.o \
+ rc-msi-digivox-ii.o \
+ rc-msi-digivox-iii.o \
rc-msi-tvanywhere.o \
rc-msi-tvanywhere-plus.o \
rc-nebula.o \
@@ -58,14 +68,18 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-purpletv.o \
rc-pv951.o \
rc-rc5-hauppauge-new.o \
- rc-rc5-streamzap.o \
rc-rc5-tv.o \
rc-rc6-mce.o \
rc-real-audio-220-32-keys.o \
+ rc-streamzap.o \
rc-tbs-nec.o \
rc-terratec-cinergy-xs.o \
+ rc-terratec-slim.o \
rc-tevii-nec.o \
+ rc-total-media-in-hand.o \
+ rc-trekstor.o \
rc-tt-1500.o \
+ rc-twinhan1027.o \
rc-videomate-s350.o \
rc-videomate-tv-pvr.o \
rc-winfast.o \
diff --git a/drivers/media/IR/keymaps/rc-alink-dtu-m.c b/drivers/media/IR/keymaps/rc-alink-dtu-m.c
new file mode 100644
index 000000000000..ddfee7f8093d
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-alink-dtu-m.c
@@ -0,0 +1,68 @@
+/*
+ * A-Link DTU(m) remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
+static struct ir_scancode alink_dtu_m[] = {
+ { 0x0800, KEY_VOLUMEUP },
+ { 0x0801, KEY_1 },
+ { 0x0802, KEY_3 },
+ { 0x0803, KEY_7 },
+ { 0x0804, KEY_9 },
+ { 0x0805, KEY_NEW }, /* symbol: PIP */
+ { 0x0806, KEY_0 },
+ { 0x0807, KEY_CHANNEL }, /* JUMP */
+ { 0x080d, KEY_5 },
+ { 0x080f, KEY_2 },
+ { 0x0812, KEY_POWER2 },
+ { 0x0814, KEY_CHANNELUP },
+ { 0x0816, KEY_VOLUMEDOWN },
+ { 0x0818, KEY_6 },
+ { 0x081a, KEY_MUTE },
+ { 0x081b, KEY_8 },
+ { 0x081c, KEY_4 },
+ { 0x081d, KEY_CHANNELDOWN },
+};
+
+static struct rc_keymap alink_dtu_m_map = {
+ .map = {
+ .scan = alink_dtu_m,
+ .size = ARRAY_SIZE(alink_dtu_m),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_ALINK_DTU_M,
+ }
+};
+
+static int __init init_rc_map_alink_dtu_m(void)
+{
+ return ir_register_map(&alink_dtu_m_map);
+}
+
+static void __exit exit_rc_map_alink_dtu_m(void)
+{
+ ir_unregister_map(&alink_dtu_m_map);
+}
+
+module_init(init_rc_map_alink_dtu_m)
+module_exit(exit_rc_map_alink_dtu_m)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-anysee.c b/drivers/media/IR/keymaps/rc-anysee.c
new file mode 100644
index 000000000000..30d70498cfed
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-anysee.c
@@ -0,0 +1,93 @@
+/*
+ * Anysee remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+static struct ir_scancode anysee[] = {
+ { 0x0800, KEY_0 },
+ { 0x0801, KEY_1 },
+ { 0x0802, KEY_2 },
+ { 0x0803, KEY_3 },
+ { 0x0804, KEY_4 },
+ { 0x0805, KEY_5 },
+ { 0x0806, KEY_6 },
+ { 0x0807, KEY_7 },
+ { 0x0808, KEY_8 },
+ { 0x0809, KEY_9 },
+ { 0x080a, KEY_POWER2 }, /* [red power button] */
+ { 0x080b, KEY_VIDEO }, /* [*] MODE */
+ { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */
+ { 0x080d, KEY_NEXT }, /* [>>|] */
+ { 0x080e, KEY_MENU }, /* MENU */
+ { 0x080f, KEY_EPG }, /* [EPG] */
+ { 0x0810, KEY_CLEAR }, /* EXIT */
+ { 0x0811, KEY_CHANNELUP },
+ { 0x0812, KEY_VOLUMEDOWN },
+ { 0x0813, KEY_VOLUMEUP },
+ { 0x0814, KEY_CHANNELDOWN },
+ { 0x0815, KEY_OK },
+ { 0x0816, KEY_RADIO }, /* [symbol TV/radio] */
+ { 0x0817, KEY_INFO }, /* [i] */
+ { 0x0818, KEY_PREVIOUS }, /* [|<<] */
+ { 0x0819, KEY_FAVORITES }, /* FAV. */
+ { 0x081a, KEY_SUBTITLE }, /* Subtitle */
+ { 0x081b, KEY_CAMERA }, /* [symbol camera] */
+ { 0x081c, KEY_YELLOW },
+ { 0x081d, KEY_RED },
+ { 0x081e, KEY_LANGUAGE }, /* [symbol Second Audio Program] */
+ { 0x081f, KEY_GREEN },
+ { 0x0820, KEY_SLEEP }, /* Sleep */
+ { 0x0821, KEY_SCREEN }, /* 16:9 / 4:3 */
+ { 0x0822, KEY_ZOOM }, /* SIZE */
+ { 0x0824, KEY_FN }, /* [F1] */
+ { 0x0825, KEY_FN }, /* [F2] */
+ { 0x0842, KEY_MUTE }, /* symbol mute */
+ { 0x0844, KEY_BLUE },
+ { 0x0847, KEY_TEXT }, /* TEXT */
+ { 0x0848, KEY_STOP },
+ { 0x0849, KEY_RECORD },
+ { 0x0850, KEY_PLAY },
+ { 0x0851, KEY_PAUSE },
+};
+
+static struct rc_keymap anysee_map = {
+ .map = {
+ .scan = anysee,
+ .size = ARRAY_SIZE(anysee),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_ANYSEE,
+ }
+};
+
+static int __init init_rc_map_anysee(void)
+{
+ return ir_register_map(&anysee_map);
+}
+
+static void __exit exit_rc_map_anysee(void)
+{
+ ir_unregister_map(&anysee_map);
+}
+
+module_init(init_rc_map_anysee)
+module_exit(exit_rc_map_anysee)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-asus-pc39.c b/drivers/media/IR/keymaps/rc-asus-pc39.c
index 2aa068cd6c75..2996e0a3b8d5 100644
--- a/drivers/media/IR/keymaps/rc-asus-pc39.c
+++ b/drivers/media/IR/keymaps/rc-asus-pc39.c
@@ -20,56 +20,56 @@
static struct ir_scancode asus_pc39[] = {
/* Keys 0 to 9 */
- { 0x15, KEY_0 },
- { 0x29, KEY_1 },
- { 0x2d, KEY_2 },
- { 0x2b, KEY_3 },
- { 0x09, KEY_4 },
- { 0x0d, KEY_5 },
- { 0x0b, KEY_6 },
- { 0x31, KEY_7 },
- { 0x35, KEY_8 },
- { 0x33, KEY_9 },
+ { 0x082a, KEY_0 },
+ { 0x0816, KEY_1 },
+ { 0x0812, KEY_2 },
+ { 0x0814, KEY_3 },
+ { 0x0836, KEY_4 },
+ { 0x0832, KEY_5 },
+ { 0x0834, KEY_6 },
+ { 0x080e, KEY_7 },
+ { 0x080a, KEY_8 },
+ { 0x080c, KEY_9 },
- { 0x3e, KEY_RADIO }, /* radio */
- { 0x03, KEY_MENU }, /* dvd/menu */
- { 0x2a, KEY_VOLUMEUP },
- { 0x19, KEY_VOLUMEDOWN },
- { 0x37, KEY_UP },
- { 0x3b, KEY_DOWN },
- { 0x27, KEY_LEFT },
- { 0x2f, KEY_RIGHT },
- { 0x25, KEY_VIDEO }, /* video */
- { 0x39, KEY_AUDIO }, /* music */
+ { 0x0801, KEY_RADIO }, /* radio */
+ { 0x083c, KEY_MENU }, /* dvd/menu */
+ { 0x0815, KEY_VOLUMEUP },
+ { 0x0826, KEY_VOLUMEDOWN },
+ { 0x0808, KEY_UP },
+ { 0x0804, KEY_DOWN },
+ { 0x0818, KEY_LEFT },
+ { 0x0810, KEY_RIGHT },
+ { 0x081a, KEY_VIDEO }, /* video */
+ { 0x0806, KEY_AUDIO }, /* music */
- { 0x21, KEY_TV }, /* tv */
- { 0x1d, KEY_EXIT }, /* back */
- { 0x0a, KEY_CHANNELUP }, /* channel / program + */
- { 0x1b, KEY_CHANNELDOWN }, /* channel / program - */
- { 0x1a, KEY_ENTER }, /* enter */
+ { 0x081e, KEY_TV }, /* tv */
+ { 0x0822, KEY_EXIT }, /* back */
+ { 0x0835, KEY_CHANNELUP }, /* channel / program + */
+ { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */
+ { 0x0825, KEY_ENTER }, /* enter */
- { 0x06, KEY_PAUSE }, /* play/pause */
- { 0x1e, KEY_PREVIOUS }, /* rew */
- { 0x26, KEY_NEXT }, /* forward */
- { 0x0e, KEY_REWIND }, /* backward << */
- { 0x3a, KEY_FASTFORWARD }, /* forward >> */
- { 0x36, KEY_STOP },
- { 0x2e, KEY_RECORD }, /* recording */
- { 0x16, KEY_POWER }, /* the button that reads "close" */
+ { 0x0839, KEY_PAUSE }, /* play/pause */
+ { 0x0821, KEY_PREVIOUS }, /* rew */
+ { 0x0819, KEY_NEXT }, /* forward */
+ { 0x0831, KEY_REWIND }, /* backward << */
+ { 0x0805, KEY_FASTFORWARD }, /* forward >> */
+ { 0x0809, KEY_STOP },
+ { 0x0811, KEY_RECORD }, /* recording */
+ { 0x0829, KEY_POWER }, /* the button that reads "close" */
- { 0x11, KEY_ZOOM }, /* full screen */
- { 0x13, KEY_MACRO }, /* recall */
- { 0x23, KEY_HOME }, /* home */
- { 0x05, KEY_PVR }, /* picture */
- { 0x3d, KEY_MUTE }, /* mute */
- { 0x01, KEY_DVD }, /* dvd */
+ { 0x082e, KEY_ZOOM }, /* full screen */
+ { 0x082c, KEY_MACRO }, /* recall */
+ { 0x081c, KEY_HOME }, /* home */
+ { 0x083a, KEY_PVR }, /* picture */
+ { 0x0802, KEY_MUTE }, /* mute */
+ { 0x083e, KEY_DVD }, /* dvd */
};
static struct rc_keymap asus_pc39_map = {
.map = {
.scan = asus_pc39,
.size = ARRAY_SIZE(asus_pc39),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .ir_type = IR_TYPE_RC5,
.name = RC_MAP_ASUS_PC39,
}
};
diff --git a/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c b/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c
new file mode 100644
index 000000000000..9ee60906c861
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-avermedia-rm-ks.c
@@ -0,0 +1,79 @@
+/*
+ * AverMedia RM-KS remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* Initial keytable is from Jose Alberto Reguero
+ and Felipe Morales Moreno */
+/* FIXME: mappings are not 100% correct? */
+static struct ir_scancode avermedia_rm_ks[] = {
+ { 0x0501, KEY_POWER2 },
+ { 0x0502, KEY_CHANNELUP },
+ { 0x0503, KEY_CHANNELDOWN },
+ { 0x0504, KEY_VOLUMEUP },
+ { 0x0505, KEY_VOLUMEDOWN },
+ { 0x0506, KEY_MUTE },
+ { 0x0507, KEY_RIGHT },
+ { 0x0508, KEY_PROG1 },
+ { 0x0509, KEY_1 },
+ { 0x050a, KEY_2 },
+ { 0x050b, KEY_3 },
+ { 0x050c, KEY_4 },
+ { 0x050d, KEY_5 },
+ { 0x050e, KEY_6 },
+ { 0x050f, KEY_7 },
+ { 0x0510, KEY_8 },
+ { 0x0511, KEY_9 },
+ { 0x0512, KEY_0 },
+ { 0x0513, KEY_AUDIO },
+ { 0x0515, KEY_EPG },
+ { 0x0516, KEY_PLAY },
+ { 0x0517, KEY_RECORD },
+ { 0x0518, KEY_STOP },
+ { 0x051c, KEY_BACK },
+ { 0x051d, KEY_FORWARD },
+ { 0x054d, KEY_LEFT },
+ { 0x0556, KEY_ZOOM },
+};
+
+static struct rc_keymap avermedia_rm_ks_map = {
+ .map = {
+ .scan = avermedia_rm_ks,
+ .size = ARRAY_SIZE(avermedia_rm_ks),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_AVERMEDIA_RM_KS,
+ }
+};
+
+static int __init init_rc_map_avermedia_rm_ks(void)
+{
+ return ir_register_map(&avermedia_rm_ks_map);
+}
+
+static void __exit exit_rc_map_avermedia_rm_ks(void)
+{
+ ir_unregister_map(&avermedia_rm_ks_map);
+}
+
+module_init(init_rc_map_avermedia_rm_ks)
+module_exit(exit_rc_map_avermedia_rm_ks)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c
new file mode 100644
index 000000000000..e0876147d471
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-azurewave-ad-tu700.c
@@ -0,0 +1,102 @@
+/*
+ * TwinHan AzureWave AD-TU700(704J) remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+static struct ir_scancode azurewave_ad_tu700[] = {
+ { 0x0000, KEY_TAB }, /* Tab */
+ { 0x0001, KEY_2 },
+ { 0x0002, KEY_CHANNELDOWN },
+ { 0x0003, KEY_1 },
+ { 0x0004, KEY_MENU }, /* Record List */
+ { 0x0005, KEY_CHANNELUP },
+ { 0x0006, KEY_3 },
+ { 0x0007, KEY_SLEEP }, /* Hibernate */
+ { 0x0008, KEY_VIDEO }, /* A/V */
+ { 0x0009, KEY_4 },
+ { 0x000a, KEY_VOLUMEDOWN },
+ { 0x000c, KEY_CANCEL }, /* Cancel */
+ { 0x000d, KEY_7 },
+ { 0x000e, KEY_AGAIN }, /* Recall */
+ { 0x000f, KEY_TEXT }, /* Teletext */
+ { 0x0010, KEY_MUTE },
+ { 0x0011, KEY_RECORD },
+ { 0x0012, KEY_FASTFORWARD }, /* FF >> */
+ { 0x0013, KEY_BACK }, /* Back */
+ { 0x0014, KEY_PLAY },
+ { 0x0015, KEY_0 },
+ { 0x0016, KEY_POWER2 }, /* [red power button] */
+ { 0x0017, KEY_FAVORITES }, /* Favorite List */
+ { 0x0018, KEY_RED },
+ { 0x0019, KEY_8 },
+ { 0x001a, KEY_STOP },
+ { 0x001b, KEY_9 },
+ { 0x001c, KEY_EPG }, /* Info/EPG */
+ { 0x001d, KEY_5 },
+ { 0x001e, KEY_VOLUMEUP },
+ { 0x001f, KEY_6 },
+ { 0x0040, KEY_REWIND }, /* FR << */
+ { 0x0041, KEY_PREVIOUS }, /* Replay */
+ { 0x0042, KEY_NEXT }, /* Skip */
+ { 0x0043, KEY_SUBTITLE }, /* Subtitle / CC */
+ { 0x0045, KEY_KPPLUS }, /* Zoom+ */
+ { 0x0046, KEY_KPMINUS }, /* Zoom- */
+ { 0x0047, KEY_NEW }, /* PIP */
+ { 0x0048, KEY_INFO }, /* Preview */
+ { 0x0049, KEY_MODE }, /* L/R */
+ { 0x004a, KEY_CLEAR }, /* Clear */
+ { 0x004b, KEY_UP }, /* up arrow */
+ { 0x004c, KEY_PAUSE },
+ { 0x004d, KEY_ZOOM }, /* Full Screen */
+ { 0x004e, KEY_LEFT }, /* left arrow */
+ { 0x004f, KEY_OK }, /* Enter / ok */
+ { 0x0050, KEY_LANGUAGE }, /* SAP */
+ { 0x0051, KEY_DOWN }, /* down arrow */
+ { 0x0052, KEY_RIGHT }, /* right arrow */
+ { 0x0053, KEY_GREEN },
+ { 0x0054, KEY_CAMERA }, /* Capture */
+ { 0x005e, KEY_YELLOW },
+ { 0x005f, KEY_BLUE },
+};
+
+static struct rc_keymap azurewave_ad_tu700_map = {
+ .map = {
+ .scan = azurewave_ad_tu700,
+ .size = ARRAY_SIZE(azurewave_ad_tu700),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_AZUREWAVE_AD_TU700,
+ }
+};
+
+static int __init init_rc_map_azurewave_ad_tu700(void)
+{
+ return ir_register_map(&azurewave_ad_tu700_map);
+}
+
+static void __exit exit_rc_map_azurewave_ad_tu700(void)
+{
+ ir_unregister_map(&azurewave_ad_tu700_map);
+}
+
+module_init(init_rc_map_azurewave_ad_tu700)
+module_exit(exit_rc_map_azurewave_ad_tu700)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c
new file mode 100644
index 000000000000..63e469e2dd21
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-digitalnow-tinytwin.c
@@ -0,0 +1,98 @@
+/*
+ * DigitalNow TinyTwin remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+static struct ir_scancode digitalnow_tinytwin[] = {
+ { 0x0000, KEY_MUTE }, /* [symbol speaker] */
+ { 0x0001, KEY_VOLUMEUP },
+ { 0x0002, KEY_POWER2 }, /* TV [power button] */
+ { 0x0003, KEY_2 },
+ { 0x0004, KEY_3 },
+ { 0x0005, KEY_4 },
+ { 0x0006, KEY_6 },
+ { 0x0007, KEY_7 },
+ { 0x0008, KEY_8 },
+ { 0x0009, KEY_NUMERIC_STAR }, /* [*] */
+ { 0x000a, KEY_0 },
+ { 0x000b, KEY_NUMERIC_POUND }, /* [#] */
+ { 0x000c, KEY_RIGHT }, /* [right arrow] */
+ { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */
+ { 0x000e, KEY_RED }, /* [red] Videos */
+ { 0x0010, KEY_POWER }, /* PC [power button] */
+ { 0x0011, KEY_YELLOW }, /* [yellow] Pictures */
+ { 0x0012, KEY_DOWN }, /* [down arrow] */
+ { 0x0013, KEY_GREEN }, /* [green] Music */
+ { 0x0014, KEY_CYCLEWINDOWS }, /* BACK */
+ { 0x0015, KEY_FAVORITES }, /* MORE */
+ { 0x0016, KEY_UP }, /* [up arrow] */
+ { 0x0017, KEY_LEFT }, /* [left arrow] */
+ { 0x0018, KEY_OK }, /* OK */
+ { 0x0019, KEY_BLUE }, /* [blue] MyTV */
+ { 0x001a, KEY_REWIND }, /* REW [<<] */
+ { 0x001b, KEY_PLAY }, /* PLAY */
+ { 0x001c, KEY_5 },
+ { 0x001d, KEY_9 },
+ { 0x001e, KEY_VOLUMEDOWN },
+ { 0x001f, KEY_1 },
+ { 0x0040, KEY_STOP }, /* STOP */
+ { 0x0042, KEY_PAUSE }, /* PAUSE */
+ { 0x0043, KEY_SCREEN }, /* Aspect */
+ { 0x0044, KEY_FORWARD }, /* FWD [>>] */
+ { 0x0045, KEY_NEXT }, /* SKIP */
+ { 0x0048, KEY_RECORD }, /* RECORD */
+ { 0x0049, KEY_VIDEO }, /* RTV */
+ { 0x004a, KEY_EPG }, /* Guide */
+ { 0x004b, KEY_CHANNELUP },
+ { 0x004c, KEY_HELP }, /* Help */
+ { 0x004d, KEY_RADIO }, /* Radio */
+ { 0x004f, KEY_CHANNELDOWN },
+ { 0x0050, KEY_DVD }, /* DVD */
+ { 0x0051, KEY_AUDIO }, /* Audio */
+ { 0x0052, KEY_TITLE }, /* Title */
+ { 0x0053, KEY_NEW }, /* [symbol PIP?] */
+ { 0x0057, KEY_MENU }, /* Mouse */
+ { 0x005a, KEY_PREVIOUS }, /* REPLAY */
+};
+
+static struct rc_keymap digitalnow_tinytwin_map = {
+ .map = {
+ .scan = digitalnow_tinytwin,
+ .size = ARRAY_SIZE(digitalnow_tinytwin),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_DIGITALNOW_TINYTWIN,
+ }
+};
+
+static int __init init_rc_map_digitalnow_tinytwin(void)
+{
+ return ir_register_map(&digitalnow_tinytwin_map);
+}
+
+static void __exit exit_rc_map_digitalnow_tinytwin(void)
+{
+ ir_unregister_map(&digitalnow_tinytwin_map);
+}
+
+module_init(init_rc_map_digitalnow_tinytwin)
+module_exit(exit_rc_map_digitalnow_tinytwin)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-digittrade.c b/drivers/media/IR/keymaps/rc-digittrade.c
new file mode 100644
index 000000000000..5dece78e19c5
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-digittrade.c
@@ -0,0 +1,82 @@
+/*
+ * Digittrade DVB-T USB Stick remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* Digittrade DVB-T USB Stick remote controller. */
+/* Imported from af9015.h.
+ Initial keytable was from Alain Kalker */
+
+/* Digittrade DVB-T USB Stick */
+static struct ir_scancode digittrade[] = {
+ { 0x0000, KEY_9 },
+ { 0x0001, KEY_EPG }, /* EPG */
+ { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */
+ { 0x0003, KEY_TEXT }, /* TELETEXT */
+ { 0x0004, KEY_8 },
+ { 0x0005, KEY_MUTE }, /* MUTE */
+ { 0x0006, KEY_POWER2 }, /* POWER */
+ { 0x0009, KEY_ZOOM }, /* FULLSCREEN */
+ { 0x000a, KEY_RECORD }, /* RECORD */
+ { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */
+ { 0x000e, KEY_STOP }, /* STOP */
+ { 0x0010, KEY_OK }, /* RETURN */
+ { 0x0011, KEY_2 },
+ { 0x0012, KEY_4 },
+ { 0x0015, KEY_3 },
+ { 0x0016, KEY_5 },
+ { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */
+ { 0x0019, KEY_CHANNELUP }, /* CH Up */
+ { 0x001a, KEY_PAUSE }, /* PAUSE */
+ { 0x001b, KEY_1 },
+ { 0x001d, KEY_AUDIO }, /* DUAL SOUND */
+ { 0x001e, KEY_PLAY }, /* PLAY */
+ { 0x001f, KEY_CAMERA }, /* SNAPSHOT */
+ { 0x0040, KEY_VOLUMEUP }, /* Vol Up */
+ { 0x0048, KEY_7 },
+ { 0x004c, KEY_6 },
+ { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */
+ { 0x0054, KEY_0 },
+};
+
+static struct rc_keymap digittrade_map = {
+ .map = {
+ .scan = digittrade,
+ .size = ARRAY_SIZE(digittrade),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_DIGITTRADE,
+ }
+};
+
+static int __init init_rc_map_digittrade(void)
+{
+ return ir_register_map(&digittrade_map);
+}
+
+static void __exit exit_rc_map_digittrade(void)
+{
+ ir_unregister_map(&digittrade_map);
+}
+
+module_init(init_rc_map_digittrade)
+module_exit(exit_rc_map_digittrade)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c b/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c
new file mode 100644
index 000000000000..7521315fd876
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-leadtek-y04g0051.c
@@ -0,0 +1,99 @@
+/*
+ * LeadTek Y04G0051 remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+static struct ir_scancode leadtek_y04g0051[] = {
+ { 0x0300, KEY_POWER2 },
+ { 0x0303, KEY_SCREEN },
+ { 0x0304, KEY_RIGHT },
+ { 0x0305, KEY_1 },
+ { 0x0306, KEY_2 },
+ { 0x0307, KEY_3 },
+ { 0x0308, KEY_LEFT },
+ { 0x0309, KEY_4 },
+ { 0x030a, KEY_5 },
+ { 0x030b, KEY_6 },
+ { 0x030c, KEY_UP },
+ { 0x030d, KEY_7 },
+ { 0x030e, KEY_8 },
+ { 0x030f, KEY_9 },
+ { 0x0310, KEY_DOWN },
+ { 0x0311, KEY_AGAIN },
+ { 0x0312, KEY_0 },
+ { 0x0313, KEY_OK }, /* 1st ok */
+ { 0x0314, KEY_MUTE },
+ { 0x0316, KEY_OK }, /* 2nd ok */
+ { 0x031e, KEY_VIDEO }, /* 2nd video */
+ { 0x031b, KEY_AUDIO },
+ { 0x031f, KEY_TEXT },
+ { 0x0340, KEY_SLEEP },
+ { 0x0341, KEY_DOT },
+ { 0x0342, KEY_REWIND },
+ { 0x0343, KEY_PLAY },
+ { 0x0344, KEY_FASTFORWARD },
+ { 0x0345, KEY_TIME },
+ { 0x0346, KEY_STOP }, /* 2nd stop */
+ { 0x0347, KEY_RECORD },
+ { 0x0348, KEY_CAMERA },
+ { 0x0349, KEY_ESC },
+ { 0x034a, KEY_NEW },
+ { 0x034b, KEY_RED },
+ { 0x034c, KEY_GREEN },
+ { 0x034d, KEY_YELLOW },
+ { 0x034e, KEY_BLUE },
+ { 0x034f, KEY_MENU },
+ { 0x0350, KEY_STOP }, /* 1st stop */
+ { 0x0351, KEY_CHANNEL },
+ { 0x0352, KEY_VIDEO }, /* 1st video */
+ { 0x0353, KEY_EPG },
+ { 0x0354, KEY_PREVIOUS },
+ { 0x0355, KEY_NEXT },
+ { 0x0356, KEY_TV },
+ { 0x035a, KEY_VOLUMEDOWN },
+ { 0x035b, KEY_CHANNELUP },
+ { 0x035e, KEY_VOLUMEUP },
+ { 0x035f, KEY_CHANNELDOWN },
+};
+
+static struct rc_keymap leadtek_y04g0051_map = {
+ .map = {
+ .scan = leadtek_y04g0051,
+ .size = ARRAY_SIZE(leadtek_y04g0051),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_LEADTEK_Y04G0051,
+ }
+};
+
+static int __init init_rc_map_leadtek_y04g0051(void)
+{
+ return ir_register_map(&leadtek_y04g0051_map);
+}
+
+static void __exit exit_rc_map_leadtek_y04g0051(void)
+{
+ ir_unregister_map(&leadtek_y04g0051_map);
+}
+
+module_init(init_rc_map_leadtek_y04g0051)
+module_exit(exit_rc_map_leadtek_y04g0051)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-lme2510.c b/drivers/media/IR/keymaps/rc-lme2510.c
new file mode 100644
index 000000000000..40dcf0b4e21a
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-lme2510.c
@@ -0,0 +1,68 @@
+/* LME2510 remote control
+ *
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include
+
+
+static struct ir_scancode lme2510_rc[] = {
+ { 0xba45, KEY_0 },
+ { 0xa05f, KEY_1 },
+ { 0xaf50, KEY_2 },
+ { 0xa25d, KEY_3 },
+ { 0xbe41, KEY_4 },
+ { 0xf50a, KEY_5 },
+ { 0xbd42, KEY_6 },
+ { 0xb847, KEY_7 },
+ { 0xb649, KEY_8 },
+ { 0xfa05, KEY_9 },
+ { 0xbc43, KEY_POWER },
+ { 0xb946, KEY_SUBTITLE },
+ { 0xf906, KEY_PAUSE },
+ { 0xfc03, KEY_MEDIA_REPEAT},
+ { 0xfd02, KEY_PAUSE },
+ { 0xa15e, KEY_VOLUMEUP },
+ { 0xa35c, KEY_VOLUMEDOWN },
+ { 0xf609, KEY_CHANNELUP },
+ { 0xe51a, KEY_CHANNELDOWN },
+ { 0xe11e, KEY_PLAY },
+ { 0xe41b, KEY_ZOOM },
+ { 0xa659, KEY_MUTE },
+ { 0xa55a, KEY_TV },
+ { 0xe718, KEY_RECORD },
+ { 0xf807, KEY_EPG },
+ { 0xfe01, KEY_STOP },
+
+};
+
+static struct rc_keymap lme2510_map = {
+ .map = {
+ .scan = lme2510_rc,
+ .size = ARRAY_SIZE(lme2510_rc),
+ .ir_type = IR_TYPE_UNKNOWN,
+ .name = RC_MAP_LME2510,
+ }
+};
+
+static int __init init_rc_lme2510_map(void)
+{
+ return ir_register_map(&lme2510_map);
+}
+
+static void __exit exit_rc_lme2510_map(void)
+{
+ ir_unregister_map(&lme2510_map);
+}
+
+module_init(init_rc_lme2510_map)
+module_exit(exit_rc_lme2510_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-ii.c b/drivers/media/IR/keymaps/rc-msi-digivox-ii.c
new file mode 100644
index 000000000000..67237fbf9e4b
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-msi-digivox-ii.c
@@ -0,0 +1,67 @@
+/*
+ * MSI DIGIVOX mini II remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+static struct ir_scancode msi_digivox_ii[] = {
+ { 0x0002, KEY_2 },
+ { 0x0003, KEY_UP }, /* up */
+ { 0x0004, KEY_3 },
+ { 0x0005, KEY_CHANNELDOWN },
+ { 0x0008, KEY_5 },
+ { 0x0009, KEY_0 },
+ { 0x000b, KEY_8 },
+ { 0x000d, KEY_DOWN }, /* down */
+ { 0x0010, KEY_9 },
+ { 0x0011, KEY_7 },
+ { 0x0014, KEY_VOLUMEUP },
+ { 0x0015, KEY_CHANNELUP },
+ { 0x0016, KEY_OK },
+ { 0x0017, KEY_POWER2 },
+ { 0x001a, KEY_1 },
+ { 0x001c, KEY_4 },
+ { 0x001d, KEY_6 },
+ { 0x001f, KEY_VOLUMEDOWN },
+};
+
+static struct rc_keymap msi_digivox_ii_map = {
+ .map = {
+ .scan = msi_digivox_ii,
+ .size = ARRAY_SIZE(msi_digivox_ii),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_MSI_DIGIVOX_II,
+ }
+};
+
+static int __init init_rc_map_msi_digivox_ii(void)
+{
+ return ir_register_map(&msi_digivox_ii_map);
+}
+
+static void __exit exit_rc_map_msi_digivox_ii(void)
+{
+ ir_unregister_map(&msi_digivox_ii_map);
+}
+
+module_init(init_rc_map_msi_digivox_ii)
+module_exit(exit_rc_map_msi_digivox_ii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-msi-digivox-iii.c b/drivers/media/IR/keymaps/rc-msi-digivox-iii.c
new file mode 100644
index 000000000000..882056e52ef9
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-msi-digivox-iii.c
@@ -0,0 +1,85 @@
+/*
+ * MSI DIGIVOX mini III remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* MSI DIGIVOX mini III */
+/* Uses NEC extended 0x61d6. */
+/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote
+ since rc-kworld-315u.c lacks NEC extended address byte. */
+static struct ir_scancode msi_digivox_iii[] = {
+ { 0x61d601, KEY_VIDEO }, /* Source */
+ { 0x61d602, KEY_3 },
+ { 0x61d603, KEY_POWER }, /* ShutDown */
+ { 0x61d604, KEY_1 },
+ { 0x61d605, KEY_5 },
+ { 0x61d606, KEY_6 },
+ { 0x61d607, KEY_CHANNELDOWN }, /* CH- */
+ { 0x61d608, KEY_2 },
+ { 0x61d609, KEY_CHANNELUP }, /* CH+ */
+ { 0x61d60a, KEY_9 },
+ { 0x61d60b, KEY_ZOOM }, /* Zoom */
+ { 0x61d60c, KEY_7 },
+ { 0x61d60d, KEY_8 },
+ { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
+ { 0x61d60f, KEY_4 },
+ { 0x61d610, KEY_ESC }, /* [back up arrow] */
+ { 0x61d611, KEY_0 },
+ { 0x61d612, KEY_OK }, /* [enter arrow] */
+ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
+ { 0x61d614, KEY_RECORD }, /* Rec */
+ { 0x61d615, KEY_STOP }, /* Stop */
+ { 0x61d616, KEY_PLAY }, /* Play */
+ { 0x61d617, KEY_MUTE }, /* Mute */
+ { 0x61d618, KEY_UP },
+ { 0x61d619, KEY_DOWN },
+ { 0x61d61a, KEY_LEFT },
+ { 0x61d61b, KEY_RIGHT },
+ { 0x61d61c, KEY_RED },
+ { 0x61d61d, KEY_GREEN },
+ { 0x61d61e, KEY_YELLOW },
+ { 0x61d61f, KEY_BLUE },
+ { 0x61d643, KEY_POWER2 }, /* [red power button] */
+};
+
+static struct rc_keymap msi_digivox_iii_map = {
+ .map = {
+ .scan = msi_digivox_iii,
+ .size = ARRAY_SIZE(msi_digivox_iii),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_MSI_DIGIVOX_III,
+ }
+};
+
+static int __init init_rc_map_msi_digivox_iii(void)
+{
+ return ir_register_map(&msi_digivox_iii_map);
+}
+
+static void __exit exit_rc_map_msi_digivox_iii(void)
+{
+ ir_unregister_map(&msi_digivox_iii_map);
+}
+
+module_init(init_rc_map_msi_digivox_iii)
+module_exit(exit_rc_map_msi_digivox_iii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-rc5-streamzap.c b/drivers/media/IR/keymaps/rc-rc5-streamzap.c
deleted file mode 100644
index 4c19c58b46d8..000000000000
--- a/drivers/media/IR/keymaps/rc-rc5-streamzap.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/* rc-rc5-streamzap.c - Keytable for Streamzap PC Remote, for use
- * with the Streamzap PC Remote IR Receiver.
- *
- * 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; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include
-
-static struct ir_scancode rc5_streamzap[] = {
-/*
- * FIXME: The Streamzap remote isn't actually true RC-5, it has an extra
- * bit in it, which presently throws the in-kernel RC-5 decoder for a loop.
- * We either have to enhance the decoder to support it, add a new decoder,
- * or just rely on lirc userspace decoding.
- */
- { 0x00, KEY_NUMERIC_0 },
- { 0x01, KEY_NUMERIC_1 },
- { 0x02, KEY_NUMERIC_2 },
- { 0x03, KEY_NUMERIC_3 },
- { 0x04, KEY_NUMERIC_4 },
- { 0x05, KEY_NUMERIC_5 },
- { 0x06, KEY_NUMERIC_6 },
- { 0x07, KEY_NUMERIC_7 },
- { 0x08, KEY_NUMERIC_8 },
- { 0x0a, KEY_POWER },
- { 0x0b, KEY_MUTE },
- { 0x0c, KEY_CHANNELUP },
- { 0x0d, KEY_VOLUMEUP },
- { 0x0e, KEY_CHANNELDOWN },
- { 0x0f, KEY_VOLUMEDOWN },
- { 0x10, KEY_UP },
- { 0x11, KEY_LEFT },
- { 0x12, KEY_OK },
- { 0x13, KEY_RIGHT },
- { 0x14, KEY_DOWN },
- { 0x15, KEY_MENU },
- { 0x16, KEY_EXIT },
- { 0x17, KEY_PLAY },
- { 0x18, KEY_PAUSE },
- { 0x19, KEY_STOP },
- { 0x1a, KEY_BACK },
- { 0x1b, KEY_FORWARD },
- { 0x1c, KEY_RECORD },
- { 0x1d, KEY_REWIND },
- { 0x1e, KEY_FASTFORWARD },
- { 0x20, KEY_RED },
- { 0x21, KEY_GREEN },
- { 0x22, KEY_YELLOW },
- { 0x23, KEY_BLUE },
-
-};
-
-static struct rc_keymap rc5_streamzap_map = {
- .map = {
- .scan = rc5_streamzap,
- .size = ARRAY_SIZE(rc5_streamzap),
- .ir_type = IR_TYPE_RC5,
- .name = RC_MAP_RC5_STREAMZAP,
- }
-};
-
-static int __init init_rc_map_rc5_streamzap(void)
-{
- return ir_register_map(&rc5_streamzap_map);
-}
-
-static void __exit exit_rc_map_rc5_streamzap(void)
-{
- ir_unregister_map(&rc5_streamzap_map);
-}
-
-module_init(init_rc_map_rc5_streamzap)
-module_exit(exit_rc_map_rc5_streamzap)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jarod Wilson ");
diff --git a/drivers/media/IR/keymaps/rc-rc6-mce.c b/drivers/media/IR/keymaps/rc-rc6-mce.c
index 39557ad401b6..1b7adabbcee9 100644
--- a/drivers/media/IR/keymaps/rc-rc6-mce.c
+++ b/drivers/media/IR/keymaps/rc-rc6-mce.c
@@ -12,35 +12,8 @@
#include
static struct ir_scancode rc6_mce[] = {
- { 0x800f0415, KEY_REWIND },
- { 0x800f0414, KEY_FASTFORWARD },
- { 0x800f041b, KEY_PREVIOUS },
- { 0x800f041a, KEY_NEXT },
-
- { 0x800f0416, KEY_PLAY },
- { 0x800f0418, KEY_PAUSE },
- { 0x800f046e, KEY_PLAYPAUSE },
- { 0x800f0419, KEY_STOP },
- { 0x800f0417, KEY_RECORD },
-
- { 0x800f041e, KEY_UP },
- { 0x800f041f, KEY_DOWN },
- { 0x800f0420, KEY_LEFT },
- { 0x800f0421, KEY_RIGHT },
-
- { 0x800f040b, KEY_ENTER },
- { 0x800f0422, KEY_OK },
- { 0x800f0423, KEY_EXIT },
- { 0x800f040a, KEY_DELETE },
-
- { 0x800f040e, KEY_MUTE },
- { 0x800f0410, KEY_VOLUMEUP },
- { 0x800f0411, KEY_VOLUMEDOWN },
- { 0x800f0412, KEY_CHANNELUP },
- { 0x800f0413, KEY_CHANNELDOWN },
- { 0x800f043a, KEY_BRIGHTNESSUP },
- { 0x800f0480, KEY_BRIGHTNESSDOWN },
+ { 0x800f0400, KEY_NUMERIC_0 },
{ 0x800f0401, KEY_NUMERIC_1 },
{ 0x800f0402, KEY_NUMERIC_2 },
{ 0x800f0403, KEY_NUMERIC_3 },
@@ -50,38 +23,67 @@ static struct ir_scancode rc6_mce[] = {
{ 0x800f0407, KEY_NUMERIC_7 },
{ 0x800f0408, KEY_NUMERIC_8 },
{ 0x800f0409, KEY_NUMERIC_9 },
- { 0x800f0400, KEY_NUMERIC_0 },
- { 0x800f041d, KEY_NUMERIC_STAR },
+ { 0x800f040a, KEY_DELETE },
+ { 0x800f040b, KEY_ENTER },
+ { 0x800f040c, KEY_POWER },
+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+ { 0x800f040e, KEY_MUTE },
+ { 0x800f040f, KEY_INFO },
+
+ { 0x800f0410, KEY_VOLUMEUP },
+ { 0x800f0411, KEY_VOLUMEDOWN },
+ { 0x800f0412, KEY_CHANNELUP },
+ { 0x800f0413, KEY_CHANNELDOWN },
+
+ { 0x800f0414, KEY_FASTFORWARD },
+ { 0x800f0415, KEY_REWIND },
+ { 0x800f0416, KEY_PLAY },
+ { 0x800f0417, KEY_RECORD },
+ { 0x800f0418, KEY_PAUSE },
+ { 0x800f046e, KEY_PLAYPAUSE },
+ { 0x800f0419, KEY_STOP },
+ { 0x800f041a, KEY_NEXT },
+ { 0x800f041b, KEY_PREVIOUS },
{ 0x800f041c, KEY_NUMERIC_POUND },
+ { 0x800f041d, KEY_NUMERIC_STAR },
+
+ { 0x800f041e, KEY_UP },
+ { 0x800f041f, KEY_DOWN },
+ { 0x800f0420, KEY_LEFT },
+ { 0x800f0421, KEY_RIGHT },
+
+ { 0x800f0422, KEY_OK },
+ { 0x800f0423, KEY_EXIT },
+ { 0x800f0424, KEY_DVD },
+ { 0x800f0425, KEY_TUNER }, /* LiveTV */
+ { 0x800f0426, KEY_EPG }, /* Guide */
+ { 0x800f0427, KEY_ZOOM }, /* Aspect */
+
+ { 0x800f043a, KEY_BRIGHTNESSUP },
{ 0x800f0446, KEY_TV },
- { 0x800f0447, KEY_AUDIO }, /* My Music */
- { 0x800f0448, KEY_PVR }, /* RecordedTV */
+ { 0x800f0447, KEY_AUDIO }, /* My Music */
+ { 0x800f0448, KEY_PVR }, /* RecordedTV */
{ 0x800f0449, KEY_CAMERA },
{ 0x800f044a, KEY_VIDEO },
- { 0x800f0424, KEY_DVD },
- { 0x800f0425, KEY_TUNER }, /* LiveTV */
+ { 0x800f044c, KEY_LANGUAGE },
+ { 0x800f044d, KEY_TITLE },
+ { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
+
{ 0x800f0450, KEY_RADIO },
- { 0x800f044c, KEY_LANGUAGE },
- { 0x800f0427, KEY_ZOOM }, /* Aspect */
-
+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
{ 0x800f045b, KEY_RED },
{ 0x800f045c, KEY_GREEN },
{ 0x800f045d, KEY_YELLOW },
{ 0x800f045e, KEY_BLUE },
- { 0x800f040f, KEY_INFO },
- { 0x800f0426, KEY_EPG }, /* Guide */
- { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
- { 0x800f044d, KEY_TITLE },
-
- { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
-
- { 0x800f040c, KEY_POWER },
- { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+ { 0x800f046e, KEY_PLAYPAUSE },
+ { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
+ { 0x800f0480, KEY_BRIGHTNESSDOWN },
+ { 0x800f0481, KEY_PLAYPAUSE },
};
static struct rc_keymap rc6_mce_map = {
diff --git a/drivers/media/IR/keymaps/rc-streamzap.c b/drivers/media/IR/keymaps/rc-streamzap.c
new file mode 100644
index 000000000000..df32013a321c
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-streamzap.c
@@ -0,0 +1,82 @@
+/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use
+ * with the Streamzap PC Remote IR Receiver.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include
+
+static struct ir_scancode 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.
+ */
+ { 0x28c0, KEY_NUMERIC_0 },
+ { 0x28c1, KEY_NUMERIC_1 },
+ { 0x28c2, KEY_NUMERIC_2 },
+ { 0x28c3, KEY_NUMERIC_3 },
+ { 0x28c4, KEY_NUMERIC_4 },
+ { 0x28c5, KEY_NUMERIC_5 },
+ { 0x28c6, KEY_NUMERIC_6 },
+ { 0x28c7, KEY_NUMERIC_7 },
+ { 0x28c8, KEY_NUMERIC_8 },
+ { 0x28c9, KEY_NUMERIC_9 },
+ { 0x28ca, KEY_POWER },
+ { 0x28cb, KEY_MUTE },
+ { 0x28cc, KEY_CHANNELUP },
+ { 0x28cd, KEY_VOLUMEUP },
+ { 0x28ce, KEY_CHANNELDOWN },
+ { 0x28cf, KEY_VOLUMEDOWN },
+ { 0x28d0, KEY_UP },
+ { 0x28d1, KEY_LEFT },
+ { 0x28d2, KEY_OK },
+ { 0x28d3, KEY_RIGHT },
+ { 0x28d4, KEY_DOWN },
+ { 0x28d5, KEY_MENU },
+ { 0x28d6, KEY_EXIT },
+ { 0x28d7, KEY_PLAY },
+ { 0x28d8, KEY_PAUSE },
+ { 0x28d9, KEY_STOP },
+ { 0x28da, KEY_BACK },
+ { 0x28db, KEY_FORWARD },
+ { 0x28dc, KEY_RECORD },
+ { 0x28dd, KEY_REWIND },
+ { 0x28de, KEY_FASTFORWARD },
+ { 0x28e0, KEY_RED },
+ { 0x28e1, KEY_GREEN },
+ { 0x28e2, KEY_YELLOW },
+ { 0x28e3, KEY_BLUE },
+
+};
+
+static struct rc_keymap streamzap_map = {
+ .map = {
+ .scan = streamzap,
+ .size = ARRAY_SIZE(streamzap),
+ .ir_type = IR_TYPE_RC5_SZ,
+ .name = RC_MAP_STREAMZAP,
+ }
+};
+
+static int __init init_rc_map_streamzap(void)
+{
+ return ir_register_map(&streamzap_map);
+}
+
+static void __exit exit_rc_map_streamzap(void)
+{
+ ir_unregister_map(&streamzap_map);
+}
+
+module_init(init_rc_map_streamzap)
+module_exit(exit_rc_map_streamzap)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson ");
diff --git a/drivers/media/IR/keymaps/rc-terratec-slim.c b/drivers/media/IR/keymaps/rc-terratec-slim.c
new file mode 100644
index 000000000000..10dee4c1deff
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-terratec-slim.c
@@ -0,0 +1,79 @@
+/*
+ * TerraTec remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* TerraTec slim remote, 7 rows, 4 columns. */
+/* Uses NEC extended 0x02bd. */
+static struct ir_scancode terratec_slim[] = {
+ { 0x02bd00, KEY_1 },
+ { 0x02bd01, KEY_2 },
+ { 0x02bd02, KEY_3 },
+ { 0x02bd03, KEY_4 },
+ { 0x02bd04, KEY_5 },
+ { 0x02bd05, KEY_6 },
+ { 0x02bd06, KEY_7 },
+ { 0x02bd07, KEY_8 },
+ { 0x02bd08, KEY_9 },
+ { 0x02bd09, KEY_0 },
+ { 0x02bd0a, KEY_MUTE },
+ { 0x02bd0b, KEY_NEW }, /* symbol: PIP */
+ { 0x02bd0e, KEY_VOLUMEDOWN },
+ { 0x02bd0f, KEY_PLAYPAUSE },
+ { 0x02bd10, KEY_RIGHT },
+ { 0x02bd11, KEY_LEFT },
+ { 0x02bd12, KEY_UP },
+ { 0x02bd13, KEY_DOWN },
+ { 0x02bd15, KEY_OK },
+ { 0x02bd16, KEY_STOP },
+ { 0x02bd17, KEY_CAMERA }, /* snapshot */
+ { 0x02bd18, KEY_CHANNELUP },
+ { 0x02bd19, KEY_RECORD },
+ { 0x02bd1a, KEY_CHANNELDOWN },
+ { 0x02bd1c, KEY_ESC },
+ { 0x02bd1f, KEY_VOLUMEUP },
+ { 0x02bd44, KEY_EPG },
+ { 0x02bd45, KEY_POWER2 }, /* [red power button] */
+};
+
+static struct rc_keymap terratec_slim_map = {
+ .map = {
+ .scan = terratec_slim,
+ .size = ARRAY_SIZE(terratec_slim),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_TERRATEC_SLIM,
+ }
+};
+
+static int __init init_rc_map_terratec_slim(void)
+{
+ return ir_register_map(&terratec_slim_map);
+}
+
+static void __exit exit_rc_map_terratec_slim(void)
+{
+ ir_unregister_map(&terratec_slim_map);
+}
+
+module_init(init_rc_map_terratec_slim)
+module_exit(exit_rc_map_terratec_slim)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-total-media-in-hand.c b/drivers/media/IR/keymaps/rc-total-media-in-hand.c
new file mode 100644
index 000000000000..fd1985763781
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-total-media-in-hand.c
@@ -0,0 +1,85 @@
+/*
+ * Total Media In Hand remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* Uses NEC extended 0x02bd */
+static struct ir_scancode total_media_in_hand[] = {
+ { 0x02bd00, KEY_1 },
+ { 0x02bd01, KEY_2 },
+ { 0x02bd02, KEY_3 },
+ { 0x02bd03, KEY_4 },
+ { 0x02bd04, KEY_5 },
+ { 0x02bd05, KEY_6 },
+ { 0x02bd06, KEY_7 },
+ { 0x02bd07, KEY_8 },
+ { 0x02bd08, KEY_9 },
+ { 0x02bd09, KEY_0 },
+ { 0x02bd0a, KEY_MUTE },
+ { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */
+ { 0x02bd0c, KEY_VIDEO }, /* TV / AV */
+ { 0x02bd0e, KEY_VOLUMEDOWN },
+ { 0x02bd0f, KEY_TIME }, /* TimeShift */
+ { 0x02bd10, KEY_RIGHT }, /* right arrow */
+ { 0x02bd11, KEY_LEFT }, /* left arrow */
+ { 0x02bd12, KEY_UP }, /* up arrow */
+ { 0x02bd13, KEY_DOWN }, /* down arrow */
+ { 0x02bd14, KEY_POWER2 }, /* [red] */
+ { 0x02bd15, KEY_OK }, /* OK */
+ { 0x02bd16, KEY_STOP },
+ { 0x02bd17, KEY_CAMERA }, /* Snapshot */
+ { 0x02bd18, KEY_CHANNELUP },
+ { 0x02bd19, KEY_RECORD },
+ { 0x02bd1a, KEY_CHANNELDOWN },
+ { 0x02bd1c, KEY_ESC }, /* Esc */
+ { 0x02bd1e, KEY_PLAY },
+ { 0x02bd1f, KEY_VOLUMEUP },
+ { 0x02bd40, KEY_PAUSE },
+ { 0x02bd41, KEY_FASTFORWARD }, /* FF >> */
+ { 0x02bd42, KEY_REWIND }, /* FR << */
+ { 0x02bd43, KEY_ZOOM }, /* [window + mouse pointer] */
+ { 0x02bd44, KEY_SHUFFLE }, /* Shuffle */
+ { 0x02bd45, KEY_INFO }, /* [red (I)] */
+};
+
+static struct rc_keymap total_media_in_hand_map = {
+ .map = {
+ .scan = total_media_in_hand,
+ .size = ARRAY_SIZE(total_media_in_hand),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_TOTAL_MEDIA_IN_HAND,
+ }
+};
+
+static int __init init_rc_map_total_media_in_hand(void)
+{
+ return ir_register_map(&total_media_in_hand_map);
+}
+
+static void __exit exit_rc_map_total_media_in_hand(void)
+{
+ ir_unregister_map(&total_media_in_hand_map);
+}
+
+module_init(init_rc_map_total_media_in_hand)
+module_exit(exit_rc_map_total_media_in_hand)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-trekstor.c b/drivers/media/IR/keymaps/rc-trekstor.c
new file mode 100644
index 000000000000..91092caca452
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-trekstor.c
@@ -0,0 +1,80 @@
+/*
+ * TrekStor remote controller keytable
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include
+
+/* TrekStor DVB-T USB Stick remote controller. */
+/* Imported from af9015.h.
+ Initial keytable was from Marc Schneider */
+static struct ir_scancode trekstor[] = {
+ { 0x0084, KEY_0 },
+ { 0x0085, KEY_MUTE }, /* Mute */
+ { 0x0086, KEY_HOMEPAGE }, /* Home */
+ { 0x0087, KEY_UP }, /* Up */
+ { 0x0088, KEY_OK }, /* OK */
+ { 0x0089, KEY_RIGHT }, /* Right */
+ { 0x008a, KEY_FASTFORWARD }, /* Fast forward */
+ { 0x008b, KEY_VOLUMEUP }, /* Volume + */
+ { 0x008c, KEY_DOWN }, /* Down */
+ { 0x008d, KEY_PLAY }, /* Play/Pause */
+ { 0x008e, KEY_STOP }, /* Stop */
+ { 0x008f, KEY_EPG }, /* Info/EPG */
+ { 0x0090, KEY_7 },
+ { 0x0091, KEY_4 },
+ { 0x0092, KEY_1 },
+ { 0x0093, KEY_CHANNELDOWN }, /* Channel - */
+ { 0x0094, KEY_8 },
+ { 0x0095, KEY_5 },
+ { 0x0096, KEY_2 },
+ { 0x0097, KEY_CHANNELUP }, /* Channel + */
+ { 0x0098, KEY_9 },
+ { 0x0099, KEY_6 },
+ { 0x009a, KEY_3 },
+ { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */
+ { 0x009c, KEY_TV }, /* TV */
+ { 0x009d, KEY_RECORD }, /* Record */
+ { 0x009e, KEY_REWIND }, /* Rewind */
+ { 0x009f, KEY_LEFT }, /* Left */
+};
+
+static struct rc_keymap trekstor_map = {
+ .map = {
+ .scan = trekstor,
+ .size = ARRAY_SIZE(trekstor),
+ .ir_type = IR_TYPE_NEC,
+ .name = RC_MAP_TREKSTOR,
+ }
+};
+
+static int __init init_rc_map_trekstor(void)
+{
+ return ir_register_map(&trekstor_map);
+}
+
+static void __exit exit_rc_map_trekstor(void)
+{
+ ir_unregister_map(&trekstor_map);
+}
+
+module_init(init_rc_map_trekstor)
+module_exit(exit_rc_map_trekstor)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari ");
diff --git a/drivers/media/IR/keymaps/rc-twinhan1027.c b/drivers/media/IR/keymaps/rc-twinhan1027.c
new file mode 100644
index 000000000000..0b5d356c2d84
--- /dev/null
+++ b/drivers/media/IR/keymaps/rc-twinhan1027.c
@@ -0,0 +1,87 @@
+#include
+
+static struct ir_scancode twinhan_vp1027[] = {
+ { 0x16, KEY_POWER2 },
+ { 0x17, KEY_FAVORITES },
+ { 0x0f, KEY_TEXT },
+ { 0x48, KEY_INFO},
+ { 0x1c, KEY_EPG },
+ { 0x04, KEY_LIST },
+
+ { 0x03, KEY_1 },
+ { 0x01, KEY_2 },
+ { 0x06, KEY_3 },
+ { 0x09, KEY_4 },
+ { 0x1d, KEY_5 },
+ { 0x1f, KEY_6 },
+ { 0x0d, KEY_7 },
+ { 0x19, KEY_8 },
+ { 0x1b, KEY_9 },
+ { 0x15, KEY_0 },
+
+ { 0x0c, KEY_CANCEL },
+ { 0x4a, KEY_CLEAR },
+ { 0x13, KEY_BACKSPACE },
+ { 0x00, KEY_TAB },
+
+ { 0x4b, KEY_UP },
+ { 0x51, KEY_DOWN },
+ { 0x4e, KEY_LEFT },
+ { 0x52, KEY_RIGHT },
+ { 0x4f, KEY_ENTER },
+
+ { 0x1e, KEY_VOLUMEUP },
+ { 0x0a, KEY_VOLUMEDOWN },
+ { 0x02, KEY_CHANNELDOWN },
+ { 0x05, KEY_CHANNELUP },
+ { 0x11, KEY_RECORD },
+
+ { 0x14, KEY_PLAY },
+ { 0x4c, KEY_PAUSE },
+ { 0x1a, KEY_STOP },
+ { 0x40, KEY_REWIND },
+ { 0x12, KEY_FASTFORWARD },
+ { 0x41, KEY_PREVIOUSSONG },
+ { 0x42, KEY_NEXTSONG },
+ { 0x54, KEY_SAVE },
+ { 0x50, KEY_LANGUAGE },
+ { 0x47, KEY_MEDIA },
+ { 0x4d, KEY_SCREEN },
+ { 0x43, KEY_SUBTITLE },
+ { 0x10, KEY_MUTE },
+ { 0x49, KEY_AUDIO },
+ { 0x07, KEY_SLEEP },
+ { 0x08, KEY_VIDEO },
+ { 0x0e, KEY_AGAIN },
+ { 0x45, KEY_EQUAL },
+ { 0x46, KEY_MINUS },
+ { 0x18, KEY_RED },
+ { 0x53, KEY_GREEN },
+ { 0x5e, KEY_YELLOW },
+ { 0x5f, KEY_BLUE },
+};
+
+static struct rc_keymap twinhan_vp1027_map = {
+ .map = {
+ .scan = twinhan_vp1027,
+ .size = ARRAY_SIZE(twinhan_vp1027),
+ .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_TWINHAN_VP1027_DVBS,
+ }
+};
+
+static int __init init_rc_map_twinhan_vp1027(void)
+{
+ return ir_register_map(&twinhan_vp1027_map);
+}
+
+static void __exit exit_rc_map_twinhan_vp1027(void)
+{
+ ir_unregister_map(&twinhan_vp1027_map);
+}
+
+module_init(init_rc_map_twinhan_vp1027)
+module_exit(exit_rc_map_twinhan_vp1027)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>");
diff --git a/drivers/media/IR/lirc_dev.c b/drivers/media/IR/lirc_dev.c
index 202581808bdc..8418b14ee4d2 100644
--- a/drivers/media/IR/lirc_dev.c
+++ b/drivers/media/IR/lirc_dev.c
@@ -57,13 +57,12 @@ struct irctl {
struct task_struct *task;
long jiffies_to_wait;
-
- struct cdev cdev;
};
static DEFINE_MUTEX(lirc_dev_lock);
static struct irctl *irctls[MAX_IRCTL_DEVICES];
+static struct cdev cdevs[MAX_IRCTL_DEVICES];
/* Only used for sysfs but defined to void otherwise */
static struct class *lirc_class;
@@ -71,15 +70,13 @@ static struct class *lirc_class;
/* helper function
* initializes the irctl structure
*/
-static void init_irctl(struct irctl *ir)
+static void lirc_irctl_init(struct irctl *ir)
{
- dev_dbg(ir->d.dev, LOGHEAD "initializing irctl\n",
- ir->d.name, ir->d.minor);
mutex_init(&ir->irctl_lock);
ir->d.minor = NOPLUG;
}
-static void cleanup(struct irctl *ir)
+static void lirc_irctl_cleanup(struct irctl *ir)
{
dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
@@ -96,7 +93,7 @@ static void cleanup(struct irctl *ir)
* reads key codes from driver and puts them into buffer
* returns 0 on success
*/
-static int add_to_buf(struct irctl *ir)
+static int lirc_add_to_buf(struct irctl *ir)
{
if (ir->d.add_to_buf) {
int res = -ENODATA;
@@ -139,7 +136,7 @@ static int lirc_thread(void *irctl)
}
if (kthread_should_stop())
break;
- if (!add_to_buf(ir))
+ if (!lirc_add_to_buf(ir))
wake_up_interruptible(&ir->buf->wait_poll);
} else {
set_current_state(TASK_INTERRUPTIBLE);
@@ -154,12 +151,15 @@ static int lirc_thread(void *irctl)
}
-static struct file_operations fops = {
+static struct file_operations lirc_dev_fops = {
.owner = THIS_MODULE,
.read = lirc_dev_fop_read,
.write = lirc_dev_fop_write,
.poll = lirc_dev_fop_poll,
.unlocked_ioctl = lirc_dev_fop_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lirc_dev_fop_ioctl,
+#endif
.open = lirc_dev_fop_open,
.release = lirc_dev_fop_close,
.llseek = noop_llseek,
@@ -169,19 +169,20 @@ static int lirc_cdev_add(struct irctl *ir)
{
int retval;
struct lirc_driver *d = &ir->d;
+ struct cdev *cdev = &cdevs[d->minor];
if (d->fops) {
- cdev_init(&ir->cdev, d->fops);
- ir->cdev.owner = d->owner;
+ cdev_init(cdev, d->fops);
+ cdev->owner = d->owner;
} else {
- cdev_init(&ir->cdev, &fops);
- ir->cdev.owner = THIS_MODULE;
+ cdev_init(cdev, &lirc_dev_fops);
+ cdev->owner = THIS_MODULE;
}
- kobject_set_name(&ir->cdev.kobj, "lirc%d", d->minor);
+ kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
- retval = cdev_add(&ir->cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+ retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
if (retval)
- kobject_put(&ir->cdev.kobj);
+ kobject_put(&cdev->kobj);
return retval;
}
@@ -202,6 +203,12 @@ int lirc_register_driver(struct lirc_driver *d)
goto out;
}
+ if (!d->dev) {
+ printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
+ err = -EINVAL;
+ goto out;
+ }
+
if (MAX_IRCTL_DEVICES <= d->minor) {
dev_err(d->dev, "lirc_dev: lirc_register_driver: "
"\"minor\" must be between 0 and %d (%d)!\n",
@@ -277,7 +284,7 @@ int lirc_register_driver(struct lirc_driver *d)
err = -ENOMEM;
goto out_lock;
}
- init_irctl(ir);
+ lirc_irctl_init(ir);
irctls[minor] = ir;
d->minor = minor;
@@ -316,7 +323,6 @@ int lirc_register_driver(struct lirc_driver *d)
d->features = LIRC_CAN_REC_LIRCCODE;
ir->d = *d;
- ir->d.minor = minor;
device_create(lirc_class, ir->d.dev,
MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
@@ -357,21 +363,28 @@ EXPORT_SYMBOL(lirc_register_driver);
int lirc_unregister_driver(int minor)
{
struct irctl *ir;
+ struct cdev *cdev;
if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
- printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
- "\"minor (%d)\" must be between 0 and %d!\n",
- minor, MAX_IRCTL_DEVICES-1);
+ printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
+ "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
return -EBADRQC;
}
ir = irctls[minor];
+ if (!ir) {
+ printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
+ "for minor %d!\n", __func__, minor);
+ return -ENOENT;
+ }
+
+ cdev = &cdevs[minor];
mutex_lock(&lirc_dev_lock);
if (ir->d.minor != minor) {
- printk(KERN_ERR "lirc_dev: lirc_unregister_driver: "
- "minor (%d) device not registered!", minor);
+ printk(KERN_ERR "lirc_dev: %s: minor (%d) device not "
+ "registered!\n", __func__, minor);
mutex_unlock(&lirc_dev_lock);
return -ENOENT;
}
@@ -390,12 +403,11 @@ int lirc_unregister_driver(int minor)
wake_up_interruptible(&ir->buf->wait_poll);
mutex_lock(&ir->irctl_lock);
ir->d.set_use_dec(ir->d.data);
- module_put(ir->d.owner);
+ module_put(cdev->owner);
mutex_unlock(&ir->irctl_lock);
- cdev_del(&ir->cdev);
} else {
- cleanup(ir);
- cdev_del(&ir->cdev);
+ lirc_irctl_cleanup(ir);
+ cdev_del(cdev);
kfree(ir);
irctls[minor] = NULL;
}
@@ -409,6 +421,7 @@ EXPORT_SYMBOL(lirc_unregister_driver);
int lirc_dev_fop_open(struct inode *inode, struct file *file)
{
struct irctl *ir;
+ struct cdev *cdev;
int retval = 0;
if (iminor(inode) >= MAX_IRCTL_DEVICES) {
@@ -425,7 +438,6 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
retval = -ENODEV;
goto error;
}
- file->private_data = ir;
dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
@@ -439,13 +451,14 @@ int lirc_dev_fop_open(struct inode *inode, struct file *file)
goto error;
}
- if (try_module_get(ir->d.owner)) {
- ++ir->open;
+ cdev = &cdevs[iminor(inode)];
+ if (try_module_get(cdev->owner)) {
+ ir->open++;
retval = ir->d.set_use_inc(ir->d.data);
if (retval) {
- module_put(ir->d.owner);
- --ir->open;
+ module_put(cdev->owner);
+ ir->open--;
} else {
lirc_buffer_clear(ir->buf);
}
@@ -469,17 +482,24 @@ EXPORT_SYMBOL(lirc_dev_fop_open);
int lirc_dev_fop_close(struct inode *inode, struct file *file)
{
struct irctl *ir = irctls[iminor(inode)];
+ struct cdev *cdev = &cdevs[iminor(inode)];
+
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return -EINVAL;
+ }
dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
WARN_ON(mutex_lock_killable(&lirc_dev_lock));
- --ir->open;
+ ir->open--;
if (ir->attached) {
ir->d.set_use_dec(ir->d.data);
- module_put(ir->d.owner);
+ module_put(cdev->owner);
} else {
- cleanup(ir);
+ lirc_irctl_cleanup(ir);
+ cdev_del(cdev);
irctls[ir->d.minor] = NULL;
kfree(ir);
}
@@ -495,6 +515,11 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
unsigned int ret;
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return POLLERR;
+ }
+
dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
if (!ir->attached) {
@@ -521,9 +546,14 @@ EXPORT_SYMBOL(lirc_dev_fop_poll);
long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- unsigned long mode;
+ __u32 mode;
int result = 0;
- struct irctl *ir = file->private_data;
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+ if (!ir) {
+ printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
+ return -ENODEV;
+ }
dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
ir->d.name, ir->d.minor, cmd);
@@ -538,7 +568,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case LIRC_GET_FEATURES:
- result = put_user(ir->d.features, (unsigned long *)arg);
+ result = put_user(ir->d.features, (__u32 *)arg);
break;
case LIRC_GET_REC_MODE:
if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -548,7 +578,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
result = put_user(LIRC_REC2MODE
(ir->d.features & LIRC_CAN_REC_MASK),
- (unsigned long *)arg);
+ (__u32 *)arg);
break;
case LIRC_SET_REC_MODE:
if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
@@ -556,7 +586,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- result = get_user(mode, (unsigned long *)arg);
+ result = get_user(mode, (__u32 *)arg);
if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
result = -EINVAL;
/*
@@ -565,7 +595,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
*/
break;
case LIRC_GET_LENGTH:
- result = put_user(ir->d.code_length, (unsigned long *)arg);
+ result = put_user(ir->d.code_length, (__u32 *)arg);
break;
case LIRC_GET_MIN_TIMEOUT:
if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -574,7 +604,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- result = put_user(ir->d.min_timeout, (unsigned long *)arg);
+ result = put_user(ir->d.min_timeout, (__u32 *)arg);
break;
case LIRC_GET_MAX_TIMEOUT:
if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
@@ -583,7 +613,7 @@ long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
- result = put_user(ir->d.max_timeout, (unsigned long *)arg);
+ result = put_user(ir->d.max_timeout, (__u32 *)arg);
break;
default:
result = -EINVAL;
@@ -604,12 +634,21 @@ ssize_t lirc_dev_fop_read(struct file *file,
loff_t *ppos)
{
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
- unsigned char buf[ir->chunk_size];
+ unsigned char *buf;
int ret = 0, written = 0;
DECLARE_WAITQUEUE(wait, current);
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return -ENODEV;
+ }
+
dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
+ buf = kzalloc(ir->chunk_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
if (mutex_lock_interruptible(&ir->irctl_lock))
return -ERESTARTSYS;
if (!ir->attached) {
@@ -681,6 +720,7 @@ ssize_t lirc_dev_fop_read(struct file *file,
mutex_unlock(&ir->irctl_lock);
out_unlocked:
+ kfree(buf);
dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
ir->d.name, ir->d.minor, ret ? "-EFAULT" : "OK", ret);
@@ -709,6 +749,11 @@ ssize_t lirc_dev_fop_write(struct file *file, const char *buffer,
{
struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return -ENODEV;
+ }
+
dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
if (!ir->attached)
diff --git a/drivers/media/IR/mceusb.c b/drivers/media/IR/mceusb.c
index bc620e10ef77..9dce684fd231 100644
--- a/drivers/media/IR/mceusb.c
+++ b/drivers/media/IR/mceusb.c
@@ -46,24 +46,58 @@
"device driver"
#define DRIVER_NAME "mceusb"
-#define USB_BUFLEN 32 /* USB reception buffer length */
-#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
-#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
+#define USB_BUFLEN 32 /* USB reception buffer length */
+#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
+#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
/* MCE constants */
-#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
-#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
-#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
-#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
-#define MCE_PACKET_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
-#define MCE_CONTROL_HEADER 0x9F /* MCE status header */
-#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
-#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
-#define MCE_DEFAULT_TX_MASK 0x03 /* Val opts: TX1=0x01, TX2=0x02, ALL=0x03 */
-#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
-#define MCE_PULSE_MASK 0x7F /* Pulse mask */
-#define MCE_MAX_PULSE_LENGTH 0x7F /* Longest transmittable pulse symbol */
-#define MCE_PACKET_LENGTH_MASK 0x1F /* Packet length mask */
+#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
+#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
+#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
+#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
+#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */
+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
+#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */
+#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
+#define MCE_PULSE_MASK 0x7f /* Pulse mask */
+#define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */
+
+#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */
+#define MCE_COMMAND_HEADER 0x9f /* MCE command header */
+#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */
+#define MCE_COMMAND_NULL 0x00 /* These show up various places... */
+/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA 0x80
+#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
+
+/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+#define MCE_CMD_PING 0x03 /* Ping device */
+#define MCE_CMD_UNKNOWN 0x04 /* Unknown */
+#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */
+#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */
+#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */
+#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */
+#define MCE_CMD_UNKNOWN3 0x09 /* Unknown */
+#define MCE_CMD_UNKNOWN4 0x0a /* Unknown */
+#define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */
+#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */
+#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */
+#define MCE_CMD_UNKNOWN5 0x0e /* Unknown */
+#define MCE_CMD_UNKNOWN6 0x0f /* Unknown */
+#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */
+#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */
+#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */
+#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */
+#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */
+#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */
+#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */
+#define MCE_CMD_UNKNOWN8 0x19 /* Unknown */
+#define MCE_CMD_UNKNOWN9 0x1b /* Unknown */
+#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */
+#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */
/* module parameters */
@@ -104,14 +138,64 @@ static int debug;
#define VENDOR_NORTHSTAR 0x04eb
#define VENDOR_REALTEK 0x0bda
#define VENDOR_TIVO 0x105a
+#define VENDOR_CONEXANT 0x0572
+
+enum mceusb_model_type {
+ MCE_GEN2 = 0, /* Most boards */
+ MCE_GEN1,
+ MCE_GEN3,
+ MCE_GEN2_TX_INV,
+ POLARIS_EVK,
+};
+
+struct mceusb_model {
+ u32 mce_gen1:1;
+ u32 mce_gen2:1;
+ u32 mce_gen3:1;
+ u32 tx_mask_inverted:1;
+ u32 is_polaris:1;
+
+ const char *rc_map; /* Allow specify a per-board map */
+ const char *name; /* per-board name */
+};
+
+static const struct mceusb_model mceusb_model[] = {
+ [MCE_GEN1] = {
+ .mce_gen1 = 1,
+ .tx_mask_inverted = 1,
+ },
+ [MCE_GEN2] = {
+ .mce_gen2 = 1,
+ },
+ [MCE_GEN2_TX_INV] = {
+ .mce_gen2 = 1,
+ .tx_mask_inverted = 1,
+ },
+ [MCE_GEN3] = {
+ .mce_gen3 = 1,
+ .tx_mask_inverted = 1,
+ },
+ [POLARIS_EVK] = {
+ .is_polaris = 1,
+ /*
+ * In fact, the EVK is shipped without
+ * remotes, but we should have something handy,
+ * to allow testing it
+ */
+ .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
+ .name = "cx231xx MCE IR",
+ },
+};
static struct usb_device_id mceusb_dev_table[] = {
/* Original Microsoft MCE IR Transceiver (often HP-branded) */
- { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d),
+ .driver_info = MCE_GEN1 },
/* Philips Infrared Transceiver - Sahara branded */
{ USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
/* Philips Infrared Transceiver - HP branded */
- { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c),
+ .driver_info = MCE_GEN2_TX_INV },
/* Philips SRM5100 */
{ USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
/* Philips Infrared Transceiver - Omaura */
@@ -127,11 +211,14 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Realtek MCE IR Receiver */
{ USB_DEVICE(VENDOR_REALTEK, 0x0161) },
/* SMK/Toshiba G83C0004D410 */
- { USB_DEVICE(VENDOR_SMK, 0x031d) },
+ { USB_DEVICE(VENDOR_SMK, 0x031d),
+ .driver_info = MCE_GEN2_TX_INV },
/* SMK eHome Infrared Transceiver (Sony VAIO) */
- { USB_DEVICE(VENDOR_SMK, 0x0322) },
+ { USB_DEVICE(VENDOR_SMK, 0x0322),
+ .driver_info = MCE_GEN2_TX_INV },
/* bundled with Hauppauge PVR-150 */
- { USB_DEVICE(VENDOR_SMK, 0x0334) },
+ { USB_DEVICE(VENDOR_SMK, 0x0334),
+ .driver_info = MCE_GEN2_TX_INV },
/* SMK eHome Infrared Transceiver */
{ USB_DEVICE(VENDOR_SMK, 0x0338) },
/* Tatung eHome Infrared Transceiver */
@@ -145,17 +232,23 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Mitsumi */
{ USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
/* Topseed eHome Infrared Transceiver */
- { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001),
+ .driver_info = MCE_GEN2_TX_INV },
/* Topseed HP eHome Infrared Transceiver */
- { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006),
+ .driver_info = MCE_GEN2_TX_INV },
/* Topseed eHome Infrared Transceiver */
- { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007),
+ .driver_info = MCE_GEN2_TX_INV },
/* Topseed eHome Infrared Transceiver */
- { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008),
+ .driver_info = MCE_GEN3 },
/* Topseed eHome Infrared Transceiver */
- { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a),
+ .driver_info = MCE_GEN2_TX_INV },
/* Topseed eHome Infrared Transceiver */
- { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011),
+ .driver_info = MCE_GEN2_TX_INV },
/* Ricavision internal Infrared Transceiver */
{ USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
/* Itron ione Libra Q-11 */
@@ -185,7 +278,8 @@ static struct usb_device_id mceusb_dev_table[] = {
/* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
{ USB_DEVICE(VENDOR_FINTEK, 0x0702) },
/* Pinnacle Remote Kit */
- { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225),
+ .driver_info = MCE_GEN3 },
/* Elitegroup Computer Systems IR */
{ USB_DEVICE(VENDOR_ECS, 0x0f38) },
/* Wistron Corp. eHome Infrared Receiver */
@@ -198,37 +292,13 @@ static struct usb_device_id mceusb_dev_table[] = {
{ USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
/* TiVo PC IR Receiver */
{ USB_DEVICE(VENDOR_TIVO, 0x2000) },
+ /* Conexant SDK */
+ { USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
+ .driver_info = POLARIS_EVK },
/* Terminating entry */
{ }
};
-static struct usb_device_id gen3_list[] = {
- { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
- {}
-};
-
-static struct usb_device_id microsoft_gen1_list[] = {
- { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
- {}
-};
-
-static struct usb_device_id std_tx_mask_list[] = {
- { USB_DEVICE(VENDOR_MICROSOFT, 0x006d) },
- { USB_DEVICE(VENDOR_PHILIPS, 0x060c) },
- { USB_DEVICE(VENDOR_SMK, 0x031d) },
- { USB_DEVICE(VENDOR_SMK, 0x0322) },
- { USB_DEVICE(VENDOR_SMK, 0x0334) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x0001) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x0006) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x0007) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x0008) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x000a) },
- { USB_DEVICE(VENDOR_TOPSEED, 0x0011) },
- { USB_DEVICE(VENDOR_PINNACLE, 0x0225) },
- {}
-};
-
/* data structure for each usb transceiver */
struct mceusb_dev {
/* ir-core bits */
@@ -248,8 +318,15 @@ struct mceusb_dev {
/* buffers and dma */
unsigned char *buf_in;
unsigned int len_in;
- u8 cmd; /* MCE command type */
- u8 rem; /* Remaining IR data bytes in packet */
+
+ enum {
+ CMD_HEADER = 0,
+ SUBCMD,
+ CMD_DATA,
+ PARSE_IRDATA,
+ } parser_state;
+ u8 cmd, rem; /* Remaining IR data bytes in packet */
+
dma_addr_t dma_in;
dma_addr_t dma_out;
@@ -257,7 +334,6 @@ struct mceusb_dev {
u32 connected:1;
u32 tx_mask_inverted:1;
u32 microsoft_gen1:1;
- u32 reserved:29;
} flags;
/* transmit support */
@@ -267,6 +343,7 @@ struct mceusb_dev {
char name[128];
char phys[64];
+ enum mceusb_model_type model;
};
/*
@@ -291,43 +368,81 @@ struct mceusb_dev {
* - SET_RX_TIMEOUT sets the receiver timeout
* - SET_RX_SENSOR sets which receiver sensor to use
*/
-static char DEVICE_RESET[] = {0x00, 0xff, 0xaa};
-static char GET_REVISION[] = {0xff, 0x0b};
-static char GET_UNKNOWN[] = {0xff, 0x18};
-static char GET_UNKNOWN2[] = {0x9f, 0x05};
-static char GET_CARRIER_FREQ[] = {0x9f, 0x07};
-static char GET_RX_TIMEOUT[] = {0x9f, 0x0d};
-static char GET_TX_BITMASK[] = {0x9f, 0x13};
-static char GET_RX_SENSOR[] = {0x9f, 0x15};
+static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
+ MCE_CMD_DEVICE_RESET};
+static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
+static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
+static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
+static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
+static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
+static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
/* sub in desired values in lower byte or bytes for full command */
/* FIXME: make use of these for transmit.
-static char SET_CARRIER_FREQ[] = {0x9f, 0x06, 0x00, 0x00};
-static char SET_TX_BITMASK[] = {0x9f, 0x08, 0x00};
-static char SET_RX_TIMEOUT[] = {0x9f, 0x0c, 0x00, 0x00};
-static char SET_RX_SENSOR[] = {0x9f, 0x14, 0x00};
+static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER,
+ MCE_CMD_S_CARRIER, 0x00, 0x00};
+static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
+static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER,
+ MCE_CMD_S_TIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER,
+ MCE_CMD_S_RXSENSOR, 0x00};
*/
+static int mceusb_cmdsize(u8 cmd, u8 subcmd)
+{
+ int datasize = 0;
+
+ switch (cmd) {
+ case MCE_COMMAND_NULL:
+ if (subcmd == MCE_HW_CMD_HEADER)
+ datasize = 1;
+ break;
+ case MCE_HW_CMD_HEADER:
+ switch (subcmd) {
+ case MCE_CMD_G_REVISION:
+ datasize = 2;
+ break;
+ }
+ case MCE_COMMAND_HEADER:
+ switch (subcmd) {
+ case MCE_CMD_UNKNOWN:
+ case MCE_CMD_S_CARRIER:
+ case MCE_CMD_S_TIMEOUT:
+ case MCE_CMD_G_RXSENSOR:
+ datasize = 2;
+ break;
+ case MCE_CMD_S_TXMASK:
+ case MCE_CMD_S_RXSENSOR:
+ datasize = 1;
+ break;
+ }
+ }
+ return datasize;
+}
+
static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
- int len, bool out)
+ int offset, int len, bool out)
{
char codes[USB_BUFLEN * 3 + 1];
char inout[9];
- int i;
u8 cmd, subcmd, data1, data2;
struct device *dev = ir->dev;
- int idx = 0;
+ int i, start, skip = 0;
+
+ if (!debug)
+ return;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
if (ir->flags.microsoft_gen1 && !out)
- idx = 2;
+ skip = 2;
- if (len <= idx)
+ if (len <= skip)
return;
for (i = 0; i < len && i < USB_BUFLEN; i++)
- snprintf(codes + i * 3, 4, "%02x ", buf[i] & 0xFF);
+ snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
- dev_info(dev, "%sx data: %s (length=%d)\n",
+ dev_info(dev, "%sx data: %s(length=%d)\n",
(out ? "t" : "r"), codes, len);
if (out)
@@ -335,91 +450,93 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
else
strcpy(inout, "Got\0");
- cmd = buf[idx] & 0xff;
- subcmd = buf[idx + 1] & 0xff;
- data1 = buf[idx + 2] & 0xff;
- data2 = buf[idx + 3] & 0xff;
+ start = offset + skip;
+ cmd = buf[start] & 0xff;
+ subcmd = buf[start + 1] & 0xff;
+ data1 = buf[start + 2] & 0xff;
+ data2 = buf[start + 3] & 0xff;
switch (cmd) {
- case 0x00:
- if (subcmd == 0xff && data1 == 0xaa)
+ case MCE_COMMAND_NULL:
+ if ((subcmd == MCE_HW_CMD_HEADER) &&
+ (data1 == MCE_CMD_DEVICE_RESET))
dev_info(dev, "Device reset requested\n");
else
dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
cmd, subcmd);
break;
- case 0xff:
+ case MCE_HW_CMD_HEADER:
switch (subcmd) {
- case 0x0b:
+ case MCE_CMD_G_REVISION:
if (len == 2)
dev_info(dev, "Get hw/sw rev?\n");
else
dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
"0x%02x 0x%02x\n", data1, data2,
- buf[idx + 4], buf[idx + 5]);
+ buf[start + 4], buf[start + 5]);
break;
- case 0xaa:
+ case MCE_CMD_DEVICE_RESET:
dev_info(dev, "Device reset requested\n");
break;
- case 0xfe:
+ case MCE_RSP_CMD_INVALID:
dev_info(dev, "Previous command not supported\n");
break;
- case 0x18:
- case 0x1b:
+ case MCE_CMD_UNKNOWN7:
+ case MCE_CMD_UNKNOWN9:
default:
dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
cmd, subcmd);
break;
}
break;
- case 0x9f:
+ case MCE_COMMAND_HEADER:
switch (subcmd) {
- case 0x03:
+ case MCE_CMD_PING:
dev_info(dev, "Ping\n");
break;
- case 0x04:
+ case MCE_CMD_UNKNOWN:
dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
data1, data2);
break;
- case 0x06:
+ case MCE_CMD_S_CARRIER:
dev_info(dev, "%s carrier mode and freq of "
"0x%02x 0x%02x\n", inout, data1, data2);
break;
- case 0x07:
+ case MCE_CMD_G_CARRIER:
dev_info(dev, "Get carrier mode and freq\n");
break;
- case 0x08:
+ case MCE_CMD_S_TXMASK:
dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
inout, data1);
break;
- case 0x0c:
+ case MCE_CMD_S_TIMEOUT:
/* value is in units of 50us, so x*50/100 or x/2 ms */
dev_info(dev, "%s receive timeout of %d ms\n",
inout, ((data1 << 8) | data2) / 2);
break;
- case 0x0d:
+ case MCE_CMD_G_TIMEOUT:
dev_info(dev, "Get receive timeout\n");
break;
- case 0x13:
+ case MCE_CMD_G_TXMASK:
dev_info(dev, "Get transmit blaster mask\n");
break;
- case 0x14:
+ case MCE_CMD_S_RXSENSOR:
dev_info(dev, "%s %s-range receive sensor in use\n",
inout, data1 == 0x02 ? "short" : "long");
break;
- case 0x15:
+ case MCE_CMD_G_RXSENSOR:
if (len == 2)
dev_info(dev, "Get receive sensor\n");
else
dev_info(dev, "Received pulse count is %d\n",
((data1 << 8) | data2));
break;
- case 0xfe:
+ case MCE_RSP_CMD_INVALID:
dev_info(dev, "Error! Hardware is likely wedged...\n");
break;
- case 0x05:
- case 0x09:
- case 0x0f:
+ case MCE_CMD_UNKNOWN2:
+ case MCE_CMD_UNKNOWN3:
+ case MCE_CMD_UNKNOWN5:
default:
dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
cmd, subcmd);
@@ -429,6 +546,12 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
default:
break;
}
+
+ if (cmd == MCE_IRDATA_TRAILER)
+ dev_info(dev, "End of raw IR data\n");
+ else if ((cmd != MCE_COMMAND_HEADER) &&
+ ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+ dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
}
static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
@@ -446,9 +569,7 @@ static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
urb->status, len);
- if (debug)
- mceusb_dev_printdata(ir, urb->transfer_buffer,
- len, true);
+ mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
}
}
@@ -536,8 +657,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
return -ENOMEM;
/* MCE tx init header */
- cmdbuf[cmdcount++] = MCE_CONTROL_HEADER;
- cmdbuf[cmdcount++] = 0x08;
+ cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
+ cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
cmdbuf[cmdcount++] = ir->tx_mask;
/* Generate mce packet data */
@@ -551,7 +672,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
if ((cmdcount < MCE_CMDBUF_SIZE) &&
(cmdcount - MCE_TX_HEADER_LENGTH) %
MCE_CODE_LENGTH == 0)
- cmdbuf[cmdcount++] = MCE_PACKET_HEADER;
+ cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
/* Insert mce packet data */
if (cmdcount < MCE_CMDBUF_SIZE)
@@ -570,7 +691,8 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
/* Fix packet length in last header */
cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
- 0x80 + (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH - 1;
+ MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
+ MCE_CODE_LENGTH - 1;
/* Check if we have room for the empty packet at the end */
if (cmdcount >= MCE_CMDBUF_SIZE) {
@@ -579,7 +701,7 @@ static int mceusb_tx_ir(void *priv, int *txbuf, u32 n)
}
/* All mce commands end with an empty packet (0x80) */
- cmdbuf[cmdcount++] = 0x80;
+ cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
/* Transmit the command to the mce device */
mce_async_out(ir, cmdbuf, cmdcount);
@@ -608,7 +730,8 @@ static int mceusb_set_tx_mask(void *priv, u32 mask)
struct mceusb_dev *ir = priv;
if (ir->flags.tx_mask_inverted)
- ir->tx_mask = (mask != 0x03 ? mask ^ 0x03 : mask) << 1;
+ ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
+ mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
else
ir->tx_mask = mask;
@@ -621,7 +744,8 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
struct mceusb_dev *ir = priv;
int clk = 10000000;
int prescaler = 0, divisor = 0;
- unsigned char cmdbuf[4] = { 0x9f, 0x06, 0x00, 0x00 };
+ unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
+ MCE_CMD_S_CARRIER, 0x00, 0x00 };
/* Carrier has changed */
if (ir->carrier != carrier) {
@@ -629,7 +753,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
if (carrier == 0) {
ir->carrier = carrier;
cmdbuf[2] = 0x01;
- cmdbuf[3] = 0x80;
+ cmdbuf[3] = MCE_IRDATA_TRAILER;
dev_dbg(ir->dev, "%s: disabling carrier "
"modulation\n", __func__);
mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
@@ -638,7 +762,7 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
for (prescaler = 0; prescaler < 4; ++prescaler) {
divisor = (clk >> (2 * prescaler)) / carrier;
- if (divisor <= 0xFF) {
+ if (divisor <= 0xff) {
ir->carrier = carrier;
cmdbuf[2] = prescaler;
cmdbuf[3] = divisor;
@@ -660,47 +784,36 @@ static int mceusb_set_tx_carrier(void *priv, u32 carrier)
static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
{
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- int i, start_index = 0;
- u8 hdr = MCE_CONTROL_HEADER;
+ DEFINE_IR_RAW_EVENT(rawir);
+ int i = 0;
/* skip meaningless 0xb1 0x60 header bytes on orig receiver */
if (ir->flags.microsoft_gen1)
- start_index = 2;
+ i = 2;
- for (i = start_index; i < buf_len;) {
- if (ir->rem == 0) {
- /* decode mce packets of the form (84),AA,BB,CC,DD */
- /* IR data packets can span USB messages - rem */
- hdr = ir->buf_in[i];
- ir->rem = (hdr & MCE_PACKET_LENGTH_MASK);
- ir->cmd = (hdr & ~MCE_PACKET_LENGTH_MASK);
- dev_dbg(ir->dev, "New data. rem: 0x%02x, cmd: 0x%02x\n",
- ir->rem, ir->cmd);
- i++;
- }
-
- /* don't process MCE commands */
- if (hdr == MCE_CONTROL_HEADER || hdr == 0xff) {
- ir->rem = 0;
- return;
- }
-
- for (; (ir->rem > 0) && (i < buf_len); i++) {
+ for (; i < buf_len; i++) {
+ switch (ir->parser_state) {
+ case SUBCMD:
+ ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
+ mceusb_dev_printdata(ir, ir->buf_in, i - 1,
+ ir->rem + 2, false);
+ ir->parser_state = CMD_DATA;
+ break;
+ case PARSE_IRDATA:
ir->rem--;
-
rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
* MCE_TIME_UNIT * 1000;
if ((ir->buf_in[i] & MCE_PULSE_MASK) == 0x7f) {
- if (ir->rawir.pulse == rawir.pulse)
+ if (ir->rawir.pulse == rawir.pulse) {
ir->rawir.duration += rawir.duration;
- else {
+ } else {
ir->rawir.duration = rawir.duration;
ir->rawir.pulse = rawir.pulse;
}
- continue;
+ if (ir->rem)
+ break;
}
rawir.duration += ir->rawir.duration;
ir->rawir.duration = 0;
@@ -711,14 +824,40 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
rawir.duration);
ir_raw_event_store(ir->idev, &rawir);
+ break;
+ case CMD_DATA:
+ ir->rem--;
+ break;
+ case CMD_HEADER:
+ /* decode mce packets of the form (84),AA,BB,CC,DD */
+ /* IR data packets can span USB messages - rem */
+ ir->cmd = ir->buf_in[i];
+ if ((ir->cmd == MCE_COMMAND_HEADER) ||
+ ((ir->cmd & MCE_COMMAND_MASK) !=
+ MCE_COMMAND_IRDATA)) {
+ ir->parser_state = SUBCMD;
+ continue;
+ }
+ ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
+ mceusb_dev_printdata(ir, ir->buf_in, i, ir->rem + 1, false);
+ if (ir->rem) {
+ ir->parser_state = PARSE_IRDATA;
+ break;
+ }
+ /*
+ * a package with len=0 (e. g. 0x80) means end of
+ * data. We could use it to do the call to
+ * ir_raw_event_handle(). For now, we don't need to
+ * use it.
+ */
+ break;
}
- if (ir->buf_in[i] == 0x80 || ir->buf_in[i] == 0x9f)
- ir->rem = 0;
-
- dev_dbg(ir->dev, "calling ir_raw_event_handle\n");
- ir_raw_event_handle(ir->idev);
+ if (ir->parser_state != CMD_HEADER && !ir->rem)
+ ir->parser_state = CMD_HEADER;
}
+ dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+ ir_raw_event_handle(ir->idev);
}
static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
@@ -737,9 +876,6 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
buf_len = urb->actual_length;
- if (debug)
- mceusb_dev_printdata(ir, urb->transfer_buffer, buf_len, false);
-
if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
ir->send_flags = SEND_FLAG_COMPLETE;
dev_dbg(ir->dev, "setup answer received %d bytes\n",
@@ -760,6 +896,7 @@ static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
case -EPIPE:
default:
+ dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
break;
}
@@ -865,6 +1002,8 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
struct input_dev *idev;
struct ir_dev_props *props;
struct device *dev = ir->dev;
+ const char *rc_map = RC_MAP_RC6_MCE;
+ const char *name = "Media Center Ed. eHome Infrared Remote Transceiver";
int ret = -ENODEV;
idev = input_allocate_device();
@@ -880,8 +1019,11 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
goto props_alloc_failed;
}
- snprintf(ir->name, sizeof(ir->name), "Media Center Ed. eHome "
- "Infrared Remote Transceiver (%04x:%04x)",
+ if (mceusb_model[ir->model].name)
+ name = mceusb_model[ir->model].name;
+
+ snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
+ name,
le16_to_cpu(ir->usbdev->descriptor.idVendor),
le16_to_cpu(ir->usbdev->descriptor.idProduct));
@@ -899,7 +1041,10 @@ static struct input_dev *mceusb_init_input_dev(struct mceusb_dev *ir)
ir->props = props;
- ret = ir_input_register(idev, RC_MAP_RC6_MCE, props, DRIVER_NAME);
+ if (mceusb_model[ir->model].rc_map)
+ rc_map = mceusb_model[ir->model].rc_map;
+
+ ret = ir_input_register(idev, rc_map, props, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
goto irdev_failed;
@@ -926,17 +1071,26 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
struct mceusb_dev *ir = NULL;
int pipe, maxp, i;
char buf[63], name[128] = "";
+ enum mceusb_model_type model = id->driver_info;
bool is_gen3;
bool is_microsoft_gen1;
bool tx_mask_inverted;
+ bool is_polaris;
dev_dbg(&intf->dev, ": %s called\n", __func__);
idesc = intf->cur_altsetting;
- is_gen3 = usb_match_id(intf, gen3_list) ? 1 : 0;
- is_microsoft_gen1 = usb_match_id(intf, microsoft_gen1_list) ? 1 : 0;
- tx_mask_inverted = usb_match_id(intf, std_tx_mask_list) ? 0 : 1;
+ is_gen3 = mceusb_model[model].mce_gen3;
+ is_microsoft_gen1 = mceusb_model[model].mce_gen1;
+ tx_mask_inverted = mceusb_model[model].tx_mask_inverted;
+ is_polaris = mceusb_model[model].is_polaris;
+
+ if (is_polaris) {
+ /* Interface 0 is IR */
+ if (idesc->desc.bInterfaceNumber)
+ return -ENODEV;
+ }
/* step through the endpoints to find first bulk in and out endpoint */
for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
@@ -997,6 +1151,9 @@ static int __devinit mceusb_dev_probe(struct usb_interface *intf,
ir->len_in = maxp;
ir->flags.microsoft_gen1 = is_microsoft_gen1;
ir->flags.tx_mask_inverted = tx_mask_inverted;
+ ir->model = model;
+
+ init_ir_raw_event(&ir->rawir);
/* Saving usb interface data for use by the transmitter routine */
ir->usb_ep_in = ep_in;
diff --git a/drivers/media/IR/nuvoton-cir.c b/drivers/media/IR/nuvoton-cir.c
new file mode 100644
index 000000000000..301be53aee85
--- /dev/null
+++ b/drivers/media/IR/nuvoton-cir.c
@@ -0,0 +1,1246 @@
+/*
+ * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
+ *
+ * Copyright (C) 2010 Jarod Wilson
+ * Copyright (C) 2009 Nuvoton PS Team
+ *
+ * Special thanks to Nuvoton for providing hardware, spec sheets and
+ * sample code upon which portions of this driver are based. Indirect
+ * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
+ * modeled after.
+ *
+ * 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.
+ *
+ * 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
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "nuvoton-cir.h"
+
+static char *chip_id = "w836x7hg";
+
+/* write val to config reg */
+static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+ outb(reg, nvt->cr_efir);
+ outb(val, nvt->cr_efdr);
+}
+
+/* read val from config reg */
+static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg)
+{
+ outb(reg, nvt->cr_efir);
+ return inb(nvt->cr_efdr);
+}
+
+/* update config register bit without changing other bits */
+static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+ u8 tmp = nvt_cr_read(nvt, reg) | val;
+ nvt_cr_write(nvt, tmp, reg);
+}
+
+/* clear config register bit without changing other bits */
+static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+ u8 tmp = nvt_cr_read(nvt, reg) & ~val;
+ nvt_cr_write(nvt, tmp, reg);
+}
+
+/* enter extended function mode */
+static inline void nvt_efm_enable(struct nvt_dev *nvt)
+{
+ /* Enabling Extended Function Mode explicitly requires writing 2x */
+ outb(EFER_EFM_ENABLE, nvt->cr_efir);
+ outb(EFER_EFM_ENABLE, nvt->cr_efir);
+}
+
+/* exit extended function mode */
+static inline void nvt_efm_disable(struct nvt_dev *nvt)
+{
+ outb(EFER_EFM_DISABLE, nvt->cr_efir);
+}
+
+/*
+ * When you want to address a specific logical device, write its logical
+ * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing
+ * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN.
+ */
+static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev)
+{
+ outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir);
+ outb(ldev, nvt->cr_efdr);
+}
+
+/* write val to cir config register */
+static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset)
+{
+ outb(val, nvt->cir_addr + offset);
+}
+
+/* read val from cir config register */
+static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset)
+{
+ u8 val;
+
+ val = inb(nvt->cir_addr + offset);
+
+ return val;
+}
+
+/* write val to cir wake register */
+static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt,
+ u8 val, u8 offset)
+{
+ outb(val, nvt->cir_wake_addr + offset);
+}
+
+/* read val from cir wake config register */
+static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
+{
+ u8 val;
+
+ val = inb(nvt->cir_wake_addr + offset);
+
+ return val;
+}
+
+#define pr_reg(text, ...) \
+ printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+/* dump current cir register contents */
+static void cir_dump_regs(struct nvt_dev *nvt)
+{
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+
+ pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
+ pr_reg(" * CR CIR ACTIVE : 0x%x\n",
+ nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+ pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
+ (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+ nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+ pr_reg(" * CR CIR IRQ NUM: 0x%x\n",
+ nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+
+ nvt_efm_disable(nvt);
+
+ pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
+ pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
+ pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
+ pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
+ pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
+ pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
+ pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
+ pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
+ pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
+ pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
+ pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
+ pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
+ pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
+ pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
+ pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
+ pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
+ pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
+}
+
+/* dump current cir wake register contents */
+static void cir_wake_dump_regs(struct nvt_dev *nvt)
+{
+ u8 i, fifo_len;
+
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+
+ pr_reg("%s: Dump CIR WAKE logical device registers:\n",
+ NVT_DRIVER_NAME);
+ pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n",
+ nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+ pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n",
+ (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+ nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+ pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n",
+ nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+
+ nvt_efm_disable(nvt);
+
+ pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
+ pr_reg(" * IRCON: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
+ pr_reg(" * IRSTS: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
+ pr_reg(" * IREN: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
+ pr_reg(" * FIFO CMP DEEP: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
+ pr_reg(" * FIFO CMP TOL: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
+ pr_reg(" * FIFO COUNT: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
+ pr_reg(" * SLCH: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
+ pr_reg(" * SLCL: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
+ pr_reg(" * FIFOCON: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
+ pr_reg(" * SRXFSTS: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
+ pr_reg(" * SAMPLE RX FIFO: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
+ pr_reg(" * WR FIFO DATA: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
+ pr_reg(" * RD FIFO ONLY: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+ pr_reg(" * RD FIFO ONLY IDX: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
+ pr_reg(" * FIFO IGNORE: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
+ pr_reg(" * IRFSM: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
+
+ fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
+ pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
+ pr_reg("* Contents = ");
+ for (i = 0; i < fifo_len; i++)
+ printk(KERN_CONT "%02x ",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+ printk(KERN_CONT "\n");
+}
+
+/* detect hardware features */
+static int nvt_hw_detect(struct nvt_dev *nvt)
+{
+ unsigned long flags;
+ u8 chip_major, chip_minor;
+ int ret = 0;
+
+ nvt_efm_enable(nvt);
+
+ /* Check if we're wired for the alternate EFER setup */
+ chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+ if (chip_major == 0xff) {
+ nvt->cr_efir = CR_EFIR2;
+ nvt->cr_efdr = CR_EFDR2;
+ nvt_efm_enable(nvt);
+ chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+ }
+
+ chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+ nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
+
+ if (chip_major != CHIP_ID_HIGH &&
+ (chip_minor != CHIP_ID_LOW || chip_minor != CHIP_ID_LOW2))
+ ret = -ENODEV;
+
+ nvt_efm_disable(nvt);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->chip_major = chip_major;
+ nvt->chip_minor = chip_minor;
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ return ret;
+}
+
+static void nvt_cir_ldev_init(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */
+ val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL);
+ val &= OUTPUT_PIN_SEL_MASK;
+ val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB);
+ nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL);
+
+ /* Select CIR logical device and enable */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI);
+ nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+
+ nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC);
+
+ nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d",
+ nvt->cir_addr, nvt->cir_irq);
+}
+
+static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
+{
+ /* Select ACPI logical device, enable it and CIR Wake */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ /* Enable CIR Wake via PSOUT# (Pin60) */
+ nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
+
+ /* enable cir interrupt of mouse/keyboard IRQ event */
+ nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
+
+ /* enable pme interrupt of cir wakeup event */
+ nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
+
+ /* Select CIR Wake logical device and enable */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI);
+ nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+
+ nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC);
+
+ nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d",
+ nvt->cir_wake_addr, nvt->cir_wake_irq);
+}
+
+/* clear out the hardware's cir rx fifo */
+static void nvt_clear_cir_fifo(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+ nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
+}
+
+/* clear out the hardware's cir wake rx fifo */
+static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON);
+ nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR,
+ CIR_WAKE_FIFOCON);
+}
+
+/* clear out the hardware's cir tx fifo */
+static void nvt_clear_tx_fifo(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+ nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON);
+}
+
+/* enable RX Trigger Level Reach and Packet End interrupts */
+static void nvt_set_cir_iren(struct nvt_dev *nvt)
+{
+ u8 iren;
+
+ iren = CIR_IREN_RTR | CIR_IREN_PE;
+ nvt_cir_reg_write(nvt, iren, CIR_IREN);
+}
+
+static void nvt_cir_regs_init(struct nvt_dev *nvt)
+{
+ /* set sample limit count (PE interrupt raised when reached) */
+ nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH);
+ nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL);
+
+ /* set fifo irq trigger levels */
+ nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV |
+ CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON);
+
+ /*
+ * Enable TX and RX, specify carrier on = low, off = high, and set
+ * sample period (currently 50us)
+ */
+ nvt_cir_reg_write(nvt,
+ CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+ CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_IRCON);
+
+ /* clear hardware rx and tx fifos */
+ nvt_clear_cir_fifo(nvt);
+ nvt_clear_tx_fifo(nvt);
+
+ /* clear any and all stray interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* and finally, enable interrupts */
+ nvt_set_cir_iren(nvt);
+}
+
+static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
+{
+ /* set number of bytes needed for wake key comparison (default 67) */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_LEN, CIR_WAKE_FIFO_CMP_DEEP);
+
+ /* set tolerance/variance allowed per byte during wake compare */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE,
+ CIR_WAKE_FIFO_CMP_TOL);
+
+ /* set sample limit count (PE interrupt raised when reached) */
+ nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH);
+ nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL);
+
+ /* set cir wake fifo rx trigger level (currently 67) */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV,
+ CIR_WAKE_FIFOCON);
+
+ /*
+ * Enable TX and RX, specific carrier on = low, off = high, and set
+ * sample period (currently 50us)
+ */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+ CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
+ CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_WAKE_IRCON);
+
+ /* clear cir wake rx fifo */
+ nvt_clear_cir_wake_fifo(nvt);
+
+ /* clear any and all stray interrupts */
+ nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+}
+
+static void nvt_enable_wake(struct nvt_dev *nvt)
+{
+ nvt_efm_enable(nvt);
+
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
+ nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
+ nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
+ nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
+
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+ CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
+ CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_WAKE_IRCON);
+ nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+ nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+}
+
+/* rx carrier detect only works in learning mode, must be called w/nvt_lock */
+static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
+{
+ u32 count, carrier, duration = 0;
+ int i;
+
+ count = nvt_cir_reg_read(nvt, CIR_FCCL) |
+ nvt_cir_reg_read(nvt, CIR_FCCH) << 8;
+
+ for (i = 0; i < nvt->pkts; i++) {
+ if (nvt->buf[i] & BUF_PULSE_BIT)
+ duration += nvt->buf[i] & BUF_LEN_MASK;
+ }
+
+ duration *= SAMPLE_PERIOD;
+
+ if (!count || !duration) {
+ nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)",
+ count, duration);
+ return 0;
+ }
+
+ carrier = (count * 1000000) / duration;
+
+ if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER))
+ nvt_dbg("WTF? Carrier frequency out of range!");
+
+ nvt_dbg("Carrier frequency: %u (count %u, duration %u)",
+ carrier, count, duration);
+
+ return carrier;
+}
+
+/*
+ * set carrier frequency
+ *
+ * set carrier on 2 registers: CP & CC
+ * always set CP as 0x81
+ * set CC by SPEC, CC = 3MHz/carrier - 1
+ */
+static int nvt_set_tx_carrier(void *data, u32 carrier)
+{
+ struct nvt_dev *nvt = data;
+ u16 val;
+
+ nvt_cir_reg_write(nvt, 1, CIR_CP);
+ val = 3000000 / (carrier) - 1;
+ nvt_cir_reg_write(nvt, val & 0xff, CIR_CC);
+
+ nvt_dbg("cp: 0x%x cc: 0x%x\n",
+ nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC));
+
+ return 0;
+}
+
+/*
+ * nvt_tx_ir
+ *
+ * 1) clean TX fifo first (handled by AP)
+ * 2) copy data from user space
+ * 3) disable RX interrupts, enable TX interrupts: TTR & TFU
+ * 4) send 9 packets to TX FIFO to open TTR
+ * in interrupt_handler:
+ * 5) send all data out
+ * go back to write():
+ * 6) disable TX interrupts, re-enable RX interupts
+ *
+ * The key problem of this function is user space data may larger than
+ * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to
+ * buf, and keep current copied data buf num in cur_buf_num. But driver's buf
+ * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
+ * set TXFCONT as 0xff, until buf_count less than 0xff.
+ */
+static int nvt_tx_ir(void *priv, int *txbuf, u32 n)
+{
+ struct nvt_dev *nvt = priv;
+ unsigned long flags;
+ size_t cur_count;
+ unsigned int i;
+ u8 iren;
+ int ret;
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+
+ if (n >= TX_BUF_LEN) {
+ nvt->tx.buf_count = cur_count = TX_BUF_LEN;
+ ret = TX_BUF_LEN;
+ } else {
+ nvt->tx.buf_count = cur_count = n;
+ ret = n;
+ }
+
+ memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
+
+ nvt->tx.cur_buf_num = 0;
+
+ /* save currently enabled interrupts */
+ iren = nvt_cir_reg_read(nvt, CIR_IREN);
+
+ /* now disable all interrupts, save TFU & TTR */
+ nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN);
+
+ nvt->tx.tx_state = ST_TX_REPLY;
+
+ nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 |
+ CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
+
+ /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */
+ for (i = 0; i < 9; i++)
+ nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO);
+
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST);
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ nvt->tx.tx_state = ST_TX_NONE;
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ /* restore enabled interrupts to prior state */
+ nvt_cir_reg_write(nvt, iren, CIR_IREN);
+
+ return ret;
+}
+
+/* dump contents of the last rx buffer we got from the hw rx fifo */
+static void nvt_dump_rx_buf(struct nvt_dev *nvt)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts);
+ for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++)
+ printk(KERN_CONT "0x%02x ", nvt->buf[i]);
+ printk(KERN_CONT "\n");
+}
+
+/*
+ * Process raw data in rx driver buffer, store it in raw IR event kfifo,
+ * trigger decode when appropriate.
+ *
+ * We get IR data samples one byte at a time. If the msb is set, its a pulse,
+ * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD
+ * (default 50us) intervals for that pulse/space. A discrete signal is
+ * followed by a series of 0x7f packets, then either 0x7 or 0x80
+ * to signal more IR coming (repeats) or end of IR, respectively. We store
+ * sample data in the raw event kfifo until we see 0x7 (except f)
+ * or 0x80, at which time, we trigger a decode operation.
+ */
+static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ unsigned int count;
+ u32 carrier;
+ u8 sample;
+ int i;
+
+ nvt_dbg_verbose("%s firing", __func__);
+
+ if (debug)
+ nvt_dump_rx_buf(nvt);
+
+ if (nvt->carrier_detect_enabled)
+ carrier = nvt_rx_carrier_detect(nvt);
+
+ count = nvt->pkts;
+ nvt_dbg_verbose("Processing buffer of len %d", count);
+
+ for (i = 0; i < count; i++) {
+ nvt->pkts--;
+ sample = nvt->buf[i];
+
+ rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
+ rawir.duration = (sample & BUF_LEN_MASK)
+ * SAMPLE_PERIOD * 1000;
+
+ if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
+ if (nvt->rawir.pulse == rawir.pulse)
+ nvt->rawir.duration += rawir.duration;
+ else {
+ nvt->rawir.duration = rawir.duration;
+ nvt->rawir.pulse = rawir.pulse;
+ }
+ continue;
+ }
+
+ rawir.duration += nvt->rawir.duration;
+
+ init_ir_raw_event(&nvt->rawir);
+ nvt->rawir.duration = 0;
+ nvt->rawir.pulse = rawir.pulse;
+
+ if (sample == BUF_PULSE_BIT)
+ rawir.pulse = false;
+
+ if (rawir.duration) {
+ nvt_dbg("Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+
+ ir_raw_event_store(nvt->rdev, &rawir);
+ }
+
+ /*
+ * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
+ * indicates end of IR signal, but new data incoming. In both
+ * cases, it means we're ready to call ir_raw_event_handle
+ */
+ if (sample == BUF_PULSE_BIT || ((sample != BUF_LEN_MASK) &&
+ (sample & BUF_REPEAT_MASK) == BUF_REPEAT_BYTE))
+ ir_raw_event_handle(nvt->rdev);
+ }
+
+ if (nvt->pkts) {
+ nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
+ nvt->pkts = 0;
+ }
+
+ nvt_dbg_verbose("%s done", __func__);
+}
+
+static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
+{
+ nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
+
+ nvt->pkts = 0;
+ nvt_clear_cir_fifo(nvt);
+ ir_raw_event_reset(nvt->rdev);
+}
+
+/* copy data from hardware rx fifo into driver buffer */
+static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
+{
+ unsigned long flags;
+ u8 fifocount, val;
+ unsigned int b_idx;
+ bool overrun = false;
+ int i;
+
+ /* Get count of how many bytes to read from RX FIFO */
+ fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT);
+ /* if we get 0xff, probably means the logical dev is disabled */
+ if (fifocount == 0xff)
+ return;
+ /* watch out for a fifo overrun condition */
+ else if (fifocount > RX_BUF_LEN) {
+ overrun = true;
+ fifocount = RX_BUF_LEN;
+ }
+
+ nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ b_idx = nvt->pkts;
+
+ /* This should never happen, but lets check anyway... */
+ if (b_idx + fifocount > RX_BUF_LEN) {
+ nvt_process_rx_ir_data(nvt);
+ b_idx = 0;
+ }
+
+ /* Read fifocount bytes from CIR Sample RX FIFO register */
+ for (i = 0; i < fifocount; i++) {
+ val = nvt_cir_reg_read(nvt, CIR_SRXFIFO);
+ nvt->buf[b_idx + i] = val;
+ }
+
+ nvt->pkts += fifocount;
+ nvt_dbg("%s: pkts now %d", __func__, nvt->pkts);
+
+ nvt_process_rx_ir_data(nvt);
+
+ if (overrun)
+ nvt_handle_rx_fifo_overrun(nvt);
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+}
+
+static void nvt_cir_log_irqs(u8 status, u8 iren)
+{
+ nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
+ status, iren,
+ status & CIR_IRSTS_RDR ? " RDR" : "",
+ status & CIR_IRSTS_RTR ? " RTR" : "",
+ status & CIR_IRSTS_PE ? " PE" : "",
+ status & CIR_IRSTS_RFO ? " RFO" : "",
+ status & CIR_IRSTS_TE ? " TE" : "",
+ status & CIR_IRSTS_TTR ? " TTR" : "",
+ status & CIR_IRSTS_TFU ? " TFU" : "",
+ status & CIR_IRSTS_GH ? " GH" : "",
+ status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE |
+ CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR |
+ CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : "");
+}
+
+static bool nvt_cir_tx_inactive(struct nvt_dev *nvt)
+{
+ unsigned long flags;
+ bool tx_inactive;
+ u8 tx_state;
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ tx_state = nvt->tx.tx_state;
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ tx_inactive = (tx_state == ST_TX_NONE);
+
+ return tx_inactive;
+}
+
+/* interrupt service routine for incoming and outgoing CIR data */
+static irqreturn_t nvt_cir_isr(int irq, void *data)
+{
+ struct nvt_dev *nvt = data;
+ u8 status, iren, cur_state;
+ unsigned long flags;
+
+ nvt_dbg_verbose("%s firing", __func__);
+
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_efm_disable(nvt);
+
+ /*
+ * Get IR Status register contents. Write 1 to ack/clear
+ *
+ * bit: reg name - description
+ * 7: CIR_IRSTS_RDR - RX Data Ready
+ * 6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach
+ * 5: CIR_IRSTS_PE - Packet End
+ * 4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set)
+ * 3: CIR_IRSTS_TE - TX FIFO Empty
+ * 2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach
+ * 1: CIR_IRSTS_TFU - TX FIFO Underrun
+ * 0: CIR_IRSTS_GH - Min Length Detected
+ */
+ status = nvt_cir_reg_read(nvt, CIR_IRSTS);
+ if (!status) {
+ nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+
+ /* ack/clear all irq flags we've got */
+ nvt_cir_reg_write(nvt, status, CIR_IRSTS);
+ nvt_cir_reg_write(nvt, 0, CIR_IRSTS);
+
+ /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */
+ iren = nvt_cir_reg_read(nvt, CIR_IREN);
+ if (!iren) {
+ nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+
+ if (debug)
+ nvt_cir_log_irqs(status, iren);
+
+ if (status & CIR_IRSTS_RTR) {
+ /* FIXME: add code for study/learn mode */
+ /* We only do rx if not tx'ing */
+ if (nvt_cir_tx_inactive(nvt))
+ nvt_get_rx_ir_data(nvt);
+ }
+
+ if (status & CIR_IRSTS_PE) {
+ if (nvt_cir_tx_inactive(nvt))
+ nvt_get_rx_ir_data(nvt);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ cur_state = nvt->study_state;
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ if (cur_state == ST_STUDY_NONE)
+ nvt_clear_cir_fifo(nvt);
+ }
+
+ if (status & CIR_IRSTS_TE)
+ nvt_clear_tx_fifo(nvt);
+
+ if (status & CIR_IRSTS_TTR) {
+ unsigned int pos, count;
+ u8 tmp;
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+
+ pos = nvt->tx.cur_buf_num;
+ count = nvt->tx.buf_count;
+
+ /* Write data into the hardware tx fifo while pos < count */
+ if (pos < count) {
+ nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO);
+ nvt->tx.cur_buf_num++;
+ /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */
+ } else {
+ tmp = nvt_cir_reg_read(nvt, CIR_IREN);
+ nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+ }
+
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ }
+
+ if (status & CIR_IRSTS_TFU) {
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ if (nvt->tx.tx_state == ST_TX_REPLY) {
+ nvt->tx.tx_state = ST_TX_REQUEST;
+ wake_up(&nvt->tx.queue);
+ }
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+ }
+
+ nvt_dbg_verbose("%s done", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+/* Interrupt service routine for CIR Wake */
+static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
+{
+ u8 status, iren, val;
+ struct nvt_dev *nvt = data;
+ unsigned long flags;
+
+ nvt_dbg_wake("%s firing", __func__);
+
+ status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
+ if (!status)
+ return IRQ_RETVAL(IRQ_NONE);
+
+ if (status & CIR_WAKE_IRSTS_IR_PENDING)
+ nvt_clear_cir_wake_fifo(nvt);
+
+ nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS);
+ nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS);
+
+ /* Interrupt may be shared with CIR, bail if Wake not enabled */
+ iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
+ if (!iren) {
+ nvt_dbg_wake("%s exiting, wake not enabled", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+ }
+
+ if ((status & CIR_WAKE_IRSTS_PE) &&
+ (nvt->wake_state == ST_WAKE_START)) {
+ while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
+ val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
+ nvt_dbg("setting wake up key: 0x%x", val);
+ }
+
+ nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->wake_state = ST_WAKE_FINISH;
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+ }
+
+ nvt_dbg_wake("%s done", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+static void nvt_enable_cir(struct nvt_dev *nvt)
+{
+ /* set function enable flags */
+ nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+ CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_IRCON);
+
+ nvt_efm_enable(nvt);
+
+ /* enable the CIR logical device */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ /* clear all pending interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* enable interrupts */
+ nvt_set_cir_iren(nvt);
+}
+
+static void nvt_disable_cir(struct nvt_dev *nvt)
+{
+ /* disable CIR interrupts */
+ nvt_cir_reg_write(nvt, 0, CIR_IREN);
+
+ /* clear any and all pending interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* clear all function enable flags */
+ nvt_cir_reg_write(nvt, 0, CIR_IRCON);
+
+ /* clear hardware rx and tx fifos */
+ nvt_clear_cir_fifo(nvt);
+ nvt_clear_tx_fifo(nvt);
+
+ nvt_efm_enable(nvt);
+
+ /* disable the CIR logical device */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+}
+
+static int nvt_open(void *data)
+{
+ struct nvt_dev *nvt = (struct nvt_dev *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->in_use = true;
+ nvt_enable_cir(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ return 0;
+}
+
+static void nvt_close(void *data)
+{
+ struct nvt_dev *nvt = (struct nvt_dev *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->in_use = false;
+ nvt_disable_cir(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+}
+
+/* Allocate memory, probe hardware, and initialize everything */
+static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+{
+ struct nvt_dev *nvt = NULL;
+ struct input_dev *rdev = NULL;
+ struct ir_dev_props *props = NULL;
+ int ret = -ENOMEM;
+
+ nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
+ if (!nvt)
+ return ret;
+
+ props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
+ if (!props)
+ goto failure;
+
+ /* input device for IR remote (and tx) */
+ rdev = input_allocate_device();
+ if (!rdev)
+ goto failure;
+
+ ret = -ENODEV;
+ /* validate pnp resources */
+ if (!pnp_port_valid(pdev, 0) ||
+ pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) {
+ dev_err(&pdev->dev, "IR PNP Port not valid!\n");
+ goto failure;
+ }
+
+ if (!pnp_irq_valid(pdev, 0)) {
+ dev_err(&pdev->dev, "PNP IRQ not valid!\n");
+ goto failure;
+ }
+
+ if (!pnp_port_valid(pdev, 1) ||
+ pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) {
+ dev_err(&pdev->dev, "Wake PNP Port not valid!\n");
+ goto failure;
+ }
+
+ nvt->cir_addr = pnp_port_start(pdev, 0);
+ nvt->cir_irq = pnp_irq(pdev, 0);
+
+ nvt->cir_wake_addr = pnp_port_start(pdev, 1);
+ /* irq is always shared between cir and cir wake */
+ nvt->cir_wake_irq = nvt->cir_irq;
+
+ nvt->cr_efir = CR_EFIR;
+ nvt->cr_efdr = CR_EFDR;
+
+ spin_lock_init(&nvt->nvt_lock);
+ spin_lock_init(&nvt->tx.lock);
+ init_ir_raw_event(&nvt->rawir);
+
+ ret = -EBUSY;
+ /* now claim resources */
+ if (!request_region(nvt->cir_addr,
+ CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+ goto failure;
+
+ if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
+ NVT_DRIVER_NAME, (void *)nvt))
+ goto failure;
+
+ if (!request_region(nvt->cir_wake_addr,
+ CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+ goto failure;
+
+ if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
+ NVT_DRIVER_NAME, (void *)nvt))
+ goto failure;
+
+ pnp_set_drvdata(pdev, nvt);
+ nvt->pdev = pdev;
+
+ init_waitqueue_head(&nvt->tx.queue);
+
+ ret = nvt_hw_detect(nvt);
+ if (ret)
+ goto failure;
+
+ /* Initialize CIR & CIR Wake Logical Devices */
+ nvt_efm_enable(nvt);
+ nvt_cir_ldev_init(nvt);
+ nvt_cir_wake_ldev_init(nvt);
+ nvt_efm_disable(nvt);
+
+ /* Initialize CIR & CIR Wake Config Registers */
+ nvt_cir_regs_init(nvt);
+ nvt_cir_wake_regs_init(nvt);
+
+ /* Set up ir-core props */
+ props->priv = nvt;
+ props->driver_type = RC_DRIVER_IR_RAW;
+ props->allowed_protos = IR_TYPE_ALL;
+ props->open = nvt_open;
+ props->close = nvt_close;
+#if 0
+ props->min_timeout = XYZ;
+ props->max_timeout = XYZ;
+ props->timeout = XYZ;
+ /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+ props->rx_resolution = XYZ;
+
+ /* tx bits */
+ props->tx_resolution = XYZ;
+#endif
+ props->tx_ir = nvt_tx_ir;
+ props->s_tx_carrier = nvt_set_tx_carrier;
+
+ rdev->name = "Nuvoton w836x7hg Infrared Remote Transceiver";
+ rdev->id.bustype = BUS_HOST;
+ rdev->id.vendor = PCI_VENDOR_ID_WINBOND2;
+ rdev->id.product = nvt->chip_major;
+ rdev->id.version = nvt->chip_minor;
+
+ nvt->props = props;
+ nvt->rdev = rdev;
+
+ device_set_wakeup_capable(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, 1);
+
+ ret = ir_input_register(rdev, RC_MAP_RC6_MCE, props, NVT_DRIVER_NAME);
+ if (ret)
+ goto failure;
+
+ nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+ if (debug) {
+ cir_dump_regs(nvt);
+ cir_wake_dump_regs(nvt);
+ }
+
+ return 0;
+
+failure:
+ if (nvt->cir_irq)
+ free_irq(nvt->cir_irq, nvt);
+ if (nvt->cir_addr)
+ release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
+
+ if (nvt->cir_wake_irq)
+ free_irq(nvt->cir_wake_irq, nvt);
+ if (nvt->cir_wake_addr)
+ release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+
+ input_free_device(rdev);
+ kfree(props);
+ kfree(nvt);
+
+ return ret;
+}
+
+static void __devexit nvt_remove(struct pnp_dev *pdev)
+{
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ /* disable CIR */
+ nvt_cir_reg_write(nvt, 0, CIR_IREN);
+ nvt_disable_cir(nvt);
+ /* enable CIR Wake (for IR power-on) */
+ nvt_enable_wake(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ /* free resources */
+ free_irq(nvt->cir_irq, nvt);
+ free_irq(nvt->cir_wake_irq, nvt);
+ release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
+ release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+
+ ir_input_unregister(nvt->rdev);
+
+ kfree(nvt->props);
+ kfree(nvt);
+}
+
+static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+ unsigned long flags;
+
+ nvt_dbg("%s called", __func__);
+
+ /* zero out misc state tracking */
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->study_state = ST_STUDY_NONE;
+ nvt->wake_state = ST_WAKE_NONE;
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ nvt->tx.tx_state = ST_TX_NONE;
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ /* disable all CIR interrupts */
+ nvt_cir_reg_write(nvt, 0, CIR_IREN);
+
+ nvt_efm_enable(nvt);
+
+ /* disable cir logical dev */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ /* make sure wake is enabled */
+ nvt_enable_wake(nvt);
+
+ return 0;
+}
+
+static int nvt_resume(struct pnp_dev *pdev)
+{
+ int ret = 0;
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+
+ nvt_dbg("%s called", __func__);
+
+ /* open interrupt */
+ nvt_set_cir_iren(nvt);
+
+ /* Enable CIR logical device */
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ nvt_cir_regs_init(nvt);
+ nvt_cir_wake_regs_init(nvt);
+
+ return ret;
+}
+
+static void nvt_shutdown(struct pnp_dev *pdev)
+{
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+ nvt_enable_wake(nvt);
+}
+
+static const struct pnp_device_id nvt_ids[] = {
+ { "WEC0530", 0 }, /* CIR */
+ { "NTN0530", 0 }, /* CIR for new chip's pnp id*/
+ { "", 0 },
+};
+
+static struct pnp_driver nvt_driver = {
+ .name = NVT_DRIVER_NAME,
+ .id_table = nvt_ids,
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .probe = nvt_probe,
+ .remove = __devexit_p(nvt_remove),
+ .suspend = nvt_suspend,
+ .resume = nvt_resume,
+ .shutdown = nvt_shutdown,
+};
+
+int nvt_init(void)
+{
+ return pnp_register_driver(&nvt_driver);
+}
+
+void nvt_exit(void)
+{
+ pnp_unregister_driver(&nvt_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging output");
+
+MODULE_DEVICE_TABLE(pnp, nvt_ids);
+MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver");
+
+MODULE_AUTHOR("Jarod Wilson ");
+MODULE_LICENSE("GPL");
+
+module_init(nvt_init);
+module_exit(nvt_exit);
diff --git a/drivers/media/IR/nuvoton-cir.h b/drivers/media/IR/nuvoton-cir.h
new file mode 100644
index 000000000000..62dc53017c8e
--- /dev/null
+++ b/drivers/media/IR/nuvoton-cir.h
@@ -0,0 +1,408 @@
+/*
+ * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
+ *
+ * Copyright (C) 2010 Jarod Wilson
+ * Copyright (C) 2009 Nuvoton PS Team
+ *
+ * Special thanks to Nuvoton for providing hardware, spec sheets and
+ * sample code upon which portions of this driver are based. Indirect
+ * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
+ * modeled after.
+ *
+ * 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.
+ *
+ * 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
+#include
+
+/* platform driver name to register */
+#define NVT_DRIVER_NAME "nuvoton-cir"
+
+/* debugging module parameter */
+static int debug;
+
+
+#define nvt_pr(level, text, ...) \
+ printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+#define nvt_dbg(text, ...) \
+ if (debug) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define nvt_dbg_verbose(text, ...) \
+ if (debug > 1) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define nvt_dbg_wake(text, ...) \
+ if (debug > 2) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+
+/*
+ * Original lirc driver said min value of 76, and recommended value of 256
+ * for the buffer length, but then used 2048. Never mind that the size of the
+ * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
+ * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
+ * and I don't have TX-capable hardware to test/debug on...
+ */
+#define TX_BUF_LEN 256
+#define RX_BUF_LEN 32
+
+struct nvt_dev {
+ struct pnp_dev *pdev;
+ struct input_dev *rdev;
+ struct ir_dev_props *props;
+ struct ir_raw_event rawir;
+
+ spinlock_t nvt_lock;
+ bool in_use;
+
+ /* for rx */
+ u8 buf[RX_BUF_LEN];
+ unsigned int pkts;
+
+ struct {
+ spinlock_t lock;
+ u8 buf[TX_BUF_LEN];
+ unsigned int buf_count;
+ unsigned int cur_buf_num;
+ wait_queue_head_t queue;
+ u8 tx_state;
+ } tx;
+
+ /* EFER Config register index/data pair */
+ u8 cr_efir;
+ u8 cr_efdr;
+
+ /* hardware I/O settings */
+ unsigned long cir_addr;
+ unsigned long cir_wake_addr;
+ int cir_irq;
+ int cir_wake_irq;
+
+ /* hardware id */
+ u8 chip_major;
+ u8 chip_minor;
+
+ /* hardware features */
+ bool hw_learning_capable;
+ bool hw_tx_capable;
+
+ /* rx settings */
+ bool learning_enabled;
+ bool carrier_detect_enabled;
+
+ /* track cir wake state */
+ u8 wake_state;
+ /* for study */
+ u8 study_state;
+ /* carrier period = 1 / frequency */
+ u32 carrier;
+};
+
+/* study states */
+#define ST_STUDY_NONE 0x0
+#define ST_STUDY_START 0x1
+#define ST_STUDY_CARRIER 0x2
+#define ST_STUDY_ALL_RECV 0x4
+
+/* wake states */
+#define ST_WAKE_NONE 0x0
+#define ST_WAKE_START 0x1
+#define ST_WAKE_FINISH 0x2
+
+/* receive states */
+#define ST_RX_WAIT_7F 0x1
+#define ST_RX_WAIT_HEAD 0x2
+#define ST_RX_WAIT_SILENT_END 0x4
+
+/* send states */
+#define ST_TX_NONE 0x0
+#define ST_TX_REQUEST 0x2
+#define ST_TX_REPLY 0x4
+
+/* buffer packet constants */
+#define BUF_PULSE_BIT 0x80
+#define BUF_LEN_MASK 0x7f
+#define BUF_REPEAT_BYTE 0x70
+#define BUF_REPEAT_MASK 0xf0
+
+/* CIR settings */
+
+/* total length of CIR and CIR WAKE */
+#define CIR_IOREG_LENGTH 0x0f
+
+/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */
+#define CIR_RX_LIMIT_COUNT 0x7d0
+
+/* CIR Regs */
+#define CIR_IRCON 0x00
+#define CIR_IRSTS 0x01
+#define CIR_IREN 0x02
+#define CIR_RXFCONT 0x03
+#define CIR_CP 0x04
+#define CIR_CC 0x05
+#define CIR_SLCH 0x06
+#define CIR_SLCL 0x07
+#define CIR_FIFOCON 0x08
+#define CIR_IRFIFOSTS 0x09
+#define CIR_SRXFIFO 0x0a
+#define CIR_TXFCONT 0x0b
+#define CIR_STXFIFO 0x0c
+#define CIR_FCCH 0x0d
+#define CIR_FCCL 0x0e
+#define CIR_IRFSM 0x0f
+
+/* CIR IRCON settings */
+#define CIR_IRCON_RECV 0x80
+#define CIR_IRCON_WIREN 0x40
+#define CIR_IRCON_TXEN 0x20
+#define CIR_IRCON_RXEN 0x10
+#define CIR_IRCON_WRXINV 0x08
+#define CIR_IRCON_RXINV 0x04
+
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03
+
+/* FIXME: make this a runtime option */
+/* select sample period as 50us */
+#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
+
+/* CIR IRSTS settings */
+#define CIR_IRSTS_RDR 0x80
+#define CIR_IRSTS_RTR 0x40
+#define CIR_IRSTS_PE 0x20
+#define CIR_IRSTS_RFO 0x10
+#define CIR_IRSTS_TE 0x08
+#define CIR_IRSTS_TTR 0x04
+#define CIR_IRSTS_TFU 0x02
+#define CIR_IRSTS_GH 0x01
+
+/* CIR IREN settings */
+#define CIR_IREN_RDR 0x80
+#define CIR_IREN_RTR 0x40
+#define CIR_IREN_PE 0x20
+#define CIR_IREN_RFO 0x10
+#define CIR_IREN_TE 0x08
+#define CIR_IREN_TTR 0x04
+#define CIR_IREN_TFU 0x02
+#define CIR_IREN_GH 0x01
+
+/* CIR FIFOCON settings */
+#define CIR_FIFOCON_TXFIFOCLR 0x80
+
+#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00
+#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10
+#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20
+#define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30
+
+/* FIXME: make this a runtime option */
+/* select TX trigger level as 16 */
+#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16
+
+#define CIR_FIFOCON_RXFIFOCLR 0x08
+
+#define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00
+#define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01
+#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02
+#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03
+
+/* FIXME: make this a runtime option */
+/* select RX trigger level as 24 */
+#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24
+
+/* CIR IRFIFOSTS settings */
+#define CIR_IRFIFOSTS_IR_PENDING 0x80
+#define CIR_IRFIFOSTS_RX_GS 0x40
+#define CIR_IRFIFOSTS_RX_FTA 0x20
+#define CIR_IRFIFOSTS_RX_EMPTY 0x10
+#define CIR_IRFIFOSTS_RX_FULL 0x08
+#define CIR_IRFIFOSTS_TX_FTA 0x04
+#define CIR_IRFIFOSTS_TX_EMPTY 0x02
+#define CIR_IRFIFOSTS_TX_FULL 0x01
+
+
+/* CIR WAKE UP Regs */
+#define CIR_WAKE_IRCON 0x00
+#define CIR_WAKE_IRSTS 0x01
+#define CIR_WAKE_IREN 0x02
+#define CIR_WAKE_FIFO_CMP_DEEP 0x03
+#define CIR_WAKE_FIFO_CMP_TOL 0x04
+#define CIR_WAKE_FIFO_COUNT 0x05
+#define CIR_WAKE_SLCH 0x06
+#define CIR_WAKE_SLCL 0x07
+#define CIR_WAKE_FIFOCON 0x08
+#define CIR_WAKE_SRXFSTS 0x09
+#define CIR_WAKE_SAMPLE_RX_FIFO 0x0a
+#define CIR_WAKE_WR_FIFO_DATA 0x0b
+#define CIR_WAKE_RD_FIFO_ONLY 0x0c
+#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d
+#define CIR_WAKE_FIFO_IGNORE 0x0e
+#define CIR_WAKE_IRFSM 0x0f
+
+/* CIR WAKE UP IRCON settings */
+#define CIR_WAKE_IRCON_DEC_RST 0x80
+#define CIR_WAKE_IRCON_MODE1 0x40
+#define CIR_WAKE_IRCON_MODE0 0x20
+#define CIR_WAKE_IRCON_RXEN 0x10
+#define CIR_WAKE_IRCON_R 0x08
+#define CIR_WAKE_IRCON_RXINV 0x04
+
+/* FIXME/jarod: make this a runtime option */
+/* select a same sample period like cir register */
+#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
+
+/* CIR WAKE IRSTS Bits */
+#define CIR_WAKE_IRSTS_RDR 0x80
+#define CIR_WAKE_IRSTS_RTR 0x40
+#define CIR_WAKE_IRSTS_PE 0x20
+#define CIR_WAKE_IRSTS_RFO 0x10
+#define CIR_WAKE_IRSTS_GH 0x08
+#define CIR_WAKE_IRSTS_IR_PENDING 0x01
+
+/* CIR WAKE UP IREN Bits */
+#define CIR_WAKE_IREN_RDR 0x80
+#define CIR_WAKE_IREN_RTR 0x40
+#define CIR_WAKE_IREN_PE 0x20
+#define CIR_WAKE_IREN_RFO 0x10
+#define CIR_WAKE_IREN_TE 0x08
+#define CIR_WAKE_IREN_TTR 0x04
+#define CIR_WAKE_IREN_TFU 0x02
+#define CIR_WAKE_IREN_GH 0x01
+
+/* CIR WAKE FIFOCON settings */
+#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08
+
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03
+
+/* FIXME: make this a runtime option */
+/* select WAKE UP RX trigger level as 67 */
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67
+
+/* CIR WAKE SRXFSTS settings */
+#define CIR_WAKE_IRFIFOSTS_RX_GS 0x80
+#define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40
+#define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20
+#define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10
+
+/* CIR Wake FIFO buffer is 67 bytes long */
+#define CIR_WAKE_FIFO_LEN 67
+/* CIR Wake byte comparison tolerance */
+#define CIR_WAKE_CMP_TOLERANCE 5
+
+/*
+ * Extended Function Enable Registers:
+ * Extended Function Index Register
+ * Extended Function Data Register
+ */
+#define CR_EFIR 0x2e
+#define CR_EFDR 0x2f
+
+/* Possible alternate EFER values, depends on how the chip is wired */
+#define CR_EFIR2 0x4e
+#define CR_EFDR2 0x4f
+
+/* Extended Function Mode enable/disable magic values */
+#define EFER_EFM_ENABLE 0x87
+#define EFER_EFM_DISABLE 0xaa
+
+/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
+#define CHIP_ID_HIGH 0xb4
+#define CHIP_ID_LOW 0x72
+#define CHIP_ID_LOW2 0x73
+
+/* Config regs we need to care about */
+#define CR_SOFTWARE_RESET 0x02
+#define CR_LOGICAL_DEV_SEL 0x07
+#define CR_CHIP_ID_HI 0x20
+#define CR_CHIP_ID_LO 0x21
+#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */
+#define CR_OUTPUT_PIN_SEL 0x27
+#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */
+/* next three regs valid for both the CIR and CIR_WAKE logical devices */
+#define CR_CIR_BASE_ADDR_HI 0x60
+#define CR_CIR_BASE_ADDR_LO 0x61
+#define CR_CIR_IRQ_RSRC 0x70
+/* next three regs valid only for ACPI logical dev */
+#define CR_ACPI_CIR_WAKE 0xe0
+#define CR_ACPI_IRQ_EVENTS 0xf6
+#define CR_ACPI_IRQ_EVENTS2 0xf7
+
+/* Logical devices that we need to care about */
+#define LOGICAL_DEV_LPT 0x01
+#define LOGICAL_DEV_CIR 0x06
+#define LOGICAL_DEV_ACPI 0x0a
+#define LOGICAL_DEV_CIR_WAKE 0x0e
+
+#define LOGICAL_DEV_DISABLE 0x00
+#define LOGICAL_DEV_ENABLE 0x01
+
+#define CIR_WAKE_ENABLE_BIT 0x08
+#define CIR_INTR_MOUSE_IRQ_BIT 0x80
+#define PME_INTR_CIR_PASS_BIT 0x08
+
+#define OUTPUT_PIN_SEL_MASK 0xbc
+#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
+#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */
+
+/* MCE CIR signal length, related on sample period */
+
+/* MCE CIR controller signal length: about 43ms
+ * 43ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define CONTROLLER_BUF_LEN_MIN 830
+
+/* MCE CIR keyboard signal length: about 26ms
+ * 26ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define KEYBOARD_BUF_LEN_MAX 650
+#define KEYBOARD_BUF_LEN_MIN 610
+
+/* MCE CIR mouse signal length: about 24ms
+ * 24ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define MOUSE_BUF_LEN_MIN 565
+
+#define CIR_SAMPLE_PERIOD 50
+#define CIR_SAMPLE_LOW_INACCURACY 0.85
+
+/* MAX silence time that driver will sent to lirc */
+#define MAX_SILENCE_TIME 60000
+
+#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100
+#define SAMPLE_PERIOD 100
+
+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50
+#define SAMPLE_PERIOD 50
+
+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25
+#define SAMPLE_PERIOD 25
+
+#else
+#define SAMPLE_PERIOD 1
+#endif
+
+/* as VISTA MCE definition, valid carrier value */
+#define MAX_CARRIER 60000
+#define MIN_CARRIER 30000
diff --git a/drivers/media/IR/streamzap.c b/drivers/media/IR/streamzap.c
index 058e29fd478c..548381c35bfd 100644
--- a/drivers/media/IR/streamzap.c
+++ b/drivers/media/IR/streamzap.c
@@ -38,7 +38,7 @@
#include
#include
-#define DRIVER_VERSION "1.60"
+#define DRIVER_VERSION "1.61"
#define DRIVER_NAME "streamzap"
#define DRIVER_DESC "Streamzap Remote Control driver"
@@ -61,14 +61,21 @@ static struct usb_device_id streamzap_table[] = {
MODULE_DEVICE_TABLE(usb, streamzap_table);
-#define STREAMZAP_PULSE_MASK 0xf0
-#define STREAMZAP_SPACE_MASK 0x0f
-#define STREAMZAP_TIMEOUT 0xff
-#define STREAMZAP_RESOLUTION 256
+#define SZ_PULSE_MASK 0xf0
+#define SZ_SPACE_MASK 0x0f
+#define SZ_TIMEOUT 0xff
+#define SZ_RESOLUTION 256
/* 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() 0
+#endif
+
enum StreamzapDecoderState {
PulseSpace,
FullPulse,
@@ -81,7 +88,6 @@ struct streamzap_ir {
/* ir-core */
struct ir_dev_props *props;
- struct ir_raw_event rawir;
/* core device info */
struct device *dev;
@@ -98,17 +104,6 @@ struct streamzap_ir {
dma_addr_t dma_in;
unsigned int buf_in_len;
- /* timer used to support delay buffering */
- struct timer_list delay_timer;
- bool timer_running;
- spinlock_t timer_lock;
- struct timer_list flush_timer;
- bool flush;
-
- /* delay buffer */
- struct kfifo fifo;
- bool fifo_initialized;
-
/* track what state we're in */
enum StreamzapDecoderState decoder_state;
/* tracks whether we are currently receiving some signal */
@@ -118,7 +113,7 @@ struct streamzap_ir {
/* start time of signal; necessary for gap tracking */
struct timeval signal_last;
struct timeval signal_start;
- /* bool timeout_enabled; */
+ bool timeout_enabled;
char name[128];
char phys[64];
@@ -143,122 +138,16 @@ static struct usb_driver streamzap_driver = {
.id_table = streamzap_table,
};
-static void streamzap_stop_timer(struct streamzap_ir *sz)
+static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
{
- unsigned long flags;
-
- spin_lock_irqsave(&sz->timer_lock, flags);
- if (sz->timer_running) {
- sz->timer_running = false;
- spin_unlock_irqrestore(&sz->timer_lock, flags);
- del_timer_sync(&sz->delay_timer);
- } else {
- spin_unlock_irqrestore(&sz->timer_lock, flags);
- }
-}
-
-static void streamzap_flush_timeout(unsigned long arg)
-{
- struct streamzap_ir *sz = (struct streamzap_ir *)arg;
-
- dev_info(sz->dev, "%s: callback firing\n", __func__);
-
- /* finally start accepting data */
- sz->flush = false;
-}
-
-static void streamzap_delay_timeout(unsigned long arg)
-{
- struct streamzap_ir *sz = (struct streamzap_ir *)arg;
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- unsigned long flags;
- int len, ret;
- static unsigned long delay;
- bool wake = false;
-
- /* deliver data every 10 ms */
- delay = msecs_to_jiffies(10);
-
- spin_lock_irqsave(&sz->timer_lock, flags);
-
- if (kfifo_len(&sz->fifo) > 0) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- wake = true;
- }
-
- len = kfifo_len(&sz->fifo);
- if (len > 0) {
- while ((len < SZ_BUF_LEN / 2) &&
- (len < SZ_BUF_LEN * sizeof(int))) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- wake = true;
- len = kfifo_len(&sz->fifo);
- }
- if (sz->timer_running)
- mod_timer(&sz->delay_timer, jiffies + delay);
-
- } else {
- sz->timer_running = false;
- }
-
- if (wake)
- ir_raw_event_handle(sz->idev);
-
- spin_unlock_irqrestore(&sz->timer_lock, flags);
-}
-
-static void streamzap_flush_delay_buffer(struct streamzap_ir *sz)
-{
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- bool wake = false;
- int ret;
-
- while (kfifo_len(&sz->fifo) > 0) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- wake = true;
- }
-
- if (wake)
- ir_raw_event_handle(sz->idev);
-}
-
-static void sz_push(struct streamzap_ir *sz)
-{
- struct ir_raw_event rawir = { .pulse = false, .duration = 0 };
- unsigned long flags;
- int ret;
-
- spin_lock_irqsave(&sz->timer_lock, flags);
- if (kfifo_len(&sz->fifo) >= sizeof(int) * SZ_BUF_LEN) {
- ret = kfifo_out(&sz->fifo, &rawir, sizeof(rawir));
- if (ret != sizeof(rawir))
- dev_err(sz->dev, "Problem w/kfifo_out...\n");
- ir_raw_event_store(sz->idev, &rawir);
- }
-
- kfifo_in(&sz->fifo, &sz->rawir, sizeof(rawir));
-
- if (!sz->timer_running) {
- sz->delay_timer.expires = jiffies + (HZ / 10);
- add_timer(&sz->delay_timer);
- sz->timer_running = true;
- }
-
- spin_unlock_irqrestore(&sz->timer_lock, flags);
+ ir_raw_event_store(sz->idev, &rawir);
}
static void sz_push_full_pulse(struct streamzap_ir *sz,
unsigned char value)
{
+ DEFINE_IR_RAW_EVENT(rawir);
+
if (sz->idle) {
long deltv;
@@ -266,57 +155,59 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
do_gettimeofday(&sz->signal_start);
deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
- sz->rawir.pulse = false;
+ rawir.pulse = false;
if (deltv > 15) {
/* really long time */
- sz->rawir.duration = IR_MAX_DURATION;
+ rawir.duration = IR_MAX_DURATION;
} else {
- sz->rawir.duration = (int)(deltv * 1000000 +
+ rawir.duration = (int)(deltv * 1000000 +
sz->signal_start.tv_usec -
sz->signal_last.tv_usec);
- sz->rawir.duration -= sz->sum;
- sz->rawir.duration *= 1000;
- sz->rawir.duration &= IR_MAX_DURATION;
+ rawir.duration -= sz->sum;
+ rawir.duration *= 1000;
+ rawir.duration &= IR_MAX_DURATION;
}
- dev_dbg(sz->dev, "ls %u\n", sz->rawir.duration);
- sz_push(sz);
+ dev_dbg(sz->dev, "ls %u\n", rawir.duration);
+ sz_push(sz, rawir);
- sz->idle = 0;
+ sz->idle = false;
sz->sum = 0;
}
- sz->rawir.pulse = true;
- sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
- sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
- sz->sum += sz->rawir.duration;
- sz->rawir.duration *= 1000;
- sz->rawir.duration &= IR_MAX_DURATION;
- dev_dbg(sz->dev, "p %u\n", sz->rawir.duration);
- sz_push(sz);
+ rawir.pulse = true;
+ rawir.duration = ((int) value) * SZ_RESOLUTION;
+ rawir.duration += SZ_RESOLUTION / 2;
+ sz->sum += rawir.duration;
+ rawir.duration *= 1000;
+ rawir.duration &= IR_MAX_DURATION;
+ dev_dbg(sz->dev, "p %u\n", rawir.duration);
+ sz_push(sz, rawir);
}
static void sz_push_half_pulse(struct streamzap_ir *sz,
unsigned char value)
{
- sz_push_full_pulse(sz, (value & STREAMZAP_PULSE_MASK) >> 4);
+ sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4);
}
static void sz_push_full_space(struct streamzap_ir *sz,
unsigned char value)
{
- sz->rawir.pulse = false;
- sz->rawir.duration = ((int) value) * STREAMZAP_RESOLUTION;
- sz->rawir.duration += STREAMZAP_RESOLUTION / 2;
- sz->sum += sz->rawir.duration;
- sz->rawir.duration *= 1000;
- dev_dbg(sz->dev, "s %u\n", sz->rawir.duration);
- sz_push(sz);
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ rawir.pulse = false;
+ rawir.duration = ((int) value) * SZ_RESOLUTION;
+ rawir.duration += SZ_RESOLUTION / 2;
+ sz->sum += rawir.duration;
+ rawir.duration *= 1000;
+ dev_dbg(sz->dev, "s %u\n", rawir.duration);
+ sz_push(sz, rawir);
}
static void sz_push_half_space(struct streamzap_ir *sz,
unsigned long value)
{
- sz_push_full_space(sz, value & STREAMZAP_SPACE_MASK);
+ sz_push_full_space(sz, value & SZ_SPACE_MASK);
}
/**
@@ -330,10 +221,8 @@ static void streamzap_callback(struct urb *urb)
struct streamzap_ir *sz;
unsigned int i;
int len;
- #if 0
- static int timeout = (((STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION) &
+ static int timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
IR_MAX_DURATION) | 0x03000000);
- #endif
if (!urb)
return;
@@ -356,57 +245,53 @@ static void streamzap_callback(struct urb *urb)
}
dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
- if (!sz->flush) {
- for (i = 0; i < urb->actual_length; i++) {
- dev_dbg(sz->dev, "%d: %x\n", i,
- (unsigned char)sz->buf_in[i]);
- switch (sz->decoder_state) {
- case PulseSpace:
- if ((sz->buf_in[i] & STREAMZAP_PULSE_MASK) ==
- STREAMZAP_PULSE_MASK) {
- sz->decoder_state = FullPulse;
- continue;
- } else if ((sz->buf_in[i] & STREAMZAP_SPACE_MASK)
- == STREAMZAP_SPACE_MASK) {
- sz_push_half_pulse(sz, sz->buf_in[i]);
- sz->decoder_state = FullSpace;
- continue;
- } else {
- sz_push_half_pulse(sz, sz->buf_in[i]);
- sz_push_half_space(sz, sz->buf_in[i]);
- }
- break;
- case FullPulse:
- sz_push_full_pulse(sz, sz->buf_in[i]);
- sz->decoder_state = IgnorePulse;
- break;
- case FullSpace:
- if (sz->buf_in[i] == STREAMZAP_TIMEOUT) {
- sz->idle = 1;
- streamzap_stop_timer(sz);
- #if 0
- if (sz->timeout_enabled) {
- sz->rawir.pulse = false;
- sz->rawir.duration = timeout;
- sz->rawir.duration *= 1000;
- sz_push(sz);
- }
- #endif
- streamzap_flush_delay_buffer(sz);
- } else
- sz_push_full_space(sz, sz->buf_in[i]);
- sz->decoder_state = PulseSpace;
- break;
- case IgnorePulse:
- if ((sz->buf_in[i]&STREAMZAP_SPACE_MASK) ==
- STREAMZAP_SPACE_MASK) {
- sz->decoder_state = FullSpace;
- continue;
- }
+ for (i = 0; i < len; i++) {
+ dev_dbg(sz->dev, "sz idx %d: %x\n",
+ i, (unsigned char)sz->buf_in[i]);
+ switch (sz->decoder_state) {
+ case PulseSpace:
+ if ((sz->buf_in[i] & SZ_PULSE_MASK) ==
+ SZ_PULSE_MASK) {
+ sz->decoder_state = FullPulse;
+ continue;
+ } else if ((sz->buf_in[i] & SZ_SPACE_MASK)
+ == SZ_SPACE_MASK) {
+ sz_push_half_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = FullSpace;
+ continue;
+ } else {
+ sz_push_half_pulse(sz, sz->buf_in[i]);
sz_push_half_space(sz, sz->buf_in[i]);
- sz->decoder_state = PulseSpace;
- break;
}
+ break;
+ case FullPulse:
+ sz_push_full_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = IgnorePulse;
+ break;
+ case FullSpace:
+ if (sz->buf_in[i] == SZ_TIMEOUT) {
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ rawir.pulse = false;
+ rawir.duration = timeout;
+ sz->idle = true;
+ if (sz->timeout_enabled)
+ sz_push(sz, rawir);
+ ir_raw_event_handle(sz->idev);
+ } else {
+ sz_push_full_space(sz, sz->buf_in[i]);
+ }
+ sz->decoder_state = PulseSpace;
+ break;
+ case IgnorePulse:
+ if ((sz->buf_in[i] & SZ_SPACE_MASK) ==
+ SZ_SPACE_MASK) {
+ sz->decoder_state = FullSpace;
+ continue;
+ }
+ sz_push_half_space(sz, sz->buf_in[i]);
+ sz->decoder_state = PulseSpace;
+ break;
}
}
@@ -446,12 +331,11 @@ static struct input_dev *streamzap_init_input_dev(struct streamzap_ir *sz)
props->priv = sz;
props->driver_type = RC_DRIVER_IR_RAW;
- /* FIXME: not sure about supported protocols, check on this */
- props->allowed_protos = IR_TYPE_RC5 | IR_TYPE_RC6;
+ props->allowed_protos = IR_TYPE_ALL;
sz->props = props;
- ret = ir_input_register(idev, RC_MAP_RC5_STREAMZAP, props, DRIVER_NAME);
+ ret = ir_input_register(idev, RC_MAP_STREAMZAP, props, DRIVER_NAME);
if (ret < 0) {
dev_err(dev, "remote input device register failed\n");
goto irdev_failed;
@@ -467,29 +351,6 @@ idev_alloc_failed:
return NULL;
}
-static int streamzap_delay_buf_init(struct streamzap_ir *sz)
-{
- int ret;
-
- ret = kfifo_alloc(&sz->fifo, sizeof(int) * SZ_BUF_LEN,
- GFP_KERNEL);
- if (ret == 0)
- sz->fifo_initialized = 1;
-
- return ret;
-}
-
-static void streamzap_start_flush_timer(struct streamzap_ir *sz)
-{
- sz->flush_timer.expires = jiffies + HZ;
- sz->flush = true;
- add_timer(&sz->flush_timer);
-
- sz->urb_in->dev = sz->usbdev;
- if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
- dev_err(sz->dev, "urb submit failed\n");
-}
-
/**
* streamzap_probe
*
@@ -575,35 +436,21 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
snprintf(name + strlen(name), sizeof(name) - strlen(name),
" %s", buf);
- retval = streamzap_delay_buf_init(sz);
- if (retval) {
- dev_err(&intf->dev, "%s: delay buffer init failed\n", __func__);
- goto free_urb_in;
- }
-
sz->idev = streamzap_init_input_dev(sz);
if (!sz->idev)
goto input_dev_fail;
sz->idle = true;
sz->decoder_state = PulseSpace;
+ /* FIXME: don't yet have a way to set this */
+ sz->timeout_enabled = true;
#if 0
/* not yet supported, depends on patches from maxim */
/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
- sz->timeout_enabled = false;
- sz->min_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
- sz->max_timeout = STREAMZAP_TIMEOUT * STREAMZAP_RESOLUTION * 1000;
+ sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+ sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
#endif
- init_timer(&sz->delay_timer);
- sz->delay_timer.function = streamzap_delay_timeout;
- sz->delay_timer.data = (unsigned long)sz;
- spin_lock_init(&sz->timer_lock);
-
- init_timer(&sz->flush_timer);
- sz->flush_timer.function = streamzap_flush_timeout;
- sz->flush_timer.data = (unsigned long)sz;
-
do_gettimeofday(&sz->signal_start);
/* Complete final initialisations */
@@ -615,16 +462,18 @@ static int __devinit streamzap_probe(struct usb_interface *intf,
usb_set_intfdata(intf, sz);
- streamzap_start_flush_timer(sz);
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
+ dev_err(sz->dev, "urb submit failed\n");
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;
input_dev_fail:
- kfifo_free(&sz->fifo);
-free_urb_in:
usb_free_urb(sz->urb_in);
free_buf_in:
usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
@@ -654,13 +503,6 @@ static void streamzap_disconnect(struct usb_interface *interface)
if (!sz)
return;
- if (sz->flush) {
- sz->flush = false;
- del_timer_sync(&sz->flush_timer);
- }
-
- streamzap_stop_timer(sz);
-
sz->usbdev = NULL;
ir_input_unregister(sz->idev);
usb_kill_urb(sz->urb_in);
@@ -674,13 +516,6 @@ static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
- if (sz->flush) {
- sz->flush = false;
- del_timer_sync(&sz->flush_timer);
- }
-
- streamzap_stop_timer(sz);
-
usb_kill_urb(sz->urb_in);
return 0;
@@ -690,13 +525,6 @@ static int streamzap_resume(struct usb_interface *intf)
{
struct streamzap_ir *sz = usb_get_intfdata(intf);
- if (sz->fifo_initialized)
- kfifo_reset(&sz->fifo);
-
- sz->flush_timer.expires = jiffies + HZ;
- sz->flush = true;
- add_timer(&sz->flush_timer);
-
if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
dev_err(sz->dev, "Error sumbiting urb\n");
return -EIO;
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 4da2a54cb8bd..e3fedc60fe77 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -56,7 +56,7 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
+ videobuf_waiton(q, &buf->vb, 0, 0);
videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 48cb154c7a46..3d88542612ea 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -414,7 +414,6 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
i2c_adapter->dev.parent = &dev->pci->dev;
i2c_adapter->algo = &saa7146_algo;
i2c_adapter->algo_data = NULL;
- i2c_adapter->id = I2C_HW_SAA7146;
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
i2c_adapter->retries = SAA7146_I2C_RETRIES;
}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 8224c301d050..2d4533ab22b7 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
- file);
+ file, NULL);
init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout;
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index a212a91a30f0..741c5732b430 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1386,7 +1386,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7146_buf),
- file);
+ file, NULL);
return 0;
}
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index b3ed5daaacf2..2385e6cca635 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -179,4 +179,11 @@ config MEDIA_TUNER_MAX2165
help
A driver for the silicon tuner MAX2165 from Maxim.
+config MEDIA_TUNER_TDA18218
+ tristate "NXP TDA18218 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ NXP TDA18218 silicon tuner driver.
+
endif # MEDIA_TUNER_CUSTOMISE
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index a5438523f30d..96da03d349ca 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
new file mode 100644
index 000000000000..8da1fdeddaa7
--- /dev/null
+++ b/drivers/media/common/tuners/tda18218.c
@@ -0,0 +1,334 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tda18218.h"
+#include "tda18218_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+ int ret;
+ u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ }
+ };
+
+ msg_len_max = priv->cfg->i2c_wr_max - 1;
+ quotient = len / msg_len_max;
+ remainder = len % msg_len_max;
+ msg_len = msg_len_max;
+ for (i = 0; (i <= quotient && remainder); i++) {
+ if (i == quotient) /* set len of the last msg */
+ msg_len = remainder;
+
+ msg[0].len = msg_len + 1;
+ buf[0] = reg + i * msg_len_max;
+ memcpy(&buf[1], &val[i * msg_len_max], msg_len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret != 1)
+ break;
+ }
+
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* read multiple registers */
+static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+ int ret;
+ u8 buf[reg+len]; /* we must start read always from reg 0x00 */
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = "\x00",
+ }, {
+ .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ memcpy(val, &buf[reg], len);
+ ret = 0;
+ } else {
+ warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write single register */
+static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
+{
+ return tda18218_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+
+static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
+{
+ return tda18218_rd_regs(priv, reg, val, 1);
+}
+
+static int tda18218_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 buf[3], i, BP_Filter, LP_Fc;
+ u32 LO_Frac;
+ /* TODO: find out correct AGC algorithm */
+ u8 agc[][2] = {
+ { R20_AGC11, 0x60 },
+ { R23_AGC21, 0x02 },
+ { R20_AGC11, 0xa0 },
+ { R23_AGC21, 0x09 },
+ { R20_AGC11, 0xe0 },
+ { R23_AGC21, 0x0c },
+ { R20_AGC11, 0x40 },
+ { R23_AGC21, 0x01 },
+ { R20_AGC11, 0x80 },
+ { R23_AGC21, 0x08 },
+ { R20_AGC11, 0xc0 },
+ { R23_AGC21, 0x0b },
+ { R24_AGC22, 0x1c },
+ { R24_AGC22, 0x0c },
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* low-pass filter cut-off frequency */
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ LP_Fc = 0;
+ LO_Frac = params->frequency + 4000000;
+ break;
+ case BANDWIDTH_7_MHZ:
+ LP_Fc = 1;
+ LO_Frac = params->frequency + 3500000;
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ LP_Fc = 2;
+ LO_Frac = params->frequency + 4000000;
+ break;
+ }
+
+ /* band-pass filter */
+ if (LO_Frac < 188000000)
+ BP_Filter = 3;
+ else if (LO_Frac < 253000000)
+ BP_Filter = 4;
+ else if (LO_Frac < 343000000)
+ BP_Filter = 5;
+ else
+ BP_Filter = 6;
+
+ buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
+ buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
+ buf[2] = priv->regs[R1C_AGC2B];
+ ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
+ if (ret)
+ goto error;
+
+ buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
+ buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
+ buf[2] = (LO_Frac / 1000) << 4 |
+ (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
+ ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
+ if (ret)
+ goto error;
+
+ buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
+ ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+ if (ret)
+ goto error;
+
+ buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
+ ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+ if (ret)
+ goto error;
+
+ /* trigger AGC */
+ for (i = 0; i < ARRAY_SIZE(agc); i++) {
+ ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
+ if (ret)
+ goto error;
+ }
+
+error:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_sleep(struct dvb_frontend *fe)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* standby */
+ ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_init(struct dvb_frontend *fe)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+
+ /* TODO: calibrations */
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops tda18218_tuner_ops = {
+ .info = {
+ .name = "NXP TDA18218",
+
+ .frequency_min = 174000000,
+ .frequency_max = 864000000,
+ .frequency_step = 1000,
+ },
+
+ .release = tda18218_release,
+ .init = tda18218_init,
+ .sleep = tda18218_sleep,
+
+ .set_params = tda18218_set_params,
+};
+
+struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+ struct tda18218_priv *priv = NULL;
+ u8 val;
+ int ret;
+ /* chip default registers values */
+ static u8 def_regs[] = {
+ 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
+ 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
+ 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
+ 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
+ 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
+ 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
+ };
+
+ priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ fe->tuner_priv = priv;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* check if the tuner is there */
+ ret = tda18218_rd_reg(priv, R00_ID, &val);
+ dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+ if (ret || val != def_regs[R00_ID]) {
+ kfree(priv);
+ return NULL;
+ }
+
+ info("NXP TDA18218HN successfully identified.");
+
+ memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ memcpy(priv->regs, def_regs, sizeof(def_regs));
+
+ /* loop-through enabled chip default register values */
+ if (priv->cfg->loop_through) {
+ priv->regs[R17_PD1] = 0xb0;
+ priv->regs[R18_PD2] = 0x59;
+ }
+
+ /* standby */
+ ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ return fe;
+}
+EXPORT_SYMBOL(tda18218_attach);
+
+MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/common/tuners/tda18218.h
new file mode 100644
index 000000000000..b4180d180029
--- /dev/null
+++ b/drivers/media/common/tuners/tda18218.h
@@ -0,0 +1,45 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_H
+#define TDA18218_H
+
+#include "dvb_frontend.h"
+
+struct tda18218_config {
+ u8 i2c_address;
+ u8 i2c_wr_max;
+ u8 loop_through:1;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
+ (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg);
+#else
+static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h
new file mode 100644
index 000000000000..904e5365c78c
--- /dev/null
+++ b/drivers/media/common/tuners/tda18218_priv.h
@@ -0,0 +1,106 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_PRIV_H
+#define TDA18218_PRIV_H
+
+#define LOG_PREFIX "tda18218"
+
+#undef dbg
+#define dbg(f, arg...) \
+ if (debug) \
+ printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define R00_ID 0x00 /* ID byte */
+#define R01_R1 0x01 /* Read byte 1 */
+#define R02_R2 0x02 /* Read byte 2 */
+#define R03_R3 0x03 /* Read byte 3 */
+#define R04_R4 0x04 /* Read byte 4 */
+#define R05_R5 0x05 /* Read byte 5 */
+#define R06_R6 0x06 /* Read byte 6 */
+#define R07_MD1 0x07 /* Main divider byte 1 */
+#define R08_PSM1 0x08 /* PSM byte 1 */
+#define R09_MD2 0x09 /* Main divider byte 2 */
+#define R0A_MD3 0x0a /* Main divider byte 1 */
+#define R0B_MD4 0x0b /* Main divider byte 4 */
+#define R0C_MD5 0x0c /* Main divider byte 5 */
+#define R0D_MD6 0x0d /* Main divider byte 6 */
+#define R0E_MD7 0x0e /* Main divider byte 7 */
+#define R0F_MD8 0x0f /* Main divider byte 8 */
+#define R10_CD1 0x10 /* Call divider byte 1 */
+#define R11_CD2 0x11 /* Call divider byte 2 */
+#define R12_CD3 0x12 /* Call divider byte 3 */
+#define R13_CD4 0x13 /* Call divider byte 4 */
+#define R14_CD5 0x14 /* Call divider byte 5 */
+#define R15_CD6 0x15 /* Call divider byte 6 */
+#define R16_CD7 0x16 /* Call divider byte 7 */
+#define R17_PD1 0x17 /* Power-down byte 1 */
+#define R18_PD2 0x18 /* Power-down byte 2 */
+#define R19_XTOUT 0x19 /* XTOUT byte */
+#define R1A_IF1 0x1a /* IF byte 1 */
+#define R1B_IF2 0x1b /* IF byte 2 */
+#define R1C_AGC2B 0x1c /* AGC2b byte */
+#define R1D_PSM2 0x1d /* PSM byte 2 */
+#define R1E_PSM3 0x1e /* PSM byte 3 */
+#define R1F_PSM4 0x1f /* PSM byte 4 */
+#define R20_AGC11 0x20 /* AGC1 byte 1 */
+#define R21_AGC12 0x21 /* AGC1 byte 2 */
+#define R22_AGC13 0x22 /* AGC1 byte 3 */
+#define R23_AGC21 0x23 /* AGC2 byte 1 */
+#define R24_AGC22 0x24 /* AGC2 byte 2 */
+#define R25_AAGC 0x25 /* Analog AGC byte */
+#define R26_RC 0x26 /* RC byte */
+#define R27_RSSI 0x27 /* RSSI byte */
+#define R28_IRCAL1 0x28 /* IR CAL byte 1 */
+#define R29_IRCAL2 0x29 /* IR CAL byte 2 */
+#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */
+#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */
+#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */
+#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */
+#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */
+#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */
+#define R30_RFCAL5 0x30 /* RF CAL byte 5 */
+#define R31_RFCAL6 0x31 /* RF CAL byte 6 */
+#define R32_RFCAL7 0x32 /* RF CAL byte 7 */
+#define R33_RFCAL8 0x33 /* RF CAL byte 8 */
+#define R34_RFCAL9 0x34 /* RF CAL byte 9 */
+#define R35_RFCAL10 0x35 /* RF CAL byte 10 */
+#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */
+#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */
+#define R38_MARGIN 0x38 /* Margin byte */
+#define R39_FMAX1 0x39 /* Fmax byte 1 */
+#define R3A_FMAX2 0x3a /* Fmax byte 2 */
+
+#define TDA18218_NUM_REGS 59
+
+struct tda18218_priv {
+ struct tda18218_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u8 regs[TDA18218_NUM_REGS];
+};
+
+#endif
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index e1f678281a58..5466d47db899 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -193,25 +193,51 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
unsigned char *regs = priv->tda18271_regs;
unsigned char buf[TDA18271_NUM_REGS + 1];
struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
- .buf = buf, .len = len + 1 };
- int i, ret;
+ .buf = buf };
+ int i, ret = 1, max;
BUG_ON((len == 0) || (idx + len > sizeof(buf)));
- buf[0] = idx;
- for (i = 1; i <= len; i++)
- buf[i] = regs[idx - 1 + i];
+
+ switch (priv->small_i2c) {
+ case TDA18271_03_BYTE_CHUNK_INIT:
+ max = 3;
+ break;
+ case TDA18271_08_BYTE_CHUNK_INIT:
+ max = 8;
+ break;
+ case TDA18271_16_BYTE_CHUNK_INIT:
+ max = 16;
+ break;
+ case TDA18271_39_BYTE_CHUNK_INIT:
+ default:
+ max = 39;
+ }
tda18271_i2c_gate_ctrl(fe, 1);
+ while (len) {
+ if (max > len)
+ max = len;
- /* write registers */
- ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ buf[0] = idx;
+ for (i = 1; i <= max; i++)
+ buf[i] = regs[idx - 1 + i];
+ msg.len = max + 1;
+
+ /* write registers */
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ if (ret != 1)
+ break;
+
+ idx += max;
+ len -= max;
+ }
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 1)
tda_err("ERROR: idx = 0x%x, len = %d, "
- "i2c_transfer returned: %d\n", idx, len, ret);
+ "i2c_transfer returned: %d\n", idx, max, ret);
return (ret == 1 ? 0 : ret);
}
@@ -326,24 +352,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
regs[R_EB22] = 0x48;
regs[R_EB23] = 0xb0;
- switch (priv->small_i2c) {
- case TDA18271_08_BYTE_CHUNK_INIT:
- tda18271_write_regs(fe, 0x00, 0x08);
- tda18271_write_regs(fe, 0x08, 0x08);
- tda18271_write_regs(fe, 0x10, 0x08);
- tda18271_write_regs(fe, 0x18, 0x08);
- tda18271_write_regs(fe, 0x20, 0x07);
- break;
- case TDA18271_16_BYTE_CHUNK_INIT:
- tda18271_write_regs(fe, 0x00, 0x10);
- tda18271_write_regs(fe, 0x10, 0x10);
- tda18271_write_regs(fe, 0x20, 0x07);
- break;
- case TDA18271_39_BYTE_CHUNK_INIT:
- default:
- tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
- break;
- }
+ tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
/* setup agc1 gain */
regs[R_EB17] = 0x00;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index 7955e49a3440..9ad4454a148d 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -1156,7 +1156,6 @@ static int tda18271_get_id(struct dvb_frontend *fe)
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
char *name;
- int ret = 0;
mutex_lock(&priv->lock);
tda18271_read_regs(fe);
@@ -1172,17 +1171,16 @@ static int tda18271_get_id(struct dvb_frontend *fe)
priv->id = TDA18271HDC2;
break;
default:
- name = "Unknown device";
- ret = -EINVAL;
- break;
+ tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
+ regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
+ priv->i2c_props.addr);
+ return -EINVAL;
}
- tda_info("%s detected @ %d-%04x%s\n", name,
- i2c_adapter_id(priv->i2c_props.adap),
- priv->i2c_props.addr,
- (0 == ret) ? "" : ", device not supported.");
+ tda_info("%s detected @ %d-%04x\n", name,
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
- return ret;
+ return 0;
}
static int tda18271_setup_configuration(struct dvb_frontend *fe,
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h
index d7fcc36dc6e6..3abb221f3d07 100644
--- a/drivers/media/common/tuners/tda18271.h
+++ b/drivers/media/common/tuners/tda18271.h
@@ -80,8 +80,9 @@ enum tda18271_output_options {
enum tda18271_small_i2c {
TDA18271_39_BYTE_CHUNK_INIT = 0,
- TDA18271_16_BYTE_CHUNK_INIT = 1,
- TDA18271_08_BYTE_CHUNK_INIT = 2,
+ TDA18271_16_BYTE_CHUNK_INIT = 16,
+ TDA18271_08_BYTE_CHUNK_INIT = 8,
+ TDA18271_03_BYTE_CHUNK_INIT = 3,
};
struct tda18271_config {
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index d2b2c12a5561..76ac5cd84af7 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -1042,7 +1042,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg)
+ const struct xc5000_config *cfg)
{
struct xc5000_priv *priv = NULL;
int instance;
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index e6d7236c9ea1..3756e73649be 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -53,11 +53,11 @@ struct xc5000_config {
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg);
+ const struct xc5000_config *cfg);
#else
static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg)
+ const struct xc5000_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index fd1df2352764..965d5eb33752 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -245,9 +245,6 @@ int flexcop_i2c_init(struct flexcop_device *fc)
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
- fc->fc_i2c_adap[0].i2c_adap.class =
- fc->fc_i2c_adap[1].i2c_adap.class =
- fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL;
fc->fc_i2c_adap[0].i2c_adap.algo =
fc->fc_i2c_adap[1].i2c_adap.algo =
fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index bca07c0bcd01..5d404f1bf036 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -862,7 +862,6 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
i2c_set_adapdata(&dev->i2c_adap, dev);
strcpy(dev->i2c_adap.name, DRIVER_NAME);
dev->i2c_adap.owner = THIS_MODULE;
- dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
dev->i2c_adap.dev.parent = &pdev->dev;
dev->i2c_adap.algo = &dm1105_algo;
dev->i2c_adap.algo_data = dev;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 970c9b8882d4..1589d5a5cb46 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -702,7 +702,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
kthread_stop(fepriv->thread);
- init_MUTEX (&fepriv->sem);
+ sema_init(&fepriv->sem, 1);
fepriv->state = FESTATE_IDLE;
/* paranoia check in case a signal arrived */
@@ -2062,7 +2062,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
}
fepriv = fe->frontend_priv;
- init_MUTEX (&fepriv->sem);
+ sema_init(&fepriv->sem, 1);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
mutex_init(&fepriv->events.mtx);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index bf0e6bed28dd..f9f19be77181 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -260,7 +260,7 @@ struct dvb_frontend_ops {
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
- int (*write)(struct dvb_frontend* fe, u8* buf, int len);
+ int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index fdc19bba2128..2525d3b3c88d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -314,6 +314,8 @@ config DVB_USB_AF9015
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
@@ -346,3 +348,13 @@ config DVB_USB_AZ6027
select DVB_STB6100 if !DVB_FE_CUSTOMISE
help
Say Y here to support the AZ6027 device
+
+config DVB_USB_LME2510
+ tristate "LME DM04/QQBOX DVB-S USB2.0 support"
+ depends on DVB_USB
+ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+ select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ select DVB_STV0288 if !DVB_FE_CUSTOMISE
+ select DVB_IX2505V if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 1a192453b0e7..5b1d12f2d591 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -88,6 +88,9 @@ obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
dvb-usb-az6027-objs = az6027.o
obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
+dvb-usb-lmedm04-objs = lmedm04.o
+obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index ea1ed3b4592a..31c0a0ed39f5 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -31,6 +31,8 @@
#include "tda18271.h"
#include "mxl5005s.h"
#include "mc44s803.h"
+#include "tda18218.h"
+#include "mxl5007t.h"
static int dvb_usb_af9015_debug;
module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@@ -205,10 +207,16 @@ static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
return af9015_write_regs(d, addr, &val, 1);
}
+static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
+{
+ struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+ val};
+ return af9015_ctrl_msg(d, &req);
+}
+
static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
{
- struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
- return af9015_ctrl_msg(d, &req);
+ return af9015_read_regs(d, addr, val, 1);
}
static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
@@ -241,7 +249,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int ret = 0, i = 0;
u16 addr;
- u8 mbox, addr_len;
+ u8 uninitialized_var(mbox), addr_len;
struct req_t req;
/* TODO: implement bus lock
@@ -280,7 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
} else {
addr = msg[i].buf[0];
addr_len = 1;
- mbox = 0;
+ /* mbox is don't care in that case */
}
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
@@ -494,7 +502,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
/* wait 2nd demodulator ready */
msleep(100);
- ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
+ ret = af9015_read_reg_i2c(d,
+ af9015_af9013_config[1].demod_address, 0x98be, &val);
if (ret)
goto error;
else
@@ -597,37 +606,6 @@ free:
return ret;
}
-static int af9015_download_ir_table(struct dvb_usb_device *d)
-{
- int i, packets = 0, ret;
- u16 addr = 0x9a56; /* ir-table start address */
- struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
- u8 *data = NULL;
- deb_info("%s:\n", __func__);
-
- data = af9015_config.ir_table;
- packets = af9015_config.ir_table_size;
-
- /* no remote */
- if (!packets)
- goto exit;
-
- /* load remote ir-table */
- for (i = 0; i < packets; i++) {
- req.addr = addr + i;
- req.data = &data[i];
- ret = af9015_ctrl_msg(d, &req);
- if (ret) {
- err("ir-table download failed at packet %d with " \
- "code %d", i, ret);
- return ret;
- }
- }
-
-exit:
- return 0;
-}
-
static int af9015_init(struct dvb_usb_device *d)
{
int ret;
@@ -637,10 +615,6 @@ static int af9015_init(struct dvb_usb_device *d)
if (ret)
goto error;
- ret = af9015_download_ir_table(d);
- if (ret)
- goto error;
-
error:
return ret;
}
@@ -733,125 +707,102 @@ error:
return ret;
}
-struct af9015_setup {
+struct af9015_rc_setup {
unsigned int id;
- struct ir_scancode *rc_key_map;
- unsigned int rc_key_map_size;
- u8 *ir_table;
- unsigned int ir_table_size;
+ char *rc_codes;
};
-static const struct af9015_setup *af9015_setup_match(unsigned int id,
- const struct af9015_setup *table)
+static char *af9015_rc_setup_match(unsigned int id,
+ const struct af9015_rc_setup *table)
{
- for (; table->rc_key_map; table++)
+ for (; table->rc_codes; table++)
if (table->id == id)
- return table;
+ return table->rc_codes;
return NULL;
}
-static const struct af9015_setup af9015_setup_modparam[] = {
- { AF9015_REMOTE_A_LINK_DTU_M,
- ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
- af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
- { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
- af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
- { AF9015_REMOTE_MYGICTV_U718,
- ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
- af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
- { AF9015_REMOTE_DIGITTRADE_DVB_T,
- ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
- af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
- { AF9015_REMOTE_AVERMEDIA_KS,
- ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
- af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
+static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
+ { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
+ { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
+ { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
+ { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
+ { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
{ }
};
-/* don't add new entries here anymore, use hashes instead */
-static const struct af9015_setup af9015_setup_usbids[] = {
- { USB_VID_LEADTEK,
- ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
- af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
- { USB_VID_VISIONPLUS,
- ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
- af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
- { USB_VID_KWORLD_2, /* TODO: use correct rc keys */
- ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
- af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
- { USB_VID_AVERMEDIA,
- ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
- af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
- { USB_VID_MSI_2,
- ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
- af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
+static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
+ { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
+ { 0xa3703d00, RC_MAP_ALINK_DTU_M },
+ { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
{ }
};
-static const struct af9015_setup af9015_setup_hashes[] = {
- { 0xb8feb708,
- ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
- af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
- { 0xa3703d00,
- ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
- af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
- { 0x9b7dc64e,
- ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
- af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
+ { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+ RC_MAP_TERRATEC_SLIM },
+ { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
+ RC_MAP_AZUREWAVE_AD_TU700 },
+ { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN,
+ RC_MAP_AZUREWAVE_AD_TU700 },
+ { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
+ RC_MAP_MSI_DIGIVOX_III },
+ { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
+ RC_MAP_LEADTEK_Y04G0051 },
+ { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
+ RC_MAP_AVERMEDIA_M135A },
+ { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT,
+ RC_MAP_TREKSTOR },
+ { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2,
+ RC_MAP_DIGITALNOW_TINYTWIN },
+ { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
+ RC_MAP_DIGITALNOW_TINYTWIN },
{ }
};
static void af9015_set_remote_config(struct usb_device *udev,
struct dvb_usb_device_properties *props)
{
- const struct af9015_setup *table = NULL;
+ u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(udev->descriptor.idProduct);
- if (dvb_usb_af9015_remote) {
- /* load remote defined as module param */
- table = af9015_setup_match(dvb_usb_af9015_remote,
- af9015_setup_modparam);
- } else {
- u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
+ /* try to load remote based module param */
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ dvb_usb_af9015_remote, af9015_rc_setup_modparam);
- table = af9015_setup_match(af9015_config.eeprom_sum,
- af9015_setup_hashes);
+ /* try to load remote based eeprom hash */
+ if (!props->rc.core.rc_codes)
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ af9015_config.eeprom_sum, af9015_rc_setup_hashes);
- if (!table && vendor == USB_VID_AFATECH) {
- /* Check USB manufacturer and product strings and try
- to determine correct remote in case of chip vendor
- reference IDs are used.
- DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
- */
- char manufacturer[10];
- memset(manufacturer, 0, sizeof(manufacturer));
- usb_string(udev, udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
- if (!strcmp("MSI", manufacturer)) {
- /* iManufacturer 1 MSI
- iProduct 2 MSI K-VOX */
- table = af9015_setup_match(
- AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- af9015_setup_modparam);
- } else if (udev->descriptor.idProduct ==
- cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
- table = &(const struct af9015_setup){ 0,
- ir_codes_af9015_table_trekstor,
- ARRAY_SIZE(ir_codes_af9015_table_trekstor),
- af9015_ir_table_trekstor,
- ARRAY_SIZE(af9015_ir_table_trekstor)
- };
- }
- } else if (!table)
- table = af9015_setup_match(vendor, af9015_setup_usbids);
+ /* try to load remote based USB ID */
+ if (!props->rc.core.rc_codes)
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ (vid << 16) + pid, af9015_rc_setup_usbids);
+
+ /* try to load remote based USB iManufacturer string */
+ if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
+ /* Check USB manufacturer and product strings and try
+ to determine correct remote in case of chip vendor
+ reference IDs are used.
+ DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+ char manufacturer[10];
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ if (!strcmp("MSI", manufacturer)) {
+ /* iManufacturer 1 MSI
+ iProduct 2 MSI K-VOX */
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ af9015_rc_setup_modparam);
+ }
}
- if (table) {
- props->rc.legacy.rc_key_map = table->rc_key_map;
- props->rc.legacy.rc_key_map_size = table->rc_key_map_size;
- af9015_config.ir_table = table->ir_table;
- af9015_config.ir_table_size = table->ir_table_size;
- }
+ /* finally load "empty" just for leaving IR receiver enabled */
+ if (!props->rc.core.rc_codes)
+ props->rc.core.rc_codes = RC_MAP_EMPTY;
+
+ return;
}
static int af9015_read_config(struct usb_device *udev)
@@ -877,10 +828,9 @@ static int af9015_read_config(struct usb_device *udev)
deb_info("%s: IR mode:%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
- if (val == AF9015_IR_MODE_DISABLED) {
- af9015_properties[i].rc.legacy.rc_key_map = NULL;
- af9015_properties[i].rc.legacy.rc_key_map_size = 0;
- } else
+ if (val == AF9015_IR_MODE_DISABLED)
+ af9015_properties[i].rc.core.rc_codes = NULL;
+ else
af9015_set_remote_config(udev, &af9015_properties[i]);
}
@@ -992,20 +942,19 @@ static int af9015_read_config(struct usb_device *udev)
case AF9013_TUNER_MT2060_2:
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_QT1010A:
+ case AF9013_TUNER_TDA18218:
af9015_af9013_config[i].rf_spec_inv = 1;
break;
case AF9013_TUNER_MXL5003D:
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
+ case AF9013_TUNER_MXL5007T:
af9015_af9013_config[i].rf_spec_inv = 0;
break;
case AF9013_TUNER_MC44S803:
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
af9015_af9013_config[i].rf_spec_inv = 1;
break;
- case AF9013_TUNER_TDA18218:
- warn("tuner NXP TDA18218 not supported yet");
- return -ENODEV;
default:
warn("tuner id:%d not supported, please report!", val);
return -ENODEV;
@@ -1020,9 +969,13 @@ error:
err("eeprom read failed:%d", ret);
/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
- content :-( Override some wrong values here. */
+ content :-( Override some wrong values here. Ditto for the
+ AVerTV Red HD+ (A850T) device. */
if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
- le16_to_cpu(udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) {
+ ((le16_to_cpu(udev->descriptor.idProduct) ==
+ USB_PID_AVERMEDIA_A850) ||
+ (le16_to_cpu(udev->descriptor.idProduct) ==
+ USB_PID_AVERMEDIA_A850T))) {
deb_info("%s: AverMedia A850: overriding config\n", __func__);
/* disable dual mode */
af9015_config.dual_mode = 0;
@@ -1059,36 +1012,53 @@ static int af9015_identify_state(struct usb_device *udev,
return ret;
}
-static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int af9015_rc_query(struct dvb_usb_device *d)
{
- u8 buf[8];
- struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
- int i, ret;
+ struct af9015_state *priv = d->priv;
+ int ret;
+ u8 buf[16];
- memset(buf, 0, sizeof(buf));
-
- ret = af9015_ctrl_msg(d, &req);
+ /* read registers needed to detect remote controller code */
+ ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
if (ret)
- return ret;
+ goto error;
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
+ if (buf[14] || buf[15]) {
+ deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
+ buf[12], buf[13], buf[14], buf[15]);
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
- if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
- rc5_data(&keymap[i]) == buf[2]) {
- *event = keymap[i].keycode;
- *state = REMOTE_KEY_PRESSED;
- break;
+ /* clean IR code from mem */
+ ret = af9015_write_regs(d, 0x98e5, "\x00\x00\x00\x00", 4);
+ if (ret)
+ goto error;
+
+ if (buf[14] == (u8) ~buf[15]) {
+ if (buf[12] == (u8) ~buf[13]) {
+ /* NEC */
+ priv->rc_keycode = buf[12] << 8 | buf[14];
+ } else {
+ /* NEC extended*/
+ priv->rc_keycode = buf[12] << 16 |
+ buf[13] << 8 | buf[14];
+ }
+ ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
+ } else {
+ priv->rc_keycode = 0; /* clear just for sure */
}
+ } else if (priv->rc_repeat != buf[6] || buf[0]) {
+ deb_rc("%s: key repeated\n", __func__);
+ ir_keydown(d->rc_input_dev, priv->rc_keycode, 0);
+ } else {
+ deb_rc("%s: no key press\n", __func__);
}
- if (!buf[1])
- deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- __func__, buf[0], buf[1], buf[2], buf[3], buf[4],
- buf[5], buf[6], buf[7]);
- return 0;
+ priv->rc_repeat = buf[6];
+
+error:
+ if (ret)
+ err("%s: failed:%d", __func__, ret);
+
+ return ret;
}
/* init 2nd I2C adapter */
@@ -1100,11 +1070,6 @@ static int af9015_i2c_init(struct dvb_usb_device *d)
strncpy(state->i2c_adap.name, d->desc->name,
sizeof(state->i2c_adap.name));
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
- state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
state->i2c_adap.algo = d->props.i2c_algo;
state->i2c_adap.algo_data = NULL;
state->i2c_adap.dev.parent = &d->udev->dev;
@@ -1166,7 +1131,7 @@ static struct qt1010_config af9015_qt1010_config = {
static struct tda18271_config af9015_tda18271_config = {
.gate = TDA18271_GATE_DIGITAL,
- .small_i2c = 1,
+ .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
};
static struct mxl5005s_config af9015_mxl5003_config = {
@@ -1208,12 +1173,22 @@ static struct mc44s803_config af9015_mc44s803_config = {
.dig_out = 1,
};
+static struct tda18218_config af9015_tda18218_config = {
+ .i2c_address = 0xc0,
+ .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
+};
+
+static struct mxl5007t_config af9015_mxl5007t_config = {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+};
+
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
struct af9015_state *state = adap->dev->priv;
struct i2c_adapter *i2c_adap;
int ret;
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
/* select I2C adapter */
if (adap->id == 0)
@@ -1238,6 +1213,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
&af9015_tda18271_config) == NULL ? -ENODEV : 0;
break;
+ case AF9013_TUNER_TDA18218:
+ ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
+ &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+ break;
case AF9013_TUNER_MXL5003D:
ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
@@ -1255,6 +1234,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
+ case AF9013_TUNER_MXL5007T:
+ ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap,
+ 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+ break;
case AF9013_TUNER_UNKNOWN:
default:
ret = -ENODEV;
@@ -1300,10 +1283,16 @@ static struct usb_device_id af9015_usb_table[] = {
/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
+ {USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
+/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
+ {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
+#define AF9015_RC_INTERVAL 500
static struct dvb_usb_device_properties af9015_properties[] = {
{
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1354,14 +1343,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc.legacy = {
+ .rc.core = {
+ .protocol = IR_TYPE_NEC,
+ .module_name = "af9015",
.rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc_interval = AF9015_RC_INTERVAL,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_NEC,
+ },
},
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 9, /* max 9 */
+ .num_device_descs = 12, /* check max from dvb-usb.h */
.devices = {
{
.name = "Afatech AF9015 DVB-T USB2.0 stick",
@@ -1389,7 +1383,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
{
.name = "DigitalNow TinyTwin DVB-T Receiver",
.cold_ids = {&af9015_usb_table[5],
- &af9015_usb_table[28], NULL},
+ &af9015_usb_table[28],
+ &af9015_usb_table[36], NULL},
.warm_ids = {NULL},
},
{
@@ -1413,6 +1408,21 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[9], NULL},
.warm_ids = {NULL},
},
+ {
+ .name = "TerraTec Cinergy T Stick RC",
+ .cold_ids = {&af9015_usb_table[33], NULL},
+ .warm_ids = {NULL},
+ },
+ {
+ .name = "TerraTec Cinergy T Stick Dual RC",
+ .cold_ids = {&af9015_usb_table[34], NULL},
+ .warm_ids = {NULL},
+ },
+ {
+ .name = "AverMedia AVerTV Red HD+ (A850T)",
+ .cold_ids = {&af9015_usb_table[35], NULL},
+ .warm_ids = {NULL},
+ },
}
}, {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1463,14 +1473,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc.legacy = {
+ .rc.core = {
+ .protocol = IR_TYPE_NEC,
+ .module_name = "af9015",
.rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc_interval = AF9015_RC_INTERVAL,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_NEC,
+ },
},
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 9, /* max 9 */
+ .num_device_descs = 9, /* check max from dvb-usb.h */
.devices = {
{
.name = "Xtensions XD-380",
@@ -1572,14 +1587,19 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc.legacy = {
+ .rc.core = {
+ .protocol = IR_TYPE_NEC,
+ .module_name = "af9015",
.rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc_interval = AF9015_RC_INTERVAL,
+ .rc_props = {
+ .allowed_protos = IR_TYPE_NEC,
+ },
},
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 9, /* max 9 */
+ .num_device_descs = 9, /* check max from dvb-usb.h */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1672,7 +1692,7 @@ static int af9015_usb_probe(struct usb_interface *intf,
static void af9015_i2c_exit(struct dvb_usb_device *d)
{
struct af9015_state *state = d->priv;
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
/* remove 2nd I2C adapter */
if (d->state & DVB_USB_STATE_I2C)
@@ -1682,7 +1702,7 @@ static void af9015_i2c_exit(struct dvb_usb_device *d)
static void af9015_usb_device_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
/* remove 2nd I2C adapter */
if (d != NULL && d->desc != NULL)
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index c8e9349742ee..f20cfa6ed690 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -100,6 +100,8 @@ enum af9015_ir_mode {
struct af9015_state {
struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
+ u8 rc_repeat;
+ u32 rc_keycode;
};
struct af9015_config {
@@ -108,8 +110,6 @@ struct af9015_config {
u16 firmware_size;
u16 firmware_checksum;
u32 eeprom_sum;
- u8 *ir_table;
- u16 ir_table_size;
};
enum af9015_remote {
@@ -121,735 +121,4 @@ enum af9015_remote {
/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
};
-/* LeadTek - Y04G0051 */
-/* Leadtek WinFast DTV Dongle Gold */
-static struct ir_scancode ir_codes_af9015_table_leadtek[] = {
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x0028, KEY_OK },
- { 0x004f, KEY_RIGHT },
- { 0x0050, KEY_LEFT },
- { 0x0051, KEY_DOWN },
- { 0x0052, KEY_UP },
- { 0x011a, KEY_POWER2 },
- { 0x04b4, KEY_TV },
- { 0x04b3, KEY_RED },
- { 0x04b2, KEY_GREEN },
- { 0x04b1, KEY_YELLOW },
- { 0x04b0, KEY_BLUE },
- { 0x003d, KEY_TEXT },
- { 0x0113, KEY_SLEEP },
- { 0x0010, KEY_MUTE },
- { 0x0105, KEY_ESC },
- { 0x0009, KEY_SCREEN },
- { 0x010f, KEY_MENU },
- { 0x003f, KEY_CHANNEL },
- { 0x0013, KEY_REWIND },
- { 0x0012, KEY_PLAY },
- { 0x0011, KEY_FASTFORWARD },
- { 0x0005, KEY_PREVIOUS },
- { 0x0029, KEY_STOP },
- { 0x002b, KEY_NEXT },
- { 0x0041, KEY_EPG },
- { 0x0019, KEY_VIDEO },
- { 0x0016, KEY_AUDIO },
- { 0x0037, KEY_DOT },
- { 0x002a, KEY_AGAIN },
- { 0x002c, KEY_CAMERA },
- { 0x003c, KEY_NEW },
- { 0x0115, KEY_RECORD },
- { 0x010b, KEY_TIME },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x004b, KEY_CHANNELUP },
- { 0x004e, KEY_CHANNELDOWN },
-};
-
-static u8 af9015_ir_table_leadtek[] = {
- 0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, /* KEY_POWER2 */
- 0x03, 0xfc, 0x56, 0xa9, 0xb4, 0x04, 0x00, /* KEY_TV */
- 0x03, 0xfc, 0x4b, 0xb4, 0xb3, 0x04, 0x00, /* KEY_RED */
- 0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, /* KEY_GREEN */
- 0x03, 0xfc, 0x4d, 0xb2, 0xb1, 0x04, 0x00, /* KEY_YELLOW */
- 0x03, 0xfc, 0x4e, 0xb1, 0xb0, 0x04, 0x00, /* KEY_BLUE */
- 0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, /* KEY_TEXT */
- 0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, /* KEY_SLEEP */
- 0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, /* KEY_MUTE */
- 0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, /* KEY_ESC */
- 0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, /* KEY_STOP (1)*/
- 0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, /* KEY_UP */
- 0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, /* KEY_SCREEN */
- 0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, /* KEY_LEFT */
- 0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, /* KEY_OK (1) */
- 0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, /* KEY_RIGHT */
- 0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, /* KEY_MENU */
- 0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, /* KEY_DOWN */
- 0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, /* KEY_CHANNEL */
- 0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, /* KEY_REWIND */
- 0x03, 0xfc, 0x43, 0xbc, 0x12, 0x00, 0x00, /* KEY_PLAY */
- 0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, /* KEY_FASTFORWARD */
- 0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, /* KEY_VIDEO (1) */
- 0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, /* KEY_PREVIOUS */
- 0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, /* KEY_STOP (2) */
- 0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, /* KEY_NEXT */
- 0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, /* KEY_EPG */
- 0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, /* KEY_1 */
- 0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, /* KEY_2 */
- 0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, /* KEY_3 */
- 0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, /* KEY_VIDEO (2) */
- 0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, /* KEY_4 */
- 0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, /* KEY_5 */
- 0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, /* KEY_6 */
- 0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, /* KEY_AUDIO */
- 0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, /* KEY_7 */
- 0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, /* KEY_8 */
- 0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, /* KEY_9 */
- 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* KEY_OK (2) */
- 0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, /* KEY_DOT */
- 0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, /* KEY_0 */
- 0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, /* KEY_AGAIN */
- 0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, /* KEY_CAMERA */
- 0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, /* KEY_NEW */
- 0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, /* KEY_RECORD */
- 0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, /* KEY_TIME */
- 0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, /* KEY_VOLUMEUP */
- 0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, /* KEY_VOLUMEDOWN */
- 0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, /* KEY_CHANNELUP */
- 0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, /* KEY_CHANNELDOWN */
-};
-
-/* TwinHan AzureWave AD-TU700(704J) */
-static struct ir_scancode ir_codes_af9015_table_twinhan[] = {
- { 0x053f, KEY_POWER },
- { 0x0019, KEY_FAVORITES }, /* Favorite List */
- { 0x0004, KEY_TEXT }, /* Teletext */
- { 0x000e, KEY_POWER },
- { 0x000e, KEY_INFO }, /* Preview */
- { 0x0008, KEY_EPG }, /* Info/EPG */
- { 0x000f, KEY_LIST }, /* Record List */
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x0029, KEY_CANCEL }, /* Cancel */
- { 0x004c, KEY_CLEAR }, /* Clear */
- { 0x002a, KEY_BACK }, /* Back */
- { 0x002b, KEY_TAB }, /* Tab */
- { 0x0052, KEY_UP }, /* up arrow */
- { 0x0051, KEY_DOWN }, /* down arrow */
- { 0x004f, KEY_RIGHT }, /* right arrow */
- { 0x0050, KEY_LEFT }, /* left arrow */
- { 0x0028, KEY_ENTER }, /* Enter / ok */
- { 0x0252, KEY_VOLUMEUP },
- { 0x0251, KEY_VOLUMEDOWN },
- { 0x004e, KEY_CHANNELDOWN },
- { 0x004b, KEY_CHANNELUP },
- { 0x004a, KEY_RECORD },
- { 0x0111, KEY_PLAY },
- { 0x0017, KEY_PAUSE },
- { 0x000c, KEY_REWIND }, /* FR << */
- { 0x0011, KEY_FASTFORWARD }, /* FF >> */
- { 0x0115, KEY_PREVIOUS }, /* Replay */
- { 0x010e, KEY_NEXT }, /* Skip */
- { 0x0013, KEY_CAMERA }, /* Capture */
- { 0x010f, KEY_LANGUAGE }, /* SAP */
- { 0x0113, KEY_TV2 }, /* PIP */
- { 0x001d, KEY_ZOOM }, /* Full Screen */
- { 0x0117, KEY_SUBTITLE }, /* Subtitle / CC */
- { 0x0010, KEY_MUTE },
- { 0x0119, KEY_AUDIO }, /* L/R */ /* TODO better event */
- { 0x0116, KEY_SLEEP }, /* Hibernate */
- { 0x0116, KEY_SWITCHVIDEOMODE },
- /* A/V */ /* TODO does not work */
- { 0x0006, KEY_AGAIN }, /* Recall */
- { 0x0116, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */
- { 0x0116, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */
- { 0x0215, KEY_RED },
- { 0x020a, KEY_GREEN },
- { 0x021c, KEY_YELLOW },
- { 0x0205, KEY_BLUE },
-};
-
-static u8 af9015_ir_table_twinhan[] = {
- 0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
- 0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
- 0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
- 0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
- 0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
- 0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
- 0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
- 0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
- 0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
- 0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
- 0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
- 0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
- 0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
- 0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
- 0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
- 0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
- 0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
- 0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
- 0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
- 0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
- 0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
- 0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
- 0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
- 0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
- 0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
- 0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
- 0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
- 0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
- 0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
- 0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
- 0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
- 0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
- 0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
- 0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
- 0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
- 0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
- 0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
- 0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
- 0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
- 0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
- 0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
- 0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
- 0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
- 0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
- 0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
- 0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
- 0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
- 0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
- 0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
-};
-
-/* A-Link DTU(m) */
-static struct ir_scancode ir_codes_af9015_table_a_link[] = {
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x002e, KEY_CHANNELUP },
- { 0x002d, KEY_CHANNELDOWN },
- { 0x0428, KEY_ZOOM },
- { 0x0041, KEY_MUTE },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0044, KEY_GOTO }, /* jump */
- { 0x0545, KEY_POWER },
-};
-
-static u8 af9015_ir_table_a_link[] = {
- 0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
- 0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
- 0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
- 0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
- 0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
- 0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
- 0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
- 0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
- 0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
- 0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
- 0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
- 0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
- 0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
- 0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
- 0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
- 0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
- 0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
- 0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
-};
-
-/* MSI DIGIVOX mini II V3.0 */
-static struct ir_scancode ir_codes_af9015_table_msi[] = {
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x030f, KEY_CHANNELUP },
- { 0x030e, KEY_CHANNELDOWN },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0545, KEY_POWER },
- { 0x0052, KEY_UP }, /* up */
- { 0x0051, KEY_DOWN }, /* down */
- { 0x0028, KEY_ENTER },
-};
-
-static u8 af9015_ir_table_msi[] = {
- 0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
- 0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
- 0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
- 0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
- 0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
- 0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
- 0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
- 0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
- 0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
- 0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
- 0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
- 0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
- 0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
- 0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
- 0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
- 0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
- 0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
- 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
-};
-
-/* MYGICTV U718 */
-static struct ir_scancode ir_codes_af9015_table_mygictv[] = {
- { 0x003d, KEY_SWITCHVIDEOMODE },
- /* TV / AV */
- { 0x0545, KEY_POWER },
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x0041, KEY_MUTE },
- { 0x002a, KEY_ESC }, /* Esc */
- { 0x002e, KEY_CHANNELUP },
- { 0x002d, KEY_CHANNELDOWN },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0052, KEY_UP }, /* up arrow */
- { 0x0051, KEY_DOWN }, /* down arrow */
- { 0x004f, KEY_RIGHT }, /* right arrow */
- { 0x0050, KEY_LEFT }, /* left arrow */
- { 0x0028, KEY_ENTER }, /* ok */
- { 0x0115, KEY_RECORD },
- { 0x0313, KEY_PLAY },
- { 0x0113, KEY_PAUSE },
- { 0x0116, KEY_STOP },
- { 0x0307, KEY_REWIND }, /* FR << */
- { 0x0309, KEY_FASTFORWARD }, /* FF >> */
- { 0x003b, KEY_TIME }, /* TimeShift */
- { 0x003e, KEY_CAMERA }, /* Snapshot */
- { 0x0316, KEY_CYCLEWINDOWS }, /* yellow, min / max */
- { 0x0000, KEY_ZOOM }, /* 'select' (?) */
- { 0x0316, KEY_SHUFFLE }, /* Shuffle */
- { 0x0345, KEY_POWER },
-};
-
-static u8 af9015_ir_table_mygictv[] = {
- 0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
- 0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
- 0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
- 0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
- 0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
- 0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
- 0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
- 0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
- 0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
- 0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
- 0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
- 0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
- 0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
- 0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
- 0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
- 0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
- 0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
- 0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
- 0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
- 0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
- 0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
- 0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
- 0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
- 0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
- 0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
- 0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
- 0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
- 0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
- 0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
- 0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
- 0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
- 0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
- 0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
- 0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
- 0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
-};
-
-/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
-static u8 af9015_ir_table_kworld[] = {
- 0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
- 0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
- 0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
- 0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
- 0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
- 0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
- 0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
- 0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
- 0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
- 0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
- 0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
- 0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
- 0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
- 0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
- 0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
- 0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
- 0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
- 0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
- 0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
- 0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
- 0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
- 0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
- 0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
- 0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
- 0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
- 0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
- 0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
- 0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
- 0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
- 0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
- 0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
- 0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
- 0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
- 0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
- 0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
- 0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
- 0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
- 0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
- 0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
- 0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
- 0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
- 0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
- 0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
- 0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
-};
-
-/* AverMedia Volar X */
-static struct ir_scancode ir_codes_af9015_table_avermedia[] = {
- { 0x053d, KEY_PROG1 }, /* SOURCE */
- { 0x0512, KEY_POWER }, /* POWER */
- { 0x051e, KEY_1 }, /* 1 */
- { 0x051f, KEY_2 }, /* 2 */
- { 0x0520, KEY_3 }, /* 3 */
- { 0x0521, KEY_4 }, /* 4 */
- { 0x0522, KEY_5 }, /* 5 */
- { 0x0523, KEY_6 }, /* 6 */
- { 0x0524, KEY_7 }, /* 7 */
- { 0x0525, KEY_8 }, /* 8 */
- { 0x0526, KEY_9 }, /* 9 */
- { 0x053f, KEY_LEFT }, /* L / DISPLAY */
- { 0x0527, KEY_0 }, /* 0 */
- { 0x050f, KEY_RIGHT }, /* R / CH RTN */
- { 0x0518, KEY_PROG2 }, /* SNAP SHOT */
- { 0x051c, KEY_PROG3 }, /* 16-CH PREV */
- { 0x052d, KEY_VOLUMEDOWN }, /* VOL DOWN */
- { 0x053e, KEY_ZOOM }, /* FULL SCREEN */
- { 0x052e, KEY_VOLUMEUP }, /* VOL UP */
- { 0x0510, KEY_MUTE }, /* MUTE */
- { 0x0504, KEY_AUDIO }, /* AUDIO */
- { 0x0515, KEY_RECORD }, /* RECORD */
- { 0x0511, KEY_PLAY }, /* PLAY */
- { 0x0516, KEY_STOP }, /* STOP */
- { 0x050c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
- { 0x0505, KEY_BACK }, /* << / RED */
- { 0x0509, KEY_FORWARD }, /* >> / YELLOW */
- { 0x0517, KEY_TEXT }, /* TELETEXT */
- { 0x050a, KEY_EPG }, /* EPG */
- { 0x0513, KEY_MENU }, /* MENU */
-
- { 0x050e, KEY_CHANNELUP }, /* CH UP */
- { 0x050d, KEY_CHANNELDOWN }, /* CH DOWN */
- { 0x0519, KEY_FIRST }, /* |<< / GREEN */
- { 0x0508, KEY_LAST }, /* >>| / BLUE */
-};
-
-static u8 af9015_ir_table_avermedia[] = {
- 0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
- 0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
- 0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
- 0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
- 0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
- 0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
- 0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
- 0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
- 0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
- 0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
- 0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
- 0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
- 0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
- 0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
- 0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
- 0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
- 0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
- 0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
- 0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
- 0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
- 0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
- 0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
- 0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
- 0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
- 0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
- 0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
- 0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
- 0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
- 0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
- 0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
- 0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
- 0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
- 0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
- 0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
-};
-
-static u8 af9015_ir_table_avermedia_ks[] = {
- 0x05, 0xfa, 0x01, 0xfe, 0x12, 0x05, 0x00,
- 0x05, 0xfa, 0x02, 0xfd, 0x0e, 0x05, 0x00,
- 0x05, 0xfa, 0x03, 0xfc, 0x0d, 0x05, 0x00,
- 0x05, 0xfa, 0x04, 0xfb, 0x2e, 0x05, 0x00,
- 0x05, 0xfa, 0x05, 0xfa, 0x2d, 0x05, 0x00,
- 0x05, 0xfa, 0x06, 0xf9, 0x10, 0x05, 0x00,
- 0x05, 0xfa, 0x07, 0xf8, 0x0f, 0x05, 0x00,
- 0x05, 0xfa, 0x08, 0xf7, 0x3d, 0x05, 0x00,
- 0x05, 0xfa, 0x09, 0xf6, 0x1e, 0x05, 0x00,
- 0x05, 0xfa, 0x0a, 0xf5, 0x1f, 0x05, 0x00,
- 0x05, 0xfa, 0x0b, 0xf4, 0x20, 0x05, 0x00,
- 0x05, 0xfa, 0x0c, 0xf3, 0x21, 0x05, 0x00,
- 0x05, 0xfa, 0x0d, 0xf2, 0x22, 0x05, 0x00,
- 0x05, 0xfa, 0x0e, 0xf1, 0x23, 0x05, 0x00,
- 0x05, 0xfa, 0x0f, 0xf0, 0x24, 0x05, 0x00,
- 0x05, 0xfa, 0x10, 0xef, 0x25, 0x05, 0x00,
- 0x05, 0xfa, 0x11, 0xee, 0x26, 0x05, 0x00,
- 0x05, 0xfa, 0x12, 0xed, 0x27, 0x05, 0x00,
- 0x05, 0xfa, 0x13, 0xec, 0x04, 0x05, 0x00,
- 0x05, 0xfa, 0x15, 0xea, 0x0a, 0x05, 0x00,
- 0x05, 0xfa, 0x16, 0xe9, 0x11, 0x05, 0x00,
- 0x05, 0xfa, 0x17, 0xe8, 0x15, 0x05, 0x00,
- 0x05, 0xfa, 0x18, 0xe7, 0x16, 0x05, 0x00,
- 0x05, 0xfa, 0x1c, 0xe3, 0x05, 0x05, 0x00,
- 0x05, 0xfa, 0x1d, 0xe2, 0x09, 0x05, 0x00,
- 0x05, 0xfa, 0x4d, 0xb2, 0x3f, 0x05, 0x00,
- 0x05, 0xfa, 0x56, 0xa9, 0x3e, 0x05, 0x00
-};
-
-/* Digittrade DVB-T USB Stick */
-static struct ir_scancode ir_codes_af9015_table_digittrade[] = {
- { 0x010f, KEY_LAST }, /* RETURN */
- { 0x0517, KEY_TEXT }, /* TELETEXT */
- { 0x0108, KEY_EPG }, /* EPG */
- { 0x0513, KEY_POWER }, /* POWER */
- { 0x0109, KEY_ZOOM }, /* FULLSCREEN */
- { 0x0040, KEY_AUDIO }, /* DUAL SOUND */
- { 0x002c, KEY_PRINT }, /* SNAPSHOT */
- { 0x0516, KEY_SUBTITLE }, /* SUBTITLE */
- { 0x0052, KEY_CHANNELUP }, /* CH Up */
- { 0x0051, KEY_CHANNELDOWN },/* Ch Dn */
- { 0x0057, KEY_VOLUMEUP }, /* Vol Up */
- { 0x0056, KEY_VOLUMEDOWN }, /* Vol Dn */
- { 0x0110, KEY_MUTE }, /* MUTE */
- { 0x0027, KEY_0 },
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0117, KEY_PLAYPAUSE }, /* TIMESHIFT */
- { 0x0115, KEY_RECORD }, /* RECORD */
- { 0x0313, KEY_PLAY }, /* PLAY */
- { 0x0116, KEY_STOP }, /* STOP */
- { 0x0113, KEY_PAUSE }, /* PAUSE */
-};
-
-static u8 af9015_ir_table_digittrade[] = {
- 0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
- 0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
- 0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
- 0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
- 0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
- 0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
- 0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
- 0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
- 0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
- 0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
- 0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
- 0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
- 0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
- 0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
- 0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
- 0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
- 0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
- 0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
- 0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
- 0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
- 0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
- 0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
- 0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
- 0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
- 0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
- 0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
- 0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
-};
-
-/* TREKSTOR DVB-T USB Stick */
-static struct ir_scancode ir_codes_af9015_table_trekstor[] = {
- { 0x0704, KEY_AGAIN }, /* Home */
- { 0x0705, KEY_MUTE }, /* Mute */
- { 0x0706, KEY_UP }, /* Up */
- { 0x0707, KEY_DOWN }, /* Down */
- { 0x0709, KEY_RIGHT }, /* Right */
- { 0x070a, KEY_ENTER }, /* OK */
- { 0x070b, KEY_FASTFORWARD }, /* Fast forward */
- { 0x070c, KEY_REWIND }, /* Rewind */
- { 0x070d, KEY_PLAY }, /* Play/Pause */
- { 0x070e, KEY_VOLUMEUP }, /* Volume + */
- { 0x070f, KEY_VOLUMEDOWN }, /* Volume - */
- { 0x0710, KEY_RECORD }, /* Record */
- { 0x0711, KEY_STOP }, /* Stop */
- { 0x0712, KEY_ZOOM }, /* TV */
- { 0x0713, KEY_EPG }, /* Info/EPG */
- { 0x0714, KEY_CHANNELDOWN }, /* Channel - */
- { 0x0715, KEY_CHANNELUP }, /* Channel + */
- { 0x071e, KEY_1 },
- { 0x071f, KEY_2 },
- { 0x0720, KEY_3 },
- { 0x0721, KEY_4 },
- { 0x0722, KEY_5 },
- { 0x0723, KEY_6 },
- { 0x0724, KEY_7 },
- { 0x0725, KEY_8 },
- { 0x0726, KEY_9 },
- { 0x0708, KEY_LEFT }, /* LEFT */
- { 0x0727, KEY_0 },
-};
-
-static u8 af9015_ir_table_trekstor[] = {
- 0x00, 0xff, 0x86, 0x79, 0x04, 0x07, 0x00,
- 0x00, 0xff, 0x85, 0x7a, 0x05, 0x07, 0x00,
- 0x00, 0xff, 0x87, 0x78, 0x06, 0x07, 0x00,
- 0x00, 0xff, 0x8c, 0x73, 0x07, 0x07, 0x00,
- 0x00, 0xff, 0x89, 0x76, 0x09, 0x07, 0x00,
- 0x00, 0xff, 0x88, 0x77, 0x0a, 0x07, 0x00,
- 0x00, 0xff, 0x8a, 0x75, 0x0b, 0x07, 0x00,
- 0x00, 0xff, 0x9e, 0x61, 0x0c, 0x07, 0x00,
- 0x00, 0xff, 0x8d, 0x72, 0x0d, 0x07, 0x00,
- 0x00, 0xff, 0x8b, 0x74, 0x0e, 0x07, 0x00,
- 0x00, 0xff, 0x9b, 0x64, 0x0f, 0x07, 0x00,
- 0x00, 0xff, 0x9d, 0x62, 0x10, 0x07, 0x00,
- 0x00, 0xff, 0x8e, 0x71, 0x11, 0x07, 0x00,
- 0x00, 0xff, 0x9c, 0x63, 0x12, 0x07, 0x00,
- 0x00, 0xff, 0x8f, 0x70, 0x13, 0x07, 0x00,
- 0x00, 0xff, 0x93, 0x6c, 0x14, 0x07, 0x00,
- 0x00, 0xff, 0x97, 0x68, 0x15, 0x07, 0x00,
- 0x00, 0xff, 0x92, 0x6d, 0x1e, 0x07, 0x00,
- 0x00, 0xff, 0x96, 0x69, 0x1f, 0x07, 0x00,
- 0x00, 0xff, 0x9a, 0x65, 0x20, 0x07, 0x00,
- 0x00, 0xff, 0x91, 0x6e, 0x21, 0x07, 0x00,
- 0x00, 0xff, 0x95, 0x6a, 0x22, 0x07, 0x00,
- 0x00, 0xff, 0x99, 0x66, 0x23, 0x07, 0x00,
- 0x00, 0xff, 0x90, 0x6f, 0x24, 0x07, 0x00,
- 0x00, 0xff, 0x94, 0x6b, 0x25, 0x07, 0x00,
- 0x00, 0xff, 0x98, 0x67, 0x26, 0x07, 0x00,
- 0x00, 0xff, 0x9f, 0x60, 0x08, 0x07, 0x00,
- 0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
-};
-
-/* MSI DIGIVOX mini III */
-static struct ir_scancode ir_codes_af9015_table_msi_digivox_iii[] = {
- { 0x0713, KEY_POWER }, /* [red power button] */
- { 0x073b, KEY_VIDEO }, /* Source */
- { 0x073e, KEY_ZOOM }, /* Zoom */
- { 0x070b, KEY_POWER2 }, /* ShutDown */
- { 0x071e, KEY_1 },
- { 0x071f, KEY_2 },
- { 0x0720, KEY_3 },
- { 0x0721, KEY_4 },
- { 0x0722, KEY_5 },
- { 0x0723, KEY_6 },
- { 0x0724, KEY_7 },
- { 0x0725, KEY_8 },
- { 0x0726, KEY_9 },
- { 0x0727, KEY_0 },
- { 0x0752, KEY_CHANNELUP }, /* CH+ */
- { 0x0751, KEY_CHANNELDOWN }, /* CH- */
- { 0x0750, KEY_VOLUMEUP }, /* Vol+ */
- { 0x074f, KEY_VOLUMEDOWN }, /* Vol- */
- { 0x0705, KEY_ESC }, /* [back up arrow] */
- { 0x0708, KEY_OK }, /* [enter arrow] */
- { 0x073f, KEY_RECORD }, /* Rec */
- { 0x0716, KEY_STOP }, /* Stop */
- { 0x072a, KEY_PLAY }, /* Play */
- { 0x073c, KEY_MUTE }, /* Mute */
- { 0x0718, KEY_UP },
- { 0x0707, KEY_DOWN },
- { 0x070f, KEY_LEFT },
- { 0x0715, KEY_RIGHT },
- { 0x0736, KEY_RED },
- { 0x0737, KEY_GREEN },
- { 0x072d, KEY_YELLOW },
- { 0x072e, KEY_BLUE },
-};
-
-static u8 af9015_ir_table_msi_digivox_iii[] = {
- 0x61, 0xd6, 0x43, 0xbc, 0x13, 0x07, 0x00, /* KEY_POWER */
- 0x61, 0xd6, 0x01, 0xfe, 0x3b, 0x07, 0x00, /* KEY_VIDEO */
- 0x61, 0xd6, 0x0b, 0xf4, 0x3e, 0x07, 0x00, /* KEY_ZOOM */
- 0x61, 0xd6, 0x03, 0xfc, 0x0b, 0x07, 0x00, /* KEY_POWER2 */
- 0x61, 0xd6, 0x04, 0xfb, 0x1e, 0x07, 0x00, /* KEY_1 */
- 0x61, 0xd6, 0x08, 0xf7, 0x1f, 0x07, 0x00, /* KEY_2 */
- 0x61, 0xd6, 0x02, 0xfd, 0x20, 0x07, 0x00, /* KEY_3 */
- 0x61, 0xd6, 0x0f, 0xf0, 0x21, 0x07, 0x00, /* KEY_4 */
- 0x61, 0xd6, 0x05, 0xfa, 0x22, 0x07, 0x00, /* KEY_5 */
- 0x61, 0xd6, 0x06, 0xf9, 0x23, 0x07, 0x00, /* KEY_6 */
- 0x61, 0xd6, 0x0c, 0xf3, 0x24, 0x07, 0x00, /* KEY_7 */
- 0x61, 0xd6, 0x0d, 0xf2, 0x25, 0x07, 0x00, /* KEY_8 */
- 0x61, 0xd6, 0x0a, 0xf5, 0x26, 0x07, 0x00, /* KEY_9 */
- 0x61, 0xd6, 0x11, 0xee, 0x27, 0x07, 0x00, /* KEY_0 */
- 0x61, 0xd6, 0x09, 0xf6, 0x52, 0x07, 0x00, /* KEY_CHANNELUP */
- 0x61, 0xd6, 0x07, 0xf8, 0x51, 0x07, 0x00, /* KEY_CHANNELDOWN */
- 0x61, 0xd6, 0x0e, 0xf1, 0x50, 0x07, 0x00, /* KEY_VOLUMEUP */
- 0x61, 0xd6, 0x13, 0xec, 0x4f, 0x07, 0x00, /* KEY_VOLUMEDOWN */
- 0x61, 0xd6, 0x10, 0xef, 0x05, 0x07, 0x00, /* KEY_ESC */
- 0x61, 0xd6, 0x12, 0xed, 0x08, 0x07, 0x00, /* KEY_OK */
- 0x61, 0xd6, 0x14, 0xeb, 0x3f, 0x07, 0x00, /* KEY_RECORD */
- 0x61, 0xd6, 0x15, 0xea, 0x16, 0x07, 0x00, /* KEY_STOP */
- 0x61, 0xd6, 0x16, 0xe9, 0x2a, 0x07, 0x00, /* KEY_PLAY */
- 0x61, 0xd6, 0x17, 0xe8, 0x3c, 0x07, 0x00, /* KEY_MUTE */
- 0x61, 0xd6, 0x18, 0xe7, 0x18, 0x07, 0x00, /* KEY_UP */
- 0x61, 0xd6, 0x19, 0xe6, 0x07, 0x07, 0x00, /* KEY_DOWN */
- 0x61, 0xd6, 0x1a, 0xe5, 0x0f, 0x07, 0x00, /* KEY_LEFT */
- 0x61, 0xd6, 0x1b, 0xe4, 0x15, 0x07, 0x00, /* KEY_RIGHT */
- 0x61, 0xd6, 0x1c, 0xe3, 0x36, 0x07, 0x00, /* KEY_RED */
- 0x61, 0xd6, 0x1d, 0xe2, 0x37, 0x07, 0x00, /* KEY_GREEN */
- 0x61, 0xd6, 0x1e, 0xe1, 0x2d, 0x07, 0x00, /* KEY_YELLOW */
- 0x61, 0xd6, 0x1f, 0xe0, 0x2e, 0x07, 0x00, /* KEY_BLUE */
-};
-
#endif
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index 4685259e1614..1759d26bca42 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -354,7 +354,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap->dev->priv;
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
switch (state->tuner) {
case DVB_PLL_THOMSON_DTT7579:
@@ -374,78 +374,32 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int anysee_rc_query(struct dvb_usb_device *d)
{
u8 buf[] = {CMD_GET_IR_CODE};
- struct ir_scancode *keymap = d->props.rc.legacy.rc_key_map;
u8 ircode[2];
- int i, ret;
+ int ret;
- ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
+ /* Remote controller is basic NEC using address byte 0x08.
+ Anysee device RC query returns only two bytes, status and code,
+ address byte is dropped. Also it does not return any value for
+ NEC RCs having address byte other than 0x08. Due to that, we
+ cannot use that device as standard NEC receiver.
+ It could be possible make hack which reads whole code directly
+ from device memory... */
+
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
if (ret)
return ret;
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
-
- for (i = 0; i < d->props.rc.legacy.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == ircode[0] &&
- rc5_data(&keymap[i]) == ircode[1]) {
- *event = keymap[i].keycode;
- *state = REMOTE_KEY_PRESSED;
- return 0;
- }
+ if (ircode[0]) {
+ deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
+ ir_keydown(d->rc_input_dev, 0x08 << 8 | ircode[1], 0);
}
+
return 0;
}
-static struct ir_scancode ir_codes_anysee_table[] = {
- { 0x0100, KEY_0 },
- { 0x0101, KEY_1 },
- { 0x0102, KEY_2 },
- { 0x0103, KEY_3 },
- { 0x0104, KEY_4 },
- { 0x0105, KEY_5 },
- { 0x0106, KEY_6 },
- { 0x0107, KEY_7 },
- { 0x0108, KEY_8 },
- { 0x0109, KEY_9 },
- { 0x010a, KEY_POWER },
- { 0x010b, KEY_DOCUMENTS }, /* * */
- { 0x0119, KEY_FAVORITES },
- { 0x0120, KEY_SLEEP },
- { 0x0121, KEY_MODE }, /* 4:3 / 16:9 select */
- { 0x0122, KEY_ZOOM },
- { 0x0147, KEY_TEXT },
- { 0x0116, KEY_TV }, /* TV / radio select */
- { 0x011e, KEY_LANGUAGE }, /* Second Audio Program */
- { 0x011a, KEY_SUBTITLE },
- { 0x011b, KEY_CAMERA }, /* screenshot */
- { 0x0142, KEY_MUTE },
- { 0x010e, KEY_MENU },
- { 0x010f, KEY_EPG },
- { 0x0117, KEY_INFO },
- { 0x0110, KEY_EXIT },
- { 0x0113, KEY_VOLUMEUP },
- { 0x0112, KEY_VOLUMEDOWN },
- { 0x0111, KEY_CHANNELUP },
- { 0x0114, KEY_CHANNELDOWN },
- { 0x0115, KEY_OK },
- { 0x011d, KEY_RED },
- { 0x011f, KEY_GREEN },
- { 0x011c, KEY_YELLOW },
- { 0x0144, KEY_BLUE },
- { 0x010c, KEY_SHUFFLE }, /* snapshot */
- { 0x0148, KEY_STOP },
- { 0x0150, KEY_PLAY },
- { 0x0151, KEY_PAUSE },
- { 0x0149, KEY_RECORD },
- { 0x0118, KEY_PREVIOUS }, /* |<< */
- { 0x010d, KEY_NEXT }, /* >>| */
- { 0x0124, KEY_PROG1 }, /* F1 */
- { 0x0125, KEY_PROG2 }, /* F2 */
-};
-
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties anysee_properties;
@@ -520,11 +474,12 @@ static struct dvb_usb_device_properties anysee_properties = {
}
},
- .rc.legacy = {
- .rc_key_map = ir_codes_anysee_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_anysee_table),
+ .rc.core = {
+ .rc_codes = RC_MAP_ANYSEE,
+ .protocol = IR_TYPE_OTHER,
+ .module_name = "anysee",
.rc_query = anysee_rc_query,
- .rc_interval = 200, /* windows driver uses 500ms */
+ .rc_interval = 250, /* windows driver uses 500ms */
},
.i2c_algo = &anysee_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index cead089bbb4f..88e4a62abc44 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -20,7 +20,6 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
}
strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
- d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
d->i2c_adap.dev.parent = &d->udev->dev;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 1a774d58d664..192a40ce583d 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -32,6 +32,7 @@
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GENPIX 0x09c0
#define USB_VID_GRANDTEC 0x5032
+#define USB_VID_GTEK 0x1f4d
#define USB_VID_HANFTEK 0x15f4
#define USB_VID_HAUPPAUGE 0x2040
#define USB_VID_HYPER_PALTEK 0x1025
@@ -133,6 +134,8 @@
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
+#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
@@ -143,6 +146,7 @@
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
#define USB_PID_TINYTWIN 0x3226
#define USB_PID_TINYTWIN_2 0xe402
+#define USB_PID_TINYTWIN_3 0x9016
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
@@ -196,6 +200,7 @@
#define USB_PID_AVERMEDIA_A309 0xa309
#define USB_PID_AVERMEDIA_A310 0xa310
#define USB_PID_AVERMEDIA_A850 0x850a
+#define USB_PID_AVERMEDIA_A850T 0x850b
#define USB_PID_AVERMEDIA_A805 0xa805
#define USB_PID_AVERMEDIA_A815M 0x815a
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
@@ -268,6 +273,7 @@
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
#define USB_PID_GENPIX_SKYWALKER_1 0x0203
#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
+#define USB_PID_GENPIX_SKYWALKER_2 0x0206
#define USB_PID_SIGMATEK_DVB_110 0x6610
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
#define USB_PID_MSI_DIGIVOX_DUO 0x8801
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
index 93c21ddd0b77..015b4e8af1a5 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -75,7 +75,7 @@ static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
return 0;
}
-static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct jdvbt90502_state *state = fe->demodulator_priv;
int err, i;
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index dbdb5347b2a8..60d11e57e7d0 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -109,7 +109,7 @@ static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
- tune->min_delay_ms = 200;
+ tune->min_delay_ms = 800;
return 0;
}
@@ -334,7 +334,7 @@ success:
static struct dvb_frontend_ops gp8psk_fe_ops = {
.info = {
- .name = "Genpix 8psk-to-USB2 DVB-S",
+ .name = "Genpix DVB-S",
.type = FE_QPSK,
.frequency_min = 800000,
.frequency_max = 2250000,
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 45106ac49674..c821293dbc22 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -227,6 +227,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
{ 0 },
};
@@ -258,7 +259,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .num_device_descs = 3,
+ .num_device_descs = 4,
.devices = {
{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -272,6 +273,10 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[3], NULL },
},
+ { .name = "Genpix SkyWalker-2 DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[4], NULL },
+ },
{ NULL },
}
};
@@ -306,6 +311,6 @@ module_init(gp8psk_usb_module_init);
module_exit(gp8psk_usb_module_exit);
MODULE_AUTHOR("Alan Nisota ");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_DESCRIPTION("Driver for Genpix DVB-S");
MODULE_VERSION("1.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
new file mode 100644
index 000000000000..d939fbbf9fe6
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -0,0 +1,1088 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
+ * LME2510C + LG TDQY-P001F
+ * LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MV001F (LME2510+LGTDQY-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * For firmware see Documentation/dvb/lmedm04.txt
+ *
+ * I2C addresses:
+ * 0xd0 - STV0288 - Demodulator
+ * 0xc0 - Sharp IX2505V - Tuner
+ * --or--
+ * 0x1c - TDA10086 - Demodulator
+ * 0xc0 - TDA8263 - Tuner
+ *
+ * ***Please Note***
+ * There are other variants of the DM04
+ * ***NOT SUPPORTED***
+ * MV0194 (LME2510+SHARP0194)
+ * MVB0194 (LME2510C+SHARP0194)
+ *
+ *
+ * VID = 3344 PID LME2510=1122 LME2510C=1120
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ * Known Issues :
+ * LME2510: Non Intel USB chipsets fail to maintain High Speed on
+ * Boot or Hot Plug.
+ *
+ * QQbox suffers from noise on LNB voltage.
+ *
+ * PID functions have been removed from this driver version due to
+ * problems with different firmware and application versions.
+ */
+#define DVB_USB_LOG_PREFIX "LME2510(C)"
+#include
+#include
+#include
+
+#include "dvb-usb.h"
+#include "lmedm04.h"
+#include "tda826x.h"
+#include "tda10086.h"
+#include "stv0288.h"
+#include "ix2505v.h"
+
+
+
+/* debug */
+static int dvb_usb_lme2510_debug;
+#define l_dprintk(var, level, args...) do { \
+ if ((var >= level)) \
+ printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
+} while (0)
+
+#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
+#define debug_data_snipet(level, name, p) \
+ deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+ *p, *(p+1), *(p+2), *(p+3), *(p+4), \
+ *(p+5), *(p+6), *(p+7));
+
+
+module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
+ DVB_USB_DEBUG_STATUS);
+
+static int dvb_usb_lme2510_firmware;
+module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+#define TUNER_LG 0x1
+#define TUNER_S7395 0x2
+
+struct lme2510_state {
+ u8 id;
+ u8 tuner_config;
+ u8 signal_lock;
+ u8 signal_level;
+ u8 signal_sn;
+ u8 time_key;
+ u8 i2c_talk_onoff;
+ u8 i2c_gate;
+ u8 i2c_tuner_gate_w;
+ u8 i2c_tuner_gate_r;
+ u8 i2c_tuner_addr;
+ u8 stream_on;
+ u8 one_tune;
+ void *buffer;
+ struct urb *lme_urb;
+ void *usb_buffer;
+
+};
+
+static int lme2510_bulk_write(struct usb_device *dev,
+ u8 *snd, int len, u8 pipe)
+{
+ int ret, actual_l;
+
+ ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+ snd, len , &actual_l, 500);
+ return ret;
+}
+
+static int lme2510_bulk_read(struct usb_device *dev,
+ u8 *rev, int len, u8 pipe)
+{
+ int ret, actual_l;
+
+ ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+ rev, len , &actual_l, 500);
+ return ret;
+}
+
+static int lme2510_usb_talk(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct lme2510_state *st = d->priv;
+ u8 *buff;
+ int ret = 0;
+
+ if (st->usb_buffer == NULL) {
+ st->usb_buffer = kmalloc(512, GFP_KERNEL);
+ if (st->usb_buffer == NULL) {
+ info("MEM Error no memory");
+ return -ENOMEM;
+ }
+ }
+ buff = st->usb_buffer;
+
+ /* the read/write capped at 512 */
+ memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
+
+ ret = mutex_lock_interruptible(&d->usb_mutex);
+
+ if (ret < 0)
+ return -EAGAIN;
+
+ ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
+
+ ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
+
+ msleep(12);
+
+ ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
+
+ ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ?
+ 512 : rlen , 0x01);
+
+ if (rlen > 0)
+ memcpy(rbuf, buff, rlen);
+
+ mutex_unlock(&d->usb_mutex);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_usb_talk_restart(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen) {
+ static u8 stream_on[] = LME_ST_ON_W;
+ int ret;
+ u8 rbuff[10];
+ /*Send Normal Command*/
+ ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ /*Restart Stream Command*/
+ ret |= lme2510_usb_talk(d, stream_on, sizeof(stream_on),
+ rbuff, sizeof(rbuff));
+ return ret;
+}
+static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress)
+{
+ struct dvb_usb_device *d = adap->dev;
+
+ deb_info(1, "INT Key Keypress =%04x", keypress);
+
+ if (keypress > 0)
+ ir_keydown(d->rc_input_dev, keypress, 0);
+
+ return 0;
+}
+
+static void lme2510_int_response(struct urb *lme_urb)
+{
+ struct dvb_usb_adapter *adap = lme_urb->context;
+ struct lme2510_state *st = adap->dev->priv;
+ static u8 *ibuf, *rbuf;
+ int i = 0, offset;
+
+ switch (lme_urb->status) {
+ case 0:
+ case -ETIMEDOUT:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ info("Error %x", lme_urb->status);
+ break;
+ }
+
+ rbuf = (u8 *) lme_urb->transfer_buffer;
+
+ offset = ((lme_urb->actual_length/8) > 4)
+ ? 4 : (lme_urb->actual_length/8) ;
+
+ for (i = 0; i < offset; ++i) {
+ ibuf = (u8 *)&rbuf[i*8];
+ deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
+ offset, i, ibuf[0], ibuf[1]);
+
+ switch (ibuf[0]) {
+ case 0xaa:
+ debug_data_snipet(1, "INT Remote data snipet in", ibuf);
+ lme2510_remote_keypress(adap,
+ (u16)(ibuf[4]<<8)+ibuf[5]);
+ break;
+ case 0xbb:
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (ibuf[2] > 0)
+ st->signal_lock = ibuf[2];
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[3];
+ st->time_key = ibuf[7];
+ break;
+ case TUNER_S7395:
+ /* Tweak for earlier firmware*/
+ if (ibuf[1] == 0x03) {
+ st->signal_level = ibuf[3];
+ st->signal_sn = ibuf[4];
+ } else {
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[5];
+ }
+ break;
+ default:
+ break;
+ }
+ debug_data_snipet(5, "INT Remote data snipet in", ibuf);
+ break;
+ case 0xcc:
+ debug_data_snipet(1, "INT Control data snipet", ibuf);
+ break;
+ default:
+ debug_data_snipet(1, "INT Unknown data snipet", ibuf);
+ break;
+ }
+ }
+ usb_submit_urb(lme_urb, GFP_ATOMIC);
+}
+
+static int lme2510_int_read(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *lme_int = adap->dev->priv;
+
+ lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (lme_int->lme_urb == NULL)
+ return -ENOMEM;
+
+ lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC,
+ &lme_int->lme_urb->transfer_dma);
+
+ if (lme_int->buffer == NULL)
+ return -ENOMEM;
+
+ usb_fill_int_urb(lme_int->lme_urb,
+ adap->dev->udev,
+ usb_rcvintpipe(adap->dev->udev, 0xa),
+ lme_int->buffer,
+ 4096,
+ lme2510_int_response,
+ adap,
+ 11);
+
+ lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
+ info("INT Interupt Service Started");
+
+ return 0;
+}
+
+static int lme2510_return_status(struct usb_device *dev)
+{
+ int ret = 0;
+ u8 data[10] = {0};
+
+ ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
+ info("Firmware Status: %x (%x)", ret , data[2]);
+
+ return (ret < 0) ? -ENODEV : data[2];
+}
+
+static int lme2510_msg(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int ret = 0;
+ struct lme2510_state *st = d->priv;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (st->i2c_talk_onoff == 1) {
+
+ ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (wbuf[2] == 0x1c) {
+ if (wbuf[3] == 0x0e) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x10)) {
+ lme2510_usb_talk_restart(d,
+ wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 0;
+ }
+ msleep(80);
+ }
+ }
+ break;
+ case TUNER_S7395:
+ if (wbuf[2] == 0xd0) {
+ if (wbuf[3] == 0x24) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x8)) {
+ lme2510_usb_talk_restart(d,
+ wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 0;
+ }
+ }
+ if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
+ msleep(5);
+
+
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ switch (wbuf[3]) {
+ case 0x0e:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_lock;
+ break;
+ case 0x43:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_level;
+ break;
+ case 0x1c:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ /*DiSEqC functions as per TDA10086*/
+ case 0x36:
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ if (wbuf[2] == 0x1c)
+ lme2510_usb_talk_restart(d,
+ wbuf, wlen, rbuf, rlen);
+ default:
+ break;
+ }
+ break;
+ case TUNER_S7395:
+ switch (wbuf[3]) {
+ case 0x10:
+ rbuf[0] = 0x55;
+ rbuf[1] = (st->signal_level & 0x80)
+ ? 0 : (st->signal_level * 2);
+ break;
+ case 0x2d:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ case 0x24:
+ rbuf[0] = 0x55;
+ rbuf[1] = (st->signal_level & 0x80)
+ ? 0 : st->signal_lock;
+ break;
+ case 0x6:
+ if (wbuf[2] == 0xd0)
+ lme2510_usb_talk(d,
+ wbuf, wlen, rbuf, rlen);
+ break;
+ case 0x1:
+ if (st->one_tune > 0)
+ break;
+ st->one_tune++;
+ st->i2c_talk_onoff = 1;
+ /*DiSEqC functions as per STV0288*/
+ case 0x5:
+ case 0x7:
+ case 0x8:
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ if (wbuf[2] == 0xd0)
+ lme2510_usb_talk_restart(d,
+ wbuf, wlen, rbuf, rlen);
+ break;
+ default:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
+ }
+ break;
+ default:
+ break;
+
+ }
+
+ deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)",
+ wbuf[3], rbuf[1]);
+
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+
+static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct lme2510_state *st = d->priv;
+ static u8 obuf[64], ibuf[512];
+ int i, read, read_o;
+ u16 len;
+ u8 gate = st->i2c_gate;
+
+ if (gate == 0)
+ gate = 5;
+
+ if (num > 2)
+ warn("more than 2 i2c messages"
+ "at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+ read_o = 1 & (msg[i].flags & I2C_M_RD);
+ read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+ read |= read_o;
+ gate = (msg[i].addr == st->i2c_tuner_addr)
+ ? (read) ? st->i2c_tuner_gate_r
+ : st->i2c_tuner_gate_w
+ : st->i2c_gate;
+ obuf[0] = gate | (read << 7);
+
+ if (gate == 5)
+ obuf[1] = (read) ? 2 : msg[i].len + 1;
+ else
+ obuf[1] = msg[i].len + read + 1;
+
+ obuf[2] = msg[i].addr;
+ if (read) {
+ if (read_o)
+ len = 3;
+ else {
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
+ obuf[msg[i].len+3] = msg[i+1].len;
+ len = msg[i].len+4;
+ }
+ } else {
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
+ len = msg[i].len+3;
+ }
+
+ if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) {
+ deb_info(1, "i2c transfer failed.");
+ return -EAGAIN;
+ }
+
+ if (read) {
+ if (read_o)
+ memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+ else {
+ memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+ i++;
+ }
+ }
+ }
+ return i;
+}
+
+static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm lme2510_i2c_algo = {
+ .master_xfer = lme2510_i2c_xfer,
+ .functionality = lme2510_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int lme2510_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ if (lme2510_return_status(udev) == 0x44)
+ *cold = 1;
+ else
+ *cold = 0;
+ return 0;
+}
+
+static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ static u8 stream_on[] = LME_ST_ON_W;
+ static u8 clear_reg_3[] = LME_CLEAR_PID;
+ static u8 rbuf[1];
+ static u8 timeout;
+ int ret = 0, len = 2, rlen = sizeof(rbuf);
+
+ deb_info(1, "STM (%02x)", onoff);
+
+ if (onoff == 1) {
+ st->i2c_talk_onoff = 0;
+ timeout = 0;
+ /* wait for i2C to be free */
+ while (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0) {
+ timeout++;
+ if (timeout > 5)
+ return -ENODEV;
+ }
+ msleep(100);
+ ret |= lme2510_usb_talk(adap->dev,
+ stream_on, len, rbuf, rlen);
+ st->stream_on = 1;
+ st->one_tune = 0;
+ mutex_unlock(&adap->dev->i2c_mutex);
+ } else {
+ deb_info(1, "STM Steam Off");
+ ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
+ sizeof(clear_reg_3), rbuf, rlen);
+ st->stream_on = 0;
+ st->i2c_talk_onoff = 1;
+ }
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_int_service(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct input_dev *input_dev;
+ char *ir_codes = RC_MAP_LME2510;
+ int ret = 0;
+
+ info("STA Configuring Remote");
+
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+ input_dev = input_allocate_device();
+ if (!input_dev)
+ return -ENOMEM;
+
+ input_dev->name = "LME2510 Remote Control";
+ input_dev->phys = d->rc_phys;
+
+ usb_to_input_id(d->udev, &input_dev->id);
+
+ ret |= ir_input_register(input_dev, ir_codes, NULL, "LME 2510");
+
+ if (ret) {
+ input_free_device(input_dev);
+ return ret;
+ }
+
+ d->rc_input_dev = input_dev;
+ /* Start the Interupt */
+ ret = lme2510_int_read(adap);
+
+ if (ret < 0) {
+ ir_input_unregister(input_dev);
+ input_free_device(input_dev);
+ }
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static u8 check_sum(u8 *p, u8 len)
+{
+ u8 sum = 0;
+ while (len--)
+ sum += *p++;
+ return sum;
+}
+
+static int lme2510_download_firmware(struct usb_device *dev,
+ const struct firmware *fw)
+{
+ int ret = 0;
+ u8 data[512] = {0};
+ u16 j, wlen, len_in, start, end;
+ u8 packet_size, dlen, i;
+ u8 *fw_data;
+
+ packet_size = 0x31;
+ len_in = 1;
+
+
+ info("FRM Starting Firmware Download");
+
+ for (i = 1; i < 3; i++) {
+ start = (i == 1) ? 0 : 512;
+ end = (i == 1) ? 512 : fw->size;
+ for (j = start; j < end; j += (packet_size+1)) {
+ fw_data = (u8 *)(fw->data + j);
+ if ((end - j) > packet_size) {
+ data[0] = i;
+ dlen = packet_size;
+ } else {
+ data[0] = i | 0x80;
+ dlen = (u8)(end - j)-1;
+ }
+ data[1] = dlen;
+ memcpy(&data[2], fw_data, dlen+1);
+ wlen = (u8) dlen + 4;
+ data[wlen-1] = check_sum(fw_data, dlen+1);
+ deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+ data[dlen+2], data[dlen+3]);
+ ret |= lme2510_bulk_write(dev, data, wlen, 1);
+ ret |= lme2510_bulk_read(dev, data, len_in , 1);
+ ret |= (data[0] == 0x88) ? 0 : -1;
+ }
+ }
+ usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
+
+
+ data[0] = 0x8a;
+ len_in = 1;
+ msleep(2000);
+ ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
+ ret |= lme2510_bulk_read(dev, data, len_in, 1);
+ msleep(400);
+
+ if (ret < 0)
+ info("FRM Firmware Download Failed (%04x)" , ret);
+ else
+ info("FRM Firmware Download Completed - Resetting Device");
+
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Default firmware for LME2510C */
+const char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw";
+
+static void lme_coldreset(struct usb_device *dev)
+{
+ int ret = 0, len_in;
+ u8 data[512] = {0};
+
+ data[0] = 0x0a;
+ len_in = 1;
+ info("FRM Firmware Cold Reset");
+ ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
+ ret |= lme2510_bulk_read(dev, data, len_in, 1);
+ return;
+}
+
+static void lme_firmware_switch(struct usb_device *udev, int cold)
+{
+ const struct firmware *fw = NULL;
+ char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
+ char lme2510c_lg[] = "dvb-usb-lme2510c-lg.fw";
+ char *firm_msg[] = {"Loading", "Switching to"};
+ int ret;
+
+ if (udev->descriptor.idProduct == 0x1122)
+ return;
+
+ switch (dvb_usb_lme2510_firmware) {
+ case 0:
+ default:
+ memcpy(&lme_firmware, lme2510c_s7395, sizeof(lme2510c_s7395));
+ ret = request_firmware(&fw, lme_firmware, &udev->dev);
+ if (ret == 0) {
+ info("FRM %s S7395 Firmware", firm_msg[cold]);
+ break;
+ }
+ if (cold == 0)
+ dvb_usb_lme2510_firmware = 1;
+ else
+ cold = 0;
+ case 1:
+ memcpy(&lme_firmware, lme2510c_lg, sizeof(lme2510c_lg));
+ ret = request_firmware(&fw, lme_firmware, &udev->dev);
+ if (ret == 0) {
+ info("FRM %s LG Firmware", firm_msg[cold]);
+ break;
+ }
+ info("FRM No Firmware Found - please install");
+ dvb_usb_lme2510_firmware = 0;
+ cold = 0;
+ break;
+ }
+ release_firmware(fw);
+ if (cold)
+ lme_coldreset(udev);
+ return;
+}
+
+static int lme2510_kill_urb(struct usb_data_stream *stream)
+{
+ int i;
+ for (i = 0; i < stream->urbs_submitted; i++) {
+ deb_info(3, "killing URB no. %d.", i);
+
+ /* stop the URB */
+ usb_kill_urb(stream->urb_list[i]);
+ }
+ stream->urbs_submitted = 0;
+ return 0;
+}
+
+static struct tda10086_config tda10086_config = {
+ .demod_address = 0x1c,
+ .invert = 0,
+ .diseqc_tone = 1,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0288_config lme_config = {
+ .demod_address = 0xd0,
+ .min_delay_ms = 15,
+ .inittab = s7395_inittab,
+};
+
+static struct ix2505v_config lme_tuner = {
+ .tuner_address = 0xc0,
+ .min_delay_ms = 100,
+ .tuner_gain = 0x0,
+ .tuner_chargepump = 0x3,
+};
+
+static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct lme2510_state *st = adap->dev->priv;
+ static u8 voltage_low[] = LME_VOLTAGE_L;
+ static u8 voltage_high[] = LME_VOLTAGE_H;
+ static u8 lnb_on[] = LNB_ON;
+ static u8 lnb_off[] = LNB_OFF;
+ static u8 rbuf[1];
+ int ret = 0, len = 3, rlen = 1;
+
+ if (st->stream_on == 1)
+ return 0;
+
+ ret |= lme2510_usb_talk(adap->dev, lnb_on, len, rbuf, rlen);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_18:
+ ret |= lme2510_usb_talk(adap->dev,
+ voltage_high, len, rbuf, rlen);
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ ret |= lme2510_usb_talk(adap->dev,
+ lnb_off, len, rbuf, rlen);
+ case SEC_VOLTAGE_13:
+ default:
+ ret |= lme2510_usb_talk(adap->dev,
+ voltage_low, len, rbuf, rlen);
+ break;
+
+
+ };
+ st->i2c_talk_onoff = 1;
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ int ret = 0;
+ struct lme2510_state *st = adap->dev->priv;
+
+ /* Interupt Start */
+ ret = lme2510_int_service(adap);
+ if (ret < 0) {
+ info("INT Unable to start Interupt Service");
+ return -ENODEV;
+ }
+
+ st->i2c_talk_onoff = 1;
+ st->i2c_gate = 4;
+
+ adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
+ &adap->dev->i2c_adap);
+
+ if (adap->fe) {
+ info("TUN Found Frontend TDA10086");
+ memcpy(&adap->fe->ops.info.name,
+ &"DM04_LG_TDQY-P001F DVB-S", 24);
+ adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 4;
+ st->i2c_tuner_addr = 0xc0;
+ if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
+ &adap->dev->i2c_adap, 1)) {
+ info("TUN TDA8263 Found");
+ st->tuner_config = TUNER_LG;
+ if (dvb_usb_lme2510_firmware != 1) {
+ dvb_usb_lme2510_firmware = 1;
+ lme_firmware_switch(adap->dev->udev, 1);
+ }
+ return 0;
+ }
+ kfree(adap->fe);
+ adap->fe = NULL;
+ }
+ st->i2c_gate = 5;
+ adap->fe = dvb_attach(stv0288_attach, &lme_config,
+ &adap->dev->i2c_adap);
+
+ if (adap->fe) {
+ info("FE Found Stv0288");
+ memcpy(&adap->fe->ops.info.name,
+ &"DM04_SHARP:BS2F7HZ7395", 22);
+ adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 5;
+ st->i2c_tuner_addr = 0xc0;
+ if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
+ &adap->dev->i2c_adap)) {
+ st->tuner_config = TUNER_S7395;
+ info("TUN Sharp IX2505V silicon tuner");
+ if (dvb_usb_lme2510_firmware != 0) {
+ dvb_usb_lme2510_firmware = 0;
+ lme_firmware_switch(adap->dev->udev, 1);
+ }
+ return 0;
+ }
+ kfree(adap->fe);
+ adap->fe = NULL;
+ }
+
+ info("DM04 Not Supported");
+ return -ENODEV;
+}
+
+static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
+{
+ struct lme2510_state *st = d->priv;
+ st->i2c_talk_onoff = 1;
+ return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties lme2510_properties;
+static struct dvb_usb_device_properties lme2510c_properties;
+
+static int lme2510_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int ret = 0;
+
+ usb_reset_configuration(udev);
+
+ usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
+
+ if (udev->speed != USB_SPEED_HIGH) {
+ ret = usb_reset_device(udev);
+ info("DEV Failed to connect in HIGH SPEED mode");
+ return -ENODEV;
+ }
+
+ lme_firmware_switch(udev, 0);
+
+ if (0 == dvb_usb_device_init(intf, &lme2510_properties,
+ THIS_MODULE, NULL, adapter_nr)) {
+ info("DEV registering device driver");
+ return 0;
+ }
+ if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
+ THIS_MODULE, NULL, adapter_nr)) {
+ info("DEV registering device driver");
+ return 0;
+ }
+
+ info("DEV lme2510 Error");
+ return -ENODEV;
+
+}
+
+static struct usb_device_id lme2510_table[] = {
+ { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */
+ { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, lme2510_table);
+
+static struct dvb_usb_device_properties lme2510_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = lme2510_download_firmware,
+ .firmware = "dvb-usb-lme2510-lg.fw",
+
+ .size_of_priv = sizeof(struct lme2510_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = lme2510_streaming_ctrl,
+ .frontend_attach = dm04_lme2510_frontend_attach,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+
+ }
+ }
+ }
+ }
+ },
+ .power_ctrl = lme2510_powerup,
+ .identify_state = lme2510_identify_state,
+ .i2c_algo = &lme2510_i2c_algo,
+ .generic_bulk_ctrl_endpoint = 0,
+ .num_device_descs = 1,
+ .devices = {
+ { "DM04 LME2510 DVB-S USB 2.0",
+ { &lme2510_table[0], NULL },
+ },
+
+ }
+};
+
+static struct dvb_usb_device_properties lme2510c_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = lme2510_download_firmware,
+ .firmware = lme_firmware,
+ .size_of_priv = sizeof(struct lme2510_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = lme2510_streaming_ctrl,
+ .frontend_attach = dm04_lme2510_frontend_attach,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x8,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+
+ }
+ }
+ }
+ }
+ },
+ .power_ctrl = lme2510_powerup,
+ .identify_state = lme2510_identify_state,
+ .i2c_algo = &lme2510_i2c_algo,
+ .generic_bulk_ctrl_endpoint = 0,
+ .num_device_descs = 1,
+ .devices = {
+ { "DM04 LME2510C USB2.0",
+ { &lme2510_table[1], NULL },
+ },
+ }
+};
+
+void *lme2510_exit_int(struct dvb_usb_device *d)
+{
+ struct lme2510_state *st = d->priv;
+ struct dvb_usb_adapter *adap = &d->adapter[0];
+ void *buffer = NULL;
+
+ if (adap != NULL) {
+ lme2510_kill_urb(&adap->stream);
+ adap->feedcount = 0;
+ }
+
+ if (st->lme_urb != NULL) {
+ st->i2c_talk_onoff = 1;
+ st->signal_lock = 0;
+ st->signal_level = 0;
+ st->signal_sn = 0;
+ buffer = st->usb_buffer;
+ usb_kill_urb(st->lme_urb);
+ usb_free_coherent(d->udev, 5000, st->buffer,
+ st->lme_urb->transfer_dma);
+ info("Interupt Service Stopped");
+ ir_input_unregister(d->rc_input_dev);
+ info("Remote Stopped");
+ }
+ return buffer;
+}
+
+void lme2510_exit(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ void *usb_buffer;
+
+ if (d != NULL) {
+ usb_buffer = lme2510_exit_int(d);
+ dvb_usb_device_exit(intf);
+ kfree(usb_buffer);
+ }
+}
+
+static struct usb_driver lme2510_driver = {
+ .name = "LME2510C_DVBS",
+ .probe = lme2510_probe,
+ .disconnect = lme2510_exit,
+ .id_table = lme2510_table,
+};
+
+/* module stuff */
+static int __init lme2510_module_init(void)
+{
+ int result = usb_register(&lme2510_driver);
+ if (result) {
+ err("usb_register failed. Error number %d", result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit lme2510_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&lme2510_driver);
+}
+
+module_init(lme2510_module_init);
+module_exit(lme2510_module_exit);
+
+MODULE_AUTHOR("Malcolm Priestley ");
+MODULE_DESCRIPTION("LM2510(C) DVB-S USB2.0");
+MODULE_VERSION("1.60");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
new file mode 100644
index 000000000000..e6af16c1e3e5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/lmedm04.h
@@ -0,0 +1,173 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
+ * LME2510C + LG TDQY-P001F
+ * LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MVB001F (LME2510+LGTDQT-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * 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.
+ * *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_LME2510_H_
+#define _DVB_USB_LME2510_H_
+
+/* Streamer & PID
+ *
+ * Note: These commands do not actually stop the streaming
+ * but form some kind of packet filtering/stream count
+ * or tuning related functions.
+ * 06 XX
+ * offset 1 = 00 Enable Streaming
+ *
+ *
+ * PID
+ * 03 XX XX ----> reg number ---> setting....20 XX
+ * offset 1 = length
+ * offset 2 = start of data
+ * end byte -1 = 20
+ * end byte = clear pid always a0, other wise 9c, 9a ??
+ *
+*/
+#define LME_ST_ON_W {0x06, 0x00}
+#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
+
+/* LNB Voltage
+ * 07 XX XX
+ * offset 1 = 01
+ * offset 2 = 00=Voltage low 01=Voltage high
+ *
+ * LNB Power
+ * 03 01 XX
+ * offset 2 = 00=ON 01=OFF
+ */
+
+#define LME_VOLTAGE_L {0x07, 0x01, 0x00}
+#define LME_VOLTAGE_H {0x07, 0x01, 0x01}
+#define LNB_ON {0x3a, 0x01, 0x00}
+#define LNB_OFF {0x3a, 0x01, 0x01}
+
+/* Initial stv0288 settings for 7395 Frontend */
+static u8 s7395_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x20,
+ 0x03, 0xa0,
+ 0x04, 0xa0,
+ 0x05, 0x12,
+ 0x06, 0x00,
+ 0x09, 0x00,
+ 0x0a, 0x04,
+ 0x0b, 0x00,
+ 0x0c, 0x00,
+ 0x0d, 0x00,
+ 0x0e, 0xc1,
+ 0x0f, 0x54,
+ 0x11, 0x7a,
+ 0x12, 0x03,
+ 0x13, 0x48,
+ 0x14, 0x84,
+ 0x15, 0xc5,
+ 0x16, 0xb8,
+ 0x17, 0x9c,
+ 0x18, 0x00,
+ 0x19, 0xa6,
+ 0x1a, 0x88,
+ 0x1b, 0x8f,
+ 0x1c, 0xf0,
+ 0x20, 0x0b,
+ 0x21, 0x54,
+ 0x22, 0xff,
+ 0x23, 0x01,
+ 0x28, 0x46,
+ 0x29, 0x66,
+ 0x2a, 0x90,
+ 0x2b, 0xfa,
+ 0x2c, 0xd9,
+ 0x30, 0x0,
+ 0x31, 0x1e,
+ 0x32, 0x14,
+ 0x33, 0x0f,
+ 0x34, 0x09,
+ 0x35, 0x0c,
+ 0x36, 0x05,
+ 0x37, 0x2f,
+ 0x38, 0x16,
+ 0x39, 0xbd,
+ 0x3a, 0x0,
+ 0x3b, 0x13,
+ 0x3c, 0x11,
+ 0x3d, 0x30,
+ 0x40, 0x63,
+ 0x41, 0x04,
+ 0x42, 0x60,
+ 0x43, 0x00,
+ 0x44, 0x00,
+ 0x45, 0x00,
+ 0x46, 0x00,
+ 0x47, 0x00,
+ 0x4a, 0x00,
+ 0x50, 0x12,
+ 0x51, 0x36,
+ 0x52, 0x21,
+ 0x53, 0x94,
+ 0x54, 0xb2,
+ 0x55, 0x29,
+ 0x56, 0x64,
+ 0x57, 0x2b,
+ 0x58, 0x54,
+ 0x59, 0x86,
+ 0x5a, 0x00,
+ 0x5b, 0x9b,
+ 0x5c, 0x08,
+ 0x5d, 0x7f,
+ 0x5e, 0xff,
+ 0x5f, 0x8d,
+ 0x70, 0x0,
+ 0x71, 0x0,
+ 0x72, 0x0,
+ 0x74, 0x0,
+ 0x75, 0x0,
+ 0x76, 0x0,
+ 0x81, 0x0,
+ 0x82, 0x3f,
+ 0x83, 0x3f,
+ 0x84, 0x0,
+ 0x85, 0x0,
+ 0x88, 0x0,
+ 0x89, 0x0,
+ 0x8a, 0x0,
+ 0x8b, 0x0,
+ 0x8c, 0x0,
+ 0x90, 0x0,
+ 0x91, 0x0,
+ 0x92, 0x0,
+ 0x93, 0x0,
+ 0x94, 0x1c,
+ 0x97, 0x0,
+ 0xa0, 0x48,
+ 0xa1, 0x0,
+ 0xb0, 0xb8,
+ 0xb1, 0x3a,
+ 0xb2, 0x10,
+ 0xb3, 0x82,
+ 0xb4, 0x80,
+ 0xb5, 0x82,
+ 0xb6, 0x82,
+ 0xb7, 0x82,
+ 0xb8, 0x20,
+ 0xb9, 0x0,
+ 0xf0, 0x0,
+ 0xf1, 0x0,
+ 0xf2, 0xc0,
+ 0xff, 0xff,
+};
+#endif
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 28294af752db..f0f1842fab60 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -24,6 +24,8 @@
#include
#include
+#include
+
#include "firedtv.h"
#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL
@@ -130,6 +132,20 @@ MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS)
", or a combination, or all = -1)");
+/*
+ * This is a workaround since there is no vendor specific command to retrieve
+ * ca_info using AVC. If this parameter is not used, ca_system_id will be
+ * filled with application_manufacturer from ca_app_info.
+ * Digital Everywhere have said that adding ca_info is on their TODO list.
+ */
+static unsigned int num_fake_ca_system_ids;
+static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
+module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
+MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
+ "does not have the same ca_system_id as your CAS, you can "
+ "override what ca_system_ids are presented to the "
+ "application by setting this field to an array of ids.");
+
static const char *debug_fcp_ctype(unsigned int ctype)
{
static const char *ctypes[] = {
@@ -368,10 +384,30 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
c->operand[12] = 0;
if (fdtv->type == FIREDTV_DVB_S2) {
- c->operand[13] = 0x1;
- c->operand[14] = 0xff;
- c->operand[15] = 0xff;
-
+ if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
+ switch (fdtv->fe.dtv_property_cache.modulation) {
+ case QAM_16: c->operand[13] = 0x1; break;
+ case QPSK: c->operand[13] = 0x2; break;
+ case PSK_8: c->operand[13] = 0x3; break;
+ default: c->operand[13] = 0x2; break;
+ }
+ switch (fdtv->fe.dtv_property_cache.rolloff) {
+ case ROLLOFF_AUTO: c->operand[14] = 0x2; break;
+ case ROLLOFF_35: c->operand[14] = 0x2; break;
+ case ROLLOFF_20: c->operand[14] = 0x0; break;
+ case ROLLOFF_25: c->operand[14] = 0x1; break;
+ /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */
+ }
+ switch (fdtv->fe.dtv_property_cache.pilot) {
+ case PILOT_AUTO: c->operand[15] = 0x0; break;
+ case PILOT_OFF: c->operand[15] = 0x0; break;
+ case PILOT_ON: c->operand[15] = 0x1; break;
+ }
+ } else {
+ c->operand[13] = 0x1; /* auto modulation */
+ c->operand[14] = 0xff; /* disable rolloff */
+ c->operand[15] = 0xff; /* disable pilot */
+ }
return 16;
} else {
return 13;
@@ -977,7 +1013,7 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
struct avc_command_frame *c = (void *)fdtv->avc_data;
struct avc_response_frame *r = (void *)fdtv->avc_data;
- int pos, ret;
+ int i, pos, ret;
mutex_lock(&fdtv->avc_mutex);
@@ -1004,9 +1040,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff;
app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff;
- app_info[3] = 2;
- app_info[4] = r->operand[pos + 0];
- app_info[5] = r->operand[pos + 1];
+ if (num_fake_ca_system_ids == 0) {
+ app_info[3] = 2;
+ app_info[4] = r->operand[pos + 0];
+ app_info[5] = r->operand[pos + 1];
+ } else {
+ app_info[3] = num_fake_ca_system_ids * 2;
+ for (i = 0; i < num_fake_ca_system_ids; i++) {
+ app_info[4 + i * 2] =
+ (fake_ca_system_ids[i] >> 8) & 0xff;
+ app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
+ }
+ }
*len = app_info[3] + 4;
out:
mutex_unlock(&fdtv->avc_mutex);
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c
index e49cdc88b0c7..d10920e2f3a2 100644
--- a/drivers/media/dvb/firewire/firedtv-fe.c
+++ b/drivers/media/dvb/firewire/firedtv-fe.c
@@ -155,6 +155,16 @@ static int fdtv_get_frontend(struct dvb_frontend *fe,
return -EOPNOTSUPP;
}
+static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
+{
+ return 0;
+}
+
+static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
+{
+ return 0;
+}
+
void fdtv_frontend_init(struct firedtv *fdtv)
{
struct dvb_frontend_ops *ops = &fdtv->fe.ops;
@@ -166,6 +176,9 @@ void fdtv_frontend_init(struct firedtv *fdtv)
ops->set_frontend = fdtv_set_frontend;
ops->get_frontend = fdtv_get_frontend;
+ ops->get_property = fdtv_get_property;
+ ops->set_property = fdtv_set_property;
+
ops->read_status = fdtv_read_status;
ops->read_ber = fdtv_read_ber;
ops->read_signal_strength = fdtv_read_signal_strength;
@@ -179,6 +192,24 @@ void fdtv_frontend_init(struct firedtv *fdtv)
switch (fdtv->type) {
case FIREDTV_DVB_S:
+ fi->type = FE_QPSK;
+
+ fi->frequency_min = 950000;
+ fi->frequency_max = 2150000;
+ fi->frequency_stepsize = 125;
+ fi->symbol_rate_min = 1000000;
+ fi->symbol_rate_max = 40000000;
+
+ fi->caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK;
+ break;
+
case FIREDTV_DVB_S2:
fi->type = FE_QPSK;
@@ -188,14 +219,15 @@ void fdtv_frontend_init(struct firedtv *fdtv)
fi->symbol_rate_min = 1000000;
fi->symbol_rate_max = 40000000;
- fi->caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 |
- FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 |
- FE_CAN_FEC_7_8 |
- FE_CAN_FEC_AUTO |
- FE_CAN_QPSK;
+ fi->caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_2G_MODULATION;
break;
case FIREDTV_DVB_C:
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index b5f6a04f9c12..e9062b08a485 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -257,6 +257,13 @@ config DVB_CX22702
help
A DVB-T tuner module. Say Y when you want to support this frontend.
+config DVB_S5H1432
+ tristate "Samsung s5h1432 demodulator (OFDM)"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
config DVB_DRX397XD
tristate "Micronas DRX3975D/DRX3977D based"
depends on DVB_CORE && I2C
@@ -455,16 +462,8 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
-config DVB_LGDT3304
- tristate "LG Electronics LGDT3304"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
config DVB_LGDT3305
- tristate "LG Electronics LGDT3305 based"
+ tristate "LG Electronics LGDT3304 and LGDT3305 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@@ -607,6 +606,13 @@ config DVB_TDA665x
Currently supported tuners:
* Panasonic ENV57H12D5 (ET-50DT)
+config DVB_IX2505V
+ tristate "Sharp IX2505V silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 874e8ada4d1d..9a31985c0dfb 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_DVB_STB0899) += stb0899.o
obj-$(CONFIG_DVB_STB6100) += stb6100.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
+obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
@@ -45,7 +46,6 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
-obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
@@ -82,3 +82,4 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
+obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index dac917f7bb7f..e2a95c07bab4 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -42,6 +42,8 @@ struct af9013_state {
struct af9013_config config;
+ /* tuner/demod RF and IF AGC limits used for signal strength calc */
+ u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
u16 signal_strength;
u32 ber;
u32 ucblocks;
@@ -220,184 +222,37 @@ static u32 af913_div(u32 a, u32 b, u32 x)
static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
{
- int ret = 0;
- u8 i = 0;
- u8 buf[24];
- u32 uninitialized_var(ns_coeff1_2048nu);
- u32 uninitialized_var(ns_coeff1_8191nu);
- u32 uninitialized_var(ns_coeff1_8192nu);
- u32 uninitialized_var(ns_coeff1_8193nu);
- u32 uninitialized_var(ns_coeff2_2k);
- u32 uninitialized_var(ns_coeff2_8k);
-
+ int ret, i, j, found;
deb_info("%s: adc_clock:%d bw:%d\n", __func__,
state->config.adc_clock, bw);
- switch (state->config.adc_clock) {
- case 28800: /* 28.800 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x01e79e7a;
- ns_coeff1_8191nu = 0x0079eb6e;
- ns_coeff1_8192nu = 0x0079e79e;
- ns_coeff1_8193nu = 0x0079e3cf;
- ns_coeff2_2k = 0x00f3cf3d;
- ns_coeff2_8k = 0x003cf3cf;
+ /* lookup coeff from table */
+ for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) {
+ if (coeff_table[i].adc_clock == state->config.adc_clock &&
+ coeff_table[i].bw == bw) {
+ found = 1;
break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x0238e38e;
- ns_coeff1_8191nu = 0x008e3d55;
- ns_coeff1_8192nu = 0x008e38e4;
- ns_coeff1_8193nu = 0x008e3472;
- ns_coeff2_2k = 0x011c71c7;
- ns_coeff2_8k = 0x00471c72;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x028a28a3;
- ns_coeff1_8191nu = 0x00a28f3d;
- ns_coeff1_8192nu = 0x00a28a29;
- ns_coeff1_8193nu = 0x00a28514;
- ns_coeff2_2k = 0x01451451;
- ns_coeff2_8k = 0x00514514;
- break;
- default:
- ret = -EINVAL;
}
- break;
- case 20480: /* 20.480 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x02adb6dc;
- ns_coeff1_8191nu = 0x00ab7313;
- ns_coeff1_8192nu = 0x00ab6db7;
- ns_coeff1_8193nu = 0x00ab685c;
- ns_coeff2_2k = 0x0156db6e;
- ns_coeff2_8k = 0x0055b6dc;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x03200001;
- ns_coeff1_8191nu = 0x00c80640;
- ns_coeff1_8192nu = 0x00c80000;
- ns_coeff1_8193nu = 0x00c7f9c0;
- ns_coeff2_2k = 0x01900000;
- ns_coeff2_8k = 0x00640000;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x03924926;
- ns_coeff1_8191nu = 0x00e4996e;
- ns_coeff1_8192nu = 0x00e49249;
- ns_coeff1_8193nu = 0x00e48b25;
- ns_coeff2_2k = 0x01c92493;
- ns_coeff2_8k = 0x00724925;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case 28000: /* 28.000 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x01f58d10;
- ns_coeff1_8191nu = 0x007d672f;
- ns_coeff1_8192nu = 0x007d6344;
- ns_coeff1_8193nu = 0x007d5f59;
- ns_coeff2_2k = 0x00fac688;
- ns_coeff2_8k = 0x003eb1a2;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x02492492;
- ns_coeff1_8191nu = 0x00924db7;
- ns_coeff1_8192nu = 0x00924925;
- ns_coeff1_8193nu = 0x00924492;
- ns_coeff2_2k = 0x01249249;
- ns_coeff2_8k = 0x00492492;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x029cbc15;
- ns_coeff1_8191nu = 0x00a7343f;
- ns_coeff1_8192nu = 0x00a72f05;
- ns_coeff1_8193nu = 0x00a729cc;
- ns_coeff2_2k = 0x014e5e0a;
- ns_coeff2_8k = 0x00539783;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case 25000: /* 25.000 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x0231bcb5;
- ns_coeff1_8191nu = 0x008c7391;
- ns_coeff1_8192nu = 0x008c6f2d;
- ns_coeff1_8193nu = 0x008c6aca;
- ns_coeff2_2k = 0x0118de5b;
- ns_coeff2_8k = 0x00463797;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x028f5c29;
- ns_coeff1_8191nu = 0x00a3dc29;
- ns_coeff1_8192nu = 0x00a3d70a;
- ns_coeff1_8193nu = 0x00a3d1ec;
- ns_coeff2_2k = 0x0147ae14;
- ns_coeff2_8k = 0x0051eb85;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x02ecfb9d;
- ns_coeff1_8191nu = 0x00bb44c1;
- ns_coeff1_8192nu = 0x00bb3ee7;
- ns_coeff1_8193nu = 0x00bb390d;
- ns_coeff2_2k = 0x01767dce;
- ns_coeff2_8k = 0x005d9f74;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- default:
- err("invalid xtal");
- return -EINVAL;
- }
- if (ret) {
- err("invalid bandwidth");
- return ret;
}
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff2_2k & 0x01c00000) >> 22);
- buf[i++] = (u8) ((ns_coeff2_2k & 0x003fc000) >> 14);
- buf[i++] = (u8) ((ns_coeff2_2k & 0x00003fc0) >> 6);
- buf[i++] = (u8) ((ns_coeff2_2k & 0x0000003f));
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff2_8k & 0x01c00000) >> 22);
- buf[i++] = (u8) ((ns_coeff2_8k & 0x003fc000) >> 14);
- buf[i++] = (u8) ((ns_coeff2_8k & 0x00003fc0) >> 6);
- buf[i++] = (u8) ((ns_coeff2_8k & 0x0000003f));
+ if (!found) {
+ err("invalid bw or clock");
+ ret = -EINVAL;
+ goto error;
+ }
- deb_info("%s: coeff:", __func__);
- debug_dump(buf, sizeof(buf), deb_info);
+ deb_info("%s: coeff: ", __func__);
+ debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info);
/* program */
- for (i = 0; i < sizeof(buf); i++) {
- ret = af9013_write_reg(state, 0xae00 + i, buf[i]);
+ for (j = 0; j < sizeof(coeff_table[i].val); j++) {
+ ret = af9013_write_reg(state, 0xae00 + j,
+ coeff_table[i].val[j]);
if (ret)
break;
}
+error:
return ret;
}
@@ -486,6 +341,19 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
if_sample_freq = 4300000; /* 4.3 MHz */
break;
}
+ } else if (state->config.tuner == AF9013_TUNER_TDA18218) {
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ if_sample_freq = 3000000; /* 3 MHz */
+ break;
+ case BANDWIDTH_7_MHZ:
+ if_sample_freq = 3500000; /* 3.5 MHz */
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ if_sample_freq = 4000000; /* 4 MHz */
+ break;
+ }
}
while (if_sample_freq > (adc_freq / 2))
@@ -1097,45 +965,31 @@ static int af9013_update_signal_strength(struct dvb_frontend *fe)
{
struct af9013_state *state = fe->demodulator_priv;
int ret;
- u8 tmp0;
- u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80;
+ u8 rf_gain, if_gain;
int signal_strength;
deb_info("%s\n", __func__);
- state->signal_strength = 0;
-
- ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0);
- if (ret)
- goto error;
- if (tmp0) {
- ret = af9013_read_reg(state, 0x9bbd, &rf_50);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9bd0, &rf_80);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9be2, &if_50);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9be4, &if_80);
- if (ret)
- goto error;
+ if (state->signal_strength_en) {
ret = af9013_read_reg(state, 0xd07c, &rf_gain);
if (ret)
goto error;
ret = af9013_read_reg(state, 0xd07d, &if_gain);
if (ret)
goto error;
- signal_strength = (0xffff / (9 * (rf_50 + if_50) - \
- 11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \
- 11 * (rf_80 + if_80));
+ signal_strength = (0xffff / \
+ (9 * (state->rf_50 + state->if_50) - \
+ 11 * (state->rf_80 + state->if_80))) * \
+ (10 * (rf_gain + if_gain) - \
+ 11 * (state->rf_80 + state->if_80));
if (signal_strength < 0)
signal_strength = 0;
else if (signal_strength > 0xffff)
signal_strength = 0xffff;
state->signal_strength = signal_strength;
+ } else {
+ state->signal_strength = 0;
}
error:
@@ -1368,6 +1222,7 @@ static int af9013_init(struct dvb_frontend *fe)
break;
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
+ case AF9013_TUNER_MXL5007T:
len = ARRAY_SIZE(tuner_init_mxl5005);
init = tuner_init_mxl5005;
break;
@@ -1393,6 +1248,7 @@ static int af9013_init(struct dvb_frontend *fe)
init = tuner_init_mt2060_2;
break;
case AF9013_TUNER_TDA18271:
+ case AF9013_TUNER_TDA18218:
len = ARRAY_SIZE(tuner_init_tda18271);
init = tuner_init_tda18271;
break;
@@ -1438,6 +1294,27 @@ static int af9013_init(struct dvb_frontend *fe)
if (ret)
goto error;
+ /* read values needed for signal strength calculation */
+ ret = af9013_read_reg_bits(state, 0x9bee, 0, 1,
+ &state->signal_strength_en);
+ if (ret)
+ goto error;
+
+ if (state->signal_strength_en) {
+ ret = af9013_read_reg(state, 0x9bbd, &state->rf_50);
+ if (ret)
+ goto error;
+ ret = af9013_read_reg(state, 0x9bd0, &state->rf_80);
+ if (ret)
+ goto error;
+ ret = af9013_read_reg(state, 0x9be2, &state->if_50);
+ if (ret)
+ goto error;
+ ret = af9013_read_reg(state, 0x9be4, &state->if_80);
+ if (ret)
+ goto error;
+ }
+
error:
return ret;
}
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index 72c71bb5d117..e53d873f7555 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -44,6 +44,7 @@ enum af9013_tuner {
AF9013_TUNER_MT2060_2 = 147, /* Microtune */
AF9013_TUNER_TDA18271 = 156, /* NXP */
AF9013_TUNER_QT1010A = 162, /* Quantek */
+ AF9013_TUNER_MXL5007T = 177, /* MaxLinear */
AF9013_TUNER_TDA18218 = 179, /* NXP */
};
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
index 0fd42b7e248e..e00b2a4a2db6 100644
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ b/drivers/media/dvb/frontends/af9013_priv.h
@@ -60,6 +60,56 @@ struct snr_table {
u8 snr;
};
+struct coeff {
+ u32 adc_clock;
+ fe_bandwidth_t bw;
+ u8 val[24];
+};
+
+/* pre-calculated coeff lookup table */
+static struct coeff coeff_table[] = {
+ /* 28.800 MHz */
+ { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
+ 0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
+ 0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
+ { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
+ 0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
+ 0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
+ { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
+ 0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
+ 0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
+ /* 20.480 MHz */
+ { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
+ 0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
+ 0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
+ { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
+ 0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
+ 0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
+ { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
+ 0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
+ 0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
+ /* 28.000 MHz */
+ { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
+ 0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
+ 0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
+ { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
+ 0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
+ 0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
+ { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
+ 0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
+ 0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
+ /* 25.000 MHz */
+ { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
+ 0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
+ 0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
+ { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
+ 0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
+ 0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
+ { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
+ 0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
+ 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
+};
+
/* QPSK SNR lookup table */
static struct snr_table qpsk_snr_table[] = {
{ 0x0b4771, 0 },
@@ -480,9 +530,10 @@ static struct regdesc tuner_init_mxl5003d[] = {
{ 0x9bd9, 0, 8, 0x08 },
};
-/* MaxLinear MXL5005 tuner init
+/* MaxLinear MXL5005S & MXL5007T tuner init
AF9013_TUNER_MXL5005D = 13
- AF9013_TUNER_MXL5005R = 30 */
+ AF9013_TUNER_MXL5005R = 30
+ AF9013_TUNER_MXL5007T = 177 */
static struct regdesc tuner_init_mxl5005[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x07 },
@@ -791,8 +842,9 @@ static struct regdesc tuner_init_unknown[] = {
{ 0x9bd9, 0, 8, 0x08 },
};
-/* NXP TDA18271 tuner init
- AF9013_TUNER_TDA18271 = 156 */
+/* NXP TDA18271 & TDA18218 tuner init
+ AF9013_TUNER_TDA18271 = 156
+ AF9013_TUNER_TDA18218 = 179 */
static struct regdesc tuner_init_tda18271[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x04 },
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 29cdbfe36852..6d9c5943eb3d 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -36,7 +36,6 @@
#include
#include
#include
-#include
#include
#include "au8522.h"
#include "au8522_priv.h"
@@ -831,9 +830,25 @@ static const struct i2c_device_id au8522_id[] = {
MODULE_DEVICE_TABLE(i2c, au8522_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "au8522",
- .probe = au8522_probe,
- .remove = au8522_remove,
- .id_table = au8522_id,
+static struct i2c_driver au8522_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "au8522",
+ },
+ .probe = au8522_probe,
+ .remove = au8522_remove,
+ .id_table = au8522_id,
};
+
+static __init int init_au8522(void)
+{
+ return i2c_add_driver(&au8522_driver);
+}
+
+static __exit void exit_au8522(void)
+{
+ i2c_del_driver(&au8522_driver);
+}
+
+module_init(init_au8522);
+module_exit(exit_au8522);
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 00b5c7e91d5d..ff6c4983051c 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -54,7 +54,7 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages");
#define dprintk if (debug) printk
/* Register values to initialise the demod */
-static u8 init_tab[] = {
+static const u8 init_tab[] = {
0x00, 0x00, /* Stop aquisition */
0x0B, 0x06,
0x09, 0x01,
@@ -92,52 +92,56 @@ static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
ret = i2c_transfer(state->i2c, &msg, 1);
- if (ret != 1)
+ if (unlikely(ret != 1)) {
printk(KERN_ERR
"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
__func__, reg, data, ret);
+ return -1;
+ }
- return (ret != 1) ? -1 : 0;
+ return 0;
}
static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
{
int ret;
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
+ u8 data;
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0,
- .buf = b0, .len = 1 },
+ .buf = ®, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
- .buf = b1, .len = 1 } };
+ .buf = &data, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- printk(KERN_ERR "%s: readreg error (ret == %i)\n",
- __func__, ret);
+ if (unlikely(ret != 2)) {
+ printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
+ __func__, reg, ret);
+ return 0;
+ }
- return b1[0];
+ return data;
}
static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
{
u8 val;
+ val = cx22702_readreg(state, 0x0C);
switch (inversion) {
case INVERSION_AUTO:
return -EOPNOTSUPP;
case INVERSION_ON:
- val = cx22702_readreg(state, 0x0C);
- return cx22702_writereg(state, 0x0C, val | 0x01);
+ val |= 0x01;
+ break;
case INVERSION_OFF:
- val = cx22702_readreg(state, 0x0C);
- return cx22702_writereg(state, 0x0C, val & 0xfe);
+ val &= 0xfe;
+ break;
default:
return -EINVAL;
}
-
+ return cx22702_writereg(state, 0x0C, val);
}
/* Retrieve the demod settings */
@@ -244,13 +248,15 @@ static int cx22702_get_tps(struct cx22702_state *state,
static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct cx22702_state *state = fe->demodulator_priv;
+ u8 val;
+
dprintk("%s(%d)\n", __func__, enable);
+ val = cx22702_readreg(state, 0x0D);
if (enable)
- return cx22702_writereg(state, 0x0D,
- cx22702_readreg(state, 0x0D) & 0xfe);
+ val &= 0xfe;
else
- return cx22702_writereg(state, 0x0D,
- cx22702_readreg(state, 0x0D) | 1);
+ val |= 0x01;
+ return cx22702_writereg(state, 0x0D, val);
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
@@ -270,23 +276,21 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
cx22702_set_inversion(state, p->inversion);
/* set bandwidth */
+ val = cx22702_readreg(state, 0x0C) & 0xcf;
switch (p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- cx22702_writereg(state, 0x0C,
- (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20);
+ val |= 0x20;
break;
case BANDWIDTH_7_MHZ:
- cx22702_writereg(state, 0x0C,
- (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10);
+ val |= 0x10;
break;
case BANDWIDTH_8_MHZ:
- cx22702_writereg(state, 0x0C,
- cx22702_readreg(state, 0x0C) & 0xcf);
break;
default:
dprintk("%s: invalid bandwidth\n", __func__);
return -EINVAL;
}
+ cx22702_writereg(state, 0x0C, val);
p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
@@ -312,33 +316,31 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
/* manually programmed values */
- val = 0;
- switch (p->u.ofdm.constellation) {
+ switch (p->u.ofdm.constellation) { /* mask 0x18 */
case QPSK:
- val = (val & 0xe7);
+ val = 0x00;
break;
case QAM_16:
- val = (val & 0xe7) | 0x08;
+ val = 0x08;
break;
case QAM_64:
- val = (val & 0xe7) | 0x10;
+ val = 0x10;
break;
default:
dprintk("%s: invalid constellation\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.hierarchy_information) {
+ switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */
case HIERARCHY_NONE:
- val = (val & 0xf8);
break;
case HIERARCHY_1:
- val = (val & 0xf8) | 1;
+ val |= 0x01;
break;
case HIERARCHY_2:
- val = (val & 0xf8) | 2;
+ val |= 0x02;
break;
case HIERARCHY_4:
- val = (val & 0xf8) | 3;
+ val |= 0x03;
break;
default:
dprintk("%s: invalid hierarchy\n", __func__);
@@ -346,44 +348,42 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x06, val);
- val = 0;
- switch (p->u.ofdm.code_rate_HP) {
+ switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */
case FEC_NONE:
case FEC_1_2:
- val = (val & 0xc7);
+ val = 0x00;
break;
case FEC_2_3:
- val = (val & 0xc7) | 0x08;
+ val = 0x08;
break;
case FEC_3_4:
- val = (val & 0xc7) | 0x10;
+ val = 0x10;
break;
case FEC_5_6:
- val = (val & 0xc7) | 0x18;
+ val = 0x18;
break;
case FEC_7_8:
- val = (val & 0xc7) | 0x20;
+ val = 0x20;
break;
default:
dprintk("%s: invalid code_rate_HP\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.code_rate_LP) {
+ switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */
case FEC_NONE:
case FEC_1_2:
- val = (val & 0xf8);
break;
case FEC_2_3:
- val = (val & 0xf8) | 1;
+ val |= 0x01;
break;
case FEC_3_4:
- val = (val & 0xf8) | 2;
+ val |= 0x02;
break;
case FEC_5_6:
- val = (val & 0xf8) | 3;
+ val |= 0x03;
break;
case FEC_7_8:
- val = (val & 0xf8) | 4;
+ val |= 0x04;
break;
default:
dprintk("%s: invalid code_rate_LP\n", __func__);
@@ -391,30 +391,28 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x07, val);
- val = 0;
- switch (p->u.ofdm.guard_interval) {
+ switch (p->u.ofdm.guard_interval) { /* mask 0x0c */
case GUARD_INTERVAL_1_32:
- val = (val & 0xf3);
+ val = 0x00;
break;
case GUARD_INTERVAL_1_16:
- val = (val & 0xf3) | 0x04;
+ val = 0x04;
break;
case GUARD_INTERVAL_1_8:
- val = (val & 0xf3) | 0x08;
+ val = 0x08;
break;
case GUARD_INTERVAL_1_4:
- val = (val & 0xf3) | 0x0c;
+ val = 0x0c;
break;
default:
dprintk("%s: invalid guard_interval\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.transmission_mode) {
+ switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */
case TRANSMISSION_MODE_2K:
- val = (val & 0xfc);
break;
case TRANSMISSION_MODE_8K:
- val = (val & 0xfc) | 1;
+ val |= 0x1;
break;
default:
dprintk("%s: invalid transmission_mode\n", __func__);
@@ -505,7 +503,7 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe,
{
struct cx22702_state *state = fe->demodulator_priv;
- u16 rs_ber = 0;
+ u16 rs_ber;
rs_ber = cx22702_readreg(state, 0x23);
*signal_strength = (rs_ber << 8) | rs_ber;
@@ -516,7 +514,7 @@ static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct cx22702_state *state = fe->demodulator_priv;
- u16 rs_ber = 0;
+ u16 rs_ber;
if (cx22702_readreg(state, 0xE4) & 0x02) {
/* Realtime statistics */
rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
@@ -572,7 +570,7 @@ static void cx22702_release(struct dvb_frontend *fe)
kfree(state);
}
-static struct dvb_frontend_ops cx22702_ops;
+static const struct dvb_frontend_ops cx22702_ops;
struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
struct i2c_adapter *i2c)
@@ -587,7 +585,6 @@ struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- state->prevUCBlocks = 0;
/* check if the demod is there */
if (cx22702_readreg(state, 0x1f) != 0x3)
@@ -605,7 +602,7 @@ error:
}
EXPORT_SYMBOL(cx22702_attach);
-static struct dvb_frontend_ops cx22702_ops = {
+static const struct dvb_frontend_ops cx22702_ops = {
.info = {
.name = "Conexant CX22702 DVB-T",
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 00a4e8f03304..7a1a5bc337d8 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -310,7 +310,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
}
-static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
+static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
{
struct cx24110_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index d8f921b6fafd..fad6a990a39b 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1108,7 +1108,6 @@ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
- state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index 980e02f1575e..a4991026254d 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -130,7 +130,6 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
struct dibx000_i2c_master *mst)
{
strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
- i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
i2c_set_adapdata(i2c_adap, mst);
if (i2c_add_adapter(i2c_adap) < 0)
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
index f74cca6dc26b..a05007c80985 100644
--- a/drivers/media/dvb/frontends/drx397xD.c
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -232,7 +232,7 @@ static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
exit_rc:
read_unlock(&fw[s->chip_rev].lock);
- return 0;
+ return rc;
}
/* Function is not endian safe, use the RD16 wrapper below */
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
new file mode 100644
index 000000000000..55f2eba7bc96
--- /dev/null
+++ b/drivers/media/dvb/frontends/ix2505v.c
@@ -0,0 +1,323 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include
+#include
+#include
+#include
+
+#include "ix2505v.h"
+
+static int ix2505v_debug;
+#define dprintk(level, args...) do { \
+ if (ix2505v_debug & level) \
+ printk(KERN_DEBUG "ix2505v: " args); \
+} while (0)
+
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_i2c(args...) dprintk(0x02, args)
+
+struct ix2505v_state {
+ struct i2c_adapter *i2c;
+ const struct ix2505v_config *config;
+ u32 frequency;
+};
+
+/**
+ * Data read format of the Sharp IX2505V B0017
+ *
+ * byte1: 1 | 1 | 0 | 0 | 0 | MA1 | MA0 | 1
+ * byte2: POR | FL | RD2 | RD1 | RD0 | X | X | X
+ *
+ * byte1 = address
+ * byte2;
+ * POR = Power on Reset (VCC H=<2.2v L=>2.2v)
+ * FL = Phase Lock (H=lock L=unlock)
+ * RD0-2 = Reserved internal operations
+ *
+ * Only POR can be used to check the tuner is present
+ *
+ * Caution: after byte2 the I2C reverts to write mode continuing to read
+ * may corrupt tuning data.
+ *
+ */
+
+static int ix2505v_read_status_reg(struct ix2505v_state *state)
+{
+ u8 addr = state->config->tuner_address;
+ u8 b2[] = {0};
+ int ret;
+
+ struct i2c_msg msg[1] = {
+ { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 1);
+ deb_i2c("Read %s ", __func__);
+
+ return (ret = 1) ? (int) b2[0] : -1;
+}
+
+static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
+{
+ struct i2c_msg msg[1] = {
+ { .addr = state->config->tuner_address, .flags = 0,
+ .buf = buf, .len = count },
+ };
+
+ int ret;
+
+ ret = i2c_transfer(state->i2c, msg, 1);
+
+ if (ret != 1) {
+ deb_i2c("%s: i2c error, ret=%d\n", __func__, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ix2505v_release(struct dvb_frontend *fe)
+{
+ struct ix2505v_state *state = fe->tuner_priv;
+
+ fe->tuner_priv = NULL;
+ kfree(state);
+
+ return 0;
+}
+
+/**
+ * Data write format of the Sharp IX2505V B0017
+ *
+ * byte1: 1 | 1 | 0 | 0 | 0 | 0(MA1)| 0(MA0)| 0
+ * byte2: 0 | BG1 | BG2 | N8 | N7 | N6 | N5 | N4
+ * byte3: N3 | N2 | N1 | A5 | A4 | A3 | A2 | A1
+ * byte4: 1 | 1(C1) | 1(C0) | PD5 | PD4 | TM | 0(RTS)| 1(REF)
+ * byte5: BA2 | BA1 | BA0 | PSC | PD3 |PD2/TS2|DIV/TS1|PD0/TS0
+ *
+ * byte1 = address
+ *
+ * Write order
+ * 1) byte1 -> byte2 -> byte3 -> byte4 -> byte5
+ * 2) byte1 -> byte4 -> byte5 -> byte2 -> byte3
+ * 3) byte1 -> byte2 -> byte3 -> byte4
+ * 4) byte1 -> byte4 -> byte5 -> byte2
+ * 5) byte1 -> byte2 -> byte3
+ * 6) byte1 -> byte4 -> byte5
+ * 7) byte1 -> byte2
+ * 8) byte1 -> byte4
+ *
+ * Recommended Setup
+ * 1 -> 8 -> 6
+ */
+
+static int ix2505v_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct ix2505v_state *state = fe->tuner_priv;
+ u32 frequency = params->frequency;
+ u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000;
+ u32 div_factor, N , A, x;
+ int ret = 0, len;
+ u8 gain, cc, ref, psc, local_osc, lpf;
+ u8 data[4] = {0};
+
+ if ((frequency < fe->ops.info.frequency_min)
+ || (frequency > fe->ops.info.frequency_max))
+ return -EINVAL;
+
+ if (state->config->tuner_gain)
+ gain = (state->config->tuner_gain < 4)
+ ? state->config->tuner_gain : 0;
+ else
+ gain = 0x0;
+
+ if (state->config->tuner_chargepump)
+ cc = state->config->tuner_chargepump;
+ else
+ cc = 0x3;
+
+ ref = 8; /* REF =1 */
+ psc = 32; /* PSC = 0 */
+
+ div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */
+ x = div_factor / psc;
+ N = x/100;
+ A = ((x - (N * 100)) * psc) / 100;
+
+ data[0] = ((gain & 0x3) << 5) | (N >> 3);
+ data[1] = (N << 5) | (A & 0x1f);
+ data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
+
+ deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A);
+
+ if (frequency <= 1065000)
+ local_osc = (6 << 5) | 2;
+ else if (frequency <= 1170000)
+ local_osc = (7 << 5) | 2;
+ else if (frequency <= 1300000)
+ local_osc = (1 << 5);
+ else if (frequency <= 1445000)
+ local_osc = (2 << 5);
+ else if (frequency <= 1607000)
+ local_osc = (3 << 5);
+ else if (frequency <= 1778000)
+ local_osc = (4 << 5);
+ else if (frequency <= 1942000)
+ local_osc = (5 << 5);
+ else /*frequency up to 2150000*/
+ local_osc = (6 << 5);
+
+ data[3] = local_osc; /* all other bits set 0 */
+
+ if (b_w <= 10000)
+ lpf = 0xc;
+ else if (b_w <= 12000)
+ lpf = 0x2;
+ else if (b_w <= 14000)
+ lpf = 0xa;
+ else if (b_w <= 16000)
+ lpf = 0x6;
+ else if (b_w <= 18000)
+ lpf = 0xe;
+ else if (b_w <= 20000)
+ lpf = 0x1;
+ else if (b_w <= 22000)
+ lpf = 0x9;
+ else if (b_w <= 24000)
+ lpf = 0x5;
+ else if (b_w <= 26000)
+ lpf = 0xd;
+ else if (b_w <= 28000)
+ lpf = 0x3;
+ else
+ lpf = 0xb;
+
+ deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
+ deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ len = sizeof(data);
+
+ ret |= ix2505v_write(state, data, len);
+
+ data[2] |= 0x4; /* set TM = 1 other bits same */
+
+ len = 1;
+ ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
+
+ msleep(10);
+
+ data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */
+ data[3] |= (lpf & 0x3) << 2;
+
+ deb_info("Data 2=[%x%x]\n", data[2], data[3]);
+
+ len = 2;
+ ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (state->config->min_delay_ms)
+ msleep(state->config->min_delay_ms);
+
+ state->frequency = frequency;
+
+ return ret;
+}
+
+static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct ix2505v_state *state = fe->tuner_priv;
+
+ *frequency = state->frequency;
+
+ return 0;
+}
+
+static struct dvb_tuner_ops ix2505v_tuner_ops = {
+ .info = {
+ .name = "Sharp IX2505V (B0017)",
+ .frequency_min = 950000,
+ .frequency_max = 2175000
+ },
+ .release = ix2505v_release,
+ .set_params = ix2505v_set_params,
+ .get_frequency = ix2505v_get_frequency,
+};
+
+struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+ const struct ix2505v_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct ix2505v_state *state = NULL;
+ int ret;
+
+ if (NULL == config) {
+ deb_i2c("%s: no config ", __func__);
+ goto error;
+ }
+
+ state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL);
+ if (NULL == state)
+ return NULL;
+
+ state->config = config;
+ state->i2c = i2c;
+
+ if (state->config->tuner_write_only) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = ix2505v_read_status_reg(state);
+
+ if (ret & 0x80) {
+ deb_i2c("%s: No IX2505V found\n", __func__);
+ goto error;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ fe->tuner_priv = state;
+
+ memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ deb_i2c("%s: initialization (%s addr=0x%02x) ok\n",
+ __func__, fe->ops.tuner_ops.info.name, config->tuner_address);
+
+ return fe;
+
+error:
+ ix2505v_release(fe);
+ return NULL;
+}
+EXPORT_SYMBOL(ix2505v_attach);
+
+module_param_named(debug, ix2505v_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB IX2505V tuner driver");
+MODULE_AUTHOR("Malcolm Priestley");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ix2505v.h b/drivers/media/dvb/frontends/ix2505v.h
new file mode 100644
index 000000000000..67e89d616d50
--- /dev/null
+++ b/drivers/media/dvb/frontends/ix2505v.h
@@ -0,0 +1,64 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVB_IX2505V_H
+#define DVB_IX2505V_H
+
+#include
+#include "dvb_frontend.h"
+
+/**
+ * Attach a ix2505v tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config ix2505v_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct ix2505v_config {
+ u8 tuner_address;
+
+ /*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */
+ u8 tuner_gain;
+
+ /*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */
+ u8 tuner_chargepump;
+
+ /* delay after tune */
+ int min_delay_ms;
+
+ /* disables reads*/
+ u8 tuner_write_only;
+
+};
+
+#if defined(CONFIG_DVB_IX2505V) || \
+ (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+ const struct ix2505v_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+ const struct ix2505v_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* DVB_IX2505V_H */
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
deleted file mode 100644
index 45a529b06b9d..000000000000
--- a/drivers/media/dvb/frontends/lgdt3304.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Driver for LG ATSC lgdt3304 driver
- *
- * Copyright (C) 2008 Markus Rechberger
- *
- */
-
-#include
-#include
-#include
-#include
-#include "dvb_frontend.h"
-#include "lgdt3304.h"
-
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
-
-#define dprintk(fmt, args...) if (debug) do {\
- printk("lgdt3304 debug: " fmt, ##args); } while (0)
-
-struct lgdt3304_state
-{
- struct dvb_frontend frontend;
- fe_modulation_t current_modulation;
- __u32 snr;
- __u32 current_frequency;
- __u8 addr;
- struct i2c_adapter *i2c;
-};
-
-static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- struct i2c_msg i2cmsgs = {
- .addr = state->addr,
- .flags = 0,
- .len = 3,
- .buf = buf
- };
- int i;
- int err;
-
- for (i=0; ii2c, &i2cmsgs, 1))<0) {
- printk("%s i2c_transfer error %d\n", __func__, err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
- i2cmsgs.buf += 3;
- }
- return 0;
-}
-
-static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- struct i2c_msg i2cmsgs[2];
- int ret;
- __u8 buf;
-
- __u8 regbuf[2] = { reg>>8, reg&0xff };
-
- i2cmsgs[0].addr = state->addr;
- i2cmsgs[0].flags = 0;
- i2cmsgs[0].len = 2;
- i2cmsgs[0].buf = regbuf;
-
- i2cmsgs[1].addr = state->addr;
- i2cmsgs[1].flags = I2C_M_RD;
- i2cmsgs[1].len = 1;
- i2cmsgs[1].buf = &buf;
-
- if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
- printk("%s i2c_transfer error %d\n", __func__, ret);
- return ret;
- }
-
- return buf;
-}
-
-static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- char buffer[3] = { reg>>8, reg&0xff, val };
- int ret;
-
- struct i2c_msg i2cmsgs = {
- .addr = state->addr,
- .flags = 0,
- .len = 3,
- .buf=buffer
- };
- ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
- if (ret != 1) {
- printk("%s i2c_transfer error %d\n", __func__, ret);
- return ret;
- }
-
- return 0;
-}
-
-
-static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
-{
- lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
- lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
- mdelay(200);
- return 0;
-}
-
-static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
- int err = 0;
-
- static __u8 lgdt3304_vsb8_data[] = {
- /* 16bit , 8bit */
- /* regs , val */
- 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x13,
- 0x00, 0x0d, 0x02,
- 0x00, 0x0e, 0x02,
- 0x00, 0x12, 0x32,
- 0x00, 0x13, 0xc4,
- 0x01, 0x12, 0x17,
- 0x01, 0x13, 0x15,
- 0x01, 0x14, 0x18,
- 0x01, 0x15, 0xff,
- 0x01, 0x16, 0x2c,
- 0x02, 0x14, 0x67,
- 0x02, 0x24, 0x8d,
- 0x04, 0x27, 0x12,
- 0x04, 0x28, 0x4f,
- 0x03, 0x08, 0x80,
- 0x03, 0x09, 0x00,
- 0x03, 0x0d, 0x00,
- 0x03, 0x0e, 0x1c,
- 0x03, 0x14, 0xe1,
- 0x05, 0x0e, 0x5b,
- };
-
- /* not yet tested .. */
- static __u8 lgdt3304_qam64_data[] = {
- /* 16bit , 8bit */
- /* regs , val */
- 0x00, 0x00, 0x18,
- 0x00, 0x0d, 0x02,
- //0x00, 0x0e, 0x02,
- 0x00, 0x12, 0x2a,
- 0x00, 0x13, 0x00,
- 0x03, 0x14, 0xe3,
- 0x03, 0x0e, 0x1c,
- 0x03, 0x08, 0x66,
- 0x03, 0x09, 0x66,
- 0x03, 0x0a, 0x08,
- 0x03, 0x0b, 0x9b,
- 0x05, 0x0e, 0x5b,
- };
-
-
- /* tested with KWorld a340 */
- static __u8 lgdt3304_qam256_data[] = {
- /* 16bit , 8bit */
- /* regs , val */
- 0x00, 0x00, 0x01, //0x19,
- 0x00, 0x12, 0x2a,
- 0x00, 0x13, 0x80,
- 0x00, 0x0d, 0x02,
- 0x03, 0x14, 0xe3,
-
- 0x03, 0x0e, 0x1c,
- 0x03, 0x08, 0x66,
- 0x03, 0x09, 0x66,
- 0x03, 0x0a, 0x08,
- 0x03, 0x0b, 0x9b,
-
- 0x03, 0x0d, 0x14,
- //0x05, 0x0e, 0x5b,
- 0x01, 0x06, 0x4a,
- 0x01, 0x07, 0x3d,
- 0x01, 0x08, 0x70,
- 0x01, 0x09, 0xa3,
-
- 0x05, 0x04, 0xfd,
-
- 0x00, 0x0d, 0x82,
-
- 0x05, 0x0e, 0x5b,
-
- 0x05, 0x0e, 0x5b,
-
- 0x00, 0x02, 0x9a,
-
- 0x00, 0x02, 0x9b,
-
- 0x00, 0x00, 0x01,
- 0x00, 0x12, 0x2a,
- 0x00, 0x13, 0x80,
- 0x00, 0x0d, 0x02,
- 0x03, 0x14, 0xe3,
-
- 0x03, 0x0e, 0x1c,
- 0x03, 0x08, 0x66,
- 0x03, 0x09, 0x66,
- 0x03, 0x0a, 0x08,
- 0x03, 0x0b, 0x9b,
-
- 0x03, 0x0d, 0x14,
- 0x01, 0x06, 0x4a,
- 0x01, 0x07, 0x3d,
- 0x01, 0x08, 0x70,
- 0x01, 0x09, 0xa3,
-
- 0x05, 0x04, 0xfd,
-
- 0x00, 0x0d, 0x82,
-
- 0x05, 0x0e, 0x5b,
- };
-
- struct lgdt3304_state *state = fe->demodulator_priv;
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
- case VSB_8:
- err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
- sizeof(lgdt3304_vsb8_data));
- break;
- case QAM_64:
- err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
- sizeof(lgdt3304_qam64_data));
- break;
- case QAM_256:
- err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
- sizeof(lgdt3304_qam256_data));
- break;
- default:
- break;
- }
-
- if (err) {
- printk("%s error setting modulation\n", __func__);
- } else {
- state->current_modulation = param->u.vsb.modulation;
- }
- }
- state->current_frequency = param->frequency;
-
- lgdt3304_soft_Reset(fe);
-
-
- if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, param);
-
- return 0;
-}
-
-static int lgdt3304_init(struct dvb_frontend *fe) {
- return 0;
-}
-
-static int lgdt3304_sleep(struct dvb_frontend *fe) {
- return 0;
-}
-
-
-static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- int r011d;
- int qam_lck;
-
- *status = 0;
- dprintk("lgdt read status\n");
-
- r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
-
- dprintk("%02x\n", r011d);
-
- switch(state->current_modulation) {
- case VSB_8:
- if (r011d & 0x80) {
- dprintk("VSB Locked\n");
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_SIGNAL;
- }
- break;
- case QAM_64:
- case QAM_256:
- qam_lck = r011d & 0x7;
- switch(qam_lck) {
- case 0x0: dprintk("Unlock\n");
- break;
- case 0x4: dprintk("1st Lock in acquisition state\n");
- break;
- case 0x6: dprintk("2nd Lock in acquisition state\n");
- break;
- case 0x7: dprintk("Final Lock in good reception state\n");
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_SIGNAL;
- break;
- }
- break;
- default:
- printk("%s unhandled modulation\n", __func__);
- }
-
-
- return 0;
-}
-
-static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
-{
- dprintk("read ber\n");
- return 0;
-}
-
-static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
-{
- dprintk("read snr\n");
- return 0;
-}
-
-static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
-{
- dprintk("read ucblocks\n");
- return 0;
-}
-
-static void lgdt3304_release(struct dvb_frontend *fe)
-{
- struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops demod_lgdt3304={
- .info = {
- .name = "LG 3304",
- .type = FE_ATSC,
- .frequency_min = 54000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 62500,
- .symbol_rate_min = 5056941,
- .symbol_rate_max = 10762000,
- .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
- },
- .init = lgdt3304_init,
- .sleep = lgdt3304_sleep,
- .set_frontend = lgdt3304_set_parameters,
- .read_snr = lgdt3304_read_snr,
- .read_ber = lgdt3304_read_ber,
- .read_status = lgdt3304_read_status,
- .read_ucblocks = lgdt3304_read_ucblocks,
- .release = lgdt3304_release,
-};
-
-struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
- struct i2c_adapter *i2c)
-{
-
- struct lgdt3304_state *state;
- state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
- if (state == NULL)
- return NULL;
- state->addr = config->i2c_address;
- state->i2c = i2c;
-
- memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
-}
-
-EXPORT_SYMBOL_GPL(lgdt3304_attach);
-MODULE_AUTHOR("Markus Rechberger ");
-MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgdt3304.h b/drivers/media/dvb/frontends/lgdt3304.h
deleted file mode 100644
index fc409fe59acb..000000000000
--- a/drivers/media/dvb/frontends/lgdt3304.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Driver for DVB-T lgdt3304 demodulator
- *
- * Copyright (C) 2008 Markus Rechberger
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef LGDT3304_H
-#define LGDT3304_H
-
-#include
-
-struct lgdt3304_config
-{
- /* demodulator's I2C address */
- u8 i2c_address;
-};
-
-#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
-extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
- struct i2c_adapter *i2c)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_LGDT */
-
-#endif /* LGDT3304_H */
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index 5ea28ae2ba8f..0fcddc4569d2 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -662,7 +662,7 @@ static void lgs8gxx_release(struct dvb_frontend *fe)
}
-static int lgs8gxx_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index beba5aa0db50..319672f8e1a7 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -69,7 +69,7 @@ static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen)
{
int err,i;
for (i=0; i < ilen-1; i++)
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 595092f9f0c4..ca2562d6f289 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -63,7 +63,7 @@ static inline struct dvb_frontend* mt352_attach(const struct mt352_config* confi
}
#endif // CONFIG_DVB_MT352
-static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
+static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) {
int r = 0;
if (fe->ops.write)
r = fe->ops.write(fe, buf, len);
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 2e9fd2893ede..e87b747ea99c 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -920,7 +920,6 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
/* create tuner i2c adapter */
strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
- state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);
diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c
new file mode 100644
index 000000000000..0c6dcb90d168
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1432.c
@@ -0,0 +1,415 @@
+/*
+ * Samsung s5h1432 DVB-T demodulator driver
+ *
+ * Copyright (C) 2009 Bill Liu
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "dvb_frontend.h"
+#include "s5h1432.h"
+
+struct s5h1432_state {
+
+ struct i2c_adapter *i2c;
+
+ /* configuration settings */
+ const struct s5h1432_config *config;
+
+ struct dvb_frontend frontend;
+
+ fe_modulation_t current_modulation;
+ unsigned int first_tune:1;
+
+ u32 current_frequency;
+ int if_freq;
+
+ u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do { \
+ if (debug) \
+ printk(arg); \
+ } while (0)
+
+static int s5h1432_writereg(struct s5h1432_state *state,
+ u8 addr, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf[] = { reg, data };
+
+ struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+ "ret == %i)\n", __func__, addr, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ {.addr = addr, .flags = 0, .buf = b0, .len = 1},
+ {.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1}
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+ return b1[0];
+}
+
+static int s5h1432_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe,
+ u32 bandwidth)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ u8 reg = 0;
+
+ /* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */
+ reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E);
+ reg &= ~(0x0C);
+ switch (bandwidth) {
+ case 6:
+ reg |= 0x08;
+ break;
+ case 7:
+ reg |= 0x04;
+ break;
+ case 8:
+ reg |= 0x00;
+ break;
+ default:
+ return 0;
+ }
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg);
+ return 1;
+}
+
+static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ switch (ifFreqHz) {
+ case TAIWAN_HI_IF_FREQ_44_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15);
+ break;
+ case EUROPE_HI_IF_FREQ_36_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40);
+ break;
+ case IF_FREQ_6_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0);
+ break;
+ case IF_FREQ_3point3_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+ break;
+ case IF_FREQ_3point5_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED);
+ break;
+ case IF_FREQ_4_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA);
+ break;
+ default:
+ {
+ u32 value = 0;
+ value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 *
+ (u32) 32768) / (48 * 1000));
+ printk(KERN_INFO
+ "Default IFFreq %d :reg value = 0x%x\n",
+ ifFreqHz, value);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4,
+ (u8) value & 0xFF);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5,
+ (u8) (value >> 8) & 0xFF);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7,
+ (u8) (value >> 16) & 0xFF);
+ break;
+ }
+
+ }
+
+ return 1;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1432_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ u32 dvb_bandwidth = 8;
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ if (p->frequency == state->current_frequency) {
+ /*current_frequency = p->frequency; */
+ /*state->current_frequency = p->frequency; */
+ } else {
+ fe->ops.tuner_ops.set_params(fe, p);
+ msleep(300);
+ s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+ switch (p->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ dvb_bandwidth = 6;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_7_MHZ:
+ dvb_bandwidth = 7;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_8_MHZ:
+ dvb_bandwidth = 8;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ default:
+ return 0;
+ }
+ /*fe->ops.tuner_ops.set_params(fe, p); */
+/*Soft Reset chip*/
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+ s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+ switch (p->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ dvb_bandwidth = 6;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_7_MHZ:
+ dvb_bandwidth = 7;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_8_MHZ:
+ dvb_bandwidth = 8;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ default:
+ return 0;
+ }
+ /*fe->ops.tuner_ops.set_params(fe,p); */
+ /*Soft Reset chip*/
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+ }
+
+ state->current_frequency = p->frequency;
+
+ return 0;
+}
+
+static int s5h1432_init(struct dvb_frontend *fe)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ u8 reg = 0;
+ state->current_frequency = 0;
+ printk(KERN_INFO " s5h1432_init().\n");
+
+ /*Set VSB mode as default, this also does a soft reset */
+ /*Initialize registers */
+
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94);
+ /* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00);
+
+ /*For NXP tuner*/
+
+ /*Set 3.3MHz as default IF frequency */
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+ /* Set reg 0x1E to get the full dynamic range */
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31);
+
+ /* Mode setting in demod */
+ reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42);
+ reg |= 0x80;
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg);
+ /* Serial mode */
+
+ /* Soft Reset chip */
+
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+
+ return 0;
+}
+
+static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ return 0;
+}
+
+static int s5h1432_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ return 0;
+}
+
+static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ return 0;
+}
+
+static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+
+ return 0;
+}
+
+static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ return 0;
+}
+
+static int s5h1432_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ return 0;
+}
+
+static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ return 0;
+}
+
+static void s5h1432_release(struct dvb_frontend *fe)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1432_ops;
+
+struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct s5h1432_state *state = NULL;
+
+ printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n");
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->current_modulation = QAM_16;
+ state->inversion = state->config->inversion;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s5h1432_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(s5h1432_attach);
+
+static struct dvb_frontend_ops s5h1432_ops = {
+
+ .info = {
+ .name = "Samsung s5h1432 DVB-T Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 177000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166666,
+ .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_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER},
+
+ .init = s5h1432_init,
+ .sleep = s5h1432_sleep,
+ .set_frontend = s5h1432_set_frontend,
+ .get_frontend = s5h1432_get_frontend,
+ .get_tune_settings = s5h1432_get_tune_settings,
+ .read_status = s5h1432_read_status,
+ .read_ber = s5h1432_read_ber,
+ .read_signal_strength = s5h1432_read_signal_strength,
+ .read_snr = s5h1432_read_snr,
+ .read_ucblocks = s5h1432_read_ucblocks,
+ .release = s5h1432_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver");
+MODULE_AUTHOR("Bill Liu");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s5h1432.h b/drivers/media/dvb/frontends/s5h1432.h
new file mode 100644
index 000000000000..b57438c32546
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1432.h
@@ -0,0 +1,91 @@
+/*
+ * Samsung s5h1432 VSB/QAM demodulator driver
+ *
+ * Copyright (C) 2009 Bill Liu
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __S5H1432_H__
+#define __S5H1432_H__
+
+#include
+
+#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
+
+#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000
+#define EUROPE_HI_IF_FREQ_36_MHZ 36000000
+#define IF_FREQ_6_MHZ 6000000
+#define IF_FREQ_3point3_MHZ 3300000
+#define IF_FREQ_3point5_MHZ 3500000
+#define IF_FREQ_4_MHZ 4000000
+
+struct s5h1432_config {
+
+ /* serial/parallel output */
+#define S5H1432_PARALLEL_OUTPUT 0
+#define S5H1432_SERIAL_OUTPUT 1
+ u8 output_mode;
+
+ /* GPIO Setting */
+#define S5H1432_GPIO_OFF 0
+#define S5H1432_GPIO_ON 1
+ u8 gpio;
+
+ /* MPEG signal timing */
+#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
+#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
+#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
+#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+ u16 mpeg_timing;
+
+ /* IF Freq for QAM and VSB in KHz */
+#define S5H1432_IF_3250 3250
+#define S5H1432_IF_3500 3500
+#define S5H1432_IF_4000 4000
+#define S5H1432_IF_5380 5380
+#define S5H1432_IF_44000 44000
+#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000
+#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000
+ u16 qam_if;
+ u16 vsb_if;
+
+ /* Spectral Inversion */
+#define S5H1432_INVERSION_OFF 0
+#define S5H1432_INVERSION_ON 1
+ u8 inversion;
+
+ /* Return lock status based on tuner lock, or demod lock */
+#define S5H1432_TUNERLOCKING 0
+#define S5H1432_DEMODLOCKING 1
+ u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1432) || \
+ (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config
+ *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_s5h1432 */
+
+#endif /* __s5h1432_H__ */
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
index d21a327db629..4b0c99a08a85 100644
--- a/drivers/media/dvb/frontends/si21xx.c
+++ b/drivers/media/dvb/frontends/si21xx.c
@@ -268,7 +268,7 @@ static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct si21xx_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
index f73c13323e90..80a9e4cba631 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb/frontends/stb6100.c
@@ -506,7 +506,7 @@ static struct dvb_tuner_ops stb6100_ops = {
};
struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
- struct stb6100_config *config,
+ const struct stb6100_config *config,
struct i2c_adapter *i2c)
{
struct stb6100_state *state = NULL;
diff --git a/drivers/media/dvb/frontends/stb6100.h b/drivers/media/dvb/frontends/stb6100.h
index 395d056599a6..2ab096614b3f 100644
--- a/drivers/media/dvb/frontends/stb6100.h
+++ b/drivers/media/dvb/frontends/stb6100.h
@@ -97,13 +97,13 @@ struct stb6100_state {
#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
- struct stb6100_config *config,
+ const struct stb6100_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
- struct stb6100_config *config,
+ const struct stb6100_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
index 2930a5d6768a..63db8fd2754c 100644
--- a/drivers/media/dvb/frontends/stv0288.c
+++ b/drivers/media/dvb/frontends/stv0288.c
@@ -6,6 +6,8 @@
Copyright (C) 2008 Igor M. Liplianin
Removed stb6000 specific tuner code and revised some
procedures.
+ 2010-09-01 Josef Pavlik
+ Fixed diseqc_msg, diseqc_burst and set_tone problems
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
@@ -78,7 +80,7 @@ static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct stv0288_state *state = fe->demodulator_priv;
@@ -156,14 +158,13 @@ static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
stv0288_writeregI(state, 0x09, 0);
msleep(30);
- stv0288_writeregI(state, 0x05, 0x16);
+ stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
for (i = 0; i < m->msg_len; i++) {
if (stv0288_writeregI(state, 0x06, m->msg[i]))
return -EREMOTEIO;
- msleep(12);
}
-
+ msleep(m->msg_len*12);
return 0;
}
@@ -174,13 +175,14 @@ static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
dprintk("%s\n", __func__);
- if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
+ if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
return -EREMOTEIO;
if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
return -EREMOTEIO;
- if (stv0288_writeregI(state, 0x06, 0x12))
+ msleep(15);
+ if (stv0288_writeregI(state, 0x05, 0x12))
return -EREMOTEIO;
return 0;
@@ -192,18 +194,19 @@ static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
- if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
+ if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
return -EREMOTEIO;
- return stv0288_writeregI(state, 0x06, 0xff);
+ break;
case SEC_TONE_OFF:
- if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
+ if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
return -EREMOTEIO;
- return stv0288_writeregI(state, 0x06, 0x00);
+ break;
default:
return -EINVAL;
}
+ return 0;
}
static u8 stv0288_inittab[] = {
@@ -486,7 +489,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
tda[2] = 0x0; /* CFRL */
for (tm = -6; tm < 7;) {
/* Viterbi status */
- if (stv0288_readreg(state, 0x24) & 0x80)
+ if (stv0288_readreg(state, 0x24) & 0x8)
break;
tda[2] += 40;
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 968874469726..4e3db3a42e06 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
{
struct stv0299_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 0fd96e22b650..ba219b767a69 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -65,7 +65,7 @@ struct stv0299_config
* First of each pair is the register, second is the value.
* List should be terminated with an 0xff, 0xff pair.
*/
- u8* inittab;
+ const u8* inittab;
/* master clock to use */
u32 mclk;
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index f2a8abe0a243..ea485d923550 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -598,7 +598,7 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
-static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
{
struct tda1004x_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 8c612719adfc..adbbf6d3d044 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -64,7 +64,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen)
{
int err, i;
for (i = 0; i < ilen - 1; i++)
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
index 8113b23ce448..22524a8e6f61 100644
--- a/drivers/media/dvb/mantis/mantis_core.c
+++ b/drivers/media/dvb/mantis/mantis_core.c
@@ -91,10 +91,7 @@ static int get_mac_address(struct mantis_pci *mantis)
return err;
}
dprintk(verbose, MANTIS_ERROR, 0,
- " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
- mantis->mac_address[0], mantis->mac_address[1],
- mantis->mac_address[2], mantis->mac_address[3],
- mantis->mac_address[4], mantis->mac_address[5]);
+ " MAC Address=[%pM]\n", mantis->mac_address);
return 0;
}
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
index 7870bcf9689a..e7794517fe26 100644
--- a/drivers/media/dvb/mantis/mantis_i2c.c
+++ b/drivers/media/dvb/mantis/mantis_i2c.c
@@ -229,7 +229,6 @@ int __devinit mantis_i2c_init(struct mantis_pci *mantis)
i2c_set_adapdata(i2c_adapter, mantis);
i2c_adapter->owner = THIS_MODULE;
- i2c_adapter->class = I2C_CLASS_TV_DIGITAL;
i2c_adapter->algo = &mantis_algo;
i2c_adapter->algo_data = NULL;
i2c_adapter->timeout = 500;
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
index de148ded52d8..fe31cfb0b158 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.c
+++ b/drivers/media/dvb/mantis/mantis_ioc.c
@@ -68,14 +68,7 @@ int mantis_get_mac(struct mantis_pci *mantis)
return err;
}
- dprintk(MANTIS_ERROR, 0,
- " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
- mac_addr[0],
- mac_addr[1],
- mac_addr[2],
- mac_addr[3],
- mac_addr[4],
- mac_addr[5]);
+ dprintk(MANTIS_ERROR, 0, " MAC Address=[%pM]\n", mac_addr);
return 0;
}
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c
index 477fe0aade86..c3ae956714e7 100644
--- a/drivers/media/dvb/ngene/ngene-i2c.c
+++ b/drivers/media/dvb/ngene/ngene-i2c.c
@@ -165,7 +165,6 @@ int ngene_i2c_init(struct ngene *dev, int dev_nr)
struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
- adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
strcpy(adap->name, "nGene");
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 1c798219dc7c..6ca6713d527a 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -647,7 +647,6 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
i2c_set_adapdata(&pluto->i2c_adap, pluto);
strcpy(pluto->i2c_adap.name, DRIVER_NAME);
pluto->i2c_adap.owner = THIS_MODULE;
- pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
pluto->i2c_adap.dev.parent = &pdev->dev;
pluto->i2c_adap.algo_data = &pluto->i2c_bit;
pluto->i2c_bit.data = pluto;
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index 69ad94934ec2..0486919c1d0f 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -1087,7 +1087,6 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pt1_update_power(pt1);
i2c_adap = &pt1->i2c_adap;
- i2c_adap->class = I2C_CLASS_TV_DIGITAL;
i2c_adap->algo = &pt1_i2c_algo;
i2c_adap->algo_data = NULL;
i2c_adap->dev.parent = &pdev->dev;
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index ff3b0fa901b3..135e45bd00c7 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -1504,8 +1504,7 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
u32 msgData[3]; /* keep it 3 ! */
} *pMsg;
- if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
- (PinNum > MAX_GPIO_PIN_NUMBER))
+ if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
return -EINVAL;
totalLen = sizeof(struct SmsMsgHdr_ST) +
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index d0e4639ee9db..a27c44a8af5a 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -40,7 +40,7 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
const s32 *samples = (const void *)buf;
for (i = 0; i < len >> 2; i++) {
- struct ir_raw_event ev;
+ DEFINE_IR_RAW_EVENT(ev);
ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
ev.pulse = (samples[i] > 0) ? false : true;
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index a12b88f53ed9..fc0a60f8a1e1 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -2472,7 +2472,6 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
get recognized before the main driver is fully loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);
- av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -2886,7 +2885,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension av7110_extension_driver = {
- .name = "dvb",
+ .name = "av7110",
.flags = SAA7146_USE_I2C_IRQ,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 244d5d51f5f9..952b33dbac4f 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -245,8 +245,11 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
return -1;
}
while (1) {
- if ((len = dvb_ringbuffer_avail(buf)) < 6)
+ len = dvb_ringbuffer_avail(buf);
+ if (len < 6) {
+ wake_up(&buf->queue);
return -1;
+ }
sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24;
sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;
sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index 054661315311..37666d4edab6 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -495,8 +495,6 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
- budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-
strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 4a3f2b8ea37d..40625b26ac10 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1694,7 +1694,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
- ttusb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
ttusb->i2c_adap.dev.parent = &udev->dev;
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 482d0f3be5ff..b701ea6e7c73 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -374,7 +374,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
switch (v->index) {
case 0:
strlcpy(v->name, "FM", sizeof(v->name));
- v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
+ v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_RDS_BLOCK_IO;
v->rangelow = 1400; /* 87.5 MHz */
v->rangehigh = 1728; /* 108.0 MHz */
v->rxsubchans = cadet_getstereo(dev);
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 353b82855949..b540e8072e92 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -176,8 +176,6 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
int retval;
int size;
- BUG_ON(!mutex_is_locked(&radio->lock));
-
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
@@ -207,8 +205,6 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
int size;
unsigned short freq_send = 0x10 + (freq >> 3) / 25;
- BUG_ON(!mutex_is_locked(&radio->lock));
-
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
@@ -253,8 +249,6 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
int retval;
int size;
- BUG_ON(!mutex_is_locked(&radio->lock));
-
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
@@ -290,11 +284,13 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
- radio->usbdev = NULL;
- mutex_unlock(&radio->lock);
-
+ /* increase the device node's refcount */
+ get_device(&radio->videodev.dev);
v4l2_device_disconnect(&radio->v4l2_dev);
video_unregister_device(&radio->videodev);
+ mutex_unlock(&radio->lock);
+ /* decrease the device node's refcount, allowing it to be released */
+ put_device(&radio->videodev.dev);
}
/* vidioc_querycap - query device capabilities */
@@ -503,28 +499,18 @@ out:
static int usb_amradio_open(struct file *file)
{
struct amradio_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
-
- if (!radio->usbdev) {
- retval = -EIO;
- goto unlock;
- }
+ int retval;
file->private_data = radio;
retval = usb_autopm_get_interface(radio->intf);
if (retval)
- goto unlock;
+ return retval;
if (unlikely(!radio->initialized)) {
retval = usb_amradio_init(radio);
if (retval)
usb_autopm_put_interface(radio->intf);
}
-
-unlock:
- mutex_unlock(&radio->lock);
return retval;
}
@@ -532,37 +518,10 @@ unlock:
static int usb_amradio_close(struct file *file)
{
struct amradio_device *radio = file->private_data;
- int retval = 0;
- mutex_lock(&radio->lock);
-
- if (!radio->usbdev)
- retval = -EIO;
- else
+ if (video_is_registered(&radio->videodev))
usb_autopm_put_interface(radio->intf);
-
- mutex_unlock(&radio->lock);
- return retval;
-}
-
-static long usb_amradio_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct amradio_device *radio = file->private_data;
- long retval = 0;
-
- mutex_lock(&radio->lock);
-
- if (!radio->usbdev) {
- retval = -EIO;
- goto unlock;
- }
-
- retval = video_ioctl2(file, cmd, arg);
-
-unlock:
- mutex_unlock(&radio->lock);
- return retval;
+ return 0;
}
/* Suspend device - stop device. Need to be checked and fixed */
@@ -571,15 +530,13 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
-
if (!radio->muted && radio->initialized) {
amradio_set_mute(radio, AMRADIO_STOP);
radio->muted = 0;
}
+ mutex_unlock(&radio->lock);
dev_info(&intf->dev, "going into suspend..\n");
-
- mutex_unlock(&radio->lock);
return 0;
}
@@ -589,7 +546,6 @@ static int usb_amradio_resume(struct usb_interface *intf)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
-
if (unlikely(!radio->initialized))
goto unlock;
@@ -604,9 +560,9 @@ static int usb_amradio_resume(struct usb_interface *intf)
amradio_set_mute(radio, AMRADIO_START);
unlock:
- dev_info(&intf->dev, "coming out of suspend..\n");
-
mutex_unlock(&radio->lock);
+
+ dev_info(&intf->dev, "coming out of suspend..\n");
return 0;
}
@@ -615,7 +571,7 @@ static const struct v4l2_file_operations usb_amradio_fops = {
.owner = THIS_MODULE,
.open = usb_amradio_open,
.release = usb_amradio_close,
- .ioctl = usb_amradio_ioctl,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
@@ -671,19 +627,20 @@ static int usb_amradio_probe(struct usb_interface *intf,
goto err_v4l2;
}
+ mutex_init(&radio->lock);
+
strlcpy(radio->videodev.name, radio->v4l2_dev.name,
sizeof(radio->videodev.name));
radio->videodev.v4l2_dev = &radio->v4l2_dev;
radio->videodev.fops = &usb_amradio_fops;
radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
radio->videodev.release = usb_amradio_video_device_release;
+ radio->videodev.lock = &radio->lock;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
radio->curfreq = 95.16 * FREQ_MUL;
- mutex_init(&radio->lock);
-
video_set_drvdata(&radio->videodev, radio);
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index 13554ab13f76..6a435786b63d 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -291,19 +291,19 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
goto unregister_v4l2_dev;
}
- sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, "si4713_i2c",
+ sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, NULL,
pdata->subdev_board_info, NULL);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
rval = -ENODEV;
- goto unregister_v4l2_dev;
+ goto put_adapter;
}
rsdev->radio_dev = video_device_alloc();
if (!rsdev->radio_dev) {
dev_err(&pdev->dev, "Failed to alloc video device.\n");
rval = -ENOMEM;
- goto unregister_v4l2_dev;
+ goto put_adapter;
}
memcpy(rsdev->radio_dev, &radio_si4713_vdev_template,
@@ -320,6 +320,8 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
free_vdev:
video_device_release(rsdev->radio_dev);
+put_adapter:
+ i2c_put_adapter(adapter);
unregister_v4l2_dev:
v4l2_device_unregister(&rsdev->v4l2_dev);
free_rsdev:
@@ -335,8 +337,12 @@ static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
struct radio_si4713_device *rsdev = container_of(v4l2_dev,
struct radio_si4713_device,
v4l2_dev);
+ struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
+ struct v4l2_subdev, list);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
video_unregister_device(rsdev->radio_dev);
+ i2c_put_adapter(client->adapter);
v4l2_device_unregister(&rsdev->v4l2_dev);
kfree(rsdev);
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 9927a595b426..ac76dfe5b3fa 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -408,17 +408,15 @@ done:
/*
* si470x_rds_on - switch on rds reception
*/
-int si470x_rds_on(struct si470x_device *radio)
+static int si470x_rds_on(struct si470x_device *radio)
{
int retval;
/* sysconfig 1 */
- mutex_lock(&radio->lock);
radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
retval = si470x_set_register(radio, SYSCONFIG1);
if (retval < 0)
radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
- mutex_unlock(&radio->lock);
return retval;
}
@@ -440,6 +438,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
unsigned int block_count = 0;
/* switch on rds reception */
+ mutex_lock(&radio->lock);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio);
@@ -480,9 +479,9 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
buf += 3;
retval += 3;
}
- mutex_unlock(&radio->lock);
done:
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -497,8 +496,11 @@ static unsigned int si470x_fops_poll(struct file *file,
int retval = 0;
/* switch on rds reception */
+
+ mutex_lock(&radio->lock);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio);
+ mutex_unlock(&radio->lock);
poll_wait(file, &radio->read_queue, pts);
@@ -516,7 +518,7 @@ static const struct v4l2_file_operations si470x_fops = {
.owner = THIS_MODULE,
.read = si470x_fops_read,
.poll = si470x_fops_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.open = si470x_fops_open,
.release = si470x_fops_release,
};
@@ -572,6 +574,7 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -594,6 +597,8 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get control failed with %d\n", retval);
+
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -607,6 +612,7 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -633,6 +639,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set control failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -662,6 +669,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -681,7 +689,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->type = V4L2_TUNER_RADIO;
#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_RDS;
+ V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
#else
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
#endif
@@ -737,6 +745,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get tuner failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -750,6 +759,7 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -776,6 +786,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set tuner failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -790,6 +801,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
int retval = 0;
/* safety checks */
+ mutex_lock(&radio->lock);
retval = si470x_disconnect_check(radio);
if (retval)
goto done;
@@ -806,6 +818,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get frequency failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -819,6 +832,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -835,6 +849,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set frequency failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -848,6 +863,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -864,6 +880,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set hardware frequency seek failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 5ec13e50a9f0..392e84fe90ef 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -517,7 +517,7 @@ int si470x_fops_open(struct file *file)
struct si470x_device *radio = video_drvdata(file);
int retval;
- lock_kernel();
+ mutex_lock(&radio->lock);
radio->users++;
retval = usb_autopm_get_interface(radio->intf);
@@ -558,7 +558,7 @@ int si470x_fops_open(struct file *file)
}
done:
- unlock_kernel();
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -577,7 +577,7 @@ int si470x_fops_release(struct file *file)
goto done;
}
- mutex_lock(&radio->disconnect_lock);
+ mutex_lock(&radio->lock);
radio->users--;
if (radio->users == 0) {
/* shutdown interrupt handler */
@@ -591,7 +591,7 @@ int si470x_fops_release(struct file *file)
video_unregister_device(radio->videodev);
kfree(radio->int_in_buffer);
kfree(radio->buffer);
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
kfree(radio);
goto done;
}
@@ -603,7 +603,7 @@ int si470x_fops_release(struct file *file)
retval = si470x_stop(radio);
usb_autopm_put_interface(radio->intf);
}
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
done:
return retval;
}
@@ -661,7 +661,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->disconnected = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
- mutex_init(&radio->disconnect_lock);
mutex_init(&radio->lock);
iface_desc = intf->cur_altsetting;
@@ -830,7 +829,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
{
struct si470x_device *radio = usb_get_intfdata(intf);
- mutex_lock(&radio->disconnect_lock);
+ mutex_lock(&radio->lock);
radio->disconnected = 1;
usb_set_intfdata(intf, NULL);
if (radio->users == 0) {
@@ -843,10 +842,10 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
kfree(radio->int_in_buffer);
video_unregister_device(radio->videodev);
kfree(radio->buffer);
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
kfree(radio);
} else {
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
}
}
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index 3cd0a29cd6e7..ea12782359a0 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -177,7 +177,6 @@ struct si470x_device {
/* driver management */
unsigned char disconnected;
- struct mutex disconnect_lock;
#endif
#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
@@ -221,7 +220,6 @@ int si470x_disconnect_check(struct si470x_device *radio);
int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
int si470x_start(struct si470x_device *radio);
int si470x_stop(struct si470x_device *radio);
-int si470x_rds_on(struct si470x_device *radio);
int si470x_fops_open(struct file *file);
int si470x_fops_release(struct file *file);
int si470x_vidioc_querycap(struct file *file, void *priv,
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index fc7f4b794649..a6e6f1987a3a 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -1804,7 +1804,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
strncpy(vm->name, "FM Modulator", 32);
vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW |
- V4L2_TUNER_CAP_RDS;
+ V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
/* Report current frequency range limits */
vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW);
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 90cae90277e7..7c0d77751f6e 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -22,7 +22,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index d000522cb0f4..ac16e815e275 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -539,7 +539,7 @@ config VIDEO_VIU
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
- depends on (FRAMEBUFFER_CONSOLE || STI_CONSOLE) && FONTS
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
select FONT_8x16
select VIDEOBUF_VMALLOC
default n
@@ -599,68 +599,8 @@ config VIDEO_W9966
Check out for more
information.
-config VIDEO_CPIA
- tristate "CPiA Video For Linux (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca cpia1 module
- instead. Note that you need atleast version 0.6.4 of libv4l for
- the cpia1 gspca module.
-
- This is the video4linux driver for cameras based on Vision's CPiA
- (Colour Processor Interface ASIC), such as the Creative Labs Video
- Blaster Webcam II. If you have one of these cameras, say Y here
- and select parallel port and/or USB lowlevel support below,
- otherwise say N. This will not work with the Creative Webcam III.
-
- Please read for more
- information.
-
- This driver is also available as a module (cpia).
-
-config VIDEO_CPIA_PP
- tristate "CPiA Parallel Port Lowlevel Support"
- depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
- help
- This is the lowlevel parallel port support for cameras based on
- Vision's CPiA (Colour Processor Interface ASIC), such as the
- Creative Webcam II. If you have the parallel port version of one
- of these cameras, say Y here, otherwise say N. It is also available
- as a module (cpia_pp).
-
-config VIDEO_CPIA_USB
- tristate "CPiA USB Lowlevel Support"
- depends on VIDEO_CPIA && USB
- help
- This is the lowlevel USB support for cameras based on Vision's CPiA
- (Colour Processor Interface ASIC), such as the Creative Webcam II.
- If you have the USB version of one of these cameras, say Y here,
- otherwise say N. This will not work with the Creative Webcam III.
- It is also available as a module (cpia_usb).
-
source "drivers/media/video/cpia2/Kconfig"
-config VIDEO_SAA5246A
- tristate "SAA5246A, SAA5281 Teletext processor"
- depends on I2C && VIDEO_V4L2
- help
- Support for I2C bus based teletext using the SAA5246A or SAA5281
- chip. Useful only if you live in Europe.
-
- To compile this driver as a module, choose M here: the
- module will be called saa5246a.
-
-config VIDEO_SAA5249
- tristate "SAA5249 Teletext processor"
- depends on I2C && VIDEO_V4L2
- help
- Support for I2C bus based teletext using the SAA5249 chip. At the
- moment this is only useful on some European WinTV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called saa5249.
-
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -669,14 +609,6 @@ config VIDEO_VINO
Say Y here to build in support for the Vino video input system found
on SGI Indy machines.
-config VIDEO_STRADIS
- tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
- help
- Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
- driver for PCI. There is a product page at
- .
-
source "drivers/media/video/zoran/Kconfig"
config VIDEO_MEYE
@@ -774,6 +706,22 @@ config VIDEO_CAFE_CCIC
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
+config VIDEO_SR030PC30
+ tristate "SR030PC30 VGA camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This driver supports SR030PC30 VGA camera from Siliconfile
+
+config VIDEO_VIA_CAMERA
+ tristate "VIAFB camera controller support"
+ depends on FB_VIA
+ select VIDEOBUF_DMA_SG
+ select VIDEO_OV7670
+ help
+ Driver support for the integrated camera controller in VIA
+ Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
+ with ov7670 sensors.
+
config SOC_CAMERA
tristate "SoC camera support"
depends on VIDEO_V4L2 && HAS_DMA && I2C
@@ -783,6 +731,12 @@ config SOC_CAMERA
over a bus like PCI or USB. For example some i2c camera connected
directly to the data bus of an SoC.
+config SOC_CAMERA_IMX074
+ tristate "imx074 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports IMX074 cameras from Sony
+
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
depends on SOC_CAMERA && I2C
@@ -835,6 +789,12 @@ config SOC_CAMERA_PLATFORM
help
This is a generic SoC camera platform driver, useful for testing
+config SOC_CAMERA_OV6650
+ tristate "ov6650 sensor support"
+ depends on SOC_CAMERA && I2C
+ ---help---
+ This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor
+
config SOC_CAMERA_OV772X
tristate "ov772x camera support"
depends on SOC_CAMERA && I2C
@@ -890,6 +850,14 @@ config VIDEO_SH_MOBILE_CEU
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
+config VIDEO_OMAP1
+ tristate "OMAP1 Camera Interface driver"
+ depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the TI OMAP1 camera interface
+
config VIDEO_OMAP2
tristate "OMAP2 Camera Capture Interface driver"
depends on VIDEO_DEV && ARCH_OMAP2
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 40f98fba5f88..af79d476a4c8 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -33,8 +33,6 @@ obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
-obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
-obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -73,12 +71,15 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
+obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o
obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o
obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o
obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
@@ -93,10 +94,6 @@ obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
obj-$(CONFIG_VIDEO_W9966) += w9966.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_VINO) += vino.o
-obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
-obj-$(CONFIG_VIDEO_CPIA) += cpia.o
-obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
-obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
@@ -125,6 +122,8 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
+obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_SE401) += se401.o
obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
@@ -163,6 +162,7 @@ obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 48e89fbf391b..23ba5c37c3e4 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -34,11 +34,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
@@ -337,9 +335,25 @@ static const struct i2c_device_id adv7170_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adv7170_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "adv7170",
- .probe = adv7170_probe,
- .remove = adv7170_remove,
- .id_table = adv7170_id,
+static struct i2c_driver adv7170_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7170",
+ },
+ .probe = adv7170_probe,
+ .remove = adv7170_remove,
+ .id_table = adv7170_id,
};
+
+static __init int init_adv7170(void)
+{
+ return i2c_add_driver(&adv7170_driver);
+}
+
+static __exit void exit_adv7170(void)
+{
+ i2c_del_driver(&adv7170_driver);
+}
+
+module_init(init_adv7170);
+module_exit(exit_adv7170);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index f1ba0d742c65..f318b51448b3 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -30,11 +30,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
@@ -376,9 +374,25 @@ static const struct i2c_device_id adv7175_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adv7175_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "adv7175",
- .probe = adv7175_probe,
- .remove = adv7175_remove,
- .id_table = adv7175_id,
+static struct i2c_driver adv7175_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7175",
+ },
+ .probe = adv7175_probe,
+ .remove = adv7175_remove,
+ .id_table = adv7175_id,
};
+
+static __init int init_adv7175(void)
+{
+ return i2c_add_driver(&adv7175_driver);
+}
+
+static __exit void exit_adv7175(void)
+{
+ i2c_del_driver(&adv7175_driver);
+}
+
+module_init(init_adv7175);
+module_exit(exit_adv7175);
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index 23e610f62736..d2138d06bcad 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -22,7 +22,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 57dd9195daf5..0453816d4ec3 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "au8522", "au8522", 0x8e >> 1, NULL);
+ NULL, "au8522", 0x8e >> 1, NULL);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.tuner_addr, NULL);
+ NULL, "tuner", dev->board.tuner_addr, NULL);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 7989a7ba7c40..162fd5f9d448 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -965,7 +965,7 @@ static int au0828_v4l2_open(struct file *filp)
NULL, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
- sizeof(struct au0828_buffer), fh);
+ sizeof(struct au0828_buffer), fh, NULL);
/* VBI Setup */
dev->vbi_width = 720;
@@ -974,7 +974,7 @@ static int au0828_v4l2_open(struct file *filp)
NULL, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
- sizeof(struct au0828_buffer), fh);
+ sizeof(struct au0828_buffer), fh, NULL);
return ret;
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 770cb9accf81..c38300fc0b1d 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -33,12 +33,10 @@
#include
#include
#include
-#include
#include
#include
#include
#include
-#include
#include
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
@@ -537,9 +535,25 @@ static const struct i2c_device_id bt819_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bt819_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "bt819",
- .probe = bt819_probe,
- .remove = bt819_remove,
- .id_table = bt819_id,
+static struct i2c_driver bt819_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bt819",
+ },
+ .probe = bt819_probe,
+ .remove = bt819_remove,
+ .id_table = bt819_id,
};
+
+static __init int init_bt819(void)
+{
+ return i2c_add_driver(&bt819_driver);
+}
+
+static __exit void exit_bt819(void)
+{
+ i2c_del_driver(&bt819_driver);
+}
+
+module_init(init_bt819);
+module_exit(exit_bt819);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index ae3337392505..a43059d4c799 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -34,11 +34,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -262,9 +260,25 @@ static const struct i2c_device_id bt856_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bt856_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "bt856",
- .probe = bt856_probe,
- .remove = bt856_remove,
- .id_table = bt856_id,
+static struct i2c_driver bt856_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bt856",
+ },
+ .probe = bt856_probe,
+ .remove = bt856_remove,
+ .id_table = bt856_id,
};
+
+static __init int init_bt856(void)
+{
+ return i2c_add_driver(&bt856_driver);
+}
+
+static __exit void exit_bt856(void)
+{
+ i2c_del_driver(&bt856_driver);
+}
+
+module_init(init_bt856);
+module_exit(exit_bt856);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 62ac422bb159..4e5dcea0501d 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -34,11 +34,9 @@
#include
#include
#include
-#include
#include
#include
#include
-#include
MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -232,9 +230,25 @@ static const struct i2c_device_id bt866_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bt866_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "bt866",
- .probe = bt866_probe,
- .remove = bt866_remove,
- .id_table = bt866_id,
+static struct i2c_driver bt866_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bt866",
+ },
+ .probe = bt866_probe,
+ .remove = bt866_remove,
+ .id_table = bt866_id,
};
+
+static __init int init_bt866(void)
+{
+ return i2c_add_driver(&bt866_driver);
+}
+
+static __exit void exit_bt866(void)
+{
+ i2c_del_driver(&bt866_driver);
+}
+
+module_init(init_bt866);
+module_exit(exit_bt866);
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 7af56cde0c79..87d8b006ef77 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -3529,7 +3529,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs);
+ &btv->c.i2c_adap, NULL, "saa6588", 0, addrs);
btv->has_saa6588 = (sd != NULL);
}
@@ -3554,7 +3554,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs);
+ &btv->c.i2c_adap, NULL, "msp3400", 0, addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
@@ -3568,7 +3568,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+ &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
return;
goto no_audio;
}
@@ -3576,7 +3576,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
case 3: {
/* The user specified that we should probe for tvaudio */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
@@ -3596,11 +3596,11 @@ void __devinit bttv_init_card2(struct bttv *btv)
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400",
+ &btv->c.i2c_adap, NULL, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400",
+ &btv->c.i2c_adap, NULL, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
}
@@ -3616,13 +3616,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+ &btv->c.i2c_adap, NULL, "tda7432", 0, addrs))
return;
}
/* Now see if we can find one of the tvaudio devices. */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, NULL, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
@@ -3646,13 +3646,13 @@ void __devinit bttv_init_tuner(struct bttv *btv)
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, NULL, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 38c7f78ad9cf..3da6e80e1041 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -842,7 +842,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(int id)
RESOURCE_OVERLAY)
static
-int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
+int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
{
int xbits; /* mutual exclusive resources */
@@ -935,7 +935,7 @@ disclaim_video_lines(struct bttv *btv)
}
static
-void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
+void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
{
if ((fh->resources & bits) != bits) {
/* trying to free ressources not allocated by us ... */
@@ -1682,7 +1682,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
kfree(old);
}
if (NULL == new)
- free_btres(btv,fh,RESOURCE_OVERLAY);
+ free_btres_lock(btv,fh,RESOURCE_OVERLAY);
dprintk("switch_overlay: done\n");
return retval;
}
@@ -1859,21 +1859,25 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
unsigned int i;
int err;
+ mutex_lock(&btv->lock);
err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
+ if (err)
+ goto err;
for (i = 0; i < BTTV_TVNORMS; i++)
if (*id & bttv_tvnorms[i].v4l2_id)
break;
- if (i == BTTV_TVNORMS)
- return -EINVAL;
+ if (i == BTTV_TVNORMS) {
+ err = -EINVAL;
+ goto err;
+ }
- mutex_lock(&btv->lock);
set_tvnorm(btv, i);
+
+err:
mutex_unlock(&btv->lock);
- return 0;
+ return err;
}
static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
@@ -1893,10 +1897,13 @@ static int bttv_enum_input(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- int n;
+ int rc = 0;
- if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
+ mutex_lock(&btv->lock);
+ if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
+ rc = -EINVAL;
+ goto err;
+ }
i->type = V4L2_INPUT_TYPE_CAMERA;
i->audioset = 1;
@@ -1919,10 +1926,12 @@ static int bttv_enum_input(struct file *file, void *priv,
i->status |= V4L2_IN_ST_NO_H_LOCK;
}
- for (n = 0; n < BTTV_TVNORMS; n++)
- i->std |= bttv_tvnorms[n].v4l2_id;
+ i->std = BTTV_NORMS;
- return 0;
+err:
+ mutex_unlock(&btv->lock);
+
+ return rc;
}
static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
@@ -1930,7 +1939,10 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
+ mutex_lock(&btv->lock);
*i = btv->input;
+ mutex_unlock(&btv->lock);
+
return 0;
}
@@ -1941,15 +1953,19 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
int err;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
-
- if (i > bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
-
mutex_lock(&btv->lock);
+ err = v4l2_prio_check(&btv->prio, fh->prio);
+ if (unlikely(err))
+ goto err;
+
+ if (i > bttv_tvcards[btv->c.type].video_inputs) {
+ err = -EINVAL;
+ goto err;
+ }
+
set_input(btv, i, btv->tvnorm);
+
+err:
mutex_unlock(&btv->lock);
return 0;
}
@@ -1961,22 +1977,25 @@ static int bttv_s_tuner(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int err;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
-
- if (btv->tuner_type == TUNER_ABSENT)
- return -EINVAL;
-
- if (0 != t->index)
+ if (unlikely(0 != t->index))
return -EINVAL;
mutex_lock(&btv->lock);
+ if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = v4l2_prio_check(&btv->prio, fh->prio);
+ if (unlikely(err))
+ goto err;
+
bttv_call_all(btv, tuner, s_tuner, t);
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 1);
+err:
mutex_unlock(&btv->lock);
return 0;
@@ -1988,8 +2007,10 @@ static int bttv_g_frequency(struct file *file, void *priv,
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
+ mutex_lock(&btv->lock);
f->type = btv->radio_user ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = btv->freq;
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -2001,21 +2022,26 @@ static int bttv_s_frequency(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int err;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
-
if (unlikely(f->tuner != 0))
return -EINVAL;
- if (unlikely(f->type != (btv->radio_user
- ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV)))
- return -EINVAL;
+
mutex_lock(&btv->lock);
+ err = v4l2_prio_check(&btv->prio, fh->prio);
+ if (unlikely(err))
+ goto err;
+
+ if (unlikely(f->type != (btv->radio_user
+ ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {
+ err = -EINVAL;
+ goto err;
+ }
btv->freq = f->frequency;
bttv_call_all(btv, tuner, s_frequency, f);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv, btv->freq);
+err:
mutex_unlock(&btv->lock);
+
return 0;
}
@@ -2124,7 +2150,7 @@ bttv_crop_adjust (struct bttv_crop * c,
also adjust the current cropping parameters to get closer to the
desired image size. */
static int
-limit_scaled_size (struct bttv_fh * fh,
+limit_scaled_size_lock (struct bttv_fh * fh,
__s32 * width,
__s32 * height,
enum v4l2_field field,
@@ -2238,7 +2264,7 @@ limit_scaled_size (struct bttv_fh * fh,
may also adjust the current cropping parameters to get closer
to the desired window size. */
static int
-verify_window (struct bttv_fh * fh,
+verify_window_lock (struct bttv_fh * fh,
struct v4l2_window * win,
int adjust_size,
int adjust_crop)
@@ -2257,7 +2283,9 @@ verify_window (struct bttv_fh * fh,
if (V4L2_FIELD_ANY == field) {
__s32 height2;
+ mutex_lock(&fh->btv->lock);
height2 = fh->btv->crop[!!fh->do_crop].rect.height >> 1;
+ mutex_unlock(&fh->btv->lock);
field = (win->w.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_TOP;
@@ -2292,7 +2320,7 @@ verify_window (struct bttv_fh * fh,
win->w.width -= win->w.left & ~width_mask;
win->w.left = (win->w.left - width_mask - 1) & width_mask;
- rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+ rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height,
field, width_mask,
/* width_bias: round down */ 0,
adjust_size, adjust_crop);
@@ -2303,7 +2331,7 @@ verify_window (struct bttv_fh * fh,
return 0;
}
-static int setup_window(struct bttv_fh *fh, struct bttv *btv,
+static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_window *win, int fixup)
{
struct v4l2_clip *clips = NULL;
@@ -2313,7 +2341,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- retval = verify_window(fh, win,
+ retval = verify_window_lock(fh, win,
/* adjust_size */ fixup,
/* adjust_crop */ fixup);
if (0 != retval)
@@ -2332,6 +2360,8 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EFAULT;
}
}
+
+ mutex_lock(&fh->cap.vb_lock);
/* clip against screen */
if (NULL != btv->fbuf.base)
n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
@@ -2354,7 +2384,6 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
BUG();
}
- mutex_lock(&fh->cap.vb_lock);
kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = n;
@@ -2362,6 +2391,14 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
fh->ov.w = win->w;
fh->ov.field = win->field;
fh->ov.setup_ok = 1;
+
+ /*
+ * FIXME: btv is protected by btv->lock mutex, while btv->init
+ * is protected by fh->cap.vb_lock. This seems to open the
+ * possibility for some race situations. Maybe the better would
+ * be to unify those locks or to use another way to store the
+ * init values that will be consumed by videobuf callbacks
+ */
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
btv->init.ov.field = win->field;
@@ -2490,7 +2527,9 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
if (V4L2_FIELD_ANY == field) {
__s32 height2;
+ mutex_lock(&btv->lock);
height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
+ mutex_unlock(&btv->lock);
field = (f->fmt.pix.height > height2)
? V4L2_FIELD_INTERLACED
: V4L2_FIELD_BOTTOM;
@@ -2516,7 +2555,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
width = f->fmt.pix.width;
height = f->fmt.pix.height;
- rc = limit_scaled_size(fh, &width, &height, field,
+ rc = limit_scaled_size_lock(fh, &width, &height, field,
/* width_mask: 4 pixels */ ~3,
/* width_bias: nearest */ 2,
/* adjust_size */ 1,
@@ -2536,7 +2575,7 @@ static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
- return verify_window(fh, &f->fmt.win,
+ return verify_window_lock(fh, &f->fmt.win,
/* adjust_size */ 1,
/* adjust_crop */ 0);
}
@@ -2563,7 +2602,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
height = f->fmt.pix.height;
field = f->fmt.pix.field;
- retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+ retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
/* width_mask: 4 pixels */ ~3,
/* width_bias: nearest */ 2,
/* adjust_size */ 1,
@@ -2601,7 +2640,7 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
return -EINVAL;
}
- return setup_window(fh, btv, &f->fmt.win, 1);
+ return setup_window_lock(fh, btv, &f->fmt.win, 1);
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -2651,11 +2690,15 @@ static int bttv_querycap(struct file *file, void *priv,
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
- if (btv->has_saa6588)
- cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+ /*
+ * No need to lock here: those vars are initialized during board
+ * probe and remains untouched during the rest of the driver lifecycle
+ */
+ if (btv->has_saa6588)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (btv->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
@@ -2730,19 +2773,25 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
struct bttv_buffer *new;
- int retval;
+ int retval = 0;
if (on) {
+ mutex_lock(&fh->cap.vb_lock);
/* verify args */
- if (NULL == btv->fbuf.base)
- return -EINVAL;
- if (!fh->ov.setup_ok) {
- dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
+ if (unlikely(!btv->fbuf.base)) {
+ mutex_unlock(&fh->cap.vb_lock);
return -EINVAL;
}
+ if (unlikely(!fh->ov.setup_ok)) {
+ dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
+ retval = -EINVAL;
+ }
+ if (retval)
+ return retval;
+ mutex_unlock(&fh->cap.vb_lock);
}
- if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+ if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
return -EBUSY;
mutex_lock(&fh->cap.vb_lock);
@@ -2785,7 +2834,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
__s32 width = fb->fmt.width;
__s32 height = fb->fmt.height;
- retval = limit_scaled_size(fh, &width, &height,
+ retval = limit_scaled_size_lock(fh, &width, &height,
V4L2_FIELD_INTERLACED,
/* width_mask */ ~3,
/* width_bias */ 2,
@@ -2852,7 +2901,7 @@ static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
struct bttv *btv = fh->btv;
int res = bttv_resource(fh);
- if (!check_alloc_btres(btv, fh, res))
+ if (!check_alloc_btres_lock(btv, fh, res))
return -EBUSY;
return videobuf_qbuf(bttv_queue(fh), b);
@@ -2872,7 +2921,7 @@ static int bttv_streamon(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int res = bttv_resource(fh);
- if (!check_alloc_btres(btv, fh, res))
+ if (!check_alloc_btres_lock(btv, fh, res))
return -EBUSY;
return videobuf_streamon(bttv_queue(fh));
}
@@ -2890,7 +2939,7 @@ static int bttv_streamoff(struct file *file, void *priv,
retval = videobuf_streamoff(bttv_queue(fh));
if (retval < 0)
return retval;
- free_btres(btv, fh, res);
+ free_btres_lock(btv, fh, res);
return 0;
}
@@ -2907,6 +2956,7 @@ static int bttv_queryctrl(struct file *file, void *priv,
c->id >= V4L2_CID_PRIVATE_LASTP1))
return -EINVAL;
+ mutex_lock(&btv->lock);
if (!btv->volume_gpio && (c->id == V4L2_CID_AUDIO_VOLUME))
*c = no_ctl;
else {
@@ -2914,6 +2964,7 @@ static int bttv_queryctrl(struct file *file, void *priv,
*c = (NULL != ctrl) ? *ctrl : no_ctl;
}
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -2924,8 +2975,11 @@ static int bttv_g_parm(struct file *file, void *f,
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
+ mutex_lock(&btv->lock);
v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
&parm->parm.capture.timeperframe);
+ mutex_unlock(&btv->lock);
+
return 0;
}
@@ -2961,7 +3015,9 @@ static int bttv_g_priority(struct file *file, void *f, enum v4l2_priority *p)
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
+ mutex_lock(&btv->lock);
*p = v4l2_prio_max(&btv->prio);
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -2971,8 +3027,13 @@ static int bttv_s_priority(struct file *file, void *f,
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
+ int rc;
- return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+ mutex_lock(&btv->lock);
+ rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
+ mutex_unlock(&btv->lock);
+
+ return rc;
}
static int bttv_cropcap(struct file *file, void *priv,
@@ -2985,7 +3046,9 @@ static int bttv_cropcap(struct file *file, void *priv,
cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
+ mutex_lock(&btv->lock);
*cap = bttv_tvnorms[btv->tvnorm].cropcap;
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -3003,7 +3066,9 @@ static int bttv_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
inconsistent with fh->width or fh->height and apps
do not expect a change here. */
+ mutex_lock(&btv->lock);
crop->c = btv->crop[!!fh->do_crop].rect;
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -3024,14 +3089,15 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
- retval = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != retval)
- return retval;
-
/* Make sure tvnorm, vbi_end and the current cropping
parameters remain consistent until we're done. Note
- read() may change vbi_end in check_alloc_btres(). */
+ read() may change vbi_end in check_alloc_btres_lock(). */
mutex_lock(&btv->lock);
+ retval = v4l2_prio_check(&btv->prio, fh->prio);
+ if (0 != retval) {
+ mutex_unlock(&btv->lock);
+ return retval;
+ }
retval = -EBUSY;
@@ -3128,17 +3194,17 @@ static ssize_t bttv_read(struct file *file, char __user *data,
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+ if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {
/* VIDEO_READ in use by another fh,
or VIDEO_STREAM by any fh. */
return -EBUSY;
}
retval = videobuf_read_one(&fh->cap, data, count, ppos,
file->f_flags & O_NONBLOCK);
- free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
+ free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+ if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
return -EBUSY;
retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
file->f_flags & O_NONBLOCK);
@@ -3157,20 +3223,19 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
unsigned int rc = POLLERR;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
- if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+ if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
return POLLERR;
return videobuf_poll_stream(file, &fh->vbi, wait);
}
+ mutex_lock(&fh->cap.vb_lock);
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
- mutex_lock(&fh->cap.vb_lock);
/* streaming capture */
if (list_empty(&fh->cap.stream))
goto err;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
- mutex_lock(&fh->cap.vb_lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
@@ -3188,7 +3253,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- mutex_unlock(&fh->cap.vb_lock);
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
@@ -3221,21 +3285,32 @@ static int bttv_open(struct file *file)
return -ENODEV;
}
- lock_kernel();
-
dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
btv->c.nr,v4l2_type_names[type]);
/* allocate per filehandle data */
- fh = kmalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (unlikely(!fh))
return -ENOMEM;
- }
file->private_data = fh;
+
+ /*
+ * btv is protected by btv->lock mutex, while btv->init and other
+ * streaming vars are protected by fh->cap.vb_lock. We need to take
+ * care of both locks to avoid troubles. However, vb_lock is used also
+ * inside videobuf, without calling buf->lock. So, it is a very bad
+ * idea to hold both locks at the same time.
+ * Let's first copy btv->init at fh, holding cap.vb_lock, and then work
+ * with the rest of init, holding btv->lock.
+ */
+ mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
+ mutex_unlock(&fh->cap.vb_lock);
+
fh->type = type;
fh->ov.setup_ok = 0;
+
+ mutex_lock(&btv->lock);
v4l2_prio_open(&btv->prio, &fh->prio);
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
@@ -3243,13 +3318,13 @@ static int bttv_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
- fh);
+ fh, NULL);
videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct bttv_buffer),
- fh);
+ fh, NULL);
set_tvnorm(btv,btv->tvnorm);
set_input(btv, btv->input, btv->tvnorm);
@@ -3272,7 +3347,7 @@ static int bttv_open(struct file *file)
bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
bttv_field_count(btv);
- unlock_kernel();
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -3281,6 +3356,7 @@ static int bttv_release(struct file *file)
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
+ mutex_lock(&btv->lock);
/* turn off overlay */
if (check_btres(fh, RESOURCE_OVERLAY))
bttv_switch_overlay(btv,fh,NULL);
@@ -3288,25 +3364,32 @@ static int bttv_release(struct file *file)
/* stop video capture */
if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
- free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
+ free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);
}
if (fh->cap.read_buf) {
buffer_release(&fh->cap,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
if (check_btres(fh, RESOURCE_VIDEO_READ)) {
- free_btres(btv, fh, RESOURCE_VIDEO_READ);
+ free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);
}
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
videobuf_stop(&fh->vbi);
- free_btres(btv,fh,RESOURCE_VBI);
+ free_btres_lock(btv,fh,RESOURCE_VBI);
}
/* free stuff */
+
+ /*
+ * videobuf uses cap.vb_lock - we should avoid holding btv->lock,
+ * otherwise we may have dead lock conditions
+ */
+ mutex_unlock(&btv->lock);
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
+ mutex_lock(&btv->lock);
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
kfree(fh);
@@ -3316,6 +3399,7 @@ static int bttv_release(struct file *file)
if (!btv->users)
audio_mute(btv, 1);
+ mutex_unlock(&btv->lock);
return 0;
}
@@ -3333,13 +3417,13 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
static const struct v4l2_file_operations bttv_fops =
{
- .owner = THIS_MODULE,
- .open = bttv_open,
- .release = bttv_release,
- .ioctl = video_ioctl2,
- .read = bttv_read,
- .mmap = bttv_mmap,
- .poll = bttv_poll,
+ .owner = THIS_MODULE,
+ .open = bttv_open,
+ .release = bttv_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = bttv_read,
+ .mmap = bttv_mmap,
+ .poll = bttv_poll,
};
static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
@@ -3412,21 +3496,19 @@ static int radio_open(struct file *file)
dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));
- lock_kernel();
-
dprintk("bttv%d: open called (radio)\n",btv->c.nr);
/* allocate per filehandle data */
fh = kmalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ if (unlikely(!fh))
return -ENOMEM;
- }
file->private_data = fh;
+ mutex_lock(&fh->cap.vb_lock);
*fh = btv->init;
- v4l2_prio_open(&btv->prio, &fh->prio);
+ mutex_unlock(&fh->cap.vb_lock);
mutex_lock(&btv->lock);
+ v4l2_prio_open(&btv->prio, &fh->prio);
btv->radio_user++;
@@ -3434,7 +3516,6 @@ static int radio_open(struct file *file)
audio_input(btv,TVAUDIO_INPUT_RADIO);
mutex_unlock(&btv->lock);
- unlock_kernel();
return 0;
}
@@ -3444,6 +3525,7 @@ static int radio_release(struct file *file)
struct bttv *btv = fh->btv;
struct rds_command cmd;
+ mutex_lock(&btv->lock);
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
kfree(fh);
@@ -3451,6 +3533,7 @@ static int radio_release(struct file *file)
btv->radio_user--;
bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
+ mutex_unlock(&btv->lock);
return 0;
}
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 685d6597ee79..d49b675045fe 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -121,9 +121,8 @@ bttv_i2c_wait_done(struct bttv *btv)
/* timeout */
if (wait_event_interruptible_timeout(btv->i2c_queue,
- btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
-
- rc = -EIO;
+ btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
+ rc = -EIO;
if (btv->i2c_done & BT848_INT_RACK)
rc = 1;
@@ -390,41 +389,3 @@ int __devinit init_bttv_i2c(struct bttv *btv)
return btv->i2c_rc;
}
-
-/* Instantiate the I2C IR receiver device, if present */
-void __devinit init_bttv_i2c_ir(struct bttv *btv)
-{
- if (0 == btv->i2c_rc) {
- struct i2c_board_info info;
- /* The external IR receiver is at i2c address 0x34 (0x35 for
- reads). Future Hauppauge cards will have an internal
- receiver at 0x30 (0x31 for reads). In theory, both can be
- fitted, and Hauppauge suggest an external overrides an
- internal.
-
- That's why we probe 0x1a (~0x34) first. CB
- */
- const unsigned short addr_list[] = {
- 0x1a, 0x18, 0x4b, 0x64, 0x30, 0x71,
- I2C_CLIENT_END
- };
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
- }
-}
-
-int __devexit fini_bttv_i2c(struct bttv *btv)
-{
- if (0 != btv->i2c_rc)
- return 0;
-
- return i2c_del_adapter(&btv->c.i2c_adap);
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index f68717a4bdec..6bf05a7dc5f9 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -245,6 +245,83 @@ 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)
+{
+ unsigned char b;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ dprintk(KERN_INFO DEVNAME ": read error\n");
+ return -EIO;
+ }
+
+ /* ignore 0xaa */
+ if (b==0xaa)
+ return 0;
+ dprintk(KERN_INFO DEVNAME ": key %02x\n", b);
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+/* Instantiate the I2C IR receiver device, if present */
+void __devinit init_bttv_i2c_ir(struct bttv *btv)
+{
+ const unsigned short addr_list[] = {
+ 0x1a, 0x18, 0x64, 0x30, 0x71,
+ I2C_CLIENT_END
+ };
+ struct i2c_board_info info;
+
+ if (0 != btv->i2c_rc)
+ return;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&btv->init_data, 0, sizeof(btv->init_data));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+ switch (btv->c.type) {
+ case BTTV_BOARD_PV951:
+ btv->init_data.name = "PV951";
+ btv->init_data.get_key = get_key_pv951;
+ btv->init_data.ir_codes = RC_MAP_PV951;
+ btv->init_data.type = IR_TYPE_OTHER;
+ info.addr = 0x4b;
+ break;
+ default:
+ /*
+ * The external IR receiver is at i2c address 0x34 (0x35 for
+ * reads). Future Hauppauge cards will have an internal
+ * receiver at 0x30 (0x31 for reads). In theory, both can be
+ * fitted, and Hauppauge suggest an external overrides an
+ * internal.
+ * That's why we probe 0x1a (~0x34) first. CB
+ */
+
+ i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
+ return;
+ }
+
+ if (btv->init_data.name)
+ info.platform_data = &btv->init_data;
+ i2c_new_device(&btv->c.i2c_adap, &info);
+
+ return;
+}
+
+int __devexit fini_bttv_i2c(struct bttv *btv)
+{
+ if (0 != btv->i2c_rc)
+ return 0;
+
+ return i2c_del_adapter(&btv->c.i2c_adap);
+}
+
int bttv_input_init(struct bttv *btv)
{
struct card_ir *ir;
@@ -420,10 +497,3 @@ void bttv_input_fini(struct bttv *btv)
kfree(btv->remote);
btv->remote = NULL;
}
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index 0fa9f39f37a3..9b57d091da48 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -582,7 +582,7 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
+ videobuf_waiton(q, &buf->vb, 0, 0);
videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(btv->c.pci,&buf->bottom);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 3ec2402c6b4a..6fd2a8ebda1e 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -18,7 +18,6 @@
#include
#include
#include
-#include
#include
#include
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 6cccc2a17eee..d1e26a448ed2 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -42,7 +42,7 @@
#include
#include
#include
-
+#include
#include "bt848.h"
#include "bttv.h"
@@ -270,6 +270,12 @@ int bttv_sub_del_devices(struct bttv_core *core);
extern int no_overlay;
+/* ---------------------------------------------------------- */
+/* bttv-input.c */
+
+extern void init_bttv_i2c_ir(struct bttv *btv);
+extern int fini_bttv_i2c(struct bttv *btv);
+
/* ---------------------------------------------------------- */
/* bttv-driver.c */
@@ -279,8 +285,6 @@ extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
extern int init_bttv_i2c(struct bttv *btv);
-extern void init_bttv_i2c_ir(struct bttv *btv);
-extern int fini_bttv_i2c(struct bttv *btv);
#define bttv_printk if (bttv_verbose) printk
#define dprintk if (bttv_debug >= 1) printk
@@ -366,6 +370,9 @@ struct bttv {
int has_remote;
struct card_ir *remote;
+ /* I2C remote data */
+ struct IR_i2c_init_data init_data;
+
/* locking */
spinlock_t s_lock;
struct mutex lock;
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 9536f1a40dd2..2934770dacc3 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -46,6 +47,7 @@
#include
#include
+#include "ov7670.h"
#include "cafe_ccic-regs.h"
#define CAFE_VERSION 0x000002
@@ -180,6 +182,7 @@ struct cafe_camera
/* Current operating parameters */
u32 sensor_type; /* Currently ov7670 only */
struct v4l2_pix_format pix_format;
+ enum v4l2_mbus_pixelcode mbus_code;
/* Locks */
struct mutex s_mutex; /* Access to this structure */
@@ -207,6 +210,49 @@ static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
return container_of(dev, struct cafe_camera, v4l2_dev);
}
+static struct cafe_format_struct {
+ __u8 *desc;
+ __u32 pixelformat;
+ int bpp; /* Bytes per pixel */
+ enum v4l2_mbus_pixelcode mbus_code;
+} cafe_formats[] = {
+ {
+ .desc = "YUYV 4:2:2",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .bpp = 2,
+ },
+ {
+ .desc = "RGB 444",
+ .pixelformat = V4L2_PIX_FMT_RGB444,
+ .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .bpp = 2,
+ },
+ {
+ .desc = "RGB 565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .bpp = 2,
+ },
+ {
+ .desc = "Raw RGB Bayer",
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .bpp = 1
+ },
+};
+#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats)
+
+static struct cafe_format_struct *cafe_find_format(u32 pixelformat)
+{
+ unsigned i;
+
+ for (i = 0; i < N_CAFE_FMTS; i++)
+ if (cafe_formats[i].pixelformat == pixelformat)
+ return cafe_formats + i;
+ /* Not found? Then return the first format. */
+ return cafe_formats;
+}
/*
* Start over with DMA buffers - dev_lock needed.
@@ -319,7 +365,6 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
{
unsigned int rval;
unsigned long flags;
- DEFINE_WAIT(the_wait);
spin_lock_irqsave(&cam->dev_lock, flags);
rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
@@ -334,28 +379,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
cafe_reg_write(cam, REG_TWSIC1, rval);
spin_unlock_irqrestore(&cam->dev_lock, flags);
- /*
- * Time to wait for the write to complete. THIS IS A RACY
- * WAY TO DO IT, but the sad fact is that reading the TWSIC1
- * register too quickly after starting the operation sends
- * the device into a place that may be kinder and better, but
- * which is absolutely useless for controlling the sensor. In
- * practice we have plenty of time to get into our sleep state
- * before the interrupt hits, and the worst case is that we
- * time out and then see that things completed, so this seems
- * the best way for now.
+ /* Unfortunately, reading TWSIC1 too soon after sending a command
+ * causes the device to die.
+ * Use a busy-wait because we often send a large quantity of small
+ * commands at-once; using msleep() would cause a lot of context
+ * switches which take longer than 2ms, resulting in a noticable
+ * boot-time and capture-start delays.
*/
- do {
- prepare_to_wait(&cam->smbus_wait, &the_wait,
- TASK_UNINTERRUPTIBLE);
- schedule_timeout(1); /* even 1 jiffy is too long */
- finish_wait(&cam->smbus_wait, &the_wait);
- } while (!cafe_smbus_write_done(cam));
+ mdelay(2);
-#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
+ /*
+ * Another sad fact is that sometimes, commands silently complete but
+ * cafe_smbus_write_done() never becomes aware of this.
+ * This happens at random and appears to possible occur with any
+ * command.
+ * We don't understand why this is. We work around this issue
+ * with the timeout in the wait below, assuming that all commands
+ * complete within the timeout.
+ */
wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
CAFE_SMBUS_TIMEOUT);
-#endif
+
spin_lock_irqsave(&cam->dev_lock, flags);
rval = cafe_reg_read(cam, REG_TWSIC1);
spin_unlock_irqrestore(&cam->dev_lock, flags);
@@ -812,15 +856,15 @@ static int cafe_cam_set_flip(struct cafe_camera *cam)
static int cafe_cam_configure(struct cafe_camera *cam)
{
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
if (cam->state != S_IDLE)
return -EINVAL;
- fmt.fmt.pix = cam->pix_format;
+ v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
ret = sensor_call(cam, core, init, 0);
if (ret == 0)
- ret = sensor_call(cam, video, s_fmt, &fmt);
+ ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
/*
* OV7670 does weird things if flip is set *before* format...
*/
@@ -1481,7 +1525,7 @@ static int cafe_vidioc_querycap(struct file *file, void *priv,
/*
* The default format we use until somebody says otherwise.
*/
-static struct v4l2_pix_format cafe_def_pix_format = {
+static const struct v4l2_pix_format cafe_def_pix_format = {
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
.pixelformat = V4L2_PIX_FMT_YUYV,
@@ -1490,28 +1534,38 @@ static struct v4l2_pix_format cafe_def_pix_format = {
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
};
+static const enum v4l2_mbus_pixelcode cafe_def_mbus_code =
+ V4L2_MBUS_FMT_YUYV8_2X8;
+
static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_fmtdesc *fmt)
{
- struct cafe_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, video, enum_fmt, fmt);
- mutex_unlock(&cam->s_mutex);
- return ret;
+ if (fmt->index >= N_CAFE_FMTS)
+ return -EINVAL;
+ strlcpy(fmt->description, cafe_formats[fmt->index].desc,
+ sizeof(fmt->description));
+ fmt->pixelformat = cafe_formats[fmt->index].pixelformat;
+ return 0;
}
-
static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
struct cafe_camera *cam = priv;
+ struct cafe_format_struct *f;
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
+ f = cafe_find_format(pix->pixelformat);
+ pix->pixelformat = f->pixelformat;
+ v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, video, try_fmt, fmt);
+ ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
mutex_unlock(&cam->s_mutex);
+ v4l2_fill_pix_format(pix, &mbus_fmt);
+ pix->bytesperline = pix->width * f->bpp;
+ pix->sizeimage = pix->height * pix->bytesperline;
return ret;
}
@@ -1519,6 +1573,7 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
struct cafe_camera *cam = priv;
+ struct cafe_format_struct *f;
int ret;
/*
@@ -1527,6 +1582,9 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
*/
if (cam->state != S_IDLE || cam->n_sbufs > 0)
return -EBUSY;
+
+ f = cafe_find_format(fmt->fmt.pix.pixelformat);
+
/*
* See if the formatting works in principle.
*/
@@ -1539,6 +1597,8 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
*/
mutex_lock(&cam->s_mutex);
cam->pix_format = fmt->fmt.pix;
+ cam->mbus_code = f->mbus_code;
+
/*
* Make sure we have appropriate DMA buffers.
*/
@@ -1652,6 +1712,30 @@ static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
return sensor_call(cam, core, g_chip_ident, chip);
}
+static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = sensor_call(cam, video, enum_framesizes, sizes);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = sensor_call(cam, video, enum_frameintervals, interval);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cafe_vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -1715,6 +1799,8 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
.vidioc_s_ctrl = cafe_vidioc_s_ctrl,
.vidioc_g_parm = cafe_vidioc_g_parm,
.vidioc_s_parm = cafe_vidioc_s_parm,
+ .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals,
.vidioc_g_chip_ident = cafe_vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = cafe_vidioc_g_register,
@@ -1890,11 +1976,33 @@ static irqreturn_t cafe_irq(int irq, void *data)
* PCI interface stuff.
*/
+static const struct dmi_system_id olpc_xo1_dmi[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1"),
+ },
+ },
+ { }
+};
+
static int cafe_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
struct cafe_camera *cam;
+ struct ov7670_config sensor_cfg = {
+ /* This controller only does SMBUS */
+ .use_smbus = true,
+
+ /*
+ * Exclude QCIF mode, because it only captures a tiny portion
+ * of the sensor FOV
+ */
+ .min_width = 320,
+ .min_height = 240,
+ };
/*
* Start putting together one of our big camera structures.
@@ -1915,6 +2023,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
init_waitqueue_head(&cam->iowait);
cam->pdev = pdev;
cam->pix_format = cafe_def_pix_format;
+ cam->mbus_code = cafe_def_mbus_code;
INIT_LIST_HEAD(&cam->dev_list);
INIT_LIST_HEAD(&cam->sb_avail);
INIT_LIST_HEAD(&cam->sb_full);
@@ -1951,13 +2060,18 @@ static int cafe_pci_probe(struct pci_dev *pdev,
if (ret)
goto out_freeirq;
+ /* Apply XO-1 clock speed */
+ if (dmi_check_system(olpc_xo1_dmi))
+ sensor_cfg.clock_speed = 45;
+
cam->sensor_addr = 0x42;
cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
- "ov7670", "ov7670", cam->sensor_addr, NULL);
+ NULL, "ov7670", cam->sensor_addr, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
}
+
ret = cafe_cam_init(cam);
if (ret)
goto out_smbus;
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
index e39a96152004..66e9283f5993 100644
--- a/drivers/media/video/cpia2/Kconfig
+++ b/drivers/media/video/cpia2/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_CPIA2
tristate "CPiA2 Video For Linux"
- depends on VIDEO_DEV && USB && VIDEO_V4L1
+ depends on VIDEO_DEV && USB && VIDEO_V4L2
---help---
This is the video4linux driver for cameras based on Vision's CPiA2
(Colour Processor Interface ASIC), such as the Digital Blue QX5
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index 8d2dfc128821..916c13d5cf7d 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -32,7 +32,7 @@
#define __CPIA2_H__
#include
-#include
+#include
#include
#include
#include
@@ -43,7 +43,7 @@
/* define for verbose debug output */
//#define _CPIA2_DEBUG_
-#define CPIA2_MAJ_VER 2
+#define CPIA2_MAJ_VER 3
#define CPIA2_MIN_VER 0
#define CPIA2_PATCH_VER 0
@@ -396,8 +396,8 @@ struct camera_data {
/* v4l */
int video_size; /* VIDEO_SIZE_ */
struct video_device *vdev; /* v4l videodev */
- struct video_picture vp; /* v4l camera settings */
- struct video_window vw; /* v4l capture area */
+ u32 width;
+ u32 height; /* Its size */
__u32 pixelformat; /* Format fourcc */
/* USB */
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index 1cc0df8befff..9606bc01b803 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -1058,44 +1058,44 @@ static int set_vw_size(struct camera_data *cam, int size)
DBG("Setting size to VGA\n");
cam->params.roi.width = STV_IMAGE_VGA_COLS;
cam->params.roi.height = STV_IMAGE_VGA_ROWS;
- cam->vw.width = STV_IMAGE_VGA_COLS;
- cam->vw.height = STV_IMAGE_VGA_ROWS;
+ cam->width = STV_IMAGE_VGA_COLS;
+ cam->height = STV_IMAGE_VGA_ROWS;
break;
case VIDEOSIZE_CIF:
DBG("Setting size to CIF\n");
cam->params.roi.width = STV_IMAGE_CIF_COLS;
cam->params.roi.height = STV_IMAGE_CIF_ROWS;
- cam->vw.width = STV_IMAGE_CIF_COLS;
- cam->vw.height = STV_IMAGE_CIF_ROWS;
+ cam->width = STV_IMAGE_CIF_COLS;
+ cam->height = STV_IMAGE_CIF_ROWS;
break;
case VIDEOSIZE_QVGA:
DBG("Setting size to QVGA\n");
cam->params.roi.width = STV_IMAGE_QVGA_COLS;
cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
- cam->vw.width = STV_IMAGE_QVGA_COLS;
- cam->vw.height = STV_IMAGE_QVGA_ROWS;
+ cam->width = STV_IMAGE_QVGA_COLS;
+ cam->height = STV_IMAGE_QVGA_ROWS;
break;
case VIDEOSIZE_288_216:
cam->params.roi.width = 288;
cam->params.roi.height = 216;
- cam->vw.width = 288;
- cam->vw.height = 216;
+ cam->width = 288;
+ cam->height = 216;
break;
case VIDEOSIZE_256_192:
- cam->vw.width = 256;
- cam->vw.height = 192;
+ cam->width = 256;
+ cam->height = 192;
cam->params.roi.width = 256;
cam->params.roi.height = 192;
break;
case VIDEOSIZE_224_168:
- cam->vw.width = 224;
- cam->vw.height = 168;
+ cam->width = 224;
+ cam->height = 168;
cam->params.roi.width = 224;
cam->params.roi.height = 168;
break;
case VIDEOSIZE_192_144:
- cam->vw.width = 192;
- cam->vw.height = 144;
+ cam->width = 192;
+ cam->height = 144;
cam->params.roi.width = 192;
cam->params.roi.height = 144;
break;
@@ -1103,8 +1103,8 @@ static int set_vw_size(struct camera_data *cam, int size)
DBG("Setting size to QCIF\n");
cam->params.roi.width = STV_IMAGE_QCIF_COLS;
cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
- cam->vw.width = STV_IMAGE_QCIF_COLS;
- cam->vw.height = STV_IMAGE_QCIF_ROWS;
+ cam->width = STV_IMAGE_QCIF_COLS;
+ cam->height = STV_IMAGE_QCIF_ROWS;
break;
default:
retval = -EINVAL;
@@ -2224,23 +2224,8 @@ static void reset_camera_struct(struct camera_data *cam)
cam->params.roi.height = STV_IMAGE_CIF_ROWS;
}
- /***
- * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP
- * Ioctl. Here, just do the window and picture stucts.
- ***/
- cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */
- cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
- cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
- cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
-
- cam->vw.x = 0;
- cam->vw.y = 0;
- cam->vw.width = cam->params.roi.width;
- cam->vw.height = cam->params.roi.height;
- cam->vw.flags = 0;
- cam->vw.clipcount = 0;
-
- return;
+ cam->width = cam->params.roi.width;
+ cam->height = cam->params.roi.height;
}
/******************************************************************************
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 5520789854da..46b433bbf2c1 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -37,7 +37,7 @@
#include
#include
#include
-#include
+#include
#include
#include
@@ -391,113 +391,6 @@ static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *
}
-/******************************************************************************
- *
- * ioctl_cap_query
- *
- *****************************************************************************/
-static int ioctl_cap_query(void *arg, struct camera_data *cam)
-{
- struct video_capability *vc;
- int retval = 0;
- vc = arg;
-
- if (cam->params.pnp_id.product == 0x151)
- strcpy(vc->name, "QX5 Microscope");
- else
- strcpy(vc->name, "CPiA2 Camera");
-
- vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER;
- vc->channels = 1;
- vc->audios = 0;
- vc->minwidth = 176; /* VIDEOSIZE_QCIF */
- vc->minheight = 144;
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_500:
- vc->maxwidth = STV_IMAGE_VGA_COLS;
- vc->maxheight = STV_IMAGE_VGA_ROWS;
- break;
- case CPIA2_VP_SENSOR_FLAGS_410:
- vc->maxwidth = STV_IMAGE_CIF_COLS;
- vc->maxheight = STV_IMAGE_CIF_ROWS;
- break;
- default:
- return -EINVAL;
- }
-
- return retval;
-}
-
-/******************************************************************************
- *
- * ioctl_get_channel
- *
- *****************************************************************************/
-static int ioctl_get_channel(void *arg)
-{
- int retval = 0;
- struct video_channel *v;
- v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
-
- v->channel = 0;
- strcpy(v->name, "Camera");
- v->tuners = 0;
- v->flags = 0;
- v->type = VIDEO_TYPE_CAMERA;
- v->norm = 0;
-
- return retval;
-}
-
-/******************************************************************************
- *
- * ioctl_set_channel
- *
- *****************************************************************************/
-static int ioctl_set_channel(void *arg)
-{
- struct video_channel *v;
- int retval = 0;
- v = arg;
-
- if (retval == 0 && v->channel != 0)
- retval = -EINVAL;
-
- return retval;
-}
-
-/******************************************************************************
- *
- * ioctl_set_image_prop
- *
- *****************************************************************************/
-static int ioctl_set_image_prop(void *arg, struct camera_data *cam)
-{
- struct video_picture *vp;
- int retval = 0;
- vp = arg;
-
- /* brightness, color, contrast need no check 0-65535 */
- memcpy(&cam->vp, vp, sizeof(*vp));
-
- /* update cam->params.colorParams */
- cam->params.color_params.brightness = vp->brightness / 256;
- cam->params.color_params.saturation = vp->colour / 256;
- cam->params.color_params.contrast = vp->contrast / 256;
-
- DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n",
- cam->params.color_params.brightness,
- cam->params.color_params.saturation,
- cam->params.color_params.contrast);
-
- cpia2_set_color_params(cam);
-
- return retval;
-}
-
static int sync(struct camera_data *cam, int frame_nr)
{
struct framebuf *frame = &cam->buffers[frame_nr];
@@ -524,63 +417,12 @@ static int sync(struct camera_data *cam, int frame_nr)
}
}
-/******************************************************************************
- *
- * ioctl_set_window_size
- *
- *****************************************************************************/
-static int ioctl_set_window_size(void *arg, struct camera_data *cam,
- struct cpia2_fh *fh)
-{
- /* copy_from_user, check validity, copy to internal structure */
- struct video_window *vw;
- int frame, err;
- vw = arg;
-
- if (vw->clipcount != 0) /* clipping not supported */
- return -EINVAL;
-
- if (vw->clips != NULL) /* clipping not supported */
- return -EINVAL;
-
- /* Ensure that only this process can change the format. */
- err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
- if(err != 0)
- return err;
-
- cam->pixelformat = V4L2_PIX_FMT_JPEG;
-
- /* Be sure to supply the Huffman tables, this isn't MJPEG */
- cam->params.compression.inhibit_htables = 0;
-
- /* we set the video window to something smaller or equal to what
- * is requested by the user???
- */
- DBG("Requested width = %d, height = %d\n", vw->width, vw->height);
- if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
- cam->vw.width = vw->width;
- cam->vw.height = vw->height;
- cam->params.roi.width = vw->width;
- cam->params.roi.height = vw->height;
- cpia2_set_format(cam);
- }
-
- for (frame = 0; frame < cam->num_frames; ++frame) {
- if (cam->buffers[frame].status == FRAME_READING)
- if ((err = sync(cam, frame)) < 0)
- return err;
-
- cam->buffers[frame].status = FRAME_EMPTY;
- }
-
- return 0;
-}
-
/******************************************************************************
*
* ioctl_get_mbuf
*
*****************************************************************************/
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
{
struct video_mbuf *vm;
@@ -595,66 +437,7 @@ static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
return 0;
}
-
-/******************************************************************************
- *
- * ioctl_mcapture
- *
- *****************************************************************************/
-static int ioctl_mcapture(void *arg, struct camera_data *cam,
- struct cpia2_fh *fh)
-{
- struct video_mmap *vm;
- int video_size, err;
- vm = arg;
-
- if (vm->frame < 0 || vm->frame >= cam->num_frames)
- return -EINVAL;
-
- /* set video size */
- video_size = cpia2_match_video_size(vm->width, vm->height);
- if (cam->video_size < 0) {
- return -EINVAL;
- }
-
- /* Ensure that only this process can change the format. */
- err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
- if(err != 0)
- return err;
-
- if (video_size != cam->video_size) {
- cam->video_size = video_size;
- cam->params.roi.width = vm->width;
- cam->params.roi.height = vm->height;
- cpia2_set_format(cam);
- }
-
- if (cam->buffers[vm->frame].status == FRAME_READING)
- if ((err=sync(cam, vm->frame)) < 0)
- return err;
-
- cam->buffers[vm->frame].status = FRAME_EMPTY;
-
- return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode);
-}
-
-/******************************************************************************
- *
- * ioctl_sync
- *
- *****************************************************************************/
-static int ioctl_sync(void *arg, struct camera_data *cam)
-{
- int frame;
-
- frame = *(int*)arg;
-
- if (frame < 0 || frame >= cam->num_frames)
- return -EINVAL;
-
- return sync(cam, frame);
-}
-
+#endif
/******************************************************************************
*
@@ -897,10 +680,10 @@ static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
*/
DBG("Requested width = %d, height = %d\n",
f->fmt.pix.width, f->fmt.pix.height);
- if (f->fmt.pix.width != cam->vw.width ||
- f->fmt.pix.height != cam->vw.height) {
- cam->vw.width = f->fmt.pix.width;
- cam->vw.height = f->fmt.pix.height;
+ if (f->fmt.pix.width != cam->width ||
+ f->fmt.pix.height != cam->height) {
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
cam->params.roi.width = f->fmt.pix.width;
cam->params.roi.height = f->fmt.pix.height;
cpia2_set_format(cam);
@@ -932,8 +715,8 @@ static int ioctl_get_fmt(void *arg,struct camera_data *cam)
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- f->fmt.pix.width = cam->vw.width;
- f->fmt.pix.height = cam->vw.height;
+ f->fmt.pix.width = cam->width;
+ f->fmt.pix.height = cam->height;
f->fmt.pix.pixelformat = cam->pixelformat;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.bytesperline = 0;
@@ -962,12 +745,12 @@ static int ioctl_cropcap(void *arg,struct camera_data *cam)
c->bounds.left = 0;
c->bounds.top = 0;
- c->bounds.width = cam->vw.width;
- c->bounds.height = cam->vw.height;
+ c->bounds.width = cam->width;
+ c->bounds.height = cam->height;
c->defrect.left = 0;
c->defrect.top = 0;
- c->defrect.width = cam->vw.width;
- c->defrect.height = cam->vw.height;
+ c->defrect.width = cam->width;
+ c->defrect.height = cam->height;
c->pixelaspect.numerator = 1;
c->pixelaspect.denominator = 1;
@@ -1587,8 +1370,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Priority check */
switch (cmd) {
- case VIDIOCSWIN:
- case VIDIOCMCAPTURE:
case VIDIOC_S_FMT:
{
struct cpia2_fh *fh = file->private_data;
@@ -1599,8 +1380,8 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
break;
}
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCGMBUF:
- case VIDIOCSYNC:
{
struct cpia2_fh *fh = file->private_data;
if(fh->prio != V4L2_PRIORITY_RECORD) {
@@ -1609,68 +1390,21 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
break;
}
+#endif
default:
break;
}
switch (cmd) {
- case VIDIOCGCAP: /* query capabilities */
- retval = ioctl_cap_query(arg, cam);
- break;
-
- case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */
- retval = ioctl_get_channel(arg);
- break;
- case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */
- retval = ioctl_set_channel(arg);
- break;
- case VIDIOCGPICT: /* image properties */
- memcpy(arg, &cam->vp, sizeof(struct video_picture));
- break;
- case VIDIOCSPICT:
- retval = ioctl_set_image_prop(arg, cam);
- break;
- case VIDIOCGWIN: /* get/set capture window */
- memcpy(arg, &cam->vw, sizeof(struct video_window));
- break;
- case VIDIOCSWIN:
- retval = ioctl_set_window_size(arg, cam, file->private_data);
- break;
- case VIDIOCGMBUF: /* mmap interface */
- retval = ioctl_get_mbuf(arg, cam);
- break;
- case VIDIOCMCAPTURE:
- retval = ioctl_mcapture(arg, cam, file->private_data);
- break;
- case VIDIOCSYNC:
- retval = ioctl_sync(arg, cam);
- break;
- /* pointless to implement overlay with this camera */
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCKEY:
- retval = -EINVAL;
- break;
-
- /* tuner interface - we have none */
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- retval = -EINVAL;
- break;
-
- /* audio interface - we have none */
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- retval = -EINVAL;
- break;
-
/* CPIA2 extension to Video4Linux API */
case CPIA2_IOC_SET_GPIO:
retval = ioctl_set_gpio(arg, cam);
break;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ case VIDIOCGMBUF: /* mmap interface */
+ retval = ioctl_get_mbuf(arg, cam);
+ break;
+#endif
case VIDIOC_QUERYCAP:
retval = ioctl_querycap(arg,cam);
break;
@@ -1874,21 +1608,8 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
*****************************************************************************/
static void reset_camera_struct_v4l(struct camera_data *cam)
{
- /***
- * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP
- * Ioctl. Here, just do the window and picture stucts.
- ***/
- cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */
- cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
- cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
- cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
-
- cam->vw.x = 0;
- cam->vw.y = 0;
- cam->vw.width = cam->params.roi.width;
- cam->vw.height = cam->params.roi.height;
- cam->vw.flags = 0;
- cam->vw.clipcount = 0;
+ cam->width = cam->params.roi.width;
+ cam->height = cam->params.roi.height;
cam->frame_size = buffer_size;
cam->num_frames = num_buffers;
@@ -1902,13 +1623,12 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
cam->pixelformat = V4L2_PIX_FMT_JPEG;
v4l2_prio_init(&cam->prio);
- return;
}
/***
* The v4l video device structure initialized for this device
***/
-static const struct v4l2_file_operations fops_template = {
+static const struct v4l2_file_operations cpia2_fops = {
.owner = THIS_MODULE,
.open = cpia2_open,
.release = cpia2_close,
@@ -1920,9 +1640,9 @@ static const struct v4l2_file_operations fops_template = {
static struct video_device cpia2_template = {
/* I could not find any place for the old .initialize initializer?? */
- .name= "CPiA2 Camera",
- .fops= &fops_template,
- .release= video_device_release,
+ .name = "CPiA2 Camera",
+ .fops = &cpia2_fops,
+ .release = video_device_release,
};
/******************************************************************************
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
index d58097ce0d5e..f66691fe5a35 100644
--- a/drivers/media/video/cpia2/cpia2dev.h
+++ b/drivers/media/video/cpia2/cpia2dev.h
@@ -29,14 +29,14 @@
#ifndef CPIA2_DEV_HEADER
#define CPIA2_DEV_HEADER
-#include
+#include
/***
* The following defines are ioctl numbers based on video4linux private ioctls,
* which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
* args
*/
-#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32)
+#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32)
/* V4L2 driver specific controls */
#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0)
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index 8362db509e2c..9358fe77e562 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -25,7 +25,6 @@
#include
#include
#include
-#include
MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
MODULE_AUTHOR("Hans Verkuil");
@@ -209,9 +208,25 @@ static const struct i2c_device_id cs5345_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cs5345_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "cs5345",
- .probe = cs5345_probe,
- .remove = cs5345_remove,
- .id_table = cs5345_id,
+static struct i2c_driver cs5345_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cs5345",
+ },
+ .probe = cs5345_probe,
+ .remove = cs5345_remove,
+ .id_table = cs5345_id,
};
+
+static __init int init_cs5345(void)
+{
+ return i2c_add_driver(&cs5345_driver);
+}
+
+static __exit void exit_cs5345(void)
+{
+ i2c_del_driver(&cs5345_driver);
+}
+
+module_init(init_cs5345);
+module_exit(exit_cs5345);
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index cc9e84d75ea7..d93e5ab45fd3 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -30,7 +30,6 @@
#include
#include
#include
-#include
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
MODULE_AUTHOR("Martin Vaughan");
@@ -239,9 +238,25 @@ static const struct i2c_device_id cs53l32a_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "cs53l32a",
- .remove = cs53l32a_remove,
- .probe = cs53l32a_probe,
- .id_table = cs53l32a_id,
+static struct i2c_driver cs53l32a_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cs53l32a",
+ },
+ .probe = cs53l32a_probe,
+ .remove = cs53l32a_remove,
+ .id_table = cs53l32a_id,
};
+
+static __init int init_cs53l32a(void)
+{
+ return i2c_add_driver(&cs53l32a_driver);
+}
+
+static __exit void exit_cs53l32a(void)
+{
+ i2c_del_driver(&cs53l32a_driver);
+}
+
+module_init(init_cs53l32a);
+module_exit(exit_cs53l32a);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index 9bc51a99376b..77be58c1096b 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -674,18 +674,25 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
/* Call the specified callback for all subdevs with a grp_id bit matching the
* mask in hw (if 0, then match them all). Ignore any errors. */
-#define cx18_call_hw(cx, hw, o, f, args...) \
- __v4l2_device_call_subdevs(&(cx)->v4l2_dev, \
- !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define cx18_call_hw(cx, hw, o, f, args...) \
+ do { \
+ struct v4l2_subdev *__sd; \
+ __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \
+ !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
+ } while (0)
#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
/* Call the specified callback for all subdevs with a grp_id bit matching the
* mask in hw (if 0, then match them all). If the callback returns an error
* other than 0 or -ENOIOCTLCMD, then return with that error code. */
-#define cx18_call_hw_err(cx, hw, o, f, args...) \
- __v4l2_device_call_subdevs_until_err( \
- &(cx)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define cx18_call_hw_err(cx, hw, o, f, args...) \
+({ \
+ struct v4l2_subdev *__sd; \
+ __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \
+ __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \
+ ##args); \
+})
#define cx18_call_all_err(cx, o, f, args...) \
cx18_call_hw_err(cx, 0, o, f , ##args)
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index 73ce90c2f577..a09caf883170 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -70,19 +70,6 @@ static const u8 hw_bus[] = {
0, /* CX18_HW_Z8F0811_IR_RX_HAUP */
};
-/* This array should match the CX18_HW_ defines */
-static const char * const hw_modules[] = {
- "tuner", /* CX18_HW_TUNER */
- NULL, /* CX18_HW_TVEEPROM */
- "cs5345", /* CX18_HW_CS5345 */
- NULL, /* CX18_HW_DVB */
- NULL, /* CX18_HW_418_AV */
- NULL, /* CX18_HW_GPIO_MUX */
- NULL, /* CX18_HW_GPIO_RESET_CTRL */
- NULL, /* CX18_HW_Z8F0811_IR_TX_HAUP */
- NULL, /* CX18_HW_Z8F0811_IR_RX_HAUP */
-};
-
/* This array should match the CX18_HW_ defines */
static const char * const hw_devicenames[] = {
"tuner",
@@ -126,7 +113,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
struct v4l2_subdev *sd;
int bus = hw_bus[idx];
struct i2c_adapter *adap = &cx->i2c_adap[bus];
- const char *mod = hw_modules[idx];
const char *type = hw_devicenames[idx];
u32 hw = 1 << idx;
@@ -136,15 +122,15 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->radio);
+ adap, NULL, type, 0, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->demod);
+ adap, NULL, type, 0, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->tv);
+ adap, NULL, type, 0, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
@@ -158,7 +144,8 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return -1;
/* It's an I2C device other than an analog tuner or IR chip */
- sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, NULL, type, hw_addrs[idx],
+ NULL);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index d6792405f8d3..7150195740dc 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -40,7 +40,6 @@
#include "cx18-av-core.h"
#include
#include
-#include
u16 cx18_service2vbi(int type)
{
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig
index 5ac7eceececa..bb04914983fd 100644
--- a/drivers/media/video/cx231xx/Kconfig
+++ b/drivers/media/video/cx231xx/Kconfig
@@ -6,6 +6,7 @@ config VIDEO_CX231XX
depends on VIDEO_IR
select VIDEOBUF_VMALLOC
select VIDEO_CX25840
+ select VIDEO_CX2341X
---help---
This is a video4linux driver for Conexant 231xx USB based TV cards.
diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile
index 6f2b57384488..a6bc4cc54677 100644
--- a/drivers/media/video/cx231xx/Makefile
+++ b/drivers/media/video/cx231xx/Makefile
@@ -1,5 +1,5 @@
cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
- cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+ cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
cx231xx-alsa-objs := cx231xx-audio.o
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
new file mode 100644
index 000000000000..aab21f3ce472
--- /dev/null
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -0,0 +1,2194 @@
+/*
+ *
+ * Support for a cx23417 mpeg encoder via cx231xx host port.
+ *
+ * (c) 2004 Jelle Foks
+ * (c) 2004 Gerd Knorr
+ * (c) 2008 Steven Toth
+ * - CX23885/7/8 support
+ *
+ * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include