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:
Linus Torvalds 2007-02-21 11:10:30 -08:00
commit e695e10bc9
170 changed files with 9998 additions and 4486 deletions

View File

@ -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

View File

@ -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]

View File

@ -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

View File

@ -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:

View File

@ -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

View 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)

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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:

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -70,6 +70,7 @@ config VIDEO_TUNER
depends on I2C
config VIDEO_BUF
depends on PCI
tristate
config VIDEO_BUF_DVB

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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,
};

View File

@ -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" },

View File

@ -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;

View File

@ -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 */

View File

@ -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) {

View File

@ -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(&current->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;
}

View File

@ -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);

View File

@ -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

View File

@ -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

View 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");

View 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

View File

@ -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

View File

@ -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);
}

View 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");

View 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

View 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");

View 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

View File

@ -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

View File

@ -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

View File

@ -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);
};

View File

@ -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 */

View File

@ -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))

View 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 = &reg, .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, &params);
}
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");

View 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

View 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

View File

@ -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 */

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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).");

View File

@ -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;

View File

@ -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_ */

View File

@ -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(&current->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;

View File

@ -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;

View File

@ -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);

View File

@ -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,

View File

@ -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();

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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"

View File

@ -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)

View File

@ -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:

View File

@ -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");

View File

@ -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---

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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;
}
/* ----------------------------------------------------------------------- */

View File

@ -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;

View File

@ -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 */

View File

@ -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

View File

@ -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 --------------------- */

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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]");
/* ----------------------------------------------------------- */
/*

View File

@ -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,
},

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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

View File

@ -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:

View File

@ -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;
}

View File

@ -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);

View File

@ -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];

View File

@ -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 *

View File

@ -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;

View File

@ -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);

View File

@ -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) {

View File

@ -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;
{

View File

@ -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",

View File

@ -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);

View File

@ -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 */

View 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: ***
*/

View File

@ -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 */
/*

View File

@ -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;

View File

@ -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