mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-02 02:26:52 +07:00
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb
* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (196 commits) V4L/DVB (5253): Qt1010: whitespace / 80 column cleanups V4L/DVB (5252): Qt1010: use ARRAY_SIZE macro when appropriate V4L/DVB (5251): Qt1010: fix compiler warning V4L/DVB (5249): Fix compiler warning in vivi.c V4L/DVB (5247): Stv0297: Enable BER/UNC counting V4L/DVB (5246): Budget-ci: IR handling fixups V4L/DVB (5245): Dvb-ttpci: use i2c gate ctrl from stv0297 frontend driver V4L/DVB (5244): Dvbdev: fix illegal re-usage of fileoperations struct V4L/DVB (5178): Avoid race when deregistering the IR control for dvb-usb V4L/DVB (5240): Qt1010: use i2c_gate_ctrl where appropriate V4L/DVB (5239): Whitespace / 80-column cleanups V4L/DVB (5238): Kconfig: qt1010 should be selected by gl861 and au6610 V4L/DVB (5237): Dvb: add new qt1010 tuner module V4L/DVB (5236): Initial support for Sigmatek DVB-110 DVB-T V4L/DVB (5235): Gl861: use parallel_ts V4L/DVB (5234): Gl861: remove unneeded declaration V4L/DVB (5233): Gl861: correct address of the bulk endpoint V4L/DVB (5232): Gl861: correct oops when loading module V4L/DVB (5231): Gl861: whitespace cleanups V4L/DVB (5230): Gl861: remove NULL entry from gl861_properties ...
This commit is contained in:
commit
e695e10bc9
@ -126,7 +126,7 @@
|
||||
125 -> MATRIX Vision Sigma-SQ
|
||||
126 -> MATRIX Vision Sigma-SLC
|
||||
127 -> APAC Viewcomp 878(AMAX)
|
||||
128 -> DViCO FusionHDTV DVB-T Lite [18ac:db10]
|
||||
128 -> DViCO FusionHDTV DVB-T Lite [18ac:db10,18ac:db11]
|
||||
129 -> V-Gear MyVCD
|
||||
130 -> Super TV Tuner
|
||||
131 -> Tibet Systems 'Progress DVR' CS16
|
||||
|
@ -104,3 +104,6 @@
|
||||
103 -> Compro Videomate DVB-T200A
|
||||
104 -> Hauppauge WinTV-HVR1110 DVB-T/Hybrid [0070:6701]
|
||||
105 -> Terratec Cinergy HT PCMCIA [153b:1172]
|
||||
106 -> Encore ENLTV [1131:2342,1131:2341,3016:2344]
|
||||
107 -> Encore ENLTV-FM [1131:230f]
|
||||
108 -> Terratec Cinergy HT PCI [153b:1175]
|
||||
|
@ -197,10 +197,10 @@ Use the ../../Maintainers file, particularly the VIDEO FOR LINUX and PARALLEL
|
||||
PORT SUPPORT sections
|
||||
|
||||
The video4linux page:
|
||||
http://roadrunner.swansea.linux.org.uk/v4l.shtml
|
||||
http://linuxtv.org
|
||||
|
||||
The video4linux2 page:
|
||||
http://millennium.diads.com/bdirks/v4l2.htm
|
||||
The V4L2 API spec:
|
||||
http://v4l2spec.bytesex.org/
|
||||
|
||||
Some web pages about the quickcams:
|
||||
http://www.dkfz-heidelberg.de/Macromol/wedemann/mini-HOWTO-cqcam.html
|
||||
|
@ -339,9 +339,9 @@ Information - video4linux/mjpeg extensions:
|
||||
(also see below)
|
||||
|
||||
Information - video4linux2:
|
||||
http://www.thedirks.org/v4l2/
|
||||
http://linuxtv.org
|
||||
http://v4l2spec.bytesex.org/
|
||||
/usr/include/linux/videodev2.h
|
||||
http://www.bytesex.org/v4l/
|
||||
|
||||
More information on the video4linux/mjpeg extensions, by Serguei
|
||||
Miridonovi and Rainer Johanni:
|
||||
|
@ -21,7 +21,7 @@ Param[0]
|
||||
0 based frame number in GOP to begin playback from.
|
||||
Param[1]
|
||||
Specifies the number of muted audio frames to play before normal
|
||||
audio resumes.
|
||||
audio resumes. (This is not implemented in the firmware, leave at 0)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -32,6 +32,10 @@ Description
|
||||
playback stops at specified PTS.
|
||||
Param[0]
|
||||
Display 0=last frame, 1=black
|
||||
Note: this takes effect immediately, so if you want to wait for a PTS,
|
||||
then use '0', otherwise the screen goes to black at once.
|
||||
You can call this later (even if there is no playback) with a 1 value
|
||||
to set the screen to black.
|
||||
Param[1]
|
||||
PTS low
|
||||
Param[2]
|
||||
@ -60,8 +64,12 @@ Param[0]
|
||||
31 Speed:
|
||||
'0' slow
|
||||
'1' fast
|
||||
Note: n is limited to 2. Anything higher does not result in
|
||||
faster playback. Instead the host should start dropping frames.
|
||||
Param[1]
|
||||
Direction: 0=forward, 1=reverse
|
||||
Note: to make reverse playback work you have to write full GOPs in
|
||||
reverse order.
|
||||
Param[2]
|
||||
Picture mask:
|
||||
1=I frames
|
||||
@ -69,13 +77,16 @@ Param[2]
|
||||
7=I, P, B frames
|
||||
Param[3]
|
||||
B frames per GOP (for reverse play only)
|
||||
Note: for reverse playback the Picture Mask should be set to I or I, P.
|
||||
Adding B frames to the mask will result in corrupt video. This field
|
||||
has to be set to the correct value in order to keep the timing correct.
|
||||
Param[4]
|
||||
Mute audio: 0=disable, 1=enable
|
||||
Param[5]
|
||||
Display 0=frame, 1=field
|
||||
Param[6]
|
||||
Specifies the number of muted audio frames to play before normal audio
|
||||
resumes.
|
||||
resumes. (Not implemented in the firmware, leave at 0)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
@ -212,6 +223,7 @@ Description
|
||||
Select audio mode
|
||||
Param[0]
|
||||
Dual mono mode action
|
||||
0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
|
||||
Param[1]
|
||||
Stereo mode action:
|
||||
0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
|
||||
@ -224,7 +236,10 @@ Description
|
||||
Setup firmware to notify the host about a particular event.
|
||||
Counterpart to API 0xD5
|
||||
Param[0]
|
||||
Event: 0=Audio mode change between stereo and dual channel
|
||||
Event: 0=Audio mode change between mono, (joint) stereo and dual channel.
|
||||
Event: 3=Decoder started
|
||||
Event: 4=Unknown: goes off 10-15 times per second while decoding.
|
||||
Event: 5=Some sync event: goes off once per frame.
|
||||
Param[1]
|
||||
Notification 0=disabled, 1=enabled
|
||||
Param[2]
|
||||
@ -273,43 +288,6 @@ Param[3]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name CX2341X_DEC_SET_AUDIO_OUTPUT
|
||||
Enum 27/0x1B
|
||||
Description
|
||||
Select audio output format
|
||||
Param[0]
|
||||
Bitmask:
|
||||
0:1 Data size:
|
||||
'00' 16 bit
|
||||
'01' 20 bit
|
||||
'10' 24 bit
|
||||
2:7 Unused
|
||||
8:9 Mode:
|
||||
'00' 2 channels
|
||||
'01' 4 channels
|
||||
'10' 6 channels
|
||||
'11' 6 channels with one line data mode
|
||||
(for left justified MSB first mode, 20 bit only)
|
||||
10:11 Unused
|
||||
12:13 Channel format:
|
||||
'00' right justified MSB first mode
|
||||
'01' left justified MSB first mode
|
||||
'10' I2S mode
|
||||
14:15 Unused
|
||||
16:21 Right justify bit count
|
||||
22:31 Unused
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name CX2341X_DEC_SET_AV_DELAY
|
||||
Enum 28/0x1C
|
||||
Description
|
||||
Set audio/video delay in 90Khz ticks
|
||||
Param[0]
|
||||
0=A/V in sync, negative=audio lags, positive=video lags
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name CX2341X_DEC_SET_PREBUFFERING
|
||||
Enum 30/0x1E
|
||||
Description
|
||||
|
815
Documentation/video4linux/cx2341x/fw-decoder-regs.txt
Normal file
815
Documentation/video4linux/cx2341x/fw-decoder-regs.txt
Normal file
@ -0,0 +1,815 @@
|
||||
PVR350 Video decoder registers 0x02002800 -> 0x02002B00
|
||||
=======================================================
|
||||
|
||||
This list has been worked out through trial and error. There will be mistakes
|
||||
and omissions. Some registers have no obvious effect so it's hard to say what
|
||||
they do, while others interact with each other, or require a certain load
|
||||
sequence. Horizontal filter setup is one example, with six registers working
|
||||
in unison and requiring a certain load sequence to correctly configure. The
|
||||
indexed colour palette is much easier to set at just two registers, but again
|
||||
it requires a certain load sequence.
|
||||
|
||||
Some registers are fussy about what they are set to. Load in a bad value & the
|
||||
decoder will fail. A firmware reload will often recover, but sometimes a reset
|
||||
is required. For registers containing size information, setting them to 0 is
|
||||
generally a bad idea. For other control registers i.e. 2878, you'll only find
|
||||
out what values are bad when it hangs.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2800
|
||||
bit 0
|
||||
Decoder enable
|
||||
0 = disable
|
||||
1 = enable
|
||||
--------------------------------------------------------------------------------
|
||||
2804
|
||||
bits 0:31
|
||||
Decoder horizontal Y alias register 1
|
||||
---------------
|
||||
2808
|
||||
bits 0:31
|
||||
Decoder horizontal Y alias register 2
|
||||
---------------
|
||||
280C
|
||||
bits 0:31
|
||||
Decoder horizontal Y alias register 3
|
||||
---------------
|
||||
2810
|
||||
bits 0:31
|
||||
Decoder horizontal Y alias register 4
|
||||
---------------
|
||||
2814
|
||||
bits 0:31
|
||||
Decoder horizontal Y alias register 5
|
||||
---------------
|
||||
2818
|
||||
bits 0:31
|
||||
Decoder horizontal Y alias trigger
|
||||
|
||||
These six registers control the horizontal aliasing filter for the Y plane.
|
||||
The first five registers must all be loaded before accessing the trigger
|
||||
(2818), as this register actually clocks the data through for the first
|
||||
five.
|
||||
|
||||
To correctly program set the filter, this whole procedure must be done 16
|
||||
times. The actual register contents are copied from a lookup-table in the
|
||||
firmware which contains 4 different filter settings.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
281C
|
||||
bits 0:31
|
||||
Decoder horizontal UV alias register 1
|
||||
---------------
|
||||
2820
|
||||
bits 0:31
|
||||
Decoder horizontal UV alias register 2
|
||||
---------------
|
||||
2824
|
||||
bits 0:31
|
||||
Decoder horizontal UV alias register 3
|
||||
---------------
|
||||
2828
|
||||
bits 0:31
|
||||
Decoder horizontal UV alias register 4
|
||||
---------------
|
||||
282C
|
||||
bits 0:31
|
||||
Decoder horizontal UV alias register 5
|
||||
---------------
|
||||
2830
|
||||
bits 0:31
|
||||
Decoder horizontal UV alias trigger
|
||||
|
||||
These six registers control the horizontal aliasing for the UV plane.
|
||||
Operation is the same as the Y filter, with 2830 being the trigger
|
||||
register.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2834
|
||||
bits 0:15
|
||||
Decoder Y source width in pixels
|
||||
|
||||
bits 16:31
|
||||
Decoder Y destination width in pixels
|
||||
---------------
|
||||
2838
|
||||
bits 0:15
|
||||
Decoder UV source width in pixels
|
||||
|
||||
bits 16:31
|
||||
Decoder UV destination width in pixels
|
||||
|
||||
NOTE: For both registers, the resulting image must be fully visible on
|
||||
screen. If the image exceeds the right edge both the source and destination
|
||||
size must be adjusted to reflect the visible portion. For the source width,
|
||||
you must take into account the scaling when calculating the new value.
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
283C
|
||||
bits 0:31
|
||||
Decoder Y horizontal scaling
|
||||
Normally = Reg 2854 >> 2
|
||||
---------------
|
||||
2840
|
||||
bits 0:31
|
||||
Decoder ?? unknown - horizontal scaling
|
||||
Usually 0x00080514
|
||||
---------------
|
||||
2844
|
||||
bits 0:31
|
||||
Decoder UV horizontal scaling
|
||||
Normally = Reg 2854 >> 2
|
||||
---------------
|
||||
2848
|
||||
bits 0:31
|
||||
Decoder ?? unknown - horizontal scaling
|
||||
Usually 0x00100514
|
||||
---------------
|
||||
284C
|
||||
bits 0:31
|
||||
Decoder ?? unknown - Y plane
|
||||
Usually 0x00200020
|
||||
---------------
|
||||
2850
|
||||
bits 0:31
|
||||
Decoder ?? unknown - UV plane
|
||||
Usually 0x00200020
|
||||
---------------
|
||||
2854
|
||||
bits 0:31
|
||||
Decoder 'master' value for horizontal scaling
|
||||
---------------
|
||||
2858
|
||||
bits 0:31
|
||||
Decoder ?? unknown
|
||||
Usually 0
|
||||
---------------
|
||||
285C
|
||||
bits 0:31
|
||||
Decoder ?? unknown
|
||||
Normally = Reg 2854 >> 1
|
||||
---------------
|
||||
2860
|
||||
bits 0:31
|
||||
Decoder ?? unknown
|
||||
Usually 0
|
||||
---------------
|
||||
2864
|
||||
bits 0:31
|
||||
Decoder ?? unknown
|
||||
Normally = Reg 2854 >> 1
|
||||
---------------
|
||||
2868
|
||||
bits 0:31
|
||||
Decoder ?? unknown
|
||||
Usually 0
|
||||
|
||||
Most of these registers either control horizontal scaling, or appear linked
|
||||
to it in some way. Register 2854 contains the 'master' value & the other
|
||||
registers can be calculated from that one. You must also remember to
|
||||
correctly set the divider in Reg 2874.
|
||||
|
||||
To enlarge:
|
||||
Reg 2854 = (source_width * 0x00200000) / destination_width
|
||||
Reg 2874 = No divide
|
||||
|
||||
To reduce from full size down to half size:
|
||||
Reg 2854 = (source_width/2 * 0x00200000) / destination width
|
||||
Reg 2874 = Divide by 2
|
||||
|
||||
To reduce from half size down to quarter size:
|
||||
Reg 2854 = (source_width/4 * 0x00200000) / destination width
|
||||
Reg 2874 = Divide by 4
|
||||
|
||||
The result is always rounded up.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
286C
|
||||
bits 0:15
|
||||
Decoder horizontal Y buffer offset
|
||||
|
||||
bits 15:31
|
||||
Decoder horizontal UV buffer offset
|
||||
|
||||
Offset into the video image buffer. If the offset is gradually incremented,
|
||||
the on screen image will move left & wrap around higher up on the right.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2870
|
||||
bits 0:15
|
||||
Decoder horizontal Y output offset
|
||||
|
||||
bits 16:31
|
||||
Decoder horizontal UV output offset
|
||||
|
||||
Offsets the actual video output. Controls output alignment of the Y & UV
|
||||
planes. The higher the value, the greater the shift to the left. Use
|
||||
reg 2890 to move the image right.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2874
|
||||
bits 0:1
|
||||
Decoder horizontal Y output size divider
|
||||
00 = No divide
|
||||
01 = Divide by 2
|
||||
10 = Divide by 3
|
||||
|
||||
bits 4:5
|
||||
Decoder horizontal UV output size divider
|
||||
00 = No divide
|
||||
01 = Divide by 2
|
||||
10 = Divide by 3
|
||||
|
||||
bit 8
|
||||
Decoder ?? unknown
|
||||
0 = Normal
|
||||
1 = Affects video output levels
|
||||
|
||||
bit 16
|
||||
Decoder ?? unknown
|
||||
0 = Normal
|
||||
1 = Disable horizontal filter
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2878
|
||||
bit 0
|
||||
?? unknown
|
||||
|
||||
bit 1
|
||||
osd on/off
|
||||
0 = osd off
|
||||
1 = osd on
|
||||
|
||||
bit 2
|
||||
Decoder + osd video timing
|
||||
0 = NTSC
|
||||
1 = PAL
|
||||
|
||||
bits 3:4
|
||||
?? unknown
|
||||
|
||||
bit 5
|
||||
Decoder + osd
|
||||
Swaps upper & lower fields
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
287C
|
||||
bits 0:10
|
||||
Decoder & osd ?? unknown
|
||||
Moves entire screen horizontally. Starts at 0x005 with the screen
|
||||
shifted heavily to the right. Incrementing in steps of 0x004 will
|
||||
gradually shift the screen to the left.
|
||||
|
||||
bits 11:31
|
||||
?? unknown
|
||||
|
||||
Normally contents are 0x00101111 (NTSC) or 0x1010111d (PAL)
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2880 -------- ?? unknown
|
||||
2884 -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
2888
|
||||
bit 0
|
||||
Decoder + osd ?? unknown
|
||||
0 = Normal
|
||||
1 = Misaligned fields (Correctable through 289C & 28A4)
|
||||
|
||||
bit 4
|
||||
?? unknown
|
||||
|
||||
bit 8
|
||||
?? unknown
|
||||
|
||||
Warning: Bad values will require a firmware reload to recover.
|
||||
Known to be bad are 0x000,0x011,0x100,0x111
|
||||
--------------------------------------------------------------------------------
|
||||
288C
|
||||
bits 0:15
|
||||
osd ?? unknown
|
||||
Appears to affect the osd position stability. The higher the value the
|
||||
more unstable it becomes. Decoder output remains stable.
|
||||
|
||||
bits 16:31
|
||||
osd ?? unknown
|
||||
Same as bits 0:15
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2890
|
||||
bits 0:11
|
||||
Decoder output horizontal offset.
|
||||
|
||||
Horizontal offset moves the video image right. A small left shift is
|
||||
possible, but it's better to use reg 2870 for that due to its greater
|
||||
range.
|
||||
|
||||
NOTE: Video corruption will occur if video window is shifted off the right
|
||||
edge. To avoid this read the notes for 2834 & 2838.
|
||||
--------------------------------------------------------------------------------
|
||||
2894
|
||||
bits 0:23
|
||||
Decoder output video surround colour.
|
||||
|
||||
Contains the colour (in yuv) used to fill the screen when the video is
|
||||
running in a window.
|
||||
--------------------------------------------------------------------------------
|
||||
2898
|
||||
bits 0:23
|
||||
Decoder video window colour
|
||||
Contains the colour (in yuv) used to fill the video window when the
|
||||
video is turned off.
|
||||
|
||||
bit 24
|
||||
Decoder video output
|
||||
0 = Video on
|
||||
1 = Video off
|
||||
|
||||
bit 28
|
||||
Decoder plane order
|
||||
0 = Y,UV
|
||||
1 = UV,Y
|
||||
|
||||
bit 29
|
||||
Decoder second plane byte order
|
||||
0 = Normal (UV)
|
||||
1 = Swapped (VU)
|
||||
|
||||
In normal usage, the first plane is Y & the second plane is UV. Though the
|
||||
order of the planes can be swapped, only the byte order of the second plane
|
||||
can be swapped. This isn't much use for the Y plane, but can be useful for
|
||||
the UV plane.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
289C
|
||||
bits 0:15
|
||||
Decoder vertical field offset 1
|
||||
|
||||
bits 16:31
|
||||
Decoder vertical field offset 2
|
||||
|
||||
Controls field output vertical alignment. The higher the number, the lower
|
||||
the image on screen. Known starting values are 0x011E0017 (NTSC) &
|
||||
0x01500017 (PAL)
|
||||
--------------------------------------------------------------------------------
|
||||
28A0
|
||||
bits 0:15
|
||||
Decoder & osd width in pixels
|
||||
|
||||
bits 16:31
|
||||
Decoder & osd height in pixels
|
||||
|
||||
All output from the decoder & osd are disabled beyond this area. Decoder
|
||||
output will simply go black outside of this region. If the osd tries to
|
||||
exceed this area it will become corrupt.
|
||||
--------------------------------------------------------------------------------
|
||||
28A4
|
||||
bits 0:11
|
||||
osd left shift.
|
||||
|
||||
Has a range of 0x770->0x7FF. With the exception of 0, any value outside of
|
||||
this range corrupts the osd.
|
||||
--------------------------------------------------------------------------------
|
||||
28A8
|
||||
bits 0:15
|
||||
osd vertical field offset 1
|
||||
|
||||
bits 16:31
|
||||
osd vertical field offset 2
|
||||
|
||||
Controls field output vertical alignment. The higher the number, the lower
|
||||
the image on screen. Known starting values are 0x011E0017 (NTSC) &
|
||||
0x01500017 (PAL)
|
||||
--------------------------------------------------------------------------------
|
||||
28AC -------- ?? unknown
|
||||
|
|
||||
V
|
||||
28BC -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
28C0
|
||||
bit 0
|
||||
Current output field
|
||||
0 = first field
|
||||
1 = second field
|
||||
|
||||
bits 16:31
|
||||
Current scanline
|
||||
The scanline counts from the top line of the first field
|
||||
through to the last line of the second field.
|
||||
--------------------------------------------------------------------------------
|
||||
28C4 -------- ?? unknown
|
||||
|
|
||||
V
|
||||
28F8 -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
28FC
|
||||
bit 0
|
||||
?? unknown
|
||||
0 = Normal
|
||||
1 = Breaks decoder & osd output
|
||||
--------------------------------------------------------------------------------
|
||||
2900
|
||||
bits 0:31
|
||||
Decoder vertical Y alias register 1
|
||||
---------------
|
||||
2904
|
||||
bits 0:31
|
||||
Decoder vertical Y alias register 2
|
||||
---------------
|
||||
2908
|
||||
bits 0:31
|
||||
Decoder vertical Y alias trigger
|
||||
|
||||
These three registers control the vertical aliasing filter for the Y plane.
|
||||
Operation is similar to the horizontal Y filter (2804). The only real
|
||||
difference is that there are only two registers to set before accessing
|
||||
the trigger register (2908). As for the horizontal filter, the values are
|
||||
taken from a lookup table in the firmware, and the procedure must be
|
||||
repeated 16 times to fully program the filter.
|
||||
--------------------------------------------------------------------------------
|
||||
290C
|
||||
bits 0:31
|
||||
Decoder vertical UV alias register 1
|
||||
---------------
|
||||
2910
|
||||
bits 0:31
|
||||
Decoder vertical UV alias register 2
|
||||
---------------
|
||||
2914
|
||||
bits 0:31
|
||||
Decoder vertical UV alias trigger
|
||||
|
||||
These three registers control the vertical aliasing filter for the UV
|
||||
plane. Operation is the same as the Y filter, with 2914 being the trigger.
|
||||
--------------------------------------------------------------------------------
|
||||
2918
|
||||
bits 0:15
|
||||
Decoder Y source height in pixels
|
||||
|
||||
bits 16:31
|
||||
Decoder Y destination height in pixels
|
||||
---------------
|
||||
291C
|
||||
bits 0:15
|
||||
Decoder UV source height in pixels divided by 2
|
||||
|
||||
bits 16:31
|
||||
Decoder UV destination height in pixels
|
||||
|
||||
NOTE: For both registers, the resulting image must be fully visible on
|
||||
screen. If the image exceeds the bottom edge both the source and
|
||||
destination size must be adjusted to reflect the visible portion. For the
|
||||
source height, you must take into account the scaling when calculating the
|
||||
new value.
|
||||
--------------------------------------------------------------------------------
|
||||
2920
|
||||
bits 0:31
|
||||
Decoder Y vertical scaling
|
||||
Normally = Reg 2930 >> 2
|
||||
---------------
|
||||
2924
|
||||
bits 0:31
|
||||
Decoder Y vertical scaling
|
||||
Normally = Reg 2920 + 0x514
|
||||
---------------
|
||||
2928
|
||||
bits 0:31
|
||||
Decoder UV vertical scaling
|
||||
When enlarging = Reg 2930 >> 2
|
||||
When reducing = Reg 2930 >> 3
|
||||
---------------
|
||||
292C
|
||||
bits 0:31
|
||||
Decoder UV vertical scaling
|
||||
Normally = Reg 2928 + 0x514
|
||||
---------------
|
||||
2930
|
||||
bits 0:31
|
||||
Decoder 'master' value for vertical scaling
|
||||
---------------
|
||||
2934
|
||||
bits 0:31
|
||||
Decoder ?? unknown - Y vertical scaling
|
||||
---------------
|
||||
2938
|
||||
bits 0:31
|
||||
Decoder Y vertical scaling
|
||||
Normally = Reg 2930
|
||||
---------------
|
||||
293C
|
||||
bits 0:31
|
||||
Decoder ?? unknown - Y vertical scaling
|
||||
---------------
|
||||
2940
|
||||
bits 0:31
|
||||
Decoder UV vertical scaling
|
||||
When enlarging = Reg 2930 >> 1
|
||||
When reducing = Reg 2930
|
||||
---------------
|
||||
2944
|
||||
bits 0:31
|
||||
Decoder ?? unknown - UV vertical scaling
|
||||
---------------
|
||||
2948
|
||||
bits 0:31
|
||||
Decoder UV vertical scaling
|
||||
Normally = Reg 2940
|
||||
---------------
|
||||
294C
|
||||
bits 0:31
|
||||
Decoder ?? unknown - UV vertical scaling
|
||||
|
||||
Most of these registers either control vertical scaling, or appear linked
|
||||
to it in some way. Register 2930 contains the 'master' value & all other
|
||||
registers can be calculated from that one. You must also remember to
|
||||
correctly set the divider in Reg 296C
|
||||
|
||||
To enlarge:
|
||||
Reg 2930 = (source_height * 0x00200000) / destination_height
|
||||
Reg 296C = No divide
|
||||
|
||||
To reduce from full size down to half size:
|
||||
Reg 2930 = (source_height/2 * 0x00200000) / destination height
|
||||
Reg 296C = Divide by 2
|
||||
|
||||
To reduce from half down to quarter.
|
||||
Reg 2930 = (source_height/4 * 0x00200000) / destination height
|
||||
Reg 296C = Divide by 4
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2950
|
||||
bits 0:15
|
||||
Decoder Y line index into display buffer, first field
|
||||
|
||||
bits 16:31
|
||||
Decoder Y vertical line skip, first field
|
||||
--------------------------------------------------------------------------------
|
||||
2954
|
||||
bits 0:15
|
||||
Decoder Y line index into display buffer, second field
|
||||
|
||||
bits 16:31
|
||||
Decoder Y vertical line skip, second field
|
||||
--------------------------------------------------------------------------------
|
||||
2958
|
||||
bits 0:15
|
||||
Decoder UV line index into display buffer, first field
|
||||
|
||||
bits 16:31
|
||||
Decoder UV vertical line skip, first field
|
||||
--------------------------------------------------------------------------------
|
||||
295C
|
||||
bits 0:15
|
||||
Decoder UV line index into display buffer, second field
|
||||
|
||||
bits 16:31
|
||||
Decoder UV vertical line skip, second field
|
||||
--------------------------------------------------------------------------------
|
||||
2960
|
||||
bits 0:15
|
||||
Decoder destination height minus 1
|
||||
|
||||
bits 16:31
|
||||
Decoder destination height divided by 2
|
||||
--------------------------------------------------------------------------------
|
||||
2964
|
||||
bits 0:15
|
||||
Decoder Y vertical offset, second field
|
||||
|
||||
bits 16:31
|
||||
Decoder Y vertical offset, first field
|
||||
|
||||
These two registers shift the Y plane up. The higher the number, the
|
||||
greater the shift.
|
||||
--------------------------------------------------------------------------------
|
||||
2968
|
||||
bits 0:15
|
||||
Decoder UV vertical offset, second field
|
||||
|
||||
bits 16:31
|
||||
Decoder UV vertical offset, first field
|
||||
|
||||
These two registers shift the UV plane up. The higher the number, the
|
||||
greater the shift.
|
||||
--------------------------------------------------------------------------------
|
||||
296C
|
||||
bits 0:1
|
||||
Decoder vertical Y output size divider
|
||||
00 = No divide
|
||||
01 = Divide by 2
|
||||
10 = Divide by 4
|
||||
|
||||
bits 8:9
|
||||
Decoder vertical UV output size divider
|
||||
00 = No divide
|
||||
01 = Divide by 2
|
||||
10 = Divide by 4
|
||||
--------------------------------------------------------------------------------
|
||||
2970
|
||||
bit 0
|
||||
Decoder ?? unknown
|
||||
0 = Normal
|
||||
1 = Affect video output levels
|
||||
|
||||
bit 16
|
||||
Decoder ?? unknown
|
||||
0 = Normal
|
||||
1 = Disable vertical filter
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
2974 -------- ?? unknown
|
||||
|
|
||||
V
|
||||
29EF -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
2A00
|
||||
bits 0:2
|
||||
osd colour mode
|
||||
001 = 16 bit (565)
|
||||
010 = 15 bit (555)
|
||||
011 = 12 bit (444)
|
||||
100 = 32 bit (8888)
|
||||
101 = 8 bit indexed
|
||||
|
||||
bits 4:5
|
||||
osd display bpp
|
||||
01 = 8 bit
|
||||
10 = 16 bit
|
||||
11 = 32 bit
|
||||
|
||||
bit 8
|
||||
osd global alpha
|
||||
0 = Off
|
||||
1 = On
|
||||
|
||||
bit 9
|
||||
osd local alpha
|
||||
0 = Off
|
||||
1 = On
|
||||
|
||||
bit 10
|
||||
osd colour key
|
||||
0 = Off
|
||||
1 = On
|
||||
|
||||
bit 11
|
||||
osd ?? unknown
|
||||
Must be 1
|
||||
|
||||
bit 13
|
||||
osd colour space
|
||||
0 = ARGB
|
||||
1 = AYVU
|
||||
|
||||
bits 16:31
|
||||
osd ?? unknown
|
||||
Must be 0x001B (some kind of buffer pointer ?)
|
||||
|
||||
When the bits-per-pixel is set to 8, the colour mode is ignored and
|
||||
assumed to be 8 bit indexed. For 16 & 32 bits-per-pixel the colour depth
|
||||
is honoured, and when using a colour depth that requires fewer bytes than
|
||||
allocated the extra bytes are used as padding. So for a 32 bpp with 8 bit
|
||||
index colour, there are 3 padding bytes per pixel. It's also possible to
|
||||
select 16bpp with a 32 bit colour mode. This results in the pixel width
|
||||
being doubled, but the color key will not work as expected in this mode.
|
||||
|
||||
Colour key is as it suggests. You designate a colour which will become
|
||||
completely transparent. When using 565, 555 or 444 colour modes, the
|
||||
colour key is always 16 bits wide. The colour to key on is set in Reg 2A18.
|
||||
|
||||
Local alpha is a per-pixel 256 step transparency, with 0 being transparent
|
||||
and 255 being solid. This is only available in 32 bit & 8 bit indexed
|
||||
colour modes.
|
||||
|
||||
Global alpha is a 256 step transparency that applies to the entire osd,
|
||||
with 0 being transparent & 255 being solid.
|
||||
|
||||
It's possible to combine colour key, local alpha & global alpha.
|
||||
--------------------------------------------------------------------------------
|
||||
2A04
|
||||
bits 0:15
|
||||
osd x coord for left edge
|
||||
|
||||
bits 16:31
|
||||
osd y coord for top edge
|
||||
---------------
|
||||
2A08
|
||||
bits 0:15
|
||||
osd x coord for right edge
|
||||
|
||||
bits 16:31
|
||||
osd y coord for bottom edge
|
||||
|
||||
For both registers, (0,0) = top left corner of the display area. These
|
||||
registers do not control the osd size, only where it's positioned & how
|
||||
much is visible. The visible osd area cannot exceed the right edge of the
|
||||
display, otherwise the osd will become corrupt. See reg 2A10 for
|
||||
setting osd width.
|
||||
--------------------------------------------------------------------------------
|
||||
2A0C
|
||||
bits 0:31
|
||||
osd buffer index
|
||||
|
||||
An index into the osd buffer. Slowly incrementing this moves the osd left,
|
||||
wrapping around onto the right edge
|
||||
--------------------------------------------------------------------------------
|
||||
2A10
|
||||
bits 0:11
|
||||
osd buffer 32 bit word width
|
||||
|
||||
Contains the width of the osd measured in 32 bit words. This means that all
|
||||
colour modes are restricted to a byte width which is divisible by 4.
|
||||
--------------------------------------------------------------------------------
|
||||
2A14
|
||||
bits 0:15
|
||||
osd height in pixels
|
||||
|
||||
bits 16:32
|
||||
osd line index into buffer
|
||||
osd will start displaying from this line.
|
||||
--------------------------------------------------------------------------------
|
||||
2A18
|
||||
bits 0:31
|
||||
osd colour key
|
||||
|
||||
Contains the colour value which will be transparent.
|
||||
--------------------------------------------------------------------------------
|
||||
2A1C
|
||||
bits 0:7
|
||||
osd global alpha
|
||||
|
||||
Contains the global alpha value (equiv ivtvfbctl --alpha XX)
|
||||
--------------------------------------------------------------------------------
|
||||
2A20 -------- ?? unknown
|
||||
|
|
||||
V
|
||||
2A2C -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
2A30
|
||||
bits 0:7
|
||||
osd colour to change in indexed palette
|
||||
---------------
|
||||
2A34
|
||||
bits 0:31
|
||||
osd colour for indexed palette
|
||||
|
||||
To set the new palette, first load the index of the colour to change into
|
||||
2A30, then load the new colour into 2A34. The full palette is 256 colours,
|
||||
so the index range is 0x00-0xFF
|
||||
--------------------------------------------------------------------------------
|
||||
2A38 -------- ?? unknown
|
||||
2A3C -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
2A40
|
||||
bits 0:31
|
||||
osd ?? unknown
|
||||
|
||||
Affects overall brightness, wrapping around to black
|
||||
--------------------------------------------------------------------------------
|
||||
2A44
|
||||
bits 0:31
|
||||
osd ?? unknown
|
||||
|
||||
Green tint
|
||||
--------------------------------------------------------------------------------
|
||||
2A48
|
||||
bits 0:31
|
||||
osd ?? unknown
|
||||
|
||||
Red tint
|
||||
--------------------------------------------------------------------------------
|
||||
2A4C
|
||||
bits 0:31
|
||||
osd ?? unknown
|
||||
|
||||
Affects overall brightness, wrapping around to black
|
||||
--------------------------------------------------------------------------------
|
||||
2A50
|
||||
bits 0:31
|
||||
osd ?? unknown
|
||||
|
||||
Colour shift
|
||||
--------------------------------------------------------------------------------
|
||||
2A54
|
||||
bits 0:31
|
||||
osd ?? unknown
|
||||
|
||||
Colour shift
|
||||
--------------------------------------------------------------------------------
|
||||
2A58 -------- ?? unknown
|
||||
|
|
||||
V
|
||||
2AFC -------- ?? unknown
|
||||
--------------------------------------------------------------------------------
|
||||
2B00
|
||||
bit 0
|
||||
osd filter control
|
||||
0 = filter off
|
||||
1 = filter on
|
||||
|
||||
bits 1:4
|
||||
osd ?? unknown
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
v0.3 - 2 February 2007 - Ian Armstrong (ian@iarmst.demon.co.uk)
|
||||
|
@ -22,6 +22,8 @@ urged to choose a smaller block size and learn the scatter-gather technique.
|
||||
|
||||
Mailbox #10 is reserved for DMA transfer information.
|
||||
|
||||
Note: the hardware expects little-endian data ('intel format').
|
||||
|
||||
Flow
|
||||
====
|
||||
|
||||
@ -64,7 +66,7 @@ addresses are the physical memory location of the target DMA buffer.
|
||||
|
||||
Each S-G array element is a struct of three 32-bit words. The first word is
|
||||
the source address, the second is the destination address. Both take up the
|
||||
entire 32 bits. The lowest 16 bits of the third word is the transfer byte
|
||||
entire 32 bits. The lowest 18 bits of the third word is the transfer byte
|
||||
count. The high-bit of the third word is the "last" flag. The last-flag tells
|
||||
the card to raise the DMA_DONE interrupt. From hard personal experience, if
|
||||
you forget to set this bit, the card will still "work" but the stream will
|
||||
@ -78,8 +80,8 @@ Array Element:
|
||||
|
||||
- 32-bit Source Address
|
||||
- 32-bit Destination Address
|
||||
- 16-bit reserved (high bit is the last flag)
|
||||
- 16-bit byte count
|
||||
- 14-bit reserved (high bit is the last flag)
|
||||
- 18-bit byte count
|
||||
|
||||
DMA Transfer Status
|
||||
===================
|
||||
@ -87,8 +89,8 @@ DMA Transfer Status
|
||||
Register 0x0004 holds the DMA Transfer Status:
|
||||
|
||||
Bit
|
||||
4 Scatter-Gather array error
|
||||
3 DMA write error
|
||||
2 DMA read error
|
||||
1 write completed
|
||||
0 read completed
|
||||
1 write completed
|
||||
2 DMA read error
|
||||
3 DMA write error
|
||||
4 Scatter-Gather array error
|
||||
|
@ -213,16 +213,6 @@ Param[1]
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name CX2341X_ENC_SET_3_2_PULLDOWN
|
||||
Enum 177/0xB1
|
||||
Description
|
||||
3:2 pulldown properties
|
||||
Param[0]
|
||||
0=enabled
|
||||
1=disabled
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
Name CX2341X_ENC_SET_VBI_LINE
|
||||
Enum 183/0xB7
|
||||
Description
|
||||
@ -332,9 +322,7 @@ Param[0]
|
||||
'01'=JointStereo
|
||||
'10'=Dual
|
||||
'11'=Mono
|
||||
Note: testing seems to indicate that Mono and possibly
|
||||
JointStereo are not working (default to stereo).
|
||||
Dual does work, though.
|
||||
Note: the cx23415 cannot decode Joint Stereo properly.
|
||||
|
||||
10:11 Mode Extension used in joint_stereo mode.
|
||||
In Layer I and II they indicate which subbands are in
|
||||
@ -413,16 +401,34 @@ Name CX2341X_ENC_SET_PGM_INDEX_INFO
|
||||
Enum 199/0xC7
|
||||
Description
|
||||
Sets the Program Index Information.
|
||||
The information is stored as follows:
|
||||
|
||||
struct info {
|
||||
u32 length; // Length of this frame
|
||||
u32 offset_low; // Offset in the file of the
|
||||
u32 offset_high; // start of this frame
|
||||
u32 mask1; // Bits 0-1 are the type mask:
|
||||
// 1=I, 2=P, 4=B
|
||||
u32 pts; // The PTS of the frame
|
||||
u32 mask2; // Bit 0 is bit 32 of the pts.
|
||||
};
|
||||
u32 table_ptr;
|
||||
struct info index[400];
|
||||
|
||||
The table_ptr is the encoder memory address in the table were
|
||||
*new* entries will be written. Note that this is a ringbuffer,
|
||||
so the table_ptr will wraparound.
|
||||
Param[0]
|
||||
Picture Mask:
|
||||
0=No index capture
|
||||
1=I frames
|
||||
3=I,P frames
|
||||
7=I,P,B frames
|
||||
(Seems to be ignored, it always indexes I, P and B frames)
|
||||
Param[1]
|
||||
Elements requested (up to 400)
|
||||
Result[0]
|
||||
Offset in SDF memory of the table.
|
||||
Offset in the encoder memory of the start of the table.
|
||||
Result[1]
|
||||
Number of allocated elements up to a maximum of Param[1]
|
||||
|
||||
@ -492,12 +498,14 @@ Name CX2341X_ENC_GET_PREV_DMA_INFO_MB_9
|
||||
Enum 203/0xCB
|
||||
Description
|
||||
Returns information on the previous DMA transfer in conjunction with
|
||||
bit 27 of the interrupt mask. Uses mailbox 9.
|
||||
bit 27 or 18 of the interrupt mask. Uses mailbox 9.
|
||||
Result[0]
|
||||
Status bits:
|
||||
Bit 0 set indicates transfer complete
|
||||
Bit 2 set indicates transfer error
|
||||
Bit 4 set indicates linked list error
|
||||
0 read completed
|
||||
1 write completed
|
||||
2 DMA read error
|
||||
3 DMA write error
|
||||
4 Scatter-Gather array error
|
||||
Result[1]
|
||||
DMA type
|
||||
Result[2]
|
||||
@ -672,7 +680,7 @@ Description
|
||||
the value.
|
||||
Param[0]
|
||||
Command number:
|
||||
1=set initial SCR value when starting encoding.
|
||||
1=set initial SCR value when starting encoding (works).
|
||||
2=set quality mode (apparently some test setting).
|
||||
3=setup advanced VIM protection handling (supposedly only for the cx23416
|
||||
for raw YUV).
|
||||
@ -681,7 +689,11 @@ Param[0]
|
||||
4=generate artificial PTS timestamps
|
||||
5=USB flush mode
|
||||
6=something to do with the quantization matrix
|
||||
7=set navigation pack insertion for DVD
|
||||
7=set navigation pack insertion for DVD: adds 0xbf (private stream 2)
|
||||
packets to the MPEG. The size of these packets is 2048 bytes (including
|
||||
the header of 6 bytes: 0x000001bf + length). The payload is zeroed and
|
||||
it is up to the application to fill them in. These packets are apparently
|
||||
inserted every four frames.
|
||||
8=enable scene change detection (seems to be a failure)
|
||||
9=set history parameters of the video input module
|
||||
10=set input field order of VIM
|
||||
|
@ -1,6 +1,8 @@
|
||||
This document describes the cx2341x memory map and documents some of the register
|
||||
space.
|
||||
|
||||
Note: the memory long words are little-endian ('intel format').
|
||||
|
||||
Warning! This information was figured out from searching through the memory and
|
||||
registers, this information may not be correct and is certainly not complete, and
|
||||
was not derived from anything more than searching through the memory space with
|
||||
@ -67,7 +69,7 @@ DMA Registers 0x000-0xff:
|
||||
0x84 - first write linked list reg, for pci memory addr
|
||||
0x88 - first write linked list reg, for length of buffer in memory addr
|
||||
(|0x80000000 or this for last link)
|
||||
0x8c-0xcc - rest of write linked list reg, 8 sets of 3 total, DMA goes here
|
||||
0x8c-0xdc - rest of write linked list reg, 8 sets of 3 total, DMA goes here
|
||||
from linked list addr in reg 0x0c, firmware must push through or
|
||||
something.
|
||||
0xe0 - first (and only) read linked list reg, for pci memory addr
|
||||
@ -123,12 +125,8 @@ Bit
|
||||
29 Encoder VBI capture
|
||||
28 Encoder Video Input Module reset event
|
||||
27 Encoder DMA complete
|
||||
26
|
||||
25 Decoder copy protect detection event
|
||||
24 Decoder audio mode change detection event
|
||||
23
|
||||
24 Decoder audio mode change detection event (through event notification)
|
||||
22 Decoder data request
|
||||
21 Decoder I-Frame? done
|
||||
20 Decoder DMA complete
|
||||
19 Decoder VBI re-insertion
|
||||
18 Decoder DMA err (linked-list bad)
|
||||
|
@ -23,7 +23,7 @@ Index
|
||||
|
||||
1. Copyright
|
||||
============
|
||||
Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
|
||||
|
||||
2. Disclaimer
|
||||
@ -135,8 +135,9 @@ And finally:
|
||||
6. Module loading
|
||||
=================
|
||||
To use the driver, it is necessary to load the "et61x251" module into memory
|
||||
after every other module required: "videodev", "usbcore" and, depending on
|
||||
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
|
||||
after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
|
||||
"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
|
||||
"uhci-hcd" or "ohci-hcd".
|
||||
|
||||
Loading can be done as shown below:
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
SN9C10x PC Camera Controllers
|
||||
SN9C1xx PC Camera Controllers
|
||||
Driver for Linux
|
||||
=============================
|
||||
|
||||
@ -53,20 +53,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
4. Overview and features
|
||||
========================
|
||||
This driver attempts to support the video interface of the devices mounting the
|
||||
SONiX SN9C101, SN9C102 and SN9C103 PC Camera Controllers.
|
||||
|
||||
It's worth to note that SONiX has never collaborated with the author during the
|
||||
development of this project, despite several requests for enough detailed
|
||||
specifications of the register tables, compression engine and video data format
|
||||
of the above chips. Nevertheless, these informations are no longer necessary,
|
||||
because all the aspects related to these chips are known and have been
|
||||
described in detail in this documentation.
|
||||
This driver attempts to support the video interface of the devices assembling
|
||||
the SONiX SN9C101, SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers
|
||||
("SN9C1xx" from now on).
|
||||
|
||||
The driver relies on the Video4Linux2 and USB core modules. It has been
|
||||
designed to run properly on SMP systems as well.
|
||||
|
||||
The latest version of the SN9C10x driver can be found at the following URL:
|
||||
The latest version of the SN9C1xx driver can be found at the following URL:
|
||||
http://www.linux-projects.org/
|
||||
|
||||
Some of the features of the driver are:
|
||||
@ -85,11 +79,11 @@ Some of the features of the driver are:
|
||||
high compression quality (see also "Notes for V4L2 application developers"
|
||||
and "Video frame formats" paragraphs);
|
||||
- full support for the capabilities of many of the possible image sensors that
|
||||
can be connected to the SN9C10x bridges, including, for instance, red, green,
|
||||
can be connected to the SN9C1xx bridges, including, for instance, red, green,
|
||||
blue and global gain adjustments and exposure (see "Supported devices"
|
||||
paragraph for details);
|
||||
- use of default color settings for sunlight conditions;
|
||||
- dynamic I/O interface for both SN9C10x and image sensor control and
|
||||
- dynamic I/O interface for both SN9C1xx and image sensor control and
|
||||
monitoring (see "Optional device control through 'sysfs'" paragraph);
|
||||
- dynamic driver control thanks to various module parameters (see "Module
|
||||
parameters" paragraph);
|
||||
@ -130,8 +124,8 @@ necessary:
|
||||
CONFIG_USB_UHCI_HCD=m
|
||||
CONFIG_USB_OHCI_HCD=m
|
||||
|
||||
The SN9C103 controller also provides a built-in microphone interface. It is
|
||||
supported by the USB Audio driver thanks to the ALSA API:
|
||||
The SN9C103, SN9c105 and SN9C120 controllers also provide a built-in microphone
|
||||
interface. It is supported by the USB Audio driver thanks to the ALSA API:
|
||||
|
||||
# Sound
|
||||
#
|
||||
@ -155,18 +149,27 @@ And finally:
|
||||
6. Module loading
|
||||
=================
|
||||
To use the driver, it is necessary to load the "sn9c102" module into memory
|
||||
after every other module required: "videodev", "usbcore" and, depending on
|
||||
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
|
||||
after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
|
||||
"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
|
||||
"uhci-hcd" or "ohci-hcd".
|
||||
|
||||
Loading can be done as shown below:
|
||||
|
||||
[root@localhost home]# modprobe sn9c102
|
||||
|
||||
At this point the devices should be recognized. You can invoke "dmesg" to
|
||||
analyze kernel messages and verify that the loading process has gone well:
|
||||
Note that the module is called "sn9c102" for historic reasons, althought it
|
||||
does not just support the SN9C102.
|
||||
|
||||
At this point all the devices supported by the driver and connected to the USB
|
||||
ports should be recognized. You can invoke "dmesg" to analyze kernel messages
|
||||
and verify that the loading process has gone well:
|
||||
|
||||
[user@localhost home]$ dmesg
|
||||
|
||||
or, to isolate all the kernel messages generated by the driver:
|
||||
|
||||
[user@localhost home]$ dmesg | grep sn9c102
|
||||
|
||||
|
||||
7. Module parameters
|
||||
====================
|
||||
@ -198,10 +201,11 @@ Default: 0
|
||||
-------------------------------------------------------------------------------
|
||||
Name: frame_timeout
|
||||
Type: uint array (min = 0, max = 64)
|
||||
Syntax: <n[,...]>
|
||||
Description: Timeout for a video frame in seconds. This parameter is
|
||||
specific for each detected camera. This parameter can be
|
||||
changed at runtime thanks to the /sys filesystem interface.
|
||||
Syntax: <0|n[,...]>
|
||||
Description: Timeout for a video frame in seconds before returning an I/O
|
||||
error; 0 for infinity. This parameter is specific for each
|
||||
detected camera and can be changed at runtime thanks to the
|
||||
/sys filesystem interface.
|
||||
Default: 2
|
||||
-------------------------------------------------------------------------------
|
||||
Name: debug
|
||||
@ -223,20 +227,21 @@ Default: 2
|
||||
8. Optional device control through "sysfs" [1]
|
||||
==========================================
|
||||
If the kernel has been compiled with the CONFIG_VIDEO_ADV_DEBUG option enabled,
|
||||
it is possible to read and write both the SN9C10x and the image sensor
|
||||
it is possible to read and write both the SN9C1xx and the image sensor
|
||||
registers by using the "sysfs" filesystem interface.
|
||||
|
||||
Every time a supported device is recognized, a write-only file named "green" is
|
||||
created in the /sys/class/video4linux/videoX directory. You can set the green
|
||||
channel's gain by writing the desired value to it. The value may range from 0
|
||||
to 15 for SN9C101 or SN9C102 bridges, from 0 to 127 for SN9C103 bridges.
|
||||
Similarly, only for SN9C103 controllers, blue and red gain control files are
|
||||
available in the same directory, for which accepted values may range from 0 to
|
||||
127.
|
||||
to 15 for the SN9C101 or SN9C102 bridges, from 0 to 127 for the SN9C103,
|
||||
SN9C105 and SN9C120 bridges.
|
||||
Similarly, only for the SN9C103, SN9C105 and SN9120 controllers, blue and red
|
||||
gain control files are available in the same directory, for which accepted
|
||||
values may range from 0 to 127.
|
||||
|
||||
There are other four entries in the directory above for each registered camera:
|
||||
"reg", "val", "i2c_reg" and "i2c_val". The first two files control the
|
||||
SN9C10x bridge, while the other two control the sensor chip. "reg" and
|
||||
SN9C1xx bridge, while the other two control the sensor chip. "reg" and
|
||||
"i2c_reg" hold the values of the current register index where the following
|
||||
reading/writing operations are addressed at through "val" and "i2c_val". Their
|
||||
use is not intended for end-users. Note that "i2c_reg" and "i2c_val" will not
|
||||
@ -259,61 +264,84 @@ Now let's set the green gain's register of the SN9C101 or SN9C102 chips to 2:
|
||||
[root@localhost #] echo 0x11 > reg
|
||||
[root@localhost #] echo 2 > val
|
||||
|
||||
Note that the SN9C10x always returns 0 when some of its registers are read.
|
||||
Note that the SN9C1xx always returns 0 when some of its registers are read.
|
||||
To avoid race conditions, all the I/O accesses to the above files are
|
||||
serialized.
|
||||
|
||||
The sysfs interface also provides the "frame_header" entry, which exports the
|
||||
frame header of the most recent requested and captured video frame. The header
|
||||
is always 18-bytes long and is appended to every video frame by the SN9C10x
|
||||
is always 18-bytes long and is appended to every video frame by the SN9C1xx
|
||||
controllers. As an example, this additional information can be used by the user
|
||||
application for implementing auto-exposure features via software.
|
||||
|
||||
The following table describes the frame header:
|
||||
The following table describes the frame header exported by the SN9C101 and
|
||||
SN9C102:
|
||||
|
||||
Byte # Value Description
|
||||
------ ----- -----------
|
||||
0x00 0xFF Frame synchronisation pattern.
|
||||
0x01 0xFF Frame synchronisation pattern.
|
||||
0x02 0x00 Frame synchronisation pattern.
|
||||
0x03 0xC4 Frame synchronisation pattern.
|
||||
0x04 0xC4 Frame synchronisation pattern.
|
||||
0x05 0x96 Frame synchronisation pattern.
|
||||
0x06 0xXX Unknown meaning. The exact value depends on the chip;
|
||||
possible values are 0x00, 0x01 and 0x20.
|
||||
0x07 0xXX Variable value, whose bits are ff00uzzc, where ff is a
|
||||
frame counter, u is unknown, zz is a size indicator
|
||||
(00 = VGA, 01 = SIF, 10 = QSIF) and c stands for
|
||||
"compression enabled" (1 = yes, 0 = no).
|
||||
0x08 0xXX Brightness sum inside Auto-Exposure area (low-byte).
|
||||
0x09 0xXX Brightness sum inside Auto-Exposure area (high-byte).
|
||||
For a pure white image, this number will be equal to 500
|
||||
times the area of the specified AE area. For images
|
||||
that are not pure white, the value scales down according
|
||||
to relative whiteness.
|
||||
0x0A 0xXX Brightness sum outside Auto-Exposure area (low-byte).
|
||||
0x0B 0xXX Brightness sum outside Auto-Exposure area (high-byte).
|
||||
For a pure white image, this number will be equal to 125
|
||||
times the area outside of the specified AE area. For
|
||||
images that are not pure white, the value scales down
|
||||
according to relative whiteness.
|
||||
according to relative whiteness.
|
||||
Byte # Value or bits Description
|
||||
------ ------------- -----------
|
||||
0x00 0xFF Frame synchronisation pattern
|
||||
0x01 0xFF Frame synchronisation pattern
|
||||
0x02 0x00 Frame synchronisation pattern
|
||||
0x03 0xC4 Frame synchronisation pattern
|
||||
0x04 0xC4 Frame synchronisation pattern
|
||||
0x05 0x96 Frame synchronisation pattern
|
||||
0x06 [3:0] Read channel gain control = (1+R_GAIN/8)
|
||||
[7:4] Blue channel gain control = (1+B_GAIN/8)
|
||||
0x07 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled
|
||||
[2:1] Maximum scale factor for compression
|
||||
[ 3 ] 1 = USB fifo(2K bytes) is full
|
||||
[ 4 ] 1 = Digital gain is finish
|
||||
[ 5 ] 1 = Exposure is finish
|
||||
[7:6] Frame index
|
||||
0x08 [7:0] Y sum inside Auto-Exposure area (low-byte)
|
||||
0x09 [7:0] Y sum inside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 32
|
||||
0x0A [7:0] Y sum outside Auto-Exposure area (low-byte)
|
||||
0x0B [7:0] Y sum outside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 128
|
||||
0x0C 0xXX Not used
|
||||
0x0D 0xXX Not used
|
||||
0x0E 0xXX Not used
|
||||
0x0F 0xXX Not used
|
||||
0x10 0xXX Not used
|
||||
0x11 0xXX Not used
|
||||
|
||||
The following bytes are used by the SN9C103 bridge only:
|
||||
The following table describes the frame header exported by the SN9C103:
|
||||
|
||||
0x0C 0xXX Unknown meaning
|
||||
0x0D 0xXX Unknown meaning
|
||||
0x0E 0xXX Unknown meaning
|
||||
0x0F 0xXX Unknown meaning
|
||||
0x10 0xXX Unknown meaning
|
||||
0x11 0xXX Unknown meaning
|
||||
Byte # Value or bits Description
|
||||
------ ------------- -----------
|
||||
0x00 0xFF Frame synchronisation pattern
|
||||
0x01 0xFF Frame synchronisation pattern
|
||||
0x02 0x00 Frame synchronisation pattern
|
||||
0x03 0xC4 Frame synchronisation pattern
|
||||
0x04 0xC4 Frame synchronisation pattern
|
||||
0x05 0x96 Frame synchronisation pattern
|
||||
0x06 [6:0] Read channel gain control = (1/2+R_GAIN/64)
|
||||
0x07 [6:0] Blue channel gain control = (1/2+B_GAIN/64)
|
||||
[7:4]
|
||||
0x08 [ 0 ] Compression mode. 0=No compression, 1=Compression enabled
|
||||
[2:1] Maximum scale factor for compression
|
||||
[ 3 ] 1 = USB fifo(2K bytes) is full
|
||||
[ 4 ] 1 = Digital gain is finish
|
||||
[ 5 ] 1 = Exposure is finish
|
||||
[7:6] Frame index
|
||||
0x09 [7:0] Y sum inside Auto-Exposure area (low-byte)
|
||||
0x0A [7:0] Y sum inside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 32
|
||||
0x0B [7:0] Y sum outside Auto-Exposure area (low-byte)
|
||||
0x0C [7:0] Y sum outside Auto-Exposure area (high-byte)
|
||||
where Y sum = (R/4 + 5G/16 + B/8) / 128
|
||||
0x0D [1:0] Audio frame number
|
||||
[ 2 ] 1 = Audio is recording
|
||||
0x0E [7:0] Audio summation (low-byte)
|
||||
0x0F [7:0] Audio summation (high-byte)
|
||||
0x10 [7:0] Audio sample count
|
||||
0x11 [7:0] Audio peak data in audio frame
|
||||
|
||||
The AE area (sx, sy, ex, ey) in the active window can be set by programming the
|
||||
registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C10x controllers, where one unit
|
||||
registers 0x1c, 0x1d, 0x1e and 0x1f of the SN9C1xx controllers, where one unit
|
||||
corresponds to 32 pixels.
|
||||
|
||||
[1] Part of the meaning of the frame header has been documented by Bertrik
|
||||
Sikken.
|
||||
[1] The frame headers exported by the SN9C105 and SN9C120 are not described.
|
||||
|
||||
|
||||
9. Supported devices
|
||||
@ -323,15 +351,19 @@ here. They have never collaborated with the author, so no advertising.
|
||||
|
||||
From the point of view of a driver, what unambiguously identify a device are
|
||||
its vendor and product USB identifiers. Below is a list of known identifiers of
|
||||
devices mounting the SN9C10x PC camera controllers:
|
||||
devices assembling the SN9C1xx PC camera controllers:
|
||||
|
||||
Vendor ID Product ID
|
||||
--------- ----------
|
||||
0x0471 0x0327
|
||||
0x0471 0x0328
|
||||
0x0c45 0x6001
|
||||
0x0c45 0x6005
|
||||
0x0c45 0x6007
|
||||
0x0c45 0x6009
|
||||
0x0c45 0x600d
|
||||
0x0c45 0x6011
|
||||
0x0c45 0x6019
|
||||
0x0c45 0x6024
|
||||
0x0c45 0x6025
|
||||
0x0c45 0x6028
|
||||
@ -342,6 +374,7 @@ Vendor ID Product ID
|
||||
0x0c45 0x602d
|
||||
0x0c45 0x602e
|
||||
0x0c45 0x6030
|
||||
0x0c45 0x603f
|
||||
0x0c45 0x6080
|
||||
0x0c45 0x6082
|
||||
0x0c45 0x6083
|
||||
@ -368,24 +401,40 @@ Vendor ID Product ID
|
||||
0x0c45 0x60bb
|
||||
0x0c45 0x60bc
|
||||
0x0c45 0x60be
|
||||
0x0c45 0x60c0
|
||||
0x0c45 0x60c8
|
||||
0x0c45 0x60cc
|
||||
0x0c45 0x60ea
|
||||
0x0c45 0x60ec
|
||||
0x0c45 0x60fa
|
||||
0x0c45 0x60fb
|
||||
0x0c45 0x60fc
|
||||
0x0c45 0x60fe
|
||||
0x0c45 0x6130
|
||||
0x0c45 0x613a
|
||||
0x0c45 0x613b
|
||||
0x0c45 0x613c
|
||||
0x0c45 0x613e
|
||||
|
||||
The list above does not imply that all those devices work with this driver: up
|
||||
until now only the ones that mount the following image sensors are supported;
|
||||
kernel messages will always tell you whether this is the case:
|
||||
until now only the ones that assemble the following image sensors are
|
||||
supported; kernel messages will always tell you whether this is the case (see
|
||||
"Module loading" paragraph):
|
||||
|
||||
Model Manufacturer
|
||||
----- ------------
|
||||
HV7131D Hynix Semiconductor, Inc.
|
||||
MI-0343 Micron Technology, Inc.
|
||||
OV7630 OmniVision Technologies, Inc.
|
||||
OV7660 OmniVision Technologies, Inc.
|
||||
PAS106B PixArt Imaging, Inc.
|
||||
PAS202BCA PixArt Imaging, Inc.
|
||||
PAS202BCB PixArt Imaging, Inc.
|
||||
TAS5110C1B Taiwan Advanced Sensor Corporation
|
||||
TAS5130D1B Taiwan Advanced Sensor Corporation
|
||||
|
||||
All the available control settings of each image sensor are supported through
|
||||
the V4L2 interface.
|
||||
Some of the available control settings of each image sensor are supported
|
||||
through the V4L2 interface.
|
||||
|
||||
Donations of new models for further testing and support would be much
|
||||
appreciated. Non-available hardware will not be supported by the author of this
|
||||
@ -429,12 +478,15 @@ supplied by this driver).
|
||||
|
||||
11. Video frame formats [1]
|
||||
=======================
|
||||
The SN9C10x PC Camera Controllers can send images in two possible video
|
||||
formats over the USB: either native "Sequential RGB Bayer" or Huffman
|
||||
compressed. The latter is used to achieve high frame rates. The current video
|
||||
format may be selected or queried from the user application by calling the
|
||||
VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2 API
|
||||
specifications.
|
||||
The SN9C1xx PC Camera Controllers can send images in two possible video
|
||||
formats over the USB: either native "Sequential RGB Bayer" or compressed.
|
||||
The compression is used to achieve high frame rates. With regard to the
|
||||
SN9C101, SN9C102 and SN9C103, the compression is based on the Huffman encoding
|
||||
algorithm described below, while the SN9C105 and SN9C120 the compression is
|
||||
based on the JPEG standard.
|
||||
The current video format may be selected or queried from the user application
|
||||
by calling the VIDIOC_S_FMT or VIDIOC_G_FMT ioctl's, as described in the V4L2
|
||||
API specifications.
|
||||
|
||||
The name "Sequential Bayer" indicates the organization of the red, green and
|
||||
blue pixels in one video frame. Each pixel is associated with a 8-bit long
|
||||
@ -447,14 +499,14 @@ G[m] R[m+1] G[m+2] R[m+2] ... G[2m-2] R[2m-1]
|
||||
... G[n(m-2)] R[n(m-1)]
|
||||
|
||||
The above matrix also represents the sequential or progressive read-out mode of
|
||||
the (n, m) Bayer color filter array used in many CCD/CMOS image sensors.
|
||||
the (n, m) Bayer color filter array used in many CCD or CMOS image sensors.
|
||||
|
||||
One compressed video frame consists of a bitstream that encodes for every R, G,
|
||||
or B pixel the difference between the value of the pixel itself and some
|
||||
reference pixel value. Pixels are organised in the Bayer pattern and the Bayer
|
||||
sub-pixels are tracked individually and alternatingly. For example, in the
|
||||
first line values for the B and G1 pixels are alternatingly encoded, while in
|
||||
the second line values for the G2 and R pixels are alternatingly encoded.
|
||||
The Huffman compressed video frame consists of a bitstream that encodes for
|
||||
every R, G, or B pixel the difference between the value of the pixel itself and
|
||||
some reference pixel value. Pixels are organised in the Bayer pattern and the
|
||||
Bayer sub-pixels are tracked individually and alternatingly. For example, in
|
||||
the first line values for the B and G1 pixels are alternatingly encoded, while
|
||||
in the second line values for the G2 and R pixels are alternatingly encoded.
|
||||
|
||||
The pixel reference value is calculated as follows:
|
||||
- the 4 top left pixels are encoded in raw uncompressed 8-bit format;
|
||||
@ -470,8 +522,9 @@ The pixel reference value is calculated as follows:
|
||||
decoding.
|
||||
|
||||
The algorithm purely describes the conversion from compressed Bayer code used
|
||||
in the SN9C10x chips to uncompressed Bayer. Additional steps are required to
|
||||
convert this to a color image (i.e. a color interpolation algorithm).
|
||||
in the SN9C101, SN9C102 and SN9C103 chips to uncompressed Bayer. Additional
|
||||
steps are required to convert this to a color image (i.e. a color interpolation
|
||||
algorithm).
|
||||
|
||||
The following Huffman codes have been found:
|
||||
0: +0 (relative to reference pixel value)
|
||||
@ -506,13 +559,18 @@ order):
|
||||
- Philippe Coval for having helped testing the PAS202BCA image sensor;
|
||||
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
|
||||
donation of a webcam;
|
||||
- Dennis Heitmann for the donation of a webcam;
|
||||
- Jon Hollstrom for the donation of a webcam;
|
||||
- Nick McGill for the donation of a webcam;
|
||||
- Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB
|
||||
image sensor;
|
||||
- Stefano Mozzi, who donated 45 EU;
|
||||
- Andrew Pearce for the donation of a webcam;
|
||||
- John Pullan for the donation of a webcam;
|
||||
- Bertrik Sikken, who reverse-engineered and documented the Huffman compression
|
||||
algorithm used in the SN9C10x controllers and implemented the first decoder;
|
||||
algorithm used in the SN9C101, SN9C102 and SN9C103 controllers and
|
||||
implemented the first decoder;
|
||||
- Mizuno Takafumi for the donation of a webcam;
|
||||
- an "anonymous" donator (who didn't want his name to be revealed) for the
|
||||
donation of a webcam.
|
||||
- an anonymous donator for the donation of four webcams.
|
||||
|
@ -23,7 +23,7 @@ Index
|
||||
|
||||
1. Copyright
|
||||
============
|
||||
Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it>
|
||||
|
||||
|
||||
2. Disclaimer
|
||||
@ -125,8 +125,9 @@ And finally:
|
||||
6. Module loading
|
||||
=================
|
||||
To use the driver, it is necessary to load the "zc0301" module into memory
|
||||
after every other module required: "videodev", "usbcore" and, depending on
|
||||
the USB host controller you have, "ehci-hcd", "uhci-hcd" or "ohci-hcd".
|
||||
after every other module required: "videodev", "v4l2_common", "compat_ioctl32",
|
||||
"usbcore" and, depending on the USB host controller you have, "ehci-hcd",
|
||||
"uhci-hcd" or "ohci-hcd".
|
||||
|
||||
Loading can be done as shown below:
|
||||
|
||||
@ -211,12 +212,11 @@ Vendor ID Product ID
|
||||
0x041e 0x4036
|
||||
0x041e 0x403a
|
||||
0x0458 0x7007
|
||||
0x0458 0x700C
|
||||
0x0458 0x700c
|
||||
0x0458 0x700f
|
||||
0x046d 0x08ae
|
||||
0x055f 0xd003
|
||||
0x055f 0xd004
|
||||
0x046d 0x08ae
|
||||
0x0ac8 0x0301
|
||||
0x0ac8 0x301b
|
||||
0x0ac8 0x303b
|
||||
|
@ -2748,7 +2748,7 @@ S: Supported
|
||||
PVRUSB2 VIDEO4LINUX DRIVER
|
||||
P: Mike Isely
|
||||
M: isely@pobox.com
|
||||
L: pvrusb2@isely.net
|
||||
L: pvrusb2@isely.net (subscribers-only)
|
||||
L: video4linux-list@redhat.com
|
||||
W: http://www.isely.net/pvrusb2/
|
||||
S: Maintained
|
||||
|
@ -70,6 +70,7 @@ config VIDEO_TUNER
|
||||
depends on I2C
|
||||
|
||||
config VIDEO_BUF
|
||||
depends on PCI
|
||||
tristate
|
||||
|
||||
config VIDEO_BUF_DVB
|
||||
|
@ -5,8 +5,4 @@ config VIDEO_SAA7146
|
||||
config VIDEO_SAA7146_VV
|
||||
tristate
|
||||
select VIDEO_BUF
|
||||
select VIDEO_VIDEOBUF
|
||||
select VIDEO_SAA7146
|
||||
|
||||
config VIDEO_VIDEOBUF
|
||||
tristate
|
||||
|
@ -256,6 +256,112 @@ int ir_decode_biphase(u32 *samples, int count, int low, int high)
|
||||
return value;
|
||||
}
|
||||
|
||||
/* RC5 decoding stuff, moved from bttv-input.c to share it with
|
||||
* saa7134 */
|
||||
|
||||
/* decode raw bit pattern to RC5 code */
|
||||
u32 ir_rc5_decode(unsigned int code)
|
||||
{
|
||||
unsigned int org_code = code;
|
||||
unsigned int pair;
|
||||
unsigned int rc5 = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 14; ++i) {
|
||||
pair = code & 0x3;
|
||||
code >>= 2;
|
||||
|
||||
rc5 <<= 1;
|
||||
switch (pair) {
|
||||
case 0:
|
||||
case 2:
|
||||
break;
|
||||
case 1:
|
||||
rc5 |= 1;
|
||||
break;
|
||||
case 3:
|
||||
dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
|
||||
"instr=%x\n", rc5, org_code, RC5_START(rc5),
|
||||
RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
|
||||
return rc5;
|
||||
}
|
||||
|
||||
void ir_rc5_timer_end(unsigned long data)
|
||||
{
|
||||
struct card_ir *ir = (struct card_ir *)data;
|
||||
struct timeval tv;
|
||||
unsigned long current_jiffies, timeout;
|
||||
u32 gap;
|
||||
u32 rc5 = 0;
|
||||
|
||||
/* get time */
|
||||
current_jiffies = jiffies;
|
||||
do_gettimeofday(&tv);
|
||||
|
||||
/* avoid overflow with gap >1s */
|
||||
if (tv.tv_sec - ir->base_time.tv_sec > 1) {
|
||||
gap = 200000;
|
||||
} else {
|
||||
gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
|
||||
tv.tv_usec - ir->base_time.tv_usec;
|
||||
}
|
||||
|
||||
/* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
|
||||
if (gap < 28000) {
|
||||
dprintk(1, "ir-common: spurious timer_end\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ir->active = 0;
|
||||
if (ir->last_bit < 20) {
|
||||
/* ignore spurious codes (caused by light/other remotes) */
|
||||
dprintk(1, "ir-common: short code: %x\n", ir->code);
|
||||
} else {
|
||||
ir->code = (ir->code << ir->shift_by) | 1;
|
||||
rc5 = ir_rc5_decode(ir->code);
|
||||
|
||||
/* two start bits? */
|
||||
if (RC5_START(rc5) != ir->start) {
|
||||
dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
|
||||
|
||||
/* right address? */
|
||||
} else if (RC5_ADDR(rc5) == ir->addr) {
|
||||
u32 toggle = RC5_TOGGLE(rc5);
|
||||
u32 instr = RC5_INSTR(rc5);
|
||||
|
||||
/* Good code, decide if repeat/repress */
|
||||
if (toggle != RC5_TOGGLE(ir->last_rc5) ||
|
||||
instr != RC5_INSTR(ir->last_rc5)) {
|
||||
dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
|
||||
toggle);
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
ir_input_keydown(ir->dev, &ir->ir, instr,
|
||||
instr);
|
||||
}
|
||||
|
||||
/* Set/reset key-up timer */
|
||||
timeout = current_jiffies + (500 + ir->rc5_key_timeout
|
||||
* HZ) / 1000;
|
||||
mod_timer(&ir->timer_keyup, timeout);
|
||||
|
||||
/* Save code for repeat test */
|
||||
ir->last_rc5 = rc5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ir_rc5_timer_keyup(unsigned long data)
|
||||
{
|
||||
struct card_ir *ir = (struct card_ir *)data;
|
||||
|
||||
dprintk(1, "ir-common: key released\n");
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_input_init);
|
||||
EXPORT_SYMBOL_GPL(ir_input_nokey);
|
||||
EXPORT_SYMBOL_GPL(ir_input_keydown);
|
||||
@ -265,6 +371,10 @@ EXPORT_SYMBOL_GPL(ir_dump_samples);
|
||||
EXPORT_SYMBOL_GPL(ir_decode_biphase);
|
||||
EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_decode);
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
|
||||
EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-basic-offset: 8
|
||||
|
@ -1606,3 +1606,174 @@ IR_KEYTAB_TYPE ir_codes_budget_ci_old[IR_KEYTAB_SIZE] = {
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_budget_ci_old);
|
||||
|
||||
/*
|
||||
* Marc Fargas <telenieko@telenieko.com>
|
||||
* this is the remote control that comes with the asus p7131
|
||||
* which has a label saying is "Model PC-39"
|
||||
*/
|
||||
IR_KEYTAB_TYPE ir_codes_asus_pc39[IR_KEYTAB_SIZE] = {
|
||||
/* 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,
|
||||
|
||||
[ 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 */
|
||||
|
||||
[ 0x21 ] = KEY_TV, /* tv */
|
||||
[ 0x1d ] = KEY_EXIT, /* back */
|
||||
[ 0x0a ] = KEY_CHANNELUP, /* channel / program + */
|
||||
[ 0x1b ] = KEY_CHANNELDOWN, /* channel / program - */
|
||||
[ 0x1a ] = 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" */
|
||||
|
||||
[ 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 */
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_asus_pc39);
|
||||
|
||||
|
||||
/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
|
||||
Juan Pablo Sormani <sorman@gmail.com> */
|
||||
IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = {
|
||||
|
||||
/* Power button does nothing, neither in Windows app,
|
||||
although it sends data (used for BIOS wakeup?) */
|
||||
[ 0x0d ] = KEY_MUTE,
|
||||
|
||||
[ 0x1e ] = KEY_TV,
|
||||
[ 0x00 ] = KEY_VIDEO,
|
||||
[ 0x01 ] = KEY_AUDIO, /* music */
|
||||
[ 0x02 ] = KEY_MHP, /* picture */
|
||||
|
||||
[ 0x1f ] = KEY_1,
|
||||
[ 0x03 ] = KEY_2,
|
||||
[ 0x04 ] = KEY_3,
|
||||
[ 0x05 ] = KEY_4,
|
||||
[ 0x1c ] = KEY_5,
|
||||
[ 0x06 ] = KEY_6,
|
||||
[ 0x07 ] = KEY_7,
|
||||
[ 0x08 ] = KEY_8,
|
||||
[ 0x1d ] = KEY_9,
|
||||
[ 0x0a ] = KEY_0,
|
||||
|
||||
[ 0x09 ] = KEY_LIST, /* -/-- */
|
||||
[ 0x0b ] = KEY_LAST, /* recall */
|
||||
|
||||
[ 0x14 ] = KEY_HOME, /* win start menu */
|
||||
[ 0x15 ] = KEY_EXIT, /* exit */
|
||||
[ 0x16 ] = KEY_UP,
|
||||
[ 0x12 ] = KEY_DOWN,
|
||||
[ 0x0c ] = KEY_RIGHT,
|
||||
[ 0x17 ] = KEY_LEFT,
|
||||
|
||||
[ 0x18 ] = KEY_ENTER, /* OK */
|
||||
|
||||
[ 0x0e ] = KEY_ESC,
|
||||
[ 0x13 ] = KEY_D, /* desktop */
|
||||
[ 0x11 ] = KEY_TAB,
|
||||
[ 0x19 ] = KEY_SWITCHVIDEOMODE, /* switch */
|
||||
|
||||
[ 0x1a ] = KEY_MENU,
|
||||
[ 0x1b ] = KEY_ZOOM, /* fullscreen */
|
||||
[ 0x44 ] = KEY_TIME, /* time shift */
|
||||
[ 0x40 ] = KEY_MODE, /* source */
|
||||
|
||||
[ 0x5a ] = KEY_RECORD,
|
||||
[ 0x42 ] = KEY_PLAY, /* play/pause */
|
||||
[ 0x45 ] = KEY_STOP,
|
||||
[ 0x43 ] = KEY_CAMERA, /* camera icon */
|
||||
|
||||
[ 0x48 ] = KEY_REWIND,
|
||||
[ 0x4a ] = KEY_FASTFORWARD,
|
||||
[ 0x49 ] = KEY_PREVIOUS,
|
||||
[ 0x4b ] = KEY_NEXT,
|
||||
|
||||
[ 0x4c ] = KEY_FAVORITES, /* tv wall */
|
||||
[ 0x4d ] = KEY_SOUND, /* DVD sound */
|
||||
[ 0x4e ] = KEY_LANGUAGE, /* DVD lang */
|
||||
[ 0x4f ] = KEY_TEXT, /* DVD text */
|
||||
|
||||
[ 0x50 ] = KEY_SLEEP, /* shutdown */
|
||||
[ 0x51 ] = KEY_MODE, /* stereo > main */
|
||||
[ 0x52 ] = KEY_SELECT, /* stereo > sap */
|
||||
[ 0x53 ] = KEY_PROG1, /* teletext */
|
||||
|
||||
|
||||
[ 0x59 ] = KEY_RED, /* AP1 */
|
||||
[ 0x41 ] = KEY_GREEN, /* AP2 */
|
||||
[ 0x47 ] = KEY_YELLOW, /* AP3 */
|
||||
[ 0x57 ] = KEY_BLUE, /* AP4 */
|
||||
|
||||
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_encore_enltv);
|
||||
|
||||
/* for the Technotrend 1500 bundled remote: */
|
||||
IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = {
|
||||
[ 0x01 ] = KEY_POWER,
|
||||
[ 0x02 ] = KEY_SHUFFLE, /* ? double-arrow key */
|
||||
[ 0x03 ] = KEY_1,
|
||||
[ 0x04 ] = KEY_2,
|
||||
[ 0x05 ] = KEY_3,
|
||||
[ 0x06 ] = KEY_4,
|
||||
[ 0x07 ] = KEY_5,
|
||||
[ 0x08 ] = KEY_6,
|
||||
[ 0x09 ] = KEY_7,
|
||||
[ 0x0a ] = KEY_8,
|
||||
[ 0x0b ] = KEY_9,
|
||||
[ 0x0c ] = KEY_0,
|
||||
[ 0x0d ] = KEY_UP,
|
||||
[ 0x0e ] = KEY_LEFT,
|
||||
[ 0x0f ] = KEY_OK,
|
||||
[ 0x10 ] = KEY_RIGHT,
|
||||
[ 0x11 ] = KEY_DOWN,
|
||||
[ 0x12 ] = KEY_INFO,
|
||||
[ 0x13 ] = KEY_EXIT,
|
||||
[ 0x14 ] = KEY_RED,
|
||||
[ 0x15 ] = KEY_GREEN,
|
||||
[ 0x16 ] = KEY_YELLOW,
|
||||
[ 0x17 ] = KEY_BLUE,
|
||||
[ 0x18 ] = KEY_MUTE,
|
||||
[ 0x19 ] = KEY_TEXT,
|
||||
[ 0x1a ] = KEY_MODE, /* ? TV/Radio */
|
||||
[ 0x21 ] = KEY_OPTION,
|
||||
[ 0x22 ] = KEY_EPG,
|
||||
[ 0x23 ] = KEY_CHANNELUP,
|
||||
[ 0x24 ] = KEY_CHANNELDOWN,
|
||||
[ 0x25 ] = KEY_VOLUMEUP,
|
||||
[ 0x26 ] = KEY_VOLUMEDOWN,
|
||||
[ 0x27 ] = KEY_SETUP,
|
||||
};
|
||||
|
||||
EXPORT_SYMBOL_GPL(ir_codes_tt_1500);
|
||||
|
@ -508,7 +508,7 @@ int saa7146_vv_release(struct saa7146_dev* dev)
|
||||
|
||||
DEB_EE(("dev:%p\n",dev));
|
||||
|
||||
pci_free_consistent(dev->pci, SAA7146_RPS_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
|
||||
pci_free_consistent(dev->pci, SAA7146_CLIPPING_MEM, vv->d_clipping.cpu_addr, vv->d_clipping.dma_handle);
|
||||
kfree(vv);
|
||||
dev->vv_data = NULL;
|
||||
dev->vv_callback = NULL;
|
||||
|
@ -385,9 +385,9 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
|
||||
else buf[3] = 0x88;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1);
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
|
||||
ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3);
|
||||
ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
|
||||
deb_tuner("tuner write returned: %d\n",ret);
|
||||
|
||||
return 0;
|
||||
@ -398,91 +398,71 @@ static u8 alps_tdee4_stv0297_inittab[] = {
|
||||
0x80, 0x00,
|
||||
0x81, 0x01,
|
||||
0x81, 0x00,
|
||||
0x00, 0x09,
|
||||
0x01, 0x69,
|
||||
0x00, 0x48,
|
||||
0x01, 0x58,
|
||||
0x03, 0x00,
|
||||
0x04, 0x00,
|
||||
0x07, 0x00,
|
||||
0x08, 0x00,
|
||||
0x20, 0x00,
|
||||
0x21, 0x40,
|
||||
0x22, 0x00,
|
||||
0x23, 0x00,
|
||||
0x24, 0x40,
|
||||
0x25, 0x88,
|
||||
0x30, 0xff,
|
||||
0x31, 0x00,
|
||||
0x31, 0x9d,
|
||||
0x32, 0xff,
|
||||
0x33, 0x00,
|
||||
0x34, 0x50,
|
||||
0x35, 0x7f,
|
||||
0x36, 0x00,
|
||||
0x37, 0x20,
|
||||
0x38, 0x00,
|
||||
0x40, 0x1c,
|
||||
0x41, 0xff,
|
||||
0x42, 0x29,
|
||||
0x34, 0x29,
|
||||
0x35, 0x55,
|
||||
0x36, 0x80,
|
||||
0x37, 0x6e,
|
||||
0x38, 0x9c,
|
||||
0x40, 0x1a,
|
||||
0x41, 0xfe,
|
||||
0x42, 0x33,
|
||||
0x43, 0x00,
|
||||
0x44, 0xff,
|
||||
0x45, 0x00,
|
||||
0x46, 0x00,
|
||||
0x49, 0x04,
|
||||
0x4a, 0x00,
|
||||
0x4a, 0x51,
|
||||
0x4b, 0xf8,
|
||||
0x52, 0x30,
|
||||
0x55, 0xae,
|
||||
0x56, 0x47,
|
||||
0x57, 0xe1,
|
||||
0x58, 0x3a,
|
||||
0x5a, 0x1e,
|
||||
0x5b, 0x34,
|
||||
0x60, 0x00,
|
||||
0x63, 0x00,
|
||||
0x64, 0x00,
|
||||
0x65, 0x00,
|
||||
0x66, 0x00,
|
||||
0x67, 0x00,
|
||||
0x68, 0x00,
|
||||
0x69, 0x00,
|
||||
0x6a, 0x02,
|
||||
0x6b, 0x00,
|
||||
0x53, 0x06,
|
||||
0x59, 0x06,
|
||||
0x5a, 0x5e,
|
||||
0x5b, 0x04,
|
||||
0x61, 0x49,
|
||||
0x62, 0x0a,
|
||||
0x70, 0xff,
|
||||
0x71, 0x00,
|
||||
0x71, 0x04,
|
||||
0x72, 0x00,
|
||||
0x73, 0x00,
|
||||
0x74, 0x0c,
|
||||
0x80, 0x00,
|
||||
0x80, 0x20,
|
||||
0x81, 0x00,
|
||||
0x82, 0x00,
|
||||
0x82, 0x30,
|
||||
0x83, 0x00,
|
||||
0x84, 0x04,
|
||||
0x85, 0x80,
|
||||
0x86, 0x24,
|
||||
0x87, 0x78,
|
||||
0x88, 0x10,
|
||||
0x85, 0x22,
|
||||
0x86, 0x08,
|
||||
0x87, 0x1b,
|
||||
0x88, 0x00,
|
||||
0x89, 0x00,
|
||||
0x90, 0x01,
|
||||
0x91, 0x01,
|
||||
0xa0, 0x04,
|
||||
0x90, 0x00,
|
||||
0x91, 0x04,
|
||||
0xa0, 0x86,
|
||||
0xa1, 0x00,
|
||||
0xa2, 0x00,
|
||||
0xb0, 0x91,
|
||||
0xb1, 0x0b,
|
||||
0xc0, 0x53,
|
||||
0xc1, 0x70,
|
||||
0xc0, 0x5b,
|
||||
0xc1, 0x10,
|
||||
0xc2, 0x12,
|
||||
0xd0, 0x00,
|
||||
0xd0, 0x02,
|
||||
0xd1, 0x00,
|
||||
0xd2, 0x00,
|
||||
0xd3, 0x00,
|
||||
0xd4, 0x00,
|
||||
0xd4, 0x02,
|
||||
0xd5, 0x00,
|
||||
0xde, 0x00,
|
||||
0xdf, 0x00,
|
||||
0x61, 0x49,
|
||||
0x62, 0x0b,
|
||||
0x53, 0x08,
|
||||
0x59, 0x08,
|
||||
0xdf, 0x01,
|
||||
0xff, 0xff,
|
||||
};
|
||||
|
||||
|
@ -390,6 +390,7 @@ static struct cards card_list[] __devinitdata = {
|
||||
{ 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" },
|
||||
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
|
||||
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
|
||||
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
|
||||
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
|
||||
{ 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
|
||||
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
|
||||
|
@ -1161,7 +1161,7 @@ static int dst_get_device_id(struct dst_state *state)
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= sizeof (dst_tlist) / sizeof (dst_tlist [0])) {
|
||||
if (i >= ARRAY_SIZE(dst_tlist)) {
|
||||
dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]);
|
||||
dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in");
|
||||
use_dst_type = DST_TYPE_IS_SAT;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
@ -213,7 +214,7 @@ static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
|
||||
freq = 2150000; /* satellite IF is 950..2150MHz */
|
||||
|
||||
/* decide which VCO to use for the input frequency */
|
||||
for(i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++);
|
||||
for(i = 1; (i < ARRAY_SIZE(osci)) && (osci[i] < freq); i++);
|
||||
printk("cx24108 debug: select vco #%d (f=%d)\n",i,freq);
|
||||
band=bandsel[i];
|
||||
/* the gain values must be set by SetSymbolrate */
|
||||
|
@ -819,6 +819,11 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2)
|
||||
set_bit(rc_keys[i + 2], input_dev->keybit);
|
||||
input_dev->keycodesize = 0;
|
||||
input_dev->keycodemax = 0;
|
||||
input_dev->id.bustype = BUS_USB;
|
||||
input_dev->id.vendor = cinergyt2->udev->descriptor.idVendor;
|
||||
input_dev->id.product = cinergyt2->udev->descriptor.idProduct;
|
||||
input_dev->id.version = 1;
|
||||
input_dev->cdev.dev = &cinergyt2->udev->dev;
|
||||
|
||||
err = input_register_device(input_dev);
|
||||
if (err) {
|
||||
|
@ -36,6 +36,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
@ -100,7 +101,7 @@ struct dvb_frontend_private {
|
||||
struct semaphore sem;
|
||||
struct list_head list_head;
|
||||
wait_queue_head_t wait_queue;
|
||||
pid_t thread_pid;
|
||||
struct task_struct *thread;
|
||||
unsigned long release_jiffies;
|
||||
unsigned int exit;
|
||||
unsigned int wakeup;
|
||||
@ -508,19 +509,11 @@ static int dvb_frontend_thread(void *data)
|
||||
struct dvb_frontend *fe = data;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
unsigned long timeout;
|
||||
char name [15];
|
||||
fe_status_t s;
|
||||
struct dvb_frontend_parameters *params;
|
||||
|
||||
dprintk("%s\n", __FUNCTION__);
|
||||
|
||||
snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num);
|
||||
|
||||
lock_kernel();
|
||||
daemonize(name);
|
||||
sigfillset(¤t->blocked);
|
||||
unlock_kernel();
|
||||
|
||||
fepriv->check_wrapped = 0;
|
||||
fepriv->quality = 0;
|
||||
fepriv->delay = 3*HZ;
|
||||
@ -532,16 +525,18 @@ static int dvb_frontend_thread(void *data)
|
||||
|
||||
while (1) {
|
||||
up(&fepriv->sem); /* is locked when we enter the thread... */
|
||||
|
||||
restart:
|
||||
timeout = wait_event_interruptible_timeout(fepriv->wait_queue,
|
||||
dvb_frontend_should_wakeup(fe),
|
||||
fepriv->delay);
|
||||
if (0 != dvb_frontend_is_exiting(fe)) {
|
||||
dvb_frontend_should_wakeup(fe) || kthread_should_stop(),
|
||||
fepriv->delay);
|
||||
|
||||
if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
|
||||
/* got signal or quitting */
|
||||
break;
|
||||
}
|
||||
|
||||
try_to_freeze();
|
||||
if (try_to_freeze())
|
||||
goto restart;
|
||||
|
||||
if (down_interruptible(&fepriv->sem))
|
||||
break;
|
||||
@ -591,7 +586,7 @@ static int dvb_frontend_thread(void *data)
|
||||
fe->ops.sleep(fe);
|
||||
}
|
||||
|
||||
fepriv->thread_pid = 0;
|
||||
fepriv->thread = NULL;
|
||||
mb();
|
||||
|
||||
dvb_frontend_wakeup(fe);
|
||||
@ -600,7 +595,6 @@ static int dvb_frontend_thread(void *data)
|
||||
|
||||
static void dvb_frontend_stop(struct dvb_frontend *fe)
|
||||
{
|
||||
unsigned long ret;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
||||
dprintk ("%s\n", __FUNCTION__);
|
||||
@ -608,33 +602,17 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
|
||||
fepriv->exit = 1;
|
||||
mb();
|
||||
|
||||
if (!fepriv->thread_pid)
|
||||
if (!fepriv->thread)
|
||||
return;
|
||||
|
||||
/* check if the thread is really alive */
|
||||
if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) {
|
||||
printk("dvb_frontend_stop: thread PID %d already died\n",
|
||||
fepriv->thread_pid);
|
||||
/* make sure the mutex was not held by the thread */
|
||||
init_MUTEX (&fepriv->sem);
|
||||
return;
|
||||
}
|
||||
|
||||
/* wake up the frontend thread, so it notices that fe->exit == 1 */
|
||||
dvb_frontend_wakeup(fe);
|
||||
|
||||
/* wait until the frontend thread has exited */
|
||||
ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid);
|
||||
if (-ERESTARTSYS != ret) {
|
||||
fepriv->state = FESTATE_IDLE;
|
||||
return;
|
||||
}
|
||||
kthread_stop(fepriv->thread);
|
||||
init_MUTEX (&fepriv->sem);
|
||||
fepriv->state = FESTATE_IDLE;
|
||||
|
||||
/* paranoia check in case a signal arrived */
|
||||
if (fepriv->thread_pid)
|
||||
printk("dvb_frontend_stop: warning: thread PID %d won't exit\n",
|
||||
fepriv->thread_pid);
|
||||
if (fepriv->thread)
|
||||
printk("dvb_frontend_stop: warning: thread %p won't exit\n",
|
||||
fepriv->thread);
|
||||
}
|
||||
|
||||
s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
|
||||
@ -684,10 +662,11 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
|
||||
{
|
||||
int ret;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct task_struct *fe_thread;
|
||||
|
||||
dprintk ("%s\n", __FUNCTION__);
|
||||
|
||||
if (fepriv->thread_pid) {
|
||||
if (fepriv->thread) {
|
||||
if (!fepriv->exit)
|
||||
return 0;
|
||||
else
|
||||
@ -701,18 +680,18 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
|
||||
|
||||
fepriv->state = FESTATE_IDLE;
|
||||
fepriv->exit = 0;
|
||||
fepriv->thread_pid = 0;
|
||||
fepriv->thread = NULL;
|
||||
mb();
|
||||
|
||||
ret = kernel_thread (dvb_frontend_thread, fe, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret);
|
||||
fe_thread = kthread_run(dvb_frontend_thread, fe,
|
||||
"kdvb-fe-%i", fe->dvb->num);
|
||||
if (IS_ERR(fe_thread)) {
|
||||
ret = PTR_ERR(fe_thread);
|
||||
printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
|
||||
up(&fepriv->sem);
|
||||
return ret;
|
||||
}
|
||||
fepriv->thread_pid = ret;
|
||||
|
||||
fepriv->thread = fe_thread;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -199,12 +199,14 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template, void *priv, int type)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
|
||||
int id;
|
||||
|
||||
if (mutex_lock_interruptible(&dvbdev_register_lock))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if ((id = dvbdev_get_free_id (adap, type)) < 0) {
|
||||
if ((id = dvbdev_get_free_id (adap, type)) < 0){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
*pdvbdev = NULL;
|
||||
printk ("%s: could get find free device id...\n", __FUNCTION__);
|
||||
@ -213,7 +215,15 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
|
||||
*pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
|
||||
|
||||
if (!dvbdev) {
|
||||
if (!dvbdev){
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
|
||||
|
||||
if (!dvbdevfops){
|
||||
kfree (dvbdev);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -223,7 +233,9 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
dvbdev->id = id;
|
||||
dvbdev->adapter = adap;
|
||||
dvbdev->priv = priv;
|
||||
dvbdev->fops = dvbdevfops;
|
||||
|
||||
memcpy(dvbdev->fops, template->fops, sizeof(struct file_operations));
|
||||
dvbdev->fops->owner = adap->module;
|
||||
|
||||
list_add_tail (&dvbdev->list_head, &adap->device_list);
|
||||
@ -251,6 +263,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev)
|
||||
dvbdev->type, dvbdev->id)));
|
||||
|
||||
list_del (&dvbdev->list_head);
|
||||
kfree (dvbdev->fops);
|
||||
kfree (dvbdev);
|
||||
}
|
||||
EXPORT_SYMBOL(dvb_unregister_device);
|
||||
|
@ -109,6 +109,34 @@ config DVB_USB_CXUSB
|
||||
Medion MD95700 hybrid USB2.0 device.
|
||||
DViCO FusionHDTV (Bluebird) USB2.0 devices
|
||||
|
||||
config DVB_USB_M920X
|
||||
tristate "Uli m920x DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_MT352 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
|
||||
Currently, only devices with a product id of
|
||||
"DTV USB MINI" (in cold state) are supported.
|
||||
Firmware required.
|
||||
|
||||
config DVB_USB_GL861
|
||||
tristate "Genesys Logic GL861 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0
|
||||
receiver with USB ID 0db0:5581.
|
||||
|
||||
config DVB_USB_AU6610
|
||||
tristate "Alcor Micro AU6610 USB2.0 support"
|
||||
depends on DVB_USB
|
||||
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
|
||||
select DVB_TUNER_QT1010 if !DVB_FE_CUSTOMISE
|
||||
help
|
||||
Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver.
|
||||
|
||||
config DVB_USB_DIGITV
|
||||
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
|
||||
depends on DVB_USB
|
||||
|
@ -30,6 +30,15 @@ obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2
|
||||
dvb-usb-umt-010-objs = umt-010.o
|
||||
obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
|
||||
|
||||
dvb-usb-m920x-objs = m920x.o
|
||||
obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o
|
||||
|
||||
dvb-usb-gl861-objs = gl861.o
|
||||
obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o
|
||||
|
||||
dvb-usb-au6610-objs = au6610.o
|
||||
obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o
|
||||
|
||||
dvb-usb-digitv-objs = digitv.o
|
||||
obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
|
||||
|
||||
|
255
drivers/media/dvb/dvb-usb/au6610.c
Normal file
255
drivers/media/dvb/dvb-usb/au6610.c
Normal file
@ -0,0 +1,255 @@
|
||||
/* DVB USB compliant linux driver for Sigmatek DVB-110 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation, version 2.
|
||||
*
|
||||
* see Documentation/dvb/README.dvb-usb for more information
|
||||
*/
|
||||
|
||||
#include "au6610.h"
|
||||
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_au6610_debug;
|
||||
module_param_named(debug, dvb_usb_au6610_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int au6610_usb_msg(struct dvb_usb_device *d, u8 operation, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
int ret;
|
||||
u16 index;
|
||||
u8 usb_buf[6]; /* enough for all known requests,
|
||||
read returns 5 and write 6 bytes */
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0] << 8;
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0] << 8;
|
||||
index += wbuf[1];
|
||||
break;
|
||||
default:
|
||||
warn("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), operation,
|
||||
USB_TYPE_VENDOR|USB_DIR_IN, addr, index, usb_buf,
|
||||
sizeof(usb_buf), AU6610_USB_TIMEOUT);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
switch (operation) {
|
||||
case AU6610_REQ_I2C_READ:
|
||||
case AU6610_REQ_USB_READ:
|
||||
/* requested value is always 5th byte in buffer */
|
||||
rbuf[0] = usb_buf[4];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au6610_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u8 request;
|
||||
u8 wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
|
||||
if (wo) {
|
||||
request = AU6610_REQ_I2C_WRITE;
|
||||
} else { /* rw */
|
||||
request = AU6610_REQ_I2C_READ;
|
||||
}
|
||||
|
||||
return au6610_usb_msg(d, request, addr, wbuf, wlen, rbuf, rlen);
|
||||
}
|
||||
|
||||
|
||||
/* I2C */
|
||||
static int au6610_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf,
|
||||
msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else if (au6610_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static u32 au6610_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm au6610_i2c_algo = {
|
||||
.master_xfer = au6610_i2c_xfer,
|
||||
.functionality = au6610_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int au6610_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zl10353_config au6610_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int au6610_zl10353_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(zl10353_attach, &au6610_zl10353_config,
|
||||
&adap->dev->i2c_adap)) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct qt1010_config au6610_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
};
|
||||
|
||||
static int au6610_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe, &adap->dev->i2c_adap,
|
||||
&au6610_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties au6610_properties;
|
||||
|
||||
static int au6610_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if (intf->num_altsetting < AU6610_ALTSETTING_COUNT)
|
||||
return -ENODEV;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &au6610_properties, THIS_MODULE, &d)) == 0) {
|
||||
alt = usb_altnum_to_altsetting(intf, AU6610_ALTSETTING);
|
||||
|
||||
if (alt == NULL) {
|
||||
deb_rc("no alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static struct usb_device_id au6610_table [] = {
|
||||
{ USB_DEVICE(USB_VID_ALCOR_MICRO, USB_PID_SIGMATEK_DVB_110) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, au6610_table);
|
||||
|
||||
static struct dvb_usb_device_properties au6610_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.size_of_priv = 0,
|
||||
.identify_state = au6610_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {
|
||||
{
|
||||
.frontend_attach = au6610_zl10353_frontend_attach,
|
||||
.tuner_attach = au6610_qt1010_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_ISOC,
|
||||
.count = 5,
|
||||
.endpoint = 0x82,
|
||||
.u = {
|
||||
.isoc = {
|
||||
.framesperurb = 40,
|
||||
.framesize = 942, /* maximum packet size */
|
||||
.interval = 1.25, /* 125 us */
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
.i2c_algo = &au6610_i2c_algo,
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{
|
||||
"Sigmatek DVB-110 DVB-T USB2.0",
|
||||
{ &au6610_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver au6610_driver = {
|
||||
.name = "dvb_usb_au6610",
|
||||
.probe = au6610_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = au6610_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init au6610_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&au6610_driver))) {
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit au6610_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&au6610_driver);
|
||||
}
|
||||
|
||||
module_init (au6610_module_init);
|
||||
module_exit (au6610_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_DESCRIPTION("Driver Sigmatek DVB-110 DVB-T USB2.0 / AU6610");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
19
drivers/media/dvb/dvb-usb/au6610.h
Normal file
19
drivers/media/dvb/dvb-usb/au6610.h
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _DVB_USB_AU6610_H_
|
||||
#define _DVB_USB_AU6610_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "au6610"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_au6610_debug,0x01,args)
|
||||
|
||||
#define AU6610_REQ_I2C_WRITE 0x14
|
||||
#define AU6610_REQ_I2C_READ 0x13
|
||||
#define AU6610_REQ_USB_WRITE 0x16
|
||||
#define AU6610_REQ_USB_READ 0x15
|
||||
|
||||
#define AU6610_USB_TIMEOUT 1000
|
||||
|
||||
#define AU6610_ALTSETTING_COUNT 6
|
||||
#define AU6610_ALTSETTING 5
|
||||
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
|
||||
/* Vendor IDs */
|
||||
#define USB_VID_ADSTECH 0x06e1
|
||||
#define USB_VID_ALCOR_MICRO 0x058f
|
||||
#define USB_VID_ANCHOR 0x0547
|
||||
#define USB_VID_AVERMEDIA 0x07ca
|
||||
#define USB_VID_COMPRO 0x185b
|
||||
@ -29,6 +30,7 @@
|
||||
#define USB_VID_LEADTEK 0x0413
|
||||
#define USB_VID_LITEON 0x04ca
|
||||
#define USB_VID_MEDION 0x1660
|
||||
#define USB_VID_MSI 0x0db0
|
||||
#define USB_VID_PINNACLE 0x2304
|
||||
#define USB_VID_VISIONPLUS 0x13d3
|
||||
#define USB_VID_TWINHAN 0x1822
|
||||
@ -119,6 +121,8 @@
|
||||
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
|
||||
#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55
|
||||
#define USB_PID_MEDION_MD95700 0x0932
|
||||
#define USB_PID_MSI_MEGASKY580 0x5580
|
||||
#define USB_PID_MSI_MEGASKY580_55801 0x5581
|
||||
#define USB_PID_KYE_DVB_T_COLD 0x701e
|
||||
#define USB_PID_KYE_DVB_T_WARM 0x701f
|
||||
#define USB_PID_PCTV_200E 0x020e
|
||||
@ -134,6 +138,7 @@
|
||||
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
|
||||
#define USB_PID_GENPIX_8PSK_COLD 0x0200
|
||||
#define USB_PID_GENPIX_8PSK_WARM 0x0201
|
||||
#define USB_PID_SIGMATEK_DVB_110 0x6610
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -151,7 +151,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
|
||||
int dvb_usb_remote_exit(struct dvb_usb_device *d)
|
||||
{
|
||||
if (d->state & DVB_USB_STATE_REMOTE) {
|
||||
cancel_delayed_work(&d->rc_query_work);
|
||||
cancel_rearming_delayed_work(&d->rc_query_work);
|
||||
flush_scheduled_work();
|
||||
input_unregister_device(d->rc_input_dev);
|
||||
}
|
||||
|
231
drivers/media/dvb/dvb-usb/gl861.c
Normal file
231
drivers/media/dvb/dvb-usb/gl861.c
Normal file
@ -0,0 +1,231 @@
|
||||
/* DVB USB compliant linux driver for GL861 USB2.0 devices.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
#include "gl861.h"
|
||||
|
||||
#include "zl10353.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
int dvb_usb_gl861_debug;
|
||||
module_param_named(debug,dvb_usb_gl861_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
|
||||
u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
|
||||
{
|
||||
u16 index;
|
||||
u16 value = addr << 8;
|
||||
int wo = (rbuf == NULL || rlen == 0); /* write-only */
|
||||
u8 req, type;
|
||||
|
||||
if (wo) {
|
||||
req = GL861_REQ_I2C_WRITE;
|
||||
type = GL861_WRITE;
|
||||
} else { /* rw */
|
||||
req = GL861_REQ_I2C_READ;
|
||||
type = GL861_READ;
|
||||
}
|
||||
|
||||
switch (wlen) {
|
||||
case 1:
|
||||
index = wbuf[0];
|
||||
break;
|
||||
case 2:
|
||||
index = wbuf[0];
|
||||
value = value + wbuf[1];
|
||||
break;
|
||||
default:
|
||||
warn("wlen = %x, aborting.", wlen);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0), req, type,
|
||||
value, index, rbuf, rlen, 2000);
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
int i;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
/* write/read request */
|
||||
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, msg[i+1].buf, msg[i+1].len) < 0)
|
||||
break;
|
||||
i++;
|
||||
} else
|
||||
if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
|
||||
msg[i].len, NULL, 0) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
return i;
|
||||
}
|
||||
|
||||
static u32 gl861_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm gl861_i2c_algo = {
|
||||
.master_xfer = gl861_i2c_xfer,
|
||||
.functionality = gl861_i2c_func,
|
||||
};
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int gl861_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
*cold = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct zl10353_config gl861_zl10353_config = {
|
||||
.demod_address = 0x1e,
|
||||
.no_tuner = 1,
|
||||
.parallel_ts = 1,
|
||||
};
|
||||
|
||||
static int gl861_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
if ((adap->fe = dvb_attach(zl10353_attach, &gl861_zl10353_config,
|
||||
&adap->dev->i2c_adap)) != NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct qt1010_config gl861_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
};
|
||||
|
||||
static int gl861_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
return dvb_attach(qt1010_attach,
|
||||
adap->fe, &adap->dev->i2c_adap,
|
||||
&gl861_qt1010_config) == NULL ? -ENODEV : 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties gl861_properties;
|
||||
|
||||
static int gl861_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if (intf->num_altsetting < 2)
|
||||
return -ENODEV;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &gl861_properties, THIS_MODULE, &d)) == 0) {
|
||||
alt = usb_altnum_to_altsetting(intf, 0);
|
||||
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id gl861_table [] = {
|
||||
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, gl861_table);
|
||||
|
||||
static struct dvb_usb_device_properties gl861_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
|
||||
.size_of_priv = 0,
|
||||
|
||||
.identify_state = gl861_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
|
||||
.frontend_attach = gl861_frontend_attach,
|
||||
.tuner_attach = gl861_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 7,
|
||||
.endpoint = 0x81,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.i2c_algo = &gl861_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "MSI Mega Sky 55801 DVB-T USB2.0",
|
||||
{ &gl861_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver gl861_driver = {
|
||||
.name = "dvb_usb_gl861",
|
||||
.probe = gl861_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = gl861_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init gl861_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&gl861_driver))) {
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit gl861_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&gl861_driver);
|
||||
}
|
||||
|
||||
module_init (gl861_module_init);
|
||||
module_exit (gl861_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Carl Lundqvist <comabug@gmail.com>");
|
||||
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / GL861");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
15
drivers/media/dvb/dvb-usb/gl861.h
Normal file
15
drivers/media/dvb/dvb-usb/gl861.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef _DVB_USB_GL861_H_
|
||||
#define _DVB_USB_GL861_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "gl861"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_gl861_debug,0x01,args)
|
||||
|
||||
#define GL861_WRITE 0x40
|
||||
#define GL861_READ 0xc0
|
||||
|
||||
#define GL861_REQ_I2C_WRITE 0x01
|
||||
#define GL861_REQ_I2C_READ 0x02
|
||||
|
||||
#endif
|
541
drivers/media/dvb/dvb-usb/m920x.c
Normal file
541
drivers/media/dvb/dvb-usb/m920x.c
Normal file
@ -0,0 +1,541 @@
|
||||
/* DVB USB compliant linux driver for MSI Mega Sky 580 DVB-T USB2.0 receiver
|
||||
*
|
||||
* Copyright (C) 2006 Aapo Tahkola (aet@rasterburn.org)
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "m920x.h"
|
||||
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#include "qt1010.h"
|
||||
|
||||
/* debug */
|
||||
static int dvb_usb_m920x_debug;
|
||||
module_param_named(debug,dvb_usb_m920x_debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
|
||||
|
||||
static struct dvb_usb_rc_key megasky_rc_keys [] = {
|
||||
{ 0x0, 0x12, KEY_POWER },
|
||||
{ 0x0, 0x1e, KEY_CYCLEWINDOWS }, /* min/max */
|
||||
{ 0x0, 0x02, KEY_CHANNELUP },
|
||||
{ 0x0, 0x05, KEY_CHANNELDOWN },
|
||||
{ 0x0, 0x03, KEY_VOLUMEUP },
|
||||
{ 0x0, 0x06, KEY_VOLUMEDOWN },
|
||||
{ 0x0, 0x04, KEY_MUTE },
|
||||
{ 0x0, 0x07, KEY_OK }, /* TS */
|
||||
{ 0x0, 0x08, KEY_STOP },
|
||||
{ 0x0, 0x09, KEY_MENU }, /* swap */
|
||||
{ 0x0, 0x0a, KEY_REWIND },
|
||||
{ 0x0, 0x1b, KEY_PAUSE },
|
||||
{ 0x0, 0x1f, KEY_FASTFORWARD },
|
||||
{ 0x0, 0x0c, KEY_RECORD },
|
||||
{ 0x0, 0x0d, KEY_CAMERA }, /* screenshot */
|
||||
{ 0x0, 0x0e, KEY_COFFEE }, /* "MTS" */
|
||||
};
|
||||
|
||||
static inline int m9206_read(struct usb_device *udev, u8 request, u16 value,\
|
||||
u16 index, void *data, int size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
|
||||
request, USB_TYPE_VENDOR | USB_DIR_IN,
|
||||
value, index, data, size, 2000);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != size)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int m9206_write(struct usb_device *udev, u8 request,
|
||||
u16 value, u16 index)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
request, USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value, index, NULL, 0, 2000);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_rc_init(struct usb_device *udev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Remote controller init. */
|
||||
if ((ret = m9206_write(udev, M9206_CORE, 0xa8, M9206_RC_INIT2)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_write(udev, M9206_CORE, 0x51, M9206_RC_INIT1)) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
|
||||
{
|
||||
struct m9206_state *m = d->priv;
|
||||
int i, ret = 0;
|
||||
u8 rc_state[2];
|
||||
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_STATE, rc_state, 1)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
|
||||
goto unlock;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(megasky_rc_keys); i++)
|
||||
if (megasky_rc_keys[i].data == rc_state[1]) {
|
||||
*event = megasky_rc_keys[i].event;
|
||||
|
||||
switch(rc_state[0]) {
|
||||
case 0x80:
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
goto unlock;
|
||||
|
||||
case 0x93:
|
||||
case 0x92:
|
||||
m->rep_count = 0;
|
||||
*state = REMOTE_KEY_PRESSED;
|
||||
goto unlock;
|
||||
|
||||
case 0x91:
|
||||
/* For comfort. */
|
||||
if (++m->rep_count > 2)
|
||||
*state = REMOTE_KEY_REPEAT;
|
||||
goto unlock;
|
||||
|
||||
default:
|
||||
deb_rc("Unexpected rc response %x\n", rc_state[0]);
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc_state[1] != 0)
|
||||
deb_rc("Unknown rc key %x\n", rc_state[1]);
|
||||
|
||||
*state = REMOTE_NO_KEY_PRESSED;
|
||||
|
||||
unlock:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* I2C */
|
||||
static int m9206_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
|
||||
int num)
|
||||
{
|
||||
struct dvb_usb_device *d = i2c_get_adapdata(adap);
|
||||
struct m9206_state *m = d->priv;
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
|
||||
return -EAGAIN;
|
||||
|
||||
if (num > 2)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].addr, 0x80)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[0], 0x0)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if (i + 1 < num && msg[i + 1].flags & I2C_M_RD) {
|
||||
int i2c_i;
|
||||
|
||||
for (i2c_i = 0; i2c_i < M9206_I2C_MAX; i2c_i++)
|
||||
if (msg[i].addr == m->i2c_r[i2c_i].addr)
|
||||
break;
|
||||
|
||||
if (i2c_i >= M9206_I2C_MAX) {
|
||||
deb_rc("No magic for i2c addr!\n");
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, m->i2c_r[i2c_i].magic, 0x80)) != 0)
|
||||
goto unlock;
|
||||
|
||||
if ((ret = m9206_read(d->udev, M9206_I2C, 0x0, 0x60, msg[i + 1].buf, msg[i + 1].len)) != 0)
|
||||
goto unlock;
|
||||
|
||||
i++;
|
||||
} else {
|
||||
if (msg[i].len != 2)
|
||||
return -EINVAL;
|
||||
|
||||
if ((ret = m9206_write(d->udev, M9206_I2C, msg[i].buf[1], 0x40)) != 0)
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
ret = i;
|
||||
unlock:
|
||||
mutex_unlock(&d->i2c_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 m9206_i2c_func(struct i2c_adapter *adapter)
|
||||
{
|
||||
return I2C_FUNC_I2C;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm m9206_i2c_algo = {
|
||||
.master_xfer = m9206_i2c_xfer,
|
||||
.functionality = m9206_i2c_func,
|
||||
};
|
||||
|
||||
|
||||
static int m9206_set_filter(struct dvb_usb_adapter *adap, int type, int idx,
|
||||
int pid)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (pid >= 0x8000)
|
||||
return -EINVAL;
|
||||
|
||||
pid |= 0x8000;
|
||||
|
||||
if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, pid, (type << 8) | (idx * 4) )) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_write(adap->dev->udev, M9206_FILTER, 0, (type << 8) | (idx * 4) )) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_update_filters(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
int enabled = m->filtering_enabled;
|
||||
int i, ret = 0, filter = 0;
|
||||
|
||||
for (i = 0; i < M9206_MAX_FILTERS; i++)
|
||||
if (m->filters[i] == 8192)
|
||||
enabled = 0;
|
||||
|
||||
/* Disable all filters */
|
||||
if ((ret = m9206_set_filter(adap, 0x81, 1, enabled)) != 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < M9206_MAX_FILTERS; i++)
|
||||
if ((ret = m9206_set_filter(adap, 0x81, i + 2, 0)) != 0)
|
||||
return ret;
|
||||
|
||||
if ((ret = m9206_set_filter(adap, 0x82, 0, 0x0)) != 0)
|
||||
return ret;
|
||||
|
||||
/* Set */
|
||||
if (enabled) {
|
||||
for (i = 0; i < M9206_MAX_FILTERS; i++) {
|
||||
if (m->filters[i] == 0)
|
||||
continue;
|
||||
|
||||
if ((ret = m9206_set_filter(adap, 0x81, filter + 2, m->filters[i])) != 0)
|
||||
return ret;
|
||||
|
||||
filter++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = m9206_set_filter(adap, 0x82, 0, 0x02f5)) != 0)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int m9206_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->filtering_enabled = onoff ? 1 : 0;
|
||||
|
||||
return m9206_update_filters(adap);
|
||||
}
|
||||
|
||||
static int m9206_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
|
||||
int onoff)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->filters[index] = onoff ? pid : 0;
|
||||
|
||||
return m9206_update_filters(adap);
|
||||
}
|
||||
|
||||
static int m9206_firmware_download(struct usb_device *udev,
|
||||
const struct firmware *fw)
|
||||
{
|
||||
u16 value, index, size;
|
||||
u8 read[4], *buff;
|
||||
int i, pass, ret = 0;
|
||||
|
||||
buff = kmalloc(65536, GFP_KERNEL);
|
||||
|
||||
if ((ret = m9206_read(udev, M9206_FILTER, 0x0, 0x8000, read, 4)) != 0)
|
||||
goto done;
|
||||
deb_rc("%x %x %x %x\n", read[0], read[1], read[2], read[3]);
|
||||
|
||||
if ((ret = m9206_read(udev, M9206_FW, 0x0, 0x0, read, 1)) != 0)
|
||||
goto done;
|
||||
deb_rc("%x\n", read[0]);
|
||||
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
for (i = 0; i + (sizeof(u16) * 3) < fw->size;) {
|
||||
value = le16_to_cpu(*(u16 *)(fw->data + i));
|
||||
i += sizeof(u16);
|
||||
|
||||
index = le16_to_cpu(*(u16 *)(fw->data + i));
|
||||
i += sizeof(u16);
|
||||
|
||||
size = le16_to_cpu(*(u16 *)(fw->data + i));
|
||||
i += sizeof(u16);
|
||||
|
||||
if (pass == 1) {
|
||||
/* Will stall if using fw->data ... */
|
||||
memcpy(buff, fw->data + i, size);
|
||||
|
||||
ret = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
|
||||
M9206_FW,
|
||||
USB_TYPE_VENDOR | USB_DIR_OUT,
|
||||
value, index, buff, size, 20);
|
||||
if (ret != size) {
|
||||
deb_rc("error while uploading fw!\n");
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
}
|
||||
msleep(3);
|
||||
}
|
||||
i += size;
|
||||
}
|
||||
if (i != fw->size) {
|
||||
ret = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
msleep(36);
|
||||
|
||||
/* m9206 will disconnect itself from the bus after this. */
|
||||
(void) m9206_write(udev, M9206_CORE, 0x01, M9206_FW_GO);
|
||||
deb_rc("firmware uploaded!\n");
|
||||
|
||||
done:
|
||||
kfree(buff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Callbacks for DVB USB */
|
||||
static int megasky_identify_state(struct usb_device *udev,
|
||||
struct dvb_usb_device_properties *props,
|
||||
struct dvb_usb_device_description **desc,
|
||||
int *cold)
|
||||
{
|
||||
struct usb_host_interface *alt;
|
||||
|
||||
alt = usb_altnum_to_altsetting(usb_ifnum_to_if(udev, 0), 1);
|
||||
*cold = (alt == NULL) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int megasky_mt352_demod_init(struct dvb_frontend *fe)
|
||||
{
|
||||
u8 config[] = { CONFIG, 0x3d };
|
||||
u8 clock[] = { CLOCK_CTL, 0x30 };
|
||||
u8 reset[] = { RESET, 0x80 };
|
||||
u8 adc_ctl[] = { ADC_CTL_1, 0x40 };
|
||||
u8 agc[] = { AGC_TARGET, 0x1c, 0x20 };
|
||||
u8 sec_agc[] = { 0x69, 0x00, 0xff, 0xff, 0x40, 0xff, 0x00, 0x40, 0x40 };
|
||||
u8 unk1[] = { 0x93, 0x1a };
|
||||
u8 unk2[] = { 0xb5, 0x7a };
|
||||
|
||||
mt352_write(fe, config, ARRAY_SIZE(config));
|
||||
mt352_write(fe, clock, ARRAY_SIZE(clock));
|
||||
mt352_write(fe, reset, ARRAY_SIZE(reset));
|
||||
mt352_write(fe, adc_ctl, ARRAY_SIZE(adc_ctl));
|
||||
mt352_write(fe, agc, ARRAY_SIZE(agc));
|
||||
mt352_write(fe, sec_agc, ARRAY_SIZE(sec_agc));
|
||||
mt352_write(fe, unk1, ARRAY_SIZE(unk1));
|
||||
mt352_write(fe, unk2, ARRAY_SIZE(unk2));
|
||||
|
||||
deb_rc("Demod init!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct mt352_config megasky_mt352_config = {
|
||||
.demod_address = 0x1e,
|
||||
.no_tuner = 1,
|
||||
.demod_init = megasky_mt352_demod_init,
|
||||
};
|
||||
|
||||
static int megasky_mt352_frontend_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
deb_rc("megasky_frontend_attach!\n");
|
||||
|
||||
m->i2c_r[M9206_I2C_DEMOD].addr = megasky_mt352_config.demod_address;
|
||||
m->i2c_r[M9206_I2C_DEMOD].magic = 0x1f;
|
||||
|
||||
if ((adap->fe = dvb_attach(mt352_attach, &megasky_mt352_config, &adap->dev->i2c_adap)) == NULL)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct qt1010_config megasky_qt1010_config = {
|
||||
.i2c_address = 0xc4
|
||||
};
|
||||
|
||||
static int megasky_qt1010_tuner_attach(struct dvb_usb_adapter *adap)
|
||||
{
|
||||
struct m9206_state *m = adap->dev->priv;
|
||||
|
||||
m->i2c_r[M9206_I2C_TUNER].addr = megasky_qt1010_config.i2c_address;
|
||||
m->i2c_r[M9206_I2C_TUNER].magic = 0xc5;
|
||||
|
||||
if (dvb_attach(qt1010_attach, adap->fe, &adap->dev->i2c_adap,
|
||||
&megasky_qt1010_config) == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DVB USB Driver stuff */
|
||||
static struct dvb_usb_device_properties megasky_properties;
|
||||
|
||||
static int m920x_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct dvb_usb_device *d;
|
||||
struct usb_host_interface *alt;
|
||||
int ret;
|
||||
|
||||
if ((ret = dvb_usb_device_init(intf, &megasky_properties, THIS_MODULE, &d)) == 0) {
|
||||
deb_rc("probed!\n");
|
||||
|
||||
alt = usb_altnum_to_altsetting(intf, 1);
|
||||
if (alt == NULL) {
|
||||
deb_rc("not alt found!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = usb_set_interface(d->udev, alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
deb_rc("Changed to alternate setting!\n");
|
||||
|
||||
if ((ret = m9206_rc_init(d->udev)) != 0)
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct usb_device_id m920x_table [] = {
|
||||
{ USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580) },
|
||||
{ } /* Terminating entry */
|
||||
};
|
||||
MODULE_DEVICE_TABLE (usb, m920x_table);
|
||||
|
||||
static struct dvb_usb_device_properties megasky_properties = {
|
||||
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
|
||||
|
||||
.usb_ctrl = DEVICE_SPECIFIC,
|
||||
.firmware = "dvb-usb-megasky-02.fw",
|
||||
.download_firmware = m9206_firmware_download,
|
||||
|
||||
.rc_interval = 100,
|
||||
.rc_key_map = megasky_rc_keys,
|
||||
.rc_key_map_size = ARRAY_SIZE(megasky_rc_keys),
|
||||
.rc_query = m9206_rc_query,
|
||||
|
||||
.size_of_priv = sizeof(struct m9206_state),
|
||||
|
||||
.identify_state = megasky_identify_state,
|
||||
.num_adapters = 1,
|
||||
.adapter = {{
|
||||
.caps = DVB_USB_ADAP_HAS_PID_FILTER |
|
||||
DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
|
||||
|
||||
.pid_filter_count = 8,
|
||||
.pid_filter = m9206_pid_filter,
|
||||
.pid_filter_ctrl = m9206_pid_filter_ctrl,
|
||||
|
||||
.frontend_attach = megasky_mt352_frontend_attach,
|
||||
.tuner_attach = megasky_qt1010_tuner_attach,
|
||||
|
||||
.stream = {
|
||||
.type = USB_BULK,
|
||||
.count = 8,
|
||||
.endpoint = 0x81,
|
||||
.u = {
|
||||
.bulk = {
|
||||
.buffersize = 512,
|
||||
}
|
||||
}
|
||||
},
|
||||
}},
|
||||
.i2c_algo = &m9206_i2c_algo,
|
||||
|
||||
.num_device_descs = 1,
|
||||
.devices = {
|
||||
{ "MSI Mega Sky 580 DVB-T USB2.0",
|
||||
{ &m920x_table[0], NULL },
|
||||
{ NULL },
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
static struct usb_driver m920x_driver = {
|
||||
.name = "dvb_usb_m920x",
|
||||
.probe = m920x_probe,
|
||||
.disconnect = dvb_usb_device_exit,
|
||||
.id_table = m920x_table,
|
||||
};
|
||||
|
||||
/* module stuff */
|
||||
static int __init m920x_module_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((ret = usb_register(&m920x_driver))) {
|
||||
err("usb_register failed. Error number %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit m920x_module_exit(void)
|
||||
{
|
||||
/* deregister this driver from the USB subsystem */
|
||||
usb_deregister(&m920x_driver);
|
||||
}
|
||||
|
||||
module_init (m920x_module_init);
|
||||
module_exit (m920x_module_exit);
|
||||
|
||||
MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
|
||||
MODULE_DESCRIPTION("Driver MSI Mega Sky 580 DVB-T USB2.0 / Uli m920x");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
35
drivers/media/dvb/dvb-usb/m920x.h
Normal file
35
drivers/media/dvb/dvb-usb/m920x.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef _DVB_USB_M920X_H_
|
||||
#define _DVB_USB_M920X_H_
|
||||
|
||||
#define DVB_USB_LOG_PREFIX "m920x"
|
||||
#include "dvb-usb.h"
|
||||
|
||||
#define deb_rc(args...) dprintk(dvb_usb_m920x_debug,0x01,args)
|
||||
|
||||
#define M9206_CORE 0x22
|
||||
#define M9206_RC_STATE 0xff51
|
||||
#define M9206_RC_KEY 0xff52
|
||||
#define M9206_RC_INIT1 0xff54
|
||||
#define M9206_RC_INIT2 0xff55
|
||||
#define M9206_FW_GO 0xff69
|
||||
|
||||
#define M9206_I2C 0x23
|
||||
#define M9206_FILTER 0x25
|
||||
#define M9206_FW 0x30
|
||||
|
||||
#define M9206_MAX_FILTERS 8
|
||||
|
||||
#define M9206_I2C_TUNER 0
|
||||
#define M9206_I2C_DEMOD 1
|
||||
#define M9206_I2C_MAX 2
|
||||
|
||||
struct m9206_state {
|
||||
u16 filters[M9206_MAX_FILTERS];
|
||||
int filtering_enabled;
|
||||
int rep_count;
|
||||
struct {
|
||||
unsigned char addr;
|
||||
unsigned char magic;
|
||||
}i2c_r[M9206_I2C_MAX];
|
||||
};
|
||||
#endif
|
@ -290,6 +290,13 @@ config DVB_TDA826X
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_TUNER_QT1010
|
||||
tristate "Quantek QT1010 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if DVB_FE_CUSTOMISE
|
||||
help
|
||||
A driver for the silicon tuner QT1010 from Quantek.
|
||||
|
||||
config DVB_TUNER_MT2060
|
||||
tristate "Microtune MT2060 silicon IF tuner"
|
||||
depends on I2C
|
||||
|
@ -38,5 +38,6 @@ obj-$(CONFIG_DVB_ISL6421) += isl6421.o
|
||||
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
|
||||
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
|
||||
obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
|
||||
obj-$(CONFIG_DVB_TUNER_QT1010) += qt1010.o
|
||||
obj-$(CONFIG_DVB_TUA6100) += tua6100.o
|
||||
obj-$(CONFIG_DVB_TUNER_LGH06XF) += lgh06xf.o
|
||||
|
@ -254,7 +254,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
|
||||
if (srate<500000)
|
||||
srate=500000;
|
||||
|
||||
for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)
|
||||
for(i = 0; (i < ARRAY_SIZE(bands)) && (srate>bands[i]); i++)
|
||||
;
|
||||
/* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
|
||||
and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
|
||||
@ -361,7 +361,7 @@ static int cx24110_initfe(struct dvb_frontend* fe)
|
||||
|
||||
dprintk("%s: init chip\n", __FUNCTION__);
|
||||
|
||||
for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
|
||||
for(i = 0; i < ARRAY_SIZE(cx24110_regdata); i++) {
|
||||
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
|
||||
};
|
||||
|
||||
|
@ -507,7 +507,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
|
||||
int i = 0;
|
||||
int pump = 2;
|
||||
int band = 0;
|
||||
int num_bands = sizeof(cx24123_bandselect_vals) / sizeof(cx24123_bandselect_vals[0]);
|
||||
int num_bands = ARRAY_SIZE(cx24123_bandselect_vals);
|
||||
|
||||
/* Defaults for low freq, low rate */
|
||||
state->VCAarg = cx24123_AGC_vals[0].VCAprogdata;
|
||||
@ -516,7 +516,7 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
|
||||
vco_div = cx24123_bandselect_vals[0].VCOdivider;
|
||||
|
||||
/* For the given symbol rate, determine the VCA, VGA and FILTUNE programming bits */
|
||||
for (i = 0; i < sizeof(cx24123_AGC_vals) / sizeof(cx24123_AGC_vals[0]); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(cx24123_AGC_vals); i++)
|
||||
{
|
||||
if ((cx24123_AGC_vals[i].symbolrate_low <= p->u.qpsk.symbol_rate) &&
|
||||
(cx24123_AGC_vals[i].symbolrate_high >= p->u.qpsk.symbol_rate) ) {
|
||||
@ -658,7 +658,7 @@ static int cx24123_initfe(struct dvb_frontend* fe)
|
||||
dprintk("%s: init frontend\n",__FUNCTION__);
|
||||
|
||||
/* Configure the demod to a good set of defaults */
|
||||
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
|
||||
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
|
||||
|
||||
/* Set the LNB polarity */
|
||||
|
@ -475,7 +475,7 @@ static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx
|
||||
tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
|
||||
dib3000mc_write_word(state, 0, tmp);
|
||||
|
||||
dib3000mc_write_word(state, 5, seq);
|
||||
dib3000mc_write_word(state, 5, (1 << 8) | ((seq & 0xf) << 4));
|
||||
|
||||
tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
|
||||
if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
|
||||
|
485
drivers/media/dvb/frontends/qt1010.c
Normal file
485
drivers/media/dvb/frontends/qt1010.c
Normal file
@ -0,0 +1,485 @@
|
||||
/*
|
||||
* Driver for Quantek QT1010 silicon tuner
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
* Aapo Tahkola <aet@rasterburn.org>
|
||||
*
|
||||
* 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 "qt1010.h"
|
||||
#include "qt1010_priv.h"
|
||||
|
||||
static int debug;
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
|
||||
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) printk(KERN_DEBUG "QT1010: " args); \
|
||||
} while (0)
|
||||
|
||||
/* read single register */
|
||||
static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val)
|
||||
{
|
||||
struct i2c_msg msg[2] = {
|
||||
{ .addr = priv->cfg->i2c_address,
|
||||
.flags = 0, .buf = ®, .len = 1 },
|
||||
{ .addr = priv->cfg->i2c_address,
|
||||
.flags = I2C_M_RD, .buf = val, .len = 1 },
|
||||
};
|
||||
|
||||
if (i2c_transfer(priv->i2c, msg, 2) != 2) {
|
||||
printk(KERN_WARNING "qt1010 I2C read failed\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* write single register */
|
||||
static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val)
|
||||
{
|
||||
u8 buf[2] = { reg, val };
|
||||
struct i2c_msg msg = { .addr = priv->cfg->i2c_address,
|
||||
.flags = 0, .buf = buf, .len = 2 };
|
||||
|
||||
if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
|
||||
printk(KERN_WARNING "qt1010 I2C write failed\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* dump all registers */
|
||||
static void qt1010_dump_regs(struct qt1010_priv *priv)
|
||||
{
|
||||
char buf[52], buf2[4];
|
||||
u8 reg, val;
|
||||
|
||||
for (reg = 0; ; reg++) {
|
||||
if (reg % 16 == 0) {
|
||||
if (reg)
|
||||
printk("%s\n", buf);
|
||||
sprintf(buf, "%02x: ", reg);
|
||||
}
|
||||
if (qt1010_readreg(priv, reg, &val) == 0)
|
||||
sprintf(buf2, "%02x ", val);
|
||||
else
|
||||
strcpy(buf2, "-- ");
|
||||
strcat(buf, buf2);
|
||||
if (reg == 0x2f)
|
||||
break;
|
||||
}
|
||||
printk("%s\n", buf);
|
||||
}
|
||||
|
||||
static int qt1010_set_params(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct qt1010_priv *priv;
|
||||
int err;
|
||||
u32 freq, div, mod1, mod2;
|
||||
u8 i, tmpval, reg05;
|
||||
qt1010_i2c_oper_t rd[48] = {
|
||||
{ QT1010_WR, 0x01, 0x80 },
|
||||
{ QT1010_WR, 0x02, 0x3f },
|
||||
{ QT1010_WR, 0x05, 0xff }, /* 02 c write */
|
||||
{ QT1010_WR, 0x06, 0x44 },
|
||||
{ QT1010_WR, 0x07, 0xff }, /* 04 c write */
|
||||
{ QT1010_WR, 0x08, 0x08 },
|
||||
{ QT1010_WR, 0x09, 0xff }, /* 06 c write */
|
||||
{ QT1010_WR, 0x0a, 0xff }, /* 07 c write */
|
||||
{ QT1010_WR, 0x0b, 0xff }, /* 08 c write */
|
||||
{ QT1010_WR, 0x0c, 0xe1 },
|
||||
{ QT1010_WR, 0x1a, 0xff }, /* 10 c write */
|
||||
{ QT1010_WR, 0x1b, 0x00 },
|
||||
{ QT1010_WR, 0x1c, 0x89 },
|
||||
{ QT1010_WR, 0x11, 0xff }, /* 13 c write */
|
||||
{ QT1010_WR, 0x12, 0xff }, /* 14 c write */
|
||||
{ QT1010_WR, 0x22, 0xff }, /* 15 c write */
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x1e, 0xd0 },
|
||||
{ QT1010_RD, 0x22, 0xff }, /* 16 c read */
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_RD, 0x05, 0xff }, /* 20 c read */
|
||||
{ QT1010_RD, 0x22, 0xff }, /* 21 c read */
|
||||
{ QT1010_WR, 0x23, 0xd0 },
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x1e, 0xe0 },
|
||||
{ QT1010_RD, 0x23, 0xff }, /* 25 c read */
|
||||
{ QT1010_RD, 0x23, 0xff }, /* 26 c read */
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x24, 0xd0 },
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x1e, 0xf0 },
|
||||
{ QT1010_RD, 0x24, 0xff }, /* 31 c read */
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x14, 0x7f },
|
||||
{ QT1010_WR, 0x15, 0x7f },
|
||||
{ QT1010_WR, 0x05, 0xff }, /* 35 c write */
|
||||
{ QT1010_WR, 0x06, 0x00 },
|
||||
{ QT1010_WR, 0x15, 0x1f },
|
||||
{ QT1010_WR, 0x16, 0xff },
|
||||
{ QT1010_WR, 0x18, 0xff },
|
||||
{ QT1010_WR, 0x1f, 0xff }, /* 40 c write */
|
||||
{ QT1010_WR, 0x20, 0xff }, /* 41 c write */
|
||||
{ QT1010_WR, 0x21, 0x53 },
|
||||
{ QT1010_WR, 0x25, 0xff }, /* 43 c write */
|
||||
{ QT1010_WR, 0x26, 0x15 },
|
||||
{ QT1010_WR, 0x00, 0xff }, /* 45 c write */
|
||||
{ QT1010_WR, 0x02, 0x00 },
|
||||
{ QT1010_WR, 0x01, 0x00 }
|
||||
};
|
||||
|
||||
#define FREQ1 32000000 /* 32 MHz */
|
||||
#define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */
|
||||
|
||||
priv = fe->tuner_priv;
|
||||
freq = params->frequency;
|
||||
div = (freq + QT1010_OFFSET) / QT1010_STEP;
|
||||
freq = (div * QT1010_STEP) - QT1010_OFFSET;
|
||||
mod1 = (freq + QT1010_OFFSET) % FREQ1;
|
||||
mod2 = (freq + QT1010_OFFSET) % FREQ2;
|
||||
priv->bandwidth =
|
||||
(fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
|
||||
priv->frequency = freq;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
/* reg 05 base value */
|
||||
if (freq < 290000000) reg05 = 0x14; /* 290 MHz */
|
||||
else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */
|
||||
else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */
|
||||
else reg05 = 0x74;
|
||||
|
||||
/* 0x5 */
|
||||
rd[2].val = reg05;
|
||||
|
||||
/* 07 - set frequency: 32 MHz scale */
|
||||
rd[4].val = (freq + QT1010_OFFSET) / FREQ1;
|
||||
|
||||
/* 09 - changes every 8/24 MHz */
|
||||
if (mod1 < 8000000) rd[6].val = 0x1d;
|
||||
else rd[6].val = 0x1c;
|
||||
|
||||
/* 0a - set frequency: 4 MHz scale (max 28 MHz) */
|
||||
if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */
|
||||
else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */
|
||||
else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */
|
||||
else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */
|
||||
else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */
|
||||
else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */
|
||||
else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */
|
||||
else rd[7].val = 0x0a; /* +28 MHz */
|
||||
|
||||
/* 0b - changes every 2/2 MHz */
|
||||
if (mod2 < 2000000) rd[8].val = 0x45;
|
||||
else rd[8].val = 0x44;
|
||||
|
||||
/* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/
|
||||
tmpval = 0x78; /* byte, overflows intentionally */
|
||||
rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08);
|
||||
|
||||
/* 11 */
|
||||
rd[13].val = 0xfd; /* TODO: correct value calculation */
|
||||
|
||||
/* 12 */
|
||||
rd[14].val = 0x91; /* TODO: correct value calculation */
|
||||
|
||||
/* 22 */
|
||||
if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */
|
||||
else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */
|
||||
else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */
|
||||
else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */
|
||||
else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */
|
||||
else rd[15].val = 0xd0;
|
||||
|
||||
/* 05 */
|
||||
rd[35].val = (reg05 & 0xf0);
|
||||
|
||||
/* 1f */
|
||||
if (mod1 < 8000000) tmpval = 0x00;
|
||||
else if (mod1 < 12000000) tmpval = 0x01;
|
||||
else if (mod1 < 16000000) tmpval = 0x02;
|
||||
else if (mod1 < 24000000) tmpval = 0x03;
|
||||
else if (mod1 < 28000000) tmpval = 0x04;
|
||||
else tmpval = 0x05;
|
||||
rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval);
|
||||
|
||||
/* 20 */
|
||||
if (mod1 < 8000000) tmpval = 0x00;
|
||||
else if (mod1 < 12000000) tmpval = 0x01;
|
||||
else if (mod1 < 20000000) tmpval = 0x02;
|
||||
else if (mod1 < 24000000) tmpval = 0x03;
|
||||
else if (mod1 < 28000000) tmpval = 0x04;
|
||||
else tmpval = 0x05;
|
||||
rd[41].val = (priv->reg20_init_val + 0x0d + tmpval);
|
||||
|
||||
/* 25 */
|
||||
rd[43].val = priv->reg25_init_val;
|
||||
|
||||
/* 00 */
|
||||
rd[45].val = 0x92; /* TODO: correct value calculation */
|
||||
|
||||
dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \
|
||||
"1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \
|
||||
"20:%02x 25:%02x 00:%02x", \
|
||||
freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \
|
||||
rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \
|
||||
rd[40].val, rd[41].val, rd[43].val, rd[45].val);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(rd); i++) {
|
||||
if (rd[i].oper == QT1010_WR) {
|
||||
err = qt1010_writereg(priv, rd[i].reg, rd[i].val);
|
||||
} else { /* read is required to proper locking */
|
||||
err = qt1010_readreg(priv, rd[i].reg, &tmpval);
|
||||
}
|
||||
if (err) return err;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
qt1010_dump_regs(priv);
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qt1010_init_meas1(struct qt1010_priv *priv,
|
||||
u8 oper, u8 reg, u8 reg_init_val, u8 *retval)
|
||||
{
|
||||
u8 i, val1, val2;
|
||||
int err;
|
||||
|
||||
qt1010_i2c_oper_t i2c_data[] = {
|
||||
{ QT1010_WR, reg, reg_init_val },
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x1e, oper },
|
||||
{ QT1010_RD, reg, 0xff }
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
|
||||
if (i2c_data[i].oper == QT1010_WR) {
|
||||
err = qt1010_writereg(priv, i2c_data[i].reg,
|
||||
i2c_data[i].val);
|
||||
} else {
|
||||
err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
|
||||
}
|
||||
if (err) return err;
|
||||
}
|
||||
|
||||
do {
|
||||
val1 = val2;
|
||||
err = qt1010_readreg(priv, reg, &val2);
|
||||
if (err) return err;
|
||||
dprintk("compare reg:%02x %02x %02x", reg, val1, val2);
|
||||
} while (val1 != val2);
|
||||
*retval = val1;
|
||||
|
||||
return qt1010_writereg(priv, 0x1e, 0x00);
|
||||
}
|
||||
|
||||
static u8 qt1010_init_meas2(struct qt1010_priv *priv,
|
||||
u8 reg_init_val, u8 *retval)
|
||||
{
|
||||
u8 i, val;
|
||||
int err;
|
||||
qt1010_i2c_oper_t i2c_data[] = {
|
||||
{ QT1010_WR, 0x07, reg_init_val },
|
||||
{ QT1010_WR, 0x22, 0xd0 },
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x1e, 0xd0 },
|
||||
{ QT1010_RD, 0x22, 0xff },
|
||||
{ QT1010_WR, 0x1e, 0x00 },
|
||||
{ QT1010_WR, 0x22, 0xff }
|
||||
};
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
|
||||
if (i2c_data[i].oper == QT1010_WR) {
|
||||
err = qt1010_writereg(priv, i2c_data[i].reg,
|
||||
i2c_data[i].val);
|
||||
} else {
|
||||
err = qt1010_readreg(priv, i2c_data[i].reg, &val);
|
||||
}
|
||||
if (err) return err;
|
||||
}
|
||||
*retval = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qt1010_init(struct dvb_frontend *fe)
|
||||
{
|
||||
struct qt1010_priv *priv = fe->tuner_priv;
|
||||
struct dvb_frontend_parameters params;
|
||||
int err = 0;
|
||||
u8 i, tmpval, *valptr = NULL;
|
||||
|
||||
qt1010_i2c_oper_t i2c_data[] = {
|
||||
{ QT1010_WR, 0x01, 0x80 },
|
||||
{ QT1010_WR, 0x0d, 0x84 },
|
||||
{ QT1010_WR, 0x0e, 0xb7 },
|
||||
{ QT1010_WR, 0x2a, 0x23 },
|
||||
{ QT1010_WR, 0x2c, 0xdc },
|
||||
{ QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */
|
||||
{ QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */
|
||||
{ QT1010_WR, 0x2b, 0x70 },
|
||||
{ QT1010_WR, 0x2a, 0x23 },
|
||||
{ QT1010_M1, 0x26, 0x08 },
|
||||
{ QT1010_M1, 0x82, 0xff },
|
||||
{ QT1010_WR, 0x05, 0x14 },
|
||||
{ QT1010_WR, 0x06, 0x44 },
|
||||
{ QT1010_WR, 0x07, 0x28 },
|
||||
{ QT1010_WR, 0x08, 0x0b },
|
||||
{ QT1010_WR, 0x11, 0xfd },
|
||||
{ QT1010_M1, 0x22, 0x0d },
|
||||
{ QT1010_M1, 0xd0, 0xff },
|
||||
{ QT1010_WR, 0x06, 0x40 },
|
||||
{ QT1010_WR, 0x16, 0xf0 },
|
||||
{ QT1010_WR, 0x02, 0x38 },
|
||||
{ QT1010_WR, 0x03, 0x18 },
|
||||
{ QT1010_WR, 0x20, 0xe0 },
|
||||
{ QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */
|
||||
{ QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */
|
||||
{ QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */
|
||||
{ QT1010_WR, 0x03, 0x19 },
|
||||
{ QT1010_WR, 0x02, 0x3f },
|
||||
{ QT1010_WR, 0x21, 0x53 },
|
||||
{ QT1010_RD, 0x21, 0xff },
|
||||
{ QT1010_WR, 0x11, 0xfd },
|
||||
{ QT1010_WR, 0x05, 0x34 },
|
||||
{ QT1010_WR, 0x06, 0x44 },
|
||||
{ QT1010_WR, 0x08, 0x08 }
|
||||
};
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
|
||||
switch (i2c_data[i].oper) {
|
||||
case QT1010_WR:
|
||||
err = qt1010_writereg(priv, i2c_data[i].reg,
|
||||
i2c_data[i].val);
|
||||
break;
|
||||
case QT1010_RD:
|
||||
if (i2c_data[i].val == 0x20)
|
||||
valptr = &priv->reg20_init_val;
|
||||
else
|
||||
valptr = &tmpval;
|
||||
err = qt1010_readreg(priv, i2c_data[i].reg, valptr);
|
||||
break;
|
||||
case QT1010_M1:
|
||||
if (i2c_data[i].val == 0x25)
|
||||
valptr = &priv->reg25_init_val;
|
||||
else if (i2c_data[i].val == 0x1f)
|
||||
valptr = &priv->reg1f_init_val;
|
||||
else
|
||||
valptr = &tmpval;
|
||||
err = qt1010_init_meas1(priv, i2c_data[i+1].reg,
|
||||
i2c_data[i].reg,
|
||||
i2c_data[i].val, valptr);
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
if (err) return err;
|
||||
}
|
||||
|
||||
for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */
|
||||
if ((err = qt1010_init_meas2(priv, i, &tmpval)))
|
||||
return err;
|
||||
|
||||
params.frequency = 545000000; /* Sigmatek DVB-110 545000000 */
|
||||
/* MSI Megasky 580 GL861 533000000 */
|
||||
return qt1010_set_params(fe, ¶ms);
|
||||
}
|
||||
|
||||
static int qt1010_release(struct dvb_frontend *fe)
|
||||
{
|
||||
kfree(fe->tuner_priv);
|
||||
fe->tuner_priv = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
||||
{
|
||||
struct qt1010_priv *priv = fe->tuner_priv;
|
||||
*frequency = priv->frequency;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qt1010_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
|
||||
{
|
||||
struct qt1010_priv *priv = fe->tuner_priv;
|
||||
*bandwidth = priv->bandwidth;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dvb_tuner_ops qt1010_tuner_ops = {
|
||||
.info = {
|
||||
.name = "Quantek QT1010",
|
||||
.frequency_min = QT1010_MIN_FREQ,
|
||||
.frequency_max = QT1010_MAX_FREQ,
|
||||
.frequency_step = QT1010_STEP,
|
||||
},
|
||||
|
||||
.release = qt1010_release,
|
||||
.init = qt1010_init,
|
||||
/* TODO: implement sleep */
|
||||
|
||||
.set_params = qt1010_set_params,
|
||||
.get_frequency = qt1010_get_frequency,
|
||||
.get_bandwidth = qt1010_get_bandwidth
|
||||
};
|
||||
|
||||
struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct qt1010_config *cfg)
|
||||
{
|
||||
struct qt1010_priv *priv = NULL;
|
||||
u8 id;
|
||||
|
||||
priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL);
|
||||
if (priv == NULL)
|
||||
return NULL;
|
||||
|
||||
priv->cfg = cfg;
|
||||
priv->i2c = i2c;
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */
|
||||
|
||||
|
||||
/* Try to detect tuner chip. Probably this is not correct register. */
|
||||
if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) {
|
||||
kfree(priv);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */
|
||||
|
||||
printk(KERN_INFO "Quantek QT1010 successfully identified.\n");
|
||||
memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops,
|
||||
sizeof(struct dvb_tuner_ops));
|
||||
|
||||
fe->tuner_priv = priv;
|
||||
return fe;
|
||||
}
|
||||
EXPORT_SYMBOL(qt1010_attach);
|
||||
|
||||
MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver");
|
||||
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
|
||||
MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
|
||||
MODULE_VERSION("0.1");
|
||||
MODULE_LICENSE("GPL");
|
53
drivers/media/dvb/frontends/qt1010.h
Normal file
53
drivers/media/dvb/frontends/qt1010.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Driver for Quantek QT1010 silicon tuner
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
* Aapo Tahkola <aet@rasterburn.org>
|
||||
*
|
||||
* 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 QT1010_H
|
||||
#define QT1010_H
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
|
||||
struct qt1010_config {
|
||||
u8 i2c_address;
|
||||
};
|
||||
|
||||
/**
|
||||
* Attach a qt1010 tuner to the supplied frontend structure.
|
||||
*
|
||||
* @param fe frontend to attach to
|
||||
* @param i2c i2c adapter to use
|
||||
* @param cfg tuner hw based configuration
|
||||
* @return fe pointer on success, NULL on failure
|
||||
*/
|
||||
#if defined(CONFIG_DVB_TUNER_QT1010) || (defined(CONFIG_DVB_TUNER_QT1010_MODULE) && defined(MODULE))
|
||||
extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct qt1010_config *cfg);
|
||||
#else
|
||||
static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe,
|
||||
struct i2c_adapter *i2c,
|
||||
struct qt1010_config *cfg)
|
||||
{
|
||||
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
#endif // CONFIG_DVB_TUNER_QT1010
|
||||
|
||||
#endif
|
105
drivers/media/dvb/frontends/qt1010_priv.h
Normal file
105
drivers/media/dvb/frontends/qt1010_priv.h
Normal file
@ -0,0 +1,105 @@
|
||||
/*
|
||||
* Driver for Quantek QT1010 silicon tuner
|
||||
*
|
||||
* Copyright (C) 2006 Antti Palosaari <crope@iki.fi>
|
||||
* Aapo Tahkola <aet@rasterburn.org>
|
||||
*
|
||||
* 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 QT1010_PRIV_H
|
||||
#define QT1010_PRIV_H
|
||||
|
||||
/*
|
||||
reg def meaning
|
||||
=== === =======
|
||||
00 00 ?
|
||||
01 a0 ? operation start/stop; start=80, stop=00
|
||||
02 00 ?
|
||||
03 19 ?
|
||||
04 00 ?
|
||||
05 00 ? maybe band selection
|
||||
06 00 ?
|
||||
07 2b set frequency: 32 MHz scale, n*32 MHz
|
||||
08 0b ?
|
||||
09 10 ? changes every 8/24 MHz; values 1d/1c
|
||||
0a 08 set frequency: 4 MHz scale, n*4 MHz
|
||||
0b 41 ? changes every 2/2 MHz; values 45/45
|
||||
0c e1 ?
|
||||
0d 94 ?
|
||||
0e b6 ?
|
||||
0f 2c ?
|
||||
10 10 ?
|
||||
11 f1 ? maybe device specified adjustment
|
||||
12 11 ? maybe device specified adjustment
|
||||
13 3f ?
|
||||
14 1f ?
|
||||
15 3f ?
|
||||
16 ff ?
|
||||
17 ff ?
|
||||
18 f7 ?
|
||||
19 80 ?
|
||||
1a d0 set frequency: 125 kHz scale, n*125 kHz
|
||||
1b 00 ?
|
||||
1c 89 ?
|
||||
1d 00 ?
|
||||
1e 00 ? looks like operation register; write cmd here, read result from 1f-26
|
||||
1f 20 ? chip initialization
|
||||
20 e0 ? chip initialization
|
||||
21 20 ?
|
||||
22 d0 ?
|
||||
23 d0 ?
|
||||
24 d0 ?
|
||||
25 40 ? chip initialization
|
||||
26 08 ?
|
||||
27 29 ?
|
||||
28 55 ?
|
||||
29 39 ?
|
||||
2a 13 ?
|
||||
2b 01 ?
|
||||
2c ea ?
|
||||
2d 00 ?
|
||||
2e 00 ? not used?
|
||||
2f 00 ? not used?
|
||||
*/
|
||||
|
||||
#define QT1010_STEP 125000 /* 125 kHz used by Windows drivers,
|
||||
hw could be more precise but we don't
|
||||
know how to use */
|
||||
#define QT1010_MIN_FREQ 48000000 /* 48 MHz */
|
||||
#define QT1010_MAX_FREQ 860000000 /* 860 MHz */
|
||||
#define QT1010_OFFSET 1246000000 /* 1246 MHz */
|
||||
|
||||
#define QT1010_WR 0
|
||||
#define QT1010_RD 1
|
||||
#define QT1010_M1 3
|
||||
|
||||
typedef struct {
|
||||
u8 oper, reg, val;
|
||||
} qt1010_i2c_oper_t;
|
||||
|
||||
struct qt1010_priv {
|
||||
struct qt1010_config *cfg;
|
||||
struct i2c_adapter *i2c;
|
||||
|
||||
u8 reg1f_init_val;
|
||||
u8 reg20_init_val;
|
||||
u8 reg25_init_val;
|
||||
|
||||
u32 frequency;
|
||||
u32 bandwidth;
|
||||
};
|
||||
|
||||
#endif
|
@ -35,6 +35,7 @@ struct stv0297_state {
|
||||
const struct stv0297_config *config;
|
||||
struct dvb_frontend frontend;
|
||||
|
||||
unsigned long last_ber;
|
||||
unsigned long base_freq;
|
||||
};
|
||||
|
||||
@ -310,6 +311,8 @@ static int stv0297_init(struct dvb_frontend *fe)
|
||||
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
|
||||
msleep(200);
|
||||
|
||||
state->last_ber = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -340,11 +343,13 @@ static int stv0297_read_ber(struct dvb_frontend *fe, u32 * ber)
|
||||
struct stv0297_state *state = fe->demodulator_priv;
|
||||
u8 BER[3];
|
||||
|
||||
stv0297_writereg(state, 0xA0, 0x80); // Start Counting bit errors for 4096 Bytes
|
||||
mdelay(25); // Hopefully got 4096 Bytes
|
||||
stv0297_readregs(state, 0xA0, BER, 3);
|
||||
mdelay(25);
|
||||
*ber = (BER[2] << 8 | BER[1]) / (8 * 4096);
|
||||
if (!(BER[0] & 0x80)) {
|
||||
state->last_ber = BER[2] << 8 | BER[1];
|
||||
stv0297_writereg_mask(state, 0xA0, 0x80, 0x80);
|
||||
}
|
||||
|
||||
*ber = state->last_ber;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -376,9 +381,14 @@ static int stv0297_read_ucblocks(struct dvb_frontend *fe, u32 * ucblocks)
|
||||
{
|
||||
struct stv0297_state *state = fe->demodulator_priv;
|
||||
|
||||
stv0297_writereg_mask(state, 0xDF, 0x03, 0x03); /* freeze the counters */
|
||||
|
||||
*ucblocks = (stv0297_readreg(state, 0xD5) << 8)
|
||||
| stv0297_readreg(state, 0xD4);
|
||||
|
||||
stv0297_writereg_mask(state, 0xDF, 0x03, 0x02); /* clear the counters */
|
||||
stv0297_writereg_mask(state, 0xDF, 0x03, 0x01); /* re-enable the counters */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -648,6 +658,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config,
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
state->last_ber = 0;
|
||||
state->base_freq = 0;
|
||||
|
||||
/* check if the demod is there */
|
||||
|
@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
|
||||
return (ret != 1) ? -EREMOTEIO : 0;
|
||||
}
|
||||
|
||||
int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
{
|
||||
struct stv0299_state* state = fe->demodulator_priv;
|
||||
|
||||
|
@ -201,7 +201,7 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
static int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
{
|
||||
struct tda10021_state* state = fe->demodulator_priv;
|
||||
|
||||
|
@ -579,7 +579,7 @@ static int tda1004x_decode_fec(int tdafec)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
|
||||
{
|
||||
struct tda1004x_state* state = fe->demodulator_priv;
|
||||
|
||||
|
@ -38,6 +38,12 @@ struct zl10353_state {
|
||||
struct zl10353_config config;
|
||||
};
|
||||
|
||||
static int debug;
|
||||
#define dprintk(args...) \
|
||||
do { \
|
||||
if (debug) printk(KERN_DEBUG "zl10353: " args); \
|
||||
} while (0)
|
||||
|
||||
static int debug_regs = 0;
|
||||
|
||||
static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
|
||||
@ -54,7 +60,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
|
||||
static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
|
||||
{
|
||||
int err, i;
|
||||
for (i = 0; i < ilen - 1; i++)
|
||||
@ -113,6 +119,36 @@ static void zl10353_dump_regs(struct dvb_frontend *fe)
|
||||
printk(KERN_DEBUG "%s\n", buf);
|
||||
}
|
||||
|
||||
static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
|
||||
enum fe_bandwidth bandwidth,
|
||||
u16 *nominal_rate)
|
||||
{
|
||||
u32 adc_clock = 22528; /* 20.480 MHz on the board(!?) */
|
||||
u8 bw;
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
|
||||
if (state->config.adc_clock)
|
||||
adc_clock = state->config.adc_clock;
|
||||
|
||||
switch (bandwidth) {
|
||||
case BANDWIDTH_6_MHZ:
|
||||
bw = 6;
|
||||
break;
|
||||
case BANDWIDTH_7_MHZ:
|
||||
bw = 7;
|
||||
break;
|
||||
case BANDWIDTH_8_MHZ:
|
||||
default:
|
||||
bw = 8;
|
||||
break;
|
||||
}
|
||||
|
||||
*nominal_rate = (64 * bw * (1<<16) / (7 * 8) * 4000 / adc_clock + 2) / 4;
|
||||
|
||||
dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
|
||||
__FUNCTION__, bw, adc_clock, *nominal_rate);
|
||||
}
|
||||
|
||||
static int zl10353_sleep(struct dvb_frontend *fe)
|
||||
{
|
||||
static u8 zl10353_softdown[] = { 0x50, 0x0C, 0x44 };
|
||||
@ -125,7 +161,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_parameters *param)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
|
||||
u16 nominal_rate;
|
||||
u8 pllbuf[6] = { 0x67 };
|
||||
|
||||
/* These settings set "auto-everything" and start the FSM. */
|
||||
@ -138,18 +174,23 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
|
||||
zl10353_single_write(fe, 0x56, 0x28);
|
||||
zl10353_single_write(fe, 0x89, 0x20);
|
||||
zl10353_single_write(fe, 0x5E, 0x00);
|
||||
zl10353_single_write(fe, 0x65, 0x5A);
|
||||
zl10353_single_write(fe, 0x66, 0xE9);
|
||||
|
||||
zl10353_calc_nominal_rate(fe, param->u.ofdm.bandwidth, &nominal_rate);
|
||||
zl10353_single_write(fe, TRL_NOMINAL_RATE_1, msb(nominal_rate));
|
||||
zl10353_single_write(fe, TRL_NOMINAL_RATE_0, lsb(nominal_rate));
|
||||
|
||||
zl10353_single_write(fe, 0x6C, 0xCD);
|
||||
zl10353_single_write(fe, 0x6D, 0x7E);
|
||||
zl10353_single_write(fe, 0x62, 0x0A);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
|
||||
// if there is no attached secondary tuner, we call set_params to program
|
||||
// a potential tuner attached somewhere else
|
||||
if (state->config.no_tuner) {
|
||||
if (fe->ops.tuner_ops.set_params) {
|
||||
fe->ops.tuner_ops.set_params(fe, param);
|
||||
if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
if (fe->ops.i2c_gate_ctrl)
|
||||
fe->ops.i2c_gate_ctrl(fe, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,6 +254,29 @@ static int zl10353_read_status(struct dvb_frontend *fe, fe_status_t *status)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10353_read_ber(struct dvb_frontend *fe, u32 *ber)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
|
||||
*ber = zl10353_read_register(state, RS_ERR_CNT_2) << 16 |
|
||||
zl10353_read_register(state, RS_ERR_CNT_1) << 8 |
|
||||
zl10353_read_register(state, RS_ERR_CNT_0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10353_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
|
||||
u16 signal = zl10353_read_register(state, AGC_GAIN_1) << 10 |
|
||||
zl10353_read_register(state, AGC_GAIN_0) << 2 | 3;
|
||||
|
||||
*strength = ~signal;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
@ -227,6 +291,16 @@ static int zl10353_read_snr(struct dvb_frontend *fe, u16 *snr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10353_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
|
||||
*ucblocks = zl10353_read_register(state, RS_UBC_1) << 8 |
|
||||
zl10353_read_register(state, RS_UBC_0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10353_get_tune_settings(struct dvb_frontend *fe,
|
||||
struct dvb_frontend_tune_settings
|
||||
*fe_tune_settings)
|
||||
@ -261,6 +335,16 @@ static int zl10353_init(struct dvb_frontend *fe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zl10353_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
|
||||
{
|
||||
u8 val = 0x0a;
|
||||
|
||||
if (enable)
|
||||
val |= 0x10;
|
||||
|
||||
return zl10353_single_write(fe, 0x62, val);
|
||||
}
|
||||
|
||||
static void zl10353_release(struct dvb_frontend *fe)
|
||||
{
|
||||
struct zl10353_state *state = fe->demodulator_priv;
|
||||
@ -319,15 +403,22 @@ static struct dvb_frontend_ops zl10353_ops = {
|
||||
|
||||
.init = zl10353_init,
|
||||
.sleep = zl10353_sleep,
|
||||
.i2c_gate_ctrl = zl10353_i2c_gate_ctrl,
|
||||
.write = zl10353_write,
|
||||
|
||||
.set_frontend = zl10353_set_parameters,
|
||||
.get_tune_settings = zl10353_get_tune_settings,
|
||||
|
||||
.read_status = zl10353_read_status,
|
||||
.read_ber = zl10353_read_ber,
|
||||
.read_signal_strength = zl10353_read_signal_strength,
|
||||
.read_snr = zl10353_read_snr,
|
||||
.read_ucblocks = zl10353_read_ucblocks,
|
||||
};
|
||||
|
||||
module_param(debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
|
||||
|
||||
module_param(debug_regs, int, 0644);
|
||||
MODULE_PARM_DESC(debug_regs, "Turn on/off frontend register dumps (default:off).");
|
||||
|
||||
|
@ -29,6 +29,9 @@ struct zl10353_config
|
||||
/* demodulator's I2C address */
|
||||
u8 demod_address;
|
||||
|
||||
/* frequencies in kHz */
|
||||
int adc_clock; // default: 22528
|
||||
|
||||
/* set if no pll is connected to the secondary i2c bus */
|
||||
int no_tuner;
|
||||
|
||||
|
@ -24,19 +24,31 @@
|
||||
|
||||
#define ID_ZL10353 0x14
|
||||
|
||||
#define msb(x) (((x) >> 8) & 0xff)
|
||||
#define lsb(x) ((x) & 0xff)
|
||||
|
||||
enum zl10353_reg_addr {
|
||||
INTERRUPT_0 = 0x00,
|
||||
INTERRUPT_1 = 0x01,
|
||||
INTERRUPT_2 = 0x02,
|
||||
INTERRUPT_3 = 0x03,
|
||||
INTERRUPT_4 = 0x04,
|
||||
INTERRUPT_5 = 0x05,
|
||||
STATUS_6 = 0x06,
|
||||
STATUS_7 = 0x07,
|
||||
STATUS_8 = 0x08,
|
||||
STATUS_9 = 0x09,
|
||||
SNR = 0x10,
|
||||
CHIP_ID = 0x7F,
|
||||
INTERRUPT_0 = 0x00,
|
||||
INTERRUPT_1 = 0x01,
|
||||
INTERRUPT_2 = 0x02,
|
||||
INTERRUPT_3 = 0x03,
|
||||
INTERRUPT_4 = 0x04,
|
||||
INTERRUPT_5 = 0x05,
|
||||
STATUS_6 = 0x06,
|
||||
STATUS_7 = 0x07,
|
||||
STATUS_8 = 0x08,
|
||||
STATUS_9 = 0x09,
|
||||
AGC_GAIN_1 = 0x0A,
|
||||
AGC_GAIN_0 = 0x0B,
|
||||
SNR = 0x10,
|
||||
RS_ERR_CNT_2 = 0x11,
|
||||
RS_ERR_CNT_1 = 0x12,
|
||||
RS_ERR_CNT_0 = 0x13,
|
||||
RS_UBC_1 = 0x14,
|
||||
RS_UBC_0 = 0x15,
|
||||
TRL_NOMINAL_RATE_1 = 0x65,
|
||||
TRL_NOMINAL_RATE_0 = 0x66,
|
||||
CHIP_ID = 0x7F,
|
||||
};
|
||||
|
||||
#endif /* _ZL10353_PRIV_ */
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include <asm/system.h>
|
||||
|
||||
@ -223,11 +224,10 @@ static void recover_arm(struct av7110 *av7110)
|
||||
|
||||
static void av7110_arm_sync(struct av7110 *av7110)
|
||||
{
|
||||
av7110->arm_rmmod = 1;
|
||||
wake_up_interruptible(&av7110->arm_wait);
|
||||
if (av7110->arm_thread)
|
||||
kthread_stop(av7110->arm_thread);
|
||||
|
||||
while (av7110->arm_thread)
|
||||
msleep(1);
|
||||
av7110->arm_thread = NULL;
|
||||
}
|
||||
|
||||
static int arm_thread(void *data)
|
||||
@ -238,17 +238,11 @@ static int arm_thread(void *data)
|
||||
|
||||
dprintk(4, "%p\n",av7110);
|
||||
|
||||
lock_kernel();
|
||||
daemonize("arm_mon");
|
||||
sigfillset(¤t->blocked);
|
||||
unlock_kernel();
|
||||
|
||||
av7110->arm_thread = current;
|
||||
|
||||
for (;;) {
|
||||
timeout = wait_event_interruptible_timeout(av7110->arm_wait,
|
||||
av7110->arm_rmmod, 5 * HZ);
|
||||
if (-ERESTARTSYS == timeout || av7110->arm_rmmod) {
|
||||
kthread_should_stop(), 5 * HZ);
|
||||
|
||||
if (-ERESTARTSYS == timeout || kthread_should_stop()) {
|
||||
/* got signal or told to quit*/
|
||||
break;
|
||||
}
|
||||
@ -276,7 +270,6 @@ static int arm_thread(void *data)
|
||||
av7110->arm_errors = 0;
|
||||
}
|
||||
|
||||
av7110->arm_thread = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -695,8 +688,8 @@ static void gpioirq(unsigned long data)
|
||||
static int dvb_osd_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(4, "%p\n", av7110);
|
||||
|
||||
@ -786,7 +779,7 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
|
||||
static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
|
||||
{
|
||||
struct dvb_demux_feed *dvbdmxfeed = dvbdmxfilter->feed;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdmxfeed->demux->priv;
|
||||
struct av7110 *av7110 = dvbdmxfeed->demux->priv;
|
||||
u16 buf[20];
|
||||
int ret, i;
|
||||
u16 handle;
|
||||
@ -835,7 +828,7 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
|
||||
|
||||
static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
|
||||
{
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdmxfilter->feed->demux->priv;
|
||||
struct av7110 *av7110 = dvbdmxfilter->feed->demux->priv;
|
||||
u16 buf[3];
|
||||
u16 answ[2];
|
||||
int ret;
|
||||
@ -871,7 +864,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
|
||||
static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
|
||||
struct av7110 *av7110 = dvbdmx->priv;
|
||||
u16 *pid = dvbdmx->pids, npids[5];
|
||||
int i;
|
||||
int ret = 0;
|
||||
@ -914,7 +907,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
|
||||
static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
|
||||
{
|
||||
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
|
||||
struct av7110 *av7110 = dvbdmx->priv;
|
||||
u16 *pid = dvbdmx->pids, npids[5];
|
||||
int i;
|
||||
|
||||
@ -1103,9 +1096,9 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
|
||||
|
||||
/* pointer casting paranoia... */
|
||||
BUG_ON(!demux);
|
||||
dvbdemux = (struct dvb_demux *) demux->priv;
|
||||
dvbdemux = demux->priv;
|
||||
BUG_ON(!dvbdemux);
|
||||
av7110 = (struct av7110 *) dvbdemux->priv;
|
||||
av7110 = dvbdemux->priv;
|
||||
|
||||
dprintk(4, "%p\n", av7110);
|
||||
|
||||
@ -1137,7 +1130,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
|
||||
|
||||
static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
|
||||
{
|
||||
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
|
||||
struct av7110* av7110 = fe->dvb->priv;
|
||||
|
||||
switch (tone) {
|
||||
case SEC_TONE_ON:
|
||||
@ -1197,7 +1190,7 @@ static int start_ts_capture(struct av7110 *budget)
|
||||
static int budget_start_feed(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dvb_demux *demux = feed->demux;
|
||||
struct av7110 *budget = (struct av7110 *) demux->priv;
|
||||
struct av7110 *budget = demux->priv;
|
||||
int status;
|
||||
|
||||
dprintk(2, "av7110: %p\n", budget);
|
||||
@ -1212,7 +1205,7 @@ static int budget_start_feed(struct dvb_demux_feed *feed)
|
||||
static int budget_stop_feed(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dvb_demux *demux = feed->demux;
|
||||
struct av7110 *budget = (struct av7110 *) demux->priv;
|
||||
struct av7110 *budget = demux->priv;
|
||||
int status;
|
||||
|
||||
dprintk(2, "budget: %p\n", budget);
|
||||
@ -1551,7 +1544,7 @@ static int get_firmware(struct av7110* av7110)
|
||||
|
||||
static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
|
||||
struct av7110* av7110 = fe->dvb->priv;
|
||||
u8 pwr = 0;
|
||||
u8 buf[4];
|
||||
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
|
||||
@ -1702,7 +1695,7 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_front
|
||||
static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
|
||||
{
|
||||
#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
|
||||
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
|
||||
struct av7110* av7110 = fe->dvb->priv;
|
||||
|
||||
return request_firmware(fw, name, &av7110->dev->pci->dev);
|
||||
#else
|
||||
@ -1867,7 +1860,7 @@ static struct stv0297_config nexusca_stv0297_config = {
|
||||
|
||||
static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
|
||||
struct av7110* av7110 = fe->dvb->priv;
|
||||
u32 div;
|
||||
u8 cfg, cpump, band_select;
|
||||
u8 data[4];
|
||||
@ -2338,6 +2331,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
|
||||
const int length = TS_WIDTH * TS_HEIGHT;
|
||||
struct pci_dev *pdev = dev->pci;
|
||||
struct av7110 *av7110;
|
||||
struct task_struct *thread;
|
||||
int ret, count = 0;
|
||||
|
||||
dprintk(4, "dev: %p\n", dev);
|
||||
@ -2622,9 +2616,12 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
|
||||
printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. "
|
||||
"System might be unstable!\n", FW_VERSION(av7110->arm_app));
|
||||
|
||||
ret = kernel_thread(arm_thread, (void *) av7110, 0);
|
||||
if (ret < 0)
|
||||
thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
|
||||
if (IS_ERR(thread)) {
|
||||
ret = PTR_ERR(thread);
|
||||
goto err_stop_arm_9;
|
||||
}
|
||||
av7110->arm_thread = thread;
|
||||
|
||||
/* set initial volume in mixer struct */
|
||||
av7110->mixer.volume_left = volume;
|
||||
|
@ -35,7 +35,6 @@
|
||||
|
||||
#define ANALOG_TUNER_VES1820 1
|
||||
#define ANALOG_TUNER_STV0297 2
|
||||
#define ANALOG_TUNER_VBI 0x100
|
||||
|
||||
extern int av7110_debug;
|
||||
|
||||
@ -205,7 +204,6 @@ struct av7110 {
|
||||
struct task_struct *arm_thread;
|
||||
wait_queue_head_t arm_wait;
|
||||
u16 arm_loops;
|
||||
int arm_rmmod;
|
||||
|
||||
void *debi_virt;
|
||||
dma_addr_t debi_bus;
|
||||
|
@ -880,8 +880,8 @@ static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event
|
||||
|
||||
static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
unsigned int mask = 0;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
@ -908,8 +908,8 @@ static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
|
||||
static ssize_t dvb_video_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
|
||||
@ -924,8 +924,8 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
|
||||
|
||||
static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
unsigned int mask = 0;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
@ -944,8 +944,8 @@ static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)
|
||||
static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
|
||||
@ -989,8 +989,8 @@ static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len,
|
||||
static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
unsigned long arg = (unsigned long) parg;
|
||||
int ret = 0;
|
||||
|
||||
@ -1203,8 +1203,8 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
|
||||
static int dvb_audio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
unsigned long arg = (unsigned long) parg;
|
||||
int ret = 0;
|
||||
|
||||
@ -1349,8 +1349,8 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
|
||||
|
||||
static int dvb_video_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
int err;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
@ -1374,8 +1374,8 @@ static int dvb_video_open(struct inode *inode, struct file *file)
|
||||
|
||||
static int dvb_video_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
|
||||
@ -1388,9 +1388,9 @@ static int dvb_video_release(struct inode *inode, struct file *file)
|
||||
|
||||
static int dvb_audio_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
int err=dvb_generic_open(inode, file);
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
int err = dvb_generic_open(inode, file);
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
|
||||
@ -1403,8 +1403,8 @@ static int dvb_audio_open(struct inode *inode, struct file *file)
|
||||
|
||||
static int dvb_audio_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(2, "av7110:%p, \n", av7110);
|
||||
|
||||
|
@ -214,8 +214,8 @@ static ssize_t ci_ll_read(struct dvb_ringbuffer *cibuf, struct file *file,
|
||||
|
||||
static int dvb_ca_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
int err = dvb_generic_open(inode, file);
|
||||
|
||||
dprintk(8, "av7110:%p\n",av7110);
|
||||
@ -228,8 +228,8 @@ static int dvb_ca_open(struct inode *inode, struct file *file)
|
||||
|
||||
static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
struct dvb_ringbuffer *rbuf = &av7110->ci_rbuffer;
|
||||
struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
|
||||
unsigned int mask = 0;
|
||||
@ -251,8 +251,8 @@ static unsigned int dvb_ca_poll (struct file *file, poll_table *wait)
|
||||
static int dvb_ca_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
unsigned long arg = (unsigned long) parg;
|
||||
|
||||
dprintk(8, "av7110:%p\n",av7110);
|
||||
@ -329,8 +329,8 @@ static int dvb_ca_ioctl(struct inode *inode, struct file *file,
|
||||
static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(8, "av7110:%p\n",av7110);
|
||||
return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
|
||||
@ -339,15 +339,13 @@ static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
|
||||
static ssize_t dvb_ca_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
|
||||
struct av7110 *av7110 = (struct av7110 *) dvbdev->priv;
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct av7110 *av7110 = dvbdev->priv;
|
||||
|
||||
dprintk(8, "av7110:%p\n",av7110);
|
||||
return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct file_operations dvb_ca_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = dvb_ca_read,
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/bitops.h>
|
||||
|
||||
#include "av7110.h"
|
||||
@ -16,6 +17,7 @@
|
||||
static int av_cnt;
|
||||
static struct av7110 *av_list[4];
|
||||
static struct input_dev *input_dev;
|
||||
static char input_phys[32];
|
||||
|
||||
static u8 delay_timer_finished;
|
||||
|
||||
@ -217,7 +219,7 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
|
||||
static struct proc_dir_entry *e;
|
||||
int err;
|
||||
|
||||
if (av_cnt >= sizeof av_list/sizeof av_list[0])
|
||||
if (av_cnt >= ARRAY_SIZE(av_list))
|
||||
return -ENOSPC;
|
||||
|
||||
av7110_setup_irc_config(av7110, 0x0001);
|
||||
@ -231,8 +233,22 @@ int __devinit av7110_ir_init(struct av7110 *av7110)
|
||||
if (!input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
snprintf(input_phys, sizeof(input_phys),
|
||||
"pci-%s/ir0", pci_name(av7110->dev->pci));
|
||||
|
||||
input_dev->name = "DVB on-card IR receiver";
|
||||
|
||||
input_dev->phys = input_phys;
|
||||
input_dev->id.bustype = BUS_PCI;
|
||||
input_dev->id.version = 1;
|
||||
if (av7110->dev->pci->subsystem_vendor) {
|
||||
input_dev->id.vendor = av7110->dev->pci->subsystem_vendor;
|
||||
input_dev->id.product = av7110->dev->pci->subsystem_device;
|
||||
} else {
|
||||
input_dev->id.vendor = av7110->dev->pci->vendor;
|
||||
input_dev->id.product = av7110->dev->pci->device;
|
||||
}
|
||||
input_dev->cdev.dev = &av7110->dev->pci->dev;
|
||||
set_bit(EV_KEY, input_dev->evbit);
|
||||
set_bit(EV_REP, input_dev->evbit);
|
||||
input_register_keys();
|
||||
|
@ -140,17 +140,6 @@ static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0297_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
|
||||
{
|
||||
u8 buf [] = { reg, data };
|
||||
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = buf, .len = 2 };
|
||||
|
||||
if (1 != saa7146_i2c_transfer(dev, &msg, 1, 1))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
|
||||
{
|
||||
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
|
||||
@ -193,6 +182,7 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
|
||||
|
||||
static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
|
||||
{
|
||||
struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
|
||||
u32 div;
|
||||
u8 data[4];
|
||||
|
||||
@ -213,8 +203,8 @@ static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
stv0297_writereg(dev, 0x1C, 0x87, 0x78);
|
||||
stv0297_writereg(dev, 0x1C, 0x86, 0xc8);
|
||||
if (av7110->fe->ops.i2c_gate_ctrl)
|
||||
av7110->fe->ops.i2c_gate_ctrl(av7110->fe, 1);
|
||||
return tuner_write(dev, 0x63, data);
|
||||
}
|
||||
|
||||
@ -817,20 +807,20 @@ int av7110_init_v4l(struct av7110 *av7110)
|
||||
saa7146_vv_release(dev);
|
||||
return -ENODEV;
|
||||
}
|
||||
if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI)) {
|
||||
if (saa7146_register_device(&av7110->vbi_dev, dev, "av7110", VFL_TYPE_VBI))
|
||||
ERR(("cannot register vbi v4l2 device. skipping.\n"));
|
||||
} else {
|
||||
if (av7110->analog_tuner_flags)
|
||||
av7110->analog_tuner_flags |= ANALOG_TUNER_VBI;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int av7110_exit_v4l(struct av7110 *av7110)
|
||||
{
|
||||
struct saa7146_dev* dev = av7110->dev;
|
||||
|
||||
saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
|
||||
if (av7110->analog_tuner_flags & ANALOG_TUNER_VBI)
|
||||
saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
|
||||
saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
|
||||
|
||||
saa7146_vv_release(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1089,6 +1089,8 @@ static int budget_av_detach(struct saa7146_dev *dev)
|
||||
msleep(200);
|
||||
|
||||
saa7146_unregister_device(&budget_av->vd, dev);
|
||||
|
||||
saa7146_vv_release(dev);
|
||||
}
|
||||
|
||||
if (budget_av->budget.ci_present)
|
||||
@ -1145,6 +1147,7 @@ static int budget_av_attach(struct saa7146_dev *dev, struct saa7146_pci_extensio
|
||||
if ((err = saa7146_register_device(&budget_av->vd, dev, "knc1", VFL_TYPE_GRABBER))) {
|
||||
/* fixme: proper cleanup here */
|
||||
ERR(("cannot register capture v4l2 device.\n"));
|
||||
saa7146_vv_release(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@
|
||||
* the project's page is at http://www.linuxtv.org/dvb/
|
||||
*/
|
||||
|
||||
#include "budget.h"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
@ -39,6 +37,8 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <media/ir-common.h>
|
||||
|
||||
#include "budget.h"
|
||||
|
||||
#include "dvb_ca_en50221.h"
|
||||
#include "stv0299.h"
|
||||
#include "stv0297.h"
|
||||
@ -130,6 +130,7 @@ static void msp430_ir_interrupt(unsigned long data)
|
||||
int toggle;
|
||||
static int prev_toggle = -1;
|
||||
static u32 ir_key;
|
||||
static int state = 0;
|
||||
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
|
||||
|
||||
/*
|
||||
@ -138,21 +139,34 @@ static void msp430_ir_interrupt(unsigned long data)
|
||||
* type1: X1CCCCCC, C = command bits (0 - 63)
|
||||
* type2: X0TDDDDD, D = device bits (0 - 31), T = RC5 toggle bit
|
||||
*
|
||||
* More than one command byte may be generated before the device byte
|
||||
* Only when we have both, a correct keypress is generated
|
||||
* Each signal from the remote control can generate one or more command
|
||||
* bytes and one or more device bytes. For the repeated bytes, the
|
||||
* highest bit (X) is set. The first command byte is always generated
|
||||
* before the first device byte. Other than that, no specific order
|
||||
* seems to apply.
|
||||
*
|
||||
* Only when we have a command and device byte, a keypress is
|
||||
* generated.
|
||||
*/
|
||||
|
||||
if (ir_debug)
|
||||
printk("budget_ci: received byte 0x%02x\n", command);
|
||||
|
||||
/* Is this a repeated byte? */
|
||||
if (command & 0x80)
|
||||
return;
|
||||
|
||||
/* Is this a RC5 command byte? */
|
||||
if (command & 0x40) {
|
||||
if (ir_debug)
|
||||
printk("budget_ci: received command byte 0x%02x\n", command);
|
||||
state = 1;
|
||||
ir_key = command & 0x3f;
|
||||
return;
|
||||
}
|
||||
|
||||
/* It's a RC5 device byte */
|
||||
if (ir_debug)
|
||||
printk("budget_ci: received device byte 0x%02x\n", command);
|
||||
if (!state)
|
||||
return;
|
||||
state = 0;
|
||||
device = command & 0x1f;
|
||||
toggle = command & 0x20;
|
||||
|
||||
@ -223,7 +237,6 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
||||
switch (budget_ci->budget.dev->pci->subsystem_device) {
|
||||
case 0x100c:
|
||||
case 0x100f:
|
||||
case 0x1010:
|
||||
case 0x1011:
|
||||
case 0x1012:
|
||||
case 0x1017:
|
||||
@ -236,6 +249,16 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
|
||||
else
|
||||
budget_ci->ir.rc5_device = rc5_device;
|
||||
break;
|
||||
case 0x1010:
|
||||
/* for the Technotrend 1500 bundled remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
IR_TYPE_RC5, ir_codes_tt_1500);
|
||||
|
||||
if (rc5_device < 0)
|
||||
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
|
||||
else
|
||||
budget_ci->ir.rc5_device = rc5_device;
|
||||
break;
|
||||
default:
|
||||
/* unknown remote */
|
||||
ir_input_init(input_dev, &budget_ci->ir.state,
|
||||
@ -869,6 +892,17 @@ static struct tda1004x_config philips_tdm1316l_config = {
|
||||
.request_firmware = philips_tdm1316l_request_firmware,
|
||||
};
|
||||
|
||||
static struct tda1004x_config philips_tdm1316l_config_invert = {
|
||||
|
||||
.demod_address = 0x8,
|
||||
.invert = 1,
|
||||
.invert_oclk = 0,
|
||||
.xtal_freq = TDA10046_XTAL_4M,
|
||||
.agc_config = TDA10046_AGC_DEFAULT,
|
||||
.if_freq = TDA10046_FREQ_3617,
|
||||
.request_firmware = philips_tdm1316l_request_firmware,
|
||||
};
|
||||
|
||||
static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
|
||||
{
|
||||
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
|
||||
@ -1092,9 +1126,8 @@ static void frontend_init(struct budget_ci *budget_ci)
|
||||
|
||||
case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
|
||||
budget_ci->tuner_pll_address = 0x60;
|
||||
philips_tdm1316l_config.invert = 1;
|
||||
budget_ci->budget.dvb_frontend =
|
||||
dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
|
||||
dvb_attach(tda10046_attach, &philips_tdm1316l_config_invert, &budget_ci->budget.i2c_adap);
|
||||
if (budget_ci->budget.dvb_frontend) {
|
||||
budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
|
||||
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
|
||||
|
@ -20,8 +20,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
@ -35,6 +33,8 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/input.h>
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "dmxdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_filter.h"
|
||||
|
@ -180,136 +180,163 @@ static int az_setfreq(struct az_device *dev, unsigned long frequency)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap (struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
|
||||
strlcpy(v->card, "Aztech Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner (struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct az_device *az = dev->priv;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
|
||||
strlcpy(v->card, "Aztech Radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
v->rangelow=(87*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(az_getstereo(az))
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*az_getsigstr(az);
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
v->rangelow=(87*16000);
|
||||
v->rangehigh=(108*16000);
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(az_getstereo(az))
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xFFFF*az_getsigstr(az);
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
az->curfreq = f->frequency;
|
||||
az_setfreq(az, az->curfreq);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = az->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (az->curvol==0)
|
||||
ctrl->value=1;
|
||||
else
|
||||
ctrl->value=0;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=az->curvol * 6554;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
az_setvol(az,0);
|
||||
} else {
|
||||
az_setvol(az,az->curvol);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
az_setvol(az,ctrl->value);
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
az_do_ioctl);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int az_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
|
||||
static int vidioc_s_tuner (struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
return video_usercopy(inode, file, cmd, arg, az_do_ioctl);
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_audio (struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(a->name, "Radio");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vidioc_s_audio (struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency (struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct az_device *az = dev->priv;
|
||||
|
||||
az->curfreq = f->frequency;
|
||||
az_setfreq(az, az->curfreq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency (struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct az_device *az = dev->priv;
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = az->curfreq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl (struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct az_device *az = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (az->curvol==0)
|
||||
ctrl->value=1;
|
||||
else
|
||||
ctrl->value=0;
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
ctrl->value=az->curvol * 6554;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct az_device *az = dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
if (ctrl->value) {
|
||||
az_setvol(az,0);
|
||||
} else {
|
||||
az_setvol(az,az->curvol);
|
||||
}
|
||||
return (0);
|
||||
case V4L2_CID_AUDIO_VOLUME:
|
||||
az_setvol(az,ctrl->value);
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct az_device aztech_unit;
|
||||
@ -318,20 +345,35 @@ static const struct file_operations aztech_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = az_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static struct video_device aztech_radio=
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Aztech radio",
|
||||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &aztech_fops,
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Aztech radio",
|
||||
.type = VID_TYPE_TUNER,
|
||||
.hardware = 0,
|
||||
.fops = &aztech_fops,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
module_param_named(debug,aztech_radio.debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,"activates debug info");
|
||||
|
||||
static int __init aztech_init(void)
|
||||
{
|
||||
if(io==-1)
|
||||
|
@ -89,14 +89,6 @@ static struct v4l2_queryctrl radio_qctrl[] = {
|
||||
#define GEMTEK_PCI_RANGE_HIGH (108*16000)
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE (1)
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE (0)
|
||||
#endif
|
||||
|
||||
struct gemtek_pci_card {
|
||||
struct video_device *videodev;
|
||||
|
||||
@ -146,12 +138,12 @@ static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
|
||||
|
||||
static inline void gemtek_pci_nil( u32 port, u8 *last_byte )
|
||||
{
|
||||
__gemtek_pci_cmd( 0x00, port, last_byte, FALSE );
|
||||
__gemtek_pci_cmd( 0x00, port, last_byte, false );
|
||||
}
|
||||
|
||||
static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte )
|
||||
{
|
||||
__gemtek_pci_cmd( cmd, port, last_byte, TRUE );
|
||||
__gemtek_pci_cmd( cmd, port, last_byte, true );
|
||||
}
|
||||
|
||||
static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency )
|
||||
@ -184,14 +176,14 @@ static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long
|
||||
static inline void gemtek_pci_mute( struct gemtek_pci_card *card )
|
||||
{
|
||||
outb( 0x1f, card->iobase );
|
||||
card->mute = TRUE;
|
||||
card->mute = true;
|
||||
}
|
||||
|
||||
static inline void gemtek_pci_unmute( struct gemtek_pci_card *card )
|
||||
{
|
||||
if ( card->mute ) {
|
||||
gemtek_pci_setfrequency( card, card->current_frequency );
|
||||
card->mute = FALSE;
|
||||
card->mute = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,7 +251,7 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
|
||||
|
||||
gemtek_pci_setfrequency( card, f->frequency );
|
||||
card->current_frequency = f->frequency;
|
||||
card->mute = FALSE;
|
||||
card->mute = false;
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
|
@ -27,7 +27,9 @@
|
||||
* BUGS:
|
||||
* - card unmutes if you change frequency
|
||||
*
|
||||
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
* (c) 2006, 2007 by Mauro Carvalho Chehab <mchehab@infradead.org>:
|
||||
* - Conversion to V4L2 API
|
||||
* - Uses video_ioctl2 for parsing and to add debug support
|
||||
*/
|
||||
|
||||
|
||||
@ -43,10 +45,18 @@
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-common.h>
|
||||
|
||||
#define DRIVER_VERSION "0.76"
|
||||
#define DRIVER_VERSION "0.77"
|
||||
|
||||
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
|
||||
#define RADIO_VERSION KERNEL_VERSION(0,7,6)
|
||||
#define RADIO_VERSION KERNEL_VERSION(0,7,7)
|
||||
|
||||
static struct video_device maxiradio_radio;
|
||||
|
||||
#define dprintk(num, fmt, arg...) \
|
||||
do { \
|
||||
if (maxiradio_radio.debug >= num) \
|
||||
printk(KERN_DEBUG "%s: " fmt, \
|
||||
maxiradio_radio.name, ## arg); } while (0)
|
||||
|
||||
static struct v4l2_queryctrl radio_qctrl[] = {
|
||||
{
|
||||
@ -81,30 +91,21 @@ module_param(radio_nr, int, 0);
|
||||
#define FREQ_IF 171200 /* 10.7*16000 */
|
||||
#define FREQ_STEP 200 /* 12.5*16 */
|
||||
|
||||
#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
|
||||
/(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
|
||||
/* (x==fmhz*16*1000) -> bits */
|
||||
#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \
|
||||
/(FREQ_STEP<<2))<<2)
|
||||
|
||||
#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
|
||||
|
||||
|
||||
static int radio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
static const struct file_operations maxiradio_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = video_exclusive_open,
|
||||
.release = video_exclusive_release,
|
||||
.ioctl = radio_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
static struct video_device maxiradio_radio =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Maxi Radio FM2000 radio",
|
||||
.type = VID_TYPE_TUNER,
|
||||
.fops = &maxiradio_fops,
|
||||
};
|
||||
|
||||
static struct radio_device
|
||||
{
|
||||
@ -116,12 +117,14 @@ static struct radio_device
|
||||
unsigned long freq;
|
||||
|
||||
struct mutex lock;
|
||||
} radio_unit = {0, 0, 0, 0, };
|
||||
|
||||
} radio_unit = {
|
||||
.muted =1,
|
||||
.freq = FREQ_LO,
|
||||
};
|
||||
|
||||
static void outbit(unsigned long bit, __u16 io)
|
||||
{
|
||||
if(bit != 0)
|
||||
if (bit != 0)
|
||||
{
|
||||
outb( power|wren|data ,io); udelay(4);
|
||||
outb( power|wren|data|clk ,io); udelay(4);
|
||||
@ -137,14 +140,20 @@ static void outbit(unsigned long bit, __u16 io)
|
||||
|
||||
static void turn_power(__u16 io, int p)
|
||||
{
|
||||
if(p != 0) outb(power, io); else outb(0,io);
|
||||
if (p != 0) {
|
||||
dprintk(1, "Radio powered on\n");
|
||||
outb(power, io);
|
||||
} else {
|
||||
dprintk(1, "Radio powered off\n");
|
||||
outb(0,io);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void set_freq(__u16 io, __u32 data)
|
||||
static void set_freq(__u16 io, __u32 freq)
|
||||
{
|
||||
unsigned long int si;
|
||||
int bl;
|
||||
int data = FREQ2BITS(freq);
|
||||
|
||||
/* TEA5757 shift register bits (see pdf) */
|
||||
|
||||
@ -163,161 +172,225 @@ static void set_freq(__u16 io, __u32 data)
|
||||
outbit(0,io); // 16 search level
|
||||
|
||||
si = 0x8000;
|
||||
for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
|
||||
for (bl = 1; bl <= 16 ; bl++) {
|
||||
outbit(data & si,io);
|
||||
si >>=1;
|
||||
}
|
||||
|
||||
outb(power,io);
|
||||
dprintk(1, "Radio freq set to %d.%02d MHz\n",
|
||||
freq / 16000,
|
||||
freq % 16000 * 100 / 16000);
|
||||
|
||||
turn_power(io, 1);
|
||||
}
|
||||
|
||||
static int get_stereo(__u16 io)
|
||||
{
|
||||
outb(power,io); udelay(4);
|
||||
outb(power,io);
|
||||
udelay(4);
|
||||
|
||||
return !(inb(io) & mo_st);
|
||||
}
|
||||
|
||||
static int get_tune(__u16 io)
|
||||
{
|
||||
outb(power+clk,io); udelay(4);
|
||||
outb(power+clk,io);
|
||||
udelay(4);
|
||||
|
||||
return !(inb(io) & mo_st);
|
||||
}
|
||||
|
||||
|
||||
static inline int radio_function(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap (struct file *file, void *priv,
|
||||
struct v4l2_capability *v)
|
||||
{
|
||||
strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
|
||||
strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner (struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card=dev->priv;
|
||||
|
||||
switch(cmd) {
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
|
||||
strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
|
||||
sprintf(v->bus_info,"ISA");
|
||||
v->version = RADIO_VERSION;
|
||||
v->capabilities = V4L2_CAP_TUNER;
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
v->rangelow=FREQ_LO;
|
||||
v->rangehigh=FREQ_HI;
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(get_stereo(card->io))
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xffff*get_tune(card->io);
|
||||
|
||||
memset(v,0,sizeof(*v));
|
||||
strcpy(v->name, "FM");
|
||||
v->type = V4L2_TUNER_RADIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
v->rangelow=FREQ_LO;
|
||||
v->rangehigh=FREQ_HI;
|
||||
v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
|
||||
v->capability=V4L2_TUNER_CAP_LOW;
|
||||
if(get_stereo(card->io))
|
||||
v->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
else
|
||||
v->audmode = V4L2_TUNER_MODE_MONO;
|
||||
v->signal=0xffff*get_tune(card->io);
|
||||
static int vidioc_s_tuner (struct file *file, void *priv,
|
||||
struct v4l2_tuner *v)
|
||||
{
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_TUNER:
|
||||
{
|
||||
struct v4l2_tuner *v = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (v->index > 0)
|
||||
return -EINVAL;
|
||||
static int vidioc_g_audio (struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index > 1)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
strcpy(a->name, "FM");
|
||||
a->capability = V4L2_AUDCAP_STEREO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
|
||||
return -EINVAL;
|
||||
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
|
||||
{
|
||||
*i = 0;
|
||||
|
||||
card->freq = f->frequency;
|
||||
set_freq(card->io, FREQ2BITS(card->freq));
|
||||
msleep(125);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FREQUENCY:
|
||||
{
|
||||
struct v4l2_frequency *f = arg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = card->freq;
|
||||
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
|
||||
{
|
||||
if (i != 0)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *qc = arg;
|
||||
int i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]),
|
||||
sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_G_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=card->muted;
|
||||
return (0);
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
case VIDIOC_S_CTRL:
|
||||
{
|
||||
struct v4l2_control *ctrl= arg;
|
||||
static int vidioc_s_audio (struct file *file, void *priv,
|
||||
struct v4l2_audio *a)
|
||||
{
|
||||
if (a->index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
card->muted = ctrl->value;
|
||||
if(card->muted)
|
||||
turn_power(card->io, 0);
|
||||
else
|
||||
set_freq(card->io, FREQ2BITS(card->freq));
|
||||
return 0;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return v4l_compat_translate_ioctl(inode,file,cmd,arg,
|
||||
radio_function);
|
||||
static int vidioc_s_frequency (struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card=dev->priv;
|
||||
|
||||
if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) {
|
||||
dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n",
|
||||
f->frequency / 16000,
|
||||
f->frequency % 16000 * 100 / 16000,
|
||||
FREQ_LO / 16000, FREQ_HI / 16000);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
card->freq = f->frequency;
|
||||
set_freq(card->io, card->freq);
|
||||
msleep(125);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int radio_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_frequency (struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card=dev->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&card->lock);
|
||||
ret = video_usercopy(inode, file, cmd, arg, radio_function);
|
||||
mutex_unlock(&card->lock);
|
||||
return ret;
|
||||
f->type = V4L2_TUNER_RADIO;
|
||||
f->frequency = card->freq;
|
||||
|
||||
dprintk(4, "radio freq is %d.%02d MHz",
|
||||
f->frequency / 16000,
|
||||
f->frequency % 16000 * 100 / 16000);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
|
||||
MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
|
||||
MODULE_LICENSE("GPL");
|
||||
static int vidioc_queryctrl (struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qc)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
|
||||
if (qc->id && qc->id == radio_qctrl[i].id) {
|
||||
memcpy(qc, &(radio_qctrl[i]), sizeof(*qc));
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card=dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
ctrl->value=card->muted;
|
||||
return (0);
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctrl)
|
||||
{
|
||||
struct video_device *dev = video_devdata(file);
|
||||
struct radio_device *card=dev->priv;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUDIO_MUTE:
|
||||
card->muted = ctrl->value;
|
||||
if(card->muted)
|
||||
turn_power(card->io, 0);
|
||||
else
|
||||
set_freq(card->io, card->freq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static struct video_device maxiradio_radio =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.name = "Maxi Radio FM2000 radio",
|
||||
.type = VID_TYPE_TUNER,
|
||||
.fops = &maxiradio_fops,
|
||||
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_g_audio = vidioc_g_audio,
|
||||
.vidioc_s_audio = vidioc_s_audio,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
};
|
||||
|
||||
static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
@ -334,7 +407,7 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d
|
||||
mutex_init(&radio_unit.lock);
|
||||
maxiradio_radio.priv = &radio_unit;
|
||||
|
||||
if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
|
||||
if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
|
||||
printk("radio-maxiradio: can't register device!");
|
||||
goto err_out_free_region;
|
||||
}
|
||||
@ -389,3 +462,10 @@ static void __exit maxiradio_radio_exit(void)
|
||||
|
||||
module_init(maxiradio_radio_init);
|
||||
module_exit(maxiradio_radio_exit);
|
||||
|
||||
MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net");
|
||||
MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio.");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
module_param_named(debug,maxiradio_radio.debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,"activates debug info");
|
||||
|
@ -342,7 +342,7 @@ endmenu # encoder / decoder chips
|
||||
|
||||
config VIDEO_VIVI
|
||||
tristate "Virtual Video Driver"
|
||||
depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
|
||||
depends on VIDEO_V4L2 && !SPARC32 && !SPARC64 && PCI
|
||||
select VIDEO_BUF
|
||||
default n
|
||||
---help---
|
||||
|
@ -113,4 +113,3 @@ obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
|
||||
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
|
||||
extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
|
||||
|
@ -307,6 +307,7 @@ static struct CARD {
|
||||
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
|
||||
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
|
||||
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
|
||||
{ 0xdb1118ac, BTTV_BOARD_DVICO_DVBT_LITE, "Ultraview DVB-T Lite" },
|
||||
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
|
||||
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
|
||||
|
||||
@ -578,14 +579,9 @@ struct tvcard bttv_tvcards[] = {
|
||||
.svhs = 2,
|
||||
.gpiomask = 0x01fe00,
|
||||
.muxsel = { 2, 3, 1, 1 },
|
||||
#if 0
|
||||
/* old */
|
||||
.gpiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000 },
|
||||
#else
|
||||
/* 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru> */
|
||||
.gpiomux = { 0x001e00, 0, 0x018000, 0x014000 },
|
||||
.gpiomute = 0x002000,
|
||||
#endif
|
||||
.needs_tvaudio = 1,
|
||||
.pll = PLL_28,
|
||||
.tuner_type = -1,
|
||||
@ -894,15 +890,10 @@ struct tvcard bttv_tvcards[] = {
|
||||
.tuner = 0,
|
||||
.svhs = 2,
|
||||
.muxsel = { 2, 3, 1, 1, 0 }, /* TV, CVid, SVid, CVid over SVid connector */
|
||||
#if 0
|
||||
.gpiomask = 0xc33000,
|
||||
.gpiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
|
||||
#else
|
||||
/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
|
||||
.gpiomask = 0xb33000,
|
||||
.gpiomux = { 0x122000,0x1000,0x0000,0x620000 },
|
||||
.gpiomute = 0x800000,
|
||||
#endif
|
||||
/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
|
||||
gpio23 -- hef4052:nEnable (0x800000)
|
||||
gpio12 -- hef4052:A1
|
||||
@ -1937,11 +1928,6 @@ struct tvcard bttv_tvcards[] = {
|
||||
.video_inputs = 4,
|
||||
.audio_inputs = 1,
|
||||
.tuner = -1,
|
||||
#if 0 /* TODO ... */
|
||||
.svhs = OSPREY540_SVID_ANALOG,
|
||||
.muxsel = { [OSPREY540_COMP_ANALOG] = 2,
|
||||
[OSPREY540_SVID_ANALOG] = 3, },
|
||||
#endif
|
||||
.pll = PLL_28,
|
||||
.tuner_type = -1,
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
@ -1949,10 +1935,6 @@ struct tvcard bttv_tvcards[] = {
|
||||
.no_msp34xx = 1,
|
||||
.no_tda9875 = 1,
|
||||
.no_tda7432 = 1,
|
||||
#if 0 /* TODO ... */
|
||||
.muxsel_hook = osprey_540_muxsel,
|
||||
.picture_hook = osprey_540_set_picture,
|
||||
#endif
|
||||
},
|
||||
|
||||
/* ---- card 0x5C ---------------------------------- */
|
||||
@ -2627,9 +2609,6 @@ struct tvcard bttv_tvcards[] = {
|
||||
.tuner_addr = ADDR_UNSET,
|
||||
.radio_addr = ADDR_UNSET,
|
||||
.has_radio = 0,
|
||||
#if 0
|
||||
.has_remote = 1,
|
||||
#endif
|
||||
},
|
||||
[BTTV_BOARD_SUPER_TV] = {
|
||||
/* Rick C <cryptdragoon@gmail.com> */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -36,13 +36,18 @@ module_param(repeat_delay, int, 0644);
|
||||
static int repeat_period = 33;
|
||||
module_param(repeat_period, int, 0644);
|
||||
|
||||
static int ir_rc5_remote_gap = 885;
|
||||
module_param(ir_rc5_remote_gap, int, 0644);
|
||||
static int ir_rc5_key_timeout = 200;
|
||||
module_param(ir_rc5_key_timeout, int, 0644);
|
||||
|
||||
#define DEVNAME "bttv-input"
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void ir_handle_key(struct bttv *btv)
|
||||
{
|
||||
struct bttv_ir *ir = btv->remote;
|
||||
struct card_ir *ir = btv->remote;
|
||||
u32 gpio,data;
|
||||
|
||||
/* read gpio value */
|
||||
@ -72,7 +77,7 @@ static void ir_handle_key(struct bttv *btv)
|
||||
|
||||
void bttv_input_irq(struct bttv *btv)
|
||||
{
|
||||
struct bttv_ir *ir = btv->remote;
|
||||
struct card_ir *ir = btv->remote;
|
||||
|
||||
if (!ir->polling)
|
||||
ir_handle_key(btv);
|
||||
@ -81,65 +86,21 @@ void bttv_input_irq(struct bttv *btv)
|
||||
static void bttv_input_timer(unsigned long data)
|
||||
{
|
||||
struct bttv *btv = (struct bttv*)data;
|
||||
struct bttv_ir *ir = btv->remote;
|
||||
unsigned long timeout;
|
||||
struct card_ir *ir = btv->remote;
|
||||
|
||||
ir_handle_key(btv);
|
||||
timeout = jiffies + (ir->polling * HZ / 1000);
|
||||
mod_timer(&ir->timer, timeout);
|
||||
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------*/
|
||||
|
||||
static int rc5_remote_gap = 885;
|
||||
module_param(rc5_remote_gap, int, 0644);
|
||||
static int rc5_key_timeout = 200;
|
||||
module_param(rc5_key_timeout, int, 0644);
|
||||
|
||||
#define RC5_START(x) (((x)>>12)&3)
|
||||
#define RC5_TOGGLE(x) (((x)>>11)&1)
|
||||
#define RC5_ADDR(x) (((x)>>6)&31)
|
||||
#define RC5_INSTR(x) ((x)&63)
|
||||
|
||||
/* decode raw bit pattern to RC5 code */
|
||||
static u32 rc5_decode(unsigned int code)
|
||||
{
|
||||
unsigned int org_code = code;
|
||||
unsigned int pair;
|
||||
unsigned int rc5 = 0;
|
||||
int i;
|
||||
|
||||
code = (code << 1) | 1;
|
||||
for (i = 0; i < 14; ++i) {
|
||||
pair = code & 0x3;
|
||||
code >>= 2;
|
||||
|
||||
rc5 <<= 1;
|
||||
switch (pair) {
|
||||
case 0:
|
||||
case 2:
|
||||
break;
|
||||
case 1:
|
||||
rc5 |= 1;
|
||||
break;
|
||||
case 3:
|
||||
dprintk(KERN_WARNING "bad code: %x\n", org_code);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dprintk(KERN_WARNING "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
|
||||
"instr=%x\n", rc5, org_code, RC5_START(rc5),
|
||||
RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
|
||||
return rc5;
|
||||
}
|
||||
|
||||
static int bttv_rc5_irq(struct bttv *btv)
|
||||
{
|
||||
struct bttv_ir *ir = btv->remote;
|
||||
struct card_ir *ir = btv->remote;
|
||||
struct timeval tv;
|
||||
u32 gpio;
|
||||
u32 gap;
|
||||
unsigned long current_jiffies, timeout;
|
||||
unsigned long current_jiffies;
|
||||
|
||||
/* read gpio port */
|
||||
gpio = bttv_gpio_read(&btv->c);
|
||||
@ -165,8 +126,8 @@ static int bttv_rc5_irq(struct bttv *btv)
|
||||
/* only if in the code (otherwise spurious IRQ or timer
|
||||
late) */
|
||||
if (ir->last_bit < 28) {
|
||||
ir->last_bit = (gap - rc5_remote_gap / 2) /
|
||||
rc5_remote_gap;
|
||||
ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
|
||||
ir_rc5_remote_gap;
|
||||
ir->code |= 1 << ir->last_bit;
|
||||
}
|
||||
/* starting new code */
|
||||
@ -176,8 +137,8 @@ static int bttv_rc5_irq(struct bttv *btv)
|
||||
ir->base_time = tv;
|
||||
ir->last_bit = 0;
|
||||
|
||||
timeout = current_jiffies + (500 + 30 * HZ) / 1000;
|
||||
mod_timer(&ir->timer_end, timeout);
|
||||
mod_timer(&ir->timer_end,
|
||||
current_jiffies + msecs_to_jiffies(30));
|
||||
}
|
||||
|
||||
/* toggle GPIO pin 4 to reset the irq */
|
||||
@ -186,96 +147,28 @@ static int bttv_rc5_irq(struct bttv *btv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void bttv_rc5_timer_end(unsigned long data)
|
||||
{
|
||||
struct bttv_ir *ir = (struct bttv_ir *)data;
|
||||
struct timeval tv;
|
||||
unsigned long current_jiffies, timeout;
|
||||
u32 gap;
|
||||
|
||||
/* get time */
|
||||
current_jiffies = jiffies;
|
||||
do_gettimeofday(&tv);
|
||||
|
||||
/* avoid overflow with gap >1s */
|
||||
if (tv.tv_sec - ir->base_time.tv_sec > 1) {
|
||||
gap = 200000;
|
||||
} else {
|
||||
gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
|
||||
tv.tv_usec - ir->base_time.tv_usec;
|
||||
}
|
||||
|
||||
/* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */
|
||||
if (gap < 28000) {
|
||||
dprintk(KERN_WARNING "spurious timer_end\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ir->active = 0;
|
||||
if (ir->last_bit < 20) {
|
||||
/* ignore spurious codes (caused by light/other remotes) */
|
||||
dprintk(KERN_WARNING "short code: %x\n", ir->code);
|
||||
} else {
|
||||
u32 rc5 = rc5_decode(ir->code);
|
||||
|
||||
/* two start bits? */
|
||||
if (RC5_START(rc5) != 3) {
|
||||
dprintk(KERN_WARNING "rc5 start bits invalid: %u\n", RC5_START(rc5));
|
||||
|
||||
/* right address? */
|
||||
} else if (RC5_ADDR(rc5) == 0x0) {
|
||||
u32 toggle = RC5_TOGGLE(rc5);
|
||||
u32 instr = RC5_INSTR(rc5);
|
||||
|
||||
/* Good code, decide if repeat/repress */
|
||||
if (toggle != RC5_TOGGLE(ir->last_rc5) ||
|
||||
instr != RC5_INSTR(ir->last_rc5)) {
|
||||
dprintk(KERN_WARNING "instruction %x, toggle %x\n", instr,
|
||||
toggle);
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
ir_input_keydown(ir->dev, &ir->ir, instr,
|
||||
instr);
|
||||
}
|
||||
|
||||
/* Set/reset key-up timer */
|
||||
timeout = current_jiffies + (500 + rc5_key_timeout
|
||||
* HZ) / 1000;
|
||||
mod_timer(&ir->timer_keyup, timeout);
|
||||
|
||||
/* Save code for repeat test */
|
||||
ir->last_rc5 = rc5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bttv_rc5_timer_keyup(unsigned long data)
|
||||
{
|
||||
struct bttv_ir *ir = (struct bttv_ir *)data;
|
||||
|
||||
dprintk(KERN_DEBUG "key released\n");
|
||||
ir_input_nokey(ir->dev, &ir->ir);
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
|
||||
static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
|
||||
{
|
||||
if (ir->polling) {
|
||||
init_timer(&ir->timer);
|
||||
ir->timer.function = bttv_input_timer;
|
||||
ir->timer.data = (unsigned long)btv;
|
||||
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
|
||||
ir->timer.expires = jiffies + HZ;
|
||||
add_timer(&ir->timer);
|
||||
} else if (ir->rc5_gpio) {
|
||||
/* set timer_end for code completion */
|
||||
init_timer(&ir->timer_end);
|
||||
ir->timer_end.function = bttv_rc5_timer_end;
|
||||
ir->timer_end.function = ir_rc5_timer_end;
|
||||
ir->timer_end.data = (unsigned long)ir;
|
||||
|
||||
init_timer(&ir->timer_keyup);
|
||||
ir->timer_keyup.function = bttv_rc5_timer_keyup;
|
||||
ir->timer_keyup.function = ir_rc5_timer_keyup;
|
||||
ir->timer_keyup.data = (unsigned long)ir;
|
||||
ir->shift_by = 1;
|
||||
ir->start = 3;
|
||||
ir->addr = 0x0;
|
||||
ir->rc5_key_timeout = ir_rc5_key_timeout;
|
||||
ir->rc5_remote_gap = ir_rc5_remote_gap;
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,7 +192,7 @@ static void bttv_ir_stop(struct bttv *btv)
|
||||
|
||||
int bttv_input_init(struct bttv *btv)
|
||||
{
|
||||
struct bttv_ir *ir;
|
||||
struct card_ir *ir;
|
||||
IR_KEYTAB_TYPE *ir_codes = NULL;
|
||||
struct input_dev *input_dev;
|
||||
int ir_type = IR_TYPE_OTHER;
|
||||
|
@ -43,7 +43,8 @@ int
|
||||
bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
struct scatterlist *sglist,
|
||||
unsigned int offset, unsigned int bpl,
|
||||
unsigned int padding, unsigned int lines)
|
||||
unsigned int padding, unsigned int skip_lines,
|
||||
unsigned int store_lines)
|
||||
{
|
||||
u32 instructions,line,todo;
|
||||
struct scatterlist *sg;
|
||||
@ -54,9 +55,11 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
one write per scan line + sync + jump (all 2 dwords). padding
|
||||
can cause next bpl to start close to a page border. First DMA
|
||||
region may be smaller than PAGE_SIZE */
|
||||
instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines;
|
||||
instructions += 2;
|
||||
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0)
|
||||
instructions = skip_lines * 4;
|
||||
instructions += (1 + ((bpl + padding) * store_lines)
|
||||
/ PAGE_SIZE + store_lines) * 8;
|
||||
instructions += 2 * 8;
|
||||
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions)) < 0)
|
||||
return rc;
|
||||
|
||||
/* sync instruction */
|
||||
@ -64,11 +67,16 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
*(rp++) = cpu_to_le32(BT848_RISC_SYNC|BT848_FIFO_STATUS_FM1);
|
||||
*(rp++) = cpu_to_le32(0);
|
||||
|
||||
while (skip_lines-- > 0) {
|
||||
*(rp++) = cpu_to_le32(BT848_RISC_SKIP | BT848_RISC_SOL |
|
||||
BT848_RISC_EOL | bpl);
|
||||
}
|
||||
|
||||
/* scan lines */
|
||||
sg = sglist;
|
||||
for (line = 0; line < lines; line++) {
|
||||
for (line = 0; line < store_lines; line++) {
|
||||
if ((btv->opt_vcr_hack) &&
|
||||
(line >= (lines - VCR_HACK_LINES)))
|
||||
(line >= (store_lines - VCR_HACK_LINES)))
|
||||
continue;
|
||||
while (offset && offset >= sg_dma_len(sg)) {
|
||||
offset -= sg_dma_len(sg);
|
||||
@ -130,7 +138,8 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
/* estimate risc mem: worst case is one write per page border +
|
||||
one write per scan line (5 dwords)
|
||||
plus sync + jump (2 dwords) */
|
||||
instructions = (ybpl * ylines * 2) / PAGE_SIZE + ylines;
|
||||
instructions = ((3 + (ybpl + ypadding) * ylines * 2)
|
||||
/ PAGE_SIZE) + ylines;
|
||||
instructions += 2;
|
||||
if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*4*5)) < 0)
|
||||
return rc;
|
||||
@ -317,10 +326,10 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
/* ---------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
|
||||
int width, int height, int interleaved, int norm)
|
||||
bttv_calc_geo_old(struct bttv *btv, struct bttv_geometry *geo,
|
||||
int width, int height, int interleaved,
|
||||
const struct bttv_tvnorm *tvnorm)
|
||||
{
|
||||
const struct bttv_tvnorm *tvnorm = &bttv_tvnorms[norm];
|
||||
u32 xsf, sr;
|
||||
int vdelay;
|
||||
|
||||
@ -360,6 +369,62 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bttv_calc_geo (struct bttv * btv,
|
||||
struct bttv_geometry * geo,
|
||||
unsigned int width,
|
||||
unsigned int height,
|
||||
int both_fields,
|
||||
const struct bttv_tvnorm * tvnorm,
|
||||
const struct v4l2_rect * crop)
|
||||
{
|
||||
unsigned int c_width;
|
||||
unsigned int c_height;
|
||||
u32 sr;
|
||||
|
||||
if ((crop->left == tvnorm->cropcap.defrect.left
|
||||
&& crop->top == tvnorm->cropcap.defrect.top
|
||||
&& crop->width == tvnorm->cropcap.defrect.width
|
||||
&& crop->height == tvnorm->cropcap.defrect.height
|
||||
&& width <= tvnorm->swidth /* see PAL-Nc et al */)
|
||||
|| bttv_tvcards[btv->c.type].muxsel[btv->input] < 0) {
|
||||
bttv_calc_geo_old(btv, geo, width, height,
|
||||
both_fields, tvnorm);
|
||||
return;
|
||||
}
|
||||
|
||||
/* For bug compatibility the image size checks permit scale
|
||||
factors > 16. See bttv_crop_calc_limits(). */
|
||||
c_width = min((unsigned int) crop->width, width * 16);
|
||||
c_height = min((unsigned int) crop->height, height * 16);
|
||||
|
||||
geo->width = width;
|
||||
geo->hscale = (c_width * 4096U + (width >> 1)) / width - 4096;
|
||||
/* Even to store Cb first, odd for Cr. */
|
||||
geo->hdelay = ((crop->left * width + c_width) / c_width) & ~1;
|
||||
|
||||
geo->sheight = c_height;
|
||||
geo->vdelay = crop->top - tvnorm->cropcap.bounds.top + MIN_VDELAY;
|
||||
sr = c_height >> !both_fields;
|
||||
sr = (sr * 512U + (height >> 1)) / height - 512;
|
||||
geo->vscale = (0x10000UL - sr) & 0x1fff;
|
||||
geo->vscale |= both_fields ? (BT848_VSCALE_INT << 8) : 0;
|
||||
geo->vtotal = tvnorm->vtotal;
|
||||
|
||||
geo->crop = (((geo->width >> 8) & 0x03) |
|
||||
((geo->hdelay >> 6) & 0x0c) |
|
||||
((geo->sheight >> 4) & 0x30) |
|
||||
((geo->vdelay >> 2) & 0xc0));
|
||||
|
||||
if (btv->opt_combfilter) {
|
||||
geo->vtc = (width < 193) ? 2 : ((width < 385) ? 1 : 0);
|
||||
geo->comb = (width < 769) ? 1 : 0;
|
||||
} else {
|
||||
geo->vtc = 0;
|
||||
geo->comb = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
bttv_apply_geo(struct bttv *btv, struct bttv_geometry *geo, int odd)
|
||||
{
|
||||
@ -522,16 +587,51 @@ int
|
||||
bttv_buffer_activate_vbi(struct bttv *btv,
|
||||
struct bttv_buffer *vbi)
|
||||
{
|
||||
/* vbi capture */
|
||||
struct btcx_riscmem *top;
|
||||
struct btcx_riscmem *bottom;
|
||||
int top_irq_flags;
|
||||
int bottom_irq_flags;
|
||||
|
||||
top = NULL;
|
||||
bottom = NULL;
|
||||
top_irq_flags = 0;
|
||||
bottom_irq_flags = 0;
|
||||
|
||||
if (vbi) {
|
||||
unsigned int crop, vdelay;
|
||||
|
||||
vbi->vb.state = STATE_ACTIVE;
|
||||
list_del(&vbi->vb.queue);
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_VBI, &vbi->top, 0);
|
||||
bttv_risc_hook(btv, RISC_SLOT_E_VBI, &vbi->bottom, 4);
|
||||
} else {
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_VBI, NULL, 0);
|
||||
bttv_risc_hook(btv, RISC_SLOT_E_VBI, NULL, 0);
|
||||
|
||||
/* VDELAY is start of video, end of VBI capturing. */
|
||||
crop = btread(BT848_E_CROP);
|
||||
vdelay = btread(BT848_E_VDELAY_LO) + ((crop & 0xc0) << 2);
|
||||
|
||||
if (vbi->geo.vdelay > vdelay) {
|
||||
vdelay = vbi->geo.vdelay & 0xfe;
|
||||
crop = (crop & 0x3f) | ((vbi->geo.vdelay >> 2) & 0xc0);
|
||||
|
||||
btwrite(vdelay, BT848_E_VDELAY_LO);
|
||||
btwrite(crop, BT848_E_CROP);
|
||||
btwrite(vdelay, BT848_O_VDELAY_LO);
|
||||
btwrite(crop, BT848_O_CROP);
|
||||
}
|
||||
|
||||
if (vbi->vbi_count[0] > 0) {
|
||||
top = &vbi->top;
|
||||
top_irq_flags = 4;
|
||||
}
|
||||
|
||||
if (vbi->vbi_count[1] > 0) {
|
||||
top_irq_flags = 0;
|
||||
bottom = &vbi->bottom;
|
||||
bottom_irq_flags = 4;
|
||||
}
|
||||
}
|
||||
|
||||
bttv_risc_hook(btv, RISC_SLOT_O_VBI, top, top_irq_flags);
|
||||
bttv_risc_hook(btv, RISC_SLOT_E_VBI, bottom, bottom_irq_flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -611,28 +711,31 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
int bpf = bpl * (buf->vb.height >> 1);
|
||||
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,buf->vb.height,
|
||||
V4L2_FIELD_HAS_BOTH(buf->vb.field),buf->tvnorm);
|
||||
V4L2_FIELD_HAS_BOTH(buf->vb.field),
|
||||
tvnorm,&buf->crop);
|
||||
|
||||
switch (buf->vb.field) {
|
||||
case V4L2_FIELD_TOP:
|
||||
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
|
||||
0,bpl,0,buf->vb.height);
|
||||
/* offset */ 0,bpl,
|
||||
/* padding */ 0,/* skip_lines */ 0,
|
||||
buf->vb.height);
|
||||
break;
|
||||
case V4L2_FIELD_BOTTOM:
|
||||
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
|
||||
0,bpl,0,buf->vb.height);
|
||||
0,bpl,0,0,buf->vb.height);
|
||||
break;
|
||||
case V4L2_FIELD_INTERLACED:
|
||||
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
|
||||
0,bpl,bpl,buf->vb.height >> 1);
|
||||
0,bpl,bpl,0,buf->vb.height >> 1);
|
||||
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
|
||||
bpl,bpl,bpl,buf->vb.height >> 1);
|
||||
bpl,bpl,bpl,0,buf->vb.height >> 1);
|
||||
break;
|
||||
case V4L2_FIELD_SEQ_TB:
|
||||
bttv_risc_packed(btv,&buf->top,buf->vb.dma.sglist,
|
||||
0,bpl,0,buf->vb.height >> 1);
|
||||
0,bpl,0,0,buf->vb.height >> 1);
|
||||
bttv_risc_packed(btv,&buf->bottom,buf->vb.dma.sglist,
|
||||
bpf,bpl,0,buf->vb.height >> 1);
|
||||
bpf,bpl,0,0,buf->vb.height >> 1);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
@ -662,7 +765,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
switch (buf->vb.field) {
|
||||
case V4L2_FIELD_TOP:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,0,buf->tvnorm);
|
||||
buf->vb.height,/* both_fields */ 0,
|
||||
tvnorm,&buf->crop);
|
||||
bttv_risc_planar(btv, &buf->top, buf->vb.dma.sglist,
|
||||
0,buf->vb.width,0,buf->vb.height,
|
||||
uoffset,voffset,buf->fmt->hshift,
|
||||
@ -670,7 +774,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
break;
|
||||
case V4L2_FIELD_BOTTOM:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,0,buf->tvnorm);
|
||||
buf->vb.height,0,
|
||||
tvnorm,&buf->crop);
|
||||
bttv_risc_planar(btv, &buf->bottom, buf->vb.dma.sglist,
|
||||
0,buf->vb.width,0,buf->vb.height,
|
||||
uoffset,voffset,buf->fmt->hshift,
|
||||
@ -678,7 +783,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
break;
|
||||
case V4L2_FIELD_INTERLACED:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,1,buf->tvnorm);
|
||||
buf->vb.height,1,
|
||||
tvnorm,&buf->crop);
|
||||
lines = buf->vb.height >> 1;
|
||||
ypadding = buf->vb.width;
|
||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
||||
@ -700,7 +806,8 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
break;
|
||||
case V4L2_FIELD_SEQ_TB:
|
||||
bttv_calc_geo(btv,&buf->geo,buf->vb.width,
|
||||
buf->vb.height,1,buf->tvnorm);
|
||||
buf->vb.height,1,
|
||||
tvnorm,&buf->crop);
|
||||
lines = buf->vb.height >> 1;
|
||||
ypadding = buf->vb.width;
|
||||
cpadding = buf->vb.width >> buf->fmt->hshift;
|
||||
@ -731,11 +838,12 @@ bttv_buffer_risc(struct bttv *btv, struct bttv_buffer *buf)
|
||||
/* build risc code */
|
||||
buf->vb.field = V4L2_FIELD_SEQ_TB;
|
||||
bttv_calc_geo(btv,&buf->geo,tvnorm->swidth,tvnorm->sheight,
|
||||
1,buf->tvnorm);
|
||||
1,tvnorm,&buf->crop);
|
||||
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
|
||||
0, RAW_BPL, 0, RAW_LINES);
|
||||
/* offset */ 0, RAW_BPL, /* padding */ 0,
|
||||
/* skip_lines */ 0, RAW_LINES);
|
||||
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
|
||||
buf->vb.size/2 , RAW_BPL, 0, RAW_LINES);
|
||||
buf->vb.size/2 , RAW_BPL, 0, 0, RAW_LINES);
|
||||
}
|
||||
|
||||
/* copy format info */
|
||||
@ -761,7 +869,8 @@ bttv_overlay_risc(struct bttv *btv,
|
||||
|
||||
/* calculate geometry */
|
||||
bttv_calc_geo(btv,&buf->geo,ov->w.width,ov->w.height,
|
||||
V4L2_FIELD_HAS_BOTH(ov->field), ov->tvnorm);
|
||||
V4L2_FIELD_HAS_BOTH(ov->field),
|
||||
&bttv_tvnorms[ov->tvnorm],&buf->crop);
|
||||
|
||||
/* build risc code */
|
||||
switch (ov->field) {
|
||||
|
@ -5,6 +5,9 @@
|
||||
|
||||
(c) 2002 Gerd Knorr <kraxel@bytesex.org>
|
||||
|
||||
Copyright (C) 2005, 2006 Michael H. Schimek <mschimek@gmx.at>
|
||||
Sponsored by OPQ Systems AB
|
||||
|
||||
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
|
||||
@ -41,8 +44,15 @@
|
||||
to be about 244. */
|
||||
#define VBI_OFFSET 244
|
||||
|
||||
/* 2048 for compatibility with earlier driver versions. The driver
|
||||
really stores 1024 + tvnorm->vbipack * 4 samples per line in the
|
||||
buffer. Note tvnorm->vbipack is <= 0xFF (limit of VBIPACK_LO + HI
|
||||
is 0x1FF DWORDs) and VBI read()s store a frame counter in the last
|
||||
four bytes of the VBI image. */
|
||||
#define VBI_BPL 2048
|
||||
|
||||
/* Compatibility. */
|
||||
#define VBI_DEFLINES 16
|
||||
#define VBI_MAXLINES 32
|
||||
|
||||
static unsigned int vbibufs = 4;
|
||||
static unsigned int vbi_debug = 0;
|
||||
@ -58,21 +68,12 @@ MODULE_PARM_DESC(vbi_debug,"vbi code debug messages, default is 0 (no)");
|
||||
#define dprintk(fmt, arg...) if (vbi_debug) \
|
||||
printk(KERN_DEBUG "bttv%d/vbi: " fmt, btv->c.nr , ## arg)
|
||||
|
||||
#define IMAGE_SIZE(fmt) \
|
||||
(((fmt)->count[0] + (fmt)->count[1]) * (fmt)->samples_per_line)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
/* vbi risc code + mm */
|
||||
|
||||
static int
|
||||
vbi_buffer_risc(struct bttv *btv, struct bttv_buffer *buf, int lines)
|
||||
{
|
||||
int bpl = 2048;
|
||||
|
||||
bttv_risc_packed(btv, &buf->top, buf->vb.dma.sglist,
|
||||
0, bpl-4, 4, lines);
|
||||
bttv_risc_packed(btv, &buf->bottom, buf->vb.dma.sglist,
|
||||
lines * bpl, bpl-4, 4, lines);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vbi_buffer_setup(struct videobuf_queue *q,
|
||||
unsigned int *count, unsigned int *size)
|
||||
{
|
||||
@ -81,8 +82,16 @@ static int vbi_buffer_setup(struct videobuf_queue *q,
|
||||
|
||||
if (0 == *count)
|
||||
*count = vbibufs;
|
||||
*size = fh->lines * 2 * 2048;
|
||||
dprintk("setup: lines=%d\n",fh->lines);
|
||||
|
||||
*size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
||||
|
||||
dprintk("setup: samples=%u start=%d,%d count=%u,%u\n",
|
||||
fh->vbi_fmt.fmt.samples_per_line,
|
||||
fh->vbi_fmt.fmt.start[0],
|
||||
fh->vbi_fmt.fmt.start[1],
|
||||
fh->vbi_fmt.fmt.count[0],
|
||||
fh->vbi_fmt.fmt.count[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -93,18 +102,93 @@ static int vbi_buffer_prepare(struct videobuf_queue *q,
|
||||
struct bttv_fh *fh = q->priv_data;
|
||||
struct bttv *btv = fh->btv;
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
unsigned int skip_lines0, skip_lines1, min_vdelay;
|
||||
int redo_dma_risc;
|
||||
int rc;
|
||||
|
||||
buf->vb.size = fh->lines * 2 * 2048;
|
||||
buf->vb.size = IMAGE_SIZE(&fh->vbi_fmt.fmt);
|
||||
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
|
||||
return -EINVAL;
|
||||
|
||||
tvnorm = fh->vbi_fmt.tvnorm;
|
||||
|
||||
/* There's no VBI_VDELAY register, RISC must skip the lines
|
||||
we don't want. With default parameters we skip zero lines
|
||||
as earlier driver versions did. The driver permits video
|
||||
standard changes while capturing, so we use vbi_fmt.tvnorm
|
||||
instead of btv->tvnorm to skip zero lines after video
|
||||
standard changes as well. */
|
||||
|
||||
skip_lines0 = 0;
|
||||
skip_lines1 = 0;
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[0] > 0)
|
||||
skip_lines0 = max(0, (fh->vbi_fmt.fmt.start[0]
|
||||
- tvnorm->vbistart[0]));
|
||||
if (fh->vbi_fmt.fmt.count[1] > 0)
|
||||
skip_lines1 = max(0, (fh->vbi_fmt.fmt.start[1]
|
||||
- tvnorm->vbistart[1]));
|
||||
|
||||
redo_dma_risc = 0;
|
||||
|
||||
if (buf->vbi_skip[0] != skip_lines0 ||
|
||||
buf->vbi_skip[1] != skip_lines1 ||
|
||||
buf->vbi_count[0] != fh->vbi_fmt.fmt.count[0] ||
|
||||
buf->vbi_count[1] != fh->vbi_fmt.fmt.count[1]) {
|
||||
buf->vbi_skip[0] = skip_lines0;
|
||||
buf->vbi_skip[1] = skip_lines1;
|
||||
buf->vbi_count[0] = fh->vbi_fmt.fmt.count[0];
|
||||
buf->vbi_count[1] = fh->vbi_fmt.fmt.count[1];
|
||||
redo_dma_risc = 1;
|
||||
}
|
||||
|
||||
if (STATE_NEEDS_INIT == buf->vb.state) {
|
||||
redo_dma_risc = 1;
|
||||
if (0 != (rc = videobuf_iolock(q, &buf->vb, NULL)))
|
||||
goto fail;
|
||||
if (0 != (rc = vbi_buffer_risc(btv,buf,fh->lines)))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (redo_dma_risc) {
|
||||
unsigned int bpl, padding, offset;
|
||||
|
||||
bpl = 2044; /* max. vbipack */
|
||||
padding = VBI_BPL - bpl;
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[0] > 0) {
|
||||
rc = bttv_risc_packed(btv, &buf->top,
|
||||
buf->vb.dma.sglist,
|
||||
/* offset */ 0, bpl,
|
||||
padding, skip_lines0,
|
||||
fh->vbi_fmt.fmt.count[0]);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (fh->vbi_fmt.fmt.count[1] > 0) {
|
||||
offset = fh->vbi_fmt.fmt.count[0] * VBI_BPL;
|
||||
|
||||
rc = bttv_risc_packed(btv, &buf->bottom,
|
||||
buf->vb.dma.sglist,
|
||||
offset, bpl,
|
||||
padding, skip_lines1,
|
||||
fh->vbi_fmt.fmt.count[1]);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* VBI capturing ends at VDELAY, start of video capturing,
|
||||
no matter where the RISC program ends. VDELAY minimum is 2,
|
||||
bounds.top is the corresponding first field line number
|
||||
times two. VDELAY counts half field lines. */
|
||||
min_vdelay = MIN_VDELAY;
|
||||
if (fh->vbi_fmt.end >= tvnorm->cropcap.bounds.top)
|
||||
min_vdelay += fh->vbi_fmt.end - tvnorm->cropcap.bounds.top;
|
||||
|
||||
/* For bttv_buffer_activate_vbi(). */
|
||||
buf->geo.vdelay = min_vdelay;
|
||||
|
||||
buf->vb.state = STATE_PREPARED;
|
||||
buf->vb.field = field;
|
||||
dprintk("buf prepare %p: top=%p bottom=%p field=%s\n",
|
||||
@ -140,7 +224,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer
|
||||
struct bttv_buffer *buf = container_of(vb,struct bttv_buffer,vb);
|
||||
|
||||
dprintk("free %p\n",vb);
|
||||
bttv_dma_free(&fh->cap,fh->btv,buf);
|
||||
bttv_dma_free(q,fh->btv,buf);
|
||||
}
|
||||
|
||||
struct videobuf_queue_ops bttv_vbi_qops = {
|
||||
@ -152,69 +236,215 @@ struct videobuf_queue_ops bttv_vbi_qops = {
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines)
|
||||
static int
|
||||
try_fmt (struct v4l2_vbi_format * f,
|
||||
const struct bttv_tvnorm * tvnorm,
|
||||
__s32 crop_start)
|
||||
{
|
||||
int vdelay;
|
||||
__s32 min_start, max_start, max_end, f2_offset;
|
||||
unsigned int i;
|
||||
|
||||
if (lines < 1)
|
||||
lines = 1;
|
||||
if (lines > VBI_MAXLINES)
|
||||
lines = VBI_MAXLINES;
|
||||
fh->lines = lines;
|
||||
/* For compatibility with earlier driver versions we must pretend
|
||||
the VBI and video capture window may overlap. In reality RISC
|
||||
magic aborts VBI capturing at the first line of video capturing,
|
||||
leaving the rest of the buffer unchanged, usually all zero.
|
||||
VBI capturing must always start before video capturing. >> 1
|
||||
because cropping counts field lines times two. */
|
||||
min_start = tvnorm->vbistart[0];
|
||||
max_start = (crop_start >> 1) - 1;
|
||||
max_end = (tvnorm->cropcap.bounds.top
|
||||
+ tvnorm->cropcap.bounds.height) >> 1;
|
||||
|
||||
vdelay = btread(BT848_E_VDELAY_LO);
|
||||
if (vdelay < lines*2) {
|
||||
vdelay = lines*2;
|
||||
btwrite(vdelay,BT848_E_VDELAY_LO);
|
||||
btwrite(vdelay,BT848_O_VDELAY_LO);
|
||||
if (min_start > max_start)
|
||||
return -EBUSY;
|
||||
|
||||
BUG_ON(max_start >= max_end);
|
||||
|
||||
f->sampling_rate = tvnorm->Fsc;
|
||||
f->samples_per_line = VBI_BPL;
|
||||
f->sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->offset = VBI_OFFSET;
|
||||
|
||||
f2_offset = tvnorm->vbistart[1] - tvnorm->vbistart[0];
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
if (0 == f->count[i]) {
|
||||
/* No data from this field. We leave f->start[i]
|
||||
alone because VIDIOCSVBIFMT is w/o and EINVALs
|
||||
when a driver does not support exactly the
|
||||
requested parameters. */
|
||||
} else {
|
||||
s64 start, count;
|
||||
|
||||
start = clamp(f->start[i], min_start, max_start);
|
||||
/* s64 to prevent overflow. */
|
||||
count = (s64) f->start[i] + f->count[i] - start;
|
||||
f->start[i] = start;
|
||||
f->count[i] = clamp(count, (s64) 1,
|
||||
max_end - start);
|
||||
}
|
||||
|
||||
min_start += f2_offset;
|
||||
max_start += f2_offset;
|
||||
max_end += f2_offset;
|
||||
}
|
||||
|
||||
if (0 == (f->count[0] | f->count[1])) {
|
||||
/* As in earlier driver versions. */
|
||||
f->start[0] = tvnorm->vbistart[0];
|
||||
f->start[1] = tvnorm->vbistart[1];
|
||||
f->count[0] = 1;
|
||||
f->count[1] = 1;
|
||||
}
|
||||
|
||||
f->flags = 0;
|
||||
|
||||
f->reserved[0] = 0;
|
||||
f->reserved[1] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
bttv_vbi_try_fmt (struct bttv_fh * fh,
|
||||
struct v4l2_vbi_format * f)
|
||||
{
|
||||
struct bttv *btv = fh->btv;
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
__s32 crop_start;
|
||||
|
||||
mutex_lock(&btv->lock);
|
||||
|
||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
||||
crop_start = btv->crop_start;
|
||||
|
||||
mutex_unlock(&btv->lock);
|
||||
|
||||
return try_fmt(f, tvnorm, crop_start);
|
||||
}
|
||||
|
||||
int
|
||||
bttv_vbi_set_fmt (struct bttv_fh * fh,
|
||||
struct v4l2_vbi_format * f)
|
||||
{
|
||||
struct bttv *btv = fh->btv;
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
__s32 start1, end;
|
||||
int rc;
|
||||
|
||||
mutex_lock(&btv->lock);
|
||||
|
||||
rc = -EBUSY;
|
||||
if (fh->resources & RESOURCE_VBI)
|
||||
goto fail;
|
||||
|
||||
tvnorm = &bttv_tvnorms[btv->tvnorm];
|
||||
|
||||
rc = try_fmt(f, tvnorm, btv->crop_start);
|
||||
if (0 != rc)
|
||||
goto fail;
|
||||
|
||||
start1 = f->start[1] - tvnorm->vbistart[1] + tvnorm->vbistart[0];
|
||||
|
||||
/* First possible line of video capturing. Should be
|
||||
max(f->start[0] + f->count[0], start1 + f->count[1]) * 2
|
||||
when capturing both fields. But for compatibility we must
|
||||
pretend the VBI and video capture window may overlap,
|
||||
so end = start + 1, the lowest possible value, times two
|
||||
because vbi_fmt.end counts field lines times two. */
|
||||
end = max(f->start[0], start1) * 2 + 2;
|
||||
|
||||
mutex_lock(&fh->vbi.lock);
|
||||
|
||||
fh->vbi_fmt.fmt = *f;
|
||||
fh->vbi_fmt.tvnorm = tvnorm;
|
||||
fh->vbi_fmt.end = end;
|
||||
|
||||
mutex_unlock(&fh->vbi.lock);
|
||||
|
||||
rc = 0;
|
||||
|
||||
fail:
|
||||
mutex_unlock(&btv->lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void
|
||||
bttv_vbi_get_fmt (struct bttv_fh * fh,
|
||||
struct v4l2_vbi_format * f)
|
||||
{
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
|
||||
*f = fh->vbi_fmt.fmt;
|
||||
|
||||
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
|
||||
|
||||
if (tvnorm != fh->vbi_fmt.tvnorm) {
|
||||
__s32 max_end;
|
||||
unsigned int i;
|
||||
|
||||
/* As in vbi_buffer_prepare() this imitates the
|
||||
behaviour of earlier driver versions after video
|
||||
standard changes, with default parameters anyway. */
|
||||
|
||||
max_end = (tvnorm->cropcap.bounds.top
|
||||
+ tvnorm->cropcap.bounds.height) >> 1;
|
||||
|
||||
f->sampling_rate = tvnorm->Fsc;
|
||||
|
||||
for (i = 0; i < 2; ++i) {
|
||||
__s32 new_start;
|
||||
|
||||
new_start = f->start[i]
|
||||
+ tvnorm->vbistart[i]
|
||||
- fh->vbi_fmt.tvnorm->vbistart[i];
|
||||
|
||||
f->start[i] = min(new_start, max_end - 1);
|
||||
f->count[i] = min((__s32) f->count[i],
|
||||
max_end - f->start[i]);
|
||||
|
||||
max_end += tvnorm->vbistart[1]
|
||||
- tvnorm->vbistart[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f)
|
||||
void
|
||||
bttv_vbi_fmt_reset (struct bttv_vbi_fmt * f,
|
||||
int norm)
|
||||
{
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
s64 count0,count1,count;
|
||||
unsigned int real_samples_per_line;
|
||||
unsigned int real_count;
|
||||
|
||||
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
|
||||
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
||||
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
|
||||
f->fmt.vbi.samples_per_line = 2048;
|
||||
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->fmt.vbi.offset = VBI_OFFSET;
|
||||
f->fmt.vbi.flags = 0;
|
||||
tvnorm = &bttv_tvnorms[norm];
|
||||
|
||||
/* s64 to prevent overflow. */
|
||||
count0 = (s64) f->fmt.vbi.start[0] + f->fmt.vbi.count[0]
|
||||
- tvnorm->vbistart[0];
|
||||
count1 = (s64) f->fmt.vbi.start[1] + f->fmt.vbi.count[1]
|
||||
- tvnorm->vbistart[1];
|
||||
count = clamp (max (count0, count1), (s64) 1, (s64) VBI_MAXLINES);
|
||||
f->fmt.sampling_rate = tvnorm->Fsc;
|
||||
f->fmt.samples_per_line = VBI_BPL;
|
||||
f->fmt.sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->fmt.offset = VBI_OFFSET;
|
||||
f->fmt.start[0] = tvnorm->vbistart[0];
|
||||
f->fmt.start[1] = tvnorm->vbistart[1];
|
||||
f->fmt.count[0] = VBI_DEFLINES;
|
||||
f->fmt.count[1] = VBI_DEFLINES;
|
||||
f->fmt.flags = 0;
|
||||
f->fmt.reserved[0] = 0;
|
||||
f->fmt.reserved[1] = 0;
|
||||
|
||||
f->fmt.vbi.start[0] = tvnorm->vbistart[0];
|
||||
f->fmt.vbi.start[1] = tvnorm->vbistart[1];
|
||||
f->fmt.vbi.count[0] = count;
|
||||
f->fmt.vbi.count[1] = count;
|
||||
/* For compatibility the buffer size must be 2 * VBI_DEFLINES *
|
||||
VBI_BPL regardless of the current video standard. */
|
||||
real_samples_per_line = 1024 + tvnorm->vbipack * 4;
|
||||
real_count = ((tvnorm->cropcap.defrect.top >> 1)
|
||||
- tvnorm->vbistart[0]);
|
||||
|
||||
f->fmt.vbi.reserved[0] = 0;
|
||||
f->fmt.vbi.reserved[1] = 0;
|
||||
}
|
||||
BUG_ON(real_samples_per_line > VBI_BPL);
|
||||
BUG_ON(real_count > VBI_DEFLINES);
|
||||
|
||||
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f)
|
||||
{
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
f->tvnorm = tvnorm;
|
||||
|
||||
tvnorm = &bttv_tvnorms[fh->btv->tvnorm];
|
||||
memset(f,0,sizeof(*f));
|
||||
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
|
||||
f->fmt.vbi.sampling_rate = tvnorm->Fsc;
|
||||
f->fmt.vbi.samples_per_line = 2048;
|
||||
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
f->fmt.vbi.offset = VBI_OFFSET;
|
||||
f->fmt.vbi.start[0] = tvnorm->vbistart[0];
|
||||
f->fmt.vbi.start[1] = tvnorm->vbistart[1];
|
||||
f->fmt.vbi.count[0] = fh->lines;
|
||||
f->fmt.vbi.count[1] = fh->lines;
|
||||
f->fmt.vbi.flags = 0;
|
||||
/* See bttv_vbi_fmt_set(). */
|
||||
f->end = tvnorm->vbistart[0] * 2 + 2;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
@ -197,33 +197,6 @@ struct bttv_core {
|
||||
struct bttv;
|
||||
|
||||
|
||||
struct bttv_ir {
|
||||
struct input_dev *dev;
|
||||
struct ir_input_state ir;
|
||||
char name[32];
|
||||
char phys[32];
|
||||
|
||||
/* Usual gpio signalling */
|
||||
|
||||
u32 mask_keycode;
|
||||
u32 mask_keydown;
|
||||
u32 mask_keyup;
|
||||
u32 polling;
|
||||
u32 last_gpio;
|
||||
struct work_struct work;
|
||||
struct timer_list timer;
|
||||
|
||||
/* RC5 gpio */
|
||||
u32 rc5_gpio;
|
||||
struct timer_list timer_end; /* timer_end for code completion */
|
||||
struct timer_list timer_keyup; /* timer_end for key release */
|
||||
u32 last_rc5; /* last good rc5 code */
|
||||
u32 last_bit; /* last raw bit seen */
|
||||
u32 code; /* raw code under construction */
|
||||
struct timeval base_time; /* time of last seen code */
|
||||
int active; /* building raw code */
|
||||
};
|
||||
|
||||
struct tvcard
|
||||
{
|
||||
char *name;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define _BTTVP_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,16)
|
||||
#define BTTV_VERSION_CODE KERNEL_VERSION(0,9,17)
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/wait.h>
|
||||
@ -66,14 +66,22 @@
|
||||
#define RISC_SLOT_LOOP 14
|
||||
|
||||
#define RESOURCE_OVERLAY 1
|
||||
#define RESOURCE_VIDEO 2
|
||||
#define RESOURCE_VIDEO_STREAM 2
|
||||
#define RESOURCE_VBI 4
|
||||
#define RESOURCE_VIDEO_READ 8
|
||||
|
||||
#define RAW_LINES 640
|
||||
#define RAW_BPL 1024
|
||||
|
||||
#define UNSET (-1U)
|
||||
|
||||
/* Min. value in VDELAY register. */
|
||||
#define MIN_VDELAY 2
|
||||
/* Even to get Cb first, odd for Cr. */
|
||||
#define MAX_HDELAY (0x3FF & -2)
|
||||
/* Limits scaled width, which must be a multiple of 4. */
|
||||
#define MAX_HACTIVE (0x3FF & -4)
|
||||
|
||||
#define clamp(x, low, high) min (max (low, x), high)
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
@ -92,8 +100,13 @@ struct bttv_tvnorm {
|
||||
u16 vtotal;
|
||||
int sram;
|
||||
/* ITU-R frame line number of the first VBI line we can
|
||||
capture, of the first and second field. */
|
||||
capture, of the first and second field. The last possible line
|
||||
is determined by cropcap.bounds. */
|
||||
u16 vbistart[2];
|
||||
/* Horizontally this counts fCLKx1 samples following the leading
|
||||
edge of the horizontal sync pulse, vertically ITU-R frame line
|
||||
numbers of the first field times two (2, 4, 6, ... 524 or 624). */
|
||||
struct v4l2_cropcap cropcap;
|
||||
};
|
||||
extern const struct bttv_tvnorm bttv_tvnorms[];
|
||||
|
||||
@ -128,6 +141,9 @@ struct bttv_buffer {
|
||||
struct bttv_geometry geo;
|
||||
struct btcx_riscmem top;
|
||||
struct btcx_riscmem bottom;
|
||||
struct v4l2_rect crop;
|
||||
unsigned int vbi_skip[2];
|
||||
unsigned int vbi_count[2];
|
||||
};
|
||||
|
||||
struct bttv_buffer_set {
|
||||
@ -146,6 +162,34 @@ struct bttv_overlay {
|
||||
int setup_ok;
|
||||
};
|
||||
|
||||
struct bttv_vbi_fmt {
|
||||
struct v4l2_vbi_format fmt;
|
||||
|
||||
/* fmt.start[] and count[] refer to this video standard. */
|
||||
const struct bttv_tvnorm *tvnorm;
|
||||
|
||||
/* Earliest possible start of video capturing with this
|
||||
v4l2_vbi_format, in struct bttv_crop.rect units. */
|
||||
__s32 end;
|
||||
};
|
||||
|
||||
/* bttv-vbi.c */
|
||||
void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, int norm);
|
||||
|
||||
struct bttv_crop {
|
||||
/* A cropping rectangle in struct bttv_tvnorm.cropcap units. */
|
||||
struct v4l2_rect rect;
|
||||
|
||||
/* Scaled image size limits with this crop rect. Divide
|
||||
max_height, but not min_height, by two when capturing
|
||||
single fields. See also bttv_crop_reset() and
|
||||
bttv_crop_adjust() in bttv-driver.c. */
|
||||
__s32 min_scaled_width;
|
||||
__s32 min_scaled_height;
|
||||
__s32 max_scaled_width;
|
||||
__s32 max_scaled_height;
|
||||
};
|
||||
|
||||
struct bttv_fh {
|
||||
struct bttv *btv;
|
||||
int resources;
|
||||
@ -160,13 +204,19 @@ struct bttv_fh {
|
||||
int width;
|
||||
int height;
|
||||
|
||||
/* current settings */
|
||||
/* video overlay */
|
||||
const struct bttv_format *ovfmt;
|
||||
struct bttv_overlay ov;
|
||||
|
||||
/* video overlay */
|
||||
/* Application called VIDIOC_S_CROP. */
|
||||
int do_crop;
|
||||
|
||||
/* vbi capture */
|
||||
struct videobuf_queue vbi;
|
||||
int lines;
|
||||
/* Current VBI capture window as seen through this fh (cannot
|
||||
be global for compatibility with earlier drivers). Protected
|
||||
by struct bttv.lock and struct bttv_fh.vbi.lock. */
|
||||
struct bttv_vbi_fmt vbi_fmt;
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
@ -176,7 +226,8 @@ struct bttv_fh {
|
||||
int bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
|
||||
struct scatterlist *sglist,
|
||||
unsigned int offset, unsigned int bpl,
|
||||
unsigned int pitch, unsigned int lines);
|
||||
unsigned int pitch, unsigned int skip_lines,
|
||||
unsigned int store_lines);
|
||||
|
||||
/* control dma register + risc main loop */
|
||||
void bttv_set_dma(struct bttv *btv, int override);
|
||||
@ -202,9 +253,9 @@ int bttv_overlay_risc(struct bttv *btv, struct bttv_overlay *ov,
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-vbi.c */
|
||||
|
||||
void bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_format *f);
|
||||
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_format *f);
|
||||
void bttv_vbi_setlines(struct bttv_fh *fh, struct bttv *btv, int lines);
|
||||
int bttv_vbi_try_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
|
||||
void bttv_vbi_get_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
|
||||
int bttv_vbi_set_fmt(struct bttv_fh *fh, struct v4l2_vbi_format *f);
|
||||
|
||||
extern struct videobuf_queue_ops bttv_vbi_qops;
|
||||
|
||||
@ -233,7 +284,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
|
||||
#define d2printk if (bttv_debug >= 2) printk
|
||||
|
||||
#define BTTV_MAX_FBUF 0x208000
|
||||
#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
|
||||
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
|
||||
#define BTTV_FREE_IDLE (HZ) /* one second */
|
||||
|
||||
@ -308,13 +358,12 @@ struct bttv {
|
||||
|
||||
/* infrared remote */
|
||||
int has_remote;
|
||||
struct bttv_ir *remote;
|
||||
struct card_ir *remote;
|
||||
|
||||
/* locking */
|
||||
spinlock_t s_lock;
|
||||
struct mutex lock;
|
||||
int resources;
|
||||
struct mutex reslock;
|
||||
#ifdef VIDIOC_G_PRIORITY
|
||||
struct v4l2_prio_state prio;
|
||||
#endif
|
||||
@ -384,6 +433,21 @@ struct bttv {
|
||||
|
||||
unsigned int users;
|
||||
struct bttv_fh init;
|
||||
|
||||
/* Default (0) and current (1) video capturing and overlay
|
||||
cropping parameters in bttv_tvnorm.cropcap units. Protected
|
||||
by bttv.lock. */
|
||||
struct bttv_crop crop[2];
|
||||
|
||||
/* Earliest possible start of video capturing in
|
||||
bttv_tvnorm.cropcap line units. Set by check_alloc_btres()
|
||||
and free_btres(). Protected by bttv.lock. */
|
||||
__s32 vbi_end;
|
||||
|
||||
/* Latest possible end of VBI capturing (= crop[x].rect.top when
|
||||
VIDEO_RESOURCES are locked). Set by check_alloc_btres()
|
||||
and free_btres(). Protected by bttv.lock. */
|
||||
__s32 crop_start;
|
||||
};
|
||||
|
||||
/* our devices */
|
||||
|
@ -1195,7 +1195,7 @@ static int cafe_vidioc_reqbufs(struct file *filp, void *priv,
|
||||
struct v4l2_requestbuffers *req)
|
||||
{
|
||||
struct cafe_camera *cam = filp->private_data;
|
||||
int ret;
|
||||
int ret = 0; /* Silence warning */
|
||||
|
||||
/*
|
||||
* Make sure it's something we can do. User pointers could be
|
||||
|
@ -1350,13 +1350,13 @@ static int cpia_write_proc(struct file *file, const char __user *buf,
|
||||
|
||||
static void create_proc_cpia_cam(struct cam_data *cam)
|
||||
{
|
||||
char name[7];
|
||||
char name[5 + 1 + 10 + 1];
|
||||
struct proc_dir_entry *ent;
|
||||
|
||||
if (!cpia_proc_root || !cam)
|
||||
return;
|
||||
|
||||
sprintf(name, "video%d", cam->vdev.minor);
|
||||
snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
|
||||
|
||||
ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
|
||||
if (!ent)
|
||||
@ -1376,12 +1376,12 @@ static void create_proc_cpia_cam(struct cam_data *cam)
|
||||
|
||||
static void destroy_proc_cpia_cam(struct cam_data *cam)
|
||||
{
|
||||
char name[7];
|
||||
char name[5 + 1 + 10 + 1];
|
||||
|
||||
if (!cam || !cam->proc_entry)
|
||||
return;
|
||||
|
||||
sprintf(name, "video%d", cam->vdev.minor);
|
||||
snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
|
||||
remove_proc_entry(name, cpia_proc_root);
|
||||
cam->proc_entry = NULL;
|
||||
}
|
||||
@ -3153,8 +3153,7 @@ static int reset_camera(struct cam_data *cam)
|
||||
|
||||
static void put_cam(struct cpia_camera_ops* ops)
|
||||
{
|
||||
if (ops->owner)
|
||||
module_put(ops->owner);
|
||||
module_put(ops->owner);
|
||||
}
|
||||
|
||||
/* ------------------------- V4L interface --------------------- */
|
||||
|
@ -56,7 +56,6 @@ const u32 cx2341x_mpeg_ctrls[] = {
|
||||
V4L2_CID_MPEG_VIDEO_B_FRAMES,
|
||||
V4L2_CID_MPEG_VIDEO_GOP_SIZE,
|
||||
V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
|
||||
V4L2_CID_MPEG_VIDEO_PULLDOWN,
|
||||
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
|
||||
V4L2_CID_MPEG_VIDEO_BITRATE,
|
||||
V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
|
||||
@ -118,9 +117,6 @@ static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
|
||||
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
|
||||
ctrl->value = params->video_gop_closure;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_PULLDOWN:
|
||||
ctrl->value = params->video_pulldown;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
|
||||
ctrl->value = params->video_bitrate_mode;
|
||||
break;
|
||||
@ -231,9 +227,6 @@ static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
|
||||
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
|
||||
params->video_gop_closure = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_PULLDOWN:
|
||||
params->video_pulldown = ctrl->value;
|
||||
break;
|
||||
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
|
||||
/* MPEG-1 only allows CBR */
|
||||
if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1 &&
|
||||
@ -679,7 +672,6 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
|
||||
.video_b_frames = 2,
|
||||
.video_gop_size = 12,
|
||||
.video_gop_closure = 1,
|
||||
.video_pulldown = 0,
|
||||
.video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
|
||||
.video_bitrate = 6000000,
|
||||
.video_bitrate_peak = 8000000,
|
||||
@ -783,10 +775,6 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
|
||||
err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure);
|
||||
if (err) return err;
|
||||
}
|
||||
if (old == NULL || old->video_pulldown != new->video_pulldown) {
|
||||
err = cx2341x_api(priv, func, CX2341X_ENC_SET_3_2_PULLDOWN, 1, new->video_pulldown);
|
||||
if (err) return err;
|
||||
}
|
||||
if (old == NULL || old->audio_properties != new->audio_properties) {
|
||||
err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties);
|
||||
if (err) return err;
|
||||
@ -888,11 +876,10 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
|
||||
printk(", Peak %d", p->video_bitrate_peak);
|
||||
}
|
||||
printk("\n");
|
||||
printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
|
||||
printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n",
|
||||
prefix,
|
||||
p->video_gop_size, p->video_b_frames,
|
||||
p->video_gop_closure ? "" : "No ",
|
||||
p->video_pulldown ? "" : "No ");
|
||||
p->video_gop_closure ? "" : "No ");
|
||||
if (p->video_temporal_decimation) {
|
||||
printk(KERN_INFO "%s: Video: Temporal Decimation %d\n",
|
||||
prefix, p->video_temporal_decimation);
|
||||
|
@ -628,17 +628,8 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
/* ioctls to allow direct access to the
|
||||
* cx25840 registers for testing */
|
||||
case VIDIOC_INT_G_REGISTER:
|
||||
{
|
||||
struct v4l2_register *reg = arg;
|
||||
|
||||
if (reg->i2c_id != I2C_DRIVERID_CX25840)
|
||||
return -EINVAL;
|
||||
reg->val = cx25840_read(client, reg->reg & 0x0fff);
|
||||
break;
|
||||
}
|
||||
|
||||
case VIDIOC_INT_S_REGISTER:
|
||||
case VIDIOC_DBG_G_REGISTER:
|
||||
case VIDIOC_DBG_S_REGISTER:
|
||||
{
|
||||
struct v4l2_register *reg = arg;
|
||||
|
||||
@ -646,7 +637,10 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
|
||||
if (cmd == VIDIOC_DBG_G_REGISTER)
|
||||
reg->val = cx25840_read(client, reg->reg & 0x0fff);
|
||||
else
|
||||
cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -893,9 +887,11 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note: revision '(device_id & 0x0f) == 2' was never built. The
|
||||
marking skips from 0x1 == 22 to 0x3 == 23. */
|
||||
v4l_info(client, "cx25%3x-2%x found @ 0x%x (%s)\n",
|
||||
(device_id & 0xfff0) >> 4,
|
||||
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
|
||||
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : (device_id & 0x0f),
|
||||
address << 1, adapter->name);
|
||||
|
||||
i2c_set_clientdata(client, state);
|
||||
|
@ -12,8 +12,3 @@ obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
|
||||
EXTRA_CFLAGS += -Idrivers/media/video
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
|
||||
|
||||
extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
|
||||
extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
|
||||
|
||||
EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
|
||||
|
@ -6,6 +6,9 @@
|
||||
* (c) 2004 Jelle Foks <jelle@foks.8m.com>
|
||||
* (c) 2004 Gerd Knorr <kraxel@bytesex.org>
|
||||
*
|
||||
* (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
* - video_ioctl2 conversion
|
||||
*
|
||||
* Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -520,7 +523,7 @@ static void blackbird_codec_settings(struct cx8802_dev *dev)
|
||||
|
||||
dev->params.width = dev->width;
|
||||
dev->params.height = dev->height;
|
||||
dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
|
||||
dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0;
|
||||
|
||||
cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
|
||||
}
|
||||
@ -710,8 +713,13 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qmenu)
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* IOCTL Handlers */
|
||||
|
||||
static int vidioc_querymenu (struct file *file, void *priv,
|
||||
struct v4l2_querymenu *qmenu)
|
||||
{
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
struct v4l2_queryctrl qctrl;
|
||||
|
||||
qctrl.id = qmenu->id;
|
||||
@ -719,221 +727,347 @@ static int blackbird_querymenu(struct cx8802_dev *dev, struct v4l2_querymenu *qm
|
||||
return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static int mpeg_do_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg)
|
||||
static int vidioc_querycap (struct file *file, void *priv,
|
||||
struct v4l2_capability *cap)
|
||||
{
|
||||
struct cx8802_fh *fh = file->private_data;
|
||||
struct cx8802_dev *dev = fh->dev;
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
if (debug > 1)
|
||||
v4l_print_ioctl(core->name,cmd);
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
/* --- capabilities ------------------------------------------ */
|
||||
case VIDIOC_QUERYCAP:
|
||||
{
|
||||
struct v4l2_capability *cap = arg;
|
||||
|
||||
memset(cap,0,sizeof(*cap));
|
||||
strcpy(cap->driver, "cx88_blackbird");
|
||||
strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
|
||||
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
|
||||
cap->version = CX88_VERSION_CODE;
|
||||
cap->capabilities =
|
||||
V4L2_CAP_VIDEO_CAPTURE |
|
||||
V4L2_CAP_READWRITE |
|
||||
V4L2_CAP_STREAMING |
|
||||
0;
|
||||
if (UNSET != core->tuner_type)
|
||||
cap->capabilities |= V4L2_CAP_TUNER;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- capture ioctls ---------------------------------------- */
|
||||
case VIDIOC_ENUM_FMT:
|
||||
{
|
||||
struct v4l2_fmtdesc *f = arg;
|
||||
int index;
|
||||
|
||||
index = f->index;
|
||||
if (index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
memset(f,0,sizeof(*f));
|
||||
f->index = index;
|
||||
strlcpy(f->description, "MPEG", sizeof(f->description));
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_G_FMT:
|
||||
{
|
||||
struct v4l2_format *f = arg;
|
||||
|
||||
memset(f,0,sizeof(*f));
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
|
||||
f->fmt.pix.colorspace = 0;
|
||||
f->fmt.pix.width = dev->width;
|
||||
f->fmt.pix.height = dev->height;
|
||||
f->fmt.pix.field = fh->mpegq.field;
|
||||
dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
|
||||
dev->width, dev->height, fh->mpegq.field );
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_TRY_FMT:
|
||||
{
|
||||
struct v4l2_format *f = arg;
|
||||
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
|
||||
dev->width, dev->height, fh->mpegq.field );
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_FMT:
|
||||
{
|
||||
struct v4l2_format *f = arg;
|
||||
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
|
||||
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --- streaming capture ------------------------------------- */
|
||||
case VIDIOC_REQBUFS:
|
||||
return videobuf_reqbufs(&fh->mpegq, arg);
|
||||
|
||||
case VIDIOC_QUERYBUF:
|
||||
return videobuf_querybuf(&fh->mpegq, arg);
|
||||
|
||||
case VIDIOC_QBUF:
|
||||
return videobuf_qbuf(&fh->mpegq, arg);
|
||||
|
||||
case VIDIOC_DQBUF:
|
||||
return videobuf_dqbuf(&fh->mpegq, arg,
|
||||
file->f_flags & O_NONBLOCK);
|
||||
|
||||
case VIDIOC_STREAMON:
|
||||
return videobuf_streamon(&fh->mpegq);
|
||||
|
||||
case VIDIOC_STREAMOFF:
|
||||
return videobuf_streamoff(&fh->mpegq);
|
||||
|
||||
/* --- mpeg compression -------------------------------------- */
|
||||
case VIDIOC_G_MPEGCOMP:
|
||||
{
|
||||
struct v4l2_mpeg_compression *f = arg;
|
||||
|
||||
printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
|
||||
"Replace with VIDIOC_G_EXT_CTRLS!");
|
||||
memcpy(f,&default_mpeg_params,sizeof(*f));
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_S_MPEGCOMP:
|
||||
printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
|
||||
"Replace with VIDIOC_S_EXT_CTRLS!");
|
||||
return 0;
|
||||
case VIDIOC_G_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *f = arg;
|
||||
|
||||
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
|
||||
return -EINVAL;
|
||||
return cx2341x_ext_ctrls(&dev->params, f, cmd);
|
||||
}
|
||||
case VIDIOC_S_EXT_CTRLS:
|
||||
case VIDIOC_TRY_EXT_CTRLS:
|
||||
{
|
||||
struct v4l2_ext_controls *f = arg;
|
||||
struct cx2341x_mpeg_params p;
|
||||
int err;
|
||||
|
||||
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
|
||||
return -EINVAL;
|
||||
p = dev->params;
|
||||
err = cx2341x_ext_ctrls(&p, f, cmd);
|
||||
if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
|
||||
err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
|
||||
dev->params = p;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
case VIDIOC_S_FREQUENCY:
|
||||
{
|
||||
blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
|
||||
BLACKBIRD_END_NOW,
|
||||
BLACKBIRD_MPEG_CAPTURE,
|
||||
BLACKBIRD_RAW_BITS_NONE);
|
||||
|
||||
cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
|
||||
|
||||
blackbird_initialize_codec(dev);
|
||||
cx88_set_scale(dev->core, dev->width, dev->height,
|
||||
fh->mpegq.field);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_LOG_STATUS:
|
||||
{
|
||||
char name[32 + 2];
|
||||
|
||||
snprintf(name, sizeof(name), "%s/2", core->name);
|
||||
printk("%s/2: ============ START LOG STATUS ============\n",
|
||||
core->name);
|
||||
cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
|
||||
cx2341x_log_status(&dev->params, name);
|
||||
printk("%s/2: ============= END LOG STATUS =============\n",
|
||||
core->name);
|
||||
return 0;
|
||||
}
|
||||
case VIDIOC_QUERYMENU:
|
||||
return blackbird_querymenu(dev, arg);
|
||||
case VIDIOC_QUERYCTRL:
|
||||
{
|
||||
struct v4l2_queryctrl *c = arg;
|
||||
|
||||
if (blackbird_queryctrl(dev, c) == 0)
|
||||
return 0;
|
||||
return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, mpeg_do_ioctl);
|
||||
}
|
||||
|
||||
default:
|
||||
return cx88_do_ioctl(inode, file, 0, dev->core, cmd, arg, cx88_ioctl_hook);
|
||||
}
|
||||
strcpy(cap->driver, "cx88_blackbird");
|
||||
strlcpy(cap->card, cx88_boards[core->board].name,sizeof(cap->card));
|
||||
sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci));
|
||||
cap->version = CX88_VERSION_CODE;
|
||||
cap->capabilities =
|
||||
V4L2_CAP_VIDEO_CAPTURE |
|
||||
V4L2_CAP_READWRITE |
|
||||
V4L2_CAP_STREAMING;
|
||||
if (UNSET != core->tuner_type)
|
||||
cap->capabilities |= V4L2_CAP_TUNER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg);
|
||||
unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
|
||||
|
||||
static unsigned int mpeg_translate_ioctl(unsigned int cmd)
|
||||
static int vidioc_enum_fmt_cap (struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
return cmd;
|
||||
if (f->index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
strlcpy(f->description, "MPEG", sizeof(f->description));
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mpeg_ioctl(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
static int vidioc_g_fmt_cap (struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
cmd = cx88_ioctl_translator( cmd );
|
||||
return video_usercopy(inode, file, cmd, arg, cx88_ioctl_hook);
|
||||
struct cx8802_fh *fh = priv;
|
||||
struct cx8802_dev *dev = fh->dev;
|
||||
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */
|
||||
f->fmt.pix.colorspace = 0;
|
||||
f->fmt.pix.width = dev->width;
|
||||
f->fmt.pix.height = dev->height;
|
||||
f->fmt.pix.field = fh->mpegq.field;
|
||||
dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
|
||||
dev->width, dev->height, fh->mpegq.field );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_try_fmt_cap (struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
struct cx8802_dev *dev = fh->dev;
|
||||
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
|
||||
dev->width, dev->height, fh->mpegq.field );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_fmt_cap (struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
struct cx8802_dev *dev = fh->dev;
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
|
||||
f->fmt.pix.bytesperline = 0;
|
||||
f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */;
|
||||
f->fmt.pix.colorspace = 0;
|
||||
dev->width = f->fmt.pix.width;
|
||||
dev->height = f->fmt.pix.height;
|
||||
fh->mpegq.field = f->fmt.pix.field;
|
||||
cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
|
||||
blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
|
||||
f->fmt.pix.height, f->fmt.pix.width);
|
||||
dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
|
||||
f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
return (videobuf_reqbufs(&fh->mpegq, p));
|
||||
}
|
||||
|
||||
static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
return (videobuf_querybuf(&fh->mpegq, p));
|
||||
}
|
||||
|
||||
static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
return (videobuf_qbuf(&fh->mpegq, p));
|
||||
}
|
||||
|
||||
static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
return (videobuf_dqbuf(&fh->mpegq, p,
|
||||
file->f_flags & O_NONBLOCK));
|
||||
}
|
||||
|
||||
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
return videobuf_streamon(&fh->mpegq);
|
||||
}
|
||||
|
||||
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
return videobuf_streamoff(&fh->mpegq);
|
||||
}
|
||||
|
||||
static int vidioc_g_mpegcomp (struct file *file, void *fh,
|
||||
struct v4l2_mpeg_compression *f)
|
||||
{
|
||||
printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
|
||||
"Replace with VIDIOC_G_EXT_CTRLS!");
|
||||
memcpy(f,&default_mpeg_params,sizeof(*f));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_mpegcomp (struct file *file, void *fh,
|
||||
struct v4l2_mpeg_compression *f)
|
||||
{
|
||||
printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
|
||||
"Replace with VIDIOC_S_EXT_CTRLS!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_ext_ctrls (struct file *file, void *priv,
|
||||
struct v4l2_ext_controls *f)
|
||||
{
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
|
||||
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
|
||||
return -EINVAL;
|
||||
return cx2341x_ext_ctrls(&dev->params, f, VIDIOC_G_EXT_CTRLS);
|
||||
}
|
||||
|
||||
static int vidioc_s_ext_ctrls (struct file *file, void *priv,
|
||||
struct v4l2_ext_controls *f)
|
||||
{
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
struct cx2341x_mpeg_params p;
|
||||
int err;
|
||||
|
||||
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
|
||||
return -EINVAL;
|
||||
p = dev->params;
|
||||
err = cx2341x_ext_ctrls(&p, f, VIDIOC_S_EXT_CTRLS);
|
||||
if (!err) {
|
||||
err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p);
|
||||
dev->params = p;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vidioc_try_ext_ctrls (struct file *file, void *priv,
|
||||
struct v4l2_ext_controls *f)
|
||||
{
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
struct cx2341x_mpeg_params p;
|
||||
int err;
|
||||
|
||||
if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
|
||||
return -EINVAL;
|
||||
p = dev->params;
|
||||
err = cx2341x_ext_ctrls(&p, f, VIDIOC_TRY_EXT_CTRLS);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vidioc_s_frequency (struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
struct cx8802_dev *dev = fh->dev;
|
||||
struct cx88_core *core = dev->core;
|
||||
|
||||
blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
|
||||
BLACKBIRD_END_NOW,
|
||||
BLACKBIRD_MPEG_CAPTURE,
|
||||
BLACKBIRD_RAW_BITS_NONE);
|
||||
cx88_set_freq (core,f);
|
||||
blackbird_initialize_codec(dev);
|
||||
cx88_set_scale(dev->core, dev->width, dev->height,
|
||||
fh->mpegq.field);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_log_status (struct file *file, void *priv)
|
||||
{
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
struct cx88_core *core = dev->core;
|
||||
char name[32 + 2];
|
||||
|
||||
snprintf(name, sizeof(name), "%s/2", core->name);
|
||||
printk("%s/2: ============ START LOG STATUS ============\n",
|
||||
core->name);
|
||||
cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
|
||||
cx2341x_log_status(&dev->params, name);
|
||||
printk("%s/2: ============= END LOG STATUS =============\n",
|
||||
core->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_queryctrl (struct file *file, void *priv,
|
||||
struct v4l2_queryctrl *qctrl)
|
||||
{
|
||||
struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
|
||||
|
||||
if (blackbird_queryctrl(dev, qctrl) == 0)
|
||||
return 0;
|
||||
|
||||
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
|
||||
if (unlikely(qctrl->id == 0))
|
||||
return -EINVAL;
|
||||
return cx8800_ctrl_query(qctrl);
|
||||
}
|
||||
|
||||
static int vidioc_enum_input (struct file *file, void *priv,
|
||||
struct v4l2_input *i)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
return cx88_enum_input (core,i);
|
||||
}
|
||||
|
||||
static int vidioc_g_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctl)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
return
|
||||
cx88_get_control(core,ctl);
|
||||
}
|
||||
|
||||
static int vidioc_s_ctrl (struct file *file, void *priv,
|
||||
struct v4l2_control *ctl)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
return
|
||||
cx88_set_control(core,ctl);
|
||||
}
|
||||
|
||||
static int vidioc_g_frequency (struct file *file, void *priv,
|
||||
struct v4l2_frequency *f)
|
||||
{
|
||||
struct cx8802_fh *fh = priv;
|
||||
struct cx88_core *core = fh->dev->core;
|
||||
|
||||
if (unlikely(UNSET == core->tuner_type))
|
||||
return -EINVAL;
|
||||
|
||||
f->type = V4L2_TUNER_ANALOG_TV;
|
||||
f->frequency = core->freq;
|
||||
cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
|
||||
*i = core->input;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
|
||||
if (i >= 4)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&core->lock);
|
||||
cx88_newstation(core);
|
||||
cx88_video_mux(core,i);
|
||||
mutex_unlock(&core->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_g_tuner (struct file *file, void *priv,
|
||||
struct v4l2_tuner *t)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
u32 reg;
|
||||
|
||||
if (unlikely(UNSET == core->tuner_type))
|
||||
return -EINVAL;
|
||||
|
||||
strcpy(t->name, "Television");
|
||||
t->type = V4L2_TUNER_ANALOG_TV;
|
||||
t->capability = V4L2_TUNER_CAP_NORM;
|
||||
t->rangehigh = 0xffffffffUL;
|
||||
|
||||
cx88_get_stereo(core ,t);
|
||||
reg = cx_read(MO_DEVICE_STATUS);
|
||||
t->signal = (reg & (1<<5)) ? 0xffff : 0x0000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_tuner (struct file *file, void *priv,
|
||||
struct v4l2_tuner *t)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
|
||||
if (UNSET == core->tuner_type)
|
||||
return -EINVAL;
|
||||
if (0 != t->index)
|
||||
return -EINVAL;
|
||||
|
||||
cx88_set_stereo(core, t->audmode, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
|
||||
{
|
||||
struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
|
||||
|
||||
mutex_lock(&core->lock);
|
||||
cx88_set_tvnorm(core,*id);
|
||||
mutex_unlock(&core->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FIXME: cx88_ioctl_hook not implemented */
|
||||
|
||||
static int mpeg_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
int minor = iminor(inode);
|
||||
@ -1059,17 +1193,47 @@ static const struct file_operations mpeg_fops =
|
||||
.read = mpeg_read,
|
||||
.poll = mpeg_poll,
|
||||
.mmap = mpeg_mmap,
|
||||
.ioctl = mpeg_ioctl,
|
||||
.ioctl = video_ioctl2,
|
||||
.llseek = no_llseek,
|
||||
};
|
||||
|
||||
static struct video_device cx8802_mpeg_template =
|
||||
{
|
||||
.name = "cx8802",
|
||||
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
|
||||
.hardware = 0,
|
||||
.fops = &mpeg_fops,
|
||||
.minor = -1,
|
||||
.name = "cx8802",
|
||||
.type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER,
|
||||
.fops = &mpeg_fops,
|
||||
.minor = -1,
|
||||
.vidioc_querymenu = vidioc_querymenu,
|
||||
.vidioc_querycap = vidioc_querycap,
|
||||
.vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
|
||||
.vidioc_g_fmt_cap = vidioc_g_fmt_cap,
|
||||
.vidioc_try_fmt_cap = vidioc_try_fmt_cap,
|
||||
.vidioc_s_fmt_cap = vidioc_s_fmt_cap,
|
||||
.vidioc_reqbufs = vidioc_reqbufs,
|
||||
.vidioc_querybuf = vidioc_querybuf,
|
||||
.vidioc_qbuf = vidioc_qbuf,
|
||||
.vidioc_dqbuf = vidioc_dqbuf,
|
||||
.vidioc_streamon = vidioc_streamon,
|
||||
.vidioc_streamoff = vidioc_streamoff,
|
||||
.vidioc_g_mpegcomp = vidioc_g_mpegcomp,
|
||||
.vidioc_s_mpegcomp = vidioc_s_mpegcomp,
|
||||
.vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
|
||||
.vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
|
||||
.vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
|
||||
.vidioc_s_frequency = vidioc_s_frequency,
|
||||
.vidioc_log_status = vidioc_log_status,
|
||||
.vidioc_queryctrl = vidioc_queryctrl,
|
||||
.vidioc_enum_input = vidioc_enum_input,
|
||||
.vidioc_g_ctrl = vidioc_g_ctrl,
|
||||
.vidioc_s_ctrl = vidioc_s_ctrl,
|
||||
.vidioc_g_frequency = vidioc_g_frequency,
|
||||
.vidioc_g_input = vidioc_g_input,
|
||||
.vidioc_s_input = vidioc_s_input,
|
||||
.vidioc_g_tuner = vidioc_g_tuner,
|
||||
.vidioc_s_tuner = vidioc_s_tuner,
|
||||
.vidioc_s_std = vidioc_s_std,
|
||||
.tvnorms = CX88_NORMS,
|
||||
.current_norm = V4L2_STD_NTSC_M,
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
@ -1164,7 +1328,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
|
||||
cx2341x_fill_defaults(&dev->params);
|
||||
dev->params.port = CX2341X_PORT_STREAMING;
|
||||
|
||||
if (core->tvnorm->id & V4L2_STD_525_60) {
|
||||
cx8802_mpeg_template.current_norm = core->tvnorm;
|
||||
|
||||
if (core->tvnorm & V4L2_STD_525_60) {
|
||||
dev->height = 480;
|
||||
} else {
|
||||
dev->height = 576;
|
||||
@ -1178,6 +1344,11 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
|
||||
blackbird_register_video(dev);
|
||||
|
||||
/* initial device configuration: needed ? */
|
||||
mutex_lock(&dev->core->lock);
|
||||
// init_controls(core);
|
||||
cx88_set_tvnorm(core,core->tvnorm);
|
||||
cx88_video_mux(core,0);
|
||||
mutex_unlock(&dev->core->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1212,8 +1383,6 @@ static int blackbird_init(void)
|
||||
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
|
||||
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
|
||||
#endif
|
||||
cx88_ioctl_hook = mpeg_do_ioctl;
|
||||
cx88_ioctl_translator = mpeg_translate_ioctl;
|
||||
return cx8802_register_driver(&cx8802_blackbird_driver);
|
||||
}
|
||||
|
||||
@ -1225,8 +1394,8 @@ static void blackbird_fini(void)
|
||||
module_init(blackbird_init);
|
||||
module_exit(blackbird_fini);
|
||||
|
||||
EXPORT_SYMBOL(cx88_ioctl_hook);
|
||||
EXPORT_SYMBOL(cx88_ioctl_translator);
|
||||
module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
|
||||
MODULE_PARM_DESC(debug,"enable debug messages [video]");
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/*
|
||||
|
@ -764,6 +764,12 @@ struct cx88_board cx88_boards[] = {
|
||||
.input = {{
|
||||
.type = CX88_VMUX_DVB,
|
||||
.vmux = 0,
|
||||
},{
|
||||
.type = CX88_VMUX_COMPOSITE1,
|
||||
.vmux = 2,
|
||||
},{
|
||||
.type = CX88_VMUX_SVIDEO,
|
||||
.vmux = 2,
|
||||
}},
|
||||
.mpeg = CX88_MPEG_DVB,
|
||||
},
|
||||
|
@ -5,6 +5,11 @@
|
||||
*
|
||||
* (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
|
||||
*
|
||||
* (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
|
||||
* - Multituner support
|
||||
* - video_ioctl2 conversion
|
||||
* - PAL/M fixes
|
||||
*
|
||||
* 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
|
||||
@ -631,30 +636,30 @@ int cx88_reset(struct cx88_core *core)
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static unsigned int inline norm_swidth(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_swidth(v4l2_std_id norm)
|
||||
{
|
||||
return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
|
||||
return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 754 : 922;
|
||||
}
|
||||
|
||||
static unsigned int inline norm_hdelay(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_hdelay(v4l2_std_id norm)
|
||||
{
|
||||
return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
|
||||
return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 135 : 186;
|
||||
}
|
||||
|
||||
static unsigned int inline norm_vdelay(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_vdelay(v4l2_std_id norm)
|
||||
{
|
||||
return (norm->id & V4L2_STD_625_50) ? 0x24 : 0x18;
|
||||
return (norm & V4L2_STD_625_50) ? 0x24 : 0x18;
|
||||
}
|
||||
|
||||
static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_fsc8(v4l2_std_id norm)
|
||||
{
|
||||
if (norm->id & V4L2_STD_PAL_M)
|
||||
if (norm & V4L2_STD_PAL_M)
|
||||
return 28604892; // 3.575611 MHz
|
||||
|
||||
if (norm->id & (V4L2_STD_PAL_Nc))
|
||||
if (norm & (V4L2_STD_PAL_Nc))
|
||||
return 28656448; // 3.582056 MHz
|
||||
|
||||
if (norm->id & V4L2_STD_NTSC) // All NTSC/M and variants
|
||||
if (norm & V4L2_STD_NTSC) // All NTSC/M and variants
|
||||
return 28636360; // 3.57954545 MHz +/- 10 Hz
|
||||
|
||||
/* SECAM have also different sub carrier for chroma,
|
||||
@ -666,20 +671,20 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
|
||||
return 35468950; // 4.43361875 MHz +/- 5 Hz
|
||||
}
|
||||
|
||||
static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_htotal(v4l2_std_id norm)
|
||||
{
|
||||
|
||||
unsigned int fsc4=norm_fsc8(norm)/2;
|
||||
|
||||
/* returns 4*FSC / vtotal / frames per seconds */
|
||||
return (norm->id & V4L2_STD_625_50) ?
|
||||
return (norm & V4L2_STD_625_50) ?
|
||||
((fsc4+312)/625+12)/25 :
|
||||
((fsc4+262)/525*1001+15000)/30000;
|
||||
}
|
||||
|
||||
static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_vbipack(v4l2_std_id norm)
|
||||
{
|
||||
return (norm->id & V4L2_STD_625_50) ? 511 : 400;
|
||||
return (norm & V4L2_STD_625_50) ? 511 : 400;
|
||||
}
|
||||
|
||||
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
|
||||
@ -692,7 +697,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
|
||||
dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height,
|
||||
V4L2_FIELD_HAS_TOP(field) ? "T" : "",
|
||||
V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "",
|
||||
core->tvnorm->name);
|
||||
v4l2_norm_to_name(core->tvnorm));
|
||||
if (!V4L2_FIELD_HAS_BOTH(field))
|
||||
height *= 2;
|
||||
|
||||
@ -729,7 +734,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig
|
||||
// setup filters
|
||||
value = 0;
|
||||
value |= (1 << 19); // CFILT (default)
|
||||
if (core->tvnorm->id & V4L2_STD_SECAM) {
|
||||
if (core->tvnorm & V4L2_STD_SECAM) {
|
||||
value |= (1 << 15);
|
||||
value |= (1 << 16);
|
||||
}
|
||||
@ -826,36 +831,36 @@ int cx88_stop_audio_dma(struct cx88_core *core)
|
||||
|
||||
static int set_tvaudio(struct cx88_core *core)
|
||||
{
|
||||
struct cx88_tvnorm *norm = core->tvnorm;
|
||||
v4l2_std_id norm = core->tvnorm;
|
||||
|
||||
if (CX88_VMUX_TELEVISION != INPUT(core->input)->type)
|
||||
return 0;
|
||||
|
||||
if (V4L2_STD_PAL_BG & norm->id) {
|
||||
if (V4L2_STD_PAL_BG & norm) {
|
||||
core->tvaudio = WW_BG;
|
||||
|
||||
} else if (V4L2_STD_PAL_DK & norm->id) {
|
||||
} else if (V4L2_STD_PAL_DK & norm) {
|
||||
core->tvaudio = WW_DK;
|
||||
|
||||
} else if (V4L2_STD_PAL_I & norm->id) {
|
||||
} else if (V4L2_STD_PAL_I & norm) {
|
||||
core->tvaudio = WW_I;
|
||||
|
||||
} else if (V4L2_STD_SECAM_L & norm->id) {
|
||||
} else if (V4L2_STD_SECAM_L & norm) {
|
||||
core->tvaudio = WW_L;
|
||||
|
||||
} else if (V4L2_STD_SECAM_DK & norm->id) {
|
||||
} else if (V4L2_STD_SECAM_DK & norm) {
|
||||
core->tvaudio = WW_DK;
|
||||
|
||||
} else if ((V4L2_STD_NTSC_M & norm->id) ||
|
||||
(V4L2_STD_PAL_M & norm->id)) {
|
||||
} else if ((V4L2_STD_NTSC_M & norm) ||
|
||||
(V4L2_STD_PAL_M & norm)) {
|
||||
core->tvaudio = WW_BTSC;
|
||||
|
||||
} else if (V4L2_STD_NTSC_M_JP & norm->id) {
|
||||
} else if (V4L2_STD_NTSC_M_JP & norm) {
|
||||
core->tvaudio = WW_EIAJ;
|
||||
|
||||
} else {
|
||||
printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
|
||||
core->name, norm->name);
|
||||
core->name, v4l2_norm_to_name(core->tvnorm));
|
||||
core->tvaudio = 0;
|
||||
return 0;
|
||||
}
|
||||
@ -874,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
|
||||
|
||||
|
||||
|
||||
int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
|
||||
int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
|
||||
{
|
||||
u32 fsc8;
|
||||
u32 adc_clock;
|
||||
@ -882,6 +887,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
|
||||
u32 step_db,step_dr;
|
||||
u64 tmp64;
|
||||
u32 bdelay,agcdelay,htotal;
|
||||
u32 cxiformat, cxoformat;
|
||||
|
||||
core->tvnorm = norm;
|
||||
fsc8 = norm_fsc8(norm);
|
||||
@ -890,23 +896,51 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
|
||||
step_db = fsc8;
|
||||
step_dr = fsc8;
|
||||
|
||||
if (norm->id & V4L2_STD_SECAM) {
|
||||
if (norm & V4L2_STD_NTSC_M_JP) {
|
||||
cxiformat = VideoFormatNTSCJapan;
|
||||
cxoformat = 0x181f0008;
|
||||
} else if (norm & V4L2_STD_NTSC_443) {
|
||||
cxiformat = VideoFormatNTSC443;
|
||||
cxoformat = 0x181f0008;
|
||||
} else if (norm & V4L2_STD_PAL_M) {
|
||||
cxiformat = VideoFormatPALM;
|
||||
cxoformat = 0x1c1f0008;
|
||||
} else if (norm & V4L2_STD_PAL_N) {
|
||||
cxiformat = VideoFormatPALN;
|
||||
cxoformat = 0x1c1f0008;
|
||||
} else if (norm & V4L2_STD_PAL_Nc) {
|
||||
cxiformat = VideoFormatPALNC;
|
||||
cxoformat = 0x1c1f0008;
|
||||
} else if (norm & V4L2_STD_PAL_60) {
|
||||
cxiformat = VideoFormatPAL60;
|
||||
cxoformat = 0x181f0008;
|
||||
} else if (norm & V4L2_STD_NTSC) {
|
||||
cxiformat = VideoFormatNTSC;
|
||||
cxoformat = 0x181f0008;
|
||||
} else if (norm & V4L2_STD_SECAM) {
|
||||
step_db = 4250000 * 8;
|
||||
step_dr = 4406250 * 8;
|
||||
|
||||
cxiformat = VideoFormatSECAM;
|
||||
cxoformat = 0x181f0008;
|
||||
} else { /* PAL */
|
||||
cxiformat = VideoFormatPAL;
|
||||
cxoformat = 0x181f0008;
|
||||
}
|
||||
|
||||
dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n",
|
||||
norm->name, fsc8, adc_clock, vdec_clock, step_db, step_dr);
|
||||
v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock,
|
||||
step_db, step_dr);
|
||||
set_pll(core,2,vdec_clock);
|
||||
|
||||
dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
|
||||
norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
|
||||
cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
|
||||
cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
|
||||
cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
|
||||
|
||||
// FIXME: as-is from DScaler
|
||||
dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
|
||||
norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
|
||||
cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
|
||||
cxoformat, cx_read(MO_OUTPUT_FORMAT));
|
||||
cx_write(MO_OUTPUT_FORMAT, cxoformat);
|
||||
|
||||
// MO_SCONV_REG = adc clock / video dec clock * 2^17
|
||||
tmp64 = adc_clock * (u64)(1 << 17);
|
||||
@ -955,7 +989,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
|
||||
set_tvaudio(core);
|
||||
|
||||
// tell i2c chips
|
||||
cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
|
||||
cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm);
|
||||
|
||||
// done
|
||||
return 0;
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
#include "mt352.h"
|
||||
#include "mt352_priv.h"
|
||||
#ifdef HAVE_VP3054_I2C
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
|
||||
# include "cx88-vp3054-i2c.h"
|
||||
#endif
|
||||
#include "zl10353.h"
|
||||
@ -200,7 +200,7 @@ static struct mt352_config dvico_fusionhdtv_dual = {
|
||||
.demod_init = dvico_dual_demod_init,
|
||||
};
|
||||
|
||||
#ifdef HAVE_VP3054_I2C
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
|
||||
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
|
||||
{
|
||||
static u8 clock_config [] = { 0x89, 0x38, 0x38 };
|
||||
@ -543,7 +543,7 @@ static int dvb_register(struct cx8802_dev *dev)
|
||||
}
|
||||
break;
|
||||
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
|
||||
#ifdef HAVE_VP3054_I2C
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
|
||||
dev->core->pll_addr = 0x61;
|
||||
dev->core->pll_desc = &dvb_pll_fmd1216me;
|
||||
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
|
||||
@ -793,7 +793,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
|
||||
if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
|
||||
goto fail_core;
|
||||
|
||||
#ifdef HAVE_VP3054_I2C
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
|
||||
err = vp3054_i2c_probe(dev);
|
||||
if (0 != err)
|
||||
goto fail_core;
|
||||
@ -822,7 +822,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
|
||||
/* dvb */
|
||||
videobuf_dvb_unregister(&dev->dvb);
|
||||
|
||||
#ifdef HAVE_VP3054_I2C
|
||||
#if defined(CONFIG_VIDEO_CX88_VP3054) || defined(CONFIG_VIDEO_CX88_VP3054_MODULE)
|
||||
vp3054_i2c_remove(dev);
|
||||
#endif
|
||||
|
||||
|
@ -145,6 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
|
||||
if (0 != core->i2c_rc)
|
||||
return;
|
||||
|
||||
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
|
||||
if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
|
||||
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
|
||||
@ -154,6 +155,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
|
||||
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
|
||||
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
|
||||
} else
|
||||
#endif
|
||||
i2c_clients_command(&core->i2c_adap, cmd, arg);
|
||||
}
|
||||
|
||||
|
@ -797,55 +797,6 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
|
||||
Add some code here later.
|
||||
*/
|
||||
|
||||
# if 0
|
||||
t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP |
|
||||
V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
|
||||
t->rxsubchans = V4L2_TUNER_SUB_MONO;
|
||||
t->audmode = V4L2_TUNER_MODE_MONO;
|
||||
|
||||
switch (core->tvaudio) {
|
||||
case WW_BTSC:
|
||||
t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP;
|
||||
t->rxsubchans = V4L2_TUNER_SUB_STEREO;
|
||||
if (1 == pilot) {
|
||||
/* SAP */
|
||||
t->rxsubchans |= V4L2_TUNER_SUB_SAP;
|
||||
}
|
||||
break;
|
||||
case WW_A2_BG:
|
||||
case WW_A2_DK:
|
||||
case WW_A2_M:
|
||||
if (1 == pilot) {
|
||||
/* stereo */
|
||||
t->rxsubchans =
|
||||
V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
|
||||
if (0 == mode)
|
||||
t->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
}
|
||||
if (2 == pilot) {
|
||||
/* dual language -- FIXME */
|
||||
t->rxsubchans =
|
||||
V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
|
||||
t->audmode = V4L2_TUNER_MODE_LANG1;
|
||||
}
|
||||
break;
|
||||
case WW_NICAM_BGDKL:
|
||||
if (0 == mode) {
|
||||
t->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
|
||||
}
|
||||
break;
|
||||
case WW_SYSTEM_L_AM:
|
||||
if (0x0 == mode && !(cx_read(AUD_INIT) & 0x04)) {
|
||||
t->audmode = V4L2_TUNER_MODE_STEREO;
|
||||
t->rxsubchans |= V4L2_TUNER_SUB_STEREO;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* nothing */
|
||||
break;
|
||||
}
|
||||
# endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -21,9 +21,11 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
|
||||
int cx8800_vbi_fmt (struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
memset(&f->fmt.vbi,0,sizeof(f->fmt.vbi));
|
||||
struct cx8800_fh *fh = priv;
|
||||
struct cx8800_dev *dev = fh->dev;
|
||||
|
||||
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
|
||||
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
|
||||
@ -31,18 +33,19 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
|
||||
f->fmt.vbi.count[0] = VBI_LINE_COUNT;
|
||||
f->fmt.vbi.count[1] = VBI_LINE_COUNT;
|
||||
|
||||
if (dev->core->tvnorm->id & V4L2_STD_525_60) {
|
||||
if (dev->core->tvnorm & V4L2_STD_525_60) {
|
||||
/* ntsc */
|
||||
f->fmt.vbi.sampling_rate = 28636363;
|
||||
f->fmt.vbi.start[0] = 10;
|
||||
f->fmt.vbi.start[1] = 273;
|
||||
|
||||
} else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
|
||||
} else if (dev->core->tvnorm & V4L2_STD_625_50) {
|
||||
/* pal */
|
||||
f->fmt.vbi.sampling_rate = 35468950;
|
||||
f->fmt.vbi.start[0] = 7 -1;
|
||||
f->fmt.vbi.start[1] = 319 -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,7 +31,9 @@
|
||||
#include <media/video-buf.h>
|
||||
#include <media/cx2341x.h>
|
||||
#include <media/audiochip.h>
|
||||
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
|
||||
#include <media/video-buf-dvb.h>
|
||||
#endif
|
||||
|
||||
#include "btcx-risc.h"
|
||||
#include "cx88-reg.h"
|
||||
@ -50,6 +52,13 @@
|
||||
/* ----------------------------------------------------------- */
|
||||
/* defines and enums */
|
||||
|
||||
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
|
||||
#define CX88_NORMS (\
|
||||
V4L2_STD_NTSC_M| V4L2_STD_NTSC_M_JP| V4L2_STD_NTSC_443 | \
|
||||
V4L2_STD_PAL_BG| V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
|
||||
V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \
|
||||
V4L2_STD_PAL_60| V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK )
|
||||
|
||||
#define FORMAT_FLAGS_PACKED 0x01
|
||||
#define FORMAT_FLAGS_PLANAR 0x02
|
||||
|
||||
@ -82,22 +91,15 @@ enum cx8802_board_access {
|
||||
/* ----------------------------------------------------------- */
|
||||
/* tv norms */
|
||||
|
||||
struct cx88_tvnorm {
|
||||
char *name;
|
||||
v4l2_std_id id;
|
||||
u32 cxiformat;
|
||||
u32 cxoformat;
|
||||
};
|
||||
|
||||
static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_maxw(v4l2_std_id norm)
|
||||
{
|
||||
return (norm->id & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
|
||||
return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
|
||||
static unsigned int inline norm_maxh(v4l2_std_id norm)
|
||||
{
|
||||
return (norm->id & V4L2_STD_625_50) ? 576 : 480;
|
||||
return (norm & V4L2_STD_625_50) ? 576 : 480;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
@ -313,13 +315,15 @@ struct cx88_core {
|
||||
unsigned int tuner_formats;
|
||||
|
||||
/* config info -- dvb */
|
||||
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
|
||||
struct dvb_pll_desc *pll_desc;
|
||||
unsigned int pll_addr;
|
||||
int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
|
||||
#endif
|
||||
|
||||
/* state info */
|
||||
struct task_struct *kthread;
|
||||
struct cx88_tvnorm *tvnorm;
|
||||
v4l2_std_id tvnorm;
|
||||
u32 tvaudio;
|
||||
u32 audiomode_manual;
|
||||
u32 audiomode_current;
|
||||
@ -460,12 +464,14 @@ struct cx8802_dev {
|
||||
int width;
|
||||
int height;
|
||||
|
||||
#if defined(CONFIG_VIDEO_BUF_DVB) || defined(CONFIG_VIDEO_BUF_DVB_MODULE)
|
||||
/* for dvb only */
|
||||
struct videobuf_dvb dvb;
|
||||
void* fe_handle;
|
||||
int (*fe_release)(void *handle);
|
||||
|
||||
void *card_priv;
|
||||
#endif
|
||||
/* for switching modulation types */
|
||||
unsigned char ts_gen_cntrl;
|
||||
|
||||
@ -536,7 +542,7 @@ extern void cx88_sram_channel_dump(struct cx88_core *core,
|
||||
|
||||
extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
|
||||
unsigned int height, enum v4l2_field field);
|
||||
extern int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm);
|
||||
extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
|
||||
|
||||
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
|
||||
struct pci_dev *pci,
|
||||
@ -553,7 +559,10 @@ extern int cx88_stop_audio_dma(struct cx88_core *core);
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-vbi.c */
|
||||
|
||||
void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
|
||||
/* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */
|
||||
int cx8800_vbi_fmt (struct file *file, void *priv,
|
||||
struct v4l2_format *f);
|
||||
|
||||
/*
|
||||
int cx8800_start_vbi_dma(struct cx8800_dev *dev,
|
||||
struct cx88_dmaqueue *q,
|
||||
@ -633,19 +642,14 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state);
|
||||
int cx8802_resume_common(struct pci_dev *pci_dev);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-video.c */
|
||||
extern int cx88_do_ioctl(struct inode *inode, struct file *file, int radio,
|
||||
struct cx88_core *core, unsigned int cmd,
|
||||
void *arg, v4l2_kioctl driver_ioctl);
|
||||
/* cx88-video.c*/
|
||||
extern const u32 cx88_user_ctrls[];
|
||||
extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
|
||||
|
||||
/* ----------------------------------------------------------- */
|
||||
/* cx88-blackbird.c */
|
||||
/* used by cx88-ivtv ioctl emulation layer */
|
||||
extern int (*cx88_ioctl_hook)(struct inode *inode, struct file *file,
|
||||
unsigned int cmd, void *arg);
|
||||
extern unsigned int (*cx88_ioctl_translator)(unsigned int cmd);
|
||||
int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
|
||||
int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
|
||||
int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
|
||||
int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
|
||||
int cx88_video_mux(struct cx88_core *core, unsigned int input);
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
|
@ -171,10 +171,7 @@ struct et61x251_device {
|
||||
struct et61x251_device*
|
||||
et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)
|
||||
{
|
||||
if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
|
||||
return cam;
|
||||
|
||||
return NULL;
|
||||
return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/***************************************************************************
|
||||
* V4L2 driver for ET61X[12]51 PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* 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 *
|
||||
@ -48,8 +48,8 @@
|
||||
#define ET61X251_MODULE_AUTHOR "(C) 2006 Luca Risolia"
|
||||
#define ET61X251_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
|
||||
#define ET61X251_MODULE_LICENSE "GPL"
|
||||
#define ET61X251_MODULE_VERSION "1:1.02"
|
||||
#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 2)
|
||||
#define ET61X251_MODULE_VERSION "1:1.04"
|
||||
#define ET61X251_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 4)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@ -85,7 +85,7 @@ MODULE_PARM_DESC(force_munmap,
|
||||
"\ndetected camera."
|
||||
"\n 0 = do not force memory unmapping"
|
||||
"\n 1 = force memory unmapping (save memory)"
|
||||
"\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
|
||||
"\nDefault value is "__MODULE_STRING(ET61X251_FORCE_MUNMAP)"."
|
||||
"\n");
|
||||
|
||||
static unsigned int frame_timeout[] = {[0 ... ET61X251_MAX_DEVICES-1] =
|
||||
@ -133,7 +133,8 @@ et61x251_request_buffers(struct et61x251_device* cam, u32 count,
|
||||
|
||||
cam->nbuffers = count;
|
||||
while (cam->nbuffers > 0) {
|
||||
if ((buff = vmalloc_32(cam->nbuffers * PAGE_ALIGN(imagesize))))
|
||||
if ((buff = vmalloc_32_user(cam->nbuffers *
|
||||
PAGE_ALIGN(imagesize))))
|
||||
break;
|
||||
cam->nbuffers--;
|
||||
}
|
||||
@ -543,10 +544,11 @@ static int et61x251_start_transfer(struct et61x251_device* cam)
|
||||
{
|
||||
struct usb_device *udev = cam->usbdev;
|
||||
struct urb* urb;
|
||||
const unsigned int wMaxPacketSize[] = {0, 256, 384, 512, 640, 768, 832,
|
||||
864, 896, 920, 956, 980, 1000,
|
||||
1022};
|
||||
const unsigned int psz = wMaxPacketSize[ET61X251_ALTERNATE_SETTING];
|
||||
struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
|
||||
usb_ifnum_to_if(udev, 0),
|
||||
ET61X251_ALTERNATE_SETTING);
|
||||
const unsigned int psz = le16_to_cpu(altsetting->
|
||||
endpoint[0].desc.wMaxPacketSize);
|
||||
s8 i, j;
|
||||
int err = 0;
|
||||
|
||||
@ -976,29 +978,31 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
|
||||
static int et61x251_create_sysfs(struct et61x251_device* cam)
|
||||
{
|
||||
struct video_device *v4ldev = cam->v4ldev;
|
||||
int rc;
|
||||
int err = 0;
|
||||
|
||||
if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
|
||||
goto err_out;
|
||||
if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
|
||||
goto err_reg;
|
||||
|
||||
rc = video_device_create_file(v4ldev, &class_device_attr_reg);
|
||||
if (rc) goto err;
|
||||
rc = video_device_create_file(v4ldev, &class_device_attr_val);
|
||||
if (rc) goto err_reg;
|
||||
if (cam->sensor.sysfs_ops) {
|
||||
rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
|
||||
if (rc) goto err_val;
|
||||
rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
|
||||
if (rc) goto err_i2c_reg;
|
||||
if ((err = video_device_create_file(v4ldev,
|
||||
&class_device_attr_i2c_reg)))
|
||||
goto err_val;
|
||||
if ((err = video_device_create_file(v4ldev,
|
||||
&class_device_attr_i2c_val)))
|
||||
goto err_i2c_reg;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_i2c_reg:
|
||||
if (cam->sensor.sysfs_ops)
|
||||
video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
|
||||
err_val:
|
||||
video_device_remove_file(v4ldev, &class_device_attr_val);
|
||||
err_reg:
|
||||
video_device_remove_file(v4ldev, &class_device_attr_reg);
|
||||
err:
|
||||
return rc;
|
||||
err_out:
|
||||
return err;
|
||||
}
|
||||
#endif /* CONFIG_VIDEO_ADV_DEBUG */
|
||||
|
||||
@ -1767,10 +1771,10 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
|
||||
rect->left = (s->_rect.left & 1L) ? rect->left | 1L : rect->left & ~1L;
|
||||
rect->top = (s->_rect.top & 1L) ? rect->top | 1L : rect->top & ~1L;
|
||||
|
||||
if (rect->width < 4)
|
||||
rect->width = 4;
|
||||
if (rect->height < 4)
|
||||
rect->height = 4;
|
||||
if (rect->width < 16)
|
||||
rect->width = 16;
|
||||
if (rect->height < 16)
|
||||
rect->height = 16;
|
||||
if (rect->width > bounds->width)
|
||||
rect->width = bounds->width;
|
||||
if (rect->height > bounds->height)
|
||||
@ -1784,8 +1788,8 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
|
||||
if (rect->top + rect->height > bounds->top + bounds->height)
|
||||
rect->top = bounds->top+bounds->height - rect->height;
|
||||
|
||||
rect->width &= ~3L;
|
||||
rect->height &= ~3L;
|
||||
rect->width &= ~15L;
|
||||
rect->height &= ~15L;
|
||||
|
||||
if (ET61X251_PRESERVE_IMGSCALE) {
|
||||
/* Calculate the actual scaling factor */
|
||||
@ -1845,6 +1849,35 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
et61x251_vidioc_enum_framesizes(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
struct v4l2_frmsizeenum frmsize;
|
||||
|
||||
if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
|
||||
return -EFAULT;
|
||||
|
||||
if (frmsize.index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
if (frmsize.pixel_format != V4L2_PIX_FMT_ET61X251 &&
|
||||
frmsize.pixel_format != V4L2_PIX_FMT_SBGGR8)
|
||||
return -EINVAL;
|
||||
|
||||
frmsize.type = V4L2_FRMSIZE_TYPE_STEPWISE;
|
||||
frmsize.stepwise.min_width = frmsize.stepwise.step_width = 16;
|
||||
frmsize.stepwise.min_height = frmsize.stepwise.step_height = 16;
|
||||
frmsize.stepwise.max_width = cam->sensor.cropcap.bounds.width;
|
||||
frmsize.stepwise.max_height = cam->sensor.cropcap.bounds.height;
|
||||
memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
|
||||
|
||||
if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
|
||||
{
|
||||
@ -1853,6 +1886,9 @@ et61x251_vidioc_enum_fmt(struct et61x251_device* cam, void __user * arg)
|
||||
if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
|
||||
return -EFAULT;
|
||||
|
||||
if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
|
||||
return -EINVAL;
|
||||
|
||||
if (fmtd.index == 0) {
|
||||
strcpy(fmtd.description, "bayer rgb");
|
||||
fmtd.pixelformat = V4L2_PIX_FMT_SBGGR8;
|
||||
@ -1934,17 +1970,17 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
|
||||
rect.width = scale * pix->width;
|
||||
rect.height = scale * pix->height;
|
||||
|
||||
if (rect.width < 4)
|
||||
rect.width = 4;
|
||||
if (rect.height < 4)
|
||||
rect.height = 4;
|
||||
if (rect.width < 16)
|
||||
rect.width = 16;
|
||||
if (rect.height < 16)
|
||||
rect.height = 16;
|
||||
if (rect.width > bounds->left + bounds->width - rect.left)
|
||||
rect.width = bounds->left + bounds->width - rect.left;
|
||||
if (rect.height > bounds->top + bounds->height - rect.top)
|
||||
rect.height = bounds->top + bounds->height - rect.top;
|
||||
|
||||
rect.width &= ~3L;
|
||||
rect.height &= ~3L;
|
||||
rect.width &= ~15L;
|
||||
rect.height &= ~15L;
|
||||
|
||||
{ /* adjust the scaling factor */
|
||||
u32 a, b;
|
||||
@ -2378,6 +2414,9 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
|
||||
case VIDIOC_S_FMT:
|
||||
return et61x251_vidioc_try_s_fmt(cam, cmd, arg);
|
||||
|
||||
case VIDIOC_ENUM_FRAMESIZES:
|
||||
return et61x251_vidioc_enum_framesizes(cam, arg);
|
||||
|
||||
case VIDIOC_G_JPEGCOMP:
|
||||
return et61x251_vidioc_g_jpegcomp(cam, arg);
|
||||
|
||||
@ -2413,6 +2452,7 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp,
|
||||
case VIDIOC_QUERYSTD:
|
||||
case VIDIOC_ENUMSTD:
|
||||
case VIDIOC_QUERYMENU:
|
||||
case VIDIOC_ENUM_FRAMEINTERVALS:
|
||||
return -EINVAL;
|
||||
|
||||
default:
|
||||
@ -2459,6 +2499,7 @@ static const struct file_operations et61x251_fops = {
|
||||
.open = et61x251_open,
|
||||
.release = et61x251_release,
|
||||
.ioctl = et61x251_ioctl,
|
||||
.compat_ioctl = v4l_compat_ioctl32,
|
||||
.read = et61x251_read,
|
||||
.poll = et61x251_poll,
|
||||
.mmap = et61x251_mmap,
|
||||
@ -2497,7 +2538,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
mutex_init(&cam->dev_mutex);
|
||||
|
||||
DBG(2, "ET61X[12]51 PC Camera Controller detected "
|
||||
"(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
|
||||
"(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
|
||||
|
||||
for (i = 0; et61x251_sensor_table[i]; i++) {
|
||||
err = et61x251_sensor_table[i](cam);
|
||||
@ -2550,9 +2591,14 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
err = et61x251_create_sysfs(cam);
|
||||
if (err)
|
||||
goto fail2;
|
||||
DBG(2, "Optional device control through 'sysfs' interface ready");
|
||||
if (!err)
|
||||
DBG(2, "Optional device control through 'sysfs' "
|
||||
"interface ready");
|
||||
else
|
||||
DBG(2, "Failed to create 'sysfs' interface for optional "
|
||||
"device controlling. Error #%d", err);
|
||||
#else
|
||||
DBG(2, "Optional device control through 'sysfs' interface disabled");
|
||||
#endif
|
||||
|
||||
usb_set_intfdata(intf, cam);
|
||||
@ -2561,13 +2607,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
|
||||
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
fail2:
|
||||
video_nr[dev_nr] = -1;
|
||||
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
|
||||
mutex_unlock(&cam->dev_mutex);
|
||||
video_unregister_device(cam->v4ldev);
|
||||
#endif
|
||||
fail:
|
||||
if (cam) {
|
||||
kfree(cam->control_buffer);
|
||||
|
@ -1,7 +1,7 @@
|
||||
/***************************************************************************
|
||||
* API for image sensors connected to ET61X[12]51 PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* 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 *
|
||||
@ -82,7 +82,7 @@ enum et61x251_i2c_rsta {
|
||||
ET61X251_I2C_RSTA_REPEAT = 0x01, /* repeat start */
|
||||
};
|
||||
|
||||
#define ET61X251_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
|
||||
#define ET61X251_MAX_CTRLS (V4L2_CID_LASTP1-V4L2_CID_BASE+10)
|
||||
|
||||
struct et61x251_sensor {
|
||||
char name[32];
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Plug-in for TAS5130D1B image sensor connected to the ET61X[12]51 *
|
||||
* PC Camera Controllers *
|
||||
* *
|
||||
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
|
||||
* *
|
||||
* 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 *
|
||||
|
@ -31,7 +31,6 @@ struct pvr2_msp3400_handler {
|
||||
struct pvr2_hdw *hdw;
|
||||
struct pvr2_i2c_client *client;
|
||||
struct pvr2_i2c_handler i2c_handler;
|
||||
struct pvr2_audio_stat astat;
|
||||
unsigned long stale_mask;
|
||||
};
|
||||
|
||||
@ -44,13 +43,6 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
|
||||
|
||||
pvr2_trace(PVR2_TRACE_CHIPS,"i2c msp3400 v4l2 set_stereo");
|
||||
|
||||
if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
|
||||
struct v4l2_tuner vt;
|
||||
memset(&vt,0,sizeof(vt));
|
||||
vt.audmode = hdw->audiomode_val;
|
||||
pvr2_i2c_client_cmd(ctxt->client,VIDIOC_S_TUNER,&vt);
|
||||
}
|
||||
|
||||
route.input = MSP_INPUT_DEFAULT;
|
||||
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
|
||||
switch (hdw->input_val) {
|
||||
@ -78,8 +70,7 @@ static void set_stereo(struct pvr2_msp3400_handler *ctxt)
|
||||
static int check_stereo(struct pvr2_msp3400_handler *ctxt)
|
||||
{
|
||||
struct pvr2_hdw *hdw = ctxt->hdw;
|
||||
return (hdw->input_dirty ||
|
||||
hdw->audiomode_dirty);
|
||||
return hdw->input_dirty;
|
||||
}
|
||||
|
||||
|
||||
@ -99,8 +90,7 @@ static int msp3400_check(struct pvr2_msp3400_handler *ctxt)
|
||||
unsigned long msk;
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
|
||||
idx++) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
|
||||
msk = 1 << idx;
|
||||
if (ctxt->stale_mask & msk) continue;
|
||||
if (msp3400_ops[idx].check(ctxt)) {
|
||||
@ -116,8 +106,7 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
|
||||
unsigned long msk;
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < sizeof(msp3400_ops)/sizeof(msp3400_ops[0]);
|
||||
idx++) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(msp3400_ops); idx++) {
|
||||
msk = 1 << idx;
|
||||
if (!(ctxt->stale_mask & msk)) continue;
|
||||
ctxt->stale_mask &= ~msk;
|
||||
@ -126,27 +115,9 @@ static void msp3400_update(struct pvr2_msp3400_handler *ctxt)
|
||||
}
|
||||
|
||||
|
||||
/* This reads back the current signal type */
|
||||
static int get_audio_status(struct pvr2_msp3400_handler *ctxt)
|
||||
{
|
||||
struct v4l2_tuner vt;
|
||||
int stat;
|
||||
|
||||
memset(&vt,0,sizeof(vt));
|
||||
stat = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
|
||||
if (stat < 0) return stat;
|
||||
|
||||
ctxt->hdw->flag_stereo = (vt.audmode & V4L2_TUNER_MODE_STEREO) != 0;
|
||||
ctxt->hdw->flag_bilingual =
|
||||
(vt.audmode & V4L2_TUNER_MODE_LANG2) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void pvr2_msp3400_detach(struct pvr2_msp3400_handler *ctxt)
|
||||
{
|
||||
ctxt->client->handler = NULL;
|
||||
ctxt->hdw->audio_stat = NULL;
|
||||
kfree(ctxt);
|
||||
}
|
||||
|
||||
@ -169,24 +140,17 @@ static const struct pvr2_i2c_handler_functions msp3400_funcs = {
|
||||
int pvr2_i2c_msp3400_setup(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
|
||||
{
|
||||
struct pvr2_msp3400_handler *ctxt;
|
||||
if (hdw->audio_stat) return 0;
|
||||
if (cp->handler) return 0;
|
||||
|
||||
ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
|
||||
ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
|
||||
if (!ctxt) return 0;
|
||||
memset(ctxt,0,sizeof(*ctxt));
|
||||
|
||||
ctxt->i2c_handler.func_data = ctxt;
|
||||
ctxt->i2c_handler.func_table = &msp3400_funcs;
|
||||
ctxt->client = cp;
|
||||
ctxt->hdw = hdw;
|
||||
ctxt->astat.ctxt = ctxt;
|
||||
ctxt->astat.status = (int (*)(void *))get_audio_status;
|
||||
ctxt->astat.detach = (void (*)(void *))pvr2_msp3400_detach;
|
||||
ctxt->stale_mask = (1 << (sizeof(msp3400_ops)/
|
||||
sizeof(msp3400_ops[0]))) - 1;
|
||||
ctxt->stale_mask = (1 << ARRAY_SIZE(msp3400_ops)) - 1;
|
||||
cp->handler = &ctxt->i2c_handler;
|
||||
hdw->audio_stat = &ctxt->astat;
|
||||
pvr2_trace(PVR2_TRACE_CHIPS,"i2c 0x%x msp3400 V4L2 handler set up",
|
||||
cp->client->addr);
|
||||
return !0;
|
||||
|
@ -83,9 +83,8 @@ struct pvr2_context *pvr2_context_create(
|
||||
void (*setup_func)(struct pvr2_context *))
|
||||
{
|
||||
struct pvr2_context *mp = NULL;
|
||||
mp = kmalloc(sizeof(*mp),GFP_KERNEL);
|
||||
mp = kzalloc(sizeof(*mp),GFP_KERNEL);
|
||||
if (!mp) goto done;
|
||||
memset(mp,0,sizeof(*mp));
|
||||
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
|
||||
mp->setup_func = setup_func;
|
||||
mutex_init(&mp->mutex);
|
||||
|
@ -26,6 +26,27 @@
|
||||
#include <linux/mutex.h>
|
||||
|
||||
|
||||
static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
|
||||
{
|
||||
if (cptr->info->check_value) {
|
||||
if (!cptr->info->check_value(cptr,val)) return -ERANGE;
|
||||
} else {
|
||||
int lim;
|
||||
lim = cptr->info->def.type_int.min_value;
|
||||
if (cptr->info->get_min_value) {
|
||||
cptr->info->get_min_value(cptr,&lim);
|
||||
}
|
||||
if (val < lim) return -ERANGE;
|
||||
lim = cptr->info->def.type_int.max_value;
|
||||
if (cptr->info->get_max_value) {
|
||||
cptr->info->get_max_value(cptr,&lim);
|
||||
}
|
||||
if (val > lim) return -ERANGE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Set the given control. */
|
||||
int pvr2_ctrl_set_value(struct pvr2_ctrl *cptr,int val)
|
||||
{
|
||||
@ -43,17 +64,8 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
|
||||
if (cptr->info->type == pvr2_ctl_bitmask) {
|
||||
mask &= cptr->info->def.type_bitmask.valid_bits;
|
||||
} else if (cptr->info->type == pvr2_ctl_int) {
|
||||
int lim;
|
||||
lim = cptr->info->def.type_int.min_value;
|
||||
if (cptr->info->get_min_value) {
|
||||
cptr->info->get_min_value(cptr,&lim);
|
||||
}
|
||||
if (val < lim) break;
|
||||
lim = cptr->info->def.type_int.max_value;
|
||||
if (cptr->info->get_max_value) {
|
||||
cptr->info->get_max_value(cptr,&lim);
|
||||
}
|
||||
if (val > lim) break;
|
||||
ret = pvr2_ctrl_range_check(cptr,val);
|
||||
if (ret < 0) break;
|
||||
} else if (cptr->info->type == pvr2_ctl_enum) {
|
||||
if (val >= cptr->info->def.type_enum.count) {
|
||||
break;
|
||||
@ -498,16 +510,13 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
|
||||
LOCK_TAKE(cptr->hdw->big_lock); do {
|
||||
if (cptr->info->type == pvr2_ctl_int) {
|
||||
ret = parse_token(ptr,len,valptr,NULL,0);
|
||||
if ((ret >= 0) &&
|
||||
((*valptr < cptr->info->def.type_int.min_value) ||
|
||||
(*valptr > cptr->info->def.type_int.max_value))) {
|
||||
ret = -ERANGE;
|
||||
if (ret >= 0) {
|
||||
ret = pvr2_ctrl_range_check(cptr,*valptr);
|
||||
}
|
||||
if (maskptr) *maskptr = ~0;
|
||||
} else if (cptr->info->type == pvr2_ctl_bool) {
|
||||
ret = parse_token(
|
||||
ptr,len,valptr,boolNames,
|
||||
sizeof(boolNames)/sizeof(boolNames[0]));
|
||||
ret = parse_token(ptr,len,valptr,boolNames,
|
||||
ARRAY_SIZE(boolNames));
|
||||
if (ret == 1) {
|
||||
*valptr = *valptr ? !0 : 0;
|
||||
} else if (ret == 0) {
|
||||
|
@ -63,6 +63,7 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
|
||||
vid_input = CX25840_COMPOSITE7;
|
||||
aud_input = CX25840_AUDIO8;
|
||||
break;
|
||||
case PVR2_CVAL_INPUT_RADIO: // Treat same as composite
|
||||
case PVR2_CVAL_INPUT_COMPOSITE:
|
||||
vid_input = CX25840_COMPOSITE3;
|
||||
aud_input = CX25840_AUDIO_SERIAL;
|
||||
@ -71,7 +72,6 @@ static void set_input(struct pvr2_v4l_cx2584x *ctxt)
|
||||
vid_input = CX25840_SVIDEO1;
|
||||
aud_input = CX25840_AUDIO_SERIAL;
|
||||
break;
|
||||
case PVR2_CVAL_INPUT_RADIO:
|
||||
default:
|
||||
// Just set it to be composite input for now...
|
||||
vid_input = CX25840_COMPOSITE3;
|
||||
@ -150,8 +150,7 @@ static int decoder_check(struct pvr2_v4l_cx2584x *ctxt)
|
||||
unsigned long msk;
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
|
||||
idx++) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
|
||||
msk = 1 << idx;
|
||||
if (ctxt->stale_mask & msk) continue;
|
||||
if (decoder_ops[idx].check(ctxt)) {
|
||||
@ -167,8 +166,7 @@ static void decoder_update(struct pvr2_v4l_cx2584x *ctxt)
|
||||
unsigned long msk;
|
||||
unsigned int idx;
|
||||
|
||||
for (idx = 0; idx < sizeof(decoder_ops)/sizeof(decoder_ops[0]);
|
||||
idx++) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(decoder_ops); idx++) {
|
||||
msk = 1 << idx;
|
||||
if (!(ctxt->stale_mask & msk)) continue;
|
||||
ctxt->stale_mask &= ~msk;
|
||||
@ -199,18 +197,6 @@ static int decoder_detect(struct pvr2_i2c_client *cp)
|
||||
}
|
||||
|
||||
|
||||
static int decoder_is_tuned(struct pvr2_v4l_cx2584x *ctxt)
|
||||
{
|
||||
struct v4l2_tuner vt;
|
||||
int ret;
|
||||
|
||||
memset(&vt,0,sizeof(vt));
|
||||
ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_G_TUNER,&vt);
|
||||
if (ret < 0) return -EINVAL;
|
||||
return vt.signal ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
|
||||
char *buf,unsigned int cnt)
|
||||
{
|
||||
@ -243,21 +229,18 @@ int pvr2_i2c_cx2584x_v4l_setup(struct pvr2_hdw *hdw,
|
||||
if (cp->handler) return 0;
|
||||
if (!decoder_detect(cp)) return 0;
|
||||
|
||||
ctxt = kmalloc(sizeof(*ctxt),GFP_KERNEL);
|
||||
ctxt = kzalloc(sizeof(*ctxt),GFP_KERNEL);
|
||||
if (!ctxt) return 0;
|
||||
memset(ctxt,0,sizeof(*ctxt));
|
||||
|
||||
ctxt->handler.func_data = ctxt;
|
||||
ctxt->handler.func_table = &hfuncs;
|
||||
ctxt->ctrl.ctxt = ctxt;
|
||||
ctxt->ctrl.detach = (void (*)(void *))decoder_detach;
|
||||
ctxt->ctrl.enable = (void (*)(void *,int))decoder_enable;
|
||||
ctxt->ctrl.tuned = (int (*)(void *))decoder_is_tuned;
|
||||
ctxt->ctrl.force_reset = (void (*)(void*))decoder_reset;
|
||||
ctxt->client = cp;
|
||||
ctxt->hdw = hdw;
|
||||
ctxt->stale_mask = (1 << (sizeof(decoder_ops)/
|
||||
sizeof(decoder_ops[0]))) - 1;
|
||||
ctxt->stale_mask = (1 << ARRAY_SIZE(decoder_ops)) - 1;
|
||||
hdw->decoder_ctrl = &ctxt->ctrl;
|
||||
cp->handler = &ctxt->handler;
|
||||
{
|
||||
|
@ -152,7 +152,7 @@ static unsigned long debugifc_find_mask(const char *buf,unsigned int count)
|
||||
{
|
||||
struct debugifc_mask_item *mip;
|
||||
unsigned int idx;
|
||||
for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
|
||||
mip = mask_items + idx;
|
||||
if (debugifc_match_keyword(buf,count,mip->name)) {
|
||||
return mip->msk;
|
||||
@ -169,7 +169,7 @@ static int debugifc_print_mask(char *buf,unsigned int sz,
|
||||
unsigned int idx;
|
||||
int bcnt = 0;
|
||||
int ccnt;
|
||||
for (idx = 0; idx < sizeof(mask_items)/sizeof(mask_items[0]); idx++) {
|
||||
for (idx = 0; idx < ARRAY_SIZE(mask_items); idx++) {
|
||||
mip = mask_items + idx;
|
||||
if (!(mip->msk & msk)) continue;
|
||||
ccnt = scnprintf(buf,sz,"%s%c%s",
|
||||
|
@ -102,9 +102,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw)
|
||||
}
|
||||
msg[1].len = pcnt;
|
||||
msg[1].buf = eeprom+tcnt;
|
||||
if ((ret = i2c_transfer(
|
||||
&hdw->i2c_adap,
|
||||
msg,sizeof(msg)/sizeof(msg[0]))) != 2) {
|
||||
if ((ret = i2c_transfer(&hdw->i2c_adap,
|
||||
msg,ARRAY_SIZE(msg))) != 2) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
"eeprom fetch set offs err=%d",ret);
|
||||
kfree(eeprom);
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "pvrusb2-encoder.h"
|
||||
#include "pvrusb2-hdw-internal.h"
|
||||
#include "pvrusb2-debug.h"
|
||||
#include "pvrusb2-fx2-cmd.h"
|
||||
|
||||
|
||||
|
||||
@ -34,34 +35,41 @@
|
||||
#define IVTV_MBOX_DRIVER_DONE 0x00000002
|
||||
#define IVTV_MBOX_DRIVER_BUSY 0x00000001
|
||||
|
||||
#define MBOX_BASE 0x44
|
||||
|
||||
|
||||
static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
|
||||
unsigned int offs,
|
||||
const u32 *data, unsigned int dlen)
|
||||
{
|
||||
unsigned int idx;
|
||||
unsigned int idx,addr;
|
||||
unsigned int bAddr;
|
||||
int ret;
|
||||
unsigned int offs = 0;
|
||||
unsigned int chunkCnt;
|
||||
|
||||
/*
|
||||
|
||||
Format: First byte must be 0x01. Remaining 32 bit words are
|
||||
spread out into chunks of 7 bytes each, little-endian ordered,
|
||||
offset at zero within each 2 blank bytes following and a
|
||||
single byte that is 0x44 plus the offset of the word. Repeat
|
||||
request for additional words, with offset adjusted
|
||||
accordingly.
|
||||
spread out into chunks of 7 bytes each, with the first 4 bytes
|
||||
being the data word (little endian), and the next 3 bytes
|
||||
being the address where that data word is to be written (big
|
||||
endian). Repeat request for additional words, with offset
|
||||
adjusted accordingly.
|
||||
|
||||
*/
|
||||
while (dlen) {
|
||||
chunkCnt = 8;
|
||||
if (chunkCnt > dlen) chunkCnt = dlen;
|
||||
memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
|
||||
hdw->cmd_buffer[0] = 0x01;
|
||||
bAddr = 0;
|
||||
hdw->cmd_buffer[bAddr++] = FX2CMD_MEM_WRITE_DWORD;
|
||||
for (idx = 0; idx < chunkCnt; idx++) {
|
||||
hdw->cmd_buffer[1+(idx*7)+6] = 0x44 + idx + offs;
|
||||
PVR2_DECOMPOSE_LE(hdw->cmd_buffer, 1+(idx*7),
|
||||
data[idx]);
|
||||
addr = idx + offs;
|
||||
hdw->cmd_buffer[bAddr+6] = (addr & 0xffu);
|
||||
hdw->cmd_buffer[bAddr+5] = ((addr>>8) & 0xffu);
|
||||
hdw->cmd_buffer[bAddr+4] = ((addr>>16) & 0xffu);
|
||||
PVR2_DECOMPOSE_LE(hdw->cmd_buffer, bAddr,data[idx]);
|
||||
bAddr += 7;
|
||||
}
|
||||
ret = pvr2_send_request(hdw,
|
||||
hdw->cmd_buffer,1+(chunkCnt*7),
|
||||
@ -76,33 +84,42 @@ static int pvr2_encoder_write_words(struct pvr2_hdw *hdw,
|
||||
}
|
||||
|
||||
|
||||
static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,int statusFl,
|
||||
static int pvr2_encoder_read_words(struct pvr2_hdw *hdw,
|
||||
unsigned int offs,
|
||||
u32 *data, unsigned int dlen)
|
||||
{
|
||||
unsigned int idx;
|
||||
int ret;
|
||||
unsigned int offs = 0;
|
||||
unsigned int chunkCnt;
|
||||
|
||||
/*
|
||||
|
||||
Format: First byte must be 0x02 (status check) or 0x28 (read
|
||||
back block of 32 bit words). Next 6 bytes must be zero,
|
||||
followed by a single byte of 0x44+offset for portion to be
|
||||
read. Returned data is packed set of 32 bits words that were
|
||||
read.
|
||||
followed by a single byte of MBOX_BASE+offset for portion to
|
||||
be read. Returned data is packed set of 32 bits words that
|
||||
were read.
|
||||
|
||||
*/
|
||||
|
||||
while (dlen) {
|
||||
chunkCnt = 16;
|
||||
if (chunkCnt > dlen) chunkCnt = dlen;
|
||||
memset(hdw->cmd_buffer,0,sizeof(hdw->cmd_buffer));
|
||||
hdw->cmd_buffer[0] = statusFl ? 0x02 : 0x28;
|
||||
hdw->cmd_buffer[7] = 0x44 + offs;
|
||||
if (chunkCnt < 16) chunkCnt = 1;
|
||||
hdw->cmd_buffer[0] =
|
||||
((chunkCnt == 1) ?
|
||||
FX2CMD_MEM_READ_DWORD : FX2CMD_MEM_READ_64BYTES);
|
||||
hdw->cmd_buffer[1] = 0;
|
||||
hdw->cmd_buffer[2] = 0;
|
||||
hdw->cmd_buffer[3] = 0;
|
||||
hdw->cmd_buffer[4] = 0;
|
||||
hdw->cmd_buffer[5] = ((offs>>16) & 0xffu);
|
||||
hdw->cmd_buffer[6] = ((offs>>8) & 0xffu);
|
||||
hdw->cmd_buffer[7] = (offs & 0xffu);
|
||||
ret = pvr2_send_request(hdw,
|
||||
hdw->cmd_buffer,8,
|
||||
hdw->cmd_buffer,chunkCnt * 4);
|
||||
hdw->cmd_buffer,
|
||||
(chunkCnt == 1 ? 4 : 16 * 4));
|
||||
if (ret) return ret;
|
||||
|
||||
for (idx = 0; idx < chunkCnt; idx++) {
|
||||
@ -129,6 +146,8 @@ static int pvr2_encoder_cmd(void *ctxt,
|
||||
u32 *argp)
|
||||
{
|
||||
unsigned int poll_count;
|
||||
unsigned int try_count = 0;
|
||||
int retry_flag;
|
||||
int ret = 0;
|
||||
unsigned int idx;
|
||||
/* These sizes look to be limited by the FX2 firmware implementation */
|
||||
@ -140,14 +159,15 @@ static int pvr2_encoder_cmd(void *ctxt,
|
||||
/*
|
||||
|
||||
The encoder seems to speak entirely using blocks 32 bit words.
|
||||
In ivtv driver terms, this is a mailbox which we populate with
|
||||
data and watch what the hardware does with it. The first word
|
||||
is a set of flags used to control the transaction, the second
|
||||
word is the command to execute, the third byte is zero (ivtv
|
||||
driver suggests that this is some kind of return value), and
|
||||
the fourth byte is a specified timeout (windows driver always
|
||||
uses 0x00060000 except for one case when it is zero). All
|
||||
successive words are the argument words for the command.
|
||||
In ivtv driver terms, this is a mailbox at MBOX_BASE which we
|
||||
populate with data and watch what the hardware does with it.
|
||||
The first word is a set of flags used to control the
|
||||
transaction, the second word is the command to execute, the
|
||||
third byte is zero (ivtv driver suggests that this is some
|
||||
kind of return value), and the fourth byte is a specified
|
||||
timeout (windows driver always uses 0x00060000 except for one
|
||||
case when it is zero). All successive words are the argument
|
||||
words for the command.
|
||||
|
||||
First, write out the entire set of words, with the first word
|
||||
being zero.
|
||||
@ -156,44 +176,42 @@ static int pvr2_encoder_cmd(void *ctxt,
|
||||
IVTV_MBOX_DRIVER_DONE | IVTV_DRIVER_BUSY this time (which
|
||||
probably means "go").
|
||||
|
||||
Next, read back 16 words as status. Check the first word,
|
||||
Next, read back the return count words. Check the first word,
|
||||
which should have IVTV_MBOX_FIRMWARE_DONE set. If however
|
||||
that bit is not set, then the command isn't done so repeat the
|
||||
read.
|
||||
|
||||
Next, read back 32 words and compare with the original
|
||||
arugments. Hopefully they will match.
|
||||
read until it is set.
|
||||
|
||||
Finally, write out just the first word again, but set it to
|
||||
0x0 this time (which probably means "idle").
|
||||
|
||||
*/
|
||||
|
||||
if (arg_cnt_send > (sizeof(wrData)/sizeof(wrData[0]))-4) {
|
||||
if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Failed to write cx23416 command"
|
||||
" - too many input arguments"
|
||||
" (was given %u limit %u)",
|
||||
arg_cnt_send,
|
||||
(unsigned int)(sizeof(wrData)/sizeof(wrData[0])) - 4);
|
||||
" (was given %u limit %lu)",
|
||||
arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (arg_cnt_recv > (sizeof(rdData)/sizeof(rdData[0]))-4) {
|
||||
if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Failed to write cx23416 command"
|
||||
" - too many return arguments"
|
||||
" (was given %u limit %u)",
|
||||
arg_cnt_recv,
|
||||
(unsigned int)(sizeof(rdData)/sizeof(rdData[0])) - 4);
|
||||
" (was given %u limit %lu)",
|
||||
arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
|
||||
retry_flag = 0;
|
||||
try_count++;
|
||||
ret = 0;
|
||||
wrData[0] = 0;
|
||||
wrData[1] = cmd;
|
||||
wrData[2] = 0;
|
||||
@ -201,59 +219,74 @@ static int pvr2_encoder_cmd(void *ctxt,
|
||||
for (idx = 0; idx < arg_cnt_send; idx++) {
|
||||
wrData[idx+4] = argp[idx];
|
||||
}
|
||||
for (; idx < (sizeof(wrData)/sizeof(wrData[0]))-4; idx++) {
|
||||
for (; idx < ARRAY_SIZE(wrData) - 4; idx++) {
|
||||
wrData[idx+4] = 0;
|
||||
}
|
||||
|
||||
ret = pvr2_encoder_write_words(hdw,wrData,idx);
|
||||
ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,idx);
|
||||
if (ret) break;
|
||||
wrData[0] = IVTV_MBOX_DRIVER_DONE|IVTV_MBOX_DRIVER_BUSY;
|
||||
ret = pvr2_encoder_write_words(hdw,wrData,1);
|
||||
ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
|
||||
if (ret) break;
|
||||
poll_count = 0;
|
||||
while (1) {
|
||||
if (poll_count < 10000000) poll_count++;
|
||||
ret = pvr2_encoder_read_words(hdw,!0,rdData,1);
|
||||
if (ret) break;
|
||||
poll_count++;
|
||||
ret = pvr2_encoder_read_words(hdw,MBOX_BASE,rdData,
|
||||
arg_cnt_recv+4);
|
||||
if (ret) {
|
||||
break;
|
||||
}
|
||||
if (rdData[0] & IVTV_MBOX_FIRMWARE_DONE) {
|
||||
break;
|
||||
}
|
||||
if (poll_count == 100) {
|
||||
if (rdData[0] && (poll_count < 1000)) continue;
|
||||
if (!rdData[0]) {
|
||||
retry_flag = !0;
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Encoder timed out waiting for us"
|
||||
"; arranging to retry");
|
||||
} else {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"***WARNING*** device's encoder"
|
||||
" appears to be stuck"
|
||||
" (status=0%08x)",rdData[0]);
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Encoder command: 0x%02x",cmd);
|
||||
for (idx = 4; idx < arg_cnt_send; idx++) {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Encoder arg%d: 0x%08x",
|
||||
idx-3,wrData[idx]);
|
||||
}
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Giving up waiting."
|
||||
" It is likely that"
|
||||
" this is a bad idea...");
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
" (status=0x%08x)",rdData[0]);
|
||||
}
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Encoder command: 0x%02x",cmd);
|
||||
for (idx = 4; idx < arg_cnt_send; idx++) {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Encoder arg%d: 0x%08x",
|
||||
idx-3,wrData[idx]);
|
||||
}
|
||||
ret = -EBUSY;
|
||||
break;
|
||||
}
|
||||
if (retry_flag) {
|
||||
if (try_count < 20) continue;
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Too many retries...");
|
||||
ret = -EBUSY;
|
||||
}
|
||||
if (ret) {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Giving up on command."
|
||||
" It is likely that"
|
||||
" this is a bad idea...");
|
||||
break;
|
||||
}
|
||||
if (ret) break;
|
||||
wrData[0] = 0x7;
|
||||
ret = pvr2_encoder_read_words(
|
||||
hdw,0,rdData,
|
||||
sizeof(rdData)/sizeof(rdData[0]));
|
||||
if (ret) break;
|
||||
for (idx = 0; idx < arg_cnt_recv; idx++) {
|
||||
argp[idx] = rdData[idx+4];
|
||||
}
|
||||
|
||||
wrData[0] = 0x0;
|
||||
ret = pvr2_encoder_write_words(hdw,wrData,1);
|
||||
ret = pvr2_encoder_write_words(hdw,MBOX_BASE,wrData,1);
|
||||
if (ret) break;
|
||||
|
||||
} while(0); LOCK_GIVE(hdw->ctl_lock);
|
||||
@ -269,13 +302,13 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
|
||||
unsigned int idx;
|
||||
u32 data[12];
|
||||
|
||||
if (args > sizeof(data)/sizeof(data[0])) {
|
||||
if (args > ARRAY_SIZE(data)) {
|
||||
pvr2_trace(
|
||||
PVR2_TRACE_ERROR_LEGS,
|
||||
"Failed to write cx23416 command"
|
||||
" - too many arguments"
|
||||
" (was given %u limit %u)",
|
||||
args,(unsigned int)(sizeof(data)/sizeof(data[0])));
|
||||
" (was given %u limit %lu)",
|
||||
args, (long unsigned) ARRAY_SIZE(data));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -288,6 +321,73 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd,
|
||||
return pvr2_encoder_cmd(hdw,cmd,args,0,data);
|
||||
}
|
||||
|
||||
|
||||
/* This implements some extra setup for the encoder that seems to be
|
||||
specific to the PVR USB2 hardware. */
|
||||
int pvr2_encoder_prep_config(struct pvr2_hdw *hdw)
|
||||
{
|
||||
int ret = 0;
|
||||
int encMisc3Arg = 0;
|
||||
|
||||
#if 0
|
||||
/* This inexplicable bit happens in the Hauppage windows
|
||||
driver (for both 24xxx and 29xxx devices). However I
|
||||
currently see no difference in behavior with or without
|
||||
this stuff. Leave this here as a note of its existence,
|
||||
but don't use it. */
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
u32 dat[1];
|
||||
dat[0] = 0x80000640;
|
||||
pvr2_encoder_write_words(hdw,0x01fe,dat,1);
|
||||
pvr2_encoder_write_words(hdw,0x023e,dat,1);
|
||||
} while(0); LOCK_GIVE(hdw->ctl_lock);
|
||||
#endif
|
||||
|
||||
/* Mike Isely <isely@pobox.com> 26-Jan-2006 The windows driver
|
||||
sends the following list of ENC_MISC commands (for both
|
||||
24xxx and 29xxx devices). Meanings are not entirely clear,
|
||||
however without the ENC_MISC(3,1) command then we risk
|
||||
random perpetual video corruption whenever the video input
|
||||
breaks up for a moment (like when switching channels). */
|
||||
|
||||
|
||||
#if 0
|
||||
/* This ENC_MISC(5,0) command seems to hurt 29xxx sync
|
||||
performance on channel changes, but is not a problem on
|
||||
24xxx devices. */
|
||||
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 5,0,0,0);
|
||||
#endif
|
||||
|
||||
/* This ENC_MISC(3,encMisc3Arg) command is critical - without
|
||||
it there will eventually be video corruption. Also, the
|
||||
29xxx case is strange - the Windows driver is passing 1
|
||||
regardless of device type but if we have 1 for 29xxx device
|
||||
the video turns sluggish. */
|
||||
switch (hdw->hdw_type) {
|
||||
case PVR2_HDW_TYPE_24XXX: encMisc3Arg = 1; break;
|
||||
case PVR2_HDW_TYPE_29XXX: encMisc3Arg = 0; break;
|
||||
default: break;
|
||||
}
|
||||
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 3,
|
||||
encMisc3Arg,0,0);
|
||||
|
||||
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 8,0,0,0);
|
||||
|
||||
#if 0
|
||||
/* This ENC_MISC(4,1) command is poisonous, so it is commented
|
||||
out. But I'm leaving it here anyway to document its
|
||||
existence in the Windows driver. The effect of this
|
||||
command is that apps displaying the stream become sluggish
|
||||
with stuttering video. */
|
||||
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 4,1,0,0);
|
||||
#endif
|
||||
|
||||
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4, 0,3,0,0);
|
||||
ret |= pvr2_encoder_vcmd(hdw, CX2341X_ENC_MISC,4,15,0,0,0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pvr2_encoder_configure(struct pvr2_hdw *hdw)
|
||||
{
|
||||
int ret;
|
||||
@ -302,6 +402,8 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
|
||||
|
||||
ret = 0;
|
||||
|
||||
ret |= pvr2_encoder_prep_config(hdw);
|
||||
|
||||
if (!ret) ret = pvr2_encoder_vcmd(
|
||||
hdw,CX2341X_ENC_SET_NUM_VSYNC_LINES, 2,
|
||||
0xf0, 0xf0);
|
||||
@ -360,15 +462,22 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
|
||||
pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
|
||||
pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
|
||||
|
||||
if (hdw->config == pvr2_config_vbi) {
|
||||
pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
|
||||
hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
|
||||
|
||||
switch (hdw->config) {
|
||||
case pvr2_config_vbi:
|
||||
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
|
||||
0x01,0x14);
|
||||
} else if (hdw->config == pvr2_config_mpeg) {
|
||||
break;
|
||||
case pvr2_config_mpeg:
|
||||
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
|
||||
0,0x13);
|
||||
} else {
|
||||
break;
|
||||
default: /* Unhandled cases for now */
|
||||
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_START_CAPTURE,2,
|
||||
0,0x13);
|
||||
break;
|
||||
}
|
||||
if (!status) {
|
||||
hdw->subsys_enabled_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
|
||||
@ -383,15 +492,19 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
|
||||
/* mask all interrupts */
|
||||
pvr2_write_register(hdw, 0x0048, 0xffffffff);
|
||||
|
||||
if (hdw->config == pvr2_config_vbi) {
|
||||
switch (hdw->config) {
|
||||
case pvr2_config_vbi:
|
||||
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
|
||||
0x01,0x01,0x14);
|
||||
} else if (hdw->config == pvr2_config_mpeg) {
|
||||
break;
|
||||
case pvr2_config_mpeg:
|
||||
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
|
||||
0x01,0,0x13);
|
||||
} else {
|
||||
break;
|
||||
default: /* Unhandled cases for now */
|
||||
status = pvr2_encoder_vcmd(hdw,CX2341X_ENC_STOP_CAPTURE,3,
|
||||
0x01,0,0x13);
|
||||
break;
|
||||
}
|
||||
|
||||
/* change some GPIO data */
|
||||
|
62
drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
Normal file
62
drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* Copyright (C) 2007 Michael Krufky <mkrufky@linuxtv.org>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _PVRUSB2_FX2_CMD_H_
|
||||
#define _PVRUSB2_FX2_CMD_H_
|
||||
|
||||
#define FX2CMD_MEM_WRITE_DWORD 0x01
|
||||
#define FX2CMD_MEM_READ_DWORD 0x02
|
||||
|
||||
#define FX2CMD_MEM_READ_64BYTES 0x28
|
||||
|
||||
#define FX2CMD_REG_WRITE 0x04
|
||||
#define FX2CMD_REG_READ 0x05
|
||||
#define FX2CMD_MEMSEL 0x06
|
||||
|
||||
#define FX2CMD_I2C_WRITE 0x08
|
||||
#define FX2CMD_I2C_READ 0x09
|
||||
|
||||
#define FX2CMD_GET_USB_SPEED 0x0b
|
||||
|
||||
#define FX2CMD_STREAMING_ON 0x36
|
||||
#define FX2CMD_STREAMING_OFF 0x37
|
||||
|
||||
#define FX2CMD_FWPOST1 0x52
|
||||
|
||||
#define FX2CMD_POWER_OFF 0xdc
|
||||
#define FX2CMD_POWER_ON 0xde
|
||||
|
||||
#define FX2CMD_DEEP_RESET 0xdd
|
||||
|
||||
#define FX2CMD_GET_EEPROM_ADDR 0xeb
|
||||
#define FX2CMD_GET_IR_CODE 0xec
|
||||
|
||||
#endif /* _PVRUSB2_FX2_CMD_H_ */
|
||||
|
||||
/*
|
||||
Stuff for Emacs to see, in order to encourage consistent editing style:
|
||||
*** Local Variables: ***
|
||||
*** mode: c ***
|
||||
*** fill-column: 75 ***
|
||||
*** tab-width: 8 ***
|
||||
*** c-basic-offset: 8 ***
|
||||
*** End: ***
|
||||
*/
|
@ -60,6 +60,7 @@ struct pvr2_decoder;
|
||||
|
||||
typedef int (*pvr2_ctlf_is_dirty)(struct pvr2_ctrl *);
|
||||
typedef void (*pvr2_ctlf_clear_dirty)(struct pvr2_ctrl *);
|
||||
typedef int (*pvr2_ctlf_check_value)(struct pvr2_ctrl *,int);
|
||||
typedef int (*pvr2_ctlf_get_value)(struct pvr2_ctrl *,int *);
|
||||
typedef int (*pvr2_ctlf_set_value)(struct pvr2_ctrl *,int msk,int val);
|
||||
typedef int (*pvr2_ctlf_val_to_sym)(struct pvr2_ctrl *,int msk,int val,
|
||||
@ -83,6 +84,7 @@ struct pvr2_ctl_info {
|
||||
pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
|
||||
pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
|
||||
pvr2_ctlf_set_value set_value; /* Set its value */
|
||||
pvr2_ctlf_check_value check_value; /* Check that value is valid */
|
||||
pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
|
||||
pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
|
||||
pvr2_ctlf_is_dirty is_dirty; /* Return true if dirty */
|
||||
@ -135,17 +137,10 @@ struct pvr2_ctrl {
|
||||
};
|
||||
|
||||
|
||||
struct pvr2_audio_stat {
|
||||
void *ctxt;
|
||||
void (*detach)(void *);
|
||||
int (*status)(void *);
|
||||
};
|
||||
|
||||
struct pvr2_decoder_ctrl {
|
||||
void *ctxt;
|
||||
void (*detach)(void *);
|
||||
void (*enable)(void *,int);
|
||||
int (*tuned)(void *);
|
||||
void (*force_reset)(void *);
|
||||
};
|
||||
|
||||
@ -212,7 +207,6 @@ struct pvr2_hdw {
|
||||
/* Frequency table */
|
||||
unsigned int freqTable[FREQTABLE_SIZE];
|
||||
unsigned int freqProgSlot;
|
||||
unsigned int freqSlot;
|
||||
|
||||
/* Stuff for handling low level control interaction with device */
|
||||
struct mutex ctl_lock_mutex;
|
||||
@ -258,9 +252,17 @@ struct pvr2_hdw {
|
||||
/* Tuner / frequency control stuff */
|
||||
unsigned int tuner_type;
|
||||
int tuner_updated;
|
||||
unsigned int freqVal;
|
||||
unsigned int freqValTelevision; /* Current freq for tv mode */
|
||||
unsigned int freqValRadio; /* Current freq for radio mode */
|
||||
unsigned int freqSlotTelevision; /* Current slot for tv mode */
|
||||
unsigned int freqSlotRadio; /* Current slot for radio mode */
|
||||
unsigned int freqSelector; /* 0=radio 1=television */
|
||||
int freqDirty;
|
||||
|
||||
/* Current tuner info - this information is polled from the I2C bus */
|
||||
struct v4l2_tuner tuner_signal_info;
|
||||
int tuner_signal_stale;
|
||||
|
||||
/* Video standard handling */
|
||||
v4l2_std_id std_mask_eeprom; // Hardware supported selections
|
||||
v4l2_std_id std_mask_avail; // Which standards we may select from
|
||||
@ -281,20 +283,17 @@ struct pvr2_hdw {
|
||||
int unit_number; /* ID for driver instance */
|
||||
unsigned long serial_number; /* ID for hardware itself */
|
||||
|
||||
/* Minor number used by v4l logic (yes, this is a hack, as there should
|
||||
be no v4l junk here). Probably a better way to do this. */
|
||||
int v4l_minor_number;
|
||||
/* Minor numbers used by v4l logic (yes, this is a hack, as there
|
||||
should be no v4l junk here). Probably a better way to do this. */
|
||||
int v4l_minor_number_video;
|
||||
int v4l_minor_number_vbi;
|
||||
int v4l_minor_number_radio;
|
||||
|
||||
/* Location of eeprom or a negative number if none */
|
||||
int eeprom_addr;
|
||||
|
||||
enum pvr2_config config;
|
||||
|
||||
/* Information about what audio signal we're hearing */
|
||||
int flag_stereo;
|
||||
int flag_bilingual;
|
||||
struct pvr2_audio_stat *audio_stat;
|
||||
|
||||
/* Control state needed for cx2341x module */
|
||||
struct cx2341x_mpeg_params enc_cur_state;
|
||||
struct cx2341x_mpeg_params enc_ctl_state;
|
||||
@ -327,6 +326,9 @@ struct pvr2_hdw {
|
||||
unsigned int control_cnt;
|
||||
};
|
||||
|
||||
/* This function gets the current frequency */
|
||||
unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
|
||||
|
||||
#endif /* __PVRUSB2_HDW_INTERNAL_H */
|
||||
|
||||
/*
|
||||
|
@ -36,6 +36,10 @@
|
||||
#include "pvrusb2-hdw-internal.h"
|
||||
#include "pvrusb2-encoder.h"
|
||||
#include "pvrusb2-debug.h"
|
||||
#include "pvrusb2-fx2-cmd.h"
|
||||
|
||||
#define TV_MIN_FREQ 55250000L
|
||||
#define TV_MAX_FREQ 850000000L
|
||||
|
||||
struct usb_device_id pvr2_device_table[] = {
|
||||
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
|
||||
@ -71,12 +75,10 @@ static const char *pvr2_client_29xxx[] = {
|
||||
|
||||
static struct pvr2_string_table pvr2_client_lists[] = {
|
||||
[PVR2_HDW_TYPE_29XXX] = {
|
||||
pvr2_client_29xxx,
|
||||
sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
|
||||
pvr2_client_29xxx, ARRAY_SIZE(pvr2_client_29xxx)
|
||||
},
|
||||
[PVR2_HDW_TYPE_24XXX] = {
|
||||
pvr2_client_24xxx,
|
||||
sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
|
||||
pvr2_client_24xxx, ARRAY_SIZE(pvr2_client_24xxx)
|
||||
},
|
||||
};
|
||||
|
||||
@ -159,9 +161,6 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
|
||||
},{
|
||||
.strid = "video_gop_closure",
|
||||
.id = V4L2_CID_MPEG_VIDEO_GOP_CLOSURE,
|
||||
},{
|
||||
.strid = "video_pulldown",
|
||||
.id = V4L2_CID_MPEG_VIDEO_PULLDOWN,
|
||||
},{
|
||||
.strid = "video_bitrate_mode",
|
||||
.id = V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
|
||||
@ -212,7 +211,7 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
|
||||
.id = V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
|
||||
}
|
||||
};
|
||||
#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
|
||||
#define MPEGDEF_COUNT ARRAY_SIZE(mpeg_ids)
|
||||
|
||||
|
||||
static const char *control_values_srate[] = {
|
||||
@ -255,10 +254,10 @@ static const char *control_values_subsystem[] = {
|
||||
[PVR2_SUBSYS_B_ENC_RUN] = "enc_run",
|
||||
};
|
||||
|
||||
static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
|
||||
static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl);
|
||||
static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw);
|
||||
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw);
|
||||
static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw);
|
||||
static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
|
||||
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
|
||||
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw);
|
||||
@ -272,8 +271,6 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
|
||||
unsigned int timeout,int probe_fl,
|
||||
void *write_data,unsigned int write_len,
|
||||
void *read_data,unsigned int read_len);
|
||||
static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res);
|
||||
static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res);
|
||||
|
||||
static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
{
|
||||
@ -289,8 +286,21 @@ static int ctrl_channelfreq_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
static int ctrl_channelfreq_set(struct pvr2_ctrl *cptr,int m,int v)
|
||||
{
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
if ((hdw->freqProgSlot > 0) && (hdw->freqProgSlot <= FREQTABLE_SIZE)) {
|
||||
hdw->freqTable[hdw->freqProgSlot-1] = v;
|
||||
unsigned int slotId = hdw->freqProgSlot;
|
||||
if ((slotId > 0) && (slotId <= FREQTABLE_SIZE)) {
|
||||
hdw->freqTable[slotId-1] = v;
|
||||
/* Handle side effects correctly - if we're tuned to this
|
||||
slot, then forgot the slot id relation since the stored
|
||||
frequency has been changed. */
|
||||
if (hdw->freqSelector) {
|
||||
if (hdw->freqSlotRadio == slotId) {
|
||||
hdw->freqSlotRadio = 0;
|
||||
}
|
||||
} else {
|
||||
if (hdw->freqSlotTelevision == slotId) {
|
||||
hdw->freqSlotTelevision = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -312,28 +322,32 @@ static int ctrl_channelprog_set(struct pvr2_ctrl *cptr,int m,int v)
|
||||
|
||||
static int ctrl_channel_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
{
|
||||
*vp = cptr->hdw->freqSlot;
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
*vp = hdw->freqSelector ? hdw->freqSlotRadio : hdw->freqSlotTelevision;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int v)
|
||||
static int ctrl_channel_set(struct pvr2_ctrl *cptr,int m,int slotId)
|
||||
{
|
||||
unsigned freq = 0;
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
hdw->freqSlot = v;
|
||||
if ((hdw->freqSlot > 0) && (hdw->freqSlot <= FREQTABLE_SIZE)) {
|
||||
freq = hdw->freqTable[hdw->freqSlot-1];
|
||||
if ((slotId < 0) || (slotId > FREQTABLE_SIZE)) return 0;
|
||||
if (slotId > 0) {
|
||||
freq = hdw->freqTable[slotId-1];
|
||||
if (!freq) return 0;
|
||||
pvr2_hdw_set_cur_freq(hdw,freq);
|
||||
}
|
||||
if (freq && (freq != hdw->freqVal)) {
|
||||
hdw->freqVal = freq;
|
||||
hdw->freqDirty = !0;
|
||||
if (hdw->freqSelector) {
|
||||
hdw->freqSlotRadio = slotId;
|
||||
} else {
|
||||
hdw->freqSlotTelevision = slotId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_freq_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
{
|
||||
*vp = cptr->hdw->freqVal;
|
||||
*vp = pvr2_hdw_get_cur_freq(cptr->hdw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -349,10 +363,7 @@ static void ctrl_freq_clear_dirty(struct pvr2_ctrl *cptr)
|
||||
|
||||
static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
|
||||
{
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
hdw->freqVal = v;
|
||||
hdw->freqDirty = !0;
|
||||
hdw->freqSlot = 0;
|
||||
pvr2_hdw_set_cur_freq(cptr->hdw,v);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -378,6 +389,89 @@ static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
|
||||
{
|
||||
*vp = cptr->hdw->input_val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
|
||||
{
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
|
||||
if (hdw->input_val != v) {
|
||||
hdw->input_val = v;
|
||||
hdw->input_dirty = !0;
|
||||
}
|
||||
|
||||
/* Handle side effects - if we switch to a mode that needs the RF
|
||||
tuner, then select the right frequency choice as well and mark
|
||||
it dirty. */
|
||||
if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
|
||||
hdw->freqSelector = 0;
|
||||
hdw->freqDirty = !0;
|
||||
} else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
|
||||
hdw->freqSelector = 1;
|
||||
hdw->freqDirty = !0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
|
||||
{
|
||||
return cptr->hdw->input_dirty != 0;
|
||||
}
|
||||
|
||||
static void ctrl_cleardirty_input(struct pvr2_ctrl *cptr)
|
||||
{
|
||||
cptr->hdw->input_dirty = 0;
|
||||
}
|
||||
|
||||
|
||||
static int ctrl_freq_max_get(struct pvr2_ctrl *cptr, int *vp)
|
||||
{
|
||||
unsigned long fv;
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
if (hdw->tuner_signal_stale) {
|
||||
pvr2_i2c_core_status_poll(hdw);
|
||||
}
|
||||
fv = hdw->tuner_signal_info.rangehigh;
|
||||
if (!fv) {
|
||||
/* Safety fallback */
|
||||
*vp = TV_MAX_FREQ;
|
||||
return 0;
|
||||
}
|
||||
if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
|
||||
fv = (fv * 125) / 2;
|
||||
} else {
|
||||
fv = fv * 62500;
|
||||
}
|
||||
*vp = fv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_freq_min_get(struct pvr2_ctrl *cptr, int *vp)
|
||||
{
|
||||
unsigned long fv;
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
if (hdw->tuner_signal_stale) {
|
||||
pvr2_i2c_core_status_poll(hdw);
|
||||
}
|
||||
fv = hdw->tuner_signal_info.rangelow;
|
||||
if (!fv) {
|
||||
/* Safety fallback */
|
||||
*vp = TV_MIN_FREQ;
|
||||
return 0;
|
||||
}
|
||||
if (hdw->tuner_signal_info.capability & V4L2_TUNER_CAP_LOW) {
|
||||
fv = (fv * 125) / 2;
|
||||
} else {
|
||||
fv = fv * 62500;
|
||||
}
|
||||
*vp = fv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
|
||||
{
|
||||
return cptr->hdw->enc_stale != 0;
|
||||
@ -534,8 +628,32 @@ static void ctrl_stdcur_clear_dirty(struct pvr2_ctrl *cptr)
|
||||
|
||||
static int ctrl_signal_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
{
|
||||
*vp = ((pvr2_hdw_get_signal_status_internal(cptr->hdw) &
|
||||
PVR2_SIGNAL_OK) ? 1 : 0);
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
pvr2_i2c_core_status_poll(hdw);
|
||||
*vp = hdw->tuner_signal_info.signal;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ctrl_audio_modes_present_get(struct pvr2_ctrl *cptr,int *vp)
|
||||
{
|
||||
int val = 0;
|
||||
unsigned int subchan;
|
||||
struct pvr2_hdw *hdw = cptr->hdw;
|
||||
pvr2_i2c_core_status_poll(hdw);
|
||||
subchan = hdw->tuner_signal_info.rxsubchans;
|
||||
if (subchan & V4L2_TUNER_SUB_MONO) {
|
||||
val |= (1 << V4L2_TUNER_MODE_MONO);
|
||||
}
|
||||
if (subchan & V4L2_TUNER_SUB_STEREO) {
|
||||
val |= (1 << V4L2_TUNER_MODE_STEREO);
|
||||
}
|
||||
if (subchan & V4L2_TUNER_SUB_LANG1) {
|
||||
val |= (1 << V4L2_TUNER_MODE_LANG1);
|
||||
}
|
||||
if (subchan & V4L2_TUNER_SUB_LANG2) {
|
||||
val |= (1 << V4L2_TUNER_MODE_LANG2);
|
||||
}
|
||||
*vp = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -604,7 +722,7 @@ static void ctrl_stdenumcur_clear_dirty(struct pvr2_ctrl *cptr)
|
||||
|
||||
#define DEFENUM(tab) \
|
||||
.type = pvr2_ctl_enum, \
|
||||
.def.type_enum.count = (sizeof(tab)/sizeof((tab)[0])), \
|
||||
.def.type_enum.count = ARRAY_SIZE(tab), \
|
||||
.def.type_enum.value_names = tab
|
||||
|
||||
#define DEFBOOL \
|
||||
@ -641,15 +759,11 @@ VCREATE_FUNCS(balance)
|
||||
VCREATE_FUNCS(bass)
|
||||
VCREATE_FUNCS(treble)
|
||||
VCREATE_FUNCS(mute)
|
||||
VCREATE_FUNCS(input)
|
||||
VCREATE_FUNCS(audiomode)
|
||||
VCREATE_FUNCS(res_hor)
|
||||
VCREATE_FUNCS(res_ver)
|
||||
VCREATE_FUNCS(srate)
|
||||
|
||||
#define MIN_FREQ 55250000L
|
||||
#define MAX_FREQ 850000000L
|
||||
|
||||
/* Table definition of all controls which can be manipulated */
|
||||
static const struct pvr2_ctl_info control_defs[] = {
|
||||
{
|
||||
@ -684,7 +798,7 @@ static const struct pvr2_ctl_info control_defs[] = {
|
||||
.v4l_id = V4L2_CID_AUDIO_VOLUME,
|
||||
.desc = "Volume",
|
||||
.name = "volume",
|
||||
.default_value = 65535,
|
||||
.default_value = 62000,
|
||||
DEFREF(volume),
|
||||
DEFINT(0,65535),
|
||||
},{
|
||||
@ -758,12 +872,16 @@ static const struct pvr2_ctl_info control_defs[] = {
|
||||
.desc = "Tuner Frequency (Hz)",
|
||||
.name = "frequency",
|
||||
.internal_id = PVR2_CID_FREQUENCY,
|
||||
.default_value = 175250000L,
|
||||
.default_value = 0,
|
||||
.set_value = ctrl_freq_set,
|
||||
.get_value = ctrl_freq_get,
|
||||
.is_dirty = ctrl_freq_is_dirty,
|
||||
.clear_dirty = ctrl_freq_clear_dirty,
|
||||
DEFINT(MIN_FREQ,MAX_FREQ),
|
||||
DEFINT(0,0),
|
||||
/* Hook in check for input value (tv/radio) and adjust
|
||||
max/min values accordingly */
|
||||
.get_max_value = ctrl_freq_max_get,
|
||||
.get_min_value = ctrl_freq_min_get,
|
||||
},{
|
||||
.desc = "Channel",
|
||||
.name = "channel",
|
||||
@ -775,7 +893,11 @@ static const struct pvr2_ctl_info control_defs[] = {
|
||||
.name = "freq_table_value",
|
||||
.set_value = ctrl_channelfreq_set,
|
||||
.get_value = ctrl_channelfreq_get,
|
||||
DEFINT(MIN_FREQ,MAX_FREQ),
|
||||
DEFINT(0,0),
|
||||
/* Hook in check for input value (tv/radio) and adjust
|
||||
max/min values accordingly */
|
||||
.get_max_value = ctrl_freq_max_get,
|
||||
.get_min_value = ctrl_freq_min_get,
|
||||
},{
|
||||
.desc = "Channel Program ID",
|
||||
.name = "freq_table_channel",
|
||||
@ -796,7 +918,20 @@ static const struct pvr2_ctl_info control_defs[] = {
|
||||
.desc = "Signal Present",
|
||||
.name = "signal_present",
|
||||
.get_value = ctrl_signal_get,
|
||||
DEFBOOL,
|
||||
DEFINT(0,65535),
|
||||
},{
|
||||
.desc = "Audio Modes Present",
|
||||
.name = "audio_modes_present",
|
||||
.get_value = ctrl_audio_modes_present_get,
|
||||
/* For this type we "borrow" the V4L2_TUNER_MODE enum from
|
||||
v4l. Nothing outside of this module cares about this,
|
||||
but I reuse it in order to also reuse the
|
||||
control_values_audiomode string table. */
|
||||
DEFMASK(((1 << V4L2_TUNER_MODE_MONO)|
|
||||
(1 << V4L2_TUNER_MODE_STEREO)|
|
||||
(1 << V4L2_TUNER_MODE_LANG1)|
|
||||
(1 << V4L2_TUNER_MODE_LANG2)),
|
||||
control_values_audiomode),
|
||||
},{
|
||||
.desc = "Video Standards Available Mask",
|
||||
.name = "video_standard_mask_available",
|
||||
@ -846,7 +981,7 @@ static const struct pvr2_ctl_info control_defs[] = {
|
||||
}
|
||||
};
|
||||
|
||||
#define CTRLDEF_COUNT (sizeof(control_defs)/sizeof(control_defs[0]))
|
||||
#define CTRLDEF_COUNT ARRAY_SIZE(control_defs)
|
||||
|
||||
|
||||
const char *pvr2_config_get_name(enum pvr2_config cfg)
|
||||
@ -855,7 +990,8 @@ const char *pvr2_config_get_name(enum pvr2_config cfg)
|
||||
case pvr2_config_empty: return "empty";
|
||||
case pvr2_config_mpeg: return "mpeg";
|
||||
case pvr2_config_vbi: return "vbi";
|
||||
case pvr2_config_radio: return "radio";
|
||||
case pvr2_config_pcm: return "pcm";
|
||||
case pvr2_config_rawvideo: return "raw video";
|
||||
}
|
||||
return "<unknown>";
|
||||
}
|
||||
@ -872,6 +1008,40 @@ unsigned long pvr2_hdw_get_sn(struct pvr2_hdw *hdw)
|
||||
return hdw->serial_number;
|
||||
}
|
||||
|
||||
unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
|
||||
{
|
||||
return hdw->freqSelector ? hdw->freqValTelevision : hdw->freqValRadio;
|
||||
}
|
||||
|
||||
/* Set the currently tuned frequency and account for all possible
|
||||
driver-core side effects of this action. */
|
||||
void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
|
||||
{
|
||||
if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
|
||||
if (hdw->freqSelector) {
|
||||
/* Swing over to radio frequency selection */
|
||||
hdw->freqSelector = 0;
|
||||
hdw->freqDirty = !0;
|
||||
}
|
||||
if (hdw->freqValRadio != val) {
|
||||
hdw->freqValRadio = val;
|
||||
hdw->freqSlotRadio = 0;
|
||||
hdw->freqDirty = !0;
|
||||
}
|
||||
} else {
|
||||
if (!(hdw->freqSelector)) {
|
||||
/* Swing over to television frequency selection */
|
||||
hdw->freqSelector = 1;
|
||||
hdw->freqDirty = !0;
|
||||
}
|
||||
if (hdw->freqValTelevision != val) {
|
||||
hdw->freqValTelevision = val;
|
||||
hdw->freqSlotTelevision = 0;
|
||||
hdw->freqDirty = !0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pvr2_hdw_get_unit_number(struct pvr2_hdw *hdw)
|
||||
{
|
||||
return hdw->unit_number;
|
||||
@ -960,12 +1130,10 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
|
||||
};
|
||||
static const struct pvr2_string_table fw_file_defs[] = {
|
||||
[PVR2_HDW_TYPE_29XXX] = {
|
||||
fw_files_29xxx,
|
||||
sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
|
||||
fw_files_29xxx, ARRAY_SIZE(fw_files_29xxx)
|
||||
},
|
||||
[PVR2_HDW_TYPE_24XXX] = {
|
||||
fw_files_24xxx,
|
||||
sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
|
||||
fw_files_24xxx, ARRAY_SIZE(fw_files_24xxx)
|
||||
},
|
||||
};
|
||||
hdw->fw1_state = FW1_STATE_FAILED; // default result
|
||||
@ -1041,7 +1209,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
|
||||
{
|
||||
const struct firmware *fw_entry = NULL;
|
||||
void *fw_ptr;
|
||||
unsigned int pipe, fw_len, fw_done;
|
||||
unsigned int pipe, fw_len, fw_done, bcnt, icnt;
|
||||
int actual_length;
|
||||
int ret = 0;
|
||||
int fwidx;
|
||||
@ -1052,8 +1220,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
|
||||
trace_firmware("pvr2_upload_firmware2");
|
||||
|
||||
ret = pvr2_locate_firmware(hdw,&fw_entry,"encoder",
|
||||
sizeof(fw_files)/sizeof(fw_files[0]),
|
||||
fw_files);
|
||||
ARRAY_SIZE(fw_files), fw_files);
|
||||
if (ret < 0) return ret;
|
||||
fwidx = ret;
|
||||
ret = 0;
|
||||
@ -1079,8 +1246,13 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
|
||||
ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
|
||||
ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
|
||||
ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
|
||||
ret |= pvr2_write_u8(hdw, 0x52, 0);
|
||||
ret |= pvr2_write_u16(hdw, 0x0600, 0);
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
|
||||
ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,0,0);
|
||||
hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
|
||||
hdw->cmd_buffer[1] = 0;
|
||||
ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
|
||||
} while (0); LOCK_GIVE(hdw->ctl_lock);
|
||||
|
||||
if (ret) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
@ -1093,11 +1265,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
|
||||
|
||||
fw_len = fw_entry->size;
|
||||
|
||||
if (fw_len % FIRMWARE_CHUNK_SIZE) {
|
||||
if (fw_len % sizeof(u32)) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
"size of %s firmware"
|
||||
" must be a multiple of 8192B",
|
||||
fw_files[fwidx]);
|
||||
" must be a multiple of %u bytes",
|
||||
fw_files[fwidx],sizeof(u32));
|
||||
release_firmware(fw_entry);
|
||||
return -1;
|
||||
}
|
||||
@ -1112,18 +1284,21 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
|
||||
|
||||
pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
|
||||
|
||||
for (fw_done = 0 ; (fw_done < fw_len) && !ret ;
|
||||
fw_done += FIRMWARE_CHUNK_SIZE ) {
|
||||
int i;
|
||||
memcpy(fw_ptr, fw_entry->data + fw_done, FIRMWARE_CHUNK_SIZE);
|
||||
/* Usbsnoop log shows that we must swap bytes... */
|
||||
for (i = 0; i < FIRMWARE_CHUNK_SIZE/4 ; i++)
|
||||
((u32 *)fw_ptr)[i] = ___swab32(((u32 *)fw_ptr)[i]);
|
||||
fw_done = 0;
|
||||
for (fw_done = 0; fw_done < fw_len;) {
|
||||
bcnt = fw_len - fw_done;
|
||||
if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE;
|
||||
memcpy(fw_ptr, fw_entry->data + fw_done, bcnt);
|
||||
/* Usbsnoop log shows that we must swap bytes... */
|
||||
for (icnt = 0; icnt < bcnt/4 ; icnt++)
|
||||
((u32 *)fw_ptr)[icnt] =
|
||||
___swab32(((u32 *)fw_ptr)[icnt]);
|
||||
|
||||
ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,
|
||||
FIRMWARE_CHUNK_SIZE,
|
||||
ret |= usb_bulk_msg(hdw->usb_dev, pipe, fw_ptr,bcnt,
|
||||
&actual_length, HZ);
|
||||
ret |= (actual_length != FIRMWARE_CHUNK_SIZE);
|
||||
ret |= (actual_length != bcnt);
|
||||
if (ret) break;
|
||||
fw_done += bcnt;
|
||||
}
|
||||
|
||||
trace_firmware("upload of %s : %i / %i ",
|
||||
@ -1142,7 +1317,11 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
|
||||
|
||||
ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
|
||||
ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
|
||||
ret |= pvr2_write_u16(hdw, 0x0600, 0);
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
|
||||
hdw->cmd_buffer[1] = 0;
|
||||
ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,0,0);
|
||||
} while (0); LOCK_GIVE(hdw->ctl_lock);
|
||||
|
||||
if (ret) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
@ -1479,7 +1658,7 @@ static int pvr2_hdw_check_firmware(struct pvr2_hdw *hdw)
|
||||
firmware needs be loaded. */
|
||||
int result;
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
hdw->cmd_buffer[0] = 0xeb;
|
||||
hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
|
||||
result = pvr2_send_request_ex(hdw,HZ*1,!0,
|
||||
hdw->cmd_buffer,1,
|
||||
hdw->cmd_buffer,1);
|
||||
@ -1611,6 +1790,16 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
|
||||
cptr->info->set_value(cptr,~0,cptr->info->default_value);
|
||||
}
|
||||
|
||||
/* Set up special default values for the television and radio
|
||||
frequencies here. It's not really important what these defaults
|
||||
are, but I set them to something usable in the Chicago area just
|
||||
to make driver testing a little easier. */
|
||||
|
||||
/* US Broadcast channel 7 (175.25 MHz) */
|
||||
hdw->freqValTelevision = 175250000L;
|
||||
/* 104.3 MHz, a usable FM station for my area */
|
||||
hdw->freqValRadio = 104300000L;
|
||||
|
||||
// Do not use pvr2_reset_ctl_endpoints() here. It is not
|
||||
// thread-safe against the normal pvr2_send_request() mechanism.
|
||||
// (We should make it thread safe).
|
||||
@ -1750,26 +1939,24 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
||||
struct pvr2_ctl_info *ciptr;
|
||||
|
||||
hdw_type = devid - pvr2_device_table;
|
||||
if (hdw_type >=
|
||||
sizeof(pvr2_device_names)/sizeof(pvr2_device_names[0])) {
|
||||
if (hdw_type >= ARRAY_SIZE(pvr2_device_names)) {
|
||||
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
|
||||
"Bogus device type of %u reported",hdw_type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdw = kmalloc(sizeof(*hdw),GFP_KERNEL);
|
||||
hdw = kzalloc(sizeof(*hdw),GFP_KERNEL);
|
||||
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"",
|
||||
hdw,pvr2_device_names[hdw_type]);
|
||||
if (!hdw) goto fail;
|
||||
memset(hdw,0,sizeof(*hdw));
|
||||
hdw->tuner_signal_stale = !0;
|
||||
cx2341x_fill_defaults(&hdw->enc_ctl_state);
|
||||
|
||||
hdw->control_cnt = CTRLDEF_COUNT;
|
||||
hdw->control_cnt += MPEGDEF_COUNT;
|
||||
hdw->controls = kmalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
|
||||
hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
|
||||
GFP_KERNEL);
|
||||
if (!hdw->controls) goto fail;
|
||||
memset(hdw->controls,0,sizeof(struct pvr2_ctrl) * hdw->control_cnt);
|
||||
hdw->hdw_type = hdw_type;
|
||||
for (idx = 0; idx < hdw->control_cnt; idx++) {
|
||||
cptr = hdw->controls + idx;
|
||||
@ -1783,11 +1970,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
||||
cptr->info = control_defs+idx;
|
||||
}
|
||||
/* Define and configure additional controls from cx2341x module. */
|
||||
hdw->mpeg_ctrl_info = kmalloc(
|
||||
hdw->mpeg_ctrl_info = kzalloc(
|
||||
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
|
||||
if (!hdw->mpeg_ctrl_info) goto fail;
|
||||
memset(hdw->mpeg_ctrl_info,0,
|
||||
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT);
|
||||
for (idx = 0; idx < MPEGDEF_COUNT; idx++) {
|
||||
cptr = hdw->controls + idx + CTRLDEF_COUNT;
|
||||
ciptr = &(hdw->mpeg_ctrl_info[idx].info);
|
||||
@ -1872,7 +2057,9 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
||||
|
||||
hdw->eeprom_addr = -1;
|
||||
hdw->unit_number = -1;
|
||||
hdw->v4l_minor_number = -1;
|
||||
hdw->v4l_minor_number_video = -1;
|
||||
hdw->v4l_minor_number_vbi = -1;
|
||||
hdw->v4l_minor_number_radio = -1;
|
||||
hdw->ctl_write_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
|
||||
if (!hdw->ctl_write_buffer) goto fail;
|
||||
hdw->ctl_read_buffer = kmalloc(PVR2_CTL_BUFFSIZE,GFP_KERNEL);
|
||||
@ -1929,10 +2116,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
|
||||
if (hdw) {
|
||||
usb_free_urb(hdw->ctl_read_urb);
|
||||
usb_free_urb(hdw->ctl_write_urb);
|
||||
if (hdw->ctl_read_buffer) kfree(hdw->ctl_read_buffer);
|
||||
if (hdw->ctl_write_buffer) kfree(hdw->ctl_write_buffer);
|
||||
if (hdw->controls) kfree(hdw->controls);
|
||||
if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
|
||||
kfree(hdw->ctl_read_buffer);
|
||||
kfree(hdw->ctl_write_buffer);
|
||||
kfree(hdw->controls);
|
||||
kfree(hdw->mpeg_ctrl_info);
|
||||
kfree(hdw);
|
||||
}
|
||||
return NULL;
|
||||
@ -1982,9 +2169,6 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
|
||||
pvr2_stream_destroy(hdw->vid_stream);
|
||||
hdw->vid_stream = NULL;
|
||||
}
|
||||
if (hdw->audio_stat) {
|
||||
hdw->audio_stat->detach(hdw->audio_stat->ctxt);
|
||||
}
|
||||
if (hdw->decoder_ctrl) {
|
||||
hdw->decoder_ctrl->detach(hdw->decoder_ctrl->ctxt);
|
||||
}
|
||||
@ -1997,10 +2181,10 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
|
||||
unit_pointers[hdw->unit_number] = NULL;
|
||||
}
|
||||
} while (0); up(&pvr2_unit_sem);
|
||||
if (hdw->controls) kfree(hdw->controls);
|
||||
if (hdw->mpeg_ctrl_info) kfree(hdw->mpeg_ctrl_info);
|
||||
if (hdw->std_defs) kfree(hdw->std_defs);
|
||||
if (hdw->std_enum_names) kfree(hdw->std_enum_names);
|
||||
kfree(hdw->controls);
|
||||
kfree(hdw->mpeg_ctrl_info);
|
||||
kfree(hdw->std_defs);
|
||||
kfree(hdw->std_enum_names);
|
||||
kfree(hdw);
|
||||
}
|
||||
|
||||
@ -2210,10 +2394,9 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
|
||||
cptr = hdw->controls + idx;
|
||||
if (cptr->info->is_dirty == 0) continue;
|
||||
if (!cptr->info->is_dirty(cptr)) continue;
|
||||
if (!commit_flag) {
|
||||
commit_flag = !0;
|
||||
}
|
||||
commit_flag = !0;
|
||||
|
||||
if (!(pvrusb2_debug & PVR2_TRACE_CTL)) continue;
|
||||
bcnt = scnprintf(buf,sizeof(buf),"\"%s\" <-- ",
|
||||
cptr->info->name);
|
||||
value = 0;
|
||||
@ -2263,6 +2446,13 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
|
||||
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
|
||||
}
|
||||
|
||||
if (hdw->input_dirty) {
|
||||
/* pk: If input changes to or from radio, then the encoder
|
||||
needs to be restarted (for ENC_MUTE_VIDEO to work) */
|
||||
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_RUN);
|
||||
}
|
||||
|
||||
|
||||
if (hdw->srate_dirty) {
|
||||
/* Write new sample rate into control structure since
|
||||
* the master copy is stale. We must track srate
|
||||
@ -2343,39 +2533,11 @@ const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
|
||||
}
|
||||
|
||||
|
||||
/* Return bit mask indicating signal status */
|
||||
static unsigned int pvr2_hdw_get_signal_status_internal(struct pvr2_hdw *hdw)
|
||||
{
|
||||
unsigned int msk = 0;
|
||||
switch (hdw->input_val) {
|
||||
case PVR2_CVAL_INPUT_TV:
|
||||
case PVR2_CVAL_INPUT_RADIO:
|
||||
if (hdw->decoder_ctrl &&
|
||||
hdw->decoder_ctrl->tuned(hdw->decoder_ctrl->ctxt)) {
|
||||
msk |= PVR2_SIGNAL_OK;
|
||||
if (hdw->audio_stat &&
|
||||
hdw->audio_stat->status(hdw->audio_stat->ctxt)) {
|
||||
if (hdw->flag_stereo) {
|
||||
msk |= PVR2_SIGNAL_STEREO;
|
||||
}
|
||||
if (hdw->flag_bilingual) {
|
||||
msk |= PVR2_SIGNAL_SAP;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
msk |= PVR2_SIGNAL_OK | PVR2_SIGNAL_STEREO;
|
||||
}
|
||||
return msk;
|
||||
}
|
||||
|
||||
|
||||
int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
|
||||
{
|
||||
int result;
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
hdw->cmd_buffer[0] = 0x0b;
|
||||
hdw->cmd_buffer[0] = FX2CMD_GET_USB_SPEED;
|
||||
result = pvr2_send_request(hdw,
|
||||
hdw->cmd_buffer,1,
|
||||
hdw->cmd_buffer,1);
|
||||
@ -2386,14 +2548,25 @@ int pvr2_hdw_is_hsm(struct pvr2_hdw *hdw)
|
||||
}
|
||||
|
||||
|
||||
/* Return bit mask indicating signal status */
|
||||
unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *hdw)
|
||||
/* Execute poll of tuner status */
|
||||
void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw)
|
||||
{
|
||||
unsigned int msk = 0;
|
||||
LOCK_TAKE(hdw->big_lock); do {
|
||||
msk = pvr2_hdw_get_signal_status_internal(hdw);
|
||||
pvr2_i2c_core_status_poll(hdw);
|
||||
} while (0); LOCK_GIVE(hdw->big_lock);
|
||||
return msk;
|
||||
}
|
||||
|
||||
|
||||
/* Return information about the tuner */
|
||||
int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp)
|
||||
{
|
||||
LOCK_TAKE(hdw->big_lock); do {
|
||||
if (hdw->tuner_signal_stale) {
|
||||
pvr2_i2c_core_status_poll(hdw);
|
||||
}
|
||||
memcpy(vtp,&hdw->tuner_signal_info,sizeof(struct v4l2_tuner));
|
||||
} while (0); LOCK_GIVE(hdw->big_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -2442,14 +2615,12 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, int enable_flag)
|
||||
pvr2_trace(PVR2_TRACE_FIRMWARE,
|
||||
"Preparing to suck out CPU firmware");
|
||||
hdw->fw_size = 0x2000;
|
||||
hdw->fw_buffer = kmalloc(hdw->fw_size,GFP_KERNEL);
|
||||
hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL);
|
||||
if (!hdw->fw_buffer) {
|
||||
hdw->fw_size = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
memset(hdw->fw_buffer,0,hdw->fw_size);
|
||||
|
||||
/* We have to hold the CPU during firmware upload. */
|
||||
pvr2_hdw_cpureset_assert(hdw,1);
|
||||
|
||||
@ -2513,16 +2684,28 @@ int pvr2_hdw_cpufw_get(struct pvr2_hdw *hdw,unsigned int offs,
|
||||
}
|
||||
|
||||
|
||||
int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw)
|
||||
int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *hdw,
|
||||
enum pvr2_v4l_type index)
|
||||
{
|
||||
return hdw->v4l_minor_number;
|
||||
switch (index) {
|
||||
case pvr2_v4l_type_video: return hdw->v4l_minor_number_video;
|
||||
case pvr2_v4l_type_vbi: return hdw->v4l_minor_number_vbi;
|
||||
case pvr2_v4l_type_radio: return hdw->v4l_minor_number_radio;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Store the v4l minor device number */
|
||||
void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
|
||||
/* Store a v4l minor device number */
|
||||
void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,
|
||||
enum pvr2_v4l_type index,int v)
|
||||
{
|
||||
hdw->v4l_minor_number = v;
|
||||
switch (index) {
|
||||
case pvr2_v4l_type_video: hdw->v4l_minor_number_video = v;
|
||||
case pvr2_v4l_type_vbi: hdw->v4l_minor_number_vbi = v;
|
||||
case pvr2_v4l_type_radio: hdw->v4l_minor_number_radio = v;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2804,7 +2987,7 @@ int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
|
||||
|
||||
LOCK_TAKE(hdw->ctl_lock);
|
||||
|
||||
hdw->cmd_buffer[0] = 0x04; /* write register prefix */
|
||||
hdw->cmd_buffer[0] = FX2CMD_REG_WRITE; /* write register prefix */
|
||||
PVR2_DECOMPOSE_LE(hdw->cmd_buffer,1,data);
|
||||
hdw->cmd_buffer[5] = 0;
|
||||
hdw->cmd_buffer[6] = (reg >> 8) & 0xff;
|
||||
@ -2825,7 +3008,7 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
|
||||
|
||||
LOCK_TAKE(hdw->ctl_lock);
|
||||
|
||||
hdw->cmd_buffer[0] = 0x05; /* read register prefix */
|
||||
hdw->cmd_buffer[0] = FX2CMD_REG_READ; /* read register prefix */
|
||||
hdw->cmd_buffer[1] = 0;
|
||||
hdw->cmd_buffer[2] = 0;
|
||||
hdw->cmd_buffer[3] = 0;
|
||||
@ -2843,39 +3026,6 @@ static int pvr2_read_register(struct pvr2_hdw *hdw, u16 reg, u32 *data)
|
||||
}
|
||||
|
||||
|
||||
static int pvr2_write_u16(struct pvr2_hdw *hdw, u16 data, int res)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOCK_TAKE(hdw->ctl_lock);
|
||||
|
||||
hdw->cmd_buffer[0] = (data >> 8) & 0xff;
|
||||
hdw->cmd_buffer[1] = data & 0xff;
|
||||
|
||||
ret = pvr2_send_request(hdw, hdw->cmd_buffer, 2, hdw->cmd_buffer, res);
|
||||
|
||||
LOCK_GIVE(hdw->ctl_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int pvr2_write_u8(struct pvr2_hdw *hdw, u8 data, int res)
|
||||
{
|
||||
int ret;
|
||||
|
||||
LOCK_TAKE(hdw->ctl_lock);
|
||||
|
||||
hdw->cmd_buffer[0] = data;
|
||||
|
||||
ret = pvr2_send_request(hdw, hdw->cmd_buffer, 1, hdw->cmd_buffer, res);
|
||||
|
||||
LOCK_GIVE(hdw->ctl_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void pvr2_hdw_render_useless_unlocked(struct pvr2_hdw *hdw)
|
||||
{
|
||||
if (!hdw->flag_ok) return;
|
||||
@ -2949,7 +3099,7 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
|
||||
hdw->flag_ok = !0;
|
||||
hdw->cmd_buffer[0] = 0xdd;
|
||||
hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
|
||||
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
|
||||
} while (0); LOCK_GIVE(hdw->ctl_lock);
|
||||
return status;
|
||||
@ -2961,7 +3111,7 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
|
||||
int status;
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
|
||||
hdw->cmd_buffer[0] = 0xde;
|
||||
hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
|
||||
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
|
||||
} while (0); LOCK_GIVE(hdw->ctl_lock);
|
||||
return status;
|
||||
@ -2994,7 +3144,8 @@ static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
|
||||
{
|
||||
int status;
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
hdw->cmd_buffer[0] = (runFl ? 0x36 : 0x37);
|
||||
hdw->cmd_buffer[0] =
|
||||
(runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
|
||||
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
|
||||
} while (0); LOCK_GIVE(hdw->ctl_lock);
|
||||
if (!status) {
|
||||
@ -3093,7 +3244,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
|
||||
{
|
||||
int result;
|
||||
LOCK_TAKE(hdw->ctl_lock); do {
|
||||
hdw->cmd_buffer[0] = 0xeb;
|
||||
hdw->cmd_buffer[0] = FX2CMD_GET_EEPROM_ADDR;
|
||||
result = pvr2_send_request(hdw,
|
||||
hdw->cmd_buffer,1,
|
||||
hdw->cmd_buffer,1);
|
||||
@ -3105,7 +3256,7 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
|
||||
|
||||
|
||||
int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
|
||||
u32 chip_id,unsigned long reg_id,
|
||||
u32 chip_id, u64 reg_id,
|
||||
int setFl,u32 *val_ptr)
|
||||
{
|
||||
#ifdef CONFIG_VIDEO_ADV_DEBUG
|
||||
@ -3115,6 +3266,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
|
||||
int stat = 0;
|
||||
int okFl = 0;
|
||||
|
||||
if (!capable(CAP_SYS_ADMIN)) return -EPERM;
|
||||
|
||||
req.i2c_id = chip_id;
|
||||
req.reg = reg_id;
|
||||
if (setFl) req.val = *val_ptr;
|
||||
@ -3123,8 +3276,8 @@ int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
|
||||
cp = list_entry(item,struct pvr2_i2c_client,list);
|
||||
if (cp->client->driver->id != chip_id) continue;
|
||||
stat = pvr2_i2c_client_cmd(
|
||||
cp,(setFl ? VIDIOC_INT_S_REGISTER :
|
||||
VIDIOC_INT_G_REGISTER),&req);
|
||||
cp,(setFl ? VIDIOC_DBG_S_REGISTER :
|
||||
VIDIOC_DBG_G_REGISTER),&req);
|
||||
if (!setFl) *val_ptr = req.val;
|
||||
okFl = !0;
|
||||
break;
|
||||
|
@ -44,12 +44,6 @@
|
||||
#define PVR2_CVAL_INPUT_COMPOSITE 2
|
||||
#define PVR2_CVAL_INPUT_RADIO 3
|
||||
|
||||
/* Values that pvr2_hdw_get_signal_status() returns */
|
||||
#define PVR2_SIGNAL_OK 0x0001
|
||||
#define PVR2_SIGNAL_STEREO 0x0002
|
||||
#define PVR2_SIGNAL_SAP 0x0004
|
||||
|
||||
|
||||
/* Subsystem definitions - these are various pieces that can be
|
||||
independently stopped / started. Usually you don't want to mess with
|
||||
this directly (let the driver handle things itself), but it is useful
|
||||
@ -72,10 +66,17 @@
|
||||
PVR2_SUBSYS_RUN_ALL )
|
||||
|
||||
enum pvr2_config {
|
||||
pvr2_config_empty,
|
||||
pvr2_config_mpeg,
|
||||
pvr2_config_vbi,
|
||||
pvr2_config_radio,
|
||||
pvr2_config_empty, /* No configuration */
|
||||
pvr2_config_mpeg, /* Encoded / compressed video */
|
||||
pvr2_config_vbi, /* Standard vbi info */
|
||||
pvr2_config_pcm, /* Audio raw pcm stream */
|
||||
pvr2_config_rawvideo, /* Video raw frames */
|
||||
};
|
||||
|
||||
enum pvr2_v4l_type {
|
||||
pvr2_v4l_type_video,
|
||||
pvr2_v4l_type_vbi,
|
||||
pvr2_v4l_type_radio,
|
||||
};
|
||||
|
||||
const char *pvr2_config_get_name(enum pvr2_config);
|
||||
@ -148,8 +149,11 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
|
||||
/* Return name for this driver instance */
|
||||
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
|
||||
|
||||
/* Return PVR2_SIGNAL_XXXX bit mask indicating signal status */
|
||||
unsigned int pvr2_hdw_get_signal_status(struct pvr2_hdw *);
|
||||
/* Mark tuner status stale so that it will be re-fetched */
|
||||
void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *);
|
||||
|
||||
/* Return information about the tuner */
|
||||
int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *);
|
||||
|
||||
/* Query device and see if it thinks it is on a high-speed USB link */
|
||||
int pvr2_hdw_is_hsm(struct pvr2_hdw *);
|
||||
@ -205,11 +209,12 @@ int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *);
|
||||
int pvr2_hdw_cpufw_get(struct pvr2_hdw *,unsigned int offs,
|
||||
char *buf,unsigned int cnt);
|
||||
|
||||
/* Retrieve previously stored v4l minor device number */
|
||||
int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
|
||||
/* Retrieve a previously stored v4l minor device number */
|
||||
int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *,enum pvr2_v4l_type index);
|
||||
|
||||
/* Store the v4l minor device number */
|
||||
void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
|
||||
/* Store a v4l minor device number */
|
||||
void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,
|
||||
enum pvr2_v4l_type index,int);
|
||||
|
||||
/* Direct read/write access to chip's registers:
|
||||
chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
|
||||
@ -217,7 +222,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
|
||||
setFl - true to set the register, false to read it
|
||||
val_ptr - storage location for source / result. */
|
||||
int pvr2_hdw_register_access(struct pvr2_hdw *,
|
||||
u32 chip_id,unsigned long reg_id,
|
||||
u32 chip_id,u64 reg_id,
|
||||
int setFl,u32 *val_ptr);
|
||||
|
||||
/* The following entry points are all lower level things you normally don't
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user