86 -> Osprey 101/151 w/ svid
87 -> Osprey 200/201/250/251
88 -> Osprey 200/250 [0070:ff01]
- 89 -> Osprey 210/220
+ 89 -> Osprey 210/220/230
90 -> Osprey 500 [0070:ff02]
91 -> Osprey 540 [0070:ff04]
92 -> Osprey 2000 [0070:ff03]
110 -> IVC-100 [ff00:a132]
111 -> IVC-120G [ff00:a182,ff01:a182,ff02:a182,ff03:a182,ff04:a182,ff05:a182,ff06:a182,ff07:a182,ff08:a182,ff09:a182,ff0a:a182,ff0b:a182,ff0c:a182,ff0d:a182,ff0e:a182,ff0f:a182]
112 -> pcHDTV HD-2000 TV [7063:2000]
-113 -> Twinhan DST + clones [11bd:0026,1822:0001,270f:fc00]
+113 -> Twinhan DST + clones [11bd:0026,1822:0001,270f:fc00,1822:0026]
114 -> Winfast VC100 [107d:6607]
115 -> Teppro TEV-560/InterVision IV-560
116 -> SIMUS GVC1100 [aa6a:82b2]
14 -> KWorld/VStream XPert DVB-T [17de:08a6]
15 -> DViCO FusionHDTV DVB-T1 [18ac:db00]
16 -> KWorld LTV883RF
- 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810]
+ 17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810,18ac:d800]
18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001]
19 -> Conexant DVB-T reference design [14f1:0187]
20 -> Provideo PV259 [1540:2580]
39 -> KWorld DVB-S 100 [17de:08b2]
40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
- 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025]
+ 42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019]
43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1]
44 -> DViCO FusionHDTV DVB-T Dual Digital [18ac:db50,18ac:db54]
45 -> KWorld HardwareMpegTV XPert [17de:0840]
46 -> DViCO FusionHDTV DVB-T Hybrid [18ac:db40,18ac:db44]
+ 47 -> pcHDTV HD5500 HDTV [7063:5500]
+ 48 -> Kworld MCE 200 Deluxe [17de:0841]
+ 49 -> PixelView PlayTV P7000 [1554:4813]
+ 50 -> NPG Tech Real TV FM Top 10 [14f1:0842]
+ 51 -> WinFast DTV2000 H [107d:665e]
92 -> AVerMedia A169 B1 [1461:6360]
93 -> Medion 7134 Bridge #2 [16be:0005]
94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502]
+ 95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138]
tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
tuner=62 - Philips TEA5767HN FM Radio
tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
-tuner=64 - LG TDVS-H062F/TUA6034
+tuner=64 - LG TDVS-H06xF
tuner=65 - Ymec TVF66T5-B/DFF
tuner=66 - LG TALN series
tuner=67 - Philips TD1316 Hybrid Tuner
tuner=70 - Samsung TCPN 2121P30A
tuner=71 - Xceive xc3028
tuner=72 - Thomson FE6600
+tuner=73 - Samsung TCPG 6121P30A
9.0 --- A sample program using v4lgrabber,
-This program is a simple image grabber that will copy a frame from the
+v4lgrab is a simple image grabber that will copy a frame from the
first video device, /dev/video0 to standard output in portable pixmap
-format (.ppm) Using this like: 'v4lgrab | convert - c-qcam.jpg'
-produced this picture of me at
- http://mug.sys.virginia.edu/~drf5n/extras/c-qcam.jpg
-
--------------------- 8< ---------------- 8< -----------------------------
-
-/* Simple Video4Linux image grabber. */
-/*
- * Video4Linux Driver Test/Example Framegrabbing Program
- *
- * Compile with:
- * gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
- * Use as:
- * v4lgrab >image.ppm
- *
- * Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
- * Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
- * with minor modifications (Dave Forrest, drf5n@virginia.edu).
- *
- */
-
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/ioctl.h>
-#include <stdlib.h>
-
-#include <linux/types.h>
-#include <linux/videodev.h>
-
-#define FILE "/dev/video0"
-
-/* Stole this from tvset.c */
-
-#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b) \
-{ \
- switch (format) \
- { \
- case VIDEO_PALETTE_GREY: \
- switch (depth) \
- { \
- case 4: \
- case 6: \
- case 8: \
- (r) = (g) = (b) = (*buf++ << 8);\
- break; \
- \
- case 16: \
- (r) = (g) = (b) = \
- *((unsigned short *) buf); \
- buf += 2; \
- break; \
- } \
- break; \
- \
- \
- case VIDEO_PALETTE_RGB565: \
- { \
- unsigned short tmp = *(unsigned short *)buf; \
- (r) = tmp&0xF800; \
- (g) = (tmp<<5)&0xFC00; \
- (b) = (tmp<<11)&0xF800; \
- buf += 2; \
- } \
- break; \
- \
- case VIDEO_PALETTE_RGB555: \
- (r) = (buf[0]&0xF8)<<8; \
- (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8; \
- (b) = ((buf[1] << 2 ) & 0xF8)<<8; \
- buf += 2; \
- break; \
- \
- case VIDEO_PALETTE_RGB24: \
- (r) = buf[0] << 8; (g) = buf[1] << 8; \
- (b) = buf[2] << 8; \
- buf += 3; \
- break; \
- \
- default: \
- fprintf(stderr, \
- "Format %d not yet supported\n", \
- format); \
- } \
-}
-
-int get_brightness_adj(unsigned char *image, long size, int *brightness) {
- long i, tot = 0;
- for (i=0;i<size*3;i++)
- tot += image[i];
- *brightness = (128 - tot/(size*3))/3;
- return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
-}
-
-int main(int argc, char ** argv)
-{
- int fd = open(FILE, O_RDONLY), f;
- struct video_capability cap;
- struct video_window win;
- struct video_picture vpic;
-
- unsigned char *buffer, *src;
- int bpp = 24, r, g, b;
- unsigned int i, src_depth;
-
- if (fd < 0) {
- perror(FILE);
- exit(1);
- }
-
- if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
- perror("VIDIOGCAP");
- fprintf(stderr, "(" FILE " not a video4linux device?)\n");
- close(fd);
- exit(1);
- }
-
- if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
- perror("VIDIOCGWIN");
- close(fd);
- exit(1);
- }
-
- if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
- perror("VIDIOCGPICT");
- close(fd);
- exit(1);
- }
-
- if (cap.type & VID_TYPE_MONOCHROME) {
- vpic.depth=8;
- vpic.palette=VIDEO_PALETTE_GREY; /* 8bit grey */
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- vpic.depth=6;
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- vpic.depth=4;
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- fprintf(stderr, "Unable to find a supported capture format.\n");
- close(fd);
- exit(1);
- }
- }
- }
- } else {
- vpic.depth=24;
- vpic.palette=VIDEO_PALETTE_RGB24;
-
- if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
- vpic.palette=VIDEO_PALETTE_RGB565;
- vpic.depth=16;
-
- if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
- vpic.palette=VIDEO_PALETTE_RGB555;
- vpic.depth=15;
-
- if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
- fprintf(stderr, "Unable to find a supported capture format.\n");
- return -1;
- }
- }
- }
- }
-
- buffer = malloc(win.width * win.height * bpp);
- if (!buffer) {
- fprintf(stderr, "Out of memory.\n");
- exit(1);
- }
-
- do {
- int newbright;
- read(fd, buffer, win.width * win.height * bpp);
- f = get_brightness_adj(buffer, win.width * win.height, &newbright);
- if (f) {
- vpic.brightness += (newbright << 8);
- if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
- perror("VIDIOSPICT");
- break;
- }
- }
- } while (f);
-
- fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
-
- src = buffer;
-
- for (i = 0; i < win.width * win.height; i++) {
- READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
- fputc(r>>8, stdout);
- fputc(g>>8, stdout);
- fputc(b>>8, stdout);
- }
-
- close(fd);
- return 0;
-}
--------------------- 8< ---------------- 8< -----------------------------
+format (.ppm) To produce .jpg output, you can use it like this:
+'v4lgrab | convert - c-qcam.jpg'
10.0 --- Other Information
Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
Card number: 7
+AverMedia 6 Eyes AVS6EYES:
+* Zoran zr36067 PCI controller
+* Zoran zr36060 MJPEG codec
+* Samsung ks0127 TV decoder
+* Conexant bt866 TV encoder
+Drivers to use: videodev, i2c-core, i2c-algo-bit,
+ videocodec, ks0127, bt866, zr36060, zr36067
+Inputs/outputs: Six physical inputs. 1-6 are composite,
+ 1-2, 3-4, 5-6 doubles as S-video,
+ 1-3 triples as component.
+ One composite output.
+Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps)
+Card number: 8
+Not autodetected, card=8 is necessary.
+
Linux Media Labs LML33:
* Zoran zr36067 PCI controller
* Zoran zr36060 MJPEG codec
was introduced in 1996, is used in the DC30 and DC30+ and
can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb
+Samsung ks0127 TV decoder
+is used in the AVS6EYES card and
+can handle: NTSC-M/N/44, PAL-M/N/B/G/H/I/D/K/L and SECAM
+
===========================
1.2 What the TV encoder can do an what not
was introduced in 1991, is used in the DC10 old
can generate: PAL , NTSC , SECAM
+Conexant bt866 TV encoder
+is used in AVS6EYES, and
+can generate: NTSC/PAL, PALÂM, PALÂN
+
The adv717x, should be able to produce PAL N. But you find nothing PAL N
specific in the registers. Seem that you have to reuse a other standard
to generate PAL N, maybe it would work if you use the PAL M settings.
-Contributors to bttv:
+Contributors to bttv:
Michael Chu <mmchu@pobox.com>
AverMedia fix and more flexible card recognition
Chris Kleitsch
Hardware I2C
-
-Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+Gerd Knorr <kraxel@cs.tu-berlin.de>
Radio card (ITT sound processor)
bigfoot <bigfoot@net-way.net>
+ many more (please mail me if you are missing in this list and would
- like to be mentioned)
+ like to be mentioned)
--- /dev/null
+This page describes how to make calls to the firmware api.
+
+How to call
+===========
+
+The preferred calling convention is known as the firmware mailbox. The
+mailboxes are basically a fixed length array that serves as the call-stack.
+
+Firmware mailboxes can be located by searching the encoder and decoder memory
+for a 16 byte signature. That signature will be located on a 256-byte boundary.
+
+Signature:
+0x78, 0x56, 0x34, 0x12, 0x12, 0x78, 0x56, 0x34,
+0x34, 0x12, 0x78, 0x56, 0x56, 0x34, 0x12, 0x78
+
+The firmware implements 20 mailboxes of 20 32-bit words. The first 10 are
+reserved for API calls. The second 10 are used by the firmware for event
+notification.
+
+ Index Name
+ ----- ----
+ 0 Flags
+ 1 Command
+ 2 Return value
+ 3 Timeout
+ 4-19 Parameter/Result
+
+
+The flags are defined in the following table. The direction is from the
+perspective of the firmware.
+
+ Bit Direction Purpose
+ --- --------- -------
+ 2 O Firmware has processed the command.
+ 1 I Driver has finished setting the parameters.
+ 0 I Driver is using this mailbox.
+
+
+The command is a 32-bit enumerator. The API specifics may be found in the
+fw-*-api.txt documents.
+
+The return value is a 32-bit enumerator. Only two values are currently defined:
+0=success and -1=command undefined.
+
+There are 16 parameters/results 32-bit fields. The driver populates these fields
+with values for all the parameters required by the call. The driver overwrites
+these fields with result values returned by the call. The API specifics may be
+found in the fw-*-api.txt documents.
+
+The timeout value protects the card from a hung driver thread. If the driver
+doesn't handle the completed call within the timeout specified, the firmware
+will reset that mailbox.
+
+To make an API call, the driver iterates over each mailbox looking for the
+first one available (bit 0 has been cleared). The driver sets that bit, fills
+in the command enumerator, the timeout value and any required parameters. The
+driver then sets the parameter ready bit (bit 1). The firmware scans the
+mailboxes for pending commands, processes them, sets the result code, populates
+the result value array with that call's return values and sets the call
+complete bit (bit 2). Once bit 2 is set, the driver should retrieve the results
+and clear all the flags. If the driver does not perform this task within the
+time set in the timeout register, the firmware will reset that mailbox.
+
+Event notifications are sent from the firmware to the host. The host tells the
+firmware which events it is interested in via an API call. That call tells the
+firmware which notification mailbox to use. The firmware signals the host via
+an interrupt. Only the 16 Results fields are used, the Flags, Command, Return
+value and Timeout words are not used.
+
--- /dev/null
+Decoder firmware API description
+================================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_PING_FW
+Enum 0/0x00
+Description
+ This API call does nothing. It may be used to check if the firmware
+ is responding.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_START_PLAYBACK
+Enum 1/0x01
+Description
+ Begin or resume playback.
+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.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_STOP_PLAYBACK
+Enum 2/0x02
+Description
+ Ends playback and clears all decoder buffers. If PTS is not zero,
+ playback stops at specified PTS.
+Param[0]
+ Display 0=last frame, 1=black
+Param[1]
+ PTS low
+Param[2]
+ PTS high
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_PLAYBACK_SPEED
+Enum 3/0x03
+Description
+ Playback stream at speed other than normal. There are two modes of
+ operation:
+ Smooth: host transfers entire stream and firmware drops unused
+ frames.
+ Coarse: host drops frames based on indexing as required to achieve
+ desired speed.
+Param[0]
+ Bitmap:
+ 0:7 0 normal
+ 1 fast only "1.5 times"
+ n nX fast, 1/nX slow
+ 30 Framedrop:
+ '0' during 1.5 times play, every other B frame is dropped
+ '1' during 1.5 times play, stream is unchanged (bitrate
+ must not exceed 8mbps)
+ 31 Speed:
+ '0' slow
+ '1' fast
+Param[1]
+ Direction: 0=forward, 1=reverse
+Param[2]
+ Picture mask:
+ 1=I frames
+ 3=I, P frames
+ 7=I, P, B frames
+Param[3]
+ B frames per GOP (for reverse play only)
+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.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_STEP_VIDEO
+Enum 5/0x05
+Description
+ Each call to this API steps the playback to the next unit defined below
+ in the current playback direction.
+Param[0]
+ 0=frame, 1=top field, 2=bottom field
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_DMA_BLOCK_SIZE
+Enum 8/0x08
+Description
+ Set DMA transfer block size. Counterpart to API 0xC9
+Param[0]
+ DMA transfer block size in bytes. A different size may be specified
+ when issuing the DMA transfer command.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_XFER_INFO
+Enum 9/0x09
+Description
+ This API call may be used to detect an end of stream condtion.
+Result[0]
+ Stream type
+Result[1]
+ Address offset
+Result[2]
+ Maximum bytes to transfer
+Result[3]
+ Buffer fullness
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_DMA_STATUS
+Enum 10/0x0A
+Description
+ Status of the last DMA transfer
+Result[0]
+ Bit 1 set means transfer complete
+ Bit 2 set means DMA error
+ Bit 3 set means linked list error
+Result[1]
+ DMA type: 0=MPEG, 1=OSD, 2=YUV
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SCHED_DMA_FROM_HOST
+Enum 11/0x0B
+Description
+ Setup DMA from host operation. Counterpart to API 0xCC
+Param[0]
+ Memory address of link list
+Param[1]
+ Total # of bytes to transfer
+Param[2]
+ DMA type (0=MPEG, 1=OSD, 2=YUV)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_PAUSE_PLAYBACK
+Enum 13/0x0D
+Description
+ Freeze playback immediately. In this mode, when internal buffers are
+ full, no more data will be accepted and data request IRQs will be
+ masked.
+Param[0]
+ Display: 0=last frame, 1=black
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_HALT_FW
+Enum 14/0x0E
+Description
+ The firmware is halted and no further API calls are serviced until
+ the firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_STANDARD
+Enum 16/0x10
+Description
+ Selects display standard
+Param[0]
+ 0=NTSC, 1=PAL
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_VERSION
+Enum 17/0x11
+Description
+ Returns decoder firmware version information
+Result[0]
+ Version bitmask:
+ Bits 0:15 build
+ Bits 16:23 minor
+ Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_STREAM_INPUT
+Enum 20/0x14
+Description
+ Select decoder stream input port
+Param[0]
+ 0=memory (default), 1=streaming
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_GET_TIMING_INFO
+Enum 21/0x15
+Description
+ Returns timing information from start of playback
+Result[0]
+ Frame count by decode order
+Result[1]
+ Video PTS bits 0:31 by display order
+Result[2]
+ Video PTS bit 32 by display order
+Result[3]
+ SCR bits 0:31 by display order
+Result[4]
+ SCR bit 32 by display order
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_AUDIO_MODE
+Enum 22/0x16
+Description
+ Select audio mode
+Param[0]
+ Dual mono mode action
+Param[1]
+ Stereo mode action:
+ 0=Stereo, 1=Left, 2=Right, 3=Mono, 4=Swap, -1=Unchanged
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_EVENT_NOTIFICATION
+Enum 23/0x17
+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
+Param[1]
+ Notification 0=disabled, 1=enabled
+Param[2]
+ Interrupt bit
+Param[3]
+ Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_DISPLAY_BUFFERS
+Enum 24/0x18
+Description
+ Number of display buffers. To decode all frames in reverse playback you
+ must use nine buffers.
+Param[0]
+ 0=six buffers, 1=nine buffers
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_EXTRACT_VBI
+Enum 25/0x19
+Description
+ Extracts VBI data
+Param[0]
+ 0=extract from extension & user data, 1=extract from private packets
+Result[0]
+ VBI table location
+Result[1]
+ VBI table size
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_DEC_SET_DECODER_SOURCE
+Enum 26/0x1A
+Description
+ Selects decoder source. Ensure that the parameters passed to this
+ API match the encoder settings.
+Param[0]
+ Mode: 0=MPEG from host, 1=YUV from encoder, 2=YUV from host
+Param[1]
+ YUV picture width
+Param[2]
+ YUV picture height
+Param[3]
+ Bitmap: see Param[0] of API 0xBD
+
+-------------------------------------------------------------------------------
+
+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
+ Decoder prebuffering, when enabled up to 128KB are buffered for
+ streams <8mpbs or 640KB for streams >8mbps
+Param[0]
+ 0=off, 1=on
--- /dev/null
+This page describes the structures and procedures used by the cx2341x DMA
+engine.
+
+Introduction
+============
+
+The cx2341x PCI interface is busmaster capable. This means it has a DMA
+engine to efficiently transfer large volumes of data between the card and main
+memory without requiring help from a CPU. Like most hardware, it must operate
+on contiguous physical memory. This is difficult to come by in large quantities
+on virtual memory machines.
+
+Therefore, it also supports a technique called "scatter-gather". The card can
+transfer multiple buffers in one operation. Instead of allocating one large
+contiguous buffer, the driver can allocate several smaller buffers.
+
+In practice, I've seen the average transfer to be roughly 80K, but transfers
+above 128K were not uncommon, particularly at startup. The 128K figure is
+important, because that is the largest block that the kernel can normally
+allocate. Even still, 128K blocks are hard to come by, so the driver writer is
+urged to choose a smaller block size and learn the scatter-gather technique.
+
+Mailbox #10 is reserved for DMA transfer information.
+
+Flow
+====
+
+This section describes, in general, the order of events when handling DMA
+transfers. Detailed information follows this section.
+
+- The card raises the Encoder interrupt.
+- The driver reads the transfer type, offset and size from Mailbox #10.
+- The driver constructs the scatter-gather array from enough free dma buffers
+ to cover the size.
+- The driver schedules the DMA transfer via the ScheduleDMAtoHost API call.
+- The card raises the DMA Complete interrupt.
+- The driver checks the DMA status register for any errors.
+- The driver post-processes the newly transferred buffers.
+
+NOTE! It is possible that the Encoder and DMA Complete interrupts get raised
+simultaneously. (End of the last, start of the next, etc.)
+
+Mailbox #10
+===========
+
+The Flags, Command, Return Value and Timeout fields are ignored.
+
+Name: Mailbox #10
+Results[0]: Type: 0: MPEG.
+Results[1]: Offset: The position relative to the card's memory space.
+Results[2]: Size: The exact number of bytes to transfer.
+
+My speculation is that since the StartCapture API has a capture type of "RAW"
+available, that the type field will have other values that correspond to YUV
+and PCM data.
+
+Scatter-Gather Array
+====================
+
+The scatter-gather array is a contiguously allocated block of memory that
+tells the card the source and destination of each data-block to transfer.
+Card "addresses" are derived from the offset supplied by Mailbox #10. Host
+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
+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
+most likely get corrupted.
+
+The transfer count must be a multiple of 256. Therefore, the driver will need
+to track how much data in the target buffer is valid and deal with it
+accordingly.
+
+Array Element:
+
+- 32-bit Source Address
+- 32-bit Destination Address
+- 16-bit reserved (high bit is the last flag)
+- 16-bit byte count
+
+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
--- /dev/null
+Encoder firmware API description
+================================
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_PING_FW
+Enum 128/0x80
+Description
+ Does nothing. Can be used to check if the firmware is responding.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_START_CAPTURE
+Enum 129/0x81
+Description
+ Commences the capture of video, audio and/or VBI data. All encoding
+ parameters must be initialized prior to this API call. Captures frames
+ continuously or until a predefined number of frames have been captured.
+Param[0]
+ Capture stream type:
+ 0=MPEG
+ 1=Raw
+ 2=Raw passthrough
+ 3=VBI
+
+Param[1]
+ Bitmask:
+ Bit 0 when set, captures YUV
+ Bit 1 when set, captures PCM audio
+ Bit 2 when set, captures VBI (same as param[0]=3)
+ Bit 3 when set, the capture destination is the decoder
+ (same as param[0]=2)
+ Bit 4 when set, the capture destination is the host
+ Note: this parameter is only meaningful for RAW capture type.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_STOP_CAPTURE
+Enum 130/0x82
+Description
+ Ends a capture in progress
+Param[0]
+ 0=stop at end of GOP (generates IRQ)
+ 1=stop immediate (no IRQ)
+Param[1]
+ Stream type to stop, see param[0] of API 0x81
+Param[2]
+ Subtype, see param[1] of API 0x81
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_AUDIO_ID
+Enum 137/0x89
+Description
+ Assigns the transport stream ID of the encoded audio stream
+Param[0]
+ Audio Stream ID
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_VIDEO_ID
+Enum 139/0x8B
+Description
+ Set video transport stream ID
+Param[0]
+ Video stream ID
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_PCR_ID
+Enum 141/0x8D
+Description
+ Assigns the transport stream ID for PCR packets
+Param[0]
+ PCR Stream ID
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_FRAME_RATE
+Enum 143/0x8F
+Description
+ Set video frames per second. Change occurs at start of new GOP.
+Param[0]
+ 0=30fps
+ 1=25fps
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_FRAME_SIZE
+Enum 145/0x91
+Description
+ Select video stream encoding resolution.
+Param[0]
+ Height in lines. Default 480
+Param[1]
+ Width in pixels. Default 720
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_BIT_RATE
+Enum 149/0x95
+Description
+ Assign average video stream bitrate. Note on the last three params:
+ Param[3] and [4] seem to be always 0, param [5] doesn't seem to be used.
+Param[0]
+ 0=variable bitrate, 1=constant bitrate
+Param[1]
+ bitrate in bits per second
+Param[2]
+ peak bitrate in bits per second, divided by 400
+Param[3]
+ Mux bitrate in bits per second, divided by 400. May be 0 (default).
+Param[4]
+ Rate Control VBR Padding
+Param[5]
+ VBV Buffer used by encoder
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_GOP_PROPERTIES
+Enum 151/0x97
+Description
+ Setup the GOP structure
+Param[0]
+ GOP size (maximum is 34)
+Param[1]
+ Number of B frames between the I and P frame, plus 1.
+ For example: IBBPBBPBBPBB --> GOP size: 12, number of B frames: 2+1 = 3
+ Note that GOP size must be a multiple of (B-frames + 1).
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_ASPECT_RATIO
+Enum 153/0x99
+Description
+ Sets the encoding aspect ratio. Changes in the aspect ratio take effect
+ at the start of the next GOP.
+Param[0]
+ '0000' forbidden
+ '0001' 1:1 square
+ '0010' 4:3
+ '0011' 16:9
+ '0100' 2.21:1
+ '0101' reserved
+ ....
+ '1111' reserved
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_DNR_FILTER_MODE
+Enum 155/0x9B
+Description
+ Assign Dynamic Noise Reduction operating mode
+Param[0]
+ Bit0: Spatial filter, set=auto, clear=manual
+ Bit1: Temporal filter, set=auto, clear=manual
+Param[1]
+ Median filter:
+ 0=Disabled
+ 1=Horizontal
+ 2=Vertical
+ 3=Horiz/Vert
+ 4=Diagonal
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_DNR_FILTER_PROPS
+Enum 157/0x9D
+Description
+ These Dynamic Noise Reduction filter values are only meaningful when
+ the respective filter is set to "manual" (See API 0x9B)
+Param[0]
+ Spatial filter: default 0, range 0:15
+Param[1]
+ Temporal filter: default 0, range 0:31
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_CORING_LEVELS
+Enum 159/0x9F
+Description
+ Assign Dynamic Noise Reduction median filter properties.
+Param[0]
+ Threshold above which the luminance median filter is enabled.
+ Default: 0, range 0:255
+Param[1]
+ Threshold below which the luminance median filter is enabled.
+ Default: 255, range 0:255
+Param[2]
+ Threshold above which the chrominance median filter is enabled.
+ Default: 0, range 0:255
+Param[3]
+ Threshold below which the chrominance median filter is enabled.
+ Default: 255, range 0:255
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_SPATIAL_FILTER_TYPE
+Enum 161/0xA1
+Description
+ Assign spatial prefilter parameters
+Param[0]
+ Luminance filter
+ 0=Off
+ 1=1D Horizontal
+ 2=1D Vertical
+ 3=2D H/V Separable (default)
+ 4=2D Symmetric non-separable
+Param[1]
+ Chrominance filter
+ 0=Off
+ 1=1D Horizontal (default)
+
+-------------------------------------------------------------------------------
+
+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
+ Selects VBI line number.
+Param[0]
+ Bits 0:4 line number
+ Bit 31 0=top_field, 1=bottom_field
+ Bits 0:31 all set specifies "all lines"
+Param[1]
+ VBI line information features: 0=disabled, 1=enabled
+Param[2]
+ Slicing: 0=None, 1=Closed Caption
+ Almost certainly not implemented. Set to 0.
+Param[3]
+ Luminance samples in this line.
+ Almost certainly not implemented. Set to 0.
+Param[4]
+ Chrominance samples in this line
+ Almost certainly not implemented. Set to 0.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_STREAM_TYPE
+Enum 185/0xB9
+Description
+ Assign stream type
+ Note: Transport stream is not working in recent firmwares.
+ And in older firmwares the timestamps in the TS seem to be
+ unreliable.
+Param[0]
+ 0=Program stream
+ 1=Transport stream
+ 2=MPEG1 stream
+ 3=PES A/V stream
+ 5=PES Video stream
+ 7=PES Audio stream
+ 10=DVD stream
+ 11=VCD stream
+ 12=SVCD stream
+ 13=DVD_S1 stream
+ 14=DVD_S2 stream
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_OUTPUT_PORT
+Enum 187/0xBB
+Description
+ Assign stream output port. Normally 0 when the data is copied through
+ the PCI bus (DMA), and 1 when the data is streamed to another chip
+ (pvrusb and cx88-blackbird).
+Param[0]
+ 0=Memory (default)
+ 1=Streaming
+ 2=Serial
+Param[1]
+ Unknown, but leaving this to 0 seems to work best. Indications are that
+ this might have to do with USB support, although passing anything but 0
+ onl breaks things.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_AUDIO_PROPERTIES
+Enum 189/0xBD
+Description
+ Set audio stream properties, may be called while encoding is in progress.
+ Note: all bitfields are consistent with ISO11172 documentation except
+ bits 2:3 which ISO docs define as:
+ '11' Layer I
+ '10' Layer II
+ '01' Layer III
+ '00' Undefined
+ This discrepancy may indicate a possible error in the documentation.
+ Testing indicated that only Layer II is actually working, and that
+ the minimum bitrate should be 192 kbps.
+Param[0]
+ Bitmask:
+ 0:1 '00' 44.1Khz
+ '01' 48Khz
+ '10' 32Khz
+ '11' reserved
+
+ 2:3 '01'=Layer I
+ '10'=Layer II
+
+ 4:7 Bitrate:
+ Index | Layer I | Layer II
+ ------+-------------+------------
+ '0000' | free format | free format
+ '0001' | 32 kbit/s | 32 kbit/s
+ '0010' | 64 kbit/s | 48 kbit/s
+ '0011' | 96 kbit/s | 56 kbit/s
+ '0100' | 128 kbit/s | 64 kbit/s
+ '0101' | 160 kbit/s | 80 kbit/s
+ '0110' | 192 kbit/s | 96 kbit/s
+ '0111' | 224 kbit/s | 112 kbit/s
+ '1000' | 256 kbit/s | 128 kbit/s
+ '1001' | 288 kbit/s | 160 kbit/s
+ '1010' | 320 kbit/s | 192 kbit/s
+ '1011' | 352 kbit/s | 224 kbit/s
+ '1100' | 384 kbit/s | 256 kbit/s
+ '1101' | 416 kbit/s | 320 kbit/s
+ '1110' | 448 kbit/s | 384 kbit/s
+ Note: For Layer II, not all combinations of total bitrate
+ and mode are allowed. See ISO11172-3 3-Annex B, Table 3-B.2
+
+ 8:9 '00'=Stereo
+ '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.
+
+ 10:11 Mode Extension used in joint_stereo mode.
+ In Layer I and II they indicate which subbands are in
+ intensity_stereo. All other subbands are coded in stereo.
+ '00' subbands 4-31 in intensity_stereo, bound==4
+ '01' subbands 8-31 in intensity_stereo, bound==8
+ '10' subbands 12-31 in intensity_stereo, bound==12
+ '11' subbands 16-31 in intensity_stereo, bound==16
+
+ 12:13 Emphasis:
+ '00' None
+ '01' 50/15uS
+ '10' reserved
+ '11' CCITT J.17
+
+ 14 CRC:
+ '0' off
+ '1' on
+
+ 15 Copyright:
+ '0' off
+ '1' on
+
+ 16 Generation:
+ '0' copy
+ '1' original
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_HALT_FW
+Enum 195/0xC3
+Description
+ The firmware is halted and no further API calls are serviced until the
+ firmware is uploaded again.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_VERSION
+Enum 196/0xC4
+Description
+ Returns the version of the encoder firmware.
+Result[0]
+ Version bitmask:
+ Bits 0:15 build
+ Bits 16:23 minor
+ Bits 24:31 major
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_GOP_CLOSURE
+Enum 197/0xC5
+Description
+ Assigns the GOP open/close property.
+Param[0]
+ 0=Open
+ 1=Closed
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_SEQ_END
+Enum 198/0xC6
+Description
+ Obtains the sequence end code of the encoder's buffer. When a capture
+ is started a number of interrupts are still generated, the last of
+ which will have Result[0] set to 1 and Result[1] will contain the size
+ of the buffer.
+Result[0]
+ State of the transfer (1 if last buffer)
+Result[1]
+ If Result[0] is 1, this contains the size of the last buffer, undefined
+ otherwise.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_PGM_INDEX_INFO
+Enum 199/0xC7
+Description
+ Sets the Program Index Information.
+Param[0]
+ Picture Mask:
+ 0=No index capture
+ 1=I frames
+ 3=I,P frames
+ 7=I,P,B frames
+Param[1]
+ Elements requested (up to 400)
+Result[0]
+ Offset in SDF memory of the table.
+Result[1]
+ Number of allocated elements up to a maximum of Param[1]
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_VBI_CONFIG
+Enum 200/0xC8
+Description
+ Configure VBI settings
+Param[0]
+ Bitmap:
+ 0 Mode '0' Sliced, '1' Raw
+ 1:3 Insertion:
+ '000' insert in extension & user data
+ '001' insert in private packets
+ '010' separate stream and user data
+ '111' separate stream and private data
+ 8:15 Stream ID (normally 0xBD)
+Param[1]
+ Frames per interrupt (max 8). Only valid in raw mode.
+Param[2]
+ Total raw VBI frames. Only valid in raw mode.
+Param[3]
+ Start codes
+Param[4]
+ Stop codes
+Param[5]
+ Lines per frame
+Param[6]
+ Byte per line
+Result[0]
+ Observed frames per interrupt in raw mode only. Rage 1 to Param[1]
+Result[1]
+ Observed number of frames in raw mode. Range 1 to Param[2]
+Result[2]
+ Memory offset to start or raw VBI data
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_DMA_BLOCK_SIZE
+Enum 201/0xC9
+Description
+ Set DMA transfer block size
+Param[0]
+ DMA transfer block size in bytes or frames. When unit is bytes,
+ supported block sizes are 2^7, 2^8 and 2^9 bytes.
+Param[1]
+ Unit: 0=bytes, 1=frames
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_GET_PREV_DMA_INFO_MB_10
+Enum 202/0xCA
+Description
+ Returns information on the previous DMA transfer in conjunction with
+ bit 27 of the interrupt mask. Uses mailbox 10.
+Result[0]
+ Type of stream
+Result[1]
+ Address Offset
+Result[2]
+ Maximum size of transfer
+
+-------------------------------------------------------------------------------
+
+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.
+Result[0]
+ Status bits:
+ Bit 0 set indicates transfer complete
+ Bit 2 set indicates transfer error
+ Bit 4 set indicates linked list error
+Result[1]
+ DMA type
+Result[2]
+ Presentation Time Stamp bits 0..31
+Result[3]
+ Presentation Time Stamp bit 32
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SCHED_DMA_TO_HOST
+Enum 204/0xCC
+Description
+ Setup DMA to host operation
+Param[0]
+ Memory address of link list
+Param[1]
+ Length of link list (wtf: what units ???)
+Param[2]
+ DMA type (0=MPEG)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_INITIALIZE_INPUT
+Enum 205/0xCD
+Description
+ Initializes the video input
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_FRAME_DROP_RATE
+Enum 208/0xD0
+Description
+ For each frame captured, skip specified number of frames.
+Param[0]
+ Number of frames to skip
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_PAUSE_ENCODER
+Enum 210/0xD2
+Description
+ During a pause condition, all frames are dropped instead of being encoded.
+Param[0]
+ 0=Pause encoding
+ 1=Continue encoding
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_REFRESH_INPUT
+Enum 211/0xD3
+Description
+ Refreshes the video input
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_COPYRIGHT
+Enum 212/0xD4
+Description
+ Sets stream copyright property
+Param[0]
+ 0=Stream is not copyrighted
+ 1=Stream is copyrighted
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_EVENT_NOTIFICATION
+Enum 213/0xD5
+Description
+ Setup firmware to notify the host about a particular event. Host must
+ unmask the interrupt bit.
+Param[0]
+ Event (0=refresh encoder input)
+Param[1]
+ Notification 0=disabled 1=enabled
+Param[2]
+ Interrupt bit
+Param[3]
+ Mailbox slot, -1 if no mailbox required.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_NUM_VSYNC_LINES
+Enum 214/0xD6
+Description
+ Depending on the analog video decoder used, this assigns the number
+ of lines for field 1 and 2.
+Param[0]
+ Field 1 number of lines:
+ 0x00EF for SAA7114
+ 0x00F0 for SAA7115
+ 0x0105 for Micronas
+Param[1]
+ Field 2 number of lines:
+ 0x00EF for SAA7114
+ 0x00F0 for SAA7115
+ 0x0106 for Micronas
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_SET_PLACEHOLDER
+Enum 215/0xD7
+Description
+ Provides a mechanism of inserting custom user data in the MPEG stream.
+Param[0]
+ 0=extension & user data
+ 1=private packet with stream ID 0xBD
+Param[1]
+ Rate at which to insert data, in units of frames (for private packet)
+ or GOPs (for ext. & user data)
+Param[2]
+ Number of data DWORDs (below) to insert
+Param[3]
+ Custom data 0
+Param[4]
+ Custom data 1
+Param[5]
+ Custom data 2
+Param[6]
+ Custom data 3
+Param[7]
+ Custom data 4
+Param[8]
+ Custom data 5
+Param[9]
+ Custom data 6
+Param[10]
+ Custom data 7
+Param[11]
+ Custom data 8
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_MUTE_VIDEO
+Enum 217/0xD9
+Description
+ Video muting
+Param[0]
+ Bit usage:
+ 0 '0'=video not muted
+ '1'=video muted, creates frames with the YUV color defined below
+ 1:7 Unused
+ 8:15 V chrominance information
+ 16:23 U chrominance information
+ 24:31 Y luminance information
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_MUTE_AUDIO
+Enum 218/0xDA
+Description
+ Audio muting
+Param[0]
+ 0=audio not muted
+ 1=audio muted (produces silent mpeg audio stream)
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_UNKNOWN
+Enum 219/0xDB
+Description
+ Unknown API, it's used by Hauppauge though.
+Param[0]
+ 0 This is the value Hauppauge uses, Unknown what it means.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_ENC_MISC
+Enum 220/0xDC
+Description
+ Miscellaneous actions. Not known for 100% what it does. It's really a
+ sort of ioctl call. The first parameter is a command number, the second
+ the value.
+Param[0]
+ Command number:
+ 1=set initial SCR value when starting encoding.
+ 2=set quality mode (apparently some test setting).
+ 3=setup advanced VIM protection handling (supposedly only for the cx23416
+ for raw YUV).
+ Actually it looks like this should be 0 for saa7114/5 based card and 1
+ for cx25840 based cards.
+ 4=generate artificial PTS timestamps
+ 5=USB flush mode
+ 6=something to do with the quantization matrix
+ 7=set navigation pack insertion for DVD
+ 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
+ 11=set quantization matrix
+ 12=reset audio interface
+ 13=set audio volume delay
+ 14=set audio delay
+
+Param[1]
+ Command value.
--- /dev/null
+This document describes the cx2341x memory map and documents some of the register
+space.
+
+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
+commands like:
+
+ ivtvctl -O min=0x02000000,max=0x020000ff
+
+So take this as is, I'm always searching for more stuff, it's a large
+register space :-).
+
+Memory Map
+==========
+
+The cx2341x exposes its entire 64M memory space to the PCI host via the PCI BAR0
+(Base Address Register 0). The addresses here are offsets relative to the
+address held in BAR0.
+
+0x00000000-0x00ffffff Encoder memory space
+0x00000000-0x0003ffff Encode.rom
+ ???-??? MPEG buffer(s)
+ ???-??? Raw video capture buffer(s)
+ ???-??? Raw audio capture buffer(s)
+ ???-??? Display buffers (6 or 9)
+
+0x01000000-0x01ffffff Decoder memory space
+0x01000000-0x0103ffff Decode.rom
+ ???-??? MPEG buffers(s)
+0x0114b000-0x0115afff Audio.rom (deprecated?)
+
+0x02000000-0x0200ffff Register Space
+
+Registers
+=========
+
+The registers occupy the 64k space starting at the 0x02000000 offset from BAR0.
+All of these registers are 32 bits wide.
+
+DMA Registers 0x000-0xff:
+
+ 0x00 - Control:
+ 0=reset/cancel, 1=read, 2=write, 4=stop
+ 0x04 - DMA status:
+ 1=read busy, 2=write busy, 4=read error, 8=write error, 16=link list error
+ 0x08 - pci DMA pointer for read link list
+ 0x0c - pci DMA pointer for write link list
+ 0x10 - read/write DMA enable:
+ 1=read enable, 2=write enable
+ 0x14 - always 0xffffffff, if set any lower instability occurs, 0x00 crashes
+ 0x18 - ??
+ 0x1c - always 0x20 or 32, smaller values slow down DMA transactions
+ 0x20 - always value of 0x780a010a
+ 0x24-0x3c - usually just random values???
+ 0x40 - Interrupt status
+ 0x44 - Write a bit here and shows up in Interrupt status 0x40
+ 0x48 - Interrupt Mask
+ 0x4C - always value of 0xfffdffff,
+ if changed to 0xffffffff DMA write interrupts break.
+ 0x50 - always 0xffffffff
+ 0x54 - always 0xffffffff (0x4c, 0x50, 0x54 seem like interrupt masks, are
+ 3 processors on chip, Java ones, VPU, SPU, APU, maybe these are the
+ interrupt masks???).
+ 0x60-0x7C - random values
+ 0x80 - first write linked list reg, for Encoder Memory addr
+ 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
+ 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
+ 0xe4 - first (and only) read linked list reg, for Decoder memory addr
+ 0xe8 - first (and only) read linked list reg, for length of buffer
+ 0xec-0xff - Nothing seems to be in these registers, 0xec-f4 are 0x00000000.
+
+Memory locations for Encoder Buffers 0x700-0x7ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for encoding, have to shift them by <<1 first.
+
+0x07F8: Encoder SDRAM refresh
+0x07FC: Encoder SDRAM pre-charge
+
+Memory locations for Decoder Buffers 0x800-0x8ff:
+
+These registers show offsets of memory locations pertaining to each
+buffer area used for decoding, have to shift them by <<1 first.
+
+0x08F8: Decoder SDRAM refresh
+0x08FC: Decoder SDRAM pre-charge
+
+Other memory locations:
+
+0x2800: Video Display Module control
+0x2D00: AO (audio output?) control
+0x2D24: Bytes Flushed
+0x7000: LSB I2C write clock bit (inverted)
+0x7004: LSB I2C write data bit (inverted)
+0x7008: LSB I2C read clock bit
+0x700c: LSB I2C read data bit
+0x9008: GPIO get input state
+0x900c: GPIO set output state
+0x9020: GPIO direction (Bit7 (GPIO 0..7) - 0:input, 1:output)
+0x9050: SPU control
+0x9054: Reset HW blocks
+0x9058: VPU control
+0xA018: Bit6: interrupt pending?
+0xA064: APU command
+
+
+Interrupt Status Register
+=========================
+
+The definition of the bits in the interrupt status register 0x0040, and the
+interrupt mask 0x0048. If a bit is cleared in the mask, then we want our ISR to
+execute.
+
+Bit
+31 Encoder Start Capture
+30 Encoder EOS
+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
+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)
+
+Missing
+Encoder API call completed
+Decoder API call completed
+Encoder API post(?)
+Decoder API post(?)
+Decoder VTRACE event
--- /dev/null
+OSD firmware API description
+============================
+
+Note: this API is part of the decoder firmware, so it's cx23415 only.
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_FRAMEBUFFER
+Enum 65/0x41
+Description
+ Return base and length of contiguous OSD memory.
+Result[0]
+ OSD base address
+Result[1]
+ OSD length
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_PIXEL_FORMAT
+Enum 66/0x42
+Description
+ Query OSD format
+Result[0]
+ 0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_PIXEL_FORMAT
+Enum 67/0x43
+Description
+ Assign pixel format
+Param[0]
+ 0=8bit index, 4=AlphaRGB 8:8:8:8
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_STATE
+Enum 68/0x44
+Description
+ Query OSD state
+Result[0]
+ Bit 0 0=off, 1=on
+ Bits 1:2 alpha control
+ Bits 3:5 pixel format
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_STATE
+Enum 69/0x45
+Description
+ OSD switch
+Param[0]
+ 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_OSD_COORDS
+Enum 70/0x46
+Description
+ Retrieve coordinates of OSD area blended with video
+Result[0]
+ OSD buffer address
+Result[1]
+ Stride in pixels
+Result[2]
+ Lines in OSD buffer
+Result[3]
+ Horizontal offset in buffer
+Result[4]
+ Vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_OSD_COORDS
+Enum 71/0x47
+Description
+ Assign the coordinates of the OSD area to blend with video
+Param[0]
+ buffer address
+Param[1]
+ buffer stride in pixels
+Param[2]
+ lines in buffer
+Param[3]
+ horizontal offset
+Param[4]
+ vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_SCREEN_COORDS
+Enum 72/0x48
+Description
+ Retrieve OSD screen area coordinates
+Result[0]
+ top left horizontal offset
+Result[1]
+ top left vertical offset
+Result[2]
+ bottom right hotizontal offset
+Result[3]
+ bottom right vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_SCREEN_COORDS
+Enum 73/0x49
+Description
+ Assign the coordinates of the screen area to blend with video
+Param[0]
+ top left horizontal offset
+Param[1]
+ top left vertical offset
+Param[2]
+ bottom left horizontal offset
+Param[3]
+ bottom left vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_GLOBAL_ALPHA
+Enum 74/0x4A
+Description
+ Retrieve OSD global alpha
+Result[0]
+ global alpha: 0=off, 1=on
+Result[1]
+ bits 0:7 global alpha
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_GLOBAL_ALPHA
+Enum 75/0x4B
+Description
+ Update global alpha
+Param[0]
+ global alpha: 0=off, 1=on
+Param[1]
+ global alpha (8 bits)
+Param[2]
+ local alpha: 0=on, 1=off
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_BLEND_COORDS
+Enum 78/0x4C
+Description
+ Move start of blending area within display buffer
+Param[0]
+ horizontal offset in buffer
+Param[1]
+ vertical offset in buffer
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_FLICKER_STATE
+Enum 79/0x4F
+Description
+ Retrieve flicker reduction module state
+Result[0]
+ flicker state: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_FLICKER_STATE
+Enum 80/0x50
+Description
+ Set flicker reduction module state
+Param[0]
+ State: 0=off, 1=on
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_BLT_COPY
+Enum 82/0x52
+Description
+ BLT copy
+Param[0]
+'0000' zero
+'0001' ~destination AND ~source
+'0010' ~destination AND source
+'0011' ~destination
+'0100' destination AND ~source
+'0101' ~source
+'0110' destination XOR source
+'0111' ~destination OR ~source
+'1000' ~destination AND ~source
+'1001' destination XNOR source
+'1010' source
+'1011' ~destination OR source
+'1100' destination
+'1101' destination OR ~source
+'1110' destination OR source
+'1111' one
+
+Param[1]
+ Resulting alpha blending
+ '01' source_alpha
+ '10' destination_alpha
+ '11' source_alpha*destination_alpha+1
+ (zero if both source and destination alpha are zero)
+Param[2]
+ '00' output_pixel = source_pixel
+
+ '01' if source_alpha=0:
+ output_pixel = destination_pixel
+ if 256 > source_alpha > 1:
+ output_pixel = ((source_alpha + 1)*source_pixel +
+ (255 - source_alpha)*destination_pixel)/256
+
+ '10' if destination_alpha=0:
+ output_pixel = source_pixel
+ if 255 > destination_alpha > 0:
+ output_pixel = ((255 - destination_alpha)*source_pixel +
+ (destination_alpha + 1)*destination_pixel)/256
+
+ '11' if source_alpha=0:
+ source_temp = 0
+ if source_alpha=255:
+ source_temp = source_pixel*256
+ if 255 > source_alpha > 0:
+ source_temp = source_pixel*(source_alpha + 1)
+ if destination_alpha=0:
+ destination_temp = 0
+ if destination_alpha=255:
+ destination_temp = destination_pixel*256
+ if 255 > destination_alpha > 0:
+ destination_temp = destination_pixel*(destination_alpha + 1)
+ output_pixel = (source_temp + destination_temp)/256
+Param[3]
+ width
+Param[4]
+ height
+Param[5]
+ destination pixel mask
+Param[6]
+ destination rectangle start address
+Param[7]
+ destination stride in dwords
+Param[8]
+ source stride in dwords
+Param[9]
+ source rectangle start address
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_BLT_FILL
+Enum 83/0x53
+Description
+ BLT fill color
+Param[0]
+ Same as Param[0] on API 0x52
+Param[1]
+ Same as Param[1] on API 0x52
+Param[2]
+ Same as Param[2] on API 0x52
+Param[3]
+ width
+Param[4]
+ height
+Param[5]
+ destination pixel mask
+Param[6]
+ destination rectangle start address
+Param[7]
+ destination stride in dwords
+Param[8]
+ color fill value
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_BLT_TEXT
+Enum 84/0x54
+Description
+ BLT for 8 bit alpha text source
+Param[0]
+ Same as Param[0] on API 0x52
+Param[1]
+ Same as Param[1] on API 0x52
+Param[2]
+ Same as Param[2] on API 0x52
+Param[3]
+ width
+Param[4]
+ height
+Param[5]
+ destination pixel mask
+Param[6]
+ destination rectangle start address
+Param[7]
+ destination stride in dwords
+Param[8]
+ source stride in dwords
+Param[9]
+ source rectangle start address
+Param[10]
+ color fill value
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_FRAMEBUFFER_WINDOW
+Enum 86/0x56
+Description
+ Positions the main output window on the screen. The coordinates must be
+ such that the entire window fits on the screen.
+Param[0]
+ window width
+Param[1]
+ window height
+Param[2]
+ top left window corner horizontal offset
+Param[3]
+ top left window corner vertical offset
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_CHROMA_KEY
+Enum 96/0x60
+Description
+ Chroma key switch and color
+Param[0]
+ state: 0=off, 1=on
+Param[1]
+ color
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_GET_ALPHA_CONTENT_INDEX
+Enum 97/0x61
+Description
+ Retrieve alpha content index
+Result[0]
+ alpha content index, Range 0:15
+
+-------------------------------------------------------------------------------
+
+Name CX2341X_OSD_SET_ALPHA_CONTENT_INDEX
+Enum 98/0x62
+Description
+ Assign alpha content index
+Param[0]
+ alpha content index, range 0:15
--- /dev/null
+This document describes how to upload the cx2341x firmware to the card.
+
+How to find
+===========
+
+See the web pages of the various projects that uses this chip for information
+on how to obtain the firmware.
+
+The firmware stored in a Windows driver can be detected as follows:
+
+- Each firmware image is 256k bytes.
+- The 1st 32-bit word of the Encoder image is 0x0000da7
+- The 1st 32-bit word of the Decoder image is 0x00003a7
+- The 2nd 32-bit word of both images is 0xaa55bb66
+
+How to load
+===========
+
+- Issue the FWapi command to stop the encoder if it is running. Wait for the
+ command to complete.
+- Issue the FWapi command to stop the decoder if it is running. Wait for the
+ command to complete.
+- Issue the I2C command to the digitizer to stop emitting VSYNC events.
+- Issue the FWapi command to halt the encoder's firmware.
+- Sleep for 10ms.
+- Issue the FWapi command to halt the decoder's firmware.
+- Sleep for 10ms.
+- Write 0x00000000 to register 0x2800 to stop the Video Display Module.
+- Write 0x00000005 to register 0x2D00 to stop the AO (audio output?).
+- Write 0x00000000 to register 0xA064 to ping? the APU.
+- Write 0xFFFFFFFE to register 0x9058 to stop the VPU.
+- Write 0xFFFFFFFF to register 0x9054 to reset the HW blocks.
+- Write 0x00000001 to register 0x9050 to stop the SPU.
+- Sleep for 10ms.
+- Write 0x0000001A to register 0x07FC to init the Encoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x07F8 to init the Encoder SDRAM's refresh to 1us.
+- Write 0x0000001A to register 0x08FC to init the Decoder SDRAM's pre-charge.
+- Write 0x80000640 to register 0x08F8 to init the Decoder SDRAM's refresh to 1us.
+- Sleep for 512ms. (600ms is recommended)
+- Transfer the encoder's firmware image to offset 0 in Encoder memory space.
+- Transfer the decoder's firmware image to offset 0 in Decoder memory space.
+- Use a read-modify-write operation to Clear bit 0 of register 0x9050 to
+ re-enable the SPU.
+- Sleep for 1 second.
+- Use a read-modify-write operation to Clear bits 3 and 0 of register 0x9058
+ to re-enable the VPU.
+- Sleep for 1 second.
+- Issue status API commands to both firmware images to verify.
+
--- /dev/null
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0 GPIO1
+ 0 0 TV Audio
+ 1 0 FM radio
+ 0 1 Line-In
+ 1 1 Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004 PCI Interrupt Status
+ bit [18] IR_SMP_INT Set when 32 input samples have been collected over
+ gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to 0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data) An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well. Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/ and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+
- ET61X[12]51 PC Camera Controllers
- Driver for Linux
- =================================
+ ET61X[12]51 PC Camera Controllers
+ Driver for Linux
+ =================================
- - Documentation -
+ - Documentation -
Index
Type: short array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- registered camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 64 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ registered camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: force_munmap
Type: bool array (min = 0, max = 64)
Syntax: <0|1[,...]>
Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+ 0 = do not force memory unmapping
+ 1 = force memory unmapping (save memory)
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.
+ specific for each detected camera. This parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Name: debug
Type: ushort
Syntax: <n>
Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used at the same time. It also shows some more informations
- about the hardware being detected. This module parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = more verbose messages
+ Level 3 is useful for testing only, when only one device
+ is used at the same time. It also shows some more informations
+ about the hardware being detected. This module parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Supported controls:
- by V4L: Contrast, Brightness, Color, Hue
- by driver options: frame rate, lighting conditions, video format,
- default picture settings, sharpness.
+ default picture settings, sharpness.
SUPPORTED CAMERAS:
init_model2_yb Integer 0..255 [0xa0] init_model2_yb=200
debug You don't need this option unless you are a developer.
- If you are a developer then you will see in the code
- what values do what. 0=off.
+ If you are a developer then you will see in the code
+ what values do what. 0=off.
flags This is a bit mask, and you can combine any number of
- bits to produce what you want. Usually you don't want
- any of extra features this option provides:
-
- FLAGS_RETRY_VIDIOCSYNC 1 This bit allows to retry failed
- VIDIOCSYNC ioctls without failing.
- Will work with xawtv, will not
- with xrealproducer. Default is
- not set.
- FLAGS_MONOCHROME 2 Activates monochrome (b/w) mode.
- FLAGS_DISPLAY_HINTS 4 Shows colored pixels which have
- magic meaning to developers.
- FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen,
- useful only for debugging.
- FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
- FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as
- it was received from the camera.
- Default (not set) is to mix the
- preceding frame in to compensate
- for occasional loss of Isoc data
- on high frame rates.
- FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame
- prior to use; relevant only if
- FLAGS_SEPARATE_FRAMES is set.
- Default is not to clean frames,
- this is a little faster but may
- produce flicker if frame rate is
- too high and Isoc data gets lost.
- FLAGS_NO_DECODING 128 This flag turns the video stream
- decoder off, and dumps the raw
- Isoc data from the camera into
- the reading process. Useful to
- developers, but not to users.
+ bits to produce what you want. Usually you don't want
+ any of extra features this option provides:
+
+ FLAGS_RETRY_VIDIOCSYNC 1 This bit allows to retry failed
+ VIDIOCSYNC ioctls without failing.
+ Will work with xawtv, will not
+ with xrealproducer. Default is
+ not set.
+ FLAGS_MONOCHROME 2 Activates monochrome (b/w) mode.
+ FLAGS_DISPLAY_HINTS 4 Shows colored pixels which have
+ magic meaning to developers.
+ FLAGS_OVERLAY_STATS 8 Shows tiny numbers on screen,
+ useful only for debugging.
+ FLAGS_FORCE_TESTPATTERN 16 Shows blue screen with numbers.
+ FLAGS_SEPARATE_FRAMES 32 Shows each frame separately, as
+ it was received from the camera.
+ Default (not set) is to mix the
+ preceding frame in to compensate
+ for occasional loss of Isoc data
+ on high frame rates.
+ FLAGS_CLEAN_FRAMES 64 Forces "cleanup" of each frame
+ prior to use; relevant only if
+ FLAGS_SEPARATE_FRAMES is set.
+ Default is not to clean frames,
+ this is a little faster but may
+ produce flicker if frame rate is
+ too high and Isoc data gets lost.
+ FLAGS_NO_DECODING 128 This flag turns the video stream
+ decoder off, and dumps the raw
+ Isoc data from the camera into
+ the reading process. Useful to
+ developers, but not to users.
framerate This setting controls frame rate of the camera. This is
- an approximate setting (in terms of "worst" ... "best")
- because camera changes frame rate depending on amount
- of light available. Setting 0 is slowest, 6 is fastest.
- Beware - fast settings are very demanding and may not
- work well with all video sizes. Be conservative.
+ an approximate setting (in terms of "worst" ... "best")
+ because camera changes frame rate depending on amount
+ of light available. Setting 0 is slowest, 6 is fastest.
+ Beware - fast settings are very demanding and may not
+ work well with all video sizes. Be conservative.
hue_correction This highly optional setting allows to adjust the
- hue of the image in a way slightly different from
- what usual "hue" control does. Both controls affect
- YUV colorspace: regular "hue" control adjusts only
- U component, and this "hue_correction" option similarly
- adjusts only V component. However usually it is enough
- to tweak only U or V to compensate for colored light or
- color temperature; this option simply allows more
- complicated correction when and if it is necessary.
+ hue of the image in a way slightly different from
+ what usual "hue" control does. Both controls affect
+ YUV colorspace: regular "hue" control adjusts only
+ U component, and this "hue_correction" option similarly
+ adjusts only V component. However usually it is enough
+ to tweak only U or V to compensate for colored light or
+ color temperature; this option simply allows more
+ complicated correction when and if it is necessary.
init_brightness These settings specify _initial_ values which will be
init_contrast used to set up the camera. If your V4L application has
init_color its own controls to adjust the picture then these
init_hue controls will be used too. These options allow you to
- preconfigure the camera when it gets connected, before
- any V4L application connects to it. Good for webcams.
+ preconfigure the camera when it gets connected, before
+ any V4L application connects to it. Good for webcams.
init_model2_rg These initial settings alter color balance of the
init_model2_rg2 camera on hardware level. All four settings may be used
init_model2_yb settings only apply to Model 2 cameras.
lighting This option selects one of three hardware-defined
- photosensitivity settings of the camera. 0=bright light,
- 1=Medium (default), 2=Low light. This setting affects
- frame rate: the dimmer the lighting the lower the frame
- rate (because longer exposition time is needed). The
- Model 2 cameras allow values more than 2 for this option,
- thus enabling extremely high sensitivity at cost of frame
- rate, color saturation and imaging sensor noise.
+ photosensitivity settings of the camera. 0=bright light,
+ 1=Medium (default), 2=Low light. This setting affects
+ frame rate: the dimmer the lighting the lower the frame
+ rate (because longer exposition time is needed). The
+ Model 2 cameras allow values more than 2 for this option,
+ thus enabling extremely high sensitivity at cost of frame
+ rate, color saturation and imaging sensor noise.
sharpness This option controls smoothing (noise reduction)
- made by camera. Setting 0 is most smooth, setting 6
- is most sharp. Be aware that CMOS sensor used in the
- camera is pretty noisy, so if you choose 6 you will
- be greeted with "snowy" image. Default is 4. Model 2
- cameras do not support this feature.
+ made by camera. Setting 0 is most smooth, setting 6
+ is most sharp. Be aware that CMOS sensor used in the
+ camera is pretty noisy, so if you choose 6 you will
+ be greeted with "snowy" image. Default is 4. Model 2
+ cameras do not support this feature.
size This setting chooses one of several image sizes that are
- supported by this driver. Cameras may support more, but
- it's difficult to reverse-engineer all formats.
- Following video sizes are supported:
-
- size=0 128x96 (Model 1 only)
- size=1 160x120
- size=2 176x144
- size=3 320x240 (Model 2 only)
- size=4 352x240 (Model 2 only)
- size=5 352x288
- size=6 640x480 (Model 3 only)
-
- The 352x288 is the native size of the Model 1 sensor
- array, so it's the best resolution the camera can
- yield. The best resolution of Model 2 is 176x144, and
- larger images are produced by stretching the bitmap.
- Model 3 has sensor with 640x480 grid, and it works too,
- but the frame rate will be exceptionally low (1-2 FPS);
- it may be still OK for some applications, like security.
- Choose the image size you need. The smaller image can
- support faster frame rate. Default is 352x288.
+ supported by this driver. Cameras may support more, but
+ it's difficult to reverse-engineer all formats.
+ Following video sizes are supported:
+
+ size=0 128x96 (Model 1 only)
+ size=1 160x120
+ size=2 176x144
+ size=3 320x240 (Model 2 only)
+ size=4 352x240 (Model 2 only)
+ size=5 352x288
+ size=6 640x480 (Model 3 only)
+
+ The 352x288 is the native size of the Model 1 sensor
+ array, so it's the best resolution the camera can
+ yield. The best resolution of Model 2 is 176x144, and
+ larger images are produced by stretching the bitmap.
+ Model 3 has sensor with 640x480 grid, and it works too,
+ but the frame rate will be exceptionally low (1-2 FPS);
+ it may be still OK for some applications, like security.
+ Choose the image size you need. The smaller image can
+ support faster frame rate. Default is 352x288.
For more information and the Troubleshooting FAQ visit this URL:
- http://www.linux-usb.org/ibmcam/
+ http://www.linux-usb.org/ibmcam/
WHAT NEEDS TO BE DONE:
TYPE: integer (Boolean)
DEFAULT: 1
DESC: Brightness is normally under automatic control and can't be set
- manually by the video app. Set to 0 for manual control.
+ manually by the video app. Set to 0 for manual control.
NAME: autogain
TYPE: integer (Boolean)
TYPE: integer (0-6)
DEFAULT: 3
DESC: Sets the threshold for printing debug messages. The higher the value,
- the more is printed. The levels are cumulative, and are as follows:
- 0=no debug messages
- 1=init/detection/unload and other significant messages
- 2=some warning messages
- 3=config/control function calls
- 4=most function calls and data parsing messages
- 5=highly repetitive mesgs
+ the more is printed. The levels are cumulative, and are as follows:
+ 0=no debug messages
+ 1=init/detection/unload and other significant messages
+ 2=some warning messages
+ 3=config/control function calls
+ 4=most function calls and data parsing messages
+ 5=highly repetitive mesgs
NAME: snapshot
TYPE: integer (Boolean)
TYPE: integer (1-4 for OV511, 1-31 for OV511+)
DEFAULT: 1
DESC: Number of cameras allowed to stream simultaneously on a single bus.
- Values higher than 1 reduce the data rate of each camera, allowing two
- or more to be used at once. If you have a complicated setup involving
- both OV511 and OV511+ cameras, trial-and-error may be necessary for
- finding the optimum setting.
+ Values higher than 1 reduce the data rate of each camera, allowing two
+ or more to be used at once. If you have a complicated setup involving
+ both OV511 and OV511+ cameras, trial-and-error may be necessary for
+ finding the optimum setting.
NAME: compress
TYPE: integer (Boolean)
DEFAULT: 0
DESC: Set this to 1 to turn on the camera's compression engine. This can
- potentially increase the frame rate at the expense of quality, if you
- have a fast CPU. You must load the proper compression module for your
- camera before starting your application (ov511_decomp or ov518_decomp).
+ potentially increase the frame rate at the expense of quality, if you
+ have a fast CPU. You must load the proper compression module for your
+ camera before starting your application (ov511_decomp or ov518_decomp).
NAME: testpat
TYPE: integer (Boolean)
DEFAULT: 0
DESC: This configures the camera's sensor to transmit a colored test-pattern
- instead of an image. This does not work correctly yet.
+ instead of an image. This does not work correctly yet.
NAME: dumppix
TYPE: integer (0-2)
- SN9C10x PC Camera Controllers
- Driver for Linux
- =============================
+ SN9C10x PC Camera Controllers
+ Driver for Linux
+ =============================
- - Documentation -
+ - Documentation -
Index
Type: short array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- recognized camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 64 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ recognized camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: force_munmap
Type: bool array (min = 0, max = 64)
Syntax: <0|1[,...]>
Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+ 0 = do not force memory unmapping
+ 1 = force memory unmapping (save memory)
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.
+ specific for each detected camera. This parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Name: debug
Type: ushort
Syntax: <n>
Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used. It also shows some more informations about the
- hardware being detected. This parameter can be changed at
- runtime thanks to the /sys filesystem interface.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = more verbose messages
+ Level 3 is useful for testing only, when only one device
+ is used. It also shows some more informations about the
+ hardware being detected. This parameter can be changed at
+ runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
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.
+ 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).
+ 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.
+ 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.
+ 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.
The following bytes are used by the SN9C103 bridge only:
--- /dev/null
+/* Simple Video4Linux image grabber. */
+/*
+ * Video4Linux Driver Test/Example Framegrabbing Program
+ *
+ * Compile with:
+ * gcc -s -Wall -Wstrict-prototypes v4lgrab.c -o v4lgrab
+ * Use as:
+ * v4lgrab >image.ppm
+ *
+ * Copyright (C) 1998-05-03, Phil Blundell <philb@gnu.org>
+ * Copied from http://www.tazenda.demon.co.uk/phil/vgrabber.c
+ * with minor modifications (Dave Forrest, drf5n@virginia.edu).
+ *
+ */
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdlib.h>
+
+#include <linux/types.h>
+#include <linux/videodev.h>
+
+#define FILE "/dev/video0"
+
+/* Stole this from tvset.c */
+
+#define READ_VIDEO_PIXEL(buf, format, depth, r, g, b) \
+{ \
+ switch (format) \
+ { \
+ case VIDEO_PALETTE_GREY: \
+ switch (depth) \
+ { \
+ case 4: \
+ case 6: \
+ case 8: \
+ (r) = (g) = (b) = (*buf++ << 8);\
+ break; \
+ \
+ case 16: \
+ (r) = (g) = (b) = \
+ *((unsigned short *) buf); \
+ buf += 2; \
+ break; \
+ } \
+ break; \
+ \
+ \
+ case VIDEO_PALETTE_RGB565: \
+ { \
+ unsigned short tmp = *(unsigned short *)buf; \
+ (r) = tmp&0xF800; \
+ (g) = (tmp<<5)&0xFC00; \
+ (b) = (tmp<<11)&0xF800; \
+ buf += 2; \
+ } \
+ break; \
+ \
+ case VIDEO_PALETTE_RGB555: \
+ (r) = (buf[0]&0xF8)<<8; \
+ (g) = ((buf[0] << 5 | buf[1] >> 3)&0xF8)<<8; \
+ (b) = ((buf[1] << 2 ) & 0xF8)<<8; \
+ buf += 2; \
+ break; \
+ \
+ case VIDEO_PALETTE_RGB24: \
+ (r) = buf[0] << 8; (g) = buf[1] << 8; \
+ (b) = buf[2] << 8; \
+ buf += 3; \
+ break; \
+ \
+ default: \
+ fprintf(stderr, \
+ "Format %d not yet supported\n", \
+ format); \
+ } \
+}
+
+int get_brightness_adj(unsigned char *image, long size, int *brightness) {
+ long i, tot = 0;
+ for (i=0;i<size*3;i++)
+ tot += image[i];
+ *brightness = (128 - tot/(size*3))/3;
+ return !((tot/(size*3)) >= 126 && (tot/(size*3)) <= 130);
+}
+
+int main(int argc, char ** argv)
+{
+ int fd = open(FILE, O_RDONLY), f;
+ struct video_capability cap;
+ struct video_window win;
+ struct video_picture vpic;
+
+ unsigned char *buffer, *src;
+ int bpp = 24, r, g, b;
+ unsigned int i, src_depth;
+
+ if (fd < 0) {
+ perror(FILE);
+ exit(1);
+ }
+
+ if (ioctl(fd, VIDIOCGCAP, &cap) < 0) {
+ perror("VIDIOGCAP");
+ fprintf(stderr, "(" FILE " not a video4linux device?)\n");
+ close(fd);
+ exit(1);
+ }
+
+ if (ioctl(fd, VIDIOCGWIN, &win) < 0) {
+ perror("VIDIOCGWIN");
+ close(fd);
+ exit(1);
+ }
+
+ if (ioctl(fd, VIDIOCGPICT, &vpic) < 0) {
+ perror("VIDIOCGPICT");
+ close(fd);
+ exit(1);
+ }
+
+ if (cap.type & VID_TYPE_MONOCHROME) {
+ vpic.depth=8;
+ vpic.palette=VIDEO_PALETTE_GREY; /* 8bit grey */
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ vpic.depth=6;
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ vpic.depth=4;
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ fprintf(stderr, "Unable to find a supported capture format.\n");
+ close(fd);
+ exit(1);
+ }
+ }
+ }
+ } else {
+ vpic.depth=24;
+ vpic.palette=VIDEO_PALETTE_RGB24;
+
+ if(ioctl(fd, VIDIOCSPICT, &vpic) < 0) {
+ vpic.palette=VIDEO_PALETTE_RGB565;
+ vpic.depth=16;
+
+ if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+ vpic.palette=VIDEO_PALETTE_RGB555;
+ vpic.depth=15;
+
+ if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+ fprintf(stderr, "Unable to find a supported capture format.\n");
+ return -1;
+ }
+ }
+ }
+ }
+
+ buffer = malloc(win.width * win.height * bpp);
+ if (!buffer) {
+ fprintf(stderr, "Out of memory.\n");
+ exit(1);
+ }
+
+ do {
+ int newbright;
+ read(fd, buffer, win.width * win.height * bpp);
+ f = get_brightness_adj(buffer, win.width * win.height, &newbright);
+ if (f) {
+ vpic.brightness += (newbright << 8);
+ if(ioctl(fd, VIDIOCSPICT, &vpic)==-1) {
+ perror("VIDIOSPICT");
+ break;
+ }
+ }
+ } while (f);
+
+ fprintf(stdout, "P6\n%d %d 255\n", win.width, win.height);
+
+ src = buffer;
+
+ for (i = 0; i < win.width * win.height; i++) {
+ READ_VIDEO_PIXEL(src, vpic.palette, src_depth, r, g, b);
+ fputc(r>>8, stdout);
+ fputc(g>>8, stdout);
+ fputc(b>>8, stdout);
+ }
+
+ close(fd);
+ return 0;
+}
- W996[87]CF JPEG USB Dual Mode Camera Chip
- Driver for Linux 2.6 (basic version)
- =========================================
+ W996[87]CF JPEG USB Dual Mode Camera Chip
+ Driver for Linux 2.6 (basic version)
+ =========================================
- - Documentation -
+ - Documentation -
Index
Type: bool
Syntax: <0|1>
Description: Automatic 'ovcamchip' module loading: 0 disabled, 1 enabled.
- If enabled, 'insmod' searches for the required 'ovcamchip'
- module in the system, according to its configuration, and
- loads that module automatically. This action is performed as
- once soon as the 'w9968cf' module is loaded into memory.
+ If enabled, 'insmod' searches for the required 'ovcamchip'
+ module in the system, according to its configuration, and
+ loads that module automatically. This action is performed as
+ once soon as the 'w9968cf' module is loaded into memory.
Default: 1
Note: The kernel must be compiled with the CONFIG_KMOD option
- enabled for the 'ovcamchip' module to be loaded and for
- this parameter to be present.
+ enabled for the 'ovcamchip' module to be loaded and for
+ this parameter to be present.
-------------------------------------------------------------------------------
Name: simcams
Type: int
Syntax: <n>
Description: Number of cameras allowed to stream simultaneously.
- n may vary from 0 to 32.
+ n may vary from 0 to 32.
Default: 32
-------------------------------------------------------------------------------
Name: video_nr
Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Specify V4L minor mode number.
- -1 = use next available
- n = use minor number n
- You can specify up to 32 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- recognized camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 32 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ recognized camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: packet_size
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Specify the maximum data payload size in bytes for alternate
- settings, for each device. n is scaled between 63 and 1023.
+ settings, for each device. n is scaled between 63 and 1023.
Default: 1023
-------------------------------------------------------------------------------
Name: max_buffers
Type: int array (min = 0, max = 32)
Syntax: <n[,...]>
Description: For advanced users.
- Specify the maximum number of video frame buffers to allocate
- for each device, from 2 to 32.
+ Specify the maximum number of video frame buffers to allocate
+ for each device, from 2 to 32.
Default: 2
-------------------------------------------------------------------------------
Name: double_buffer
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Hardware double buffering: 0 disabled, 1 enabled.
- It should be enabled if you want smooth video output: if you
- obtain out of sync. video, disable it, or try to
- decrease the 'clockdiv' module parameter value.
+ It should be enabled if you want smooth video output: if you
+ obtain out of sync. video, disable it, or try to
+ decrease the 'clockdiv' module parameter value.
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: clamping
Type: int array (min = 0, max = 32)
Syntax: <0|1|2[,...]>
Description: Video filter type.
- 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
- The filter is used to reduce noise and aliasing artifacts
- produced by the CCD or CMOS image sensor.
+ 0 none, 1 (1-2-1) 3-tap filter, 2 (2-3-6-3-2) 5-tap filter.
+ The filter is used to reduce noise and aliasing artifacts
+ produced by the CCD or CMOS image sensor.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: largeview
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Software scaling (for non-compressed video only):
- 0 disabled, 1 enabled.
- Disable it if you have a slow CPU or you don't have enough
- memory.
+ 0 disabled, 1 enabled.
+ Disable it if you have a slow CPU or you don't have enough
+ memory.
Default: 0 for every device.
Note: If 'w9968cf-vpp' is not present, this parameter is set to 0.
-------------------------------------------------------------------------------
Type: int array (min = 0, max = 32)
Syntax: <0|1|2[,...]>
Description: Software video decompression:
- 0 = disables decompression
- (doesn't allow formats needing decompression).
- 1 = forces decompression
- (allows formats needing decompression only).
- 2 = allows any permitted formats.
- Formats supporting (de)compressed video are YUV422P and
- YUV420P/YUV420 in any resolutions where width and height are
- multiples of 16.
+ 0 = disables decompression
+ (doesn't allow formats needing decompression).
+ 1 = forces decompression
+ (allows formats needing decompression only).
+ 2 = allows any permitted formats.
+ Formats supporting (de)compressed video are YUV422P and
+ YUV420P/YUV420 in any resolutions where width and height are
+ multiples of 16.
Default: 2 for every device.
Note: If 'w9968cf-vpp' is not present, forcing decompression is not
- allowed; in this case this parameter is set to 2.
+ allowed; in this case this parameter is set to 2.
-------------------------------------------------------------------------------
Name: force_palette
Type: int array (min = 0, max = 32)
Syntax: <0|9|10|13|15|8|7|1|6|3|4|5[,...]>
Description: Force picture palette.
- In order:
- 0 = Off - allows any of the following formats:
- 9 = UYVY 16 bpp - Original video, compression disabled
- 10 = YUV420 12 bpp - Original video, compression enabled
- 13 = YUV422P 16 bpp - Original video, compression enabled
- 15 = YUV420P 12 bpp - Original video, compression enabled
- 8 = YUVY 16 bpp - Software conversion from UYVY
- 7 = YUV422 16 bpp - Software conversion from UYVY
- 1 = GREY 8 bpp - Software conversion from UYVY
- 6 = RGB555 16 bpp - Software conversion from UYVY
- 3 = RGB565 16 bpp - Software conversion from UYVY
- 4 = RGB24 24 bpp - Software conversion from UYVY
- 5 = RGB32 32 bpp - Software conversion from UYVY
- When not 0, this parameter will override 'decompression'.
+ In order:
+ 0 = Off - allows any of the following formats:
+ 9 = UYVY 16 bpp - Original video, compression disabled
+ 10 = YUV420 12 bpp - Original video, compression enabled
+ 13 = YUV422P 16 bpp - Original video, compression enabled
+ 15 = YUV420P 12 bpp - Original video, compression enabled
+ 8 = YUVY 16 bpp - Software conversion from UYVY
+ 7 = YUV422 16 bpp - Software conversion from UYVY
+ 1 = GREY 8 bpp - Software conversion from UYVY
+ 6 = RGB555 16 bpp - Software conversion from UYVY
+ 3 = RGB565 16 bpp - Software conversion from UYVY
+ 4 = RGB24 24 bpp - Software conversion from UYVY
+ 5 = RGB32 32 bpp - Software conversion from UYVY
+ When not 0, this parameter will override 'decompression'.
Default: 0 for every device. Initial palette is 9 (UYVY).
Note: If 'w9968cf-vpp' is not present, this parameter is set to 9.
-------------------------------------------------------------------------------
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Read RGB video data instead of BGR:
- 1 = use RGB component ordering.
- 0 = use BGR component ordering.
- This parameter has effect when using RGBX palettes only.
+ 1 = use RGB component ordering.
+ 0 = use BGR component ordering.
+ This parameter has effect when using RGBX palettes only.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autobright
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Image sensor automatically changes brightness:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: autoexp
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Image sensor automatically changes exposure:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 1 for every device.
-------------------------------------------------------------------------------
Name: lightfreq
Type: int array (min = 0, max = 32)
Syntax: <50|60[,...]>
Description: Light frequency in Hz:
- 50 for European and Asian lighting, 60 for American lighting.
+ 50 for European and Asian lighting, 60 for American lighting.
Default: 50 for every device.
-------------------------------------------------------------------------------
Name: bandingfilter
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Banding filter to reduce effects of fluorescent
- lighting:
- 0 disabled, 1 enabled.
- This filter tries to reduce the pattern of horizontal
- light/dark bands caused by some (usually fluorescent) lighting.
+ lighting:
+ 0 disabled, 1 enabled.
+ This filter tries to reduce the pattern of horizontal
+ light/dark bands caused by some (usually fluorescent) lighting.
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: clockdiv
Type: int array (min = 0, max = 32)
Syntax: <-1|n[,...]>
Description: Force pixel clock divisor to a specific value (for experts):
- n may vary from 0 to 127.
- -1 for automatic value.
- See also the 'double_buffer' module parameter.
+ n may vary from 0 to 127.
+ -1 for automatic value.
+ See also the 'double_buffer' module parameter.
Default: -1 for every device.
-------------------------------------------------------------------------------
Name: backlight
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Objects are lit from behind:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: mirror
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: Reverse image horizontally:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: monochrome
Type: bool array (min = 0, max = 32)
Syntax: <0|1[,...]>
Description: The image sensor is monochrome:
- 0 = no, 1 = yes
+ 0 = no, 1 = yes
Default: 0 for every device.
-------------------------------------------------------------------------------
Name: brightness
Type: long array (min = 0, max = 32)
Syntax: <n[,...]>
Description: Set picture brightness (0-65535).
- This parameter has no effect if 'autobright' is enabled.
+ This parameter has no effect if 'autobright' is enabled.
Default: 31000 for every device.
-------------------------------------------------------------------------------
Name: hue
Type: int
Syntax: <n>
Description: Debugging information level, from 0 to 6:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = configuration or general messages
- 4 = warnings
- 5 = called functions
- 6 = function internals
- Level 5 and 6 are useful for testing only, when only one
- device is used.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = configuration or general messages
+ 4 = warnings
+ 5 = called functions
+ 6 = function internals
+ Level 5 and 6 are useful for testing only, when only one
+ device is used.
Default: 2
-------------------------------------------------------------------------------
Name: specific_debug
Type: bool
Syntax: <0|1>
Description: Enable or disable specific debugging messages:
- 0 = print messages concerning every level <= 'debug' level.
- 1 = print messages concerning the level indicated by 'debug'.
+ 0 = print messages concerning every level <= 'debug' level.
+ 1 = print messages concerning the level indicated by 'debug'.
Default: 0
-------------------------------------------------------------------------------
- ZC0301 Image Processor and Control Chip
- Driver for Linux
- =======================================
+ ZC0301 and ZC0301P Image Processor and Control Chip
+ Driver for Linux
+ ===================================================
- - Documentation -
+ - Documentation -
Index
4. Overview and features
========================
-This driver supports the video interface of the devices mounting the ZC0301
-Image Processor and Control Chip.
+This driver supports the video interface of the devices mounting the ZC0301 or
+ZC0301P Image Processors and Control Chips.
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 ZC0301 driver can be found at the following URL:
+The latest version of the ZC0301[P] driver can be found at the following URL:
http://www.linux-projects.org/
Some of the features of the driver are:
And finally:
- # USB Multimedia devices
+ # V4L USB devices
#
CONFIG_USB_ZC0301=m
Type: short array (min = 0, max = 64)
Syntax: <-1|n[,...]>
Description: Specify V4L2 minor mode number:
- -1 = use next available
- n = use minor number n
- You can specify up to 64 cameras this way.
- For example:
- video_nr=-1,2,-1 would assign minor number 2 to the second
- registered camera and use auto for the first one and for every
- other camera.
+ -1 = use next available
+ n = use minor number n
+ You can specify up to 64 cameras this way.
+ For example:
+ video_nr=-1,2,-1 would assign minor number 2 to the second
+ registered camera and use auto for the first one and for every
+ other camera.
Default: -1
-------------------------------------------------------------------------------
Name: force_munmap
Type: bool array (min = 0, max = 64)
Syntax: <0|1[,...]>
Description: Force the application to unmap previously mapped buffer memory
- before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
- all the applications support this feature. This parameter is
- specific for each detected camera.
- 0 = do not force memory unmapping
- 1 = force memory unmapping (save memory)
+ before calling any VIDIOC_S_CROP or VIDIOC_S_FMT ioctl's. Not
+ all the applications support this feature. This parameter is
+ specific for each detected camera.
+ 0 = do not force memory unmapping
+ 1 = force memory unmapping (save memory)
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.
+ specific for each detected camera. This parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
Name: debug
Type: ushort
Syntax: <n>
Description: Debugging information level, from 0 to 3:
- 0 = none (use carefully)
- 1 = critical errors
- 2 = significant informations
- 3 = more verbose messages
- Level 3 is useful for testing only, when only one device
- is used at the same time. It also shows some more informations
- about the hardware being detected. This module parameter can be
- changed at runtime thanks to the /sys filesystem interface.
+ 0 = none (use carefully)
+ 1 = critical errors
+ 2 = significant informations
+ 3 = more verbose messages
+ Level 3 is useful for testing only, when only one device
+ is used at the same time. It also shows some more informations
+ about the hardware being detected. This module parameter can be
+ changed at runtime thanks to the /sys filesystem interface.
Default: 2
-------------------------------------------------------------------------------
0x041e 0x4017
0x041e 0x401c
0x041e 0x401e
+0x041e 0x401f
+0x041e 0x4022
0x041e 0x4034
0x041e 0x4035
+0x041e 0x4036
+0x041e 0x403a
+0x0458 0x7007
+0x0458 0x700C
+0x0458 0x700f
+0x046d 0x08ae
+0x055f 0xd003
+0x055f 0xd004
0x046d 0x08ae
0x0ac8 0x0301
+0x0ac8 0x301b
+0x0ac8 0x303b
+0x10fd 0x0128
0x10fd 0x8050
+0x10fd 0x804e
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;
Model Manufacturer
----- ------------
PAS202BCB PixArt Imaging, Inc.
+PB-0330 Photobit Corporation
9. Notes for V4L2 application developers
been taken from the documentation of the ZC030x Video4Linux1 driver written
by Andrew Birkett <andy@nobugs.org>;
- The initialization values of the ZC0301 controller connected to the PAS202BCB
- image sensor have been taken from the SPCA5XX driver maintained by
- Michel Xhaard <mxhaard@magic.fr>.
+ and PB-0330 image sensors have been taken from the SPCA5XX driver maintained
+ by Michel Xhaard <mxhaard@magic.fr>;
+- Stanislav Lechev donated one camera.
module will be called videodev.
config VIDEO_V4L1
- boolean "Enable Video For Linux API 1 (DEPRECATED)"
+ bool "Enable Video For Linux API 1 (DEPRECATED)"
depends on VIDEO_DEV
select VIDEO_V4L1_COMPAT
default y
If you are unsure as to whether this is required, answer Y.
config VIDEO_V4L1_COMPAT
- boolean "Enable Video For Linux API 1 compatible Layer"
+ bool "Enable Video For Linux API 1 compatible Layer"
depends on VIDEO_DEV
default y
---help---
config VIDEO_TVEEPROM
tristate
+config VIDEO_CX2341X
+ tristate
+
config USB_DABUSB
tristate "DABUSB driver"
depends on USB
saa7146-objs := saa7146_i2c.o saa7146_core.o
-saa7146_vv-objs := saa7146_vv_ksyms.o saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
+saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o
ir-common-objs := ir-functions.o ir-keymaps.o
obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o
* c-basic-offset: 8
* End:
*/
-
EXPORT_SYMBOL_GPL(ir_codes_em_terratec);
-IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE] = {
[ 0x3a ] = KEY_0,
[ 0x31 ] = KEY_1,
[ 0x32 ] = KEY_2,
[ 0x27 ] = KEY_RECORD,
};
-EXPORT_SYMBOL_GPL(ir_codes_em_pinnacle_usb);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_grey);
IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
[ 0x0f ] = KEY_0,
[ 0x0f ] = KEY_9,
[ 0x00 ] = KEY_POWER,
- [ 0x02 ] = KEY_TUNER, /* TV/FM */
- [ 0x1e ] = KEY_VIDEO,
+ [ 0x1b ] = KEY_AUDIO, /* Audio Source */
+ [ 0x02 ] = KEY_TUNER, /* TV/FM, not on Y0400052 */
+ [ 0x1e ] = KEY_VIDEO, /* Video Source */
+ [ 0x16 ] = KEY_INFO, /* Display information */
[ 0x04 ] = KEY_VOLUMEUP,
[ 0x08 ] = KEY_VOLUMEDOWN,
[ 0x0c ] = KEY_CHANNELUP,
[ 0x10 ] = KEY_CHANNELDOWN,
[ 0x03 ] = KEY_ZOOM, /* fullscreen */
- [ 0x1f ] = KEY_SUBTITLE, /* closed caption/teletext */
+ [ 0x1f ] = KEY_TEXT, /* closed caption/teletext */
[ 0x20 ] = KEY_SLEEP,
+ [ 0x29 ] = KEY_CLEAR, /* boss key */
[ 0x14 ] = KEY_MUTE,
[ 0x2b ] = KEY_RED,
[ 0x2c ] = KEY_GREEN,
[ 0x2d ] = KEY_YELLOW,
[ 0x2e ] = KEY_BLUE,
- [ 0x18 ] = KEY_KPPLUS, /* fine tune + */
- [ 0x19 ] = KEY_KPMINUS, /* fine tune - */
+ [ 0x18 ] = KEY_KPPLUS, /* fine tune + , not on Y040052 */
+ [ 0x19 ] = KEY_KPMINUS, /* fine tune - , not on Y040052 */
+ [ 0x2a ] = KEY_MEDIA, /* PIP (Picture in picture */
[ 0x21 ] = KEY_DOT,
[ 0x13 ] = KEY_ENTER,
- [ 0x22 ] = KEY_BACK,
+ [ 0x11 ] = KEY_LAST, /* Recall (last channel */
+ [ 0x22 ] = KEY_PREVIOUS,
[ 0x23 ] = KEY_PLAYPAUSE,
[ 0x24 ] = KEY_NEXT,
+ [ 0x25 ] = KEY_ARCHIVE, /* Time Shifting */
[ 0x26 ] = KEY_STOP,
- [ 0x27 ] = KEY_RECORD
+ [ 0x27 ] = KEY_RECORD,
+ [ 0x28 ] = KEY_SAVE, /* Screenshot */
+ [ 0x2f ] = KEY_MENU,
+ [ 0x30 ] = KEY_CANCEL,
+ [ 0x31 ] = KEY_CHANNEL, /* Channel Surf */
+ [ 0x32 ] = KEY_SUBTITLE,
+ [ 0x33 ] = KEY_LANGUAGE,
+ [ 0x34 ] = KEY_REWIND,
+ [ 0x35 ] = KEY_FASTFORWARD,
+ [ 0x36 ] = KEY_TV,
+ [ 0x37 ] = KEY_RADIO, /* FM */
+ [ 0x38 ] = KEY_DVD
};
EXPORT_SYMBOL_GPL(ir_codes_winfast);
-IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = {
+IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE] = {
[ 0x59 ] = KEY_MUTE,
[ 0x4a ] = KEY_POWER,
[ 0x0a ] = KEY_BACKSPACE,
};
-EXPORT_SYMBOL_GPL(ir_codes_pinnacle);
+EXPORT_SYMBOL_GPL(ir_codes_pinnacle_color);
/* Hauppauge: the newer, gray remotes (seems there are multiple
* slightly different versions), shipped with cx88+ivtv cards.
EXPORT_SYMBOL_GPL(ir_codes_hauppauge_new);
+IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
+ [ 0x1d ] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+ [ 0x2a ] = KEY_FRONT,
+
+ [ 0x3e ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x06 ] = KEY_3,
+ [ 0x0a ] = KEY_4,
+ [ 0x0e ] = KEY_5,
+ [ 0x12 ] = KEY_6,
+ [ 0x16 ] = KEY_7,
+ [ 0x1a ] = KEY_8,
+ [ 0x1e ] = KEY_9,
+ [ 0x3a ] = KEY_0,
+ [ 0x22 ] = KEY_NUMLOCK, /* -/-- */
+ [ 0x20 ] = KEY_REFRESH,
+
+ [ 0x03 ] = KEY_BRIGHTNESSDOWN,
+ [ 0x28 ] = KEY_AUDIO,
+ [ 0x3c ] = KEY_UP,
+ [ 0x3f ] = KEY_LEFT,
+ [ 0x2e ] = KEY_MUTE,
+ [ 0x3b ] = KEY_RIGHT,
+ [ 0x00 ] = KEY_DOWN,
+ [ 0x07 ] = KEY_BRIGHTNESSUP,
+ [ 0x2c ] = KEY_TEXT,
+
+ [ 0x37 ] = KEY_RECORD,
+ [ 0x17 ] = KEY_PLAY,
+ [ 0x13 ] = KEY_PAUSE,
+ [ 0x26 ] = KEY_STOP,
+ [ 0x18 ] = KEY_FASTFORWARD,
+ [ 0x14 ] = KEY_REWIND,
+ [ 0x33 ] = KEY_ZOOM,
+ [ 0x32 ] = KEY_KEYBOARD,
+ [ 0x30 ] = KEY_GOTO, /* Pointing arrow */
+ [ 0x36 ] = KEY_MACRO, /* Maximize/Minimize (yellow) */
+ [ 0x0b ] = KEY_RADIO,
+ [ 0x10 ] = KEY_POWER,
+
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_npgtech);
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_vv_init);
int saa7146_vv_release(struct saa7146_dev* dev)
{
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_vv_release);
int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
char *name, int type)
*vid = vfd;
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_register_device);
int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev)
{
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_unregister_device);
static int __init saa7146_vv_init_module(void)
{
vv->current_hps_source = source;
vv->current_hps_sync = sync;
}
+EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
int saa7146_enable_overlay(struct saa7146_fh *fh)
{
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_start_preview);
int saa7146_stop_preview(struct saa7146_fh *fh)
{
return 0;
}
+EXPORT_SYMBOL_GPL(saa7146_stop_preview);
static int s_fmt(struct saa7146_fh *fh, struct v4l2_format *f)
{
+++ /dev/null
-#include <linux/module.h>
-#include <media/saa7146_vv.h>
-
-EXPORT_SYMBOL_GPL(saa7146_start_preview);
-EXPORT_SYMBOL_GPL(saa7146_stop_preview);
-
-EXPORT_SYMBOL_GPL(saa7146_set_hps_source_and_sync);
-EXPORT_SYMBOL_GPL(saa7146_register_device);
-EXPORT_SYMBOL_GPL(saa7146_unregister_device);
-
-EXPORT_SYMBOL_GPL(saa7146_vv_init);
-EXPORT_SYMBOL_GPL(saa7146_vv_release);
#include "stv0297.h"
#include "mt312.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
#include "dvb-pll.h"
/* lnb control */
return 0;
}
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct flexcop_device *fc = fe->dvb->priv;
div = params->frequency / 125;
if (params->frequency < 1500000) buf[3] |= 0x10;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
return -EIO;
+ }
return 0;
}
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
- .pll_set = samsung_tbmu24112_pll_set,
};
/* dvb-t mt352 */
return 0;
}
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
+ if (buf_len < 5)
+ return -EINVAL;
+
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
- pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
+ pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = 0xcc;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = samsung_tdtc9251dh0_demod_init,
- .pll_set = samsung_tdtc9251dh0_pll_set,
};
static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
return request_firmware(fw, name, fc->dev);
}
-static int lgdt3303_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct flexcop_device *fc = fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg =
- { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
- int err;
-
- dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
- dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
- __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
- if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
- printk(KERN_WARNING "lgdt3303: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- buf[0] = 0x86 | 0x18;
- buf[1] = 0x50;
- msg.len = 2;
- if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
- printk(KERN_WARNING "lgdt3303: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
+ return lg_h06xf_pll_set(fe, &fc->i2c_adap, params);
}
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.demod_address = 0x59,
.demod_chip = LGDT3303,
.serial_mpeg = 0x04,
- .pll_set = lgdt3303_pll_set,
.clock_polarity_flip = 1,
};
static struct nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a,
- .pll_address = 0xc2,
- .pll_desc = &dvb_pll_samsung_tbmv,
};
static struct bcm3510_config air2pc_atsc_first_gen_config = {
.request_firmware = flexcop_fe_request_firmware,
};
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
if (params->frequency < 1550000)
buf[3] |= 0x02;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
static struct mt312_config skystar23_samsung_tbdu18132_config = {
.demod_address = 0x0e,
- .pll_set = skystar23_samsung_tbdu18132_pll_set,
};
+static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct flexcop_device *fc = fe->dvb->priv;
+ u8 buf[4];
+ u16 div;
+ int ret;
+
+/* 62.5 kHz * 10 */
+#define REF_FREQ 625
+#define FREQ_OFFSET 36125
+
+ div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz
+
+ buf[0] = (u8)( div >> 8) & 0x7f;
+ buf[1] = (u8) div & 0xff;
+
+/* F(osc) = N * Reference Freq. (62.5 kHz)
+ * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
+ * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
+ * byte 4 : 1 * * AGD R3 R2 R1 R0
+ * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
+ * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
+ buf[2] = 0x95;
+
+// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
+// 47 - 153 0 * 0 0 0 0 0 1 0x01
+// 153 - 430 0 * 0 0 0 0 1 0 0x02
+// 430 - 822 0 * 0 0 1 0 0 0 0x08
+// 822 - 862 1 * 0 0 1 0 0 0 0x88
+
+ if (fep->frequency <= 153000000) buf[3] = 0x01;
+ else if (fep->frequency <= 430000000) buf[3] = 0x02;
+ else if (fep->frequency <= 822000000) buf[3] = 0x08;
+ else buf[3] = 0x88;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ 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);
+ deb_tuner("tuner write returned: %d\n",ret);
+
+ return 0;
+}
static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x01,
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
ops->set_voltage = flexcop_set_voltage;
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
fc->dev_type = FC_AIR_DVB;
+ fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
} else
/* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
+ dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
/* try the air atsc 3nd generation (lgdt3303) */
if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC3;
+ fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
} else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
/* try the cable dvb (stv0297) */
if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_CABLE;
+ fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
} else
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
+
+ ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
} else {
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
- ops = fc->fe->ops;
+ ops = &fc->fe->ops;
if (ops->release != NULL)
ops->release(fc->fe);
fc->fe = NULL;
if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0)
return ret;
- if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0)
- goto dma1_free;
+ if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) {
+ flexcop_dma_free(&fc_pci->dma[0]);
+ return ret;
+ }
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1);
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
fc_pci->init_state |= FC_PCI_DMA_INIT;
- goto success;
-dma1_free:
- flexcop_dma_free(&fc_pci->dma[0]);
-
-success:
return ret;
}
spin_lock_init(&fc_pci->irq_lock);
fc_pci->init_state |= FC_PCI_INIT;
- goto success;
+ return ret;
err_pci_iounmap:
pci_iounmap(fc_pci->pdev, fc_pci->io_mem);
pci_release_regions(fc_pci->pdev);
err_pci_disable_device:
pci_disable_device(fc_pci->pdev);
-
-success:
return ret;
}
INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
- goto success;
+ return ret;
+
err_fc_exit:
flexcop_device_exit(fc);
err_pci_exit:
flexcop_pci_exit(fc_pci);
err_kfree:
flexcop_device_kfree(fc);
-success:
return ret;
}
flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS);
flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1);
- ret = 0;
- goto success;
+ return 0;
+
urb_error:
flexcop_usb_transfer_exit(fc_usb);
-success:
return ret;
}
goto err_fc_exit;
info("%s successfully initialized and connected.",DRIVER_NAME);
- ret = 0;
- goto success;
+ return 0;
+
err_fc_exit:
flexcop_device_exit(fc);
err_usb_exit:
flexcop_usb_exit(fc_usb);
err_kfree:
flexcop_device_kfree(fc);
-success:
return ret;
}
static int flexcop_dvb_init(struct flexcop_device *fc)
{
int ret;
- if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) {
+ if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) {
err("error registering DVB adapter");
return ret;
}
dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
fc->init_state |= FC_STATE_DVB_INIT;
- goto success;
+ return 0;
err_connect_frontend:
fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend);
err_dmx:
dvb_unregister_adapter(&fc->dvb_adapter);
return ret;
-
-success:
- return 0;
}
static void flexcop_dvb_exit(struct flexcop_device *fc)
flexcop_device_name(fc,"initialization of","complete");
- ret = 0;
- goto success;
+ return 0;
+
error:
flexcop_device_exit(fc);
-success:
return ret;
}
EXPORT_SYMBOL(flexcop_device_initialize);
int bt878_num;
struct bt878 bt878[BT878_MAX];
-EXPORT_SYMBOL(bt878_debug);
-EXPORT_SYMBOL(bt878_verbose);
EXPORT_SYMBOL(bt878_num);
EXPORT_SYMBOL(bt878);
{ 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
- { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"},
+ { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" },
+ { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" },
+
{ 0, -1, NULL }
};
printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n",
bt878_num);
+ if (bt878_num >= BT878_MAX) {
+ printk(KERN_ERR "bt878: Too many devices inserted\n");
+ result = -ENOMEM;
+ goto fail0;
+ }
if (pci_enable_device(dev))
return -EIO;
module_param(dst_addons, int, 0644);
MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)");
+static unsigned int dst_algo;
+module_param(dst_algo, int, 0644);
+MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)");
+
#define HAS_LOCK 1
#define ATTEMPT_TUNE 2
#define HAS_POWER 4
#define DST_INFO 2
#define DST_DEBUG 3
-#define dprintk(x, y, z, format, arg...) do { \
- if (z) { \
- if ((x > DST_ERROR) && (x > y)) \
- printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_NOTICE) && (x > y)) \
- printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_INFO) && (x > y)) \
- printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \
- else if ((x > DST_DEBUG) && (x > y)) \
- printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \
- } else { \
- if (x > y) \
- printk(format, ##arg); \
- } \
+#define dprintk(x, y, z, format, arg...) do { \
+ if (z) { \
+ if ((x > DST_ERROR) && (x > y)) \
+ printk(KERN_ERR "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_NOTICE) && (x > y)) \
+ printk(KERN_NOTICE "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_INFO) && (x > y)) \
+ printk(KERN_INFO "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ else if ((x > DST_DEBUG) && (x > y)) \
+ printk(KERN_DEBUG "dst(%d) %s: " format "\n", \
+ state->bt->nr, __func__ , ##arg); \
+ } else { \
+ if (x > y) \
+ printk(format, ##arg); \
+ } \
} while(0)
*result = 0;
if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) {
- dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err);
+ dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err);
return -EREMOTEIO;
}
*result = (u8) rd_packet.rd.value;
state->tx_tuna[2] = (freq >> 16) & 0xff;
state->tx_tuna[3] = (freq >> 8) & 0xff;
state->tx_tuna[4] = (u8) freq;
+ } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+ freq = freq / 1000;
+ if (freq < 51000 || freq > 858000)
+ return -EINVAL;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
+ state->tx_tuna[5] = 0x00; /* ATSC */
+ state->tx_tuna[6] = 0x00;
+ if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG)
+ state->tx_tuna[7] = 0x00; /* Digital */
} else
return -EINVAL;
}
dprintk(verbose, DST_INFO, 1, "set symrate %u", srate);
srate /= 1000;
- if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
- sval = srate;
- sval <<= 20;
- do_div(sval, 88000);
- symcalc = (u32) sval;
- dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
- state->tx_tuna[5] = (u8) (symcalc >> 12);
- state->tx_tuna[6] = (u8) (symcalc >> 4);
- state->tx_tuna[7] = (u8) (symcalc << 4);
- } else {
- state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
- state->tx_tuna[6] = (u8) (srate >> 8);
- state->tx_tuna[7] = (u8) srate;
- }
- state->tx_tuna[8] &= ~0x20;
- if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
- if (srate > 8000)
- state->tx_tuna[8] |= 0x20;
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_SYMDIV) {
+ sval = srate;
+ sval <<= 20;
+ do_div(sval, 88000);
+ symcalc = (u32) sval;
+ dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc);
+ state->tx_tuna[5] = (u8) (symcalc >> 12);
+ state->tx_tuna[6] = (u8) (symcalc >> 4);
+ state->tx_tuna[7] = (u8) (symcalc << 4);
+ } else {
+ state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f;
+ state->tx_tuna[6] = (u8) (srate >> 8);
+ state->tx_tuna[7] = (u8) srate;
+ }
+ state->tx_tuna[8] &= ~0x20;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+ if (srate > 8000)
+ state->tx_tuna[8] |= 0x20;
+ }
+ } else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name);
+ if (!strncmp(state->fw_name, "DCTNEW", 6)) {
+ state->tx_tuna[5] = (u8) (srate >> 8);
+ state->tx_tuna[6] = (u8) srate;
+ state->tx_tuna[7] = 0x00;
+ } else if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+ state->tx_tuna[5] = 0x00;
+ state->tx_tuna[6] = (u8) (srate >> 8);
+ state->tx_tuna[7] = (u8) srate;
+ }
}
return 0;
}
-
static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
{
if (state->dst_type != DST_TYPE_IS_CABLE)
state->tx_tuna[8] = 0x80;
break;
case QAM_256:
- state->tx_tuna[8] = 0x00;
+ if (!strncmp(state->fw_name, "DCTNEW", 6))
+ state->tx_tuna[8] = 0xff;
+ else if (!strncmp(state->fw_name, "DCT-CI", 6))
+ state->tx_tuna[8] = 0x00;
break;
case QPSK:
case QAM_AUTO:
}
EXPORT_SYMBOL(dst_check_sum);
-static void dst_type_flags_print(u32 type_flags)
+static void dst_type_flags_print(struct dst_state *state)
{
+ u32 type_flags = state->type_flags;
+
dprintk(verbose, DST_ERROR, 0, "DST type flags :");
- if (type_flags & DST_TYPE_HAS_NEWTUNE)
- dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE);
+ if (type_flags & DST_TYPE_HAS_TS188)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188);
+ if (type_flags & DST_TYPE_HAS_NEWTUNE_2)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2);
if (type_flags & DST_TYPE_HAS_TS204)
dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204);
+ if (type_flags & DST_TYPE_HAS_VLF)
+ dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF);
if (type_flags & DST_TYPE_HAS_SYMDIV)
dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV);
if (type_flags & DST_TYPE_HAS_FW_1)
}
-static int dst_type_print(u8 type)
+static int dst_type_print(struct dst_state *state, u8 type)
{
char *otype;
switch (type) {
otype = "cable";
break;
+ case DST_TYPE_IS_ATSC:
+ otype = "atsc";
+ break;
+
default:
dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type);
return -EINVAL;
return 0;
}
+struct tuner_types tuner_list[] = {
+ {
+ .tuner_type = TUNER_TYPE_L64724,
+ .tuner_name = "L 64724",
+ .board_name = "UNKNOWN",
+ .fw_name = "UNKNOWN"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1020",
+ .fw_name = "DST-MOT"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1020",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_MB86A15,
+ .tuner_name = "MB 86A15",
+ .board_name = "VP1022",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_MB86A15,
+ .tuner_name = "MB 86A15",
+ .board_name = "VP1025",
+ .fw_name = "DST-03T"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1030",
+ .fw_name = "DST-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_STV0299,
+ .tuner_name = "STV 0299",
+ .board_name = "VP1030",
+ .fw_name = "DSTMCI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2021",
+ .fw_name = "DCTNEW"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2030",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2031",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP2040",
+ .fw_name = "DCT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3020",
+ .fw_name = "DTTFTA"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3021",
+ .fw_name = "DTTFTA"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_TDA10046,
+ .tuner_name = "TDA10046",
+ .board_name = "VP3040",
+ .fw_name = "DTT-CI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_UNKNOWN,
+ .tuner_name = "UNKNOWN",
+ .board_name = "VP3051",
+ .fw_name = "DTTNXT"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_NXT200x,
+ .tuner_name = "NXT200x",
+ .board_name = "VP3220",
+ .fw_name = "ATSCDI"
+ },
+
+ {
+ .tuner_type = TUNER_TYPE_NXT200x,
+ .tuner_name = "NXT200x",
+ .board_name = "VP3250",
+ .fw_name = "ATSCAD"
+ },
+};
+
/*
Known cards list
Satellite
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.device_id = "DST-030",
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2,
.dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5
- | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO
+ | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO,
+ .tuner_type = TUNER_TYPE_MULTI
},
{
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
.type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* obsolete */
{
.device_id = "DST-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
}, /* An OEM board */
{
.device_id = "DSTMCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF,
.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
- | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
+ | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC,
+ .tuner_type = TUNER_TYPE_MULTI
},
{
.device_id = "DSTFCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1,
+ .dst_feature = 0,
+ .tuner_type = 0
}, /* unknown to vendor */
{
.device_id = "DCT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_CABLE,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1
- | DST_TYPE_HAS_FW_2,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
},
{
.device_id = "DCTNEW",
.offset = 1,
.dst_type = DST_TYPE_IS_CABLE,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE,
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.device_id = "DTT-CI",
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
- .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE,
- .dst_feature = DST_TYPE_HAS_CA
+ .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF,
+ .dst_feature = DST_TYPE_HAS_CA,
+ .tuner_type = 0
},
{
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.offset = 1,
.dst_type = DST_TYPE_IS_TERR,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = DST_TYPE_HAS_ANALOG
+ .dst_feature = DST_TYPE_HAS_ANALOG,
+ .tuner_type = 0
},
{
.offset = 1,
.dst_type = DST_TYPE_IS_ATSC,
.type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .dst_feature = 0,
+ .tuner_type = 0
},
{
.device_id = "ATSCAD",
.offset = 1,
.dst_type = DST_TYPE_IS_ATSC,
- .type_flags = DST_TYPE_HAS_FW_2,
- .dst_feature = 0
+ .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+ .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG,
+ .tuner_type = 0
},
{ }
static int dst_card_type(struct dst_state *state)
{
+ int j;
+ struct tuner_types *p_tuner_list = NULL;
+
u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
get_type[7] = dst_check_sum(get_type, 7);
if (dst_command(state, get_type, 8) < 0) {
return -1;
}
memset(&state->card_info, '\0', 8);
- memcpy(&state->card_info, &state->rxbuffer, 8);
+ memcpy(&state->card_info, &state->rxbuffer, 7);
dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]);
+ for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+ if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) {
+ state->tuner_type = p_tuner_list->tuner_type;
+ dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]",
+ p_tuner_list->tuner_name, p_tuner_list->tuner_type);
+ }
+ }
+
return 0;
}
return -1;
}
memset(&state->vendor, '\0', 8);
- memcpy(&state->vendor, &state->rxbuffer, 8);
+ memcpy(&state->vendor, &state->rxbuffer, 7);
dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]);
return 0;
}
+static void debug_dst_buffer(struct dst_state *state)
+{
+ int i;
+
+ if (verbose > 2) {
+ printk("%s: [", __func__);
+ for (i = 0; i < 8; i++)
+ printk(" %02x", state->rxbuffer[i]);
+ printk("]\n");
+ }
+}
+
+static int dst_check_stv0299(struct dst_state *state)
+{
+ u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ check_stv0299[7] = dst_check_sum(check_stv0299, 7);
+ if (dst_command(state, check_stv0299, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed");
+ return -1;
+ }
+ debug_dst_buffer(state);
+
+ if (memcmp(&check_stv0299, &state->rxbuffer, 8)) {
+ dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM");
+ state->tuner_type = TUNER_TYPE_STV0299;
+ return 0;
+ }
+
+ return -1;
+}
+
+static int dst_check_mb86a15(struct dst_state *state)
+{
+ u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+ check_mb86a15[7] = dst_check_sum(check_mb86a15, 7);
+ if (dst_command(state, check_mb86a15, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed");
+ return -1;
+ }
+ debug_dst_buffer(state);
+
+ if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM");
+ state->tuner_type = TUNER_TYPE_MB86A15;
+ return 0;
+ }
+
+ return -1;
+}
+
static int dst_get_tuner_info(struct dst_state *state)
{
u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
get_tuner_1[7] = dst_check_sum(get_tuner_1, 7);
get_tuner_2[7] = dst_check_sum(get_tuner_2, 7);
+ dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE");
if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
- if (dst_command(state, get_tuner_2, 8) < 0) {
- dprintk(verbose, DST_INFO, 1, "Unsupported Command");
- return -1;
+ if (dst_command(state, get_tuner_1, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported");
+ goto force;
}
} else {
- if (dst_command(state, get_tuner_1, 8) < 0) {
- dprintk(verbose, DST_INFO, 1, "Unsupported Command");
- return -1;
+ if (dst_command(state, get_tuner_2, 8) < 0) {
+ dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported");
+ goto force;
}
}
memset(&state->board_info, '\0', 8);
memcpy(&state->board_info, &state->rxbuffer, 8);
if (state->type_flags & DST_TYPE_HAS_MULTI_FE) {
- if (state->board_info[1] == 0x0b) {
- if (state->type_flags & DST_TYPE_HAS_TS204)
- state->type_flags &= ~DST_TYPE_HAS_TS204;
- state->type_flags |= DST_TYPE_HAS_NEWTUNE;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=188");
- } else {
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
- state->type_flags |= DST_TYPE_HAS_TS204;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=204");
- }
- } else {
- if (state->board_info[0] == 0xbc) {
- if (state->type_flags & DST_TYPE_HAS_TS204)
- state->type_flags &= ~DST_TYPE_HAS_TS204;
- state->type_flags |= DST_TYPE_HAS_NEWTUNE;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]);
-
- } else if (state->board_info[0] == 0xcc) {
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- state->type_flags &= ~DST_TYPE_HAS_NEWTUNE;
- state->type_flags |= DST_TYPE_HAS_TS204;
- dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]);
+ dprintk(verbose, DST_ERROR, 1, "DST type has TS=188");
+ }
+ if (state->board_info[0] == 0xbc) {
+ if (state->type_flags != DST_TYPE_IS_ATSC)
+ state->type_flags |= DST_TYPE_HAS_TS188;
+ else
+ state->type_flags |= DST_TYPE_HAS_NEWTUNE_2;
+
+ if (state->board_info[1] == 0x01) {
+ state->dst_hw_cap |= DST_TYPE_HAS_DBOARD;
+ dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard");
}
}
return 0;
+force:
+ if (!strncmp(state->fw_name, "DCT-CI", 6)) {
+ state->type_flags |= DST_TYPE_HAS_TS204;
+ dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name);
+ }
+
+ return -1;
}
static int dst_get_device_id(struct dst_state *state)
{
u8 reply;
- int i;
- struct dst_types *p_dst_type;
+ int i, j;
+ struct dst_types *p_dst_type = NULL;
+ struct tuner_types *p_tuner_list = NULL;
+
u8 use_dst_type = 0;
u32 use_type_flags = 0;
static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff};
+ state->tuner_type = 0;
device_type[7] = dst_check_sum(device_type, 7);
if (write_dst(state, device_type, FIXED_COMM))
/* Card capabilities */
state->dst_hw_cap = p_dst_type->dst_feature;
- dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id);
-
+ dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id);
+ strncpy(&state->fw_name[0], p_dst_type->device_id, 6);
+ /* Multiple tuners */
+ if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) {
+ switch (use_dst_type) {
+ case DST_TYPE_IS_SAT:
+ /* STV0299 check */
+ if (dst_check_stv0299(state) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "Unsupported");
+ state->tuner_type = TUNER_TYPE_MB86A15;
+ }
+ break;
+ default:
+ break;
+ }
+ if (dst_check_mb86a15(state) < 0)
+ dprintk(verbose, DST_ERROR, 1, "Unsupported");
+ /* Single tuner */
+ } else {
+ state->tuner_type = p_dst_type->tuner_type;
+ }
+ for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) {
+ if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) &&
+ p_tuner_list->tuner_type == state->tuner_type) {
+ dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]",
+ p_dst_type->device_id, p_tuner_list->tuner_name);
+ }
+ }
break;
}
}
use_dst_type = DST_TYPE_IS_SAT;
use_type_flags = DST_TYPE_HAS_SYMDIV;
}
- dst_type_print(use_dst_type);
+ dst_type_print(state, use_dst_type);
state->type_flags = use_type_flags;
state->dst_type = use_dst_type;
- dst_type_flags_print(state->type_flags);
+ dst_type_flags_print(state);
return 0;
}
static int dst_probe(struct dst_state *state)
{
mutex_init(&state->dst_mutex);
- if ((rdc_8820_reset(state)) < 0) {
- dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
- return -1;
- }
- if (dst_addons & DST_TYPE_HAS_CA)
+ if (dst_addons & DST_TYPE_HAS_CA) {
+ if ((rdc_8820_reset(state)) < 0) {
+ dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed.");
+ return -1;
+ }
msleep(4000);
- else
+ } else {
msleep(100);
-
+ }
if ((dst_comm_init(state)) < 0) {
dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed.");
return -1;
}
if (dst_get_mac(state) < 0) {
dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command");
- return 0;
}
if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) {
if (dst_get_tuner_info(state) < 0)
state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
state->decode_strength = state->rxbuffer[4] << 8;
state->decode_snr = state->rxbuffer[3] << 8;
+ } else if (state->dst_type == DST_TYPE_IS_ATSC) {
+ state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0;
+ state->decode_strength = state->rxbuffer[4] << 8;
+ state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
}
state->cur_jiff = jiffies;
}
state->diseq_flags &= ~(HAS_LOCK);
if (!dst_wait_dst_ready(state, NO_DELAY))
return -EIO;
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE)
- /* how to get variable length reply ???? */
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ !(state->dst_type == DST_TYPE_IS_ATSC))
+
retval = read_dst(state, state->rx_tuna, 10);
else
retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM);
dprintk(verbose, DST_DEBUG, 1, "read not successful");
return retval;
}
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ !(state->dst_type == DST_TYPE_IS_CABLE) &&
+ !(state->dst_type == DST_TYPE_IS_ATSC)) {
+
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
dprintk(verbose, DST_INFO, 1, "checksum failure ? ");
return -EIO;
dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed.");
goto error;
}
- if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
+ if ((state->type_flags & DST_TYPE_HAS_VLF) &&
+ (!(state->dst_type == DST_TYPE_IS_ATSC))) {
+
state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
retval = write_dst(state, &state->tx_tuna[0], 10);
} else {
if (state->dst_type != DST_TYPE_IS_SAT)
return 0;
- if (cmd->msg_len == 0 || cmd->msg_len > 4)
+ if (cmd->msg_len > 0 && cmd->msg_len < 5)
+ memcpy(&paket[3], cmd->msg, cmd->msg_len);
+ else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5)
+ memcpy(&paket[2], cmd->msg, cmd->msg_len);
+ else
return -EINVAL;
- memcpy(&paket[3], cmd->msg, cmd->msg_len);
paket[7] = dst_check_sum(&paket[0], 7);
dst_command(state, paket, 8);
return 0;
static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 };
static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
- static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
+ static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 };
state->inversion = INVERSION_OFF;
state->voltage = SEC_VOLTAGE_13;
state->bandwidth = BANDWIDTH_7_MHZ;
state->cur_jiff = jiffies;
if (state->dst_type == DST_TYPE_IS_SAT)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204));
else if (state->dst_type == DST_TYPE_IS_TERR)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204));
else if (state->dst_type == DST_TYPE_IS_CABLE)
- memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+ memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204));
+ else if (state->dst_type == DST_TYPE_IS_ATSC)
+ memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner));
return 0;
}
return 0;
}
-static int dst_set_frontend(struct dvb_frontend* fe,
+static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+ struct dst_state *state = fe->demodulator_priv;
+
+ if (p != NULL) {
+ dst_set_freq(state, p->frequency);
+ dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency);
+
+ if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ dst_set_inversion(state, p->inversion);
+ dst_set_fec(state, p->u.qpsk.fec_inner);
+ dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_polarization(state);
+ dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->u.qpsk.symbol_rate);
+
+ } else if (state->dst_type == DST_TYPE_IS_TERR)
+ dst_set_bandwidth(state, p->u.ofdm.bandwidth);
+ else if (state->dst_type == DST_TYPE_IS_CABLE) {
+ dst_set_fec(state, p->u.qam.fec_inner);
+ dst_set_symbolrate(state, p->u.qam.symbol_rate);
+ dst_set_modulation(state, p->u.qam.modulation);
+ }
+ dst_write_tuna(fe);
+ }
+
+ return 0;
+}
+
+static int dst_tune_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters* p,
unsigned int mode_flags,
int *delay,
return 0;
}
+static int dst_get_tuning_algo(struct dvb_frontend *fe)
+{
+ return dst_algo;
+}
+
static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
{
struct dst_state *state = fe->demodulator_priv;
static struct dvb_frontend_ops dst_dvbt_ops;
static struct dvb_frontend_ops dst_dvbs_ops;
static struct dvb_frontend_ops dst_dvbc_ops;
+static struct dvb_frontend_ops dst_atsc_ops;
struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter)
{
return NULL;
}
/* determine settings based on type */
+ /* create dvb_frontend */
switch (state->dst_type) {
case DST_TYPE_IS_TERR:
- memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_CABLE:
- memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_SAT:
- memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
+ break;
+ case DST_TYPE_IS_ATSC:
+ memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops));
break;
default:
dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist.");
kfree(state);
return NULL;
}
-
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return state; /* Manu (DST is a card not a frontend) */
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
.release = dst_release,
.init = dst_init,
- .tune = dst_set_frontend,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
+ .get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
+ .read_status = dst_read_status,
+ .read_signal_strength = dst_read_signal_strength,
+ .read_snr = dst_read_snr,
+};
+
+static struct dvb_frontend_ops dst_atsc_ops = {
+ .info = {
+ .name = "DST ATSC",
+ .type = FE_ATSC,
+ .frequency_stepsize = 62500,
+ .frequency_min = 510000000,
+ .frequency_max = 858000000,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .release = dst_release,
+ .init = dst_init,
+ .tune = dst_tune_frontend,
+ .set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
+ .get_frontend_algo = dst_get_tuning_algo,
.read_status = dst_read_status,
.read_signal_strength = dst_read_signal_strength,
.read_snr = dst_read_snr,
};
-MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver");
+MODULE_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver");
MODULE_AUTHOR("Jamie Honan, Manu Abraham");
MODULE_LICENSE("GPL");
return -EOPNOTSUPP;
}
+static void put_command_and_length(u8 *data, int command, int length)
+{
+ data[0] = (command >> 16) & 0xff;
+ data[1] = (command >> 8) & 0xff;
+ data[2] = command & 0xff;
+ data[3] = length;
+}
static void put_checksum(u8 *check_string, int length)
{
u8 dst_ca_comm_err = 0;
while (dst_ca_comm_err < RETRIES) {
- dst_comm_init(state);
dprintk(verbose, DST_CA_NOTICE, 1, " Put Command");
if (dst_ci_command(state, data, ca_string, len, read)) { // If error
dst_error_recovery(state);
dst_ca_comm_err++; // work required here.
+ } else {
+ break;
}
- break;
}
+ if(dst_ca_comm_err == RETRIES)
+ return -1;
+
return 0;
}
static int ca_get_app_info(struct dst_state *state)
{
+ int length, str_length;
static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff};
put_checksum(&command[0], command[0]);
(state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12]));
dprintk(verbose, DST_CA_INFO, 1, " ==================================================================================================");
+ // Transform dst message to correct application_info message
+ length = state->messages[5];
+ str_length = length - 6;
+ if (str_length < 0) {
+ str_length = 0;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering.");
+ }
+
+ // First, the command and length fields
+ put_command_and_length(&state->messages[0], CA_APP_INFO, length);
+
+ // Copy application_type, application_manufacturer and manufacturer_code
+ memcpy(&state->messages[4], &state->messages[7], 5);
+
+ // Set string length and copy string
+ state->messages[9] = str_length;
+ memcpy(&state->messages[10], &state->messages[12], str_length);
+
+ return 0;
+}
+
+static int ca_get_ca_info(struct dst_state *state)
+{
+ int srcPtr, dstPtr, i, num_ids;
+ static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff};
+ const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7;
+
+ put_checksum(&slot_command[0], slot_command[0]);
+ if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !");
+ return -1;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !");
+
+ // Print raw data
+ dprintk(verbose, DST_CA_INFO, 0, " DST data = [");
+ for (i = 0; i < state->messages[0] + 1; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]);
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
+ // Set the command and length of the output
+ num_ids = state->messages[in_num_ids_pos];
+ if (num_ids >= 100) {
+ num_ids = 100;
+ dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering.");
+ }
+ put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2);
+
+ dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = [");
+ srcPtr = in_system_id_pos;
+ dstPtr = out_system_id_pos;
+ for(i = 0; i < num_ids; i++) {
+ dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]);
+ // Append to output
+ state->messages[dstPtr + 0] = state->messages[srcPtr + 0];
+ state->messages[dstPtr + 1] = state->messages[srcPtr + 1];
+ srcPtr += 2;
+ dstPtr += 2;
+ }
+ dprintk(verbose, DST_CA_INFO, 0, "]\n");
+
return 0;
}
dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]);
dprintk(verbose, DST_CA_INFO, 0, "===================================\n");
- for (i = 0; i < 8; i++)
+ for (i = 0; i < slot_cap[0] + 1; i++)
dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]);
dprintk(verbose, DST_CA_INFO, 0, "\n");
if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
return -EFAULT;
break;
+ case CA_INFO:
+ memcpy(p_ca_message->msg, state->messages, 128);
+ if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) )
+ return -EFAULT;
+ break;
}
}
rdc_reset_state(state);
return -1;
}
- dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes.");
+ dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success.");
return 0;
}
return 0;
}
+
static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
{
u32 length = 0;
}
dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !");
break;
+ case CA_INFO_ENQUIRY:
+ dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information");
+
+ if ((ca_get_ca_info(state)) < 0) {
+ dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !");
+ result = -1;
+ goto free_mem_and_exit;
+ }
+ dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !");
+ break;
}
}
free_mem_and_exit:
void __user *arg = (void __user *)ioctl_arg;
int result = 0;
- if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
- }
- if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
+ p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
+ p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
+ p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL);
+ if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) {
dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
- }
- if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
- dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure");
- return -ENOMEM;
+ result = -ENOMEM;
+ goto free_mem_and_exit;
}
+
/* We have now only the standard ioctl's, the driver is upposed to handle internals. */
switch (cmd) {
case CA_SEND_MSG:
static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset)
{
- int bytes_read = 0;
+ ssize_t bytes_read = 0;
dprintk(verbose, DST_CA_DEBUG, 1, " Device read.");
#define DST_TYPE_IS_CABLE 2
#define DST_TYPE_IS_ATSC 3
-#define DST_TYPE_HAS_NEWTUNE 1
+#define DST_TYPE_HAS_TS188 1
#define DST_TYPE_HAS_TS204 2
#define DST_TYPE_HAS_SYMDIV 4
#define DST_TYPE_HAS_FW_1 8
#define DST_TYPE_HAS_OBS_REGS 128
#define DST_TYPE_HAS_INC_COUNT 256
#define DST_TYPE_HAS_MULTI_FE 512
+#define DST_TYPE_HAS_NEWTUNE_2 1024
+#define DST_TYPE_HAS_DBOARD 2048
+#define DST_TYPE_HAS_VLF 4096
/* Card capability list */
#define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */
#define DST_TYPE_HAS_SESSION 128
+#define TUNER_TYPE_MULTI 1
+#define TUNER_TYPE_UNKNOWN 2
+/* DVB-S */
+#define TUNER_TYPE_L64724 4
+#define TUNER_TYPE_STV0299 8
+#define TUNER_TYPE_MB86A15 16
+
+/* DVB-T */
+#define TUNER_TYPE_TDA10046 32
+
+/* ATSC */
+#define TUNER_TYPE_NXT200x 64
+
+
#define RDC_8820_PIO_0_DISABLE 0
#define RDC_8820_PIO_0_ENABLE 1
#define RDC_8820_INT 2
struct bt878* bt;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct dst_config* config;
u8 card_info[8];
u8 vendor[8];
u8 board_info[8];
-
+ u32 tuner_type;
+ char *tuner_name;
struct mutex dst_mutex;
+ u8 fw_name[8];
+};
+
+struct tuner_types {
+ u32 tuner_type;
+ char *tuner_name;
+ char *board_name;
+ char *fw_name;
};
struct dst_types {
u8 dst_type;
u32 type_flags;
u32 dst_feature;
+ u32 tuner_type;
};
struct dst_config
return 0;
}
-static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
+ if (buf_len < 5)
+ return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 542000000)
else
bs = 0x08;
- pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address
+ pllbuf[0] = 0x60;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config thomson_dtt7579_config = {
.demod_address = 0x0f,
.demod_init = thomson_dtt7579_demod_init,
- .pll_set = thomson_dtt7579_pll_set,
};
-static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static struct zl10353_config thomson_dtt7579_zl10353_config = {
+ .demod_address = 0x0f,
+};
+
+static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
u32 freq = params->frequency;
return 0;
}
-static int pinnsat_pll_init(struct dvb_frontend* fe)
+static int pinnsat_tuner_init(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
return 0;
}
-static int pinnsat_pll_sleep(struct dvb_frontend* fe)
+static int pinnsat_tuner_sleep(struct dvb_frontend* fe)
{
struct dvb_bt8xx_card *card = fe->dvb->priv;
static struct cx24110_config pctvsat_config = {
.demod_address = 0x55,
- .pll_init = pinnsat_pll_init,
- .pll_set = cx24108_pll_set,
- .pll_sleep = pinnsat_pll_sleep,
};
-static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int microtune_mt7202dtf_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 cfg, cpump, band_select;
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return (div * 166666 - 36000000);
}
static struct sp887x_config microtune_mt7202dtf_config = {
.demod_address = 0x70,
- .pll_set = microtune_mt7202dtf_pll_set,
.request_firmware = microtune_mt7202dtf_request_firmware,
};
return 0;
}
-static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
unsigned char bs = 0;
unsigned char cp = 0;
+ if (buf_len < 5) return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
if (params->frequency < 150000000)
else
bs = 0x08;
- pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
+ pllbuf[0] = 0x61;
pllbuf[1] = div >> 8;
pllbuf[2] = div & 0xff;
pllbuf[3] = cp;
pllbuf[4] = bs;
- return 0;
+ return 5;
}
static struct mt352_config advbt771_samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = advbt771_samsung_tdtc9251dh0_demod_init,
- .pll_set = advbt771_samsung_tdtc9251dh0_pll_set,
};
static struct dst_config dst_config = {
.sleep = or51211_sleep,
};
-static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
u8 buf[4];
else
return -EINVAL;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(card->i2c_adapter, &msg, 1);
return 0;
}
static struct nxt6000_config vp3021_alps_tded4_config = {
.demod_address = 0x0a,
.clock_inversion = 1,
- .pll_set = vp3021_alps_tded4_pll_set,
};
static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe)
return 0;
}
-static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
+static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len)
{
u32 div;
struct dvb_ofdm_parameters *op = ¶ms->u.ofdm;
+ if (buf_len < 5)
+ return -EINVAL;
+
div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
- pllbuf[0] = 0xc2;
+ pllbuf[0] = 0x61;
pllbuf[1] = (div >> 8) & 0x7F;
pllbuf[2] = div & 0xFF;
pllbuf[3] = 0x85;
if (op->bandwidth == 8)
pllbuf[4] |= 0x04;
- return 0;
+ return 5;
}
static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt)
static struct mt352_config digitv_alps_tded4_config = {
.demod_address = 0x0a,
.demod_init = digitv_alps_tded4_demod_init,
- .pll_set = digitv_alps_tded4_pll_set,
};
-static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv;
- u8 buf[4];
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- int err;
-
- dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0);
- dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
- __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
- if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) {
- printk(KERN_WARNING "dvb-bt8xx: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- /* Set the Auxiliary Byte. */
- buf[2] &= ~0x20;
- buf[2] |= 0x18;
- buf[3] = 0x50;
- i2c_transfer(card->i2c_adapter, &msg, 1);
-
- return 0;
+ return lg_h06xf_pll_set(fe, card->i2c_adapter, params);
}
static struct lgdt330x_config tdvs_tua6034_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .pll_set = tdvs_tua6034_pll_set,
};
static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
switch(type) {
case BTTV_BOARD_DVICO_DVBT_LITE:
card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+
+ if (card->fe == NULL)
+ card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+ card->i2c_adapter);
+
if (card->fe != NULL) {
- card->fe->ops->info.frequency_min = 174000000;
- card->fe->ops->info.frequency_max = 862000000;
+ card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+ card->fe->ops.info.frequency_max = 862000000;
}
break;
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card);
card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
- if (card->fe != NULL)
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
dprintk ("dvb_bt8xx: lgdt330x detected\n");
+ }
break;
case BTTV_BOARD_NEBULA_DIGITV:
digitv_alps_tded4_reset(card);
card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
break;
}
digitv_alps_tded4_reset(card);
card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
- if (card->fe != NULL)
+ if (card->fe != NULL) {
+ card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n");
+ }
break;
case BTTV_BOARD_AVDVBT_761:
card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
+ }
break;
case BTTV_BOARD_AVDVBT_771:
card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
if (card->fe != NULL) {
- card->fe->ops->info.frequency_min = 174000000;
- card->fe->ops->info.frequency_max = 862000000;
+ card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
+ card->fe->ops.info.frequency_min = 174000000;
+ card->fe->ops.info.frequency_max = 862000000;
}
break;
case BTTV_BOARD_PINNACLESAT:
card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+ if (card->fe) {
+ card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
+ card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
+ card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params;
+ }
break;
case BTTV_BOARD_PC_HDTV:
else
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
printk("dvb-bt8xx: Frontend registration failed!\n");
- if (card->fe->ops->release)
- card->fe->ops->release(card->fe);
+ if (card->fe->ops.release)
+ card->fe->ops.release(card->fe);
card->fe = NULL;
}
}
{
int result;
- if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) {
+ if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) {
printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result);
return result;
}
#include "cx24110.h"
#include "or51211.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "zl10353.h"
struct dvb_bt8xx_card {
struct mutex lock;
config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE
bool "Register the onboard IR Remote Control Receiver as Input Device"
depends on DVB_CINERGYT2_TUNING
- default "yes"
+ default y
help
Enable this option if you want to use the onboard Infrared Remote
Control Receiver as Linux-Input device.
{
struct dvb_device *dvbdev = file->private_data;
struct cinergyt2 *cinergyt2 = dvbdev->priv;
+ unsigned int mask = 0;
if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem))
return -ERESTARTSYS;
poll_wait(file, &cinergyt2->poll_wq, wait);
+ if (cinergyt2->pending_fe_events != 0)
+ mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
mutex_unlock(&cinergyt2->sem);
- return (POLLIN | POLLRDNORM | POLLPRI);
+ return mask;
}
return -ENOMEM;
}
- if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) {
+ if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) {
kfree(cinergyt2);
return err;
}
# Makefile for the kernel DVB device drivers.
#
-dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
- dvb_ca_en50221.o dvb_frontend.o \
- dvb_net.o dvb_ringbuffer.o
+dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
+ dvb_ca_en50221.o dvb_frontend.o \
+ dvb_net.o dvb_ringbuffer.o dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o
mutex_unlock(&dmxdevfilter->mutex);
break;
- case DMX_GET_EVENT:
- break;
-
case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) {
ret = -EINVAL;
break;
case DVB_CA_SLOTSTATE_VALIDATE:
- if (dvb_ca_en50221_parse_attributes(ca, slot)
- != 0) {
+ if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
case DVB_CA_SLOTSTATE_LINKINIT:
if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+ /* we need this extra check for annoying interfaces like the budget-av */
+ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+ (ca->pub->poll_slot_status)) {
+ int status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+ if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+ ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+ dvb_ca_en50221_thread_update_delay(ca);
+ break;
+ }
+ }
+
printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
dvb_ca_en50221_thread_update_delay(ca);
goto bailout;
}
memcpy(&demux->tsbuf[i], buf, j);
- if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) {
+ if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) {
memcpy(tmppack, demux->tsbuf, 188);
if (tmppack[0] == 0xB8)
tmppack[0] = 0x47;
}
while (p < count) {
- if ((buf[p] == 0x47) | (buf[p] == 0xB8)) {
+ if ((buf[p] == 0x47) || (buf[p] == 0xB8)) {
if (count - p >= 204) {
memcpy(tmppack, &buf[p], 188);
if (tmppack[0] == 0xB8)
module_param(dvb_override_tune_delay, int, 0644);
MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)");
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
#define dprintk if (dvb_frontend_debug) printk
#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW 1
/*
* FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
* FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
sizeof (struct dvb_frontend_parameters));
if (status & FE_HAS_LOCK)
- if (fe->ops->get_frontend)
- fe->ops->get_frontend(fe, &e->parameters);
+ if (fe->ops.get_frontend)
+ fe->ops.get_frontend(fe, &e->parameters);
events->eventw = wp;
{
dprintk ("DVB: initialising frontend %i (%s)...\n",
fe->dvb->num,
- fe->ops->info.name);
-
- if (fe->ops->init)
- fe->ops->init(fe);
+ fe->ops.info.name);
+
+ if (fe->ops.init)
+ fe->ops.init(fe);
+ if (fe->ops.tuner_ops.init) {
+ fe->ops.tuner_ops.init(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
}
void dvb_frontend_reinitialise(struct dvb_frontend *fe)
u32 original_frequency = fepriv->parameters.frequency;
/* are we using autoinversion? */
- autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO));
/* setup parameters correctly */
fepriv->parameters.frequency += fepriv->lnb_drift;
if (autoinversion)
fepriv->parameters.inversion = fepriv->inversion;
- if (fe->ops->set_frontend)
- fe->ops->set_frontend(fe, &fepriv->parameters);
+ if (fe->ops.set_frontend)
+ fe->ops.set_frontend(fe, &fepriv->parameters);
fepriv->parameters.frequency = original_frequency;
fepriv->parameters.inversion = original_inversion;
/* in SCAN mode, we just set the frontend when asked and leave it alone */
if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
if (fepriv->state & FESTATE_RETUNE) {
- if (fe->ops->set_frontend)
- fe->ops->set_frontend(fe, &fepriv->parameters);
+ if (fe->ops.set_frontend)
+ fe->ops.set_frontend(fe, &fepriv->parameters);
fepriv->state = FESTATE_TUNED;
}
fepriv->delay = 3*HZ;
if (fepriv->state & FESTATE_RETUNE) {
s = 0;
} else {
- if (fe->ops->read_status)
- fe->ops->read_status(fe, &s);
+ if (fe->ops.read_status)
+ fe->ops.read_status(fe, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
fepriv->state = FESTATE_TUNED;
/* if we're tuned, then we have determined the correct inversion */
- if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) &&
+ if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
(fepriv->parameters.inversion == INVERSION_AUTO)) {
fepriv->parameters.inversion = fepriv->inversion;
}
/* don't actually do anything if we're in the LOSTLOCK state,
* the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
if ((fepriv->state & FESTATE_LOSTLOCK) &&
- (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+ (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
return;
}
if (fepriv->reinitialise) {
dvb_frontend_init(fe);
if (fepriv->tone != -1) {
- fe->ops->set_tone(fe, fepriv->tone);
+ fe->ops.set_tone(fe, fepriv->tone);
}
if (fepriv->voltage != -1) {
- fe->ops->set_voltage(fe, fepriv->voltage);
+ fe->ops.set_voltage(fe, fepriv->voltage);
}
fepriv->reinitialise = 0;
}
/* do an iteration of the tuning loop */
- if (fe->ops->tune) {
+ if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) {
/* have we been asked to retune? */
params = NULL;
if (fepriv->state & FESTATE_RETUNE) {
fepriv->state = FESTATE_TUNED;
}
- fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
+ fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s);
if (s != fepriv->status) {
dvb_frontend_add_event(fe, s);
fepriv->status = s;
if (dvb_shutdown_timeout) {
if (dvb_powerdown_on_sleep)
- if (fe->ops->set_voltage)
- fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF);
- if (fe->ops->sleep)
- fe->ops->sleep(fe);
+ if (fe->ops.set_voltage)
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+ if (fe->ops.tuner_ops.sleep) {
+ fe->ops.tuner_ops.sleep(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.sleep)
+ fe->ops.sleep(fe);
}
fepriv->thread_pid = 0;
switch (cmd) {
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
- memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info));
+ memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
break;
}
- if (fe->ops->read_status)
- err = fe->ops->read_status(fe, status);
+ if (fe->ops.read_status)
+ err = fe->ops.read_status(fe, status);
break;
}
case FE_READ_BER:
- if (fe->ops->read_ber)
- err = fe->ops->read_ber(fe, (__u32*) parg);
+ if (fe->ops.read_ber)
+ err = fe->ops.read_ber(fe, (__u32*) parg);
break;
case FE_READ_SIGNAL_STRENGTH:
- if (fe->ops->read_signal_strength)
- err = fe->ops->read_signal_strength(fe, (__u16*) parg);
+ if (fe->ops.read_signal_strength)
+ err = fe->ops.read_signal_strength(fe, (__u16*) parg);
break;
case FE_READ_SNR:
- if (fe->ops->read_snr)
- err = fe->ops->read_snr(fe, (__u16*) parg);
+ if (fe->ops.read_snr)
+ err = fe->ops.read_snr(fe, (__u16*) parg);
break;
case FE_READ_UNCORRECTED_BLOCKS:
- if (fe->ops->read_ucblocks)
- err = fe->ops->read_ucblocks(fe, (__u32*) parg);
+ if (fe->ops.read_ucblocks)
+ err = fe->ops.read_ucblocks(fe, (__u32*) parg);
break;
case FE_DISEQC_RESET_OVERLOAD:
- if (fe->ops->diseqc_reset_overload) {
- err = fe->ops->diseqc_reset_overload(fe);
+ if (fe->ops.diseqc_reset_overload) {
+ err = fe->ops.diseqc_reset_overload(fe);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_DISEQC_SEND_MASTER_CMD:
- if (fe->ops->diseqc_send_master_cmd) {
- err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+ if (fe->ops.diseqc_send_master_cmd) {
+ err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_DISEQC_SEND_BURST:
- if (fe->ops->diseqc_send_burst) {
- err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+ if (fe->ops.diseqc_send_burst) {
+ err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
}
break;
case FE_SET_TONE:
- if (fe->ops->set_tone) {
- err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
+ if (fe->ops.set_tone) {
+ err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->tone = (fe_sec_tone_mode_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
break;
case FE_SET_VOLTAGE:
- if (fe->ops->set_voltage) {
- err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg);
+ if (fe->ops.set_voltage) {
+ err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
fepriv->voltage = (fe_sec_voltage_t) parg;
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
break;
case FE_DISHNETWORK_SEND_LEGACY_CMD:
- if (fe->ops->dishnetwork_send_legacy_command) {
- err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+ if (fe->ops.dishnetwork_send_legacy_command) {
+ err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
- } else if (fe->ops->set_voltage) {
+ } else if (fe->ops.set_voltage) {
/*
* NOTE: This is a fallback condition. Some frontends
* (stv0299 for instance) take longer than 8msec to
/* before sending a command, initialize by sending
* a 32ms 18V to the switch
*/
- fe->ops->set_voltage(fe, SEC_VOLTAGE_18);
+ fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
dvb_frontend_sleep_until(&nexttime, 32000);
for (i = 0; i < 9; i++) {
do_gettimeofday(&tv[i + 1]);
if ((cmd & 0x01) != last) {
/* set voltage to (last ? 13V : 18V) */
- fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
last = (last) ? 0 : 1;
}
cmd = cmd >> 1;
break;
case FE_DISEQC_RECV_SLAVE_REPLY:
- if (fe->ops->diseqc_recv_slave_reply)
- err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+ if (fe->ops.diseqc_recv_slave_reply)
+ err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
break;
case FE_ENABLE_HIGH_LNB_VOLTAGE:
- if (fe->ops->enable_high_lnb_voltage)
- err = fe->ops->enable_high_lnb_voltage(fe, (long) parg);
+ if (fe->ops.enable_high_lnb_voltage)
+ err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
break;
case FE_SET_FRONTEND: {
fepriv->parameters.inversion = INVERSION_AUTO;
fetunesettings.parameters.inversion = INVERSION_AUTO;
}
- if (fe->ops->info.type == FE_OFDM) {
+ if (fe->ops.info.type == FE_OFDM) {
/* without hierachical coding code_rate_LP is irrelevant,
* so we tolerate the otherwise invalid FEC_NONE setting */
if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE &&
}
/* get frontend-specific tuning settings */
- if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) {
+ if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
fepriv->max_drift = fetunesettings.max_drift;
fepriv->step_size = fetunesettings.step_size;
} else {
/* default values */
- switch(fe->ops->info.type) {
+ switch(fe->ops.info.type) {
case FE_QPSK:
fepriv->min_delay = HZ/20;
fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000;
case FE_OFDM:
fepriv->min_delay = HZ/20;
- fepriv->step_size = fe->ops->info.frequency_stepsize * 2;
- fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1;
+ fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+ fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
break;
case FE_ATSC:
- printk("dvb-core: FE_ATSC not handled yet.\n");
+ fepriv->min_delay = HZ/20;
+ fepriv->step_size = 0;
+ fepriv->max_drift = 0;
break;
}
}
break;
case FE_GET_FRONTEND:
- if (fe->ops->get_frontend) {
+ if (fe->ops.get_frontend) {
memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters));
- err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg);
+ err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg);
}
break;
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
- fe->ops->info.name);
+ fe->ops.info.name);
dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND);
mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
- if (fe->ops->release)
- fe->ops->release(fe);
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.release)
+ fe->ops.release(fe);
else
- printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name);
+ printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
/* fe is invalid now */
kfree(fepriv);
mutex_unlock(&frontend_mutex);
struct dvb_frontend;
+struct dvb_tuner_info {
+ char name[128];
+
+ u32 frequency_min;
+ u32 frequency_max;
+ u32 frequency_step;
+
+ u32 bandwidth_min;
+ u32 bandwidth_max;
+ u32 bandwidth_step;
+};
+
+struct dvb_tuner_ops {
+
+ struct dvb_tuner_info info;
+
+ int (*release)(struct dvb_frontend *fe);
+ int (*init)(struct dvb_frontend *fe);
+ int (*sleep)(struct dvb_frontend *fe);
+
+ /** This is for simple PLLs - set all parameters in one go. */
+ int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
+
+ /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+ int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len);
+
+ int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+ int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+
+#define TUNER_STATUS_LOCKED 1
+ int (*get_status)(struct dvb_frontend *fe, u32 *status);
+
+ /** These are provided seperately from set_params in order to facilitate silicon
+ * tuners which require sophisticated tuning loops, controlling each parameter seperately. */
+ int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+ int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+};
+
struct dvb_frontend_ops {
struct dvb_frontend_info info;
unsigned int mode_flags,
int *delay,
fe_status_t *status);
+ /* get frontend tuning algorithm from the module */
+ int (*get_frontend_algo)(struct dvb_frontend *fe);
/* these two are only used for the swzigzag code */
int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+
+ struct dvb_tuner_ops tuner_ops;
};
#define MAX_EVENT 8
};
struct dvb_frontend {
- struct dvb_frontend_ops* ops;
+ struct dvb_frontend_ops ops;
struct dvb_adapter *dvb;
void* demodulator_priv;
+ void* tuner_priv;
void* frontend_priv;
void* misc_priv;
};
--- /dev/null
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+ 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+ 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+ 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+ 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+ 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+ 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+ 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+ 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+ 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+ 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+ 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+ 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+ 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+ 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+ 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+ 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+ 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+ 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+ 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+ 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+ 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+ 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+ 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+ 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+ 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+ 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+ 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+ 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+ 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+ 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+ 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+ 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+ /**
+ * returns: log2(value) * 2^24
+ * wrong result if value = 0 (log2(0) is undefined)
+ */
+ unsigned int msb;
+ unsigned int logentry;
+ unsigned int significand;
+ unsigned int interpolation;
+
+ if (unlikely(value == 0)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ /* first detect the msb (count begins at 0) */
+ msb = fls(value) - 1;
+
+ /**
+ * now we use a logtable after the following method:
+ *
+ * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+ * where x = msb and therefore 1 <= y < 2
+ * first y is determined by shifting the value left
+ * so that msb is bit 31
+ * 0x00231f56 -> 0x8C7D5800
+ * the result is y * 2^31 -> "significand"
+ * then the highest 9 bits are used for a table lookup
+ * the highest bit is discarded because it's always set
+ * the highest nine bits in our example are 100011000
+ * so we would use the entry 0x18
+ */
+ significand = value << (31 - msb);
+ logentry = (significand >> 23) & 0xff;
+
+ /**
+ * last step we do is interpolation because of the
+ * limitations of the log table the error is that part of
+ * the significand which isn't used for lookup then we
+ * compute the ratio between the error and the next table entry
+ * and interpolate it between the log table entry used and the
+ * next one the biggest error possible is 0x7fffff
+ * (in our example it's 0x7D5800)
+ * needed value for next table entry is 0x800000
+ * so the interpolation is
+ * (error / 0x800000) * (logtable_next - logtable_current)
+ * in the implementation the division is moved to the end for
+ * better accuracy there is also an overflow correction if
+ * logtable_next is 256
+ */
+ interpolation = ((significand & 0x7fffff) *
+ ((logtable[(logentry + 1) & 0xff] -
+ logtable[logentry]) & 0xffff)) >> 15;
+
+ /* now we return the result */
+ return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+ /**
+ * returns: log10(value) * 2^24
+ * wrong result if value = 0 (log10(0) is undefined)
+ */
+ u64 log;
+
+ if (unlikely(value == 0)) {
+ WARN_ON(1);
+ return 0;
+ }
+
+ log = intlog2(value);
+
+ /**
+ * we use the following method:
+ * log10(x) = log2(x) * log10(2)
+ */
+
+ return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
--- /dev/null
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ * intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ * intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ * due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
* Hilmar Linder <hlinder@cosy.sbg.ac.at>
* and Wolfram Stering <wstering@cosy.sbg.ac.at>
*
- * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt.
+ * ULE Decaps according to RFC 4326.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* Bugfixes and robustness improvements.
* Filtering on dest MAC addresses, if present (D-Bit = 0)
* ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by
+ * Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ * Paris Lodron University of Salzburg.
*/
/*
*
* Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
*
- * TS_FEED callback is called once for every single TS cell although it is
- * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()).
- *
*/
#include <linux/module.h>
#ifdef ULE_DEBUG
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
static void hexdump( const unsigned char *buf, unsigned short len )
#define ULE_TEST 0
#define ULE_BRIDGED 1
+#define ULE_OPTEXTHDR_PADDING 0
+
static int ule_test_sndu( struct dvb_net_priv *p )
{
return -1;
static int ule_bridged_sndu( struct dvb_net_priv *p )
{
- /* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt.
- * This has to be the last extension header, otherwise it won't work.
- * Blame the authors!
+ struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+ if(ntohs(hdr->h_proto) < 1536) {
+ int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+ /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+ if(framelen != ntohs(hdr->h_proto)) {
+ return -1;
+ }
+ }
+ /* Note:
+ * From RFC4326:
+ * "A bridged SNDU is a Mandatory Extension Header of Type 1.
+ * It must be the final (or only) extension header specified in the header chain of a SNDU."
+ * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
*/
p->ule_bridged = 1;
return 0;
}
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+ return 0;
+}
/** Handle ULE extension headers.
* Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
{ [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, };
/* Table of optional extension header handlers. The header type is the index. */
- static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, };
+ static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+ { [0] = ule_exthdr_padding, [1] = NULL, };
int ext_len = 0;
unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
/* Mandatory extension header */
if (ule_mandatory_ext_handlers[htype]) {
ext_len = ule_mandatory_ext_handlers[htype]( p );
- p->ule_next_hdr += ext_len;
- if (! p->ule_bridged) {
- p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
- p->ule_next_hdr += 2;
- } else {
- p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) );
- /* This assures the extension handling loop will terminate. */
+ if(ext_len >= 0) {
+ p->ule_next_hdr += ext_len;
+ if (!p->ule_bridged) {
+ p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr);
+ p->ule_next_hdr += 2;
+ } else {
+ p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+ /* This assures the extension handling loop will terminate. */
+ }
}
+ // else: extension handler failed or SNDU should be discarded
} else
ext_len = -1; /* SNDU has to be discarded. */
} else {
/* Optional extension header. Calculate the length. */
- ext_len = hlen << 2;
+ ext_len = hlen << 1;
/* Process the optional extension header according to its type. */
if (ule_optional_ext_handlers[htype])
(void)ule_optional_ext_handlers[htype]( p );
p->ule_next_hdr += ext_len;
- p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr );
- p->ule_next_hdr += 2;
+ p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) );
+ /*
+ * note: the length of the next header type is included in the
+ * length of THIS optional extension header
+ */
}
return ext_len;
p->ule_next_hdr = p->ule_skb->data;
do {
l = handle_one_ule_extension( p );
- if (l == -1) return -1; /* Stop extension header processing and discard SNDU. */
+ if (l < 0)
+ return l; /* Stop extension header processing and discard SNDU. */
total_ext_len += l;
+#ifdef ULE_DEBUG
+ dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+ "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+ (int) p->ule_sndu_type, l, total_ext_len);
+#endif
} while (p->ule_sndu_type < 1536);
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
priv->need_pusi = 1;
}
}
- /* Check continuity counter. */
if (new_ts) {
+ /* Check continuity counter. */
if ((ts[3] & 0x0F) == priv->tscc)
priv->tscc = (priv->tscc + 1) & 0x0F;
else {
/* TS discontinuity handling: */
printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
- "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+ "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
dev_kfree_skb( priv->ule_skb );
/* Prepare for next SNDU. */
// reset_ule(priv); moved to below.
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_frame_errors++;
}
reset_ule(priv);
/* skip to next PUSI. */
priv->need_pusi = 1;
- ts += TS_SZ;
- priv->ts_count++;
continue;
}
/* If we still have an incomplete payload, but PUSI is
* cells (continuity counter wrap). */
if (ts[1] & TS_PUSI) {
if (! priv->need_pusi) {
- if (*from_where > 181) {
+ if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
/* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */
printk(KERN_WARNING "%lu: Invalid pointer "
"field: %u.\n", priv->ts_count, *from_where);
}
reset_ule(priv);
priv->need_pusi = 1;
- ts += TS_SZ;
- priv->ts_count++;
continue;
}
/* Skip pointer field (we're processing a
if (priv->ule_sndu_remain > 183) {
/* Current SNDU lacks more data than there could be available in the
* current TS cell. */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
"got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n",
priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
} else
priv->ule_dbit = 0;
- if (priv->ule_sndu_len > 32763) {
+ if (priv->ule_sndu_len < 5) {
printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
"Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+ priv->stats.rx_errors++;
+ priv->stats.rx_length_errors++;
priv->ule_sndu_len = 0;
priv->need_pusi = 1;
new_ts = 1;
ule_dump = 1;
#endif
- ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++;
+ priv->stats.rx_errors++;
+ priv->stats.rx_crc_errors++;
dev_kfree_skb(priv->ule_skb);
} else {
/* CRC32 verified OK. */
+ u8 dest_addr[ETH_ALEN];
+ static const u8 bc_addr[ETH_ALEN] =
+ { [ 0 ... ETH_ALEN-1] = 0xff };
+
+ /* CRC32 was OK. Remove it from skb. */
+ priv->ule_skb->tail -= 4;
+ priv->ule_skb->len -= 4;
+
+ if (!priv->ule_dbit) {
+ /*
+ * The destination MAC address is the
+ * next data in the skb. It comes
+ * before any extension headers.
+ *
+ * Check if the payload of this SNDU
+ * should be passed up the stack.
+ */
+ register int drop = 0;
+ if (priv->rx_mode != RX_MODE_PROMISC) {
+ if (priv->ule_skb->data[0] & 0x01) {
+ /* multicast or broadcast */
+ if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+ /* multicast */
+ if (priv->rx_mode == RX_MODE_MULTI) {
+ int i;
+ for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+ ;
+ if (i == priv->multi_num)
+ drop = 1;
+ } else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+ drop = 1; /* no broadcast; */
+ /* else: all multicast mode: accept all multicast packets */
+ }
+ /* else: broadcast */
+ }
+ else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+ drop = 1;
+ /* else: destination address matches the MAC address of our receiver device */
+ }
+ /* else: promiscious mode; pass everything up the stack */
+
+ if (drop) {
+#ifdef ULE_DEBUG
+ dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+ MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+ dev_kfree_skb(priv->ule_skb);
+ goto sndu_done;
+ }
+ else
+ {
+ memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN);
+ skb_pull(priv->ule_skb, ETH_ALEN);
+ }
+ }
+
/* Handle ULE Extension Headers. */
if (priv->ule_sndu_type < 1536) {
/* There is an extension header. Handle it accordingly. */
- int l = handle_ule_extensions( priv );
+ int l = handle_ule_extensions(priv);
if (l < 0) {
/* Mandatory extension header unknown or TEST SNDU. Drop it. */
// printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
- dev_kfree_skb( priv->ule_skb );
+ dev_kfree_skb(priv->ule_skb);
goto sndu_done;
}
- skb_pull( priv->ule_skb, l );
+ skb_pull(priv->ule_skb, l);
}
- /* CRC32 was OK. Remove it from skb. */
- priv->ule_skb->tail -= 4;
- priv->ule_skb->len -= 4;
-
- /* Filter on receiver's destination MAC address, if present. */
- if (!priv->ule_dbit) {
- /* The destination MAC address is the next data in the skb. */
- if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) {
- /* MAC addresses don't match. Drop SNDU. */
- // printk( KERN_WARNING "Dropping SNDU, MAC address.\n" );
- dev_kfree_skb( priv->ule_skb );
- goto sndu_done;
- }
- if (! priv->ule_bridged) {
- skb_push( priv->ule_skb, ETH_ALEN + 2 );
- ethh = (struct ethhdr *)priv->ule_skb->data;
- memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN );
- memset( ethh->h_source, 0, ETH_ALEN );
- ethh->h_proto = htons( priv->ule_sndu_type );
- } else {
- /* Skip the Receiver destination MAC address. */
- skb_pull( priv->ule_skb, ETH_ALEN );
- }
- } else {
- if (! priv->ule_bridged) {
- skb_push( priv->ule_skb, ETH_HLEN );
- ethh = (struct ethhdr *)priv->ule_skb->data;
- memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN );
- memset( ethh->h_source, 0, ETH_ALEN );
- ethh->h_proto = htons( priv->ule_sndu_type );
- } else {
- /* skb is in correct state; nothing to do. */
+ /*
+ * Construct/assure correct ethernet header.
+ * Note: in bridged mode (priv->ule_bridged !=
+ * 0) we already have the (original) ethernet
+ * header at the start of the payload (after
+ * optional dest. address and any extension
+ * headers).
+ */
+
+ if (!priv->ule_bridged) {
+ skb_push(priv->ule_skb, ETH_HLEN);
+ ethh = (struct ethhdr *)priv->ule_skb->data;
+ if (!priv->ule_dbit) {
+ /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+ memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+ memset(ethh->h_source, 0, ETH_ALEN);
}
+ else /* zeroize source and dest */
+ memset( ethh, 0, ETH_ALEN*2 );
+
+ ethh->h_proto = htons(priv->ule_sndu_type);
}
+ /* else: skb is in correct state; nothing to do. */
priv->ule_bridged = 0;
/* Stuff into kernel's protocol stack. */
* receive the packet anyhow. */
/* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
priv->ule_skb->pkt_type = PACKET_HOST; */
- ((struct dvb_net_priv *) dev->priv)->stats.rx_packets++;
- ((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len;
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += priv->ule_skb->len;
netif_rx(priv->ule_skb);
}
sndu_done:
dprintk("%s: start filtering\n", __FUNCTION__);
priv->secfeed->start_filtering(priv->secfeed);
} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
- struct timespec timeout = { 0, 30000000 }; // 30 msec
+ struct timespec timeout = { 0, 10000000 }; // 10 msec
/* we have payloads encapsulated in TS */
dprintk("%s: alloc tsfeed\n", __FUNCTION__);
/* Set netdevice pointer for ts decaps callback. */
priv->tsfeed->priv = (void *)dev;
- ret = priv->tsfeed->set(priv->tsfeed, priv->pid,
- TS_PACKET, DMX_TS_PES_OTHER,
+ ret = priv->tsfeed->set(priv->tsfeed,
+ priv->pid, /* pid */
+ TS_PACKET, /* type */
+ DMX_TS_PES_OTHER, /* pes type */
32768, /* circular buffer size */
- timeout);
+ timeout /* timeout */
+ );
if (ret < 0) {
printk("%s: could not set ts feed\n", dev->name);
"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
- NULL, "dvb%d.%s%d", adap->num, dnames[type], id);
+ adap->device, "dvb%d.%s%d", adap->num, dnames[type], id);
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
adap->num, dnames[type], id, nums2minor(adap->num, type, id),
}
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module)
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device)
{
int num;
adap->num = num;
adap->name = name;
adap->module = module;
+ adap->device = device;
list_add_tail (&adap->list_head, &dvb_adapter_list);
u8 proposed_mac [6];
void* priv;
+ struct device *device;
+
struct module *module;
};
};
-extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module);
+extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device);
extern int dvb_unregister_adapter (struct dvb_adapter *adap);
extern int dvb_register_device (struct dvb_adapter *adap,
select DVB_CX22702
select DVB_LGDT330X
select DVB_MT352
+ select DVB_ZL10353
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
DVB-S USB2.0 receivers.
+config DVB_USB_GP8PSK
+ tristate "GENPIX 8PSK->USB module support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+ GENPIX 8psk module
+
+ DVB-S USB2.0 receivers.
+
config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o
obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o
+dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o
+obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o
+
dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
#include "cx22702.h"
#include "lgdt330x.h"
+#include "lg_h06xf.h"
#include "mt352.h"
#include "mt352_priv.h"
+#include "zl10353.h"
/* debug */
int dvb_usb_cxusb_debug;
return 0;
}
+static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+ return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+}
+
static struct cx22702_config cxusb_cx22702_config = {
.demod_address = 0x63,
.output_mode = CX22702_PARALLEL_OUTPUT,
-
- .pll_init = dvb_usb_pll_init_i2c,
- .pll_set = dvb_usb_pll_set_i2c,
};
static struct lgdt330x_config cxusb_lgdt3303_config = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
- .pll_set = dvb_usb_pll_set_i2c,
};
static struct mt352_config cxusb_dee1601_config = {
.demod_address = 0x0f,
.demod_init = cxusb_dee1601_demod_init,
- .pll_set = dvb_usb_pll_set,
};
-struct mt352_config cxusb_mt352_config = {
+static struct zl10353_config cxusb_zl10353_dee1601_config = {
+ .demod_address = 0x0f,
+};
+
+static struct mt352_config cxusb_mt352_config = {
/* used in both lgz201 and th7579 */
.demod_address = 0x0f,
.demod_init = cxusb_mt352_demod_init,
- .pll_set = dvb_usb_pll_set,
};
/* Callbacks for DVB USB */
d->pll_addr = 0x61;
memcpy(d->pll_init, bpll, 4);
d->pll_desc = &dvb_pll_fmd1216me;
- return 0;
-}
-static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d)
-{
- u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 };
- /* bpll[2] : unset bit 3, set bits 4&5
- bpll[3] : 0x50 - digital, 0x20 - analog */
- d->pll_addr = 0x61;
- memcpy(d->pll_init, bpll, 4);
- d->pll_desc = &dvb_pll_tdvs_tua6034;
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
return 0;
}
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_thomson_dtt7579;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_lg_z201;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_thomson_dtt7579;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ return 0;
+}
+
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+{
+ d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
return 0;
}
cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL)
+ if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
+ ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
return 0;
return -EIO;
.streaming_ctrl = cxusb_streaming_ctrl,
.power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_lgdt3303_frontend_attach,
- .tuner_attach = cxusb_lgh064f_tuner_attach,
+ .tuner_attach = cxusb_lgdt3303_tuner_attach,
.i2c_algo = &cxusb_i2c_algo,
struct dib3000_config demod_cfg;
struct dibusb_state *st = d->priv;
- demod_cfg.pll_set = dvb_usb_pll_set_i2c;
- demod_cfg.pll_init = dvb_usb_pll_init_i2c;
-
for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
return 0;
}
{
d->pll_addr = 0x60;
d->pll_desc = &dvb_pll_env57h1xd5;
+
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
return 0;
}
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
struct dibusb_state *st = d->priv;
demod_cfg.demod_address = 0x8;
- demod_cfg.pll_set = dvb_usb_pll_set_i2c;
- demod_cfg.pll_init = dvb_usb_pll_init_i2c;
- if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+ if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
+ d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
return -ENODEV;
+ }
d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
static struct mt352_config digitv_mt352_config = {
.demod_init = digitv_mt352_demod_init,
- .pll_set = dvb_usb_pll_set,
};
-static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
u8 b[5];
- dvb_usb_pll_set(fe,fep,b);
+ dvb_usb_tuner_calc_regs(fe,fep,b, 5);
return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
}
static struct nxt6000_config digitv_nxt6000_config = {
.clock_inversion = 1,
- .pll_set = digitv_nxt6000_pll_set,
};
static int digitv_frontend_attach(struct dvb_usb_device *d)
{
- if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL ||
- (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL)
+ if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
+ }
+ if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+ d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ return 0;
+ }
return -EIO;
}
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
};
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
deb_info("attaching frontend dtt200u\n");
state->d = d;
- memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
- goto success;
+ return &state->frontend;
error:
return NULL;
-success:
- return &state->frontend;
}
static struct dvb_frontend_ops dtt200u_fe_ops = {
int ret;
if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
- d->owner)) < 0) {
+ d->owner, &d->udev->dev)) < 0) {
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
- goto success;
+ d->state |= DVB_USB_STATE_DVB;
+ return 0;
+
err_dmx_dev:
dvb_dmx_release(&d->demux);
err_dmx:
dvb_unregister_adapter(&d->dvb_adap);
err:
return ret;
-success:
- d->state |= DVB_USB_STATE_DVB;
- return 0;
}
int dvb_usb_dvb_exit(struct dvb_usb_device *d)
/* re-assign sleep and wakeup functions */
if (d->fe != NULL) {
- d->fe_init = d->fe->ops->init; d->fe->ops->init = dvb_usb_fe_wakeup;
- d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+ d->fe_init = d->fe->ops.init; d->fe->ops.init = dvb_usb_fe_wakeup;
+ d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
err("Frontend registration failed.");
- if (d->fe->ops->release)
- d->fe->ops->release(d->fe);
+ if (d->fe->ops.release)
+ d->fe->ops.release(d->fe);
d->fe = NULL;
return -ENODEV;
}
return 0;
}
-int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
{
struct dvb_usb_device *d = fe->dvb->priv;
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
d->pll_init[2],d->pll_init[3]);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_init.");
ret = -EREMOTEIO;
d->tuner_pass_ctrl(fe,0,d->pll_addr);
return ret;
}
-EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
-int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
{
struct dvb_usb_device *d = fe->dvb->priv;
+ if (buf_len != 5)
+ return -EINVAL;
if (d->pll_desc == NULL)
return 0;
deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
- b[0] = d->pll_addr << 1;
+ b[0] = d->pll_addr;
dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
- return 0;
+ return 5;
}
-EXPORT_SYMBOL(dvb_usb_pll_set);
+EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
-int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
struct dvb_usb_device *d = fe->dvb->priv;
int ret = 0;
u8 b[5];
struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
- dvb_usb_pll_set(fe,fep,b);
+ dvb_usb_tuner_calc_regs(fe,fep,b,5);
if (d->tuner_pass_ctrl)
d->tuner_pass_ctrl(fe,1,d->pll_addr);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_set.");
ret = -EREMOTEIO;
return ret;
}
-EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
+EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c);
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+#define USB_VID_GENPIX 0x09c0
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
#define USB_PID_KYE_DVB_T_WARM 0x701f
#define USB_PID_PCTV_200E 0x020e
#define USB_PID_PCTV_400E 0x020f
-
+#define USB_PID_GENPIX_8PSK_COLD 0x0200
+#define USB_PID_GENPIX_8PSK_WARM 0x0201
#endif
extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
/* commonly used pll init and set functions */
-extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
-extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
-extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len);
+extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
/* commonly used firmware download types and function */
struct hexline {
--- /dev/null
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * 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 "gp8psk.h"
+
+struct gp8psk_fe_state {
+ struct dvb_frontend fe;
+
+ struct dvb_usb_device *d;
+
+ u16 snr;
+
+ unsigned long next_snr_check;
+};
+
+static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 lock;
+
+ if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1))
+ return -EINVAL;
+
+ if (lock)
+ *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ else
+ *status = 0;
+
+ return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+ (void) fe;
+ *ber = 0;
+ return 0;
+}
+
+/* not supported by this Frontend */
+static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+ (void) fe;
+ *unc = 0;
+ return 0;
+}
+
+static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 buf[2];
+
+ if (time_after(jiffies,st->next_snr_check)) {
+ gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2);
+ *snr = (int)(buf[1]) << 8 | buf[0];
+ /* snr is reported in dBu*256 */
+ /* snr / 38.4 ~= 100% strength */
+ /* snr * 17 returns 100% strength as 65535 */
+ if (*snr <= 3855)
+ *snr = (*snr<<4) + *snr; // snr * 17
+ else
+ *snr = 65535;
+ st->next_snr_check = jiffies + (10*HZ)/1000;
+ } else {
+ *snr = st->snr;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+ return gp8psk_fe_read_snr(fe, strength);
+}
+
+static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 800;
+ return 0;
+}
+
+static int gp8psk_fe_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ u8 cmd[10];
+ u32 freq = fep->frequency * 1000;
+
+ cmd[4] = freq & 0xff;
+ cmd[5] = (freq >> 8) & 0xff;
+ cmd[6] = (freq >> 16) & 0xff;
+ cmd[7] = (freq >> 24) & 0xff;
+
+ switch(fe->ops.info.type) {
+ case FE_QPSK:
+ cmd[0] = fep->u.qpsk.symbol_rate & 0xff;
+ cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff;
+ cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff;
+ cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff;
+ cmd[8] = ADV_MOD_DVB_QPSK;
+ cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/
+ break;
+ default:
+ // other modes are unsuported right now
+ cmd[0] = 0;
+ cmd[1] = 0;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ cmd[8] = 0;
+ cmd[9] = 0;
+ break;
+ }
+
+ gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10);
+
+ state->next_snr_check = jiffies;
+
+ return 0;
+}
+
+static int gp8psk_fe_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ return 0;
+}
+
+
+static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd *m)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+
+ deb_fe("%s\n",__FUNCTION__);
+
+ if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0,
+ m->msg, m->msg_len)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe,
+ fe_sec_mini_cmd_t burst)
+{
+ struct gp8psk_fe_state *st = fe->demodulator_priv;
+ u8 cmd;
+
+ deb_fe("%s\n",__FUNCTION__);
+
+ /* These commands are certainly wrong */
+ cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01;
+
+ if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0,
+ &cmd, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+ if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE,
+ (tone == SEC_TONE_ON), 0, NULL, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+
+ if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE,
+ voltage == SEC_VOLTAGE_18, 0, NULL, 0)) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd)
+{
+ struct gp8psk_fe_state* state = fe->demodulator_priv;
+ u8 cmd = sw_cmd & 0x7f;
+
+ if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0,
+ NULL, 0)) {
+ return -EINVAL;
+ }
+ if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80),
+ 0, NULL, 0)) {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void gp8psk_fe_release(struct dvb_frontend* fe)
+{
+ struct gp8psk_fe_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops gp8psk_fe_ops;
+
+struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d)
+{
+ struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL);
+ if (s == NULL)
+ goto error;
+
+ s->d = d;
+ memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops));
+ s->fe.demodulator_priv = s;
+
+ goto success;
+error:
+ return NULL;
+success:
+ return &s->fe;
+}
+
+
+static struct dvb_frontend_ops gp8psk_fe_ops = {
+ .info = {
+ .name = "Genpix 8psk-USB DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 100,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .symbol_rate_tolerance = 500, /* ppm */
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = gp8psk_fe_release,
+
+ .init = NULL,
+ .sleep = NULL,
+
+ .set_frontend = gp8psk_fe_set_frontend,
+ .get_frontend = gp8psk_fe_get_frontend,
+ .get_tune_settings = gp8psk_fe_get_tune_settings,
+
+ .read_status = gp8psk_fe_read_status,
+ .read_ber = gp8psk_fe_read_ber,
+ .read_signal_strength = gp8psk_fe_read_signal_strength,
+ .read_snr = gp8psk_fe_read_snr,
+ .read_ucblocks = gp8psk_fe_read_unc_blocks,
+
+ .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg,
+ .diseqc_send_burst = gp8psk_fe_send_diseqc_burst,
+ .set_tone = gp8psk_fe_set_tone,
+ .set_voltage = gp8psk_fe_set_voltage,
+ .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd,
+};
--- /dev/null
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * 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 "gp8psk.h"
+
+/* debug */
+static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw";
+int dvb_usb_gp8psk_debug;
+module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
+{
+ int ret = 0,try = 0;
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ while (ret >= 0 && ret != blen && try < 3) {
+ ret = usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_IN,
+ value,index,b,blen,
+ 2000);
+ deb_info("reading number %d (ret: %d)\n",try,ret);
+ try++;
+ }
+
+ if (ret < 0 || ret != blen) {
+ warn("usb in operation failed.");
+ ret = -EIO;
+ } else
+ ret = 0;
+
+ deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen)
+{
+ int ret;
+
+ deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ debug_dump(b,blen,deb_xfer);
+
+ if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
+ return ret;
+
+ if (usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev,0),
+ req,
+ USB_TYPE_VENDOR | USB_DIR_OUT,
+ value,index,b,blen,
+ 2000) != blen) {
+ warn("usb out operation failed.");
+ ret = -EIO;
+ } else
+ ret = 0;
+ mutex_unlock(&d->usb_mutex);
+
+ return ret;
+}
+
+static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d)
+{
+ int ret;
+ const struct firmware *fw = NULL;
+ u8 *ptr, *buf;
+ if ((ret = request_firmware(&fw, bcm4500_firmware,
+ &d->udev->dev)) != 0) {
+ err("did not find the bcm4500 firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)",
+ bcm4500_firmware,ret);
+ return ret;
+ }
+
+ ret = -EINVAL;
+
+ if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0))
+ goto out_rel_fw;
+
+ info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware);
+
+ ptr = fw->data;
+ buf = kmalloc(512, GFP_KERNEL | GFP_DMA);
+
+ while (ptr[0] != 0xff) {
+ u16 buflen = ptr[0] + 4;
+ if (ptr + buflen >= fw->data + fw->size) {
+ err("failed to load bcm4500 firmware.");
+ goto out_free;
+ }
+ memcpy(buf, ptr, buflen);
+ if (dvb_usb_generic_write(d, buf, buflen)) {
+ err("failed to load bcm4500 firmware.");
+ goto out_free;
+ }
+ ptr += buflen;
+ }
+
+ ret = 0;
+
+out_free:
+ kfree(buf);
+out_rel_fw:
+ release_firmware(fw);
+
+ return ret;
+}
+
+static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 status, buf;
+ if (onoff) {
+ gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ if (! (status & 0x01)) /* started */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
+ return -EINVAL;
+
+ if (! (status & 0x02)) /* BCM4500 firmware loaded */
+ if(gp8psk_load_bcm4500fw(d))
+ return EINVAL;
+
+ if (! (status & 0x04)) /* LNB Power */
+ if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0,
+ &buf, 1))
+ return EINVAL;
+
+ /* Set DVB mode */
+ if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0))
+ return -EINVAL;
+ gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1);
+ } else {
+ /* Turn off LNB power */
+ if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1))
+ return EINVAL;
+ /* Turn off 8psk power */
+ if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1))
+ return -EINVAL;
+
+ }
+ return 0;
+}
+
+
+static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+}
+
+static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+{
+ d->fe = gp8psk_fe_attach(d);
+
+ return 0;
+}
+
+static struct dvb_usb_properties gp8psk_properties;
+
+static int gp8psk_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL);
+}
+
+static struct usb_device_id gp8psk_usb_table [] = {
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
+
+static struct dvb_usb_properties gp8psk_properties = {
+ .caps = 0,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-gp8psk-01.fw",
+
+ .streaming_ctrl = gp8psk_streaming_ctrl,
+ .power_ctrl = gp8psk_power_ctrl,
+ .frontend_attach = gp8psk_frontend_attach,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x82,
+ .u = {
+ .bulk = {
+ .buffersize = 8192,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver",
+ .cold_ids = { &gp8psk_usb_table[0], NULL },
+ .warm_ids = { &gp8psk_usb_table[1], NULL },
+ },
+ { 0 },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver gp8psk_usb_driver = {
+ .name = "dvb_usb_gp8psk",
+ .probe = gp8psk_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = gp8psk_usb_table,
+};
+
+/* module stuff */
+static int __init gp8psk_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&gp8psk_usb_driver))) {
+ err("usb_register failed. (%d)",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit gp8psk_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&gp8psk_usb_driver);
+}
+
+module_init(gp8psk_usb_module_init);
+module_exit(gp8psk_usb_module_exit);
+
+MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
+MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
--- /dev/null
+/* DVB USB compliant Linux driver for the
+ * - GENPIX 8pks/qpsk USB2.0 DVB-S module
+ *
+ * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com)
+ *
+ * Thanks to GENPIX for the sample code used to implement this module.
+ *
+ * This module is based off the vp7045 and vp702x modules
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_GP8PSK_H_
+#define _DVB_USB_GP8PSK_H_
+
+#define DVB_USB_LOG_PREFIX "gp8psk"
+#include "dvb-usb.h"
+
+extern int dvb_usb_gp8psk_debug;
+#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
+#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
+/* gp8psk commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN 0xC0
+#define TH_COMMAND_OUT 0xC1
+
+/* command bytes */
+#define GET_8PSK_CONFIG 0x80
+#define SET_8PSK_CONFIG 0x81
+#define ARM_TRANSFER 0x85
+#define TUNE_8PSK 0x86
+#define GET_SIGNAL_STRENGTH 0x87
+#define LOAD_BCM4500 0x88
+#define BOOT_8PSK 0x89
+#define START_INTERSIL 0x8A
+#define SET_LNB_VOLTAGE 0x8B
+#define SET_22KHZ_TONE 0x8C
+#define SEND_DISEQC_COMMAND 0x8D
+#define SET_DVB_MODE 0x8E
+#define SET_DN_SWITCH 0x8F
+#define GET_SIGNAL_LOCK 0x90
+
+/* Satellite modulation modes */
+#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */
+#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */
+#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */
+#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */
+
+#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */
+#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */
+#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */
+#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */
+#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */
+#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */
+
+#define GET_USB_SPEED 0x07
+ #define USB_SPEED_LOW 0
+ #define USB_SPEED_FULL 1
+ #define USB_SPEED_HIGH 2
+
+#define RESET_FX2 0x13
+
+#define FW_VERSION_READ 0x0B
+#define VENDOR_STRING_READ 0x0C
+#define PRODUCT_STRING_READ 0x0D
+#define FW_BCD_VERSION_READ 0x14
+
+extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d);
+extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+ u16 index, u8 *b, int blen);
+
+#endif
memset(&umt_config,0,sizeof(struct mt352_config));
umt_config.demod_init = umt_mt352_demod_init;
umt_config.demod_address = 0xf;
- umt_config.pll_set = dvb_usb_pll_set;
d->fe = mt352_attach(&umt_config, &d->i2c_adap);
{
d->pll_addr = 0x61;
d->pll_desc = &dvb_pll_tua6034;
+ d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
goto error;
s->d = d;
- s->fe.ops = &vp702x_fe_ops;
+
+ memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops));
s->fe.demodulator_priv = s;
s->lnb_buf[1] = SET_LNB_POWER;
s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */
- goto success;
+ return &s->fe;
error:
return NULL;
-success:
- return &s->fe;
}
struct vp7045_fe_state {
struct dvb_frontend fe;
- struct dvb_frontend_ops ops;
-
struct dvb_usb_device *d;
};
goto error;
s->d = d;
- memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
- s->fe.ops = &s->ops;
+ memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops));
s->fe.demodulator_priv = s;
- goto success;
+ return &s->fe;
error:
return NULL;
-success:
- return &s->fe;
}
help
A DVB-C tuner module. Say Y when you want to support this frontend.
-comment "ATSC (North American/Korean Terresterial DTV) frontends"
+comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
depends on DVB_CORE
config DVB_NXT200X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+
+comment "Miscellaneous devices"
+ depends on DVB_CORE
+
+config DVB_LNBP21
+ tristate "LNBP21 SEC controller"
+ depends on DVB_CORE
+ help
+ An SEC control chip.
+
+config DVB_ISL6421
+ tristate "ISL6421 SEC controller"
+ depends on DVB_CORE
+ help
+ An SEC control chip.
+
endmenu
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
+obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6421) += isl6421.o
struct bcm3510_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct bcm3510_config* config;
struct dvb_frontend frontend;
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
mutex_init(&state->hab_mutex);
return 0;
}
-static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
+static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
int ret;
u8 data[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
data[2] = 0x80 | ((div & 0x18000) >> 10) | 4;
data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(i2c, &msg, 1);
return (ret != 1) ? -EIO : 0;
}
.skip_reinit = 0,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsbe1_set_symbol_rate,
- .pll_set = alps_bsbe1_pll_set,
};
#endif
return 0;
}
-static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int alps_bsru6_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
u8 buf[4];
u32 div;
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ struct i2c_adapter *i2c = fe->tuner_priv;
if ((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
if (params->frequency > 1530000)
buf[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(i2c, &msg, 1) != 1)
return -EIO;
return 0;
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_bsru6_set_symbol_rate,
- .pll_set = alps_bsru6_pll_set,
};
#endif
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx22700_config* config;
struct dvb_frontend frontend;
cx22700_writereg (state, 0x00, 0x01);
- if (state->config->pll_init) {
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_init(fe);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
- }
-
return 0;
}
cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/
cx22700_writereg (state, 0x00, 0x00);
- cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */
- state->config->pll_set(fe, p);
- cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx22700_set_inversion (state, p->inversion);
cx22700_set_tps (state, &p->u.ofdm);
cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */
return cx22700_get_tps (state, &p->u.ofdm);
}
+static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct cx22700_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return cx22700_writereg(state, 0x0a, 0x00);
+ } else {
+ return cx22700_writereg(state, 0x0a, 0x01);
+ }
+}
+
static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 150;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (cx22700_readreg(state, 0x07) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.release = cx22700_release,
.init = cx22700_init,
+ .i2c_gate_ctrl = cx22700_i2c_gate_ctrl,
.set_frontend = cx22700_set_frontend,
.get_frontend = cx22700_get_frontend,
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct cx22702_config* config;
u8 val;
struct cx22702_state* state = fe->demodulator_priv;
- /* set PLL */
- cx22702_i2c_gate_ctrl(fe, 1);
- if (state->config->pll_set) {
- state->config->pll_set(fe, p);
- } else if (state->config->pll_desc) {
- u8 pllbuf[4];
- struct i2c_msg msg = { .addr = state->config->pll_address,
- .buf = pllbuf, .len = 4 };
- dvb_pll_configure(state->config->pll_desc, pllbuf,
- p->frequency,
- p->u.ofdm.bandwidth);
- i2c_transfer(state->i2c, &msg, 1);
- } else {
- BUG();
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- cx22702_i2c_gate_ctrl(fe, 0);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
- /* init PLL */
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
cx22702_i2c_gate_ctrl(fe, 0);
return 0;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->prevUCBlocks = 0;
/* check if the demod is there */
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.release = cx22702_release,
.init = cx22702_init,
+ .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
.set_frontend = cx22702_set_tps,
.get_frontend = cx22702_get_frontend,
.read_signal_strength = cx22702_read_signal_strength,
.read_snr = cx22702_read_snr,
.read_ucblocks = cx22702_read_ucblocks,
- .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
};
module_param(debug, int, 0644);
#define CX22702_PARALLEL_OUTPUT 0
#define CX22702_SERIAL_OUTPUT 1
u8 output_mode;
-
- /* PLL maintenance */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct cx24110_config* config;
struct dvb_frontend frontend;
static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
int i;
-dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
+ dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
if (srate>90999000UL/2)
srate=90999000UL/2;
if (srate<500000)
cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data);
};
- if (state->config->pll_init) state->config->pll_init(fe);
-
- return 0;
-}
-
-static int cx24110_sleep(struct dvb_frontend *fe)
-{
- struct cx24110_state *state = fe->demodulator_priv;
-
- if (state->config->pll_sleep)
- return state->config->pll_sleep(fe);
return 0;
}
{
struct cx24110_state *state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
cx24110_set_inversion (state, p->inversion);
cx24110_set_fec (state, p->u.qpsk.fec_inner);
cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate);
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->lastbler = 0;
state->lastesn0 = 0;
if ((ret != 0x5a) && (ret != 0x69)) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.release = cx24110_release,
.init = cx24110_initfe,
- .sleep = cx24110_sleep,
.set_frontend = cx24110_set_frontend,
.get_frontend = cx24110_get_frontend,
.read_status = cx24110_read_status,
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
- int (*pll_sleep)(struct dvb_frontend* fe);
};
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
struct cx24123_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct cx24123_config* config;
struct dvb_frontend frontend;
u32 lastber;
u16 snr;
- u8 lnbreg;
/* Some PLL specifics for tuning */
u32 VCAarg;
return 0;
}
-static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data)
-{
- u8 buf[] = { reg, data };
- /* fixme: put the intersil addr int the config */
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 };
- int err;
-
- if (debug>1)
- printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n",
- __FUNCTION__,reg, data);
-
- if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
- printk("%s: writelnbreg error (err == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
- return -EREMOTEIO;
- }
-
- /* cache the write, no way to read back */
- state->lnbreg = data;
-
- return 0;
-}
-
static int cx24123_readreg(struct cx24123_state* state, u8 reg)
{
int ret;
return b1[0];
}
-static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg)
-{
- return state->lnbreg;
-}
-
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
u8 nom_reg = cx24123_readreg(state, 0x0e);
u8 pll_mult;
/* check if symbol rate is within limits */
- if ((srate > state->ops.info.symbol_rate_max) ||
- (srate < state->ops.info.symbol_rate_min))
+ if ((srate > state->frontend.ops.info.symbol_rate_max) ||
+ (srate < state->frontend.ops.info.symbol_rate_min))
return -EOPNOTSUPP;;
/* choose the sampling rate high enough for the required operation,
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
- /* Configure the LNB for 14V */
- if (state->config->use_isl6421)
- cx24123_writelnbreg(state, 0x0, 0x2a);
-
return 0;
}
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
-
- case 1:
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */
- case SEC_VOLTAGE_18:
- dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */
- case SEC_VOLTAGE_OFF:
- dprintk("%s: isl5421 voltage off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x30);
- default:
- return -EINVAL;
- };
-
- case 0:
-
- val = cx24123_readreg(state, 0x29);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: setting voltage 13V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val | 0x80);
- case SEC_VOLTAGE_18:
- dprintk("%s: setting voltage 18V\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 1);
- return cx24123_writereg(state, 0x29, val & 0x7f);
- case SEC_VOLTAGE_OFF:
- dprintk("%s: setting voltage off\n", __FUNCTION__);
- if (state->config->enable_lnb_voltage)
- state->config->enable_lnb_voltage(fe, 0);
- return 0;
- default:
- return -EINVAL;
- };
- }
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x80);
+ case SEC_VOLTAGE_18:
+ dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0x7f);
+ default:
+ return -EINVAL;
+ };
return 0;
}
static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd)
{
struct cx24123_state *state = fe->demodulator_priv;
- int i, val;
+ int i, val, tone;
dprintk("%s:\n",__FUNCTION__);
- /* check if continuous tone has been stopped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
/* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
for (i = 0; i < cmd->msg_len; i++)
cx24123_writereg(state, 0x2C + i, cmd->msg[i]);
/* wait for diseqc message to finish sending */
cx24123_wait_for_diseqc(state);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
+
return 0;
}
static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst)
{
struct cx24123_state *state = fe->demodulator_priv;
- int val;
+ int val, tone;
dprintk("%s:\n", __FUNCTION__);
- /* check if continuous tone has been stoped */
- if (state->config->use_isl6421)
- val = cx24123_readlnbreg(state, 0x00) & 0x10;
- else
- val = cx24123_readreg(state, 0x29) & 0x10;
-
-
- if (val) {
- printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__);
- return -ENOTSUPP;
- }
+ /* stop continuous tone if enabled */
+ tone = cx24123_readreg(state, 0x29);
+ if (tone & 0x10)
+ cx24123_writereg(state, 0x29, tone & ~0x50);
+ /* wait for diseqc queue ready */
cx24123_wait_for_diseqc(state);
/* select tone mode */
- val = cx24123_readreg(state, 0x2a) & 0xf8;
- cx24123_writereg(state, 0x2a, val | 0x04);
-
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4);
+ msleep(30);
val = cx24123_readreg(state, 0x29);
-
if (burst == SEC_MINI_A)
cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00));
else if (burst == SEC_MINI_B)
return -EINVAL;
cx24123_wait_for_diseqc(state);
+ cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb);
+ /* restart continuous tone if enabled */
+ if (tone & 0x10) {
+ cx24123_writereg(state, 0x29, tone & ~0x40);
+ }
return 0;
}
struct cx24123_state *state = fe->demodulator_priv;
u8 val;
- switch (state->config->use_isl6421) {
- case 1:
-
- val = cx24123_readlnbreg(state, 0x0);
-
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: isl6421 sec tone on\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: isl6421 sec tone off\n",__FUNCTION__);
- return cx24123_writelnbreg(state, 0x0, val & 0x2f);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
-
- case 0:
+ /* wait for diseqc queue ready */
+ cx24123_wait_for_diseqc(state);
- val = cx24123_readreg(state, 0x29);
+ val = cx24123_readreg(state, 0x29) & ~0x40;
- switch (tone) {
- case SEC_TONE_ON:
- dprintk("%s: setting tone on\n", __FUNCTION__);
- return cx24123_writereg(state, 0x29, val | 0x10);
- case SEC_TONE_OFF:
- dprintk("%s: setting tone off\n",__FUNCTION__);
- return cx24123_writereg(state, 0x29, val & 0xef);
- default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
- return -EINVAL;
- }
+ switch (tone) {
+ case SEC_TONE_ON:
+ dprintk("%s: setting tone on\n", __FUNCTION__);
+ return cx24123_writereg(state, 0x29, val | 0x10);
+ case SEC_TONE_OFF:
+ dprintk("%s: setting tone off\n",__FUNCTION__);
+ return cx24123_writereg(state, 0x29, val & 0xef);
+ default:
+ printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ return -EINVAL;
}
return 0;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->lastber = 0;
state->snr = 0;
- state->lnbreg = 0;
state->VCAarg = 0;
state->VGAarg = 0;
state->bandselectarg = 0;
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
/* the demodulator's i2c address */
u8 demod_address;
- /*
- cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip
- for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits
- from register 0x29 of the CX24123 demodulator
- */
- int use_isl6421;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
-
- void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on);
};
extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
struct dib3000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
/* configuration settings */
struct dib3000_config config;
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance and the i2c address of the PLL */
- int (*pll_init)(struct dvb_frontend *fe);
- int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
};
struct dib_fe_xfer_ops
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
- if (tuner && state->config.pll_set) {
- state->config.pll_set(fe, fep);
+ if (tuner && fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
return 0;
}
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
int search_state,auto_val;
u16 val;
- if (tuner && state->config.pll_set) { /* initial call from dvb */
- state->config.pll_set(fe,fep);
+ if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
+ fe->ops.tuner_ops.set_params(fe, fep);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
state->last_tuned_freq = fep->frequency;
// if (!scanboost) {
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
- if (state->config.pll_init)
- state->config.pll_init(fe);
-
deb_info("init end\n");
return 0;
}
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct dib3000_config));
- memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
/* check for the correct demod */
if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
/* set the xfer operations */
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(dib3000mc_attach);
static struct dvb_frontend_ops dib3000mc_ops = {
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000mc_attach);
EXPORT_SYMBOL(dvb_pll_tua6034);
/* Infineon TUA6034
- * used in LG TDVS H061F and LG TDVS H062F
+ * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
*/
-struct dvb_pll_desc dvb_pll_tdvs_tua6034 = {
- .name = "LG/Infineon TUA6034",
+struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
+ .name = "LG TDVS-H06xF",
.min = 54000000,
.max = 863000000,
.count = 3,
{ 999999999, 44000000, 62500, 0xce, 0x04 },
},
};
-EXPORT_SYMBOL(dvb_pll_tdvs_tua6034);
+EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf);
/* Philips FMD1216ME
* used in Medion Hybrid PCMCIA card and USB Box
};
EXPORT_SYMBOL(dvb_pll_thomson_fe6600);
+struct dvb_pll_priv {
+ /* i2c details */
+ int pll_i2c_address;
+ struct i2c_adapter *i2c;
+
+ /* the PLL descriptor */
+ struct dvb_pll_desc *pll_desc;
+
+ /* cached frequency/bandwidth */
+ u32 frequency;
+ u32 bandwidth;
+};
+
/* ----------------------------------------------------------- */
/* code */
if (debug)
printk("pll: %s: freq=%d bw=%d | i=%d/%d\n",
desc->name, freq, bandwidth, i, desc->count);
- BUG_ON(i == desc->count);
+ if (i == desc->count)
+ return -EINVAL;
div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize;
buf[0] = div >> 8;
}
EXPORT_SYMBOL(dvb_pll_configure);
+static int dvb_pll_release(struct dvb_frontend *fe)
+{
+ if (fe->tuner_priv)
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int dvb_pll_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int i;
+ int result;
+
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (priv->pll_desc->entries[i].limit == 0)
+ break;
+ }
+ if (i == priv->pll_desc->count)
+ return 0;
+
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = priv->pll_desc->entries[i].config;
+ buf[3] = priv->pll_desc->entries[i].cb;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ return 0;
+}
+
+static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ u8 buf[4];
+ struct i2c_msg msg =
+ { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) };
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0)
+ return result;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) {
+ return result;
+ }
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 0;
+}
+
+static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ int result;
+ u32 div;
+ int i;
+ u32 bandwidth = 0;
+
+ if (buf_len < 5)
+ return -EINVAL;
+
+ // DVBT bandwidth only just now
+ if (fe->ops.info.type == FE_OFDM) {
+ bandwidth = params->u.ofdm.bandwidth;
+ }
+
+ if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0)
+ return result;
+ buf[0] = priv->pll_i2c_address;
+
+ // calculate the frequency we set it to
+ for (i = 0; i < priv->pll_desc->count; i++) {
+ if (params->frequency > priv->pll_desc->entries[i].limit)
+ continue;
+ break;
+ }
+ div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize;
+ priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset;
+ priv->bandwidth = bandwidth;
+
+ return 5;
+}
+
+static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct dvb_pll_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static struct dvb_tuner_ops dvb_pll_tuner_ops = {
+ .release = dvb_pll_release,
+ .sleep = dvb_pll_sleep,
+ .set_params = dvb_pll_set_params,
+ .calc_regs = dvb_pll_calc_regs,
+ .get_frequency = dvb_pll_get_frequency,
+ .get_bandwidth = dvb_pll_get_bandwidth,
+};
+
+int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+{
+ struct dvb_pll_priv *priv = NULL;
+
+ priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
+
+ priv->pll_i2c_address = pll_addr;
+ priv->i2c = i2c;
+ priv->pll_desc = desc;
+
+ memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops));
+ strncpy(fe->ops.tuner_ops.info.name, desc->name, 128);
+ fe->ops.tuner_ops.info.frequency_min = desc->min;
+ fe->ops.tuner_ops.info.frequency_min = desc->max;
+
+ fe->tuner_priv = priv;
+ return 0;
+}
+EXPORT_SYMBOL(dvb_pll_attach);
+
MODULE_DESCRIPTION("dvb pll library");
MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL");
#ifndef __DVB_PLL_H__
#define __DVB_PLL_H__
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
struct dvb_pll_desc {
char *name;
u32 min;
extern struct dvb_pll_desc dvb_pll_tua6010xs;
extern struct dvb_pll_desc dvb_pll_env57h1xd5;
extern struct dvb_pll_desc dvb_pll_tua6034;
-extern struct dvb_pll_desc dvb_pll_tdvs_tua6034;
+extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf;
extern struct dvb_pll_desc dvb_pll_tda665x;
extern struct dvb_pll_desc dvb_pll_fmd1216me;
extern struct dvb_pll_desc dvb_pll_tded4;
extern struct dvb_pll_desc dvb_pll_thomson_fe6600;
-int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
+extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
+/**
+ * Attach a dvb-pll to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param pll_addr i2c address of the PLL (if used).
+ * @param i2c i2c adapter to use (set to NULL if not used).
+ * @param desc dvb_pll_desc to use.
+ * @return 0 on success, nonzero on failure.
+ */
+extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+
#endif
struct dvb_dummy_fe_state {
- struct dvb_frontend_ops ops;
struct dvb_frontend frontend;
};
static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
+ if (fe->ops->tuner_ops->set_params) {
+ fe->ops->tuner_ops->set_params(fe, p);
+ if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0);
+ }
+
return 0;
}
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL);
if (state == NULL) goto error;
- /* setup the state */
- memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
--- /dev/null
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6421.h"
+
+struct isl6421 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ u8 i2c_addr;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ isl6421->config |= ISL6421_EN1;
+ break;
+ case SEC_VOLTAGE_18:
+ isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
+ .buf = &isl6421->config,
+ .len = sizeof(isl6421->config) };
+
+ if (arg)
+ isl6421->config |= ISL6421_LLC1;
+ else
+ isl6421->config &= ~ISL6421_LLC1;
+
+ isl6421->config |= isl6421->override_or;
+ isl6421->config &= isl6421->override_and;
+
+ return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6421_release(struct dvb_frontend *fe)
+{
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+
+ /* power off */
+ isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = isl6421->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+{
+ struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
+ if (!isl6421)
+ return -ENOMEM;
+
+ /* default configuration */
+ isl6421->config = ISL6421_ISEL1;
+ isl6421->i2c = i2c;
+ isl6421->i2c_addr = i2c_addr;
+ fe->misc_priv = isl6421;
+
+ /* bits which should be forced to '1' */
+ isl6421->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ isl6421->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(isl6421);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ isl6421->release_chain = fe->ops.release;
+ fe->ops.release = isl6421_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = isl6421_set_voltage;
+ fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(isl6421_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421");
+MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss");
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * isl6421.h - driver for lnb supply and control ic ISL6421
+ *
+ * Copyright (C) 2006 Andrew de Quincey
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6421_H
+#define _ISL6421_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+#define ISL6421_OLF1 0x01
+#define ISL6421_EN1 0x02
+#define ISL6421_VSEL1 0x04
+#define ISL6421_LLC1 0x08
+#define ISL6421_ENT1 0x10
+#define ISL6421_ISEL1 0x20
+#define ISL6421_DCL 0x40
+
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear);
+
+#endif
struct l64781_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct l64781_config* config;
struct dvb_frontend frontend;
u8 val0x06;
int bw = p->bandwidth - BANDWIDTH_8_MHZ;
- state->config->pll_set(fe, param);
+ 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 (param->inversion != INVERSION_ON &&
param->inversion != INVERSION_OFF)
/* Everything is two's complement, soft bit and CSI_OUT too */
l64781_writereg (state, 0x1e, 0x09);
- if (state->config->pll_init) state->config->pll_init(fe);
-
/* delay a bit after first init attempt */
if (state->first) {
state->first = 0;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->first = 1;
/**
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
--- /dev/null
+/*
+ * lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF
+ *
+ * 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 _LG_H06XF_H_
+#define _LG_H06XF_H_
+#include "dvb-pll.h"
+
+static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap,
+ struct dvb_frontend_parameters* params)
+{
+ u8 buf[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+ int err;
+
+ dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ /* Set the Auxiliary Byte. */
+ buf[0] = buf[2];
+ buf[0] &= ~0x20;
+ buf[0] |= 0x18;
+ buf[1] = 0x50;
+ msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lg_h06xf: %s error "
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+#endif
* DViCO FusionHDTV 5 Lite
* DViCO FusionHDTV 5 USB Gold
* Air2PC/AirStar 2 ATSC 3rd generation (HD5000)
+ * pcHDTV HD5500
*
* TODO:
* signal strength always returns 0.
struct lgdt330x_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct lgdt330x_config* config;
}
/* Tune to the specified frequency */
- if (state->config->pll_set)
- state->config->pll_set(fe, param);
+ 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);
+ }
/* Keep track of the new frequency */
/* FIXME this is the wrong way to do this... */
if (state->current_modulation == VSB_8) {
+ i2c_read_demod_bytes(state, 0x6e, buf, 5);
/* Phase Tracker Mean-Square Error Register for VSB */
noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4];
} else {
/* Setup the state */
state->config = config;
state->i2c = i2c;
+
+ /* Create dvb_frontend */
switch (config->demod_chip) {
case LGDT3302:
- memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
break;
case LGDT3303:
- memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops));
break;
default:
goto error;
}
+ state->frontend.demodulator_priv = state;
/* Verify communication with demod chip */
if (i2c_read_demod_bytes(state, 2, buf, 1))
state->current_frequency = -1;
state->current_modulation = -1;
- /* Create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
/* PLL interface */
int (*pll_rf_set) (struct dvb_frontend* fe, int index);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
--- /dev/null
+/*
+ * lnbp21.h - driver for lnb supply and control ic lnbp21
+ *
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "lnbp21.h"
+
+struct lnbp21 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ void (*release_chain)(struct dvb_frontend* fe);
+};
+
+static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
+
+ switch(voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ lnbp21->config |= LNBP21_EN;
+ break;
+ case SEC_VOLTAGE_18:
+ lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
+ break;
+ default:
+ return -EINVAL;
+ };
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0,
+ .buf = &lnbp21->config,
+ .len = sizeof(lnbp21->config) };
+
+ if (arg)
+ lnbp21->config |= LNBP21_LLC;
+ else
+ lnbp21->config &= ~LNBP21_LLC;
+
+ lnbp21->config |= lnbp21->override_or;
+ lnbp21->config &= lnbp21->override_and;
+
+ return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void lnbp21_release(struct dvb_frontend *fe)
+{
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+
+ /* LNBP power off */
+ lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free data & call next release routine */
+ fe->ops.release = lnbp21->release_chain;
+ kfree(fe->misc_priv);
+ fe->misc_priv = NULL;
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+
+int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+ struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
+ if (!lnbp21)
+ return -ENOMEM;
+
+ /* default configuration */
+ lnbp21->config = LNBP21_ISEL;
+ lnbp21->i2c = i2c;
+ fe->misc_priv = lnbp21;
+
+ /* bits which should be forced to '1' */
+ lnbp21->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ lnbp21->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(lnbp21);
+ fe->misc_priv = NULL;
+ return -EIO;
+ }
+
+ /* install release callback */
+ lnbp21->release_chain = fe->ops.release;
+ fe->ops.release = lnbp21_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = lnbp21_set_voltage;
+ fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+
+ return 0;
+}
+EXPORT_SYMBOL(lnbp21_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21");
+MODULE_AUTHOR("Oliver Endriss");
+MODULE_LICENSE("GPL");
#ifndef _LNBP21_H
#define _LNBP21_H
-/* system register */
+/* system register bits */
#define LNBP21_OLF 0x01
#define LNBP21_OTF 0x02
#define LNBP21_EN 0x04
#define LNBP21_ISEL 0x40
#define LNBP21_PCL 0x80
-struct lnbp21 {
- u8 config;
- u8 override_or;
- u8 override_and;
- struct i2c_adapter *i2c;
- void (*release_chain)(struct dvb_frontend* fe);
-};
+#include <linux/dvb/frontend.h>
-static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- break;
- case SEC_VOLTAGE_13:
- lnbp21->config |= LNBP21_EN;
- break;
- case SEC_VOLTAGE_18:
- lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
- break;
- default:
- return -EINVAL;
- };
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
- struct i2c_msg msg = { .addr = 0x08, .flags = 0,
- .buf = &lnbp21->config,
- .len = sizeof(lnbp21->config) };
-
- if (arg)
- lnbp21->config |= LNBP21_LLC;
- else
- lnbp21->config &= ~LNBP21_LLC;
-
- lnbp21->config |= lnbp21->override_or;
- lnbp21->config &= lnbp21->override_and;
-
- return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
-}
-
-static void lnbp21_exit(struct dvb_frontend *fe)
-{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
- /* LNBP power off */
- lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-
- /* free data & call next release routine */
- fe->ops->release = lnbp21->release_chain;
- kfree(fe->misc_priv);
- fe->misc_priv = NULL;
- if (fe->ops->release)
- fe->ops->release(fe);
-}
-
-static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
-{
- struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
-
- if (!lnbp21)
- return -ENOMEM;
-
- /* default configuration */
- lnbp21->config = LNBP21_ISEL;
-
- /* bits which should be forced to '1' */
- lnbp21->override_or = override_set;
-
- /* bits which should be forced to '0' */
- lnbp21->override_and = ~override_clear;
-
- /* install release callback */
- lnbp21->release_chain = fe->ops->release;
- fe->ops->release = lnbp21_exit;
-
- /* override frontend ops */
- fe->ops->set_voltage = lnbp21_set_voltage;
- fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
-
- lnbp21->i2c = i2c;
- fe->misc_priv = lnbp21;
-
- return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
-}
+/* override_set and override_clear control which system register bits (above) to always set & clear */
+extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
#endif
struct mt312_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct mt312_config* config;
struct dvb_frontend frontend;
if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0)
return ret;
- if (state->config->pll_init) {
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_init(fe);
- mt312_writereg(state, GPP_CTRL, 0x00);
- }
-
return 0;
}
dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency);
- if ((p->frequency < fe->ops->info.frequency_min)
- || (p->frequency > fe->ops->info.frequency_max))
+ if ((p->frequency < fe->ops.info.frequency_min)
+ || (p->frequency > fe->ops.info.frequency_max))
return -EINVAL;
if ((p->inversion < INVERSION_OFF)
|| (p->inversion > INVERSION_ON))
return -EINVAL;
- if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min)
- || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max))
+ if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min)
+ || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max))
return -EINVAL;
if ((p->u.qpsk.fec_inner < FEC_NONE)
return -EINVAL;
}
- mt312_writereg(state, GPP_CTRL, 0x40);
- state->config->pll_set(fe, p);
- mt312_writereg(state, GPP_CTRL, 0x00);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* sr = (u16)(sr * 256.0 / 1000000.0) */
sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625);
return 0;
}
+static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct mt312_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return mt312_writereg(state, GPP_CTRL, 0x40);
+ } else {
+ return mt312_writereg(state, GPP_CTRL, 0x00);
+ }
+}
+
static int mt312_sleep(struct dvb_frontend* fe)
{
struct mt312_state *state = fe->demodulator_priv;
.init = mt312_initfe,
.sleep = mt312_sleep,
+ .i2c_gate_ctrl = mt312_i2c_gate_ctrl,
.set_frontend = mt312_set_frontend,
.get_frontend = mt312_get_frontend,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt312_readreg(state, ID, &state->id) < 0)
goto error;
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
switch (state->id) {
case ID_VP310:
- strcpy(state->ops.info.name, "Zarlink VP310 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
state->frequency = 90;
break;
case ID_MT312:
- strcpy(state->ops.info.name, "Zarlink MT312 DVB-S");
+ strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
state->frequency = 60;
break;
default:
goto error;
}
- /* create dvb_frontend */
- state->frontend.ops = &state->ops;
- state->frontend.demodulator_priv = state;
return &state->frontend;
error:
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
struct mt352_state {
struct i2c_adapter* i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
/* configuration settings */
struct mt352_config config;
mt352_calc_nominal_rate(state, op->bandwidth, buf+4);
mt352_calc_input_freq(state, buf+6);
- state->config.pll_set(fe, param, buf+8);
- mt352_write(fe, buf, sizeof(buf));
if (state->config.no_tuner) {
- /* start decoding */
+ 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);
+ }
+
+ mt352_write(fe, buf, 8);
mt352_write(fe, fsm_go, 2);
} else {
- /* start tuning */
- mt352_write(fe, tuner_go, 2);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
+ buf[8] <<= 1;
+ mt352_write(fe, buf, sizeof(buf));
+ mt352_write(fe, tuner_go, 2);
+ }
}
+
return 0;
}
/* setup the state */
state->i2c = i2c;
memcpy(&state->config,config,sizeof(struct mt352_config));
- memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
/* Initialise the demodulator and PLL. Cannot be NULL */
int (*demod_init)(struct dvb_frontend* fe);
-
- /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings.
- * byte0: Set to pll i2c address (nonlinux; left shifted by 1)
- * byte1-4: PLL configuration.
- */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf);
};
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct nxt200x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct nxt200x_config* config;
struct dvb_frontend frontend;
dprintk("%s\n", __FUNCTION__);
- dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]);
+ dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]);
/* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip.
* direct write is required for Philips TUV1236D and ALPS TDHU2 */
switch (state->demod_chip) {
case NXT2004:
- if (i2c_writebytes(state, state->config->pll_address, data, 4))
+ if (i2c_writebytes(state, data[0], data+1, 4))
printk(KERN_WARNING "nxt200x: error writing to tuner\n");
/* wait until we have a lock */
while (count < 20) {
- i2c_readbytes(state, state->config->pll_address, &buf, 1);
+ i2c_readbytes(state, data[0], &buf, 1);
if (buf & 0x40)
return 0;
msleep(100);
nxt200x_writebytes(state, 0x34, &buf, 1);
/* write actual tuner bytes */
- nxt200x_writebytes(state, 0x36, data, 4);
+ nxt200x_writebytes(state, 0x36, data+1, 4);
/* set tuner i2c address */
- buf = state->config->pll_address;
+ buf = data[0] << 1;
nxt200x_writebytes(state, 0x35, &buf, 1);
/* write UC Opmode to begin transfer */
struct dvb_frontend_parameters *p)
{
struct nxt200x_state* state = fe->demodulator_priv;
- u8 buf[4];
+ u8 buf[5];
/* stop the micro first */
nxt200x_microcontroller_stop(state);
}
/* get tuning information */
- dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0);
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, p, buf, 5);
+ }
/* set additional params */
switch (p->u.vsb.modulation) {
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* read card id */
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
/* the demodulator's i2c address */
u8 demod_address;
- /* tuner information */
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
-
/* used to set pll input */
int (*set_pll_input)(u8* buf, int input);
struct nxt6000_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct nxt6000_config* config;
struct dvb_frontend frontend;
nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0);
nxt6000_writereg(state, TS_FORMAT, 0);
-
- if (state->config->pll_init) {
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_init(fe);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
- }
}
static void nxt6000_dump_status(struct nxt6000_state *state)
struct nxt6000_state* state = fe->demodulator_priv;
int result;
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */
- state->config->pll_set(fe, param);
- nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */
+ 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 ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0)
return result;
return 0;
}
+static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct nxt6000_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01);
+ } else {
+ return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00);
+ }
+}
+
static struct dvb_frontend_ops nxt6000_ops;
struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.release = nxt6000_release,
.init = nxt6000_init,
+ .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl,
.get_tune_settings = nxt6000_fe_get_tune_settings,
/* should clock inversion be used? */
u8 clock_inversion:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
struct or51132_state
{
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51132_config* config;
{
struct or51132_state* state = fe->demodulator_priv;
static u8 run_buf[] = {0x7F,0x01};
- static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00};
- u8 rec_buf[14];
- u8 cmd_buf[14];
+ u8 rec_buf[8];
+ u8 cmd_buf[3];
u32 firmwareAsize, firmwareBsize;
int i,ret;
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x10;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
cmd_buf[0] = 0x04;
cmd_buf[1] = 0x17;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
cmd_buf[0] = 0x00;
cmd_buf[1] = 0x00;
- cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,2))) {
for(i=0;i<4;i++) {
msleep(20); /* 20ms */
- get_ver_buf[4] = i+1;
+ /* Once upon a time, this command might have had something
+ to do with getting the firmware version, but it's
+ not used anymore:
+ {0x04,0x00,0x30,0x00,i+1} */
+ /* Read 8 bytes, two bytes at a time */
if ((ret = i2c_readbytes(state,state->config->demod_address,
&rec_buf[i*2],2))) {
printk(KERN_WARNING
cmd_buf[0] = 0x10;
cmd_buf[1] = 0x00;
cmd_buf[2] = 0x00;
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if ((ret = i2c_writebytes(state,state->config->demod_address,
cmd_buf,3))) {
static int or51132_setmode(struct dvb_frontend* fe)
{
struct or51132_state* state = fe->demodulator_priv;
- unsigned char cmd_buf[4];
+ unsigned char cmd_buf[3];
dprintk("setmode %d\n",(int)state->current_modulation);
/* set operation mode in Receiver 1 register; */
default:
printk("setmode:Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
printk(KERN_WARNING "or51132: set_mode error 1\n");
default:
printk("setmode: Modulation set to unsupported value\n");
};
- cmd_buf[3] = 0x00;
msleep(20); /* 20ms */
if (i2c_writebytes(state,state->config->demod_address,
cmd_buf,3)) {
return 0;
}
+/* Some modulations use the same firmware. This classifies modulations
+ by the firmware they use. */
+#define MOD_FWCLASS_UNKNOWN 0
+#define MOD_FWCLASS_VSB 1
+#define MOD_FWCLASS_QAM 2
+static int modulation_fw_class(fe_modulation_t modulation)
+{
+ switch(modulation) {
+ case VSB_8:
+ return MOD_FWCLASS_VSB;
+ case QAM_AUTO:
+ case QAM_64:
+ case QAM_256:
+ return MOD_FWCLASS_QAM;
+ default:
+ return MOD_FWCLASS_UNKNOWN;
+ }
+}
+
static int or51132_set_parameters(struct dvb_frontend* fe,
struct dvb_frontend_parameters *param)
{
int ret;
- u8 buf[4];
struct or51132_state* state = fe->demodulator_priv;
const struct firmware *fw;
-
- /* Change only if we are actually changing the modulation */
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
- case VSB_8:
+ const char *fwname;
+ int clock_mode;
+
+ /* Upload new firmware only if we need a different one */
+ if (modulation_fw_class(state->current_modulation) !=
+ modulation_fw_class(param->u.vsb.modulation)) {
+ switch(modulation_fw_class(param->u.vsb.modulation)) {
+ case MOD_FWCLASS_VSB:
dprintk("set_parameters VSB MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_VSB_FIRMWARE);
- ret = request_firmware(&fw, OR51132_VSB_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_VSB_FIRMWARE;
+
/* Set non-punctured clock for VSB */
- state->config->set_ts_params(fe, 0);
+ clock_mode = 0;
break;
- case QAM_AUTO:
- case QAM_64:
- case QAM_256:
+ case MOD_FWCLASS_QAM:
dprintk("set_parameters QAM MODE\n");
- printk("or51132: Waiting for firmware upload(%s)...\n",
- OR51132_QAM_FIRMWARE);
- ret = request_firmware(&fw, OR51132_QAM_FIRMWARE,
- &state->i2c->dev);
- if (ret){
- printk(KERN_WARNING "or51132: No firmware up"
- "loaded(timeout or file not found?)\n");
- return ret;
- }
+ fwname = OR51132_QAM_FIRMWARE;
+
/* Set punctured clock for QAM */
- state->config->set_ts_params(fe, 1);
+ clock_mode = 1;
break;
default:
- printk("or51132:Modulation type(%d) UNSUPPORTED\n",
+ printk("or51132: Modulation type(%d) UNSUPPORTED\n",
param->u.vsb.modulation);
return -1;
- };
+ }
+ printk("or51132: Waiting for firmware upload(%s)...\n",
+ fwname);
+ ret = request_firmware(&fw, fwname, &state->i2c->dev);
+ if (ret) {
+ printk(KERN_WARNING "or51132: No firmware up"
+ "loaded(timeout or file not found?)\n");
+ return ret;
+ }
ret = or51132_load_firmware(fe, fw);
release_firmware(fw);
if (ret) {
return ret;
}
printk("or51132: Firmware upload complete.\n");
-
+ state->config->set_ts_params(fe, clock_mode);
+ }
+ /* Change only if we are actually changing the modulation */
+ if (state->current_modulation != param->u.vsb.modulation) {
state->current_modulation = param->u.vsb.modulation;
or51132_setmode(fe);
}
- dvb_pll_configure(state->config->pll_desc, buf,
- param->frequency, 0);
- dprintk("set_parameters tuner bytes: 0x%02x 0x%02x "
- "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]);
- if (i2c_writebytes(state, state->config->pll_address ,buf, 4))
- printk(KERN_WARNING "or51132: set_parameters error "
- "writing to tuner\n");
+ 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);
+ }
/* Set to current mode */
or51132_setmode(fe);
return 0;
}
+static int or51132_get_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct or51132_state* state = fe->demodulator_priv;
+ u8 buf[2];
+
+ /* Receiver Status */
+ buf[0]=0x04;
+ buf[1]=0x00;
+ msleep(30); /* 30ms */
+ if (i2c_writebytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters write error\n");
+ return -EREMOTEIO;
+ }
+ msleep(30); /* 30ms */
+ if (i2c_readbytes(state,state->config->demod_address,buf,2)) {
+ printk(KERN_WARNING "or51132: get_parameters read error\n");
+ return -EREMOTEIO;
+ }
+ switch(buf[0]) {
+ case 0x06: param->u.vsb.modulation = VSB_8; break;
+ case 0x43: param->u.vsb.modulation = QAM_64; break;
+ case 0x45: param->u.vsb.modulation = QAM_256; break;
+ default:
+ printk(KERN_WARNING "or51132: unknown status 0x%02x\n",
+ buf[0]);
+ return -EREMOTEIO;
+ }
+
+ /* FIXME: Read frequency from frontend, take AFC into account */
+ param->frequency = state->current_frequency;
+
+ /* FIXME: How to read inversion setting? Receiver 6 register? */
+ param->inversion = INVERSION_AUTO;
+
+ return 0;
+}
+
static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct or51132_state* state = fe->demodulator_priv;
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->current_frequency = -1;
state->current_modulation = -1;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.info = {
.name = "Oren OR51132 VSB/QAM Frontend",
- .type = FE_ATSC,
+ .type = FE_ATSC,
.frequency_min = 44000000,
.frequency_max = 958000000,
.frequency_stepsize = 166666,
.sleep = or51132_sleep,
.set_frontend = or51132_set_parameters,
+ .get_frontend = or51132_get_parameters,
.get_tune_settings = or51132_get_tune_settings,
.read_status = or51132_read_status,
{
/* The demodulator's i2c address */
u8 demod_address;
- u8 pll_address;
- struct dvb_pll_desc *pll_desc;
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
struct or51211_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* Configuration settings */
const struct or51211_config* config;
/* Setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->initialized = 0;
state->current_frequency = 0;
/* Create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
struct s5h1420_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct s5h1420_config* config;
struct dvb_frontend frontend;
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
- u32 tmp;
/* check if we should do a fast-tune */
memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
(state->fec_inner == p->u.qpsk.fec_inner) &&
(state->symbol_rate == p->u.qpsk.symbol_rate)) {
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ u32 tmp;
+ fe->ops.tuner_ops.get_frequency(fe, &tmp);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, p->frequency - tmp);
+ } else {
+ s5h1420_setfreqoffset(state, 0);
}
return 0;
}
s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
/* set tuner PLL */
- if (state->config->pll_set) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_set(fe, p, &tmp);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, 0);
}
return 0;
}
+static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ } else {
+ return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+}
+
static int s5h1420_init (struct dvb_frontend* fe)
{
struct s5h1420_state* state = fe->demodulator_priv;
msleep(10);
s5h1420_reset(state);
- /* init PLL */
- if (state->config->pll_init) {
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- state->config->pll_init(fe);
- s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
- }
-
return 0;
}
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->postlocked = 0;
state->fclk = 88000000;
state->tunedfreq = 0;
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = s5h1420_init,
.sleep = s5h1420_sleep,
+ .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl,
.set_frontend = s5h1420_set_frontend,
.get_frontend = s5h1420_get_frontend,
/* does the inversion require inversion? */
u8 invert:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
};
extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
-
const struct sp8870_config* config;
struct dvb_frontend frontend;
sp8870_microcontroller_stop(state);
// set tuner parameters
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_set(fe, p);
- sp8870_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
// sample rate correction bit [23..17]
sp8870_writereg(state, 0x0319, 0x000A);
sp8870_writereg(state, 0x0D00, 0x010);
sp8870_writereg(state, 0x0D01, 0x000);
- /* setup PLL */
- if (state->config->pll_init) {
- sp8870_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp8870_writereg(state, 0x206, 0x000);
- }
-
return 0;
}
return 0;
}
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp8870_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp8870_writereg(state, 0x206, 0x001);
+ } else {
+ return sp8870_writereg(state, 0x206, 0x000);
+ }
+}
+
static void sp8870_release(struct dvb_frontend* fe)
{
struct sp8870_state* state = fe->demodulator_priv;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp8870_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = sp8870_init,
.sleep = sp8870_sleep,
+ .i2c_gate_ctrl = sp8870_i2c_gate_ctrl,
.set_frontend = sp8870_set_frontend,
.get_tune_settings = sp8870_get_tune_settings,
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
struct sp887x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct sp887x_config* config;
struct dvb_frontend frontend;
/* bit 0x010: enable data valid signal */
sp887x_writereg(state, 0xd00, 0x010);
sp887x_writereg(state, 0x0d1, 0x000);
-
- /* setup the PLL */
- if (state->config->pll_init) {
- sp887x_writereg(state, 0x206, 0x001);
- state->config->pll_init(fe);
- sp887x_writereg(state, 0x206, 0x000);
- }
-
- printk ("done.\n");
return 0;
};
sp887x_microcontroller_stop(state);
/* setup the PLL */
- sp887x_writereg(state, 0x206, 0x001);
- actual_freq = state->config->pll_set(fe, p);
- sp887x_writereg(state, 0x206, 0x000);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (fe->ops.tuner_ops.get_frequency) {
+ fe->ops.tuner_ops.get_frequency(fe, &actual_freq);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ } else {
+ actual_freq = p->frequency;
+ }
/* read status reg in order to clear <pending irqs */
sp887x_readreg(state, 0x200);
return 0;
}
+static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct sp887x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return sp887x_writereg(state, 0x206, 0x001);
+ } else {
+ return sp887x_writereg(state, 0x206, 0x000);
+ }
+}
+
static int sp887x_sleep(struct dvb_frontend* fe)
{
struct sp887x_state* state = fe->demodulator_priv;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
/* check if the demod is there */
if (sp887x_readreg(state, 0x0200) < 0) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = sp887x_init,
.sleep = sp887x_sleep,
+ .i2c_gate_ctrl = sp887x_i2c_gate_ctrl,
.set_frontend = sp887x_setup_frontend_parameters,
.get_tune_settings = sp887x_get_tune_settings,
/* the demodulator's i2c address */
u8 demod_address;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
-
- /* this should return the actual frequency tuned to */
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
struct stv0297_state {
struct i2c_adapter *i2c;
- struct dvb_frontend_ops ops;
const struct stv0297_config *config;
struct dvb_frontend frontend;
int ret;
u8 b0[] = { reg };
u8 b1[] = { 0 };
- struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len =
- 1},
- {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
- };
+ struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1},
+ {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1}
+ };
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret);
+ return -1;
+ }
}
return b1[0];
};
// this device needs a STOP between the register and data
- if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
- }
- if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
- dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
- return -1;
+ if (state->config->stop_during_read) {
+ if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
+ } else {
+ if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) {
+ dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret);
+ return -1;
+ }
}
return 0;
return 0;
}
-int stv0297_enable_plli2c(struct dvb_frontend *fe)
+static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct stv0297_state *state = fe->demodulator_priv;
- stv0297_writereg(state, 0x87, 0x78);
- stv0297_writereg(state, 0x86, 0xc8);
+ if (enable) {
+ stv0297_writereg(state, 0x87, 0x78);
+ stv0297_writereg(state, 0x86, 0xc8);
+ }
return 0;
}
stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]);
msleep(200);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
case QAM_32:
case QAM_64:
delay = 100;
- sweeprate = 1500;
+ sweeprate = 1000;
break;
case QAM_128:
}
stv0297_init(fe);
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
/* clear software interrupts */
stv0297_writereg(state, 0x82, 0x0);
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->base_freq = 0;
/* check if the demod is there */
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = stv0297_init,
.sleep = stv0297_sleep,
+ .i2c_gate_ctrl = stv0297_i2c_gate_ctrl,
.set_frontend = stv0297_set_frontend,
.get_frontend = stv0297_get_frontend,
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(stv0297_attach);
-EXPORT_SYMBOL(stv0297_enable_plli2c);
/* does the "inversion" need inverted? */
u8 invert:1;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
+ /* set to 1 if the device requires an i2c STOP during reading */
+ u8 stop_during_read:1;
};
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
-extern int stv0297_enable_plli2c(struct dvb_frontend* fe);
#endif // STV0297_H
struct stv0299_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct stv0299_config* config;
struct dvb_frontend frontend;
return ret == 2 ? 0 : ret;
}
-int stv0299_enable_plli2c (struct dvb_frontend* fe)
-{
- struct stv0299_state* state = fe->demodulator_priv;
-
- return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
-}
-
static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec)
{
dprintk ("%s\n", __FUNCTION__);
for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2)
stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]);
- if (state->config->pll_init) {
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_init(fe, state->i2c);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
- }
-
return 0;
}
if (state->config->invert) invval = (~invval) & 1;
stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval);
- stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */
- state->config->pll_set(fe, state->i2c, p);
- stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
stv0299_set_FEC (state, p->u.qpsk.fec_inner);
stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate);
return 0;
}
+static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct stv0299_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ stv0299_writeregI(state, 0x05, 0xb5);
+ } else {
+ stv0299_writeregI(state, 0x05, 0x35);
+ }
+ udelay(1);
+ return 0;
+}
+
static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
struct stv0299_state* state = fe->demodulator_priv;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
state->tuner_frequency = 0;
state->symbol_rate = 0;
if (id != 0xa1 && id != 0x80) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = stv0299_init,
.sleep = stv0299_sleep,
+ .i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
.set_frontend = stv0299_set_frontend,
.get_frontend = stv0299_get_frontend,
MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver");
MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
- "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy");
+ "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(stv0299_enable_plli2c);
EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach);
/* Set the symbol rate */
int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c);
- int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params);
};
extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-extern int stv0299_enable_plli2c (struct dvb_frontend* fe);
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c);
struct tda10021_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda10021_config* config;
struct dvb_frontend frontend;
return (ret != 1) ? -EREMOTEIO : 0;
}
+int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ return tda10021_writereg(state, reg, data);
+}
+EXPORT_SYMBOL(tda10021_write_byte);
+
static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
{
u8 b0 [] = { reg };
//Activate PLL
tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
-
- if (state->config->pll_init) {
- lock_tuner(state);
- state->config->pll_init(fe);
- unlock_tuner(state);
- }
-
return 0;
}
//printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate);
- lock_tuner(state);
- state->config->pll_set(fe, p);
- unlock_tuner(state);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
tda10021_writereg (state, 0x34, state->pwm);
return 0;
}
+static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ lock_tuner(state);
+ } else {
+ unlock_tuner(state);
+ }
+ return 0;
+}
+
static int tda10021_sleep(struct dvb_frontend* fe)
{
struct tda10021_state* state = fe->demodulator_priv;
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->pwm = pwm;
state->reg0 = tda10021_inittab[0];
if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = tda10021_init,
.sleep = tda10021_sleep,
+ .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
.set_frontend = tda10021_set_parameters,
.get_frontend = tda10021_get_frontend,
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
struct i2c_adapter* i2c, u8 pwm);
+extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+
#endif // TDA10021_H
struct tda1004x_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
const struct tda1004x_config* config;
struct dvb_frontend frontend;
tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC
- // Init the PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_init(fe);
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
return -EIO;
}
- // Init the tuner PLL
- if (state->config->pll_init) {
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_init(fe)) {
- printk(KERN_ERR "tda1004x: pll init failed\n");
- return -EIO;
- }
- tda1004x_disable_tuner_i2c(state);
- }
-
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream
}
// set frequency
- tda1004x_enable_tuner_i2c(state);
- if (state->config->pll_set(fe, fe_params)) {
- printk(KERN_ERR "tda1004x: pll set failed\n");
- return -EIO;
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fe_params);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
}
- tda1004x_disable_tuner_i2c(state);
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
break;
case TDA1004X_DEMOD_TDA10046:
- if (state->config->pll_sleep != NULL) {
- tda1004x_enable_tuner_i2c(state);
- state->config->pll_sleep(fe);
- if (state->config->if_freq != TDA10046_FREQ_052) {
- /* special hack for Philips EUROPA Based boards:
- * keep the I2c bridge open for tuner access in analog mode
- */
- tda1004x_disable_tuner_i2c(state);
- }
- }
/* set outputs to tristate */
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff);
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
return 0;
}
+static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda1004x_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return tda1004x_enable_tuner_i2c(state);
+ } else {
+ return tda1004x_disable_tuner_i2c(state);
+ }
+}
+
static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 800;
.init = tda10045_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10045;
/* check if the demod is there */
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
.init = tda10046_init,
.sleep = tda1004x_sleep,
+ .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
.get_frontend = tda1004x_get_fe,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->demod_type = TDA1004X_DEMOD_TDA10046;
/* check if the demod is there */
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
/* AGC configuration */
enum tda10046_agc agc_config;
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- void (*pll_sleep)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
-
/* request firmware for device */
/* set this to NULL if the card has a firmware EEPROM */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
struct tda8083_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct tda8083_config* config;
struct dvb_frontend frontend;
{
struct tda8083_state* state = fe->demodulator_priv;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
tda8083_set_inversion (state, p->inversion);
tda8083_set_fec (state, p->u.qpsk.fec_inner);
tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate);
for (i=0; i<44; i++)
tda8083_writereg (state, i, tda8083_init_tab[i]);
- if (state->config->pll_init) state->config->pll_init(fe);
-
tda8083_writereg (state, 0x00, 0x3c);
tda8083_writereg (state, 0x00, 0x04);
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if ((tda8083_readreg(state, 0x00)) != 0x05) goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
{
/* the demodulator's i2c address */
u8 demod_address;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
struct ves1820_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1820_config* config;
struct dvb_frontend frontend;
ves1820_writereg(state, 0x34, state->pwm);
- if (state->config->pll_init)
- state->config->pll_init(fe);
-
return 0;
}
if (real_qam < 0 || real_qam > 4)
return -EINVAL;
- state->config->pll_set(fe, p);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
ves1820_set_symbolrate(state, p->u.qam.symbol_rate);
ves1820_writereg(state, 0x34, state->pwm);
goto error;
/* setup the state */
- memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
state->reg0 = ves1820_inittab[0];
state->config = config;
state->i2c = i2c;
if (verbose)
printk("ves1820: pwm=0x%02x\n", state->pwm);
- state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
- state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
-
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */
+ state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */
state->frontend.demodulator_priv = state;
+
return &state->frontend;
error:
/* SELAGC control */
u8 selagc:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
struct ves1x93_state {
struct i2c_adapter* i2c;
- struct dvb_frontend_ops ops;
/* configuration settings */
const struct ves1x93_config* config;
struct dvb_frontend frontend;
}
}
- if (state->config->pll_init) {
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_init(fe);
- ves1x93_writereg(state, 0x00, 0x01);
- }
-
return 0;
}
{
struct ves1x93_state* state = fe->demodulator_priv;
- ves1x93_writereg(state, 0x00, 0x11);
- state->config->pll_set(fe, p);
- ves1x93_writereg(state, 0x00, 0x01);
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ }
ves1x93_set_inversion (state, p->inversion);
ves1x93_set_fec (state, p->u.qpsk.fec_inner);
ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate);
kfree(state);
}
+static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct ves1x93_state* state = fe->demodulator_priv;
+
+ if (enable) {
+ return ves1x93_writereg(state, 0x00, 0x11);
+ } else {
+ return ves1x93_writereg(state, 0x00, 0x01);
+ }
+}
+
static struct dvb_frontend_ops ves1x93_ops;
struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->inversion = INVERSION_OFF;
/* check if the demod is there + identify it */
}
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
.init = ves1x93_init,
.sleep = ves1x93_sleep,
+ .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
.set_frontend = ves1x93_set_frontend,
.get_frontend = ves1x93_get_frontend,
/* should PWM be inverted? */
u8 invert_pwm:1;
-
- /* PLL maintenance */
- int (*pll_init)(struct dvb_frontend* fe);
- int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
};
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
struct zl10353_state {
struct i2c_adapter *i2c;
struct dvb_frontend frontend;
- struct dvb_frontend_ops ops;
struct zl10353_config config;
};
struct dvb_frontend_parameters *param)
{
struct zl10353_state *state = fe->demodulator_priv;
+
u8 pllbuf[6] = { 0x67 };
/* These settings set "auto-everything" and start the FSM. */
zl10353_single_write(fe, 0x66, 0xE9);
zl10353_single_write(fe, 0x62, 0x0A);
- state->config.pll_set(fe, param, pllbuf + 1);
+ // 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 pllbuf is defined, retrieve the settings
+ if (fe->ops.tuner_ops.calc_regs) {
+ fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5);
+ pllbuf[1] <<= 1;
+ } else {
+ // fake pllbuf settings
+ pllbuf[1] = 0x61 << 1;
+ pllbuf[2] = 0;
+ pllbuf[3] = 0;
+ pllbuf[3] = 0;
+ pllbuf[4] = 0;
+ }
+
+ // there is no call to _just_ start decoding, so we send the pllbuf anyway
+ // even if there isn't a PLL attached to the secondary bus
zl10353_write(fe, pllbuf, sizeof(pllbuf));
zl10353_single_write(fe, 0x70, 0x01);
/* setup the state */
state->i2c = i2c;
memcpy(&state->config, config, sizeof(struct zl10353_config));
- memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
/* check if the demod is there */
if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353)
goto error;
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
/* demodulator's I2C address */
u8 demod_address;
- /* function which configures the PLL buffer (for secondary I2C
- * connected tuner) or tunes the PLL (for direct connected tuner) */
- int (*pll_set)(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params, u8 *pllbuf);
+ /* set if no pll is connected to the secondary i2c bus */
+ int no_tuner;
};
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
}
/* LG Innotek TDTE-E001P (Infineon TUA6034) */
-static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *p)
+static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct pluto *pluto = frontend_to_pluto(fe);
struct i2c_msg msg;
msg.buf = buf;
msg.len = sizeof(buf);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
if (ret < 0)
return ret;
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_set = lg_tdtpe001p_pll_set,
- .pll_sleep = NULL,
.request_firmware = pluto2_request_firmware,
};
dev_err(&pluto->pdev->dev, "could not attach frontend\n");
return -ENODEV;
}
+ pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params;
ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
if (ret < 0) {
- if (pluto->fe->ops->release)
- pluto->fe->ops->release(pluto->fe);
+ if (pluto->fe->ops.release)
+ pluto->fe->ops.release(pluto->fe);
return ret;
}
goto err_pluto_hw_exit;
/* dvb */
- ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+ ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev);
if (ret < 0)
goto err_i2c_bit_del_bus;
select DVB_SP8870
select DVB_STV0297
select DVB_L64781
+ select DVB_LNBP21
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
select DVB_TDA8083
select DVB_TDA10021
select DVB_S5H1420
+ select DVB_LNBP21
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
select DVB_STV0297
select DVB_STV0299
select DVB_TDA1004X
+ select DVB_LNBP21
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
hostprogs-y := fdump
-ifdef CONFIG_DVB_AV7110_FIRMWARE
-$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h
+ifeq ($(CONFIG_DVB_AV7110_FIRMWARE),y)
+$(obj)/av7110.o: $(obj)/av7110_firm.h
-$(obj)/av7110_firm.h:
+$(obj)/av7110_firm.h: $(obj)/fdump
$(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@
endif
#endif
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
u8 pwr = 0;
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
data[2] = 0x8e;
data[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
-static int philips_cd1516_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
data[2] = 0x8e;
data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = philips_cd1516_pll_set,
};
-static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div, pwr;
data[2] = 0x85;
data[3] = pwr << 6;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
static struct sp8870_config alps_tdlb7_config = {
.demod_address = 0x71,
- .pll_set = alps_tdlb7_pll_set,
.request_firmware = alps_tdlb7_request_firmware,
};
0xff, 0xff,
};
-static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
{
struct av7110* av7110 = fe->dvb->priv;
u32 div;
else
return -EINVAL;
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
printk("nexusca: pll transfer failed!\n");
return -EIO;
// wait for PLL lock
for(i = 0; i < 20; i++) {
-
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
if (data[0] & 0x40) break;
msleep(10);
.demod_address = 0x1C,
.inittab = nexusca_stv0297_inittab,
.invert = 1,
- .pll_set = nexusca_stv0297_pll_set,
+ .stop_during_read = 1,
};
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+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;
u32 div;
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
- .pll_set = grundig_29504_401_pll_set,
};
case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
av7110->fe = ves1820_attach(&philips_cd1516_config,
&av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+ }
break;
}
// try the ALPS BSRV2 first of all
av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
// try the ALPS BSRU6 now
av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
// Try the grundig 29504-451
av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
break;
}
/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
+ }
break;
case 0x0003:
/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
break;
}
break;
// ALPS TDLB7
av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+ }
break;
case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ }
break;
case 0x0004: // Galaxis DVB-S rev1.3
/* ALPS BSRV2 */
av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
/* Grundig 29504-451 */
av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
- av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
- av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst;
- av7110->fe->ops->set_tone = av7110_set_tone;
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
+ av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst;
+ av7110->fe->ops.set_tone = av7110_set_tone;
av7110->recover = dvb_s_recover;
}
break;
case 0x0008: // Hauppauge/TT DVB-T
av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
+ if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ }
break;
case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
if (av7110->fe) {
+ av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
+
/* set TDA9819 into DVB mode */
saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD)
saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF)
/* ALPS BSBE1 */
av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
if (av7110->fe) {
- if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+ av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ av7110->fe->tuner_priv = &av7110->i2c_adap;
+
+ if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
printk("dvb-ttpci: LNBP21 not found!\n");
- if (av7110->fe->ops->release)
- av7110->fe->ops->release(av7110->fe);
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
} else {
- av7110->fe->ops->dishnetwork_send_legacy_command = NULL;
+ av7110->fe->ops.dishnetwork_send_legacy_command = NULL;
av7110->recover = dvb_s_recover;
}
}
av7110->dev->pci->subsystem_vendor,
av7110->dev->pci->subsystem_device);
} else {
- FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init);
- FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
- FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
- FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
- FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;)
+ FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command);
+ FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend);
ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
if (ret < 0) {
printk("av7110: Frontend registration failed!\n");
- if (av7110->fe->ops->release)
- av7110->fe->ops->release(av7110->fe);
+ if (av7110->fe->ops.release)
+ av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
}
}
goto err_kfree_0;
ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name,
- THIS_MODULE);
+ THIS_MODULE, &dev->pci->dev);
if (ret < 0)
goto err_put_firmware_1;
#define DEBICICAM 0x02420000
+#define SLOTSTATUS_NONE 1
+#define SLOTSTATUS_PRESENT 2
+#define SLOTSTATUS_RESET 4
+#define SLOTSTATUS_READY 8
+#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY)
+
struct budget_av {
struct budget budget;
struct video_device *vd;
struct tasklet_struct ciintf_irq_tasklet;
int slot_status;
struct dvb_ca_en50221 ca;
+ u8 reinitialise_demod:1;
+ u8 tda10021_poclkp:1;
+ u8 tda10021_ts_enabled;
+ int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p);
};
+static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot);
+
+
/* GPIO Connections:
* 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*!
* 1 - CI memory select 0=>IO memory, 1=>Attribute Memory
udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 1\n");
+ }
return result;
}
udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 2\n");
+ }
return result;
}
udelay(1);
result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 3\n");
+ return -ETIMEDOUT;
+ }
return result;
}
udelay(1);
result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0);
-
- if (result == -ETIMEDOUT)
- budget_av->slot_status = 0;
+ if (result == -ETIMEDOUT) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 5\n");
+ }
return result;
}
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int timeout = 50; // 5 seconds (4.4.6 Ready)
if (slot != 0)
return -EINVAL;
dprintk(1, "ciintf_slot_reset\n");
+ budget_av->slot_status = SLOTSTATUS_RESET;
saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
msleep(20); /* 20 ms Vcc settling time */
saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */
+ ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
+ msleep(20);
- /* This should have been based on pin 16 READY of the pcmcia port,
- * but AFAICS it is not routed to the saa7146 */
- while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d)
- msleep(100);
-
- /* reinitialise the frontend */
- dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
+ /* reinitialise the frontend if necessary */
+ if (budget_av->reinitialise_demod)
+ dvb_frontend_reinitialise(budget_av->budget.dvb_frontend);
- if (timeout <= 0)
- {
- printk(KERN_ERR "budget-av: cam reset failed (timeout).\n");
- saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
- return -ETIMEDOUT;
+ /* set tda10021 back to original clock configuration on reset */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
}
return 0;
dprintk(1, "ciintf_slot_shutdown\n");
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB);
- budget_av->slot_status = 0;
+ budget_av->slot_status = SLOTSTATUS_NONE;
+
+ /* set tda10021 back to original clock configuration when cam removed */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ budget_av->tda10021_ts_enabled = 0;
+ }
return 0;
}
dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status);
ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA);
+
+ /* tda10021 seems to need a different TS clock config when data is routed to the CAM */
+ if (budget_av->tda10021_poclkp) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ budget_av->tda10021_ts_enabled = 1;
+ }
+
return 0;
}
{
struct budget_av *budget_av = (struct budget_av *) ca->data;
struct saa7146_dev *saa = budget_av->budget.dev;
- int cam_present = 0;
+ int result;
if (slot != 0)
return -EINVAL;
- if (!budget_av->slot_status)
- {
- // first of all test the card detect line
+ /* test the card detect line - needs to be done carefully
+ * since it never goes high for some CAMs on this interface (e.g. topuptv) */
+ if (budget_av->slot_status == SLOTSTATUS_NONE) {
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
udelay(1);
- if (saa7146_read(saa, PSR) & MASK_06)
- {
- cam_present = 1;
+ if (saa7146_read(saa, PSR) & MASK_06) {
+ if (budget_av->slot_status == SLOTSTATUS_NONE) {
+ budget_av->slot_status = SLOTSTATUS_PRESENT;
+ printk(KERN_INFO "budget-av: cam inserted A\n");
+ }
}
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO);
+ }
- // that is unreliable however, so try and read from IO memory
- if (!cam_present)
- {
- saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
- if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT)
- {
- cam_present = 1;
+ /* We also try and read from IO memory to work round the above detection bug. If
+ * there is no CAM, we will get a timeout. Only done if there is no cam
+ * present, since this test actually breaks some cams :(
+ *
+ * if the CI interface is not open, we also do the above test since we
+ * don't care if the cam has problems - we'll be resetting it on open() anyway */
+ if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) {
+ saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
+ result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1);
+ if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) {
+ budget_av->slot_status = SLOTSTATUS_PRESENT;
+ printk(KERN_INFO "budget-av: cam inserted B\n");
+ } else if (result < 0) {
+ if (budget_av->slot_status != SLOTSTATUS_NONE) {
+ ciintf_slot_shutdown(ca, slot);
+ printk(KERN_INFO "budget-av: cam ejected 5\n");
+ return 0;
}
}
+ }
- // did we find something?
- if (cam_present) {
- printk(KERN_INFO "budget-av: cam inserted\n");
- budget_av->slot_status = 1;
- }
- } else if (!open) {
- saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO);
- if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT)
- {
- printk(KERN_INFO "budget-av: cam ejected\n");
- saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */
- budget_av->slot_status = 0;
+ /* read from attribute memory in reset/ready state to know when the CAM is ready */
+ if (budget_av->slot_status == SLOTSTATUS_RESET) {
+ result = ciintf_read_attribute_mem(ca, slot, 0);
+ if (result == 0x1d) {
+ budget_av->slot_status = SLOTSTATUS_READY;
}
}
- if (budget_av->slot_status == 1)
- return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
-
+ /* work out correct return code */
+ if (budget_av->slot_status != SLOTSTATUS_NONE) {
+ if (budget_av->slot_status & SLOTSTATUS_READY) {
+ return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY;
+ }
+ return DVB_CA_EN50221_POLL_CAM_PRESENT;
+ }
return 0;
}
budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable;
budget_av->ca.poll_slot_status = ciintf_poll_slot_status;
budget_av->ca.data = budget_av;
+ budget_av->budget.ci_present = 1;
+ budget_av->slot_status = SLOTSTATUS_NONE;
if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter,
&budget_av->ca, 0, 1)) != 0) {
}
printk(KERN_INFO "budget-av: ci interface initialised.\n");
- budget_av->budget.ci_present = 1;
return 0;
error:
return 0;
}
-static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u32 div;
u8 buf[4];
+ struct budget *budget = (struct budget *) fe->dvb->priv;
struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) };
if ((params->frequency < 950000) || (params->frequency > 2150000))
else if (params->frequency < 2150000)
buf[3] |= 0xC0;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
#define MIN2(a,b) ((a) < (b) ? (a) : (b))
#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 reg0 [2] = { 0x00, 0x00 };
u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
int R, A, N, P, M;
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
int freq = params->frequency;
+ struct budget *budget = (struct budget *) fe->dvb->priv;
first_ZF = (freq) / 1000;
reg0[1] |= 0x03;
/* already enabled - do not reenable i2c repeater or TX fails */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg0;
msg.len = sizeof(reg0);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
- stv0299_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg1;
msg.len = sizeof(reg1);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
- stv0299_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
msg.buf = reg2;
msg.len = sizeof(reg2);
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278_ty_ci_pll_set,
};
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278_ty_ci_pll_set,
};
static struct stv0299_config cinergy_1200s_1894_0010_config = {
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate,
- .pll_set = philips_su1278sh2_tua6100_pll_set,
};
-static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 buf[4];
buf[3] = (params->frequency < 150000000 ? 0x01 :
params->frequency < 445000000 ? 0x02 : 0x04);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
static struct tda10021_config philips_cu1216_config = {
.demod_address = 0x0c,
- .pll_set = philips_cu1216_pll_set,
};
-static int philips_tu1216_pll_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_init(struct dvb_frontend *fe)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
return 0;
}
-static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct budget *budget = (struct budget *) fe->dvb->priv;
u8 tuner_buf[4];
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_init,
- .pll_set = philips_tu1216_pll_set,
- .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
0xff, 0xff
};
-static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
u8 buf[4];
int rc;
struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)};
+ struct budget *budget = (struct budget *) fe->dvb->priv;
if((params->frequency < 950000) || (params->frequency > 2150000))
return -EINVAL;
params->frequency, 0);
if(rc < 0) return rc;
- if(i2c_transfer(i2c, &tuner_msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
return 0;
static struct stv0299_config philips_sd1878_config = {
.demod_address = 0x68,
- .inittab = philips_sd1878_inittab,
+ .inittab = philips_sd1878_inittab,
.mclk = 88000000UL,
.invert = 0,
.skip_reinit = 0,
.volt13_op0_op1 = STV0299_VOLT13_OP0,
.min_delay_ms = 100,
.set_symbol_rate = philips_sd1878_ci_set_symbol_rate,
- .pll_set = philips_sd1878_tda8261_pll_set,
};
static u8 read_pwm(struct budget_av *budget_av)
#define SUBID_DVBS_TV_STAR 0x0014
#define SUBID_DVBS_TV_STAR_CI 0x0016
+#define SUBID_DVBS_EASYWATCH_1 0x001a
#define SUBID_DVBS_EASYWATCH 0x001e
#define SUBID_DVBC_KNC1 0x0020
#define SUBID_DVBC_KNC1_PLUS 0x0021
#define SUBID_DVBT_KNC1 0x0030
#define SUBID_DVBT_CINERGY1200 0x1157
+
+static int tda10021_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct budget_av* budget_av = fe->dvb->priv;
+ int result;
+
+ result = budget_av->tda10021_set_frontend(fe, p);
+ if (budget_av->tda10021_ts_enabled) {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ } else {
+ tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ }
+
+ return result;
+}
+
static void frontend_init(struct budget_av *budget_av)
{
struct saa7146_dev * saa = budget_av->budget.dev;
struct dvb_frontend * fe = NULL;
+ /* Enable / PowerON Frontend */
+ saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
+
+ /* additional setup necessary for the PLUS cards */
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBT_KNC1_PLUS:
- // Enable / PowerON Frontend
- saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO);
saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI);
break;
}
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1:
+ case SUBID_DVBS_EASYWATCH_1:
if (saa->pci->subsystem_vendor == 0x1894) {
fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+ }
} else {
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
}
break;
case SUBID_DVBS_EASYWATCH:
fe = stv0299_attach(&philips_sd1878_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
+ }
break;
case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_TYPHOON:
fe = stv0299_attach(&typhoon_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
break;
case SUBID_DVBS_CINERGY1200:
fe = stv0299_attach(&cinergy_1200s_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
+ }
break;
case SUBID_DVBC_KNC1:
case SUBID_DVBC_KNC1_PLUS:
+ case SUBID_DVBC_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
fe = tda10021_attach(&philips_cu1216_config,
&budget_av->budget.i2c_adap,
read_pwm(budget_av));
+ if (fe) {
+ budget_av->tda10021_poclkp = 1;
+ budget_av->tda10021_set_frontend = fe->ops.set_frontend;
+ fe->ops.set_frontend = tda10021_set_frontend;
+ fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
+ }
break;
case SUBID_DVBT_KNC1:
case SUBID_DVBT_KNC1_PLUS:
- fe = tda10046_attach(&philips_tu1216_config,
- &budget_av->budget.i2c_adap);
- break;
-
- case SUBID_DVBC_CINERGY1200:
- fe = tda10021_attach(&philips_cu1216_config,
- &budget_av->budget.i2c_adap,
- read_pwm(budget_av));
- break;
-
case SUBID_DVBT_CINERGY1200:
+ budget_av->reinitialise_demod = 1;
fe = tda10046_attach(&philips_tu1216_config,
&budget_av->budget.i2c_adap);
+ if (fe) {
+ fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
+ fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params;
+ }
break;
}
if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
budget_av->budget.dvb_frontend)) {
printk(KERN_ERR "budget-av: Frontend registration failed!\n");
- if (budget_av->budget.dvb_frontend->ops->release)
- budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend);
+ if (budget_av->budget.dvb_frontend->ops.release)
+ budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
budget_av->budget.dvb_frontend = NULL;
}
}
MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T);
MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR);
MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR);
+MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S);
MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP);
MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP);
MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP);
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
+ MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a),
MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020),
MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021),
MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030),
return 0;
}
-static int philips_su1278_tt_pll_set(struct dvb_frontend *fe,
- struct i2c_adapter *i2c,
- struct dvb_frontend_parameters *params)
+static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
+ struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u32 div;
u8 buf[4];
struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) };
else if (params->frequency < 2150000)
buf[3] |= 0xC0;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 50,
.set_symbol_rate = philips_su1278_tt_set_symbol_rate,
- .pll_set = philips_su1278_tt_pll_set,
};
-static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe)
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
sizeof(td1316_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1);
}
return 0;
}
-static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int 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;
u8 tuner_buf[4];
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tdm1316l_pll_init,
- .pll_set = philips_tdm1316l_pll_set,
- .pll_sleep = NULL,
.request_firmware = philips_tdm1316l_request_firmware,
};
-static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+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;
u8 tuner_buf[5];
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
tuner_buf[4] = 0x80;
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(50);
- stv0297_enable_plli2c(fe);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
.demod_address = 0x1c,
.inittab = dvbc_philips_tdm1316l_inittab,
.invert = 0,
- .pll_set = dvbc_philips_tdm1316l_pll_set,
+ .stop_during_read = 1,
};
budget_ci->budget.dvb_frontend =
stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
break;
}
break;
budget_ci->budget.dvb_frontend =
stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
break;
}
break;
budget_ci->budget.dvb_frontend =
stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
}
break;
budget_ci->budget.dvb_frontend =
tda10045_attach(&philips_tdm1316l_config, &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;
break;
}
break;
budget_ci->budget.dvb_frontend =
tda10046_attach(&philips_tdm1316l_config, &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;
break;
}
break;
case 0x1017: // TT S-1500 PCI
budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
- budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
- if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+ budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
+ budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
+
+ budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
+ if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
- if (budget_ci->budget.dvb_frontend->ops->release)
- budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ if (budget_ci->budget.dvb_frontend->ops.release)
+ budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
if (dvb_register_frontend
(&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
printk("budget-ci: Frontend registration failed!\n");
- if (budget_ci->budget.dvb_frontend->ops->release)
- budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend);
+ if (budget_ci->budget.dvb_frontend->ops.release)
+ budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
budget->dev->name, budget->buffer_width, budget->buffer_height);
printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size);
- dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner);
+ if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) {
+ return ret;
+ }
/* set dd1 stream a & b */
saa7146_write(dev, DD1_STREAM_B, 0x00000000);
return 0;
}
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u8 pwr = 0;
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
u32 div;
data[2] = 0x8e;
data[3] = 0x00;
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
static void frontend_init(struct budget_patch* budget)
// try the ALPS BSRV2 first of all
budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_patch_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
break;
}
// try the ALPS BSRU6 now
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
// Try the grundig 29504-451
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
break;
} else {
if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
printk("budget-av: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ if (budget->dvb_frontend->ops.release)
+ budget->dvb_frontend->ops.release(budget->dvb_frontend);
budget->dvb_frontend = NULL;
}
}
return 0;
}
-static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u8 pwr = 0;
// NOTE: since we're using a prescaler of 2, we set the
// divisor frequency to 62.5kHz and divide by 125 above
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
.demod_address = 0x08,
.xin = 90100000UL,
.invert_pwm = 0,
- .pll_set = alps_bsrv2_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
-static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
data[2] = ((div >> 10) & 0x60) | cfg;
data[3] = (cpump << 6) | band_select;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
- .pll_set = grundig_29504_401_pll_set,
};
-static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
data[2] = 0x8e;
data[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
- .pll_set = grundig_29504_451_pll_set,
};
-static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
u32 div;
else
data[3] = 0xc0;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
- *freqout = div * 1000;
return 0;
}
static struct s5h1420_config s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
- .pll_set = s5h1420_pll_set,
};
static u8 read_pwm(struct budget* budget)
// try the ALPS BSRV2 first of all
budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
// try the ALPS BSRU6 now
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops->set_tone = budget_set_tone;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
+ budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
+ budget->dvb_frontend->ops.set_tone = budget_set_tone;
break;
}
break;
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
- if (budget->dvb_frontend) break;
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
break;
case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
- if (budget->dvb_frontend) break;
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
+ break;
+ }
break;
case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
+ budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
}
break;
case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage;
- budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL;
+ budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
+ budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
+ budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
}
break;
case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
- if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+ budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
+ if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out;
}
error_out:
printk("budget: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops->release)
- budget->dvb_frontend->ops->release(budget->dvb_frontend);
+ if (budget->dvb_frontend->ops.release)
+ budget->dvb_frontend->ops.release(budget->dvb_frontend);
budget->dvb_frontend = NULL;
return;
}
select DVB_VES1820
select DVB_TDA8083
select DVB_STV0299
+ select DVB_STV0297
+ select DVB_LNBP21
help
Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'Nova-USB'.
#include "tda1004x.h"
#include "stv0299.h"
#include "tda8083.h"
+#include "stv0297.h"
+#include "lnbp21.h"
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
}
#endif
-static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
-{
- struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
- int ret;
- u8 data[1];
- struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) };
-
- switch(voltage) {
- case SEC_VOLTAGE_OFF:
- data[0] = 0x00;
- break;
- case SEC_VOLTAGE_13:
- data[0] = 0x44;
- break;
- case SEC_VOLTAGE_18:
- data[0] = 0x4c;
- break;
- default:
- return -EINVAL;
- };
-
- ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1);
- return (ret != 1) ? -EIO : 0;
-}
-
static int ttusb_update_lnb(struct ttusb *ttusb)
{
u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
-static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 data[4];
data[2] = ((div >> 10) & 0x60) | 0x85;
data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static struct cx22700_config alps_tdmb7_config = {
.demod_address = 0x43,
- .pll_set = alps_tdmb7_pll_set,
};
-static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
+static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
// setup PLL configuration
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
msleep(1);
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
}
return 0;
}
-static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 tuner_buf[4];
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
.demod_address = 0x8,
.invert = 1,
.invert_oclk = 0,
- .pll_init = philips_tdm1316l_pll_init,
- .pll_set = philips_tdm1316l_pll_set,
.request_firmware = philips_tdm1316l_request_firmware,
};
return 0;
}
-static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params)
+static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
if (ttusb->revision == TTUSB_REV_2_2)
buf[3] |= 0x20;
- if (i2c_transfer(i2c, &msg, 1) != 1)
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = alps_stv0299_set_symbol_rate,
- .pll_set = philips_tsa5059_pll_set,
};
-static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 buf[4];
buf[2] = 0x8e;
buf[3] = 0x00;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
.demod_address = 0x68,
- .pll_set = ttusb_novas_grundig_29504_491_pll_set,
};
-static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb* ttusb = fe->dvb->priv;
u32 div;
data[2] = 0x85 | ((div >> 10) & 0x60);
data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
return -EIO;
.xin = 57840000UL,
.invert = 1,
.selagc = VES1820_SELAGC_SIGNAMPERR,
- .pll_set = alps_tdbe2_pll_set,
};
static u8 read_pwm(struct ttusb* ttusb)
}
+static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv;
+ u8 tuner_buf[5];
+ struct i2c_msg tuner_msg = {.addr = 0x60,
+ .flags = 0,
+ .buf = tuner_buf,
+ .len = sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ // determine charge pump
+ tuner_frequency = params->frequency;
+ if (tuner_frequency < 87000000) {return -EINVAL;}
+ else if (tuner_frequency < 130000000) {cp = 3; band = 1;}
+ else if (tuner_frequency < 160000000) {cp = 5; band = 1;}
+ else if (tuner_frequency < 200000000) {cp = 6; band = 1;}
+ else if (tuner_frequency < 290000000) {cp = 3; band = 2;}
+ else if (tuner_frequency < 420000000) {cp = 5; band = 2;}
+ else if (tuner_frequency < 480000000) {cp = 6; band = 2;}
+ else if (tuner_frequency < 620000000) {cp = 3; band = 4;}
+ else if (tuner_frequency < 830000000) {cp = 5; band = 4;}
+ else if (tuner_frequency < 895000000) {cp = 7; band = 4;}
+ else {return -EINVAL;}
+
+ // assume PLL filter should always be 8MHz for the moment.
+ filter = 1;
+
+ // calculate divisor
+ // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz
+ tuner_frequency = ((params->frequency + 36125000) / 62500);
+
+ // setup tuner buffer
+ tuner_buf[0] = tuner_frequency >> 8;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xc8;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ tuner_buf[4] = 0x80;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
+ return -EIO;
+ }
+
+ msleep(50);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
+ printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
+ return -EIO;
+ }
+
+ msleep(1);
+
+ return 0;
+}
+
+static u8 dvbc_philips_tdm1316l_inittab[] = {
+ 0x80, 0x21,
+ 0x80, 0x20,
+ 0x81, 0x01,
+ 0x81, 0x00,
+ 0x00, 0x09,
+ 0x01, 0x69,
+ 0x03, 0x00,
+ 0x04, 0x00,
+ 0x07, 0x00,
+ 0x08, 0x00,
+ 0x20, 0x00,
+ 0x21, 0x40,
+ 0x22, 0x00,
+ 0x23, 0x00,
+ 0x24, 0x40,
+ 0x25, 0x88,
+ 0x30, 0xff,
+ 0x31, 0x00,
+ 0x32, 0xff,
+ 0x33, 0x00,
+ 0x34, 0x50,
+ 0x35, 0x7f,
+ 0x36, 0x00,
+ 0x37, 0x20,
+ 0x38, 0x00,
+ 0x40, 0x1c,
+ 0x41, 0xff,
+ 0x42, 0x29,
+ 0x43, 0x20,
+ 0x44, 0xff,
+ 0x45, 0x00,
+ 0x46, 0x00,
+ 0x49, 0x04,
+ 0x4a, 0xff,
+ 0x4b, 0x7f,
+ 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,
+ 0x70, 0xff,
+ 0x71, 0x00,
+ 0x72, 0x00,
+ 0x73, 0x00,
+ 0x74, 0x0c,
+ 0x80, 0x00,
+ 0x81, 0x00,
+ 0x82, 0x00,
+ 0x83, 0x00,
+ 0x84, 0x04,
+ 0x85, 0x80,
+ 0x86, 0x24,
+ 0x87, 0x78,
+ 0x88, 0x00,
+ 0x89, 0x00,
+ 0x90, 0x01,
+ 0x91, 0x01,
+ 0xa0, 0x00,
+ 0xa1, 0x00,
+ 0xa2, 0x00,
+ 0xb0, 0x91,
+ 0xb1, 0x0b,
+ 0xc0, 0x4b,
+ 0xc1, 0x00,
+ 0xc2, 0x00,
+ 0xd0, 0x00,
+ 0xd1, 0x00,
+ 0xd2, 0x00,
+ 0xd3, 0x00,
+ 0xd4, 0x00,
+ 0xd5, 0x00,
+ 0xde, 0x00,
+ 0xdf, 0x00,
+ 0x61, 0x38,
+ 0x62, 0x0a,
+ 0x53, 0x13,
+ 0x59, 0x08,
+ 0x55, 0x00,
+ 0x56, 0x40,
+ 0x57, 0x08,
+ 0x58, 0x3d,
+ 0x88, 0x10,
+ 0xa0, 0x00,
+ 0xa0, 0x00,
+ 0xa0, 0x00,
+ 0xa0, 0x04,
+ 0xff, 0xff,
+};
+
+static struct stv0297_config dvbc_philips_tdm1316l_config = {
+ .demod_address = 0x1c,
+ .inittab = dvbc_philips_tdm1316l_inittab,
+ .invert = 0,
+};
+
static void frontend_init(struct ttusb* ttusb)
{
switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
// try the stv0299 based first
ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
+
if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
alps_stv0299_config.inittab = alps_bsbe1_inittab;
- ttusb->fe->ops->set_voltage = lnbp21_set_voltage;
+ lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
} else { // ALPS BSRU6
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
}
break;
}
// Grundig 29504-491
ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
- ttusb->fe->ops->set_voltage = ttusb_set_voltage;
+ ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
+ ttusb->fe->ops.set_voltage = ttusb_set_voltage;
break;
}
-
break;
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
+ break;
+ }
+
+ ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
+ }
break;
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
break;
+ }
// Philips td1316
ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
- if (ttusb->fe != NULL)
+ if (ttusb->fe != NULL) {
+ ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
+ ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
break;
+ }
break;
}
} else {
if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
printk("dvb-ttusb-budget: Frontend registration failed!\n");
- if (ttusb->fe->ops->release)
- ttusb->fe->ops->release(ttusb->fe);
+ if (ttusb->fe->ops.release)
+ ttusb->fe->ops.release(ttusb->fe);
ttusb->fe = NULL;
}
}
mutex_unlock(&ttusb->semi2c);
- if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) {
+ if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) {
ttusb_free_iso_urbs(ttusb);
kfree(ttusb);
return result;
dprintk("%s\n", __FUNCTION__);
if ((result = dvb_register_adapter(&dec->adapter,
- dec->model_name, THIS_MODULE)) < 0) {
+ dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) {
printk("%s: dvb_register_adapter failed: error %d\n",
__FUNCTION__, result);
} else {
if (dvb_register_frontend(&dec->adapter, dec->fe)) {
printk("budget-ci: Frontend registration failed!\n");
- if (dec->fe->ops->release)
- dec->fe->ops->release(dec->fe);
+ if (dec->fe->ops.release)
+ dec->fe->ops.release(dec->fe);
dec->fe = NULL;
}
}
struct ttusbdecfe_state {
- struct dvb_frontend_ops ops;
-
/* configuration settings */
const struct ttusbdecfe_config* config;
/* setup the state */
state->config = config;
- memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
state->config = config;
state->voltage = 0;
state->hi_band = 0;
- memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
/* create dvb_frontend */
- state->frontend.ops = &state->ops;
+ memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
}
Choose Y here if you have this PCI FM radio card.
In order to control your radio card, you will need to use programs
- that are compatible with the Video for Linux API. Information on
+ that are compatible with the Video for Linux API. Information on
this API and pointers to "v4l" programs may be found at
<file:Documentation/video4linux/API.html>.
obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o
+
+EXTRA_CFLAGS += -Isound
/* What ever you think about the ACI, version 0x07 is not very well!
* I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions... Robert
+ * conditions... Robert
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/videodev.h>
-#include "../../../sound/oss/aci.h"
+#include <media/v4l2-common.h>
+#include "oss/aci.h"
#include "miropcm20-rds-core.h"
static int radio_nr = -1;
struct video_device *dev = video_devdata(file);
struct pcm20_device *pcm20 = dev->priv;
int i;
-
+
switch(cmd)
{
case VIDIOCGCAP:
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=87*16000;
v->rangehigh=108*16000;
return i;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags=VIDEO_AUDIO_MUTABLE;
v->mode|=VIDEO_SOUND_MONO;
/* v->step=2048; */
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
{
if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
goto video_register_device;
-
+
if(attach_aci_rds()<0)
goto attach_aci_rds;
#include <linux/mutex.h>
#include <asm/io.h>
-#include "../../../sound/oss/aci.h"
+#include "oss/aci.h"
#include "miropcm20-rds-core.h"
#define DEBUG 0
#define RDS_BUSYMASK 0x10 /* Bit 4 */
#define RDS_CLOCKMASK 0x08 /* Bit 3 */
-#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
+#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1)
#if DEBUG
static void print_matrix(char array[], unsigned int length)
{
- int i, j;
-
- for (i=0; i<length; i++) {
- printk(KERN_DEBUG "aci-rds: ");
- for (j=7; j>=0; j--) {
- printk("%d", (array[i] >> j) & 0x1);
- }
- if (i%8 == 0)
- printk(" byte-border\n");
- else
- printk("\n");
- }
+ int i, j;
+
+ for (i=0; i<length; i++) {
+ printk(KERN_DEBUG "aci-rds: ");
+ for (j=7; j>=0; j--) {
+ printk("%d", (array[i] >> j) & 0x1);
+ }
+ if (i%8 == 0)
+ printk(" byte-border\n");
+ else
+ printk("\n");
+ }
}
#endif /* DEBUG */
{
unsigned char sendbuffer[8];
int i;
-
+
if (byte2trans(cmd, sendbuffer, 8) != 0){
return -1;
} else {
I have to waitread() here */
if (rds_waitread() < 0)
return -1;
-
+
memset(databuffer, 0, datasize);
for (i=0; i< READSIZE; i++)
ret = 0;
mutex_unlock(&aci_rds_mutex);
-
+
return ret;
}
EXPORT_SYMBOL(aci_rds_cmd);
static void print_matrix(char *ch, char out[])
{
- int j;
+ int j;
for (j=7; j>=0; j--) {
out[7-j] = ((*ch >> j) & 0x1) + '0';
* out(port, start_increasing_volume);
* wait(a_wee_while);
* out(port, stop_changing_the_volume);
- *
+ *
*/
#include <linux/module.h> /* Modules */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_RTRACK_PORT */
#include <asm/semaphore.h> /* Lock for the I/O */
#define CONFIG_RADIO_RTRACK_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK_PORT;
+static int io = CONFIG_RADIO_RTRACK_PORT;
static int radio_nr = -1;
static struct mutex lock;
int i;
mutex_lock(&lock);
-
+
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
outb (0xd8, io); /* enable card */
- }
+ }
mutex_unlock(&lock);
return 0;
}
dev->muted = 0;
if(vol > dev->curvol)
- for(i = dev->curvol; i < vol; i++)
+ for(i = dev->curvol; i < vol; i++)
rt_incvol();
else
- for(i = dev->curvol; i > vol; i--)
+ for(i = dev->curvol; i > vol; i--)
rt_decvol();
dev->curvol = vol;
return 0;
}
-/* the 128+64 on these outb's is to keep the volume stable while tuning
+/* the 128+64 on these outb's is to keep the volume stable while tuning
* without them, the volume _will_ creep up with each frequency change
* and bit 4 (+16) is to keep the signal strength meter enabled
*/
outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */
outb_p(128+64+16+8+2+1, port); /* clock */
}
- sleep_delay(1000);
+ sleep_delay(1000);
}
static void send_1_byte(int port, struct rt_device *dev)
if ((dev->curvol == 0) || (dev->muted)) {
outb_p(128+64+16+4 +1, port); /* wr-enable+data high */
outb_p(128+64+16+4+2+1, port); /* clock */
- }
+ }
else {
outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */
outb_p(128+64+16+8+4+2+1, port); /* clock */
}
- sleep_delay(1000);
+ sleep_delay(1000);
}
static int rt_setfreq(struct rt_device *dev, unsigned long freq)
freq += 171200; /* Add 10.7 MHz IF */
freq /= 800; /* Convert to 50 kHz units */
-
+
mutex_lock(&lock); /* Stop other ops interfering */
-
+
send_0_byte (io, dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
outb (0xd0, io); /* volume steady + sigstr */
else
outb (0xd8, io); /* volume steady + sigstr + on */
-
+
mutex_unlock(&lock);
return 0;
{
struct video_device *dev = video_devdata(file);
struct rt_device *rt=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=rt->curvol * 6554;
v->step=6554;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
rt_mute(rt);
else
rt_setvol(rt,v->volume/6554);
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = rt_ioctl,
+ .ioctl = rt_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
return -EINVAL;
}
- if (!request_region(io, 2, "rtrack"))
+ if (!request_region(io, 2, "rtrack"))
{
printk(KERN_ERR "rtrack: port 0x%x already in use\n", io);
return -EBUSY;
}
rtrack_radio.priv=&rtrack_unit;
-
+
if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 2);
printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n");
/* Set up the I/O locking */
-
+
mutex_init(&lock);
-
- /* mute card - prevents noisy bootups */
+
+ /* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
outb(0x48, io); /* volume down but still "on" */
-/* radio-aztech.c - Aztech radio card driver for Linux 2.2
+/* radio-aztech.c - Aztech radio card driver for Linux 2.2
*
- * Adapted to support the Video for Linux API by
+ * Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_AZTECH_PORT */
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
#define CONFIG_RADIO_AZTECH_PORT -1
#endif
-static int io = CONFIG_RADIO_AZTECH_PORT;
+static int io = CONFIG_RADIO_AZTECH_PORT;
static int radio_nr = -1;
static int radio_wait_time = 1000;
static struct mutex lock;
static int volconvert(int level)
{
- level>>=14; /* Map 16bits down to 2 bit */
- level&=3;
-
+ level>>=14; /* Map 16bits down to 2 bit */
+ level&=3;
+
/* convert to card-friendly values */
- switch (level)
+ switch (level)
{
- case 0:
+ case 0:
return 0;
- case 1:
+ case 1:
return 1;
case 2:
return 4;
frequency += 171200; /* Add 10.7 MHz IF */
frequency /= 800; /* Convert to 50 kHz units */
-
+
mutex_lock(&lock);
-
+
send_0_byte (dev); /* 0: LSB of frequency */
for (i = 0; i < 13; i++) /* : frequency bits (1-13) */
udelay (radio_wait_time);
outb_p(128+64+volconvert(dev->curvol), io);
-
+
mutex_unlock(&lock);
return 0;
{
struct video_device *dev = video_devdata(file);
struct az_device *az = dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=az->curvol;
v->step=16384;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
az->curvol=v->volume;
az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
az_setvol(az,0);
else
az_setvol(az,az->curvol);
return -EINVAL;
}
- if (!request_region(io, 2, "aztech"))
+ if (!request_region(io, 2, "aztech"))
{
printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
return -EBUSY;
mutex_init(&lock);
aztech_radio.priv=&aztech_unit;
-
+
if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io,2);
return -EINVAL;
}
-
+
printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
/* mute card - prevents noisy bootups */
outb (0, io);
* Russell Kroll (rkroll@exploits.org)
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/param.h>
#include <linux/pnp.h>
/*
* Signal Strength Threshold Values
- * The V4L API spec does not define any particular unit for the signal
+ * The V4L API spec does not define any particular unit for the signal
* strength value. These values are in microvolts of RF at the tuner's input.
*/
static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
static int cadet_getrds(void)
{
- int rdsstat=0;
+ int rdsstat=0;
spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
+ outb(3,io); /* Select Decoder Control/Status */
outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
spin_unlock(&cadet_io_lock);
-
+
msleep(100);
- spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
+ spin_lock(&cadet_io_lock);
+ outb(3,io); /* Select Decoder Control/Status */
if((inb(io+1)&0x80)!=0) {
- rdsstat|=VIDEO_TUNER_RDS_ON;
+ rdsstat|=VIDEO_TUNER_RDS_ON;
}
if((inb(io+1)&0x10)!=0) {
- rdsstat|=VIDEO_TUNER_MBS_ON;
+ rdsstat|=VIDEO_TUNER_MBS_ON;
}
spin_unlock(&cadet_io_lock);
return rdsstat;
static int cadet_getstereo(void)
{
int ret = 0;
- if(curtuner != 0) /* Only FM has stereo capability! */
- return 0;
+ if(curtuner != 0) /* Only FM has stereo capability! */
+ return 0;
spin_lock(&cadet_io_lock);
- outb(7,io); /* Select tuner control */
+ outb(7,io); /* Select tuner control */
if( (inb(io+1) & 0x40) == 0)
- ret = 1;
- spin_unlock(&cadet_io_lock);
- return ret;
+ ret = 1;
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static unsigned cadet_gettune(void)
{
- int curvol,i;
+ int curvol,i;
unsigned fifo=0;
- /*
- * Prepare for read
- */
+ /*
+ * Prepare for read
+ */
spin_lock(&cadet_io_lock);
-
- outb(7,io); /* Select tuner control */
- curvol=inb(io+1); /* Save current volume/mute setting */
- outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
+
+ outb(7,io); /* Select tuner control */
+ curvol=inb(io+1); /* Save current volume/mute setting */
+ outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
tunestat=0xffff;
- /*
- * Read the shift register
- */
- for(i=0;i<25;i++) {
- fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
- if(i<24) {
- outb(0x01,io+1);
+ /*
+ * Read the shift register
+ */
+ for(i=0;i<25;i++) {
+ fifo=(fifo<<1)|((inb(io+1)>>7)&0x01);
+ if(i<24) {
+ outb(0x01,io+1);
tunestat&=inb(io+1);
- outb(0x00,io+1);
- }
- }
-
- /*
- * Restore volume/mute setting
- */
- outb(curvol,io+1);
+ outb(0x00,io+1);
+ }
+ }
+
+ /*
+ * Restore volume/mute setting
+ */
+ outb(curvol,io+1);
spin_unlock(&cadet_io_lock);
return fifo;
static unsigned cadet_getfreq(void)
{
- int i;
- unsigned freq=0,test,fifo=0;
+ int i;
+ unsigned freq=0,test,fifo=0;
/*
* Read current tuning
*/
fifo=cadet_gettune();
- /*
- * Convert to actual frequency
- */
+ /*
+ * Convert to actual frequency
+ */
if(curtuner==0) { /* FM */
- test=12500;
- for(i=0;i<14;i++) {
- if((fifo&0x01)!=0) {
- freq+=test;
- }
- test=test<<1;
- fifo=fifo>>1;
- }
- freq-=10700000; /* IF frequency is 10.7 MHz */
- freq=(freq*16)/1000000; /* Make it 1/16 MHz */
+ test=12500;
+ for(i=0;i<14;i++) {
+ if((fifo&0x01)!=0) {
+ freq+=test;
+ }
+ test=test<<1;
+ fifo=fifo>>1;
+ }
+ freq-=10700000; /* IF frequency is 10.7 MHz */
+ freq=(freq*16)/1000000; /* Make it 1/16 MHz */
}
if(curtuner==1) { /* AM */
- freq=((fifo&0x7fff)-2010)*16;
+ freq=((fifo&0x7fff)-2010)*16;
}
- return freq;
+ return freq;
}
static void cadet_settune(unsigned fifo)
{
- int i;
- unsigned test;
+ int i;
+ unsigned test;
spin_lock(&cadet_io_lock);
-
+
outb(7,io); /* Select tuner control */
/*
* Write the shift register
outb(7,io); /* Select tuner control */
outb(test,io+1); /* Initialize for write */
for(i=0;i<25;i++) {
- test|=0x01; /* Toggle SCK High */
+ test|=0x01; /* Toggle SCK High */
outb(test,io+1);
test&=0xfe; /* Toggle SCK Low */
outb(test,io+1);
static void cadet_setfreq(unsigned freq)
{
- unsigned fifo;
- int i,j,test;
- int curvol;
+ unsigned fifo;
+ int i,j,test;
+ int curvol;
- /*
- * Formulate a fifo command
- */
+ /*
+ * Formulate a fifo command
+ */
fifo=0;
if(curtuner==0) { /* FM */
- test=102400;
- freq=(freq*1000)/16; /* Make it kHz */
- freq+=10700; /* IF is 10700 kHz */
- for(i=0;i<14;i++) {
- fifo=fifo<<1;
- if(freq>=test) {
- fifo|=0x01;
- freq-=test;
- }
- test=test>>1;
- }
+ test=102400;
+ freq=(freq*1000)/16; /* Make it kHz */
+ freq+=10700; /* IF is 10700 kHz */
+ for(i=0;i<14;i++) {
+ fifo=fifo<<1;
+ if(freq>=test) {
+ fifo|=0x01;
+ freq-=test;
+ }
+ test=test>>1;
+ }
}
if(curtuner==1) { /* AM */
- fifo=(freq/16)+2010; /* Make it kHz */
+ fifo=(freq/16)+2010; /* Make it kHz */
fifo|=0x100000; /* Select AM Band */
}
- /*
- * Save current volume/mute setting
- */
+ /*
+ * Save current volume/mute setting
+ */
spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
- curvol=inb(io+1);
- spin_unlock(&cadet_io_lock);
+ curvol=inb(io+1);
+ spin_unlock(&cadet_io_lock);
/*
* Tune the card
*/
for(j=3;j>-1;j--) {
- cadet_settune(fifo|(j<<16));
-
- spin_lock(&cadet_io_lock);
+ cadet_settune(fifo|(j<<16));
+
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
outb(curvol,io+1);
spin_unlock(&cadet_io_lock);
-
+
msleep(100);
cadet_gettune();
if((tunestat & 0x40) == 0) { /* Tuned */
- sigstrength=sigtable[curtuner][j];
+ sigstrength=sigtable[curtuner][j];
return;
}
}
static int cadet_getvol(void)
{
int ret = 0;
-
+
spin_lock(&cadet_io_lock);
-
- outb(7,io); /* Select tuner control */
- if((inb(io + 1) & 0x20) != 0)
- ret = 0xffff;
-
- spin_unlock(&cadet_io_lock);
- return ret;
+
+ outb(7,io); /* Select tuner control */
+ if((inb(io + 1) & 0x20) != 0)
+ ret = 0xffff;
+
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static void cadet_setvol(int vol)
{
spin_lock(&cadet_io_lock);
- outb(7,io); /* Select tuner control */
- if(vol>0)
- outb(0x20,io+1);
- else
- outb(0x00,io+1);
+ outb(7,io); /* Select tuner control */
+ if(vol>0)
+ outb(0x20,io+1);
+ else
+ outb(0x00,io+1);
spin_unlock(&cadet_io_lock);
-}
+}
static void cadet_handler(unsigned long data)
{
if(spin_trylock(&cadet_io_lock))
{
- outb(0x3,io); /* Select RDS Decoder Control */
+ outb(0x3,io); /* Select RDS Decoder Control */
if((inb(io+1)&0x20)!=0) {
- printk(KERN_CRIT "cadet: RDS fifo overflow\n");
+ printk(KERN_CRIT "cadet: RDS fifo overflow\n");
}
outb(0x80,io); /* Select RDS fifo */
while((inb(io)&0x80)!=0) {
- rdsbuf[rdsin]=inb(io+1);
+ rdsbuf[rdsin]=inb(io+1);
if(rdsin==rdsout)
- printk(KERN_WARNING "cadet: RDS buffer overflow\n");
+ printk(KERN_WARNING "cadet: RDS buffer overflow\n");
else
rdsin++;
}
* Service pending read
*/
if( rdsin!=rdsout)
- wake_up_interruptible(&read_queue);
+ wake_up_interruptible(&read_queue);
- /*
+ /*
* Clean up and exit
*/
init_timer(&readtimer);
static ssize_t cadet_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
- int i=0;
+ int i=0;
unsigned char readbuf[RDS_BUFFER];
- if(rdsstat==0) {
+ if(rdsstat==0) {
spin_lock(&cadet_io_lock);
- rdsstat=1;
+ rdsstat=1;
outb(0x80,io); /* Select RDS fifo */
spin_unlock(&cadet_io_lock);
init_timer(&readtimer);
add_timer(&readtimer);
}
if(rdsin==rdsout) {
- if (file->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
- interruptible_sleep_on(&read_queue);
- }
+ if (file->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&read_queue);
+ }
while( i<count && rdsin!=rdsout)
- readbuf[i++]=rdsbuf[rdsout++];
+ readbuf[i++]=rdsbuf[rdsout++];
if (copy_to_user(data,readbuf,i))
- return -EFAULT;
+ return -EFAULT;
return i;
}
return -EINVAL;
}
switch(v->tuner) {
- case 0:
- strcpy(v->name,"FM");
- v->rangelow=1400; /* 87.5 MHz */
- v->rangehigh=1728; /* 108.0 MHz */
- v->flags=0;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- if(cadet_getstereo()==1) {
- v->flags|=VIDEO_TUNER_STEREO_ON;
- }
+ case 0:
+ strcpy(v->name,"FM");
+ v->rangelow=1400; /* 87.5 MHz */
+ v->rangehigh=1728; /* 108.0 MHz */
+ v->flags=0;
+ v->mode=0;
+ v->mode|=VIDEO_MODE_AUTO;
+ v->signal=sigstrength;
+ if(cadet_getstereo()==1) {
+ v->flags|=VIDEO_TUNER_STEREO_ON;
+ }
v->flags|=cadet_getrds();
- break;
- case 1:
- strcpy(v->name,"AM");
- v->rangelow=8320; /* 520 kHz */
- v->rangehigh=26400; /* 1650 kHz */
- v->flags=0;
- v->flags|=VIDEO_TUNER_LOW;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- break;
+ break;
+ case 1:
+ strcpy(v->name,"AM");
+ v->rangelow=8320; /* 520 kHz */
+ v->rangehigh=26400; /* 1650 kHz */
+ v->flags=0;
+ v->flags|=VIDEO_TUNER_LOW;
+ v->mode=0;
+ v->mode|=VIDEO_MODE_AUTO;
+ v->signal=sigstrength;
+ break;
}
return 0;
}
if((v->tuner<0)||(v->tuner>1)) {
return -EINVAL;
}
- curtuner=v->tuner;
+ curtuner=v->tuner;
return 0;
}
case VIDIOCGFREQ:
{
- unsigned long *freq = arg;
+ unsigned long *freq = arg;
*freq = cadet_getfreq();
return 0;
}
case VIDIOCSFREQ:
{
- unsigned long *freq = arg;
+ unsigned long *freq = arg;
if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
- return -EINVAL;
+ return -EINVAL;
}
if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
- return -EINVAL;
+ return -EINVAL;
}
cadet_setfreq(*freq);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
if(cadet_getstereo()==0) {
- v->mode=VIDEO_SOUND_MONO;
+ v->mode=VIDEO_SOUND_MONO;
} else {
v->mode=VIDEO_SOUND_STEREO;
}
v->volume=cadet_getvol();
v->step=0xffff;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
cadet_setvol(v->volume);
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
cadet_setvol(0);
else
cadet_setvol(0xffff);
static int cadet_probe(void)
{
- static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
+ static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e};
int i;
for(i=0;i<8;i++) {
- io=iovals[i];
+ io=iovals[i];
if (request_region(io, 2, "cadet-probe")) {
- cadet_setfreq(1410);
+ cadet_setfreq(1410);
if(cadet_getfreq()==1410) {
release_region(io, 2);
- return io;
+ return io;
}
release_region(io, 2);
}
return -1;
}
-/*
+/*
* io should only be set if the user has used something like
* isapnp (the userspace program) to initialize this card for us
*/
static int __init cadet_init(void)
{
spin_lock_init(&cadet_io_lock);
-
+
/*
* If a probe was requested then probe ISAPnP first (safest)
*/
/*
* Else we bail out
*/
-
- if(io < 0) {
-#ifdef MODULE
+
+ if(io < 0) {
+#ifdef MODULE
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
#endif
- goto fail;
+ goto fail;
}
if (!request_region(io,2,"cadet"))
goto fail;
/*
***************************************************************************
- *
+ *
* radio-gemtek-pci.c - Gemtek PCI Radio driver
* (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
*
* radio device driver.
*
* Please, let me know if this piece of code was useful :)
- *
+ *
* TODO: multiple device support and portability were not tested
*
***************************************************************************
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/errno.h>
#include <asm/io.h>
#define TRUE (1)
#endif
-#ifndef FALSE
+#ifndef FALSE
#define FALSE (0)
#endif
struct gemtek_pci_card {
struct video_device *videodev;
-
+
u32 iobase;
u32 length;
u8 chiprev;
u16 model;
-
+
u32 current_frequency;
u8 mute;
};
return (u8)value;
}
-#define _b0( v ) *((u8 *)&v)
+#define _b0( v ) *((u8 *)&v)
static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep )
{
register u8 byte = *last_byte;
if ( !value ) {
if ( !keep )
value = (u16)port;
- byte &= 0xfd;
+ byte &= 0xfd;
} else
byte |= 2;
byte &= 0xfe;
_b0( value ) = byte;
outw( value, port );
-
+
*last_byte = byte;
}
c->audios = 1;
strcpy( c->name, "Gemtek PCI Radio" );
return 0;
- }
+ }
case VIDIOCGTUNER:
{
struct video_tuner *t = arg;
- if ( t->tuner )
+ if ( t->tuner )
return -EINVAL;
t->rangelow = GEMTEK_PCI_RANGE_LOW;
case VIDIOCSFREQ:
{
unsigned long *freq = arg;
-
+
if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
(*freq > GEMTEK_PCI_RANGE_HIGH) )
return -EINVAL;
return 0;
}
-
+
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *a = arg;
memset( a, 0, sizeof( *a ) );
a->volume = 1;
a->step = 65535;
strcpy( a->name, "Radio" );
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *a = arg;
- if ( a->audio )
+ if ( a->audio )
return -EINVAL;
- if ( a->flags & VIDEO_AUDIO_MUTE )
+ if ( a->flags & VIDEO_AUDIO_MUTE )
gemtek_pci_mute( card );
else
gemtek_pci_unmute( card );
return -ENOMEM;
}
- if ( pci_enable_device( pci_dev ) )
+ if ( pci_enable_device( pci_dev ) )
goto err_pci;
-
+
card->iobase = pci_resource_start( pci_dev, 0 );
card->length = pci_resource_len( pci_dev, 0 );
pci_read_config_word( pci_dev, PCI_SUBSYSTEM_ID, &card->model );
pci_set_drvdata( pci_dev, card );
-
+
if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) {
printk( KERN_ERR "gemtek_pci: out of memory\n" );
goto err_video;
devradio->priv = card;
gemtek_pci_mute( card );
- printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
+ printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
card->chiprev, card->iobase, card->iobase + card->length - 1 );
return 0;
err_pci:
kfree( card );
- return -ENODEV;
+ return -ENODEV;
}
static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev )
kfree( card->videodev );
release_region( card->iobase, card->length );
-
+
if ( mx )
gemtek_pci_mute( card );
kfree( card );
-
+
pci_set_drvdata( pci_dev, NULL );
}
* Besides the protocol changes, this is mostly a copy of:
*
* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- *
+ *
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
#include <linux/spinlock.h>
#define CONFIG_RADIO_GEMTEK_PORT -1
#endif
-static int io = CONFIG_RADIO_GEMTEK_PORT;
+static int io = CONFIG_RADIO_GEMTEK_PORT;
static int radio_nr = -1;
static spinlock_t lock;
*/
static void gemtek_mute(struct gemtek_device *dev)
{
- if(dev->muted)
+ if(dev->muted)
return;
spin_lock(&lock);
outb(0x10, io);
freq /= 100000;
spin_lock(&lock);
-
+
/* 2 start bits */
outb_p(0x03, io);
udelay(5);
outb_p(0x07, io);
udelay(5);
- /* 28 frequency bits (lsb first) */
+ /* 28 frequency bits (lsb first) */
for (i = 0; i < 14; i++)
if (freq & (1 << i))
one();
else
zero();
- /* 36 unknown bits */
+ /* 36 unknown bits */
for (i = 0; i < 11; i++)
zero();
one();
udelay(5);
spin_unlock(&lock);
-
+
return 0;
}
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=87*16000;
v->rangehigh=108*16000;
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE;
v->volume=1;
v->step=65535;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
gemtek_mute(rt);
else
- gemtek_unmute(rt);
+ gemtek_unmute(rt);
return 0;
}
return -EINVAL;
}
- if (!request_region(io, 4, "gemtek"))
+ if (!request_region(io, 4, "gemtek"))
{
printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
return -EBUSY;
}
gemtek_radio.priv=&gemtek_unit;
-
+
if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 4);
/* this is _maybe_ unnecessary */
outb(0x01, io);
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
gemtek_unit.muted = 0;
gemtek_mute(&gemtek_unit);
* (c) 2000 A. Tlalka, atlka@pg.gda.pl
* Notes on the hardware
*
- * + Frequency control is done digitally
+ * + Frequency control is done digitally
* + No volume control - only mute/unmute - you have to use Aux line volume
* control on Maestro card to set the volume
* + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
#include <linux/mutex.h>
#include <linux/pci.h>
#include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
#define DRIVER_VERSION "0.05"
struct radio_device {
u16 io, /* base of Maestro card radio io (GPIO_DATA)*/
muted, /* VIDEO_AUDIO_MUTE */
- stereo, /* VIDEO_TUNER_STEREO_ON */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
struct mutex lock;
};
for (l=24;l--;) {
outw(STR_CLK, io); /* HI state */
udelay(2);
- if(!l)
+ if(!l)
dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
outw(0, io); /* LO state */
udelay(2);
data <<= 1; /* shift data */
rdata = inw(io);
if(!l)
- dev->stereo = rdata & STR_MOST ?
+ dev->stereo = rdata & STR_MOST ?
0 : VIDEO_TUNER_STEREO_ON;
else
if(rdata & STR_DATA)
-/*
- * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
+/*
+ * Guillemot Maxi Radio FM 2000 PCI radio card driver for Linux
* (C) 2001 Dimitromanolakis Apostolos <apdim@grecian.net>
*
* Based in the radio Maestro PCI driver. Actually it uses the same chip
* for radio but different pci controller.
*
* I didn't have any specs I reversed engineered the protocol from
- * the windows driver (radio.dll).
+ * the windows driver (radio.dll).
*
* The card uses the TEA5757 chip that includes a search function but it
- * is useless as I haven't found any way to read back the frequency. If
+ * is useless as I haven't found any way to read back the frequency. If
* anybody does please mail me.
*
* For the pdf file see:
* - tiding up
* - removed support for multiple devices as it didn't work anyway
*
- * BUGS:
+ * BUGS:
* - card unmutes if you change frequency
*
*/
#include <linux/pci.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
/* version 0.75 Sun Feb 4 22:51:27 EET 2001 */
#define DRIVER_VERSION "0.75"
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
- .ioctl = radio_ioctl,
+ .ioctl = radio_ioctl,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
{
__u16 io, /* base of radio io */
muted, /* VIDEO_AUDIO_MUTE */
- stereo, /* VIDEO_TUNER_STEREO_ON */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
tuned; /* signal strength (0 or 0xffff) */
-
+
unsigned long freq;
-
+
struct mutex lock;
} radio_unit = {0, 0, 0, 0, };
outb( power|wren|data|clk ,io); udelay(4);
outb( power|wren|data ,io); udelay(4);
}
- else
+ else
{
outb( power|wren ,io); udelay(4);
outb( power|wren|clk ,io); udelay(4);
{
unsigned long int si;
int bl;
-
+
/* TEA5757 shift register bits (see pdf) */
- outbit(0,io); // 24 search
+ outbit(0,io); // 24 search
outbit(1,io); // 23 search up/down
-
+
outbit(0,io); // 22 stereo/mono
outbit(0,io); // 21 band
outbit(0,io); // 19 port ?
outbit(0,io); // 18 port ?
-
+
outbit(0,io); // 17 search level
outbit(0,io); // 16 search level
-
+
si = 0x8000;
for(bl = 1; bl <= 16 ; bl++) { outbit(data & si,io); si >>=1; }
-
+
outb(power,io);
}
static int get_stereo(__u16 io)
-{
+{
outb(power,io); udelay(4);
return !(inb(io) & mo_st);
}
static int get_tune(__u16 io)
-{
+{
outb(power+clk,io); udelay(4);
return !(inb(io) & mo_st);
}
switch(cmd) {
case VIDIOCGCAP: {
struct video_capability *v = arg;
-
+
memset(v,0,sizeof(*v));
strcpy(v->name, "Maxi Radio FM2000 radio");
v->type=VID_TYPE_TUNER;
}
case VIDIOCGTUNER: {
struct video_tuner *v = arg;
-
+
if(v->tuner)
return -EINVAL;
-
+
card->stereo = 0xffff * get_stereo(card->io);
card->tuned = 0xffff * get_tune(card->io);
-
+
v->flags = VIDEO_TUNER_LOW | card->stereo;
v->signal = card->tuned;
-
+
strcpy(v->name, "FM");
-
+
v->rangelow = FREQ_LO;
v->rangehigh = FREQ_HI;
v->mode = VIDEO_MODE_AUTO;
-
+
return 0;
}
case VIDIOCSTUNER: {
}
case VIDIOCGFREQ: {
unsigned long *freq = arg;
-
+
*freq = card->freq;
return 0;
}
case VIDIOCSFREQ: {
unsigned long *freq = arg;
-
+
if (*freq < FREQ_LO || *freq > FREQ_HI)
return -EINVAL;
card->freq = *freq;
msleep(125);
return 0;
}
- case VIDIOCGAUDIO: {
+ case VIDIOCGAUDIO: {
struct video_audio *v = arg;
memset(v,0,sizeof(*v));
strcpy(v->name, "Radio");
v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
v->mode=VIDEO_SOUND_STEREO;
- return 0;
+ return 0;
}
-
+
case VIDIOCSAUDIO: {
struct video_audio *v = arg;
-
+
if(v->audio)
return -EINVAL;
card->muted = v->flags & VIDEO_AUDIO_MUTE;
}
case VIDIOCGUNIT: {
struct video_unit *v = arg;
-
+
v->video=VIDEO_NO_UNIT;
v->vbi=VIDEO_NO_UNIT;
v->radio=dev->minor;
v->audio=0;
v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return 0;
}
default: return -ENOIOCTLCMD;
}
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);
static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
if(!request_region(pci_resource_start(pdev, 0),
- pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
- printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
- goto err_out;
+ pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) {
+ printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n");
+ goto err_out;
}
if (pci_enable_device(pdev))
- goto err_out_free_region;
+ goto err_out_free_region;
radio_unit.io = pci_resource_start(pdev, 0);
mutex_init(&radio_unit.lock);
maxiradio_radio.priv = &radio_unit;
if(video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) {
- printk("radio-maxiradio: can't register device!");
- goto err_out_free_region;
+ printk("radio-maxiradio: can't register device!");
+ goto err_out_free_region;
}
printk(KERN_INFO "radio-maxiradio: version "
/* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
- *
+ *
* Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_RTRACK2_PORT */
#include <linux/spinlock.h>
#define CONFIG_RADIO_RTRACK2_PORT -1
#endif
-static int io = CONFIG_RADIO_RTRACK2_PORT;
+static int io = CONFIG_RADIO_RTRACK2_PORT;
static int radio_nr = -1;
static spinlock_t lock;
static void rt_mute(struct rt_device *dev)
{
- if(dev->muted)
+ if(dev->muted)
return;
spin_lock(&lock);
outb(1, io);
static void zero(void)
{
- outb_p(1, io);
+ outb_p(1, io);
outb_p(3, io);
outb_p(1, io);
}
static void one(void)
{
- outb_p(5, io);
+ outb_p(5, io);
outb_p(7, io);
outb_p(5, io);
}
int i;
freq = freq / 200 + 856;
-
+
spin_lock(&lock);
outb_p(0xc8, io);
outb_p(0xc8, io);
if (!dev->muted)
outb_p(0, io);
-
+
spin_unlock(&lock);
return 0;
}
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=88*16000;
v->rangehigh=108*16000;
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE;
v->volume=1;
v->step=65535;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
rt_mute(rt);
else
- rt_unmute(rt);
+ rt_unmute(rt);
return 0;
}
printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n");
return -EINVAL;
}
- if (!request_region(io, 4, "rtrack2"))
+ if (!request_region(io, 4, "rtrack2"))
{
printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io);
return -EBUSY;
rtrack2_radio.priv=&rtrack2_unit;
- spin_lock_init(&lock);
+ spin_lock_init(&lock);
if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io, 4);
return -EINVAL;
}
-
+
printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n");
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
outb(1, io);
rtrack2_unit.muted = 1;
* Frequency control is done digitally -- ie out(port,encodefreq(95.8));
* No volume control - only mute/unmute - you have to use line volume
* control on SB-part of SF16FMI
- *
+ *
*/
#include <linux/kernel.h> /* __setup */
#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/isapnp.h>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
struct fmi_device
{
int port;
- int curvol; /* 1 or 0 */
- unsigned long curfreq; /* freq in kHz */
- __u32 flags;
+ int curvol; /* 1 or 0 */
+ unsigned long curfreq; /* freq in kHz */
+ __u32 flags;
};
-static int io = -1;
+static int io = -1;
static int radio_nr = -1;
static struct pnp_dev *dev = NULL;
static struct mutex lock;
/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
/* It is only useful to give freq in intervall of 800 (=0.05Mhz),
- * other bits will be truncated, e.g 92.7400016 -> 92.7, but
+ * other bits will be truncated, e.g 92.7400016 -> 92.7, but
* 92.7400017 -> 92.75
*/
#define RSF16_ENCODE(x) ((x)/800+214)
static void outbits(int bits, unsigned int data, int port)
{
while(bits--) {
- if(data & 1) {
+ if(data & 1) {
outb(5, port);
udelay(6);
outb(7, port);
int res;
int myport = dev->port;
-
+
mutex_lock(&lock);
val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */
outb(val, myport);
msleep(143); /* was schedule_timeout(HZ/7) */
res = (int)inb(myport+1);
outb(val, myport);
-
+
mutex_unlock(&lock);
return (res & 2) ? 0 : 0xFFFF;
}
{
struct video_device *dev = video_devdata(file);
struct fmi_device *fmi=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
return -EINVAL;
/*rounding in steps of 800 to match th freq
that will be used */
- fmi->curfreq = (*freq/800)*800;
+ fmi->curfreq = (*freq/800)*800;
fmi_setfreq(fmi);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0,sizeof(*v));
v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
strcpy(v->name, "Radio");
v->mode=VIDEO_SOUND_STEREO;
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
if(v->audio)
return -EINVAL;
fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
- fmi->curvol ?
+ fmi->curvol ?
fmi_unmute(fmi->port) : fmi_mute(fmi->port);
return 0;
}
- case VIDIOCGUNIT:
+ case VIDIOCGUNIT:
{
- struct video_unit *v = arg;
+ struct video_unit *v = arg;
v->video=VIDEO_NO_UNIT;
v->vbi=VIDEO_NO_UNIT;
v->radio=dev->minor;
v->audio=0; /* How do we find out this??? */
v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return 0;
}
default:
return -ENOIOCTLCMD;
fmi_unit.curfreq = 0;
fmi_unit.flags = VIDEO_TUNER_LOW;
fmi_radio.priv = &fmi_unit;
-
+
mutex_init(&lock);
-
+
if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) {
release_region(io, 2);
return -EINVAL;
}
-
+
printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io);
/* mute card - prevents noisy bootups */
fmi_mute(io);
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
static struct mutex lock;
}
static int fmr2_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+ unsigned int cmd, void *arg)
{
struct video_device *dev = video_devdata(file);
struct fmr2_device *fmr2 = dev->priv;
}
static int fmr2_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+ unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
}
* (c) 1999 R. Offermanns (rolf@offermanns.de)
* based on the aimslab radio driver from M. Kirkwood
* many thanks to Michael Becker and Friedhelm Birth (from TerraTec)
- *
+ *
*
* History:
* 1999-05-21 First preview release
- *
+ *
* Notes on the hardware:
* There are two "main" chips on the card:
* - Philips OM5610 (http://www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
* (as soon i have understand how to get started :)
* If you can help me out with that, please contact me!!
*
- *
+ *
*/
#include <linux/module.h> /* Modules */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TERRATEC_PORT */
#include <linux/spinlock.h>
#define WRT_EN 0x10
/*******************************************************************/
-static int io = CONFIG_RADIO_TERRATEC_PORT;
+static int io = CONFIG_RADIO_TERRATEC_PORT;
static int radio_nr = -1;
static spinlock_t lock;
static int tt_setvol(struct tt_device *dev, int vol)
{
-
+
// printk(KERN_ERR "setvol called, vol = %d\n", vol);
if(vol == dev->curvol) { /* requested volume = current */
if (dev->muted) { /* user is unmuting the card */
dev->muted = 0;
cardWriteVol(vol); /* enable card */
- }
-
+ }
+
return 0;
}
}
dev->muted = 0;
-
+
cardWriteVol(vol);
-
+
dev->curvol = vol;
return 0;
/* many more or less strange things are going on here, but hey, it works :) */
static int tt_setfreq(struct tt_device *dev, unsigned long freq1)
-{
+{
int freq;
int i;
int p;
int temp;
long rest;
-
+
unsigned char buffer[25]; /* we have to bit shift 25 registers */
freq = freq1/160; /* convert the freq. to a nice to handle value */
for(i=24;i>-1;i--)
{
if (rest%temp == rest)
buffer[i] = 0;
- else
+ else
{
- buffer[i] = 1;
+ buffer[i] = 1;
rest = rest-temp;
}
i--;
}
spin_lock(&lock);
-
+
for (i=24;i>-1;i--) /* bit shift the values to the radiocard */
{
- if (buffer[i]==1)
+ if (buffer[i]==1)
{
outb(WRT_EN|DATA, BASEPORT);
outb(WRT_EN|DATA|CLK_ON , BASEPORT);
outb(WRT_EN|0x00|CLK_ON , BASEPORT);
}
}
- outb(0x00, BASEPORT);
-
+ outb(0x00, BASEPORT);
+
spin_unlock(&lock);
-
- return 0;
+
+ return 0;
}
static int tt_getsigstr(struct tt_device *dev) /* TODO */
{
struct video_device *dev = video_devdata(file);
struct tt_device *tt=dev->priv;
-
+
switch(cmd)
{
case VIDIOCGCAP:
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
v->volume=tt->curvol * 6554;
v->step=6554;
strcpy(v->name, "Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
+ if(v->flags&VIDEO_AUDIO_MUTE)
tt_mute(tt);
else
tt_setvol(tt,v->volume/6554);
printk(KERN_ERR "You must set an I/O address with io=0x???\n");
return -EINVAL;
}
- if (!request_region(io, 2, "terratec"))
+ if (!request_region(io, 2, "terratec"))
{
printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io);
return -EBUSY;
}
terratec_radio.priv=&terratec_unit;
-
+
spin_lock_init(&lock);
-
+
if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1)
{
release_region(io,2);
return -EINVAL;
}
-
+
printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n");
- /* mute card - prevents noisy bootups */
+ /* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
cardWriteVol(0);
{
video_unregister_device(&terratec_radio);
release_region(io,2);
- printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
+ printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n");
}
module_init(terratec_init);
-/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
+/* radio-trust.c - Trust FM Radio card driver for Linux 2.2
* by Eric Lammerts <eric@scintilla.utwente.nl>
*
* Based on radio-aztech.c. Original notes:
*
- * Adapted to support the Video for Linux API by
+ * Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
* Quay Ly
* Donald Song
- * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
+ * Jason Lewis (jlewis@twilight.vtc.vsc.edu)
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
#include <asm/io.h>
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
#define CONFIG_RADIO_TRUST_PORT -1
#endif
-static int io = CONFIG_RADIO_TRUST_PORT;
+static int io = CONFIG_RADIO_TRUST_PORT;
static int radio_nr = -1;
static int ioval = 0xf;
static __u16 curvol;
static int tr_getsigstr(void)
{
int i, v;
-
+
for(i = 0, v = 0; i < 100; i++) v |= inb(io);
return (v & 1)? 0 : 0xffff;
}
{
struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if(v->tuner) /* Only 1 tuner */
return -EINVAL;
v->rangelow = 87500 * 16;
return 0;
}
case VIDIOCGAUDIO:
- {
+ {
struct video_audio *v = arg;
memset(v,0, sizeof(*v));
v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
+ VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
v->volume = curvol * 2048;
v->step = 2048;
v->bass = curbass * 4370;
v->treble = curtreble * 4370;
-
+
strcpy(v->name, "Trust FM Radio");
- return 0;
+ return 0;
}
case VIDIOCSAUDIO:
{
struct video_audio *v = arg;
- if(v->audio)
+ if(v->audio)
return -EINVAL;
- tr_setvol(v->volume);
+ tr_setvol(v->volume);
tr_setbass(v->bass);
tr_settreble(v->treble);
tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */
write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */
- tr_setvol(0x8000);
+ tr_setvol(0x8000);
tr_setbass(0x8000);
tr_settreble(0x8000);
tr_setstereo(1);
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_TYPHOON_* */
#define BANNER "Typhoon Radio Card driver v0.1\n"
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
- typhoon_get_info))
- printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
+ typhoon_get_info))
+ printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
#endif
return 0;
/* zoltrix radio plus driver for Linux radio support
* (c) 1998 C. van Schaik <carl@leg.uct.ac.za>
*
- * BUGS
+ * BUGS
* Due to the inconsistency in reading from the signal flags
* it is difficult to get an accurate tuned signal.
*
*
* 1999-05-06 - (C. van Schaik)
* - Make signal strength and stereo scans
- * kinder to cpu while in delay
+ * kinder to cpu while in delay
* 1999-01-05 - (C. van Schaik)
* - Changed tuning to 1/160Mhz accuracy
* - Added stereo support
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/videodev.h> /* kernel radio structs */
+#include <media/v4l2-common.h>
#include <linux/config.h> /* CONFIG_RADIO_ZOLTRIX_PORT */
#ifndef CONFIG_RADIO_ZOLTRIX_PORT
i = 45;
mutex_lock(&dev->lock);
-
+
outb(0, io);
outb(0, io);
inb(io + 3); /* Zoltrix needs to be read to confirm */
udelay(1000);
inb(io+2);
- udelay(1000);
-
+ udelay(1000);
+
if (dev->muted)
{
outb(0, io);
inb(io + 3);
udelay(1000);
}
-
+
mutex_unlock(&dev->lock);
-
+
if(!dev->muted)
{
- zol_setvol(dev, dev->curvol);
+ zol_setvol(dev, dev->curvol);
}
return 0;
}
b = inb(io);
mutex_unlock(&dev->lock);
-
+
if (a != b)
return (0);
- if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
+ if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */
|| (a == 0xef)) /* with a binary scanner on the card io */
return (1);
- return (0);
+ return (0);
}
static int zol_is_stereo (struct zol_device *dev)
int x1, x2;
mutex_lock(&dev->lock);
-
+
outb(0x00, io);
outb(dev->curvol, io);
msleep(20);
x2 = inb(io);
mutex_unlock(&dev->lock);
-
+
if ((x1 == x2) && (x1 == 0xcf))
return 1;
return 0;
case VIDIOCGTUNER:
{
struct video_tuner *v = arg;
- if (v->tuner)
+ if (v->tuner)
return -EINVAL;
strcpy(v->name, "FM");
v->rangelow = (int) (88.0 * 16000);
printk(KERN_INFO "Zoltrix Radio Plus card driver.\n");
mutex_init(&zoltrix_unit.lock);
-
+
/* mute card - prevents noisy bootups */
/* this ensures that the volume is all the way down */
support for the Linux Media Labs LML33R10 MJPEG capture/playback
card.
+config VIDEO_ZORAN_AVS6EYES
+ tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
+ depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+ help
+ Support for the AverMedia 6 Eyes video surveillance card.
+
config VIDEO_ZR36120
tristate "Zoran ZR36120/36125 Video For Linux"
depends on PCI && I2C && VIDEO_V4L1 && BROKEN
source "drivers/media/video/cx88/Kconfig"
-config VIDEO_OVCAMCHIP
- tristate "OmniVision Camera Chip support"
- depends on I2C && VIDEO_V4L1
- ---help---
- Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
- This driver is intended to be used with the ov511 and w9968cf USB
- camera drivers.
-
- To compile this driver as a module, choose M here: the
- module will be called ovcamchip.
-
config VIDEO_M32R_AR
tristate "AR devices"
depends on M32R && VIDEO_V4L1
To compile this driver as a module, choose M here: the
module will be called cs53l32a.
+config VIDEO_TLV320AIC23B
+ tristate "Texas Instruments TLV320AIC23B audio codec"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Texas Instruments TLV320AIC23B audio codec.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tlv320aic23b.
+
config VIDEO_WM8775
tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
depends on VIDEO_DEV && I2C && EXPERIMENTAL
source "drivers/media/video/cx25840/Kconfig"
config VIDEO_SAA711X
- tristate "Philips SAA7113/4/5 video decoders (OBSOLETED)"
- depends on VIDEO_V4L1 && I2C && EXPERIMENTAL
+ tristate "Philips SAA7113/4/5 video decoders"
+ depends on VIDEO_DEV && I2C && EXPERIMENTAL
---help---
- Old support for the Philips SAA7113/4 video decoders.
+ Support for the Philips SAA7113/4/5 video decoders.
To compile this driver as a module, choose M here: the
module will be called saa7115.
source "drivers/media/video/et61x251/Kconfig"
+config VIDEO_OVCAMCHIP
+ tristate "OmniVision Camera Chip support"
+ depends on I2C && VIDEO_V4L1
+ ---help---
+ Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
+ This driver is intended to be used with the ov511 and w9968cf USB
+ camera drivers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ovcamchip.
+
+config USB_W9968CF
+ tristate "USB W996[87]CF JPEG Dual Mode Camera support"
+ depends on USB && VIDEO_V4L1 && I2C
+ select VIDEO_OVCAMCHIP
+ ---help---
+ Say Y here if you want support for cameras based on OV681 or
+ Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
+
+ This driver has an optional plugin, which is distributed as a
+ separate module only (released under GPL). It allows to use higher
+ resolutions and framerates, but cannot be included in the official
+ Linux kernel for performance purposes.
+
+ See <file:Documentation/video4linux/w9968cf.txt> for more info.
+
+ To compile this driver as a module, choose M here: the
+ module will be called w9968cf.
+
config USB_OV511
tristate "USB OV511 Camera support"
depends on USB && VIDEO_V4L1
To compile this driver as a module, choose M here: the
module will be called stv680.
-config USB_W9968CF
- tristate "USB W996[87]CF JPEG Dual Mode Camera support"
- depends on USB && VIDEO_V4L1 && I2C
- select VIDEO_OVCAMCHIP
- ---help---
- Say Y here if you want support for cameras based on OV681 or
- Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
- This driver has an optional plugin, which is distributed as a
- separate module only (released under GPL). It allows to use higher
- resolutions and framerates, but cannot be included in the official
- Linux kernel for performance purposes.
-
- See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called w9968cf.
-
source "drivers/media/video/zc0301/Kconfig"
source "drivers/media/video/pwc/Kconfig"
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
tuner-objs := tuner-core.o tuner-types.o tuner-simple.o \
- mt20xx.o tda8290.o tea5767.o
+ mt20xx.o tda8290.o tea5767.o tda9887.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
zr36016.o
obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
+obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
+obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o
obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
-obj-$(CONFIG_VIDEO_TUNER) += tuner.o tda9887.o
+obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_BUF) += video-buf.o
obj-$(CONFIG_VIDEO_BUF_DVB) += video-buf-dvb.o
obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
ar_outl(0x0300, PLDI2CMOD); /* I2CMOD ACK/8b-data/7b-addr/auto */
ar_outl(0x1, PLDI2CACK); /* I2CACK ACK */
- /* I2C CLK */
+ /* I2C CLK */
/* 50MH-100k */
if (freq == 75) {
ar_outl(369, PLDI2CFREQ); /* BCLK = 75MHz */
--- /dev/null
+/*
+ bt866 - BT866 Digital Video Encoder (Rockwell Part)
+
+ Copyright (C) 1999 Mike Bernson <mike@mlb.org>
+ Copyright (C) 1998 Dave Perks <dperks@ibm.net>
+
+ Modifications for LML33/DC10plus unified driver
+ Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx>
+
+ This code was modify/ported from the saa7111 driver written
+ by Dave Perks.
+
+ This code was adapted for the bt866 by Christer Weinigel and ported
+ to 2.6 by Martin Samuelsson.
+
+ 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 <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/major.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev.h>
+#include <asm/uaccess.h>
+
+#include <linux/video_encoder.h>
+
+MODULE_LICENSE("GPL");
+
+#define BT866_DEVNAME "bt866"
+#define I2C_BT866 0x88
+
+MODULE_LICENSE("GPL");
+
+#define DEBUG(x) /* Debug driver */
+
+/* ----------------------------------------------------------------------- */
+
+struct bt866 {
+ struct i2c_client *i2c;
+ int addr;
+ unsigned char reg[128];
+
+ int norm;
+ int enable;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+};
+
+static int bt866_write(struct bt866 *dev,
+ unsigned char subaddr, unsigned char data);
+
+static int bt866_do_command(struct bt866 *encoder,
+ unsigned int cmd, void *arg)
+{
+ switch (cmd) {
+ case ENCODER_GET_CAPABILITIES:
+ {
+ struct video_encoder_capability *cap = arg;
+
+ DEBUG(printk
+ (KERN_INFO "%s: get capabilities\n",
+ encoder->i2c->name));
+
+ cap->flags
+ = VIDEO_ENCODER_PAL
+ | VIDEO_ENCODER_NTSC
+ | VIDEO_ENCODER_CCIR;
+ cap->inputs = 2;
+ cap->outputs = 1;
+ }
+ break;
+
+ case ENCODER_SET_NORM:
+ {
+ int *iarg = arg;
+
+ DEBUG(printk(KERN_INFO "%s: set norm %d\n",
+ encoder->i2c->name, *iarg));
+
+ switch (*iarg) {
+
+ case VIDEO_MODE_NTSC:
+ break;
+
+ case VIDEO_MODE_PAL:
+ break;
+
+ default:
+ return -EINVAL;
+
+ }
+ encoder->norm = *iarg;
+ }
+ break;
+
+ case ENCODER_SET_INPUT:
+ {
+ int *iarg = arg;
+ static const __u8 init[] = {
+ 0xc8, 0xcc, /* CRSCALE */
+ 0xca, 0x91, /* CBSCALE */
+ 0xcc, 0x24, /* YC16 | OSDNUM */
+ 0xda, 0x00, /* */
+ 0xdc, 0x24, /* SETMODE | PAL */
+ 0xde, 0x02, /* EACTIVE */
+
+ /* overlay colors */
+ 0x70, 0xEB, 0x90, 0x80, 0xB0, 0x80, /* white */
+ 0x72, 0xA2, 0x92, 0x8E, 0xB2, 0x2C, /* yellow */
+ 0x74, 0x83, 0x94, 0x2C, 0xB4, 0x9C, /* cyan */
+ 0x76, 0x70, 0x96, 0x3A, 0xB6, 0x48, /* green */
+ 0x78, 0x54, 0x98, 0xC6, 0xB8, 0xB8, /* magenta */
+ 0x7A, 0x41, 0x9A, 0xD4, 0xBA, 0x64, /* red */
+ 0x7C, 0x23, 0x9C, 0x72, 0xBC, 0xD4, /* blue */
+ 0x7E, 0x10, 0x9E, 0x80, 0xBE, 0x80, /* black */
+
+ 0x60, 0xEB, 0x80, 0x80, 0xc0, 0x80, /* white */
+ 0x62, 0xA2, 0x82, 0x8E, 0xc2, 0x2C, /* yellow */
+ 0x64, 0x83, 0x84, 0x2C, 0xc4, 0x9C, /* cyan */
+ 0x66, 0x70, 0x86, 0x3A, 0xc6, 0x48, /* green */
+ 0x68, 0x54, 0x88, 0xC6, 0xc8, 0xB8, /* magenta */
+ 0x6A, 0x41, 0x8A, 0xD4, 0xcA, 0x64, /* red */
+ 0x6C, 0x23, 0x8C, 0x72, 0xcC, 0xD4, /* blue */
+ 0x6E, 0x10, 0x8E, 0x80, 0xcE, 0x80, /* black */
+ };
+ int i;
+ u8 val;
+
+ for (i = 0; i < ARRAY_SIZE(init) / 2; i += 2)
+ bt866_write(encoder, init[i], init[i+1]);
+
+ val = encoder->reg[0xdc];
+
+ if (*iarg == 0)
+ val |= 0x40; /* CBSWAP */
+ else
+ val &= ~0x40; /* !CBSWAP */
+
+ bt866_write(encoder, 0xdc, val);
+
+ val = encoder->reg[0xcc];
+ if (*iarg == 2)
+ val |= 0x01; /* OSDBAR */
+ else
+ val &= ~0x01; /* !OSDBAR */
+ bt866_write(encoder, 0xcc, val);
+
+ DEBUG(printk(KERN_INFO "%s: set input %d\n",
+ encoder->i2c->name, *iarg));
+
+ switch (*iarg) {
+ case 0:
+ break;
+ case 1:
+ break;
+ default:
+ return -EINVAL;
+
+ }
+ }
+ break;
+
+ case ENCODER_SET_OUTPUT:
+ {
+ int *iarg = arg;
+
+ DEBUG(printk(KERN_INFO "%s: set output %d\n",
+ encoder->i2c->name, *iarg));
+
+ /* not much choice of outputs */
+ if (*iarg != 0)
+ return -EINVAL;
+ }
+ break;
+
+ case ENCODER_ENABLE_OUTPUT:
+ {
+ int *iarg = arg;
+ encoder->enable = !!*iarg;
+
+ DEBUG(printk
+ (KERN_INFO "%s: enable output %d\n",
+ encoder->i2c->name, encoder->enable));
+ }
+ break;
+
+ case 4711:
+ {
+ int *iarg = arg;
+ __u8 val;
+
+ printk("bt866: square = %d\n", *iarg);
+
+ val = encoder->reg[0xdc];
+ if (*iarg)
+ val |= 1; /* SQUARE */
+ else
+ val &= ~1; /* !SQUARE */
+ bt866_write(encoder, 0xdc, val);
+ break;
+ }
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int bt866_write(struct bt866 *encoder,
+ unsigned char subaddr, unsigned char data)
+{
+ unsigned char buffer[2];
+ int err;
+
+ buffer[0] = subaddr;
+ buffer[1] = data;
+
+ encoder->reg[subaddr] = data;
+
+ DEBUG(printk
+ ("%s: write 0x%02X = 0x%02X\n",
+ encoder->i2c->name, subaddr, data));
+
+ for (err = 0; err < 3;) {
+ if (i2c_master_send(encoder->i2c, buffer, 2) == 2)
+ break;
+ err++;
+ printk(KERN_WARNING "%s: I/O error #%d "
+ "(write 0x%02x/0x%02x)\n",
+ encoder->i2c->name, err, encoder->addr, subaddr);
+ schedule_timeout_interruptible(HZ/10);
+ }
+ if (err == 3) {
+ printk(KERN_WARNING "%s: giving up\n",
+ encoder->i2c->name);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter);
+static int bt866_detach(struct i2c_client *client);
+static int bt866_command(struct i2c_client *client,
+ unsigned int cmd, void *arg);
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_BT866>>1, I2C_CLIENT_END};
+static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+
+static struct i2c_client_address_data addr_data = {
+ normal_i2c,
+ probe,
+ ignore,
+};
+
+static struct i2c_driver i2c_driver_bt866 = {
+ .driver.name = BT866_DEVNAME,
+ .id = I2C_DRIVERID_BT866,
+ .attach_adapter = bt866_attach,
+ .detach_client = bt866_detach,
+ .command = bt866_command
+};
+
+
+static struct i2c_client bt866_client_tmpl =
+{
+ .name = "(nil)",
+ .addr = 0,
+ .adapter = NULL,
+ .driver = &i2c_driver_bt866,
+ .usage_count = 0
+};
+
+static int bt866_found_proc(struct i2c_adapter *adapter,
+ int addr, int kind)
+{
+ struct bt866 *encoder;
+ struct i2c_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &bt866_client_tmpl, sizeof(*client));
+
+ encoder = kzalloc(sizeof(*encoder), GFP_KERNEL);
+ if (encoder == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, encoder);
+ client->adapter = adapter;
+ client->addr = addr;
+ sprintf(client->name, "%s-%02x", BT866_DEVNAME, adapter->id);
+
+ encoder->i2c = client;
+ encoder->addr = addr;
+ //encoder->encoder_type = ENCODER_TYPE_UNKNOWN;
+
+ /* initialize */
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int bt866_attach(struct i2c_adapter *adapter)
+{
+ if (adapter->id == I2C_HW_B_ZR36067)
+ return i2c_probe(adapter, &addr_data, bt866_found_proc);
+ return 0;
+}
+
+static int bt866_detach(struct i2c_client *client)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+
+ i2c_detach_client(client);
+ kfree(encoder);
+ kfree(client);
+
+ return 0;
+}
+
+static int bt866_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct bt866 *encoder = i2c_get_clientdata(client);
+ return bt866_do_command(encoder, cmd, arg);
+}
+
+static int __devinit bt866_init(void)
+{
+ i2c_add_driver(&i2c_driver_bt866);
+ return 0;
+}
+
+static void __devexit bt866_exit(void)
+{
+ i2c_del_driver(&i2c_driver_bt866);
+}
+
+module_init(bt866_init);
+module_exit(bt866_exit);
{ 0x41a0a051, BTTV_BOARD_FLYVIDEO_98FM, "Lifeview FlyVideo 98 LR50 Rev Q" },
{ 0x18501f7f, BTTV_BOARD_FLYVIDEO_98, "Lifeview Flyvideo 98" },
- { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
+ { 0x010115cb, BTTV_BOARD_GMV1, "AG GMV1" },
{ 0x010114c7, BTTV_BOARD_MODTEC_205, "Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV" },
{ 0x10b42636, BTTV_BOARD_HAUPPAUGE878, "STB ???" },
{ 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" },
{ 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" },
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
+ { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
{ 0, -1, NULL }
};
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2x0] = {
- .name = "Osprey 210/220", /* 0x1(A|B)-04C0-C1 */
+ .name = "Osprey 210/220/230", /* 0x1(A|B)-04C0-C1 */
.video_inputs = 2,
.audio_inputs = 1,
.tuner = -1,
/* Michael Krufky <mkrufky@m1k.net> */
.name = "DViCO FusionHDTV 5 Lite",
.tuner = 0,
- .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.video_inputs = 3,
},
/* ---- card 0x88---------------------------------- */
[BTTV_BOARD_ACORP_Y878F] = {
- /* Mauro Carvalho Chehab <mchehab@brturbo.com.br> */
+ /* Mauro Carvalho Chehab <mchehab@infradead.org> */
.name = "Acorp Y878F",
.video_inputs = 3,
.audio_inputs = 1,
break;
case 0x0060:
case 0x0070:
+ case 0x00A0:
btv->c.type = BTTV_BOARD_OSPREY2x0;
/* enable output on select control lines */
gpio_inout(0xffffff,0x000303);
return 0;
}
-void bttv_gpio_irq(struct bttv_core *core)
-{
- struct bttv_sub_driver *drv;
- struct bttv_sub_device *dev;
- struct list_head *item;
-
- list_for_each(item,&core->subs) {
- dev = list_entry(item,struct bttv_sub_device,list);
- drv = to_bttv_sub_drv(dev->dev.driver);
- if (drv && drv->gpio_irq)
- drv->gpio_irq(dev);
- }
-}
-
/* ----------------------------------------------------------------------- */
/* external: sub-driver register/unregister */
if (ir->rc5_gpio) {
u32 gpio;
- /* enable remote irq */
+ /* enable remote irq */
bttv_gpio_inout(&btv->c, (1 << 4), 1 << 4);
gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
char wanted[BUS_ID_SIZE];
int (*probe)(struct bttv_sub_device *sub);
void (*remove)(struct bttv_sub_device *sub);
- void (*gpio_irq)(struct bttv_sub_device *sub);
};
#define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv)
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/mutex.h>
extern struct bus_type bttv_sub_bus_type;
int bttv_sub_add_device(struct bttv_core *core, char *name);
int bttv_sub_del_devices(struct bttv_core *core);
-void bttv_gpio_irq(struct bttv_core *core);
/* ---------------------------------------------------------- */
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
{
struct video_picture *p = arg;
if(p->palette!=VIDEO_PALETTE_GREY)
- return -EINVAL;
+ return -EINVAL;
if(p->depth!=4 && p->depth!=6)
return -EINVAL;
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include "cpia.h"
-#ifdef CONFIG_VIDEO_CPIA_PP
-extern int cpia_pp_init(void);
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
-extern int cpia_usb_init(void);
-#endif
-
static int video_nr = -1;
#ifdef MODULE
static unsigned short colorspace_conv;
module_param(colorspace_conv, ushort, 0444);
MODULE_PARM_DESC(colorspace_conv,
- " Colorspace conversion:"
- "\n 0 = disable, 1 = enable"
- "\n Default value is 0"
- );
+ " Colorspace conversion:"
+ "\n 0 = disable, 1 = enable"
+ "\n Default value is 0"
+ );
#define ABOUT "V4L-Driver for Vision CPiA based cameras"
proc_cpia_create();
#endif
-#ifdef CONFIG_VIDEO_CPIA_PP
- cpia_pp_init();
-#endif
-#ifdef CONFIG_VIDEO_CPIA_USB
- cpia_usb_init();
-#endif
-
return 0;
}
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
struct cam_data {
struct list_head cam_data_list;
- struct mutex busy_lock; /* guard against SMP multithreading */
+ struct mutex busy_lock; /* guard against SMP multithreading */
struct cpia_camera_ops *ops; /* lowlevel driver operations */
void *lowlevel_data; /* private data for lowlevel driver */
u8 *raw_image; /* buffer for raw image data */
#include <linux/version.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/poll.h>
cpia2_free_buffers(cam);
if (!cam->present) {
video_unregister_device(dev);
+ mutex_unlock(&cam->busy_lock);
kfree(cam);
+ return 0;
}
}
} else {
if(cam->params.flicker_control.cam_register &
CPIA2_VP_FLICKER_MODES_50HZ) {
- mode = FLICKER_50;
+ mode = FLICKER_50;
} else {
- mode = FLICKER_60;
+ mode = FLICKER_60;
}
}
for(i=0; i<NUM_FLICKER_CONTROLS; i++) {
.detach = cpia_pp_detach,
};
-int cpia_pp_init(void)
+static int cpia_pp_init(void)
{
printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
static int __init cpia_pp_setup(char *str)
{
+ int err;
+
if (!strncmp(str, "parport", 7)) {
int n = simple_strtoul(str + 7, NULL, 10);
if (parport_ptr < PARPORT_MAX) {
parport_nr[parport_ptr++] = PPCPIA_PARPORT_NONE;
}
+ err=cpia_pp_init();
+ if (err)
+ return err;
+
return 1;
}
return 0;
}
-int cpia_usb_init(void)
-{
- /* return -ENODEV; */
- return 0;
-}
-
/* Probing and initializing */
static int cpia_probe(struct usb_interface *intf,
--- /dev/null
+/*
+ * cx2341x - generic code for cx23415/6 based devices
+ *
+ * Copyright (C) 2006 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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 <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+
+#include <media/tuner.h>
+#include <media/cx2341x.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("cx23415/6 driver");
+MODULE_AUTHOR("Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+const u32 cx2341x_mpeg_ctrls[] = {
+ V4L2_CID_MPEG_CLASS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_CID_MPEG_AUDIO_MODE,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ 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,
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ 0
+};
+
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_get_ctrl(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ ctrl->value = params->audio_sampling_freq;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ ctrl->value = params->audio_encoding;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ ctrl->value = params->audio_l2_bitrate;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ ctrl->value = params->audio_mode;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ ctrl->value = params->audio_mode_extension;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ ctrl->value = params->audio_emphasis;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ ctrl->value = params->audio_crc;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ ctrl->value = params->video_encoding;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ ctrl->value = params->video_aspect;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ ctrl->value = params->video_b_frames;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = params->video_gop_size;
+ break;
+ 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;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = params->video_bitrate;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ ctrl->value = params->video_bitrate_peak;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ ctrl->value = params->video_temporal_decimation;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = params->stream_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ ctrl->value = params->video_spatial_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ ctrl->value = params->video_spatial_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_luma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ ctrl->value = params->video_chroma_spatial_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ ctrl->value = params->video_temporal_filter_mode;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ ctrl->value = params->video_temporal_filter;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ ctrl->value = params->video_median_filter_type;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_luma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_luma_median_filter_bottom;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ ctrl->value = params->video_chroma_median_filter_top;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ ctrl->value = params->video_chroma_median_filter_bottom;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Map the control ID to the correct field in the cx2341x_mpeg_params
+ struct. Return -EINVAL if the ID is unknown, else return 0. */
+static int cx2341x_set_ctrl(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_control *ctrl)
+{
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ params->audio_sampling_freq = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ params->audio_encoding = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ params->audio_l2_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ params->audio_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ params->audio_mode_extension = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ params->audio_emphasis = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ params->audio_crc = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ params->video_aspect = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+ int b = ctrl->value + 1;
+ int gop = params->video_gop_size;
+ params->video_b_frames = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ break;
+ }
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: {
+ int b = params->video_b_frames + 1;
+ int gop = ctrl->value;
+ params->video_gop_size = b * ((gop + b - 1) / b);
+ /* Max GOP size = 34 */
+ while (params->video_gop_size > 34)
+ params->video_gop_size -= b;
+ ctrl->value = params->video_gop_size;
+ break;
+ }
+ 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 &&
+ ctrl->value != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ return -EINVAL;
+ params->video_bitrate_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ params->video_bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ params->video_bitrate_peak = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ params->video_temporal_decimation = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ params->stream_type = ctrl->value;
+ params->video_encoding =
+ (params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+ params->stream_type == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 : V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ /* MPEG-1 implies CBR */
+ params->video_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ params->video_spatial_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ params->video_spatial_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ params->video_luma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ params->video_chroma_spatial_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ params->video_temporal_filter_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ params->video_temporal_filter = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ params->video_median_filter_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ params->video_luma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ params->video_luma_median_filter_bottom = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ params->video_chroma_median_filter_top = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ params->video_chroma_median_filter_bottom = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ qctrl->flags = 0;
+ switch (qctrl->id) {
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ name = "Spatial Filter Mode";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ name = "Spatial Filter";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ name = "Spatial Luma Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ name = "Spatial Chroma Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ name = "Temporal Filter Mode";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ name = "Temporal Filter";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ name = "Median Filter Type";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ name = "Median Luma Filter Maximum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ name = "Median Luma Filter Minimum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ name = "Median Chroma Filter Maximum";
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ name = "Median Chroma Filter Minimum";
+ break;
+
+ default:
+ return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ min = 0;
+ step = 1;
+ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ snprintf(qctrl->name, sizeof(qctrl->name), name);
+ return 0;
+}
+
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params, struct v4l2_queryctrl *qctrl)
+{
+ int err;
+
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return -EINVAL;
+
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->audio_mode != V4L2_MPEG_AUDIO_MODE_JOINT_STEREO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ /* this setting is read-only for the cx2341x since the
+ V4L2_CID_MPEG_STREAM_TYPE really determines the
+ MPEG-1/2 setting */
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0)
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ err = v4l2_ctrl_query_fill_std(qctrl);
+ if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return err;
+
+ /* CX23415/6 specific */
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 1,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 15, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE, 1,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF);
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR, 1,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF);
+ if (params->video_spatial_filter_mode == V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO, 1,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ cx2341x_ctrl_query_fill(qctrl, 0, 31, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_temporal_filter_mode == V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_ctrl_query_fill(qctrl,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG, 1,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 255);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ cx2341x_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ if (params->video_median_filter_type == V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+ return 0;
+
+ default:
+ return v4l2_ctrl_query_fill_std(qctrl);
+
+ }
+}
+
+const char **cx2341x_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ "1D Vertical",
+ "2D H/V Separable",
+ "2D Symmetric non-separable",
+ NULL
+ };
+
+ static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ NULL
+ };
+
+ static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_median_filter_type_menu[] = {
+ "Off",
+ "Horizontal",
+ "Vertical",
+ "Horizontal/Vertical",
+ "Diagonal",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return NULL;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_video_spatial_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_luma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_chroma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_video_temporal_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_video_median_filter_type_menu;
+ default:
+ return v4l2_ctrl_get_menu(id);
+ }
+}
+
+static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
+{
+ params->audio_properties = (params->audio_sampling_freq << 0) |
+ ((3 - params->audio_encoding) << 2) |
+ ((1 + params->audio_l2_bitrate) << 4) |
+ (params->audio_mode << 8) |
+ (params->audio_mode_extension << 10) |
+ (((params->audio_emphasis == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17) ?
+ 3 :
+ params->audio_emphasis) << 12) |
+ (params->audio_crc << 14);
+}
+
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_controls *ctrls, int cmd)
+{
+ int err = 0;
+ int i;
+
+ if (cmd == VIDIOC_G_EXT_CTRLS) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = cx2341x_get_ctrl(params, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+ struct v4l2_queryctrl qctrl;
+ const char **menu_items = NULL;
+
+ qctrl.id = ctrl->id;
+ err = cx2341x_ctrl_query(params, &qctrl);
+ if (err)
+ break;
+ if (qctrl.type == V4L2_CTRL_TYPE_MENU)
+ menu_items = cx2341x_ctrl_get_menu(qctrl.id);
+ err = v4l2_ctrl_check(ctrl, &qctrl, menu_items);
+ if (err)
+ break;
+ err = cx2341x_set_ctrl(params, ctrl);
+ if (err)
+ break;
+ }
+ if (err == 0 && params->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ params->video_bitrate_peak < params->video_bitrate) {
+ err = -ERANGE;
+ ctrls->error_idx = ctrls->count;
+ }
+ if (err) {
+ ctrls->error_idx = i;
+ }
+ else {
+ cx2341x_calc_audio_properties(params);
+ }
+ return err;
+}
+
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
+{
+ static struct cx2341x_mpeg_params default_params = {
+ /* misc */
+ .port = CX2341X_PORT_MEMORY,
+ .width = 720,
+ .height = 480,
+ .is_50hz = 0,
+
+ /* stream */
+ .stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+
+ /* audio */
+ .audio_sampling_freq = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ .audio_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+ .audio_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_224K,
+ .audio_mode = V4L2_MPEG_AUDIO_MODE_STEREO,
+ .audio_mode_extension = V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ .audio_emphasis = V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ .audio_crc = V4L2_MPEG_AUDIO_CRC_NONE,
+
+ /* video */
+ .video_encoding = V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+ .video_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .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,
+ .video_temporal_decimation = 0,
+
+ /* encoding filters */
+ .video_spatial_filter_mode = V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ .video_spatial_filter = 0,
+ .video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ .video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ .video_temporal_filter = 0,
+ .video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ .video_luma_median_filter_top = 255,
+ .video_luma_median_filter_bottom = 0,
+ .video_chroma_median_filter_top = 255,
+ .video_chroma_median_filter_bottom = 0,
+ };
+
+ *p = default_params;
+ cx2341x_calc_audio_properties(p);
+}
+
+static int cx2341x_api(void *priv, cx2341x_mbox_func func, int cmd, int args, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i;
+
+ va_start(vargs, args);
+
+ for (i = 0; i < args; i++) {
+ data[i] = va_arg(vargs, int);
+ }
+ va_end(vargs);
+ return func(priv, cmd, args, 0, data);
+}
+
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ const struct cx2341x_mpeg_params *old, const struct cx2341x_mpeg_params *new)
+{
+ static int mpeg_stream_type[] = {
+ 0, /* MPEG-2 PS */
+ 1, /* MPEG-2 TS */
+ 2, /* MPEG-1 SS */
+ 14, /* DVD */
+ 11, /* VCD */
+ 12, /* SVCD */
+ };
+
+ int err = 0;
+
+ cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
+
+ if (old == NULL || old->is_50hz != new->is_50hz) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz);
+ if (err) return err;
+ }
+
+ if (old == NULL || old->width != new->width || old->height != new->height ||
+ old->video_encoding != new->video_encoding) {
+ u16 w = new->width;
+ u16 h = new->height;
+
+ if (new->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ w /= 2;
+ h /= 2;
+ }
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+ if (err) return err;
+ }
+
+ if (old == NULL || old->stream_type != new->stream_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_aspect != new->video_aspect) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_b_frames != new->video_b_frames ||
+ old->video_gop_size != new->video_gop_size) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ new->video_gop_size, new->video_b_frames + 1);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_gop_closure != new->video_gop_closure) {
+ 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;
+ }
+ if (old == NULL || old->video_bitrate_mode != new->video_bitrate_mode ||
+ old->video_bitrate != new->video_bitrate ||
+ old->video_bitrate_peak != new->video_bitrate_peak) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5,
+ new->video_bitrate_mode, new->video_bitrate,
+ new->video_bitrate_peak / 400, 0, 0);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_spatial_filter_mode != new->video_spatial_filter_mode ||
+ old->video_temporal_filter_mode != new->video_temporal_filter_mode ||
+ old->video_median_filter_type != new->video_median_filter_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+ new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1),
+ new->video_median_filter_type);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_luma_median_filter_bottom != new->video_luma_median_filter_bottom ||
+ old->video_luma_median_filter_top != new->video_luma_median_filter_top ||
+ old->video_chroma_median_filter_bottom != new->video_chroma_median_filter_bottom ||
+ old->video_chroma_median_filter_top != new->video_chroma_median_filter_top) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ new->video_luma_median_filter_bottom,
+ new->video_luma_median_filter_top,
+ new->video_chroma_median_filter_bottom,
+ new->video_chroma_median_filter_top);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_luma_spatial_filter_type != new->video_luma_spatial_filter_type ||
+ old->video_chroma_spatial_filter_type != new->video_chroma_spatial_filter_type) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+ new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type);
+ if (err) return err;
+ }
+ if (old == NULL ||
+ old->video_spatial_filter != new->video_spatial_filter ||
+ old->video_temporal_filter != new->video_temporal_filter) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+ new->video_spatial_filter, new->video_temporal_filter);
+ if (err) return err;
+ }
+ if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
+ err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1,
+ new->video_temporal_decimation);
+ if (err) return err;
+ }
+ return 0;
+}
+
+static const char *cx2341x_menu_item(struct cx2341x_mpeg_params *p, u32 id)
+{
+ const char **menu = cx2341x_ctrl_get_menu(id);
+ struct v4l2_ext_control ctrl;
+
+ if (menu == NULL)
+ goto invalid;
+ ctrl.id = id;
+ if (cx2341x_get_ctrl(p, &ctrl))
+ goto invalid;
+ while (ctrl.value-- && *menu) menu++;
+ if (*menu == NULL)
+ goto invalid;
+ return *menu;
+
+invalid:
+ return "<invalid>";
+}
+
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int card_id)
+{
+ int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+
+ /* Stream */
+ printk(KERN_INFO "cx2341x-%d: Stream: %s\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+
+ /* Video */
+ printk(KERN_INFO "cx2341x-%d: Video: %dx%d, %d fps\n",
+ card_id,
+ p->width / (is_mpeg1 ? 2 : 1), p->height / (is_mpeg1 ? 2 : 1),
+ p->is_50hz ? 25 : 30);
+ printk(KERN_INFO "cx2341x-%d: Video: %s, %s, %s, %d",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_ASPECT),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE),
+ p->video_bitrate);
+ if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
+ printk(", Peak %d", p->video_bitrate_peak);
+ }
+ printk("\n");
+ printk(KERN_INFO "cx2341x-%d: Video: GOP Size %d, %d B-Frames, %sGOP Closure, %s3:2 Pulldown\n",
+ card_id,
+ p->video_gop_size, p->video_b_frames,
+ p->video_gop_closure ? "" : "No ",
+ p->video_pulldown ? "" : "No ");
+ if (p->video_temporal_decimation) {
+ printk(KERN_INFO "cx2341x-%d: Video: Temporal Decimation %d\n",
+ card_id, p->video_temporal_decimation);
+ }
+
+ /* Audio */
+ printk(KERN_INFO "cx2341x-%d: Audio: %s, %s, %s, %s",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_ENCODING),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_L2_BITRATE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE));
+ if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) {
+ printk(", %s",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION));
+ }
+ printk(", %s, %s\n",
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC));
+
+ /* Encoding filters */
+ printk(KERN_INFO "cx2341x-%d: Spatial Filter: %s, Luma %s, Chroma %s, %d\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE),
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
+ p->video_spatial_filter);
+ printk(KERN_INFO "cx2341x-%d: Temporal Filter: %s, %d\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
+ p->video_temporal_filter);
+ printk(KERN_INFO "cx2341x-%d: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
+ card_id,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE),
+ p->video_luma_median_filter_bottom,
+ p->video_luma_median_filter_top,
+ p->video_chroma_median_filter_bottom,
+ p->video_chroma_median_filter_top);
+}
+
+EXPORT_SYMBOL(cx2341x_fill_defaults);
+EXPORT_SYMBOL(cx2341x_ctrl_query);
+EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
+EXPORT_SYMBOL(cx2341x_ext_ctrls);
+EXPORT_SYMBOL(cx2341x_update);
+EXPORT_SYMBOL(cx2341x_log_status);
+EXPORT_SYMBOL(cx2341x_mpeg_ctrls);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
+
if (freq != 32000 && freq != 44100 && freq != 48000)
return -EINVAL;
- /* assert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x01);
-
/* common for all inputs and rates */
/* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
cx25840_write(client, 0x127, 0x50);
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xee39bb01);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x0801f77f */
cx25840_write4(client, 0x900, 0x7ff70108);
cx25840_write4(client, 0x904, 0x7ff70108);
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xd66bec00);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x08016d59 */
cx25840_write4(client, 0x900, 0x596d0108);
cx25840_write4(client, 0x904, 0x596d0108);
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xe5d69800);
+ if (state->is_cx25836)
+ break;
+
/* src3/4/6_ctl = 0x08014faa */
cx25840_write4(client, 0x900, 0xaa4f0108);
cx25840_write4(client, 0x904, 0xaa4f0108);
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0x69082a01);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0x00000108);
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xd66bec00);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0xcd600108);
/* AUX_PLL_FRAC */
cx25840_write4(client, 0x110, 0xe5d69800);
+ if (state->is_cx25836)
+ break;
+
/* src1_ctl = 0x08010000 */
cx25840_write4(client, 0x8f8, 0x00800108);
}
}
- /* deassert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
state->audclk_freq = freq;
return 0;
/* stop microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0);
+ /* assert soft reset */
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
+
/* Mute everything to prevent the PFFT! */
cx25840_write(client, 0x8d3, 0x1f);
} else {
/* Set Path1 to Analog Demod Main Channel */
cx25840_write4(client, 0x8d0, 0x7038061f);
+ }
+ set_audclk_freq(client, state->audclk_freq);
+
+ /* deassert soft reset */
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
+
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
/* When the microcontroller detects the
* audio format, it will unmute the lines */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
}
-
- set_audclk_freq(client, state->audclk_freq);
}
static int get_volume(struct i2c_client *client)
int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_control *ctrl = arg;
+ int retval;
switch (cmd) {
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return set_audclk_freq(client, *(u32 *)arg);
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ cx25840_and_or(client, 0x803, ~0x10, 0);
+ cx25840_write(client, 0x8d3, 0x1f);
+ }
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 1);
+ retval = set_audclk_freq(client, *(u32 *)arg);
+ if (!state->is_cx25836)
+ cx25840_and_or(client, 0x810, ~0x1, 0);
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
+ return retval;
case VIDIOC_G_CTRL:
switch (ctrl->id) {
*
* VBI support by Hans Verkuil <hverkuil@xs4all.nl>.
*
+ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca>
+ * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>.
+ *
* 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
static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END };
-static int cx25840_debug;
+int cx25840_debug;
module_param_named(debug,cx25840_debug, int, 0644);
(buffer[2] << 8) | buffer[3];
}
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask,
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
u8 or_value)
{
return cx25840_write(client, addr,
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
enum cx25840_audio_input aud_input);
-static void log_status(struct i2c_client *client);
+static void log_audio_status(struct i2c_client *client);
+static void log_video_status(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
cx25840_write(client, 0x15d, 0xe1);
}
+static void cx25836_initialize(struct i2c_client *client)
+{
+ /* reset configuration is described on page 3-77 of the CX25836 datasheet */
+ /* 2. */
+ cx25840_and_or(client, 0x000, ~0x01, 0x01);
+ cx25840_and_or(client, 0x000, ~0x01, 0x00);
+ /* 3a. */
+ cx25840_and_or(client, 0x15a, ~0x70, 0x00);
+ /* 3b. */
+ cx25840_and_or(client, 0x15b, ~0x1e, 0x06);
+ /* 3c. */
+ cx25840_and_or(client, 0x159, ~0x02, 0x02);
+ /* 3d. */
+ /* There should be a 10-us delay here, but since the
+ i2c bus already has a 10-us delay we don't need to do
+ anything */
+ /* 3e. */
+ cx25840_and_or(client, 0x159, ~0x02, 0x00);
+ /* 3f. */
+ cx25840_and_or(client, 0x159, ~0xc0, 0xc0);
+ /* 3g. */
+ cx25840_and_or(client, 0x159, ~0x01, 0x00);
+ cx25840_and_or(client, 0x159, ~0x01, 0x01);
+ /* 3h. */
+ cx25840_and_or(client, 0x15b, ~0x1e, 0x10);
+}
+
static void cx25840_initialize(struct i2c_client *client, int loadfw)
{
struct cx25840_state *state = i2c_get_clientdata(client);
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
- /* Note: perhaps V4L2_STD_PAL_M should be handled as V4L2_STD_NTSC
- instead of V4L2_STD_PAL. Someone needs to test this. */
- if (std & V4L2_STD_PAL) {
- /* Follow tuner change procedure for PAL */
- cx25840_write(client, 0x808, 0xff);
- cx25840_write(client, 0x80b, 0x10);
- } else if (std & V4L2_STD_SECAM) {
- /* Select autodetect for SECAM */
- cx25840_write(client, 0x808, 0xff);
- cx25840_write(client, 0x80b, 0x10);
- } else if (std & V4L2_STD_NTSC) {
+ if (std & V4L2_STD_525_60) {
/* Certain Hauppauge PVR150 models have a hardware bug
that causes audio to drop out. For these models the
audio standard must be set explicitly.
cx25840_write(client, 0x808, hw_fix ? 0x1f : 0xf6);
}
cx25840_write(client, 0x80b, 0x00);
+ } else if (std & V4L2_STD_PAL) {
+ /* Follow tuner change procedure for PAL */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
+ } else if (std & V4L2_STD_SECAM) {
+ /* Select autodetect for SECAM */
+ cx25840_write(client, 0x808, 0xff);
+ cx25840_write(client, 0x80b, 0x10);
}
if (cx25840_read(client, 0x803) & 0x10) {
state->vid_input = vid_input;
state->aud_input = aud_input;
- cx25840_audio_set_path(client);
- input_change(client);
+ if (!state->is_cx25836) {
+ cx25840_audio_set_path(client);
+ input_change(client);
+ }
return 0;
}
}
}
+ v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
+
/* Follow step 9 of section 3.16 in the cx25840 datasheet.
Without this PAL may display a vertical ghosting effect.
This happens for example with the Yuan MPC622. */
v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
/* check VID_FMT_SEL first */
u8 fmt = cx25840_read(client, 0x400) & 0xf;
{
/* if the audio std is A2-M, then this is the South Korean
NTSC standard */
- if (cx25840_read(client, 0x805) == 2)
+ if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
return V4L2_STD_NTSC_M_KR;
return V4L2_STD_NTSC_M;
}
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
return cx25840_audio(client, VIDIOC_S_CTRL, ctrl);
default:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_MUTE:
+ if (state->is_cx25836)
+ return -EINVAL;
return cx25840_audio(client, VIDIOC_G_CTRL, ctrl);
default:
return -EINVAL;
/* ----------------------------------------------------------------------- */
-static struct v4l2_queryctrl cx25840_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BASS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- }, {
- .id = V4L2_CID_AUDIO_TREBLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- },
-};
-
-/* ----------------------------------------------------------------------- */
-
static int cx25840_command(struct i2c_client *client, unsigned int cmd,
void *arg)
{
case VIDIOC_STREAMON:
v4l_dbg(1, cx25840_debug, client, "enable output\n");
- cx25840_write(client, 0x115, 0x8c);
- cx25840_write(client, 0x116, 0x07);
+ cx25840_write(client, 0x115, state->is_cx25836 ? 0x0c : 0x8c);
+ cx25840_write(client, 0x116, state->is_cx25836 ? 0x04 : 0x07);
break;
case VIDIOC_STREAMOFF:
break;
case VIDIOC_LOG_STATUS:
- log_status(client);
+ log_video_status(client);
+ if (!state->is_cx25836)
+ log_audio_status(client);
break;
case VIDIOC_G_CTRL:
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(cx25840_qctrl); i++)
- if (qc->id && qc->id == cx25840_qctrl[i].id) {
- memcpy(qc, &cx25840_qctrl[i], sizeof(*qc));
- return 0;
- }
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
+ if (state->is_cx25836)
+ return -EINVAL;
+
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
return -EINVAL;
}
return set_input(client, route->input, state->aud_input);
case VIDIOC_INT_G_AUDIO_ROUTING:
+ if (state->is_cx25836)
+ return -EINVAL;
route->input = state->aud_input;
route->output = 0;
break;
case VIDIOC_INT_S_AUDIO_ROUTING:
+ if (state->is_cx25836)
+ return -EINVAL;
return set_input(client, state->vid_input, route->input);
case VIDIOC_S_FREQUENCY:
- input_change(client);
+ if (!state->is_cx25836) {
+ input_change(client);
+ }
break;
case VIDIOC_G_TUNER:
{
- u8 mode = cx25840_read(client, 0x804);
- u8 vpres = cx25840_read(client, 0x80a) & 0x10;
+ u8 vpres = cx25840_read(client, 0x40e) & 0x20;
+ u8 mode;
int val = 0;
if (state->radio)
break;
+ vt->signal = vpres ? 0xffff : 0x0;
+ if (state->is_cx25836)
+ break;
+
vt->capability |=
V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
- vt->signal = vpres ? 0xffff : 0x0;
+ mode = cx25840_read(client, 0x804);
/* get rxsubchans and audmode */
if ((mode & 0xf) == 1)
}
case VIDIOC_S_TUNER:
- if (state->radio)
+ if (state->radio || state->is_cx25836)
break;
switch (vt->audmode) {
return set_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_RESET:
- cx25840_initialize(client, 0);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client, 0);
break;
case VIDIOC_INT_G_CHIP_IDENT:
- *(enum v4l2_chip_ident *)arg =
- V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf);
+ *(enum v4l2_chip_ident *)arg = state->id;
break;
default:
{
struct i2c_client *client;
struct cx25840_state *state;
+ enum v4l2_chip_ident id;
u16 device_id;
/* Check if the adapter supports the needed features
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
return 0;
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ state = kzalloc(sizeof(struct cx25840_state), GFP_KERNEL);
+ if (state == 0)
return -ENOMEM;
+ client = &state->c;
client->addr = address;
client->adapter = adapter;
client->driver = &i2c_driver_cx25840;
device_id |= cx25840_read(client, 0x100);
/* The high byte of the device ID should be
- * 0x84 if chip is present */
- if ((device_id & 0xff00) != 0x8400) {
+ * 0x83 for the cx2583x and 0x84 for the cx2584x */
+ if ((device_id & 0xff00) == 0x8300) {
+ id = V4L2_IDENT_CX25836 + ((device_id >> 4) & 0xf) - 6;
+ state->is_cx25836 = 1;
+ }
+ else if ((device_id & 0xff00) == 0x8400) {
+ id = V4L2_IDENT_CX25840 + ((device_id >> 4) & 0xf);
+ state->is_cx25836 = 0;
+ }
+ else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
- kfree(client);
+ kfree(state);
return 0;
}
(device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3,
address << 1, adapter->name);
- state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL);
- if (state == NULL) {
- kfree(client);
- return -ENOMEM;
- }
-
i2c_set_clientdata(client, state);
- memset(state, 0, sizeof(struct cx25840_state));
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
+ state->vbi_line_offset = 8;
+ state->id = id;
- cx25840_initialize(client, 1);
+ if (state->is_cx25836)
+ cx25836_initialize(client);
+ else
+ cx25840_initialize(client, 1);
i2c_attach_client(client);
}
kfree(state);
- kfree(client);
return 0;
}
/* ----------------------------------------------------------------------- */
-static void log_status(struct i2c_client *client)
+static void log_video_status(struct i2c_client *client)
{
static const char *const fmt_strs[] = {
"0x0",
};
struct cx25840_state *state = i2c_get_clientdata(client);
- u8 microctrl_vidfmt = cx25840_read(client, 0x80a);
u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf;
u8 gen_stat1 = cx25840_read(client, 0x40d);
+ u8 gen_stat2 = cx25840_read(client, 0x40e);
+ int vid_input = state->vid_input;
+
+ v4l_info(client, "Video signal: %spresent\n",
+ (gen_stat2 & 0x20) ? "" : "not ");
+ v4l_info(client, "Detected format: %s\n",
+ fmt_strs[gen_stat1 & 0xf]);
+
+ v4l_info(client, "Specified standard: %s\n",
+ vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
+
+ if (vid_input >= CX25840_COMPOSITE1 &&
+ vid_input <= CX25840_COMPOSITE8) {
+ v4l_info(client, "Specified video input: Composite %d\n",
+ vid_input - CX25840_COMPOSITE1 + 1);
+ } else {
+ v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
+ (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
+ }
+
+ v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
+}
+
+/* ----------------------------------------------------------------------- */
+
+static void log_audio_status(struct i2c_client *client)
+{
+ struct cx25840_state *state = i2c_get_clientdata(client);
u8 download_ctl = cx25840_read(client, 0x803);
u8 mod_det_stat0 = cx25840_read(client, 0x804);
u8 mod_det_stat1 = cx25840_read(client, 0x805);
u8 pref_mode = cx25840_read(client, 0x809);
u8 afc0 = cx25840_read(client, 0x80b);
u8 mute_ctl = cx25840_read(client, 0x8d3);
- int vid_input = state->vid_input;
int aud_input = state->aud_input;
char *p;
- v4l_info(client, "Video signal: %spresent\n",
- (microctrl_vidfmt & 0x10) ? "" : "not ");
- v4l_info(client, "Detected format: %s\n",
- fmt_strs[gen_stat1 & 0xf]);
-
switch (mod_det_stat0) {
case 0x00: p = "mono"; break;
case 0x01: p = "stereo"; break;
v4l_info(client, "Configured audio system: %s\n", p);
}
- v4l_info(client, "Specified standard: %s\n",
- vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
-
- if (vid_input >= CX25840_COMPOSITE1 &&
- vid_input <= CX25840_COMPOSITE8) {
- v4l_info(client, "Specified video input: Composite %d\n",
- vid_input - CX25840_COMPOSITE1 + 1);
- } else {
- v4l_info(client, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
- (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
- }
if (aud_input) {
v4l_info(client, "Specified audio input: Tuner (In%d)\n", aud_input);
} else {
v4l_info(client, "Specified audio input: External\n");
}
- v4l_info(client, "Specified audioclock freq: %d Hz\n", state->audclk_freq);
-
switch (pref_mode & 0xf) {
case 0: p = "mono/language A"; break;
case 1: p = "language B"; break;
#include <linux/videodev2.h>
#include <linux/i2c.h>
+extern int cx25840_debug;
+
/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
struct cx25840_state {
+ struct i2c_client c;
int pvr150_workaround;
int radio;
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
+ int vbi_line_offset;
+ enum v4l2_chip_ident id;
+ int is_cx25836;
};
/* ----------------------------------------------------------------------- */
int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
u8 cx25840_read(struct i2c_client *client, u16 addr);
u32 cx25840_read4(struct i2c_client *client, u16 addr);
-int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value);
+int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
void cx25840_vbi_setup(struct i2c_client *client)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
v4l2_std_id std = cx25840_get_v4lstd(client);
+ int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
+ int luma_lpf,uv_lpf, comb;
+ u32 pll_int,pll_frac,pll_post;
+ /* datasheet startup, step 8d */
if (std & ~V4L2_STD_NTSC) {
- /* datasheet startup, step 8d */
cx25840_write(client, 0x49f, 0x11);
+ } else {
+ cx25840_write(client, 0x49f, 0x14);
+ }
- cx25840_write(client, 0x470, 0x84);
- cx25840_write(client, 0x471, 0x00);
- cx25840_write(client, 0x472, 0x2d);
- cx25840_write(client, 0x473, 0x5d);
-
- cx25840_write(client, 0x474, 0x24);
- cx25840_write(client, 0x475, 0x40);
- cx25840_write(client, 0x476, 0x24);
- cx25840_write(client, 0x477, 0x28);
-
- cx25840_write(client, 0x478, 0x1f);
- cx25840_write(client, 0x479, 0x02);
+ if (std & V4L2_STD_625_50) {
+ hblank=0x084;
+ hactive=0x2d0;
+ burst=0x5d;
+ vblank=0x024;
+ vactive=0x244;
+ vblank656=0x28;
+ src_decimation=0x21f;
+ luma_lpf=2;
if (std & V4L2_STD_SECAM) {
- cx25840_write(client, 0x47a, 0x80);
- cx25840_write(client, 0x47b, 0x00);
- cx25840_write(client, 0x47c, 0x5f);
- cx25840_write(client, 0x47d, 0x42);
+ uv_lpf=0;
+ comb=0;
+ sc=0x0a425f;
} else {
- cx25840_write(client, 0x47a, 0x90);
- cx25840_write(client, 0x47b, 0x20);
- cx25840_write(client, 0x47c, 0x63);
- cx25840_write(client, 0x47d, 0x82);
+ uv_lpf=1;
+ comb=0x20;
+ sc=0x0a8263;
}
-
- cx25840_write(client, 0x47e, 0x0a);
- cx25840_write(client, 0x47f, 0x01);
} else {
- /* datasheet startup, step 8d */
- cx25840_write(client, 0x49f, 0x14);
+ hactive=720;
+ hblank=122;
+ vactive=487;
+ luma_lpf=1;
+ uv_lpf=1;
+
+ src_decimation=0x21f;
+ if (std == V4L2_STD_PAL_M) {
+ vblank=20;
+ vblank656=24;
+ burst=0x61;
+ comb=0x20;
+
+ sc=555452;
+ } else {
+ vblank=26;
+ vblank656=26;
+ burst=0x5b;
+ comb=0x66;
+ sc=556063;
+ }
+ }
+
+ /* DEBUG: Displays configured PLL frequency */
+ pll_int=cx25840_read(client, 0x108);
+ pll_frac=cx25840_read4(client, 0x10c)&0x1ffffff;
+ pll_post=cx25840_read(client, 0x109);
+ v4l_dbg(1, cx25840_debug, client,
+ "PLL regs = int: %u, frac: %u, post: %u\n",
+ pll_int,pll_frac,pll_post);
+
+ if (pll_post) {
+ int fin, fsc;
+ int pll= (28636363L*((((u64)pll_int)<<25L)+pll_frac)) >>25L;
+
+ pll/=pll_post;
+ v4l_dbg(1, cx25840_debug, client, "PLL = %d.%06d MHz\n",
+ pll/1000000, pll%1000000);
+ v4l_dbg(1, cx25840_debug, client, "PLL/8 = %d.%06d MHz\n",
+ pll/8000000, (pll/8)%1000000);
+
+ fin=((u64)src_decimation*pll)>>12;
+ v4l_dbg(1, cx25840_debug, client, "ADC Sampling freq = "
+ "%d.%06d MHz\n",
+ fin/1000000,fin%1000000);
+
+ fsc= (((u64)sc)*pll) >> 24L;
+ v4l_dbg(1, cx25840_debug, client, "Chroma sub-carrier freq = "
+ "%d.%06d MHz\n",
+ fsc/1000000,fsc%1000000);
+
+ v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
+ "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
+ "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
+ " sc 0x%06x\n",
+ hblank, hactive, vblank, vactive, vblank656,
+ src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
+ }
+
+ /* Sets horizontal blanking delay and active lines */
+ cx25840_write(client, 0x470, hblank);
+ cx25840_write(client, 0x471, 0xff&(((hblank>>8)&0x3)|(hactive <<4)));
+ cx25840_write(client, 0x472, hactive>>4);
+
+ /* Sets burst gate delay */
+ cx25840_write(client, 0x473, burst);
- cx25840_write(client, 0x470, 0x7a);
- cx25840_write(client, 0x471, 0x00);
- cx25840_write(client, 0x472, 0x2d);
- cx25840_write(client, 0x473, 0x5b);
+ /* Sets vertical blanking delay and active duration */
+ cx25840_write(client, 0x474, vblank);
+ cx25840_write(client, 0x475, 0xff&(((vblank>>8)&0x3)|(vactive <<4)));
+ cx25840_write(client, 0x476, vactive>>4);
+ cx25840_write(client, 0x477, vblank656);
- cx25840_write(client, 0x474, 0x1a);
- cx25840_write(client, 0x475, 0x70);
- cx25840_write(client, 0x476, 0x1e);
- cx25840_write(client, 0x477, 0x1e);
+ /* Sets src decimation rate */
+ cx25840_write(client, 0x478, 0xff&src_decimation);
+ cx25840_write(client, 0x479, 0xff&(src_decimation>>8));
- cx25840_write(client, 0x478, 0x1f);
- cx25840_write(client, 0x479, 0x02);
- cx25840_write(client, 0x47a, 0x50);
- cx25840_write(client, 0x47b, 0x66);
+ /* Sets Luma and UV Low pass filters */
+ cx25840_write(client, 0x47a, luma_lpf<<6|((uv_lpf<<4)&0x30));
- cx25840_write(client, 0x47c, 0x1f);
- cx25840_write(client, 0x47d, 0x7c);
- cx25840_write(client, 0x47e, 0x08);
+ /* Enables comb filters */
+ cx25840_write(client, 0x47b, comb);
+
+ /* Sets SC Step*/
+ cx25840_write(client, 0x47c, sc);
+ cx25840_write(client, 0x47d, 0xff&sc>>8);
+ cx25840_write(client, 0x47e, 0xff&sc>>16);
+
+ /* Sets VBI parameters */
+ if (std & V4L2_STD_625_50) {
+ cx25840_write(client, 0x47f, 0x01);
+ state->vbi_line_offset = 5;
+ } else {
cx25840_write(client, 0x47f, 0x00);
+ state->vbi_line_offset = 8;
}
}
int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_format *fmt;
struct v4l2_sliced_vbi_format *svbi;
case VIDIOC_S_FMT:
{
- int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC);
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
int vbi_offset = is_pal ? 1 : 0;
int i, x;
u8 lcr[24];
cx25840_vbi_setup(client);
/* Sliced VBI */
- cx25840_write(client, 0x404, 0x36); /* Ancillery data */
+ cx25840_write(client, 0x404, 0x32); /* Ancillary data */
cx25840_write(client, 0x406, 0x13);
cx25840_write(client, 0x47f, vbi_offset);
}
}
- for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
- cx25840_write(client, i, lcr[6 + x]);
+ if (is_pal) {
+ for (x = 1, i = 0x424; i <= 0x434; i++, x++) {
+ cx25840_write(client, i, lcr[6 + x]);
+ }
+ }
+ else {
+ for (x = 1, i = 0x424; i <= 0x430; i++, x++) {
+ cx25840_write(client, i, lcr[9 + x]);
+ }
+ for (i = 0x431; i <= 0x434; i++) {
+ cx25840_write(client, i, 0);
+ }
}
cx25840_write(client, 0x43c, 0x16);
if (is_pal) {
cx25840_write(client, 0x474, 0x2a);
} else {
- cx25840_write(client, 0x474, 0x1a + 6);
+ cx25840_write(client, 0x474, 0x22);
}
break;
}
id1 = p[-1];
id2 = p[0] & 0xf;
l = p[2] & 0x3f;
- l += 5;
+ l += state->vbi_line_offset;
p += 4;
switch (id2) {
select VIDEO_BUF
select VIDEO_TUNER
select VIDEO_TVEEPROM
+ select VIDEO_CX2341X
select VIDEO_IR
---help---
This is a video4linux driver for Conexant 2388x based
select DVB_LGDT330X
select DVB_NXT200X
select DVB_CX24123
+ select DVB_ISL6421
---help---
This builds cx88-dvb with all currently supported frontend
demodulators. If you wish to tweak your configuration, and
default y
depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
select DVB_CX24123
+ select DVB_ISL6421
---help---
This adds DVB-S support for cards based on the
Connexant 2388x chip and the CX24123 demodulator.
* PCI function #1 of the cx2388x.
*
* (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>
- * (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ * (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
* Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
* Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
*
MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
MODULE_AUTHOR("Ricardo Cerqueira");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
MODULE_SUPPORTED_DEVICE("{{Conexant,23881},"
"{{Conexant,23882},"
chip->irq = -1;
spin_lock_init(&chip->reg_lock);
- cx88_reset(core);
chip->core = core;
/* get irq */
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
#include "cx88.h"
-#include <media/v4l2-common.h>
MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards");
MODULE_AUTHOR("Jelle Foks <jelle@foks.8m.com>, Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
/* ------------------------------------------------------------------ */
-#define BLACKBIRD_FIRM_ENC_FILENAME "blackbird-fw-enc.bin"
#define BLACKBIRD_FIRM_IMAGE_SIZE 256*1024
/* defines below are from ivtv-driver.h */
/* Firmware API commands */
#define IVTV_API_STD_TIMEOUT 500
-#define BLACKBIRD_API_PING 0x80
-#define BLACKBIRD_API_BEGIN_CAPTURE 0x81
enum blackbird_capture_type {
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_CAPTURE,
BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10
};
-#define BLACKBIRD_API_END_CAPTURE 0x82
enum blackbird_capture_end {
BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
BLACKBIRD_END_NOW, /* stop immediately, no irq */
};
-#define BLACKBIRD_API_SET_AUDIO_ID 0x89
-#define BLACKBIRD_API_SET_VIDEO_ID 0x8B
-#define BLACKBIRD_API_SET_PCR_ID 0x8D
-#define BLACKBIRD_API_SET_FRAMERATE 0x8F
enum blackbird_framerate {
BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */
};
-#define BLACKBIRD_API_SET_RESOLUTION 0x91
-#define BLACKBIRD_API_SET_VIDEO_BITRATE 0x95
-enum blackbird_video_bitrate_type {
- BLACKBIRD_VIDEO_VBR,
- BLACKBIRD_VIDEO_CBR
-};
-#define BLACKBIRD_PEAK_RATE_DIVISOR 400
-enum blackbird_mux_rate {
- BLACKBIRD_MUX_RATE_DEFAULT,
- /* dvd mux rate: multiply by 400 to get the actual rate */
- BLACKBIRD_MUX_RATE_DVD = 25200
-};
-#define BLACKBIRD_API_SET_GOP_STRUCTURE 0x97
-#define BLACKBIRD_API_SET_ASPECT_RATIO 0x99
-enum blackbird_aspect_ratio {
- BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
- BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
- BLACKBIRD_ASPECT_RATIO_4_3,
- BLACKBIRD_ASPECT_RATIO_16_9,
- BLACKBIRD_ASPECT_RATIO_221_100,
- BLACKBIRD_ASPECT_RATIO_RESERVED
-};
-#define BLACKBIRD_API_SET_DNR_MODE 0x9B
-enum blackbird_dnr_bits {
- BLACKBIRD_DNR_BITS_MANUAL,
- BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
- BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
- BLACKBIRD_DNR_BITS_AUTO
-};
-enum blackbird_median_filter {
- BLACKBIRD_MEDIAN_FILTER_DISABLED,
- BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
- BLACKBIRD_MEDIAN_FILTER_VERTICAL,
- BLACKBIRD_MEDIAN_FILTER_HV,
- BLACKBIRD_MEDIAN_FILTER_DIAGONAL
-};
-#define BLACKBIRD_API_SET_MANUAL_DNR 0x9D
-#define BLACKBIRD_API_SET_DNR_MEDIAN 0x9F
-#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
-enum blackbird_spatial_filter_luma {
- BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
- BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
- BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
-};
-enum blackbird_spatial_filter_chroma {
- BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
-};
-#define BLACKBIRD_API_SET_3_2_PULLDOWN 0xB1
-enum blackbird_pulldown {
- BLACKBIRD_3_2_PULLDOWN_DISABLED,
- BLACKBIRD_3_2_PULLDOWN_ENABLED
-};
-#define BLACKBIRD_API_SET_VBI_LINE_NO 0xB7
-enum blackbird_vbi_line_bits {
- BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
- BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
- BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
-};
-enum blackbird_vbi_line {
- BLACKBIRD_VBI_LINE_DISABLED,
- BLACKBIRD_VBI_LINE_ENABLED
-};
-enum blackbird_vbi_slicing {
- BLACKBIRD_VBI_SLICING_NONE,
- BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
-};
-#define BLACKBIRD_API_SET_STREAM_TYPE 0xB9
-enum blackbird_stream_type {
- BLACKBIRD_STREAM_PROGRAM,
- BLACKBIRD_STREAM_TRANSPORT,
- BLACKBIRD_STREAM_MPEG1,
- BLACKBIRD_STREAM_PES_AV,
- BLACKBIRD_STREAM_UNKNOWN4,
- BLACKBIRD_STREAM_PES_VIDEO,
- BLACKBIRD_STREAM_UNKNOWN6,
- BLACKBIRD_STREAM_PES_AUDIO,
- BLACKBIRD_STREAM_UNKNOWN8,
- BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
- BLACKBIRD_STREAM_DVD,
- BLACKBIRD_STREAM_VCD,
- BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
-};
-#define BLACKBIRD_API_SET_OUTPUT_PORT 0xBB
enum blackbird_stream_port {
BLACKBIRD_OUTPUT_PORT_MEMORY,
BLACKBIRD_OUTPUT_PORT_STREAMING,
BLACKBIRD_OUTPUT_PORT_SERIAL
};
-#define BLACKBIRD_API_SET_AUDIO_PARAMS 0xBD
-enum blackbird_audio_bits_sample_rate {
- BLACKBIRD_AUDIO_BITS_44100HZ,
- BLACKBIRD_AUDIO_BITS_48000HZ,
- BLACKBIRD_AUDIO_BITS_32000HZ,
- BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
-};
-enum blackbird_audio_bits_encoding {
- BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
- BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
-};
-enum blackbird_audio_bits_bitrate_layer_1 {
- BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
- BLACKBIRD_AUDIO_BITS_LAYER_1_32 = 0x01 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_64 = 0x02 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_96 = 0x03 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
-};
-enum blackbird_audio_bits_bitrate_layer_2 {
- BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
- BLACKBIRD_AUDIO_BITS_LAYER_2_32 = 0x01 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_48 = 0x02 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_56 = 0x03 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_64 = 0x04 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_80 = 0x05 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_96 = 0x06 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
- BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
-};
-enum blackbird_audio_bits_mode {
- BLACKBIRD_AUDIO_BITS_STEREO,
- BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
- BLACKBIRD_AUDIO_BITS_DUAL = 0x2 << 8,
- BLACKBIRD_AUDIO_BITS_MONO = 0x3 << 8,
-};
-enum blackbird_audio_bits_mode_extension {
- BLACKBIRD_AUDIO_BITS_BOUND_4,
- BLACKBIRD_AUDIO_BITS_BOUND_8 = 0x1 << 10,
- BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
- BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
-};
-enum blackbird_audio_bits_emphasis {
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15 = 0x1 << 12,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED = 0x2 << 12,
- BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
-};
-enum blackbird_audio_bits_crc {
- BLACKBIRD_AUDIO_BITS_CRC_OFF,
- BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
-};
-enum blackbird_audio_bits_copyright {
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
-};
-enum blackbird_audio_bits_original {
- BLACKBIRD_AUDIO_BITS_COPY,
- BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
-};
-#define BLACKBIRD_API_HALT 0xC3
-#define BLACKBIRD_API_GET_VERSION 0xC4
-#define BLACKBIRD_API_SET_GOP_CLOSURE 0xC5
-enum blackbird_gop_closure {
- BLACKBIRD_GOP_CLOSURE_OFF,
- BLACKBIRD_GOP_CLOSURE_ON,
-};
-#define BLACKBIRD_API_DATA_XFER_STATUS 0xC6
enum blackbird_data_xfer_status {
BLACKBIRD_MORE_BUFFERS_FOLLOW,
BLACKBIRD_LAST_BUFFER,
};
-#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
enum blackbird_picture_mask {
BLACKBIRD_PICTURE_MASK_NONE,
BLACKBIRD_PICTURE_MASK_I_FRAMES,
BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
};
-#define BLACKBIRD_API_SET_VBI_PARAMS 0xC8
enum blackbird_vbi_mode_bits {
BLACKBIRD_VBI_BITS_SLICED,
BLACKBIRD_VBI_BITS_RAW,
BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
};
-#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
enum blackbird_dma_unit {
BLACKBIRD_DMA_BYTES,
BLACKBIRD_DMA_FRAMES,
};
-#define BLACKBIRD_API_DMA_TRANSFER_INFO 0xCA
-#define BLACKBIRD_API_DMA_TRANSFER_STAT 0xCB
enum blackbird_dma_transfer_status_bits {
BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
};
-#define BLACKBIRD_API_SET_DMA2HOST_ADDR 0xCC
-#define BLACKBIRD_API_INIT_VIDEO_INPUT 0xCD
-#define BLACKBIRD_API_SET_FRAMESKIP 0xD0
-#define BLACKBIRD_API_PAUSE 0xD2
enum blackbird_pause {
BLACKBIRD_PAUSE_ENCODING,
BLACKBIRD_RESUME_ENCODING,
};
-#define BLACKBIRD_API_REFRESH_INPUT 0xD3
-#define BLACKBIRD_API_SET_COPYRIGHT 0xD4
enum blackbird_copyright {
BLACKBIRD_COPYRIGHT_OFF,
BLACKBIRD_COPYRIGHT_ON,
};
-#define BLACKBIRD_API_SET_NOTIFICATION 0xD5
enum blackbird_notification_type {
BLACKBIRD_NOTIFICATION_REFRESH,
};
enum blackbird_notification_mailbox {
BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
};
-#define BLACKBIRD_API_SET_CAPTURE_LINES 0xD6
enum blackbird_field1_lines {
BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
};
-#define BLACKBIRD_API_SET_CUSTOM_DATA 0xD7
enum blackbird_custom_data_type {
BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
BLACKBIRD_CUSTOM_PRIVATE_PACKET,
};
-#define BLACKBIRD_API_MUTE_VIDEO 0xD9
enum blackbird_mute {
BLACKBIRD_UNMUTE,
BLACKBIRD_MUTE,
BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
};
-#define BLACKBIRD_API_MUTE_AUDIO 0xDA
/* Registers */
#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
/* ------------------------------------------------------------------ */
-/* We don't need to call the API often, so using just one mailbox will probably suffice */
-static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
- u32 inputcnt, u32 outputcnt, ...)
+static int blackbird_mbox_func(void *priv, int command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA])
{
+ struct cx8802_dev *dev = priv;
unsigned long timeout;
u32 value, flag, retval;
int i;
- va_list args;
- va_start(args, outputcnt);
dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
/* write command + args + fill remaining with zeros */
memory_write(dev->core, dev->mailbox + 1, command); /* command code */
memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */
- for (i = 0; i < inputcnt ; i++) {
- value = va_arg(args, int);
- memory_write(dev->core, dev->mailbox + 4 + i, value);
- dprintk(1, "API Input %d = %d\n", i, value);
+ for (i = 0; i < in; i++) {
+ memory_write(dev->core, dev->mailbox + 4 + i, data[i]);
+ dprintk(1, "API Input %d = %d\n", i, data[i]);
}
- for (; i < 16 ; i++)
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
memory_write(dev->core, dev->mailbox + 4 + i, 0);
flag |= 3; /* tell 'em we're done writing */
}
/* read output values */
- for (i = 0; i < outputcnt ; i++) {
- int *vptr = va_arg(args, int *);
- memory_read(dev->core, dev->mailbox + 4 + i, vptr);
- dprintk(1, "API Output %d = %d\n", i, *vptr);
+ for (i = 0; i < out; i++) {
+ memory_read(dev->core, dev->mailbox + 4 + i, data + i);
+ dprintk(1, "API Output %d = %d\n", i, data[i]);
}
- va_end(args);
memory_read(dev->core, dev->mailbox + 2, &retval);
dprintk(1, "API result = %d\n",retval);
memory_write(dev->core, dev->mailbox, flag);
return retval;
}
+/* ------------------------------------------------------------------ */
+/* We don't need to call the API often, so using just one mailbox will probably suffice */
+static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command,
+ u32 inputcnt, u32 outputcnt, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ va_start(vargs, outputcnt);
+
+ for (i = 0; i < inputcnt; i++) {
+ data[i] = va_arg(vargs, int);
+ }
+ err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+ return err;
+}
static int blackbird_find_mailbox(struct cx8802_dev *dev)
{
if (retval < 0)
dprintk(0, "Error with register_write\n");
- retval = request_firmware(&firmware, BLACKBIRD_FIRM_ENC_FILENAME,
+ retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME,
&dev->pci->dev);
if (retval != 0) {
dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
- BLACKBIRD_FIRM_ENC_FILENAME);
+ CX2341X_FIRM_ENC_FILENAME);
dprintk(0, "Please fix your hotplug setup, the board will "
"not work without firmware loaded!\n");
return -1;
*DB: "DirectBurn"
*/
-static struct blackbird_dnr default_dnr_params = {
- .mode = BLACKBIRD_DNR_BITS_MANUAL,
- .type = BLACKBIRD_MEDIAN_FILTER_DISABLED,
- .spatial = 0,
- .temporal = 0
-};
+static void blackbird_codec_settings(struct cx8802_dev *dev)
+{
+ /* assign frame size */
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->height, dev->width);
+
+ dev->params.width = dev->width;
+ dev->params.height = dev->height;
+ dev->params.is_50hz = (dev->core->tvnorm->id & V4L2_STD_625_50) != 0;
+
+ cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params);
+}
+
static struct v4l2_mpeg_compression default_mpeg_params = {
.st_type = V4L2_MPEG_PS_2,
.st_bitrate = {
.target = 224,
.max = 224
},
- .au_sample_rate = 44100,
+ .au_sample_rate = 48000,
.au_pesid = 0,
.vi_type = V4L2_MPEG_VI_2,
.vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3,
.max = 6000
},
.vi_frame_rate = 25,
- .vi_frames_per_gop = 15,
+ .vi_frames_per_gop = 12,
.vi_bframes_count = 2,
.vi_pesid = 0,
- .closed_gops = 0,
+ .closed_gops = 1,
.pulldown = 0
};
-static enum blackbird_stream_type mpeg_stream_types[] = {
- [V4L2_MPEG_SS_1] = BLACKBIRD_STREAM_MPEG1,
- [V4L2_MPEG_PS_2] = BLACKBIRD_STREAM_PROGRAM,
- [V4L2_MPEG_TS_2] = BLACKBIRD_STREAM_TRANSPORT,
- [V4L2_MPEG_PS_DVD] = BLACKBIRD_STREAM_DVD,
-};
-static enum blackbird_aspect_ratio mpeg_stream_ratios[] = {
- [V4L2_MPEG_ASPECT_SQUARE] = BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
- [V4L2_MPEG_ASPECT_4_3] = BLACKBIRD_ASPECT_RATIO_4_3,
- [V4L2_MPEG_ASPECT_16_9] = BLACKBIRD_ASPECT_RATIO_16_9,
- [V4L2_MPEG_ASPECT_1_221] = BLACKBIRD_ASPECT_RATIO_221_100,
-};
-static enum blackbird_video_bitrate_type mpeg_video_bitrates[] = {
- [V4L2_BITRATE_NONE] = BLACKBIRD_VIDEO_CBR,
- [V4L2_BITRATE_CBR] = BLACKBIRD_VIDEO_CBR,
- [V4L2_BITRATE_VBR] = BLACKBIRD_VIDEO_VBR,
-};
-/* find the best layer I/II bitrate to fit a given numeric value */
-struct bitrate_bits {
- u32 bits; /* layer bits for the best fit */
- u32 rate; /* actual numeric value for the layer best fit */
-};
-struct bitrate_approximation {
- u32 target; /* numeric value of the rate we want */
- struct bitrate_bits layer[2];
-};
-static struct bitrate_approximation mpeg_audio_bitrates[] = {
- /* target layer[0].bits layer[0].rate layer[1].bits layer[1].rate */
- { 0, { { 0, 0, }, { 0, 0, }, }, },
- { 32, { { BLACKBIRD_AUDIO_BITS_LAYER_1_32 , 32, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_32 , 32, }, }, },
- { 48, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_48 , 48, }, }, },
- { 56, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_56 , 56, }, }, },
- { 64, { { BLACKBIRD_AUDIO_BITS_LAYER_1_64 , 64, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_64 , 64, }, }, },
- { 80, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_80 , 80, }, }, },
- { 96, { { BLACKBIRD_AUDIO_BITS_LAYER_1_96 , 96, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_96 , 96, }, }, },
- { 112, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_112, 112, }, }, },
- { 128, { { BLACKBIRD_AUDIO_BITS_LAYER_1_128, 128, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_128, 128, }, }, },
- { 160, { { BLACKBIRD_AUDIO_BITS_LAYER_1_160, 160, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_160, 160, }, }, },
- { 192, { { BLACKBIRD_AUDIO_BITS_LAYER_1_192, 192, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_192, 192, }, }, },
- { 224, { { BLACKBIRD_AUDIO_BITS_LAYER_1_224, 224, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_224, 224, }, }, },
- { 256, { { BLACKBIRD_AUDIO_BITS_LAYER_1_256, 256, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_256, 256, }, }, },
- { 288, { { BLACKBIRD_AUDIO_BITS_LAYER_1_288, 288, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
- { 320, { { BLACKBIRD_AUDIO_BITS_LAYER_1_320, 320, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_320, 320, }, }, },
- { 352, { { BLACKBIRD_AUDIO_BITS_LAYER_1_352, 352, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
- { 384, { { BLACKBIRD_AUDIO_BITS_LAYER_1_384, 384, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
- { 416, { { BLACKBIRD_AUDIO_BITS_LAYER_1_416, 416, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
- { 448, { { BLACKBIRD_AUDIO_BITS_LAYER_1_448, 448, }, { BLACKBIRD_AUDIO_BITS_LAYER_2_384, 384, }, }, },
-};
-static const int BITRATES_SIZE = ARRAY_SIZE(mpeg_audio_bitrates);
-
-static void blackbird_set_default_params(struct cx8802_dev *dev)
-{
- struct v4l2_mpeg_compression *params = &dev->params;
- u32 au_params;
-
- /* assign stream type */
- if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
- params->st_type = V4L2_MPEG_PS_2;
- if( params->st_type == V4L2_MPEG_SS_1 )
- params->vi_type = V4L2_MPEG_VI_1;
- else
- params->vi_type = V4L2_MPEG_VI_2;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
-
- /* assign framerate */
- if( params->vi_frame_rate <= 25 )
- {
- params->vi_frame_rate = 25;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
- }
- else
- {
- params->vi_frame_rate = 30;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
- }
-
- /* assign aspect ratio */
- if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
- params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
-
- /* assign gop properties */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
-
- /* assign gop closure */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
-
- /* assign 3 2 pulldown */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
-
- /* make sure the params are within bounds */
- if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->au_bitrate.mode = V4L2_BITRATE_NONE;
-
- /* assign audio properties */
- /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- au_params = BLACKBIRD_AUDIO_BITS_STEREO |
- /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
- BLACKBIRD_AUDIO_BITS_CRC_OFF |
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
- BLACKBIRD_AUDIO_BITS_COPY |
- 0;
- if( params->au_sample_rate <= 32000 )
- {
- params->au_sample_rate = 32000;
- au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
- }
- else if( params->au_sample_rate <= 44100 )
- {
- params->au_sample_rate = 44100;
- au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
- }
- else
- {
- params->au_sample_rate = 48000;
- au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
- }
- if( params->au_type == V4L2_MPEG_AU_2_I )
- {
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
- }
- else
- {
- /* TODO: try to handle the other formats more gracefully */
- params->au_type = V4L2_MPEG_AU_2_II;
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
- }
- if( params->au_bitrate.mode )
- {
- int layer;
-
- if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
- params->au_bitrate.max = params->vi_bitrate.target;
- else
- params->au_bitrate.target = params->vi_bitrate.max;
-
- layer = params->au_type;
- if( params->au_bitrate.target == 0 )
- {
- /* TODO: use the minimum possible bitrate instead of 0 ? */
- au_params |= 0;
- }
- else if( params->au_bitrate.target >=
- mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
- {
- /* clamp the bitrate to the max supported by the standard */
- params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
- }
- else
- {
- /* round up to the nearest supported bitrate */
- int i;
- for(i = 1; i < BITRATES_SIZE; i++)
- {
- if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
- params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
- {
- params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
- break;
- }
- }
- }
- }
- else
- {
- /* TODO: ??? */
- params->au_bitrate.target = params->au_bitrate.max = 0;
- au_params |= 0;
- }
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
-
- /* assign bitrates */
- if( params->vi_bitrate.mode )
- {
- /* bitrate is set, let's figure out the cbr/vbr mess */
- if( params->vi_bitrate.max < params->vi_bitrate.target )
- {
- if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
- params->vi_bitrate.max = params->vi_bitrate.target;
- else
- params->vi_bitrate.target = params->vi_bitrate.max;
- }
- }
- else
- {
- if( params->st_bitrate.max < params->st_bitrate.target )
- {
- if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
- params->st_bitrate.target = params->st_bitrate.max;
- else
- params->st_bitrate.max = params->st_bitrate.target;
- }
- /* calculate vi_bitrate = st_bitrate - au_bitrate */
- params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
- params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
- }
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
- mpeg_video_bitrates[params->vi_bitrate.mode],
- params->vi_bitrate.target * 1000, /* kbps -> bps */
- params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
- BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
-
- /* TODO: implement the stream ID stuff:
- ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
- ps_size, au_pesid, vi_pesid
- */
-}
-#define CHECK_PARAM( name ) ( dev->params.name != params->name )
-#define IF_PARAM( name ) if( CHECK_PARAM( name ) )
-#define UPDATE_PARAM( name ) dev->params.name = params->name
-void blackbird_set_params(struct cx8802_dev *dev, struct v4l2_mpeg_compression *params)
-{
- u32 au_params;
-
- /* assign stream type */
- if( params->st_type >= ARRAY_SIZE(mpeg_stream_types) )
- params->st_type = V4L2_MPEG_PS_2;
- if( params->st_type == V4L2_MPEG_SS_1 )
- params->vi_type = V4L2_MPEG_VI_1;
- else
- params->vi_type = V4L2_MPEG_VI_2;
- if( CHECK_PARAM( st_type ) || CHECK_PARAM( vi_type ) )
- {
- UPDATE_PARAM( st_type );
- UPDATE_PARAM( vi_type );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, mpeg_stream_types[params->st_type]);
- }
-
- /* assign framerate */
- if( params->vi_frame_rate <= 25 )
- params->vi_frame_rate = 25;
- else
- params->vi_frame_rate = 30;
- IF_PARAM( vi_frame_rate )
- {
- UPDATE_PARAM( vi_frame_rate );
- if( params->vi_frame_rate == 25 )
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
- else
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_NTSC_30);
- }
-
- /* assign aspect ratio */
- if( params->vi_aspect_ratio >= ARRAY_SIZE(mpeg_stream_ratios) )
- params->vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3;
- IF_PARAM( vi_aspect_ratio )
- {
- UPDATE_PARAM( vi_aspect_ratio );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, mpeg_stream_ratios[params->vi_aspect_ratio]);
- }
-
- /* assign gop properties */
- if( CHECK_PARAM( vi_frames_per_gop ) || CHECK_PARAM( vi_bframes_count ) )
- {
- UPDATE_PARAM( vi_frames_per_gop );
- UPDATE_PARAM( vi_bframes_count );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, params->vi_frames_per_gop, params->vi_bframes_count+1);
- }
-
- /* assign gop closure */
- IF_PARAM( closed_gops )
- {
- UPDATE_PARAM( closed_gops );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, params->closed_gops);
- }
-
- /* assign 3 2 pulldown */
- IF_PARAM( pulldown )
- {
- UPDATE_PARAM( pulldown );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, params->pulldown);
- }
-
- /* make sure the params are within bounds */
- if( params->st_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->vi_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->vi_bitrate.mode = V4L2_BITRATE_NONE;
- if( params->au_bitrate.mode >= ARRAY_SIZE(mpeg_video_bitrates) )
- params->au_bitrate.mode = V4L2_BITRATE_NONE;
-
- /* assign audio properties */
- /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- au_params = BLACKBIRD_AUDIO_BITS_STEREO |
- /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
- BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
- BLACKBIRD_AUDIO_BITS_CRC_OFF |
- BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
- BLACKBIRD_AUDIO_BITS_COPY |
- 0;
- if( params->au_sample_rate < 32000 )
- {
- params->au_sample_rate = 32000;
- au_params |= BLACKBIRD_AUDIO_BITS_32000HZ;
- }
- else if( params->au_sample_rate < 44100 )
- {
- params->au_sample_rate = 44100;
- au_params |= BLACKBIRD_AUDIO_BITS_44100HZ;
- }
- else
- {
- params->au_sample_rate = 48000;
- au_params |= BLACKBIRD_AUDIO_BITS_48000HZ;
- }
- if( params->au_type == V4L2_MPEG_AU_2_I )
- {
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_1;
- }
- else
- {
- /* TODO: try to handle the other formats more gracefully */
- params->au_type = V4L2_MPEG_AU_2_II;
- au_params |= BLACKBIRD_AUDIO_BITS_LAYER_2;
- }
- if( params->au_bitrate.mode )
- {
- int layer;
-
- if( params->au_bitrate.mode == V4L2_BITRATE_CBR )
- params->au_bitrate.max = params->vi_bitrate.target;
- else
- params->au_bitrate.target = params->vi_bitrate.max;
-
- layer = params->au_type;
- if( params->au_bitrate.target == 0 )
- {
- /* TODO: use the minimum possible bitrate instead of 0 ? */
- au_params |= 0;
- }
- else if( params->au_bitrate.target >=
- mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate )
- {
- /* clamp the bitrate to the max supported by the standard */
- params->au_bitrate.target = mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[BITRATES_SIZE-1].layer[layer].bits;
- }
- else
- {
- /* round up to the nearest supported bitrate */
- int i;
- for(i = 1; i < BITRATES_SIZE; i++)
- {
- if( params->au_bitrate.target > mpeg_audio_bitrates[i-1].layer[layer].rate &&
- params->au_bitrate.target <= mpeg_audio_bitrates[i].layer[layer].rate )
- {
- params->au_bitrate.target = mpeg_audio_bitrates[i].layer[layer].rate;
- params->au_bitrate.max = params->au_bitrate.target;
- au_params |= mpeg_audio_bitrates[i].layer[layer].bits;
- break;
- }
- }
- }
- }
- else
- {
- /* TODO: ??? */
- params->au_bitrate.target = params->au_bitrate.max = 0;
- au_params |= 0;
- }
- if( CHECK_PARAM( au_type ) || CHECK_PARAM( au_sample_rate )
- || CHECK_PARAM( au_bitrate.mode ) || CHECK_PARAM( au_bitrate.max )
- || CHECK_PARAM( au_bitrate.target )
- )
- {
- UPDATE_PARAM( au_type );
- UPDATE_PARAM( au_sample_rate );
- UPDATE_PARAM( au_bitrate );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0, au_params );
- }
-
- /* assign bitrates */
- if( params->vi_bitrate.mode )
- {
- /* bitrate is set, let's figure out the cbr/vbr mess */
- if( params->vi_bitrate.max < params->vi_bitrate.target )
- {
- if( params->vi_bitrate.mode == V4L2_BITRATE_CBR )
- params->vi_bitrate.max = params->vi_bitrate.target;
- else
- params->vi_bitrate.target = params->vi_bitrate.max;
- }
- }
- else
- {
- if( params->st_bitrate.max < params->st_bitrate.target )
- {
- if( params->st_bitrate.mode == V4L2_BITRATE_VBR )
- params->st_bitrate.target = params->st_bitrate.max;
- else
- params->st_bitrate.max = params->st_bitrate.target;
- }
- /* calculate vi_bitrate = st_bitrate - au_bitrate */
- params->vi_bitrate.max = params->st_bitrate.max - params->au_bitrate.max;
- params->vi_bitrate.target = params->st_bitrate.target - params->au_bitrate.target;
- }
- UPDATE_PARAM( st_bitrate );
- if( CHECK_PARAM( vi_bitrate.mode ) || CHECK_PARAM( vi_bitrate.max )
- || CHECK_PARAM( vi_bitrate.target )
- )
- {
- UPDATE_PARAM( vi_bitrate );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 4, 0,
- mpeg_video_bitrates[params->vi_bitrate.mode],
- params->vi_bitrate.target * 1000, /* kbps -> bps */
- params->vi_bitrate.max * 1000 / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
- BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
- }
-
- /* TODO: implement the stream ID stuff:
- ts_pid_pmt, ts_pid_audio, ts_pid_video, ts_pid_pcr,
- ps_size, au_pesid, vi_pesid
- */
- UPDATE_PARAM( ts_pid_pmt );
- UPDATE_PARAM( ts_pid_audio );
- UPDATE_PARAM( ts_pid_video );
- UPDATE_PARAM( ts_pid_pcr );
- UPDATE_PARAM( ps_size );
- UPDATE_PARAM( au_pesid );
- UPDATE_PARAM( vi_pesid );
-}
-
-static void blackbird_set_default_dnr_params(struct cx8802_dev *dev)
-{
- /* assign dnr filter mode */
- if( dev->dnr_params.mode > BLACKBIRD_DNR_BITS_AUTO )
- dev->dnr_params.mode = BLACKBIRD_DNR_BITS_MANUAL;
- if( dev->dnr_params.type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
- dev->dnr_params.type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
- dev->dnr_params.mode,
- dev->dnr_params.type
- );
-
- /* assign dnr filter props*/
- if( dev->dnr_params.spatial > 15 )
- dev->dnr_params.spatial = 15;
- if( dev->dnr_params.temporal > 31 )
- dev->dnr_params.temporal = 31;
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0,
- dev->dnr_params.spatial,
- dev->dnr_params.temporal
- );
-}
-#define CHECK_DNR_PARAM( name ) ( dev->dnr_params.name != dnr_params->name )
-#define UPDATE_DNR_PARAM( name ) dev->dnr_params.name = dnr_params->name
-void blackbird_set_dnr_params(struct cx8802_dev *dev, struct blackbird_dnr* dnr_params)
-{
- /* assign dnr filter mode */
- /* clamp values */
- if( dnr_params->mode > BLACKBIRD_DNR_BITS_AUTO )
- dnr_params->mode = BLACKBIRD_DNR_BITS_MANUAL;
- if( dnr_params->type > BLACKBIRD_MEDIAN_FILTER_DIAGONAL )
- dnr_params->type = BLACKBIRD_MEDIAN_FILTER_DISABLED;
- /* check if the params actually changed */
- if( CHECK_DNR_PARAM( mode ) || CHECK_DNR_PARAM( type ) )
- {
- UPDATE_DNR_PARAM( mode );
- UPDATE_DNR_PARAM( type );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0, dnr_params->mode, dnr_params->type);
- }
-
- /* assign dnr filter props*/
- if( dnr_params->spatial > 15 )
- dnr_params->spatial = 15;
- if( dnr_params->temporal > 31 )
- dnr_params->temporal = 31;
- if( CHECK_DNR_PARAM( spatial ) || CHECK_DNR_PARAM( temporal ) )
- {
- UPDATE_DNR_PARAM( spatial );
- UPDATE_DNR_PARAM( temporal );
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, dnr_params->spatial, dnr_params->temporal);
- }
-}
-
-static void blackbird_codec_settings(struct cx8802_dev *dev)
-{
-
- /* assign output port */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
-
- /* assign frame size */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
- dev->height, dev->width);
-
- /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
-
- /* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
- BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
- BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
- );
-
- /* assign frame drop rate */
- /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
-
- blackbird_set_default_params(dev);
- blackbird_set_default_dnr_params(dev);
-}
-
static int blackbird_initialize_codec(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
int retval;
dprintk(1,"Initialize codec\n");
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
/* ping was not successful, reset and upload firmware */
cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
if (dev->mailbox < 0)
return -1;
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");
return -1;
}
- retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
+ retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version);
if (retval < 0) {
dprintk(0, "ERROR: Firmware get encoder version failed!\n");
return -1;
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
BLACKBIRD_FIELD1_SAA7115,
- BLACKBIRD_FIELD1_SAA7115
+ BLACKBIRD_FIELD2_SAA7115
);
/* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
- blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+ blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
/* initialize the video input */
- blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0);
+ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
msleep(1);
- blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
+ blackbird_api_cmd(dev, CX2341X_ENC_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
- blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
+ blackbird_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
/* start capturing to the host interface */
- /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); */
- blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+ /* blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, 0, 0x13); */
+ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE
);
msleep(10);
- blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
+ blackbird_api_cmd(dev, CX2341X_ENC_REFRESH_INPUT, 0,0);
return 0;
}
{
struct v4l2_mpeg_compression *f = arg;
- memcpy(f,&dev->params,sizeof(*f));
+ 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_mpeg_compression *f = arg;
+ struct v4l2_ext_controls *f = arg;
- blackbird_set_params(dev, f);
+ 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;
}
{
struct cx8802_fh *fh = file->private_data;
- /* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
- blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+ /* blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+ blackbird_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
BLACKBIRD_END_NOW,
BLACKBIRD_MPEG_CAPTURE,
BLACKBIRD_RAW_BITS_NONE
);
+ cx8802_cancel_buffers(fh->dev);
/* stop mpeg capture */
if (fh->mpegq.streaming)
videobuf_streamoff(&fh->mpegq);
dev->core = core;
dev->width = 720;
dev->height = 576;
- memcpy(&dev->params,&default_mpeg_params,sizeof(default_mpeg_params));
- memcpy(&dev->dnr_params,&default_dnr_params,sizeof(default_dnr_params));
-
- if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN) {
-
- if (core->tuner_formats & V4L2_STD_525_60) {
- dev->height = 480;
- dev->params.vi_frame_rate = 30;
- } else {
- dev->height = 576;
- dev->params.vi_frame_rate = 25;
- }
+ cx2341x_fill_defaults(&dev->params);
+ dev->params.port = CX2341X_PORT_STREAMING;
+ if (core->tvnorm->id & V4L2_STD_525_60) {
+ dev->height = 480;
+ } else {
+ dev->height = 576;
}
err = cx8802_init_common(dev);
EXPORT_SYMBOL(cx88_ioctl_hook);
EXPORT_SYMBOL(cx88_ioctl_translator);
-EXPORT_SYMBOL(blackbird_set_params);
-EXPORT_SYMBOL(blackbird_set_dnr_params);
/* ----------------------------------------------------------- */
/*
.radio = {
.type = CX88_RADIO,
.gpio0 = 0xff10,
- },
+ },
},
[CX88_BOARD_ATI_WONDER_PRO] = {
.name = "ATI TV Wonder Pro",
.gpio1 = 0x00007004,
.gpio2 = 0x0035d700,
.gpio3 = 0x02000000,
- },
+ },
},
[CX88_BOARD_LEADTEK_PVR2000] = {
// gpio values for PAL version from regspy by DScaler
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
.gpio0 = 0x000027df,
- },{
+ },{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
.gpio0 = 0x000027df,
},
[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
.name = "DViCO FusionHDTV 5 Gold",
- .tuner_type = TUNER_LG_TDVS_H062F,
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H062F */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.dvb = 1,
},
[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
- /* FIXME: Standard video using the cx88 broadcast decoder is
- * working, but blackbird isn't working yet, audio is only
- * working correctly for television mode. S-Video and Composite
- * are working for video-only, so I have them disabled for now.
- */
+ /* FIXME: Audio not working for s-video / composite inputs. */
.name = "KWorld HardwareMpegTV XPert",
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
.vmux = 0,
.gpio0 = 0x3de2,
.gpio2 = 0x00ff,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x3de6,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x3de6,
}},
.radio = {
.type = CX88_RADIO,
.gpio0 = 0x3de6,
.gpio2 = 0x00ff,
},
+ .blackbird = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
.name = "DViCO FusionHDTV DVB-T Hybrid",
}},
.dvb = 1,
},
-
+ [CX88_BOARD_PCHDTV_HD5500] = {
+ .name = "pcHDTV HD5500 HDTV",
+ .tuner_type = TUNER_LG_TDVS_H06XF, /* TDVS-H064F */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x87fd,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x87f9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x87f9,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_KWORLD_MCE200_DELUXE] = {
+ /* FIXME: tested TV input only, disabled composite,
+ svideo and radio until they can be tested also. */
+ .name = "Kworld MCE 200 Deluxe",
+ .tuner_type = TUNER_TENA_9533_DI,
+ .radio_type = UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0000BDE6
+ }},
+ .blackbird = 1,
+ },
+ [CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
+ /* FIXME: SVideo, Composite and FM inputs are untested */
+ .name = "PixelView PlayTV P7000",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE |
+ TDA9887_PORT2_ACTIVE,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x5da6,
+ }},
+ .blackbird = 1,
+ },
+ [CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
+ .name = "NPG Tech Real TV FM Top 10",
+ .tuner_type = TUNER_TNF_5335MF, /* Actually a TNF9535 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0788,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x078b,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x078b,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x074a,
+ },
+ },
+ [CX88_BOARD_WINFAST_DTV2000H] = {
+ /* video inputs and radio still in testing */
+ .name = "WinFast DTV2000 H",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00017304,
+ .gpio1 = 0x00008203,
+ .gpio2 = 0x00017304,
+ .gpio3 = 0x02000000,
+ }},
+ .dvb = 1,
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
.subvendor = 0x18ac,
.subdevice = 0xdb44,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID,
+ },{
+ .subvendor = 0x7063,
+ .subdevice = 0x5500,
+ .card = CX88_BOARD_PCHDTV_HD5500,
+ },{
+ .subvendor = 0x17de,
+ .subdevice = 0x0841,
+ .card = CX88_BOARD_KWORLD_MCE200_DELUXE,
+ },{
+ .subvendor = 0x1822,
+ .subdevice = 0x0019,
+ .card = CX88_BOARD_DNTV_LIVE_DVB_T_PRO,
+ },{
+ .subvendor = 0x1554,
+ .subdevice = 0x4813,
+ .card = CX88_BOARD_PIXELVIEW_PLAYTV_P7000,
+ },{
+ .subvendor = 0x14f1,
+ .subdevice = 0x0842,
+ .card = CX88_BOARD_NPGTECH_REALTV_TOP10FM,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x665e,
+ .card = CX88_BOARD_WINFAST_DTV2000H,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd800, /* FusionHDTV 3 Gold (original revision) */
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
static unsigned int inline norm_vbipack(struct cx88_tvnorm *norm)
{
- return (norm->id & V4L2_STD_625_50) ? 511 : 288;
+ return (norm->id & V4L2_STD_625_50) ? 511 : 400;
}
int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height,
htotal, cx_read(MO_HTOTAL), (u32)tmp64);
cx_write(MO_HTOTAL, htotal);
- // vbi stuff
- cx_write(MO_VBI_PACKET, ((1 << 11) | /* (norm_vdelay(norm) << 11) | */
- norm_vbipack(norm)));
+ // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes
+ // the effective vbi offset ~244 samples, the same as the Bt8x8
+ cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm));
// this is needed as well to set all tvnorm parameter
cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED);
#endif
#ifdef HAVE_LGDT330X
# include "lgdt330x.h"
+# include "lg_h06xf.h"
#endif
#ifdef HAVE_NXT200X
# include "nxt200x.h"
#ifdef HAVE_CX24123
# include "cx24123.h"
#endif
+#include "isl6421.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
/* ------------------------------------------------------------------ */
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
-static int zarlink_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *pllbuf)
-{
- struct cx8802_dev *dev = fe->dvb->priv;
-
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
- params->frequency,
- params->u.ofdm.bandwidth);
- return 0;
-}
-#endif
-
#ifdef HAVE_MT352
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
static struct mt352_config dvico_fusionhdtv = {
.demod_address = 0x0F,
.demod_init = dvico_fusionhdtv_demod_init,
- .pll_set = zarlink_pll_set,
};
static struct mt352_config dntv_live_dvbt_config = {
.demod_address = 0x0f,
.demod_init = dntv_live_dvbt_demod_init,
- .pll_set = zarlink_pll_set,
};
static struct mt352_config dvico_fusionhdtv_dual = {
.demod_address = 0x0F,
.demod_init = dvico_dual_demod_init,
- .pll_set = zarlink_pll_set,
};
#ifdef HAVE_VP3054_I2C
.buf = fmd1216_init, .len = sizeof(fmd1216_init) };
int err;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
if (err < 0)
return err;
return 0;
}
-static int dntv_live_dvbt_pro_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
+static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
struct cx8802_dev *dev= fe->dvb->priv;
+ u8 buf[4];
struct i2c_msg msg =
{ .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf+1, .len = 4 };
+ .buf = buf, .len = 4 };
int err;
/* Switch PLL to DVB mode */
return err;
/* Tune PLL */
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf+1,
+ dvb_pll_configure(dev->core->pll_desc, buf,
params->frequency,
params->u.ofdm.bandwidth);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
+
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ __FUNCTION__, dev->core->pll_addr, buf[0], err);
if (err < 0)
return err;
else
.demod_address = 0x0f,
.no_tuner = 1,
.demod_init = dntv_live_dvbt_pro_demod_init,
- .pll_set = dntv_live_dvbt_pro_pll_set,
};
#endif
#endif
#ifdef HAVE_ZL10353
-static int dvico_hybrid_tune_pll(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params,
- u8 *pllbuf)
+static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
{
+ u8 pllbuf[4];
struct cx8802_dev *dev= fe->dvb->priv;
struct i2c_msg msg =
{ .addr = dev->core->pll_addr, .flags = 0,
- .buf = pllbuf + 1, .len = 4 };
+ .buf = pllbuf, .len = 4 };
int err;
- pllbuf[0] = dev->core->pll_addr << 1;
- dvb_pll_configure(dev->core->pll_desc, pllbuf + 1,
+ dvb_pll_configure(dev->core->pll_desc, pllbuf,
params->frequency,
params->u.ofdm.bandwidth);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
static struct zl10353_config dvico_fusionhdtv_hybrid = {
.demod_address = 0x0F,
- .pll_set = dvico_hybrid_tune_pll,
+ .no_tuner = 1,
};
static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
.demod_address = 0x0F,
- .pll_set = zarlink_pll_set,
};
#endif
static struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x60,
- .pll_desc = &dvb_pll_thomson_dtt7579,
};
static struct cx22702_config hauppauge_novat_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt759x,
};
static struct cx22702_config hauppauge_hvr1100_config = {
.demod_address = 0x63,
.output_mode = CX22702_SERIAL_OUTPUT,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_fmd1216me,
};
#endif
static struct or51132_config pchdtv_hd3000 = {
.demod_address = 0x15,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_thomson_dtt761x,
.set_ts_params = or51132_set_ts_param,
};
#endif
#ifdef HAVE_LGDT330X
-static int lgdt330x_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
/* FIXME make this routine use the tuner-simple code.
* It could probably be shared with a number of ATSC
{ .addr = dev->core->pll_addr, .flags = 0, .buf = buf, .len = 4 };
int err;
- /* Put the analog decoder in standby to keep it quiet */
- cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
-
dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
__FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
"(addr %02x <- %02x, err = %i)\n",
else
return -EREMOTEIO;
}
- if (core->tuner_type == TUNER_LG_TDVS_H062F) {
- /* Set the Auxiliary Byte. */
- buf[2] &= ~0x20;
- buf[2] |= 0x18;
- buf[3] = 0x50;
- i2c_transfer(&core->i2c_adap, &msg, 1);
- }
return 0;
}
+static int lgdt3303_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ /* Put the analog decoder in standby to keep it quiet */
+ cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
+
+ return lg_h06xf_pll_set(fe, &core->i2c_adap, params);
+}
+
static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
{
struct cx8802_dev *dev= fe->dvb->priv;
.demod_address = 0x0e,
.demod_chip = LGDT3302,
.serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
- .pll_set = lgdt330x_pll_set,
.set_ts_params = lgdt330x_set_ts_param,
};
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .pll_set = lgdt330x_pll_set,
+ .set_ts_params = lgdt330x_set_ts_param,
+};
+
+static struct lgdt330x_config pchdtv_hd5500 = {
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
.set_ts_params = lgdt330x_set_ts_param,
};
#endif
static struct nxt200x_config ati_hdtvwonder = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tuv1236d,
.set_pll_input = nxt200x_set_pll_input,
.set_ts_params = nxt200x_set_ts_param,
};
return 0;
}
-static void cx24123_enable_lnb_voltage(struct dvb_frontend* fe, int on)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
- if (on)
- cx_write(MO_GP0_IO, 0x000006f9);
- else
+ if (voltage == SEC_VOLTAGE_OFF) {
cx_write(MO_GP0_IO, 0x000006fB);
+ } else {
+ cx_write(MO_GP0_IO, 0x000006f9);
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
}
static struct cx24123_config hauppauge_novas_config = {
.demod_address = 0x55,
- .use_isl6421 = 1,
.set_ts_params = cx24123_set_ts_param,
};
static struct cx24123_config kworld_dvbs_100_config = {
.demod_address = 0x15,
- .use_isl6421 = 0,
.set_ts_params = cx24123_set_ts_param,
- .enable_lnb_voltage = cx24123_enable_lnb_voltage,
};
#endif
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt759x);
+ }
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
case CX88_BOARD_WINFAST_DTV1000:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
break;
+ case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_fmd1216me);
+ }
break;
#endif
#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- dev->core->pll_addr = 0x60;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
#ifdef HAVE_MT352
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
- if (dev->dvb.frontend != NULL)
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
break;
+ }
#endif
#ifdef HAVE_ZL10353
/* ZL10353 replaces MT352 on later cards */
dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
+#endif
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+#ifdef HAVE_MT352
+ /* The tin box says DEE1601, but it seems to be DTT7579
+ * compatible, with a slightly different MT352 AGC gain. */
+ dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ break;
+ }
+#endif
+#ifdef HAVE_ZL10353
+ /* ZL10353 replaces MT352 on later cards */
+ dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
+ }
#endif
break;
#endif /* HAVE_MT352 || HAVE_ZL10353 */
#ifdef HAVE_MT352
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_lg_z201;
dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_lg_z201);
+ }
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_ADSTECH_DVB_T_PCI:
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_unknown_1;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_unknown_1);
+ }
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#ifdef HAVE_VP3054_I2C
dev->core->pll_desc = &dvb_pll_fmd1216me;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
+ }
#else
printk("%s: built without vp3054 support\n", dev->core->name);
#endif
break;
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
- /* The tin box says DEE1601, but it seems to be DTT7579
- * compatible, with a slightly different MT352 AGC gain. */
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_thomson_dtt7579;
- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
- &dev->core->i2c_adap);
- break;
#endif
#ifdef HAVE_ZL10353
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
dev->core->pll_desc = &dvb_pll_thomson_fe6600;
dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
+ }
break;
#endif
#ifdef HAVE_OR51132
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt761x);
+ }
break;
#endif
#ifdef HAVE_LGDT330X
dev->core->pll_desc = &dvb_pll_microtune_4042;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
+ }
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->core->pll_addr = 0x61;
- dev->core->pll_desc = &dvb_pll_tdvs_tua6034;
dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
+ }
+ break;
+ case CX88_BOARD_PCHDTV_HD5500:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 1);
+ mdelay(200);
+ dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
+ }
}
break;
#endif
case CX88_BOARD_ATI_HDTVWONDER:
dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_tuv1236d);
+ }
break;
#endif
#ifdef HAVE_CX24123
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
+ 0x08, 0x00, 0x00);
+ }
break;
case CX88_BOARD_KWORLD_DVBS_100:
dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
&dev->core->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
+ dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
+ }
break;
#endif
default:
}
if (dev->core->pll_desc) {
- dev->dvb.frontend->ops->info.frequency_min = dev->core->pll_desc->min;
- dev->dvb.frontend->ops->info.frequency_max = dev->core->pll_desc->max;
+ dev->dvb.frontend->ops.info.frequency_min = dev->core->pll_desc->min;
+ dev->dvb.frontend->ops.info.frequency_max = dev->core->pll_desc->max;
}
/* Put the analog decoder in standby to keep it quiet */
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
/* register everything */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
}
/* ----------------------------------------------------------- */
return;
if (core->dvbdev) {
- if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
i2c_clients_command(&core->i2c_adap, cmd, arg);
- if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
- core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+ if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
+ core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
} else
i2c_clients_command(&core->i2c_adap, cmd, arg);
}
static void cx88_ir_handle_key(struct cx88_IR *ir)
{
struct cx88_core *core = ir->core;
- u32 gpio, data;
+ u32 gpio, data, auxgpio;
/* read gpio value */
gpio = cx_read(ir->gpio_addr);
+ if (core->board == CX88_BOARD_NPGTECH_REALTV_TOP10FM) {
+ /* This board apparently uses a combination of 2 GPIO
+ to represent the keys. Additionally, the second GPIO
+ can be used for parity.
+
+ Example:
+
+ for key "5"
+ gpio = 0x758, auxgpio = 0xe5 or 0xf5
+ for key "Power"
+ gpio = 0x758, auxgpio = 0xed or 0xfd
+ */
+
+ auxgpio = cx_read(MO_GP1_IO);
+ /* Take out the parity part */
+ gpio+=(gpio & 0x7fd) + (auxgpio & 0xef);
+ } else
+ auxgpio = gpio;
+
if (ir->polling) {
- if (ir->last_gpio == gpio)
+ if (ir->last_gpio == auxgpio)
return;
- ir->last_gpio = gpio;
+ ir->last_gpio = auxgpio;
}
/* extract data */
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
+ case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_WINFAST2000XP_EXPERT:
ir_codes = ir_codes_winfast;
ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
ir->mask_keyup = 0x100;
- ir->polling = 1; /* ms */
+ ir->polling = 50; /* ms */
break;
case CX88_BOARD_IODATA_GVBCTV7E:
ir_codes = ir_codes_iodata_bctv7e;
ir_type = IR_TYPE_PD;
ir->sampling = 0xff00; /* address */
break;
+ case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
+ ir_codes = ir_codes_npgtech;
+ ir->gpio_addr = MO_GP0_IO;
+ ir->mask_keycode = 0xfa;
+ ir->polling = 50; /* ms */
+ break;
}
if (NULL == ir_codes) {
{
struct cx88_core *core = dev->core;
- dprintk(0, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
+ dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", dev->width, dev->height, buf->vb.field);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
+ case CX88_BOARD_PCHDTV_HD5500:
cx_write(TS_SOP_STAT, 1<<13);
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
q->count = 1;
/* enable irqs */
- dprintk( 0, "setting the interrupt mask\n" );
+ dprintk( 1, "setting the interrupt mask\n" );
cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
cx_set(MO_TS_INTMSK, 0x1f0011);
static int cx8802_stop_dma(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
- dprintk( 0, "cx8802_stop_dma\n" );
+ dprintk( 1, "cx8802_stop_dma\n" );
/* stop dma */
cx_clear(MO_TS_DMACNTRL, 0x11);
struct cx88_buffer *buf;
struct list_head *item;
- dprintk( 0, "cx8802_restart_queue\n" );
+ dprintk( 1, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
{
- dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
+ struct cx88_buffer *prev;
+ prev = NULL;
+
+ dprintk(1, "cx8802_restart_queue: queue is empty\n" );
+
+ for (;;) {
+ if (list_empty(&q->queued))
+ return 0;
+ buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
+ if (NULL == prev) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ cx8802_start_dma(dev, q, buf);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(1,"[%p/%d] restart_queue - first active\n",
+ buf,buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue,&q->active);
+ buf->vb.state = STATE_ACTIVE;
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(1,"[%p/%d] restart_queue - move to active\n",
+ buf,buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
return 0;
}
buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
if (list_empty(&cx88q->active)) {
- dprintk( 0, "queue is empty - first active\n" );
+ dprintk( 1, "queue is empty - first active\n" );
list_add_tail(&buf->vb.queue,&cx88q->active);
cx8802_start_dma(dev, cx88q, buf);
buf->vb.state = STATE_ACTIVE;
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(0,"[%p/%d] %s - first active\n",
+ dprintk(1,"[%p/%d] %s - first active\n",
buf, buf->vb.i, __FUNCTION__);
} else {
}
if (restart)
{
- dprintk(0, "restarting queue\n" );
+ dprintk(1, "restarting queue\n" );
cx8802_restart_queue(dev,q);
}
spin_unlock_irqrestore(&dev->slock,flags);
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
+#include <linux/config.h>
#include <linux/kthread.h>
#include "cx88.h"
{
u32 volume;
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
/* restart dma; This avoids buzz in NICAM and is good in others */
cx88_stop_audio_dma(core);
#endif
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
-#ifndef USING_CX88_ALSA
+#ifndef CONFIG_VIDEO_CX88_ALSA
cx88_start_audio_dma(core);
#endif
if (cx88_boards[core->board].blackbird) {
/* sets sound input from external adc */
- if (core->board == CX88_BOARD_HAUPPAUGE_ROSLYN)
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_ROSLYN:
+ case CX88_BOARD_KWORLD_MCE200_DELUXE:
+ case CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT:
+ case CX88_BOARD_PIXELVIEW_PLAYTV_P7000:
+ case CX88_BOARD_ASUS_PVR_416:
cx_clear(AUD_CTL, EN_I2SIN_ENABLE);
- else
+ break;
+ default:
cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+ }
cx_write(AUD_I2SINPUTCNTL, 4);
cx_write(AUD_BAUDRATE, 1);
if (dev->core->tvnorm->id & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
- f->fmt.vbi.start[0] = 10 -1;
- f->fmt.vbi.start[1] = 273 -1;
+ f->fmt.vbi.start[0] = 10;
+ f->fmt.vbi.start[1] = 273;
} else if (dev->core->tvnorm->id & V4L2_STD_625_50) {
/* pal */
#include <linux/videodev2.h>
#include <linux/kdev_t.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/video-buf.h>
+#include <media/cx2341x.h>
#include <media/video-buf-dvb.h>
#include "btcx-risc.h"
#include <linux/version.h>
#include <linux/mutex.h>
-#define CX88_VERSION_CODE KERNEL_VERSION(0,0,5)
+#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
#ifndef TRUE
# define TRUE (1==1)
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44
#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46
+#define CX88_BOARD_PCHDTV_HD5500 47
+#define CX88_BOARD_KWORLD_MCE200_DELUXE 48
+#define CX88_BOARD_PIXELVIEW_PLAYTV_P7000 49
+#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
+#define CX88_BOARD_WINFAST_DTV2000H 51
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
/* config info -- dvb */
struct dvb_pll_desc *pll_desc;
unsigned int pll_addr;
+ int (*prev_set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
/* state info */
struct task_struct *kthread;
int disabled;
};
-/* TODO: move this to struct v4l2_mpeg_compression ? */
-struct blackbird_dnr {
- u32 mode;
- u32 type;
- u32 spatial;
- u32 temporal;
-};
-
struct cx8802_dev {
struct cx88_core *core;
spinlock_t slock;
unsigned char ts_gen_cntrl;
/* mpeg params */
- struct v4l2_mpeg_compression params;
- struct blackbird_dnr dnr_params;
+ struct cx2341x_mpeg_params params;
};
/* ----------------------------------------------------------- */
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);
-void blackbird_set_params(struct cx8802_dev *dev,
- struct v4l2_mpeg_compression *params);
-void blackbird_set_dnr_params(struct cx8802_dev *dev,
- struct blackbird_dnr* dnr_params);
/*
* Local variables:
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
#include <linux/usb.h>
#include <media/tuner.h>
#include <media/msp3400.h>
+#include <media/saa7115.h>
+#include <media/tvp5150.h>
#include <media/tveeprom.h>
#include <media/audiochip.h>
#include <media/v4l2-common.h>
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 1,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
/*FIXME: S-Video not tested */
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 0,
+ .vmux = TVP5150_COMPOSITE0,
.amux = MSP_INPUT_DEFAULT,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 2,
+ .vmux = TVP5150_SVIDEO,
.amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1,
MSP_DSP_IN_SCART, MSP_DSP_IN_SCART),
}},
.decoder = EM28XX_SAA7114,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 4,
+ .vmux = SAA7115_COMPOSITE4,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_TELEVISION,
- .vmux = 2,
+ .vmux = SAA7115_COMPOSITE2,
.amux = 0,
},{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
.decoder = EM28XX_SAA7113,
.input = {{
.type = EM28XX_VMUX_COMPOSITE1,
- .vmux = 0,
+ .vmux = SAA7115_COMPOSITE0,
.amux = 1,
},{
.type = EM28XX_VMUX_SVIDEO,
- .vmux = 9,
+ .vmux = SAA7115_SVIDEO3,
.amux = 1,
}},
},
}
}
-EXPORT_SYMBOL(em28xx_boards);
-EXPORT_SYMBOL(em28xx_bcount);
-EXPORT_SYMBOL(em28xx_id_table);
-
MODULE_DEVICE_TABLE (usb, em28xx_id_table);
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
}
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
- u8 ymax)
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+ u8 ymin, u8 ymax)
{
em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
}
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u16 width, u16 height)
{
u8 cwidth = width;
return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
}
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
* em28xx_isoIrq()
* handles the incoming isoc urbs and fills the frames from our inqueue
*/
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
{
struct em28xx *dev = urb->context;
int i, status;
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
return I2C_FUNC_SMBUS_EMUL;
}
-#ifndef I2C_PEC
-static void inc_use(struct i2c_adapter *adap)
-{
- MOD_INC_USE_COUNT;
-}
-
-static void dec_use(struct i2c_adapter *adap)
-{
- MOD_DEC_USE_COUNT;
-}
-#endif
static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client)
{
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x86:
+ case 0x43:
+ case 0x4b:
+ {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
em28xx_i2c_call_clients(dev, TDA9887_SET_CONFIG, &dev->tda9887_conf);
break;
+ }
case 0x42:
dprintk1(1,"attach_inform: saa7114 detected.\n");
break;
case 0xba:
dprintk1(1,"attach_inform: tvp5150 detected.\n");
break;
+
default:
dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
dev->tuner_addr = client->addr;
};
static struct i2c_adapter em28xx_adap_template = {
-#ifdef I2C_PEC
.owner = THIS_MODULE,
-#else
- .inc_use = inc_use,
- .dec_use = dec_use,
-#endif
.class = I2C_CLASS_TV_ANALOG,
.name = "em28xx",
.id = I2C_HW_B_EM28XX,
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
This program is free software; you can redistribute it and/or modify
return 1;
}
-static int get_key_pinnacle_usb(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Terratec)");
break;
case (EM2820_BOARD_PINNACLE_USB_2):
- ir->ir_codes = ir_codes_em_pinnacle_usb;
- ir->get_key = get_key_pinnacle_usb;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ ir->get_key = get_key_pinnacle_usb_grey;
snprintf(ir->c.name, sizeof(ir->c.name), "i2c IR (EM28XX Pinnacle PCTV)");
break;
case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2):
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Sascha Sommer <saschasommer@freenet.de>
Some parts based on SN9C10x PC Camera Controllers GPL driver made
#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
"Markus Rechberger <mrechberger@gmail.com>, " \
- "Mauro Carvalho Chehab <mchehab@brturbo.com.br>, " \
+ "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
"Sascha Sommer <saschasommer@freenet.de>"
#define DRIVER_NAME "em28xx"
static void em28xx_config_i2c(struct em28xx *dev)
{
struct v4l2_frequency f;
+ struct v4l2_routing route;
+
+ route.input = INPUT(dev->ctl_input)->vmux;
+ route.output = 0;
em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL);
- em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
/* configure tuner */
static void video_mux(struct em28xx *dev, int index)
{
- int input, ainput;
+ int ainput;
+ struct v4l2_routing route;
- input = INPUT(index)->vmux;
+ route.input = INPUT(index)->vmux;
+ route.output = 0;
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
- em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
- em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput);
+ em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,route.input,dev->ctl_ainput);
if (dev->has_msp34xx) {
- struct v4l2_routing route;
-
if (dev->i2s_speed)
em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
route.input = dev->ctl_ainput;
Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com>
Ludovico Cavedon <cavedon@sssup.it>
- Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ Mauro Carvalho Chehab <mchehab@infradead.org>
Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de>
int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
int em28xx_outfmt_set_yuv422(struct em28xx *dev);
-int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, u8 ymin,
- u8 ymax);
-int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
- u16 width, u16 height);
-int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v);
int em28xx_resolution_set(struct em28xx *dev);
-void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs);
int em28xx_init_isoc(struct em28xx *dev);
void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
case VIDIOC_G_CTRL:
return et61x251_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return et61x251_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return et61x251_vidioc_cropcap(cam, arg);
case VIDIOC_G_PARM:
return et61x251_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return et61x251_vidioc_s_parm(cam, arg);
return 1;
}
-/* The new pinnacle PCTV remote (with the colored buttons)
+/* Common (grey or coloured) pinnacle PCTV remote handling
*
- * Ricardo Cerqueira <v4l@cerqueira.org>
*/
-
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw,
+ int parity_offset, int marker, int code_modulo)
{
unsigned char b[4];
unsigned int start = 0,parity = 0,code = 0;
}
for (start = 0; start<4; start++) {
- if (b[start] == 0x80) {
- code=b[(start+3)%4];
- parity=b[(start+2)%4];
+ if (b[start] == marker) {
+ code=b[(start+parity_offset+1)%4];
+ parity=b[(start+parity_offset)%4];
}
}
if (ir->old == parity)
return 0;
-
ir->old = parity;
- /* Reduce code value to fit inside IR_KEYTAB_SIZE
- *
- * this is the only value that results in 42 unique
- * codes < 128
- */
+ /* drop special codes when a key is held down a long time for the grey controller
+ In this case, the second bit of the code is asserted */
+ if (marker == 0xfe && (code & 0x40))
+ return 0;
- code %= 0x88;
+ code %= code_modulo;
*ir_raw = code;
*ir_key = code;
return 1;
}
-EXPORT_SYMBOL_GPL(get_key_pinnacle);
+/* The grey pinnacle PCTV remote
+ *
+ * There are one issue with this remote:
+ * - I2c packet does not change when the same key is pressed quickly. The workaround
+ * is to hold down each key for about half a second, so that another code is generated
+ * in the i2c packet, and the function can distinguish key presses.
+ *
+ * Sylvain Pasche <sylvain.pasche@gmail.com>
+ */
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 1, 0xfe, 0xff);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_grey);
+
+
+/* The new pinnacle PCTV remote (with the colored buttons)
+ *
+ * Ricardo Cerqueira <v4l@cerqueira.org>
+ */
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ /* code_modulo parameter (0x88) is used to reduce code value to fit inside IR_KEYTAB_SIZE
+ *
+ * this is the only value that results in 42 unique
+ * codes < 128
+ */
+
+ return get_key_pinnacle(ir, ir_key, ir_raw, 2, 0x80, 0x88);
+}
+
+EXPORT_SYMBOL_GPL(get_key_pinnacle_color);
/* ----------------------------------------------------------------------- */
--- /dev/null
+/*
+ * Video Capture Driver (Video for Linux 1/2)
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *****************************************************************************
+ *
+ * Modified and extended by
+ * Mike Bernson <mike@mlb.org>
+ * Gerard v.d. Horst
+ * Leon van Stuivenberg <l.vanstuivenberg@chello.nl>
+ * Gernot Ziegler <gz@lysator.liu.se>
+ *
+ * Version History:
+ * V1.0 Ryan Drake Initial version by Ryan Drake
+ * V1.1 Gerard v.d. Horst Added some debugoutput, reset the video-standard
+ */
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include "ks0127.h"
+
+#include <linux/i2c.h>
+#include <linux/video_decoder.h>
+
+#define dprintk if (debug) printk
+
+/* i2c identification */
+#define I2C_KS0127_ADDON 0xD8
+#define I2C_KS0127_ONBOARD 0xDA
+
+#define KS_TYPE_UNKNOWN 0
+#define KS_TYPE_0122S 1
+#define KS_TYPE_0127 2
+#define KS_TYPE_0127B 3
+
+/* ks0127 control registers */
+#define KS_STAT 0x00
+#define KS_CMDA 0x01
+#define KS_CMDB 0x02
+#define KS_CMDC 0x03
+#define KS_CMDD 0x04
+#define KS_HAVB 0x05
+#define KS_HAVE 0x06
+#define KS_HS1B 0x07
+#define KS_HS1E 0x08
+#define KS_HS2B 0x09
+#define KS_HS2E 0x0a
+#define KS_AGC 0x0b
+#define KS_HXTRA 0x0c
+#define KS_CDEM 0x0d
+#define KS_PORTAB 0x0e
+#define KS_LUMA 0x0f
+#define KS_CON 0x10
+#define KS_BRT 0x11
+#define KS_CHROMA 0x12
+#define KS_CHROMB 0x13
+#define KS_DEMOD 0x14
+#define KS_SAT 0x15
+#define KS_HUE 0x16
+#define KS_VERTIA 0x17
+#define KS_VERTIB 0x18
+#define KS_VERTIC 0x19
+#define KS_HSCLL 0x1a
+#define KS_HSCLH 0x1b
+#define KS_VSCLL 0x1c
+#define KS_VSCLH 0x1d
+#define KS_OFMTA 0x1e
+#define KS_OFMTB 0x1f
+#define KS_VBICTL 0x20
+#define KS_CCDAT2 0x21
+#define KS_CCDAT1 0x22
+#define KS_VBIL30 0x23
+#define KS_VBIL74 0x24
+#define KS_VBIL118 0x25
+#define KS_VBIL1512 0x26
+#define KS_TTFRAM 0x27
+#define KS_TESTA 0x28
+#define KS_UVOFFH 0x29
+#define KS_UVOFFL 0x2a
+#define KS_UGAIN 0x2b
+#define KS_VGAIN 0x2c
+#define KS_VAVB 0x2d
+#define KS_VAVE 0x2e
+#define KS_CTRACK 0x2f
+#define KS_POLCTL 0x30
+#define KS_REFCOD 0x31
+#define KS_INVALY 0x32
+#define KS_INVALU 0x33
+#define KS_INVALV 0x34
+#define KS_UNUSEY 0x35
+#define KS_UNUSEU 0x36
+#define KS_UNUSEV 0x37
+#define KS_USRSAV 0x38
+#define KS_USREAV 0x39
+#define KS_SHS1A 0x3a
+#define KS_SHS1B 0x3b
+#define KS_SHS1C 0x3c
+#define KS_CMDE 0x3d
+#define KS_VSDEL 0x3e
+#define KS_CMDF 0x3f
+#define KS_GAMMA0 0x40
+#define KS_GAMMA1 0x41
+#define KS_GAMMA2 0x42
+#define KS_GAMMA3 0x43
+#define KS_GAMMA4 0x44
+#define KS_GAMMA5 0x45
+#define KS_GAMMA6 0x46
+#define KS_GAMMA7 0x47
+#define KS_GAMMA8 0x48
+#define KS_GAMMA9 0x49
+#define KS_GAMMA10 0x4a
+#define KS_GAMMA11 0x4b
+#define KS_GAMMA12 0x4c
+#define KS_GAMMA13 0x4d
+#define KS_GAMMA14 0x4e
+#define KS_GAMMA15 0x4f
+#define KS_GAMMA16 0x50
+#define KS_GAMMA17 0x51
+#define KS_GAMMA18 0x52
+#define KS_GAMMA19 0x53
+#define KS_GAMMA20 0x54
+#define KS_GAMMA21 0x55
+#define KS_GAMMA22 0x56
+#define KS_GAMMA23 0x57
+#define KS_GAMMA24 0x58
+#define KS_GAMMA25 0x59
+#define KS_GAMMA26 0x5a
+#define KS_GAMMA27 0x5b
+#define KS_GAMMA28 0x5c
+#define KS_GAMMA29 0x5d
+#define KS_GAMMA30 0x5e
+#define KS_GAMMA31 0x5f
+#define KS_GAMMAD0 0x60
+#define KS_GAMMAD1 0x61
+#define KS_GAMMAD2 0x62
+#define KS_GAMMAD3 0x63
+#define KS_GAMMAD4 0x64
+#define KS_GAMMAD5 0x65
+#define KS_GAMMAD6 0x66
+#define KS_GAMMAD7 0x67
+#define KS_GAMMAD8 0x68
+#define KS_GAMMAD9 0x69
+#define KS_GAMMAD10 0x6a
+#define KS_GAMMAD11 0x6b
+#define KS_GAMMAD12 0x6c
+#define KS_GAMMAD13 0x6d
+#define KS_GAMMAD14 0x6e
+#define KS_GAMMAD15 0x6f
+#define KS_GAMMAD16 0x70
+#define KS_GAMMAD17 0x71
+#define KS_GAMMAD18 0x72
+#define KS_GAMMAD19 0x73
+#define KS_GAMMAD20 0x74
+#define KS_GAMMAD21 0x75
+#define KS_GAMMAD22 0x76
+#define KS_GAMMAD23 0x77
+#define KS_GAMMAD24 0x78
+#define KS_GAMMAD25 0x79
+#define KS_GAMMAD26 0x7a
+#define KS_GAMMAD27 0x7b
+#define KS_GAMMAD28 0x7c
+#define KS_GAMMAD29 0x7d
+#define KS_GAMMAD30 0x7e
+#define KS_GAMMAD31 0x7f
+
+
+/****************************************************************************
+* mga_dev : represents one ks0127 chip.
+****************************************************************************/
+
+struct adjust {
+ int contrast;
+ int bright;
+ int hue;
+ int ugain;
+ int vgain;
+};
+
+struct ks0127 {
+ struct i2c_client *client;
+ unsigned char addr;
+ int format_width;
+ int format_height;
+ int cap_width;
+ int cap_height;
+ int norm;
+ int ks_type;
+ u8 regs[256];
+};
+
+
+static int debug; /* insmod parameter */
+
+module_param(debug, int, 0);
+MODULE_PARM_DESC(debug, "Debug output");
+MODULE_LICENSE("GPL");
+
+static u8 reg_defaults[64];
+
+
+
+static void init_reg_defaults(void)
+{
+ u8 *table = reg_defaults;
+
+ table[KS_CMDA] = 0x2c; /* VSE=0, CCIR 601, autodetect standard */
+ table[KS_CMDB] = 0x12; /* VALIGN=0, AGC control and input */
+ table[KS_CMDC] = 0x00; /* Test options */
+ /* clock & input select, write 1 to PORTA */
+ table[KS_CMDD] = 0x01;
+ table[KS_HAVB] = 0x00; /* HAV Start Control */
+ table[KS_HAVE] = 0x00; /* HAV End Control */
+ table[KS_HS1B] = 0x10; /* HS1 Start Control */
+ table[KS_HS1E] = 0x00; /* HS1 End Control */
+ table[KS_HS2B] = 0x00; /* HS2 Start Control */
+ table[KS_HS2E] = 0x00; /* HS2 End Control */
+ table[KS_AGC] = 0x53; /* Manual setting for AGC */
+ table[KS_HXTRA] = 0x00; /* Extra Bits for HAV and HS1/2 */
+ table[KS_CDEM] = 0x00; /* Chroma Demodulation Control */
+ table[KS_PORTAB] = 0x0f; /* port B is input, port A output GPPORT */
+ table[KS_LUMA] = 0x01; /* Luma control */
+ table[KS_CON] = 0x00; /* Contrast Control */
+ table[KS_BRT] = 0x00; /* Brightness Control */
+ table[KS_CHROMA] = 0x2a; /* Chroma control A */
+ table[KS_CHROMB] = 0x90; /* Chroma control B */
+ table[KS_DEMOD] = 0x00; /* Chroma Demodulation Control & Status */
+ table[KS_SAT] = 0x00; /* Color Saturation Control*/
+ table[KS_HUE] = 0x00; /* Hue Control */
+ table[KS_VERTIA] = 0x00; /* Vertical Processing Control A */
+ /* Vertical Processing Control B, luma 1 line delayed */
+ table[KS_VERTIB] = 0x12;
+ table[KS_VERTIC] = 0x0b; /* Vertical Processing Control C */
+ table[KS_HSCLL] = 0x00; /* Horizontal Scaling Ratio Low */
+ table[KS_HSCLH] = 0x00; /* Horizontal Scaling Ratio High */
+ table[KS_VSCLL] = 0x00; /* Vertical Scaling Ratio Low */
+ table[KS_VSCLH] = 0x00; /* Vertical Scaling Ratio High */
+ /* 16 bit YCbCr 4:2:2 output; I can't make the bt866 like 8 bit /Sam */
+ table[KS_OFMTA] = 0x30;
+ table[KS_OFMTB] = 0x00; /* Output Control B */
+ /* VBI Decoder Control; 4bit fmt: avoid Y overflow */
+ table[KS_VBICTL] = 0x5d;
+ table[KS_CCDAT2] = 0x00; /* Read Only register */
+ table[KS_CCDAT1] = 0x00; /* Read Only register */
+ table[KS_VBIL30] = 0xa8; /* VBI data decoding options */
+ table[KS_VBIL74] = 0xaa; /* VBI data decoding options */
+ table[KS_VBIL118] = 0x2a; /* VBI data decoding options */
+ table[KS_VBIL1512] = 0x00; /* VBI data decoding options */
+ table[KS_TTFRAM] = 0x00; /* Teletext frame alignment pattern */
+ table[KS_TESTA] = 0x00; /* test register, shouldn't be written */
+ table[KS_UVOFFH] = 0x00; /* UV Offset Adjustment High */
+ table[KS_UVOFFL] = 0x00; /* UV Offset Adjustment Low */
+ table[KS_UGAIN] = 0x00; /* U Component Gain Adjustment */
+ table[KS_VGAIN] = 0x00; /* V Component Gain Adjustment */
+ table[KS_VAVB] = 0x07; /* VAV Begin */
+ table[KS_VAVE] = 0x00; /* VAV End */
+ table[KS_CTRACK] = 0x00; /* Chroma Tracking Control */
+ table[KS_POLCTL] = 0x41; /* Timing Signal Polarity Control */
+ table[KS_REFCOD] = 0x80; /* Reference Code Insertion Control */
+ table[KS_INVALY] = 0x10; /* Invalid Y Code */
+ table[KS_INVALU] = 0x80; /* Invalid U Code */
+ table[KS_INVALV] = 0x80; /* Invalid V Code */
+ table[KS_UNUSEY] = 0x10; /* Unused Y Code */
+ table[KS_UNUSEU] = 0x80; /* Unused U Code */
+ table[KS_UNUSEV] = 0x80; /* Unused V Code */
+ table[KS_USRSAV] = 0x00; /* reserved */
+ table[KS_USREAV] = 0x00; /* reserved */
+ table[KS_SHS1A] = 0x00; /* User Defined SHS1 A */
+ /* User Defined SHS1 B, ALT656=1 on 0127B */
+ table[KS_SHS1B] = 0x80;
+ table[KS_SHS1C] = 0x00; /* User Defined SHS1 C */
+ table[KS_CMDE] = 0x00; /* Command Register E */
+ table[KS_VSDEL] = 0x00; /* VS Delay Control */
+ /* Command Register F, update -immediately- */
+ /* (there might come no vsync)*/
+ table[KS_CMDF] = 0x02;
+}
+
+
+/* We need to manually read because of a bug in the KS0127 chip.
+ *
+ * An explanation from kayork@mail.utexas.edu:
+ *
+ * During I2C reads, the KS0127 only samples for a stop condition
+ * during the place where the acknoledge bit should be. Any standard
+ * I2C implementation (correctly) throws in another clock transition
+ * at the 9th bit, and the KS0127 will not recognize the stop condition
+ * and will continue to clock out data.
+ *
+ * So we have to do the read ourself. Big deal.
+ workaround in i2c-algo-bit
+ */
+
+
+static u8 ks0127_read(struct ks0127 *ks, u8 reg)
+{
+ struct i2c_client *c = ks->client;
+ char val = 0;
+ struct i2c_msg msgs[] = {
+ {c->addr, 0, sizeof(reg), ®},
+ {c->addr, I2C_M_RD | I2C_M_NO_RD_ACK, sizeof(val), &val}};
+ int ret;
+
+ ret = i2c_transfer(c->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret != ARRAY_SIZE(msgs))
+ dprintk("ks0127_write error\n");
+
+ return val;
+}
+
+
+static void ks0127_write(struct ks0127 *ks, u8 reg, u8 val)
+{
+ char msg[] = {reg, val};
+
+ if (i2c_master_send(ks->client, msg, sizeof(msg)) != sizeof(msg))
+ dprintk("ks0127_write error\n");
+
+ ks->regs[reg] = val;
+}
+
+
+/* generic bit-twiddling */
+static void ks0127_and_or(struct ks0127 *ks, u8 reg, u8 and_v, u8 or_v)
+{
+ u8 val = ks->regs[reg];
+ val = (val & and_v) | or_v;
+ ks0127_write(ks, reg, val);
+}
+
+
+
+/****************************************************************************
+* ks0127 private api
+****************************************************************************/
+static void ks0127_reset(struct ks0127* ks)
+{
+ int i;
+ u8 *table = reg_defaults;
+
+ ks->ks_type = KS_TYPE_UNKNOWN;
+
+ dprintk("ks0127: reset\n");
+ msleep(1);
+
+ /* initialize all registers to known values */
+ /* (except STAT, 0x21, 0x22, TEST and 0x38,0x39) */
+
+ for(i = 1; i < 33; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 35; i < 40; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 41; i < 56; i++)
+ ks0127_write(ks, i, table[i]);
+
+ for(i = 58; i < 64; i++)
+ ks0127_write(ks, i, table[i]);
+
+
+ if ((ks0127_read(ks, KS_STAT) & 0x80) == 0) {
+ ks->ks_type = KS_TYPE_0122S;
+ dprintk("ks0127: ks0122s Found\n");
+ return;
+ }
+
+ switch(ks0127_read(ks, KS_CMDE) & 0x0f) {
+
+ case 0:
+ ks->ks_type = KS_TYPE_0127;
+ dprintk("ks0127: ks0127 found\n");
+ break;
+
+ case 9:
+ ks->ks_type = KS_TYPE_0127B;
+ dprintk("ks0127: ks0127B Revision A found\n");
+ break;
+
+ default:
+ dprintk("ks0127: unknown revision\n");
+ break;
+ }
+}
+
+static int ks0127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg)
+{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
+ int *iarg = (int*)arg;
+
+ int status;
+
+ if (!ks)
+ return -ENODEV;
+
+ switch (cmd) {
+
+ case DECODER_INIT:
+ dprintk("ks0127: command DECODER_INIT\n");
+ ks0127_reset(ks);
+ break;
+
+ case DECODER_SET_INPUT:
+ switch(*iarg) {
+ case KS_INPUT_COMPOSITE_1:
+ case KS_INPUT_COMPOSITE_2:
+ case KS_INPUT_COMPOSITE_3:
+ case KS_INPUT_COMPOSITE_4:
+ case KS_INPUT_COMPOSITE_5:
+ case KS_INPUT_COMPOSITE_6:
+ dprintk("ks0127: command DECODER_SET_INPUT %d: "
+ "Composite\n", *iarg);
+ /* autodetect 50/60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ /* VSE=0 */
+ ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ /* set input line */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ /* non-freerunning mode */
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ /* analog input */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ /* enable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ /* chroma trap, HYBWR=1 */
+ ks0127_and_or(ks, KS_LUMA, 0x00,
+ (reg_defaults[KS_LUMA])|0x0c);
+ /* scaler fullbw, luma comb off */
+ ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+ /* manual chroma comb .25 .5 .25 */
+ ks0127_and_or(ks, KS_VERTIC, 0x0f, 0x90);
+
+ /* chroma path delay */
+ ks0127_and_or(ks, KS_CHROMB, 0x0f, 0x90);
+
+ ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+ case KS_INPUT_SVIDEO_1:
+ case KS_INPUT_SVIDEO_2:
+ case KS_INPUT_SVIDEO_3:
+ dprintk("ks0127: command DECODER_SET_INPUT %d: "
+ "S-Video\n", *iarg);
+ /* autodetect 50/60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ /* VSE=0 */
+ ks0127_and_or(ks, KS_CMDA, ~0x40, 0x00);
+ /* set input line */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, *iarg);
+ /* non-freerunning mode */
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x0a);
+ /* analog input */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x00);
+ /* enable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x00);
+ ks0127_and_or(ks, KS_LUMA, 0x00,
+ reg_defaults[KS_LUMA]);
+ /* disable luma comb */
+ ks0127_and_or(ks, KS_VERTIA, 0x08,
+ (reg_defaults[KS_VERTIA]&0xf0)|0x01);
+ ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ reg_defaults[KS_VERTIC]&0xf0);
+
+ ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ reg_defaults[KS_CHROMB]&0xf0);
+
+ ks0127_write(ks, KS_UGAIN, reg_defaults[KS_UGAIN]);
+ ks0127_write(ks, KS_VGAIN, reg_defaults[KS_VGAIN]);
+ ks0127_write(ks, KS_UVOFFH, reg_defaults[KS_UVOFFH]);
+ ks0127_write(ks, KS_UVOFFL, reg_defaults[KS_UVOFFL]);
+ break;
+
+ case KS_INPUT_YUV656:
+ dprintk("ks0127: command DECODER_SET_INPUT 15: "
+ "YUV656\n");
+ if (ks->norm == VIDEO_MODE_NTSC ||
+ ks->norm == KS_STD_PAL_M)
+ /* force 60 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x03);
+ else
+ /* force 50 Hz */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x02);
+
+ ks0127_and_or(ks, KS_CMDA, 0xff, 0x40); /* VSE=1 */
+ /* set input line and VALIGN */
+ ks0127_and_or(ks, KS_CMDB, 0xb0, (*iarg | 0x40));
+ /* freerunning mode, */
+ /* TSTGEN = 1 TSTGFR=11 TSTGPH=0 TSTGPK=0 VMEM=1*/
+ ks0127_and_or(ks, KS_CMDC, 0x70, 0x87);
+ /* digital input, SYNDIR = 0 INPSL=01 CLKDIR=0 EAV=0 */
+ ks0127_and_or(ks, KS_CMDD, 0x03, 0x08);
+ /* disable chroma demodulation */
+ ks0127_and_or(ks, KS_CTRACK, 0xcf, 0x30);
+ /* HYPK =01 CTRAP = 0 HYBWR=0 PED=1 RGBH=1 UNIT=1 */
+ ks0127_and_or(ks, KS_LUMA, 0x00, 0x71);
+ ks0127_and_or(ks, KS_VERTIC, 0x0f,
+ reg_defaults[KS_VERTIC]&0xf0);
+
+ /* scaler fullbw, luma comb off */
+ ks0127_and_or(ks, KS_VERTIA, 0x08, 0x81);
+
+ ks0127_and_or(ks, KS_CHROMB, 0x0f,
+ reg_defaults[KS_CHROMB]&0xf0);
+
+ ks0127_and_or(ks, KS_CON, 0x00, 0x00);
+ ks0127_and_or(ks, KS_BRT, 0x00, 32); /* spec: 34 */
+ /* spec: 229 (e5) */
+ ks0127_and_or(ks, KS_SAT, 0x00, 0xe8);
+ ks0127_and_or(ks, KS_HUE, 0x00, 0);
+
+ ks0127_and_or(ks, KS_UGAIN, 0x00, 238);
+ ks0127_and_or(ks, KS_VGAIN, 0x00, 0x00);
+
+ /*UOFF:0x30, VOFF:0x30, TSTCGN=1 */
+ ks0127_and_or(ks, KS_UVOFFH, 0x00, 0x4f);
+ ks0127_and_or(ks, KS_UVOFFL, 0x00, 0x00);
+ break;
+
+ default:
+ dprintk("ks0127: command DECODER_SET_INPUT: "
+ "Unknown input %d\n", *iarg);
+ break;
+ }
+
+ /* hack: CDMLPF sometimes spontaneously switches on; */
+ /* force back off */
+ ks0127_write(ks, KS_DEMOD, reg_defaults[KS_DEMOD]);
+ break;
+
+ case DECODER_SET_OUTPUT:
+ switch(*iarg) {
+ case KS_OUTPUT_YUV656E:
+ dprintk("ks0127: command DECODER_SET_OUTPUT: "
+ "OUTPUT_YUV656E (Missing)\n");
+ return -EINVAL;
+ break;
+
+ case KS_OUTPUT_EXV:
+ dprintk("ks0127: command DECODER_SET_OUTPUT: "
+ "OUTPUT_EXV\n");
+ ks0127_and_or(ks, KS_OFMTA, 0xf0, 0x09);
+ break;
+ }
+ break;
+
+ case DECODER_SET_NORM: //sam This block mixes old and new norm names...
+ /* Set to automatic SECAM/Fsc mode */
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+
+ ks->norm = *iarg;
+ switch(*iarg)
+ {
+ /* this is untested !! */
+ /* It just detects PAL_N/NTSC_M (no special frequencies) */
+ /* And you have to set the standard a second time afterwards */
+ case VIDEO_MODE_AUTO:
+ dprintk("ks0127: command DECODER_SET_NORM: AUTO\n");
+
+ /* The chip determines the format */
+ /* based on the current field rate */
+ ks0127_and_or(ks, KS_CMDA, 0xfc, 0x00);
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ /* This is wrong for PAL ! As I said, */
+ /* you need to set the standard once again !! */
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_NTSC:
+ dprintk("ks0127: command DECODER_SET_NORM: NTSC_M\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case KS_STD_NTSC_N:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "NTSC_N (fixme)\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ ks->format_height = 240;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_PAL:
+ dprintk("ks0127: command DECODER_SET_NORM: PAL_N\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x20);
+ ks->format_height = 290;
+ ks->format_width = 704;
+ break;
+
+ case KS_STD_PAL_M:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "PAL_M (fixme)\n");
+ ks0127_and_or(ks, KS_CHROMA, 0x9f, 0x40);
+ ks->format_height = 290;
+ ks->format_width = 704;
+ break;
+
+ case VIDEO_MODE_SECAM:
+ dprintk("ks0127: command KS0127_SET_STANDARD: "
+ "SECAM\n");
+ ks->format_height = 290;
+ ks->format_width = 704;
+
+ /* set to secam autodetection */
+ ks0127_and_or(ks, KS_CHROMA, 0xdf, 0x20);
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x00);
+ schedule_timeout_interruptible(HZ/10+1);
+
+ /* did it autodetect? */
+ if (ks0127_read(ks, KS_DEMOD) & 0x40)
+ break;
+
+ /* force to secam mode */
+ ks0127_and_or(ks, KS_DEMOD, 0xf0, 0x0f);
+ break;
+
+ default:
+ dprintk("ks0127: command DECODER_SET_NORM: "
+ "Unknown norm %d\n", *iarg);
+ break;
+ }
+ break;
+
+ case DECODER_SET_PICTURE:
+ dprintk("ks0127: command DECODER_SET_PICTURE "
+ "not yet supported (fixme)\n");
+ return -EINVAL;
+
+ //sam todo: KS0127_SET_BRIGHTNESS: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_CONTRAST: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_HUE: Merge into DECODER_SET_PICTURE?
+ //sam todo: KS0127_SET_SATURATION: Merge into DECODER_SET_PICTURE
+ //sam todo: KS0127_SET_AGC_MODE:
+ //sam todo: KS0127_SET_AGC:
+ //sam todo: KS0127_SET_CHROMA_MODE:
+ //sam todo: KS0127_SET_PIXCLK_MODE:
+ //sam todo: KS0127_SET_GAMMA_MODE:
+ //sam todo: KS0127_SET_UGAIN:
+ //sam todo: KS0127_SET_VGAIN:
+ //sam todo: KS0127_SET_INVALY:
+ //sam todo: KS0127_SET_INVALU:
+ //sam todo: KS0127_SET_INVALV:
+ //sam todo: KS0127_SET_UNUSEY:
+ //sam todo: KS0127_SET_UNUSEU:
+ //sam todo: KS0127_SET_UNUSEV:
+ //sam todo: KS0127_SET_VSALIGN_MODE:
+
+ case DECODER_ENABLE_OUTPUT:
+ {
+
+ int *iarg = arg;
+ int enable = (*iarg != 0);
+ if (enable) {
+ dprintk("ks0127: command "
+ "DECODER_ENABLE_OUTPUT on "
+ "(%d)\n", enable);
+ /* All output pins on */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30);
+ /* Obey the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00);
+ } else {
+ dprintk("ks0127: command "
+ "DECODER_ENABLE_OUTPUT off "
+ "(%d)\n", enable);
+ /* Video output pins off */
+ ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00);
+ /* Ignore the OEN pin */
+ ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80);
+ }
+ }
+ break;
+
+ //sam todo: KS0127_SET_OUTPUT_MODE:
+ //sam todo: KS0127_SET_WIDTH:
+ //sam todo: KS0127_SET_HEIGHT:
+ //sam todo: KS0127_SET_HSCALE:
+
+ case DECODER_GET_STATUS:
+ dprintk("ks0127: command DECODER_GET_STATUS\n");
+ *iarg = 0;
+ status = ks0127_read(ks, KS_STAT);
+ if (!(status & 0x20)) /* NOVID not set */
+ *iarg = (*iarg & DECODER_STATUS_GOOD);
+ if ((status & 0x01)) /* CLOCK set */
+ *iarg = (*iarg & DECODER_STATUS_COLOR);
+ if ((status & 0x08)) /* PALDET set */
+ *iarg = (*iarg & DECODER_STATUS_PAL);
+ else
+ *iarg = (*iarg & DECODER_STATUS_NTSC);
+ break;
+
+ //Catch any unknown command
+ default:
+ dprintk("ks0127: command unknown: %04X\n", cmd);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+
+
+static int ks0127_probe(struct i2c_adapter *adapter);
+static int ks0127_detach(struct i2c_client *client);
+static int ks0127_command(struct i2c_client *client,
+ unsigned int cmd, void *arg);
+
+
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {I2C_KS0127_ADDON>>1,
+ I2C_KS0127_ONBOARD>>1, I2C_CLIENT_END};
+static unsigned short probe[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static unsigned short ignore[2] = {I2C_CLIENT_END, I2C_CLIENT_END};
+static struct i2c_client_address_data addr_data = {
+ normal_i2c,
+ probe,
+ ignore,
+};
+
+static struct i2c_driver i2c_driver_ks0127 = {
+ .driver.name = "ks0127",
+ .id = I2C_DRIVERID_KS0127,
+ .attach_adapter = ks0127_probe,
+ .detach_client = ks0127_detach,
+ .command = ks0127_command
+};
+
+static struct i2c_client ks0127_client_tmpl =
+{
+ .name = "(ks0127 unset)",
+ .addr = 0,
+ .adapter = NULL,
+ .driver = &i2c_driver_ks0127,
+ .usage_count = 0
+};
+
+static int ks0127_found_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+ struct ks0127 *ks;
+ struct i2c_client *client;
+
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
+ if (client == NULL)
+ return -ENOMEM;
+ memcpy(client, &ks0127_client_tmpl, sizeof(*client));
+
+ ks = kzalloc(sizeof(*ks), GFP_KERNEL);
+ if (ks == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+
+ i2c_set_clientdata(client, ks);
+ client->adapter = adapter;
+ client->addr = addr;
+ sprintf(client->name, "ks0127-%02x", adapter->id);
+
+ ks->client = client;
+ ks->addr = addr;
+ ks->ks_type = KS_TYPE_UNKNOWN;
+
+ /* power up */
+ ks0127_write(ks, KS_CMDA, 0x2c);
+ mdelay(10);
+
+ /* reset the device */
+ ks0127_reset(ks);
+ printk(KERN_INFO "ks0127: attach: %s video decoder\n",
+ ks->addr==(I2C_KS0127_ADDON>>1) ? "addon" : "on-board");
+
+ i2c_attach_client(client);
+ return 0;
+}
+
+
+static int ks0127_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->id == I2C_HW_B_ZR36067)
+ return i2c_probe(adapter, &addr_data, ks0127_found_proc);
+ return 0;
+}
+
+static int ks0127_detach(struct i2c_client *client)
+{
+ struct ks0127 *ks = i2c_get_clientdata(client);
+
+ ks0127_write(ks, KS_OFMTA, 0x20); /*tristate*/
+ ks0127_write(ks, KS_CMDA, 0x2c | 0x80); /* power down */
+
+ i2c_detach_client(client);
+ kfree(ks);
+ kfree(client);
+
+ dprintk("ks0127: detach\n");
+ return 0;
+}
+
+
+static int __devinit ks0127_init_module(void)
+{
+ init_reg_defaults();
+ i2c_add_driver(&i2c_driver_ks0127);
+ return 0;
+}
+
+static void __devexit ks0127_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver_ks0127);
+}
+
+
+module_init(ks0127_init_module);
+module_exit(ks0127_cleanup_module);
--- /dev/null
+/*
+ * Video Capture Driver ( Video for Linux 1/2 )
+ * for the Matrox Marvel G200,G400 and Rainbow Runner-G series
+ *
+ * This module is an interface to the KS0127 video decoder chip.
+ *
+ * Copyright (C) 1999 Ryan Drake <stiletto@mediaone.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef KS0127_H
+#define KS0127_H
+
+#include <linux/videodev.h>
+
+/* input channels */
+#define KS_INPUT_COMPOSITE_1 0
+#define KS_INPUT_COMPOSITE_2 1
+#define KS_INPUT_COMPOSITE_3 2
+#define KS_INPUT_COMPOSITE_4 4
+#define KS_INPUT_COMPOSITE_5 5
+#define KS_INPUT_COMPOSITE_6 6
+
+#define KS_INPUT_SVIDEO_1 8
+#define KS_INPUT_SVIDEO_2 9
+#define KS_INPUT_SVIDEO_3 10
+
+#define KS_INPUT_YUV656 15
+#define KS_INPUT_COUNT 10
+
+/* output channels */
+#define KS_OUTPUT_YUV656E 0
+#define KS_OUTPUT_EXV 1
+
+/* video standards */
+#define KS_STD_NTSC_N 112 /* 50 Hz NTSC */
+#define KS_STD_PAL_M 113 /* 60 Hz PAL */
+
+#endif /* KS0127_H */
+
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/delay.h>
static void meye_vm_open(struct vm_area_struct *vma)
{
- int idx = (int)vma->vm_private_data;
+ long idx = (long)vma->vm_private_data;
meye.vma_use_count[idx]++;
}
static void meye_vm_close(struct vm_area_struct *vma)
{
- int idx = (int)vma->vm_private_data;
+ long idx = (long)vma->vm_private_data;
meye.vma_use_count[idx]--;
}
return V4L2_TUNER_MODE_MONO;
}
-static struct v4l2_queryctrl msp_qctrl_std[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-
-static struct v4l2_queryctrl msp_qctrl_sound_processing[] = {
- {
- .id = V4L2_CID_AUDIO_BALANCE,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_BASS,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_TREBLE,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .type = V4L2_CTRL_TYPE_INTEGER,
- },{
- .id = V4L2_CID_AUDIO_LOUDNESS,
- .name = "Loudness",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- },
-};
-
-
static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
struct msp_state *state = i2c_get_clientdata(client);
int sc1_out = rt->output & 0xf;
int sc2_out = (rt->output >> 4) & 0xf;
u16 val, reg;
+ int i;
+ int extern_input = 1;
if (state->routing.input == rt->input &&
state->routing.output == rt->output)
break;
state->routing = *rt;
+ /* check if the tuner input is used */
+ for (i = 0; i < 5; i++) {
+ if (((rt->input >> (4 + i * 4)) & 0xf) == 0)
+ extern_input = 0;
+ }
+ if (extern_input)
+ state->mode = MSP_MODE_EXTERN;
+ else
+ state->mode = MSP_MODE_AM_DETECT;
msp_set_scart(client, sc_in, 0);
msp_set_scart(client, sc1_out, 1);
msp_set_scart(client, sc2_out, 2);
msp_set_audmode(client);
reg = (state->opmode == OPMODE_AUTOSELECT) ? 0x30 : 0xbb;
val = msp_read_dem(client, reg);
- if (tuner != ((val >> 8) & 1)) {
- msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
- /* wake thread when a new tuner input is chosen */
- msp_wake_thread(client);
- }
+ msp_write_dem(client, reg, (val & ~0x100) | (tuner << 8));
+ /* wake thread when a new input is chosen */
+ msp_wake_thread(client);
break;
}
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(msp_qctrl_std); i++)
- if (qc->id && qc->id == msp_qctrl_std[i].id) {
- memcpy(qc, &msp_qctrl_std[i], sizeof(*qc));
- return 0;
- }
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ break;
+ }
if (!state->has_sound_processing)
return -EINVAL;
- for (i = 0; i < ARRAY_SIZE(msp_qctrl_sound_processing); i++)
- if (qc->id && qc->id == msp_qctrl_sound_processing[i].id) {
- memcpy(qc, &msp_qctrl_sound_processing[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
+ switch (qc->id) {
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
}
case VIDIOC_G_CTRL:
case MSP_MODE_EXTERN: p = "External input"; break;
default: p = "unknown"; break;
}
- if (state->opmode == OPMODE_MANUAL) {
+ if (state->mode == MSP_MODE_EXTERN) {
+ v4l_info(client, "Mode: %s\n", p);
+ } else if (state->opmode == OPMODE_MANUAL) {
v4l_info(client, "Mode: %s (%s%s)\n", p,
(state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono",
(state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : "");
the hardware does not support SAP. So the rxsubchans combination
of STEREO | LANG2 does not occur. */
- /* switch to mono if only mono is available */
- if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
- audmode = V4L2_TUNER_MODE_MONO;
- /* if bilingual */
- else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
- /* and mono or stereo, then fallback to lang1 */
- if (audmode == V4L2_TUNER_MODE_MONO ||
- audmode == V4L2_TUNER_MODE_STEREO)
- audmode = V4L2_TUNER_MODE_LANG1;
+ if (state->mode != MSP_MODE_EXTERN) {
+ /* switch to mono if only mono is available */
+ if (state->rxsubchans == V4L2_TUNER_SUB_MONO)
+ audmode = V4L2_TUNER_MODE_MONO;
+ /* if bilingual */
+ else if (state->rxsubchans & V4L2_TUNER_SUB_LANG2) {
+ /* and mono or stereo, then fallback to lang1 */
+ if (audmode == V4L2_TUNER_MODE_MONO ||
+ audmode == V4L2_TUNER_MODE_STEREO)
+ audmode = V4L2_TUNER_MODE_LANG1;
+ }
+ /* if stereo, and audmode is not mono, then switch to stereo */
+ else if (audmode != V4L2_TUNER_MODE_MONO)
+ audmode = V4L2_TUNER_MODE_STEREO;
}
- /* if stereo, and audmode is not mono, then switch to stereo */
- else if (audmode != V4L2_TUNER_MODE_MONO)
- audmode = V4L2_TUNER_MODE_STEREO;
/* switch demodulator */
switch (state->mode) {
/* no carrier scan, just unmute */
v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
state->scan_in_progress = 0;
+ state->rxsubchans = V4L2_TUNER_SUB_STEREO;
msp_set_audio(client);
continue;
}
if (kthread_should_stop())
break;
+ if (state->mode == MSP_MODE_EXTERN) {
+ /* no carrier scan needed, just unmute */
+ v4l_dbg(1, msp_debug, client, "thread: no carrier scan\n");
+ state->scan_in_progress = 0;
+ msp_set_audio(client);
+ continue;
+ }
+
/* setup the chip*/
msp34xxg_reset(client);
state->std = state->radio ? 0x40 : msp_standard;
v4l_dbg(1, msp_debug, client, "detected standard: %s (0x%04x)\n",
msp_standard_std_name(state->std), state->std);
+ if (state->std == 9) {
+ /* AM NICAM mode */
+ msp_write_dsp(client, 0x0e, 0x7c00);
+ }
+
/* unmute: dispatch sound to scart output, set scart volume */
msp_set_audio(client);
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
- int nextf;
+ int nextf;
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
if (frame->scanstate == STATE_LINES) {
- int nextf;
+ int nextf;
frame->grabstate = FRAME_DONE;
wake_up_interruptible(&frame->wq);
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
struct video_picture *p = arg;
if(!((p->palette==VIDEO_PALETTE_RGB565 && p->depth==16)
||(p->palette==VIDEO_PALETTE_RGB555 && p->depth==15)))
- return -EINVAL;
+ return -EINVAL;
pd->picture= *p;
/*
* Philips PCA645, PCA646
* Philips PCVC675, PCVC680, PCVC690
* Philips PCVC720/40, PCVC730, PCVC740, PCVC750
+ * Philips SPC900NC
* Askey VC010
* Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro'
and 'Orbit'/'Sphere'
and never will be, but the 665 and 720/20 are supported by other
drivers.
- See <file:Documentation/usb/philips.txt> for more information and
- installation instructions.
+ Some newer logitech webcams are not handled by this driver but by the
+ Usb Video Class driver (linux-uvc).
The built-in microphone is enabled by selecting USB Audio support.
To compile this driver as a module, choose M here: the
module will be called pwc.
+
+config USB_PWC_DEBUG
+ bool "USB Philips Cameras verbose debug"
+ depends USB_PWC
+ help
+ Say Y here in order to have the pwc driver generate verbose debugging
+ messages.
+ A special module options 'trace' is used to control the verbosity.
-pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-timon.o pwc-kiara.o
+pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-v4l.o pwc-uncompress.o
+pwc-objs += pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o
obj-$(CONFIG_USB_PWC) += pwc.o
+
+ifeq ($(CONFIG_USB_PWC_DEBUG),y)
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=1
+else
+EXTRA_CFLAGS += -DCONFIG_PWC_DEBUG=0
+endif
+
+
Functions that send various control messages to the webcam, including
video modes.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
#include <asm/uaccess.h>
#endif
#include <asm/errno.h>
+#include <linux/version.h>
#include "pwc.h"
-#include "pwc-ioctl.h"
#include "pwc-uncompress.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
/* Request types: video */
#define SET_LUM_CTL 0x01
#define GET_STATUS_CTL 0x06
#define SET_EP_STREAM_CTL 0x07
#define GET_EP_STREAM_CTL 0x08
+#define GET_XX_CTL 0x09
+#define SET_XX_CTL 0x0A
+#define GET_XY_CTL 0x0B
+#define SET_XY_CTL 0x0C
#define SET_MPT_CTL 0x0D
#define GET_MPT_CTL 0x0E
#define READ_SHUTTER_FORMATTER 0x0600
#define READ_RED_GAIN_FORMATTER 0x0700
#define READ_BLUE_GAIN_FORMATTER 0x0800
+#define GET_STATUS_B00 0x0B00
#define SENSOR_TYPE_FORMATTER1 0x0C00
+#define GET_STATUS_3000 0x3000
#define READ_RAW_Y_MEAN_FORMATTER 0x3100
#define SET_POWER_SAVE_MODE_FORMATTER 0x3200
#define MIRROR_IMAGE_FORMATTER 0x3300
#define LED_FORMATTER 0x3400
+#define LOWLIGHT 0x3500
+#define GET_STATUS_3600 0x3600
#define SENSOR_TYPE_FORMATTER2 0x3700
+#define GET_STATUS_3800 0x3800
+#define GET_STATUS_4000 0x4000
+#define GET_STATUS_4100 0x4100 /* Get */
+#define CTL_STATUS_4200 0x4200 /* [GS] 1 */
/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
#include "pwc-nala.h"
};
+static void pwc_set_image_buffer_size(struct pwc_device *pdev);
/****************************************************************************/
&buf, buflen, 500)
-#if PWC_DEBUG
-void pwc_hexdump(void *p, int len)
-{
- int i;
- unsigned char *s;
- char buf[100], *d;
-
- s = (unsigned char *)p;
- d = buf;
- *d = '\0';
- Debug("Doing hexdump @ %p, %d bytes.\n", p, len);
- for (i = 0; i < len; i++) {
- d += sprintf(d, "%02X ", *s++);
- if ((i & 0xF) == 0xF) {
- Debug("%s\n", buf);
- d = buf;
- *d = '\0';
- }
- }
- if ((i & 0xF) != 0)
- Debug("%s\n", buf);
-}
-#endif
-
-static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
+static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen)
{
return usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
-static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
+static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
{
unsigned char buf[3];
int ret, fps;
if (pEntry->alternate == 0)
return -EINVAL;
- if (pEntry->compressed)
- return -ENOENT; /* Not supported. */
-
memcpy(buf, pEntry->mode, 3);
ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3);
if (ret < 0) {
- Debug("Failed to send video command... %d\n", ret);
+ PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
return ret;
}
if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
- {
- switch(pdev->type) {
- case 645:
- case 646:
-/* pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
- break;
-
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-/* pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
- break;
- }
- }
+ pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
pdev->cmd_len = 3;
memcpy(pdev->cmd_buf, buf, 3);
}
-static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
{
unsigned char buf[13];
const struct Timon_table_entry *pChoose;
if (ret < 0)
return ret;
-/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
- pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+ if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 13;
memcpy(pdev->cmd_buf, buf, 13);
}
-static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
+static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
{
const struct Kiara_table_entry *pChoose = NULL;
int fps, ret;
fps = (frames / 5) - 1;
/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
- if (size == PSZ_VGA && frames == 5 && snapshot)
+ if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
{
/* Only available in case the raw palette is selected or
we have the decompressor available. This mode is
only available in compressed form
*/
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
- {
- Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette);
- pChoose = &RawEntry;
- }
- else
- {
- Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n");
- }
+ PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
+ pChoose = &RawEntry;
}
else
{
if the preferred ratio is not available.
Skip this step when using RAW modes.
*/
+ snapshot = 0;
while (compression <= 3) {
pChoose = &Kiara_table[size][fps][compression];
if (pChoose->alternate != 0)
if (pChoose == NULL || pChoose->alternate == 0)
return -ENOENT; /* Not supported. */
- Debug("Using alternate setting %d.\n", pChoose->alternate);
+ PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
/* usb_control_msg won't take staticly allocated arrays as argument?? */
memcpy(buf, pChoose->mode, 12);
if (ret < 0)
return ret;
-/* if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
- pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); */
+ if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 12;
memcpy(pdev->cmd_buf, buf, 12);
pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
else
pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
+ PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
+ pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
return 0;
}
-static void pwc_set_image_buffer_size(struct pwc_device *pdev)
-{
- int i, factor = 0, filler = 0;
-
- /* for PALETTE_YUV420P */
- switch(pdev->vpalette)
- {
- case VIDEO_PALETTE_YUV420P:
- factor = 6;
- filler = 128;
- break;
- case VIDEO_PALETTE_RAW:
- factor = 6; /* can be uncompressed YUV420P */
- filler = 0;
- break;
- }
-
- /* Set sizes in bytes */
- pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
- pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
-
- /* Align offset, or you'll get some very weird results in
- YUV420 mode... x must be multiple of 4 (to get the Y's in
- place), and y even (or you'll mixup U & V). This is less of a
- problem for YUV420P.
- */
- pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
- pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
-
- /* Fill buffers with gray or black */
- for (i = 0; i < MAX_IMAGES; i++) {
- if (pdev->image_ptr[i] != NULL)
- memset(pdev->image_ptr[i], filler, pdev->view.size);
- }
-}
-
-
-
/**
@pdev: device structure
@width: viewport width
{
int ret, size;
- Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+ PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
size = pwc_decode_size(pdev, width, height);
if (size < 0) {
- Debug("Could not find suitable size.\n");
+ PWC_DEBUG_MODULE("Could not find suitable size.\n");
return -ERANGE;
}
- Debug("decode_size = %d.\n", size);
+ PWC_TRACE("decode_size = %d.\n", size);
- ret = -EINVAL;
- switch(pdev->type) {
- case 645:
- case 646:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
ret = set_video_mode_Nala(pdev, size, frames);
- break;
- case 675:
- case 680:
- case 690:
- ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
- break;
-
- case 720:
- case 730:
- case 740:
- case 750:
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
- break;
+
+ } else {
+ ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
}
if (ret < 0) {
- if (ret == -ENOENT)
- Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames);
- else {
- Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
- }
+ PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
return ret;
}
pdev->view.x = width;
pdev->view.y = height;
pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
pwc_set_image_buffer_size(pdev);
- Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
+ PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y);
return 0;
}
+#define BLACK_Y 0
+#define BLACK_U 128
+#define BLACK_V 128
+
+static void pwc_set_image_buffer_size(struct pwc_device *pdev)
+{
+ int i, factor = 0;
+
+ /* for PALETTE_YUV420P */
+ switch(pdev->vpalette)
+ {
+ case VIDEO_PALETTE_YUV420P:
+ factor = 6;
+ break;
+ case VIDEO_PALETTE_RAW:
+ factor = 6; /* can be uncompressed YUV420P */
+ break;
+ }
+
+ /* Set sizes in bytes */
+ pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
+ pdev->view.size = pdev->view.x * pdev->view.y * factor / 4;
+
+ /* Align offset, or you'll get some very weird results in
+ YUV420 mode... x must be multiple of 4 (to get the Y's in
+ place), and y even (or you'll mixup U & V). This is less of a
+ problem for YUV420P.
+ */
+ pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
+ pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
+
+ /* Fill buffers with black colors */
+ for (i = 0; i < pwc_mbufs; i++) {
+ unsigned char *p = pdev->image_data + pdev->images[i].offset;
+ memset(p, BLACK_Y, pdev->view.x * pdev->view.y);
+ p += pdev->view.x * pdev->view.y;
+ memset(p, BLACK_U, pdev->view.x * pdev->view.y/4);
+ p += pdev->view.x * pdev->view.y/4;
+ memset(p, BLACK_V, pdev->view.x * pdev->view.y/4);
+ }
+}
+
+
/* BRIGHTNESS */
ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 9;
+ return buf;
}
int pwc_set_brightness(struct pwc_device *pdev, int value)
ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 10;
+ return buf;
}
int pwc_set_contrast(struct pwc_device *pdev, int value)
ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1);
if (ret < 0)
return ret;
- return buf << 11;
+ return buf;
}
int pwc_set_gamma(struct pwc_device *pdev, int value)
/* SATURATION */
-int pwc_get_saturation(struct pwc_device *pdev)
+/* return a value between [-100 , 100] */
+int pwc_get_saturation(struct pwc_device *pdev, int *value)
{
char buf;
- int ret;
+ int ret, saturation_register;
if (pdev->type < 675)
- return -1;
- ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+ return -EINVAL;
+ if (pdev->type < 730)
+ saturation_register = SATURATION_MODE_FORMATTER2;
+ else
+ saturation_register = SATURATION_MODE_FORMATTER1;
+ ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1);
if (ret < 0)
return ret;
- return 32768 + buf * 327;
+ *value = (signed)buf;
+ return 0;
}
+/* @param value saturation color between [-100 , 100] */
int pwc_set_saturation(struct pwc_device *pdev, int value)
{
char buf;
+ int saturation_register;
if (pdev->type < 675)
return -EINVAL;
- if (value < 0)
- value = 0;
- if (value > 0xffff)
- value = 0xffff;
- /* saturation ranges from -100 to +100 */
- buf = (value - 32768) / 327;
- return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1);
+ if (value < -100)
+ value = -100;
+ if (value > 100)
+ value = 100;
+ if (pdev->type < 730)
+ saturation_register = SATURATION_MODE_FORMATTER2;
+ else
+ saturation_register = SATURATION_MODE_FORMATTER1;
+ return SendControlMsg(SET_CHROM_CTL, saturation_register, 1);
}
/* AGC */
-static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
+int pwc_set_agc(struct pwc_device *pdev, int mode, int value)
{
char buf;
int ret;
return 0;
}
-static inline int pwc_get_agc(struct pwc_device *pdev, int *value)
+int pwc_get_agc(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
return 0;
}
-static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
+int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value)
{
char buf[2];
int speed, ret;
value = 0;
if (value > 0xffff)
value = 0xffff;
- switch(pdev->type) {
- case 675:
- case 680:
- case 690:
+
+ if (DEVICE_USE_CODEC2(pdev->type)) {
/* speed ranges from 0x0 to 0x290 (656) */
speed = (value / 100);
buf[1] = speed >> 8;
buf[0] = speed & 0xff;
- break;
- case 720:
- case 730:
- case 740:
- case 750:
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
/* speed seems to range from 0x0 to 0xff */
buf[1] = 0;
buf[0] = value >> 8;
- break;
}
ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2);
return ret;
}
+/* This function is not exported to v4l1, so output values between 0 -> 256 */
+int pwc_get_shutter_speed(struct pwc_device *pdev, int *value)
+{
+ unsigned char buf[2];
+ int ret;
+
+ ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2);
+ if (ret < 0)
+ return ret;
+ *value = buf[0] + (buf[1] << 8);
+ if (DEVICE_USE_CODEC2(pdev->type)) {
+ /* speed ranges from 0x0 to 0x290 (656) */
+ *value *= 256/656;
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
+ /* speed seems to range from 0x0 to 0xff */
+ }
+ return 0;
+}
+
/* POWER */
/* private calls */
-static inline int pwc_restore_user(struct pwc_device *pdev)
+int pwc_restore_user(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0);
}
-static inline int pwc_save_user(struct pwc_device *pdev)
+int pwc_save_user(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0);
}
-static inline int pwc_restore_factory(struct pwc_device *pdev)
+int pwc_restore_factory(struct pwc_device *pdev)
{
char buf; /* dummy */
return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0);
* 03: manual
* 04: auto
*/
-static inline int pwc_set_awb(struct pwc_device *pdev, int mode)
+int pwc_set_awb(struct pwc_device *pdev, int mode)
{
char buf;
int ret;
return 0;
}
-static inline int pwc_get_awb(struct pwc_device *pdev)
+int pwc_get_awb(struct pwc_device *pdev)
{
unsigned char buf;
int ret;
return buf;
}
-static inline int pwc_set_red_gain(struct pwc_device *pdev, int value)
+int pwc_set_red_gain(struct pwc_device *pdev, int value)
{
unsigned char buf;
return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1);
}
-static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value)
+int pwc_get_red_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
}
-static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value)
+int pwc_set_blue_gain(struct pwc_device *pdev, int value)
{
unsigned char buf;
return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1);
}
-static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
+int pwc_get_blue_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
internal red/blue gains, which may be different from the manual
gains set or read above.
*/
-static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_red_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
return 0;
}
-static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
+static int pwc_read_blue_gain(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
}
-static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
+static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
{
unsigned char buf;
return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1);
}
-static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
}
-static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
+static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
{
unsigned char buf;
return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1);
}
-static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
+static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
{
unsigned char buf;
int ret;
return 0;
}
-static inline int pwc_set_contour(struct pwc_device *pdev, int contour)
+int pwc_set_contour(struct pwc_device *pdev, int contour)
{
unsigned char buf;
int ret;
return 0;
}
-static inline int pwc_get_contour(struct pwc_device *pdev, int *contour)
+int pwc_get_contour(struct pwc_device *pdev, int *contour)
{
unsigned char buf;
int ret;
}
-static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight)
+int pwc_set_backlight(struct pwc_device *pdev, int backlight)
{
unsigned char buf;
return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
}
-static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
+int pwc_get_backlight(struct pwc_device *pdev, int *backlight)
{
int ret;
unsigned char buf;
ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1);
if (ret < 0)
return ret;
- *backlight = buf;
+ *backlight = !!buf;
return 0;
}
+int pwc_set_colour_mode(struct pwc_device *pdev, int colour)
+{
+ unsigned char buf;
-static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker)
+ if (colour)
+ buf = 0xff;
+ else
+ buf = 0x0;
+ return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+}
+
+int pwc_get_colour_mode(struct pwc_device *pdev, int *colour)
+{
+ int ret;
+ unsigned char buf;
+
+ ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1);
+ if (ret < 0)
+ return ret;
+ *colour = !!buf;
+ return 0;
+}
+
+
+int pwc_set_flicker(struct pwc_device *pdev, int flicker)
{
unsigned char buf;
return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
}
-static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
+int pwc_get_flicker(struct pwc_device *pdev, int *flicker)
{
int ret;
unsigned char buf;
ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1);
if (ret < 0)
return ret;
- *flicker = buf;
+ *flicker = !!buf;
return 0;
}
-
-static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
+int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise)
{
unsigned char buf;
return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1);
}
-static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
+int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise)
{
int ret;
unsigned char buf;
return 0;
}
-static int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
{
unsigned char buf;
return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1);
}
-static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+int pwc_mpt_reset(struct pwc_device *pdev, int flags)
+{
+ int ret;
+ ret = _pwc_mpt_reset(pdev, flags);
+ if (ret >= 0) {
+ pdev->pan_angle = 0;
+ pdev->tilt_angle = 0;
+ }
+ return ret;
+}
+
+static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
{
unsigned char buf[4];
return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4);
}
-static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
+int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
+{
+ int ret;
+
+ /* check absolute ranges */
+ if (pan < pdev->angle_range.pan_min ||
+ pan > pdev->angle_range.pan_max ||
+ tilt < pdev->angle_range.tilt_min ||
+ tilt > pdev->angle_range.tilt_max)
+ return -ERANGE;
+
+ /* go to relative range, check again */
+ pan -= pdev->pan_angle;
+ tilt -= pdev->tilt_angle;
+ /* angles are specified in degrees * 100, thus the limit = 36000 */
+ if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
+ return -ERANGE;
+
+ ret = _pwc_mpt_set_angle(pdev, pan, tilt);
+ if (ret >= 0) {
+ pdev->pan_angle += pan;
+ pdev->tilt_angle += tilt;
+ }
+ if (ret == -EPIPE) /* stall -> out of range */
+ ret = -ERANGE;
+ return ret;
+}
+
+static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
{
int ret;
unsigned char buf[5];
/* End of Add-Ons */
/* ************************************************* */
+/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
+ ioctl() calls. With 2.4, you have to do tedious copy_from_user()
+ and copy_to_user() calls. With these macros we circumvent this,
+ and let me maintain only one source file. The functionality is
+ exactly the same otherwise.
+ */
+
+
+/* define local variable for arg */
+#define ARG_DEF(ARG_type, ARG_name)\
+ ARG_type *ARG_name = arg;
+/* copy arg to local variable */
+#define ARG_IN(ARG_name) /* nothing */
+/* argument itself (referenced) */
+#define ARGR(ARG_name) (*ARG_name)
+/* argument address */
+#define ARGA(ARG_name) ARG_name
+/* copy local variable to arg */
+#define ARG_OUT(ARG_name) /* nothing */
+
int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
case VIDIOCPWCSCQUAL:
{
- int *qual = arg;
+ ARG_DEF(int, qual)
- if (*qual < 0 || *qual > 3)
+ ARG_IN(qual)
+ if (ARGR(qual) < 0 || ARGR(qual) > 3)
ret = -EINVAL;
else
- ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, *qual, pdev->vsnapshot);
+ ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
if (ret >= 0)
- pdev->vcompression = *qual;
+ pdev->vcompression = ARGR(qual);
break;
}
case VIDIOCPWCGCQUAL:
{
- int *qual = arg;
- *qual = pdev->vcompression;
+ ARG_DEF(int, qual)
+
+ ARGR(qual) = pdev->vcompression;
+ ARG_OUT(qual)
break;
}
case VIDIOCPWCPROBE:
{
- struct pwc_probe *probe = arg;
- strcpy(probe->name, pdev->vdev->name);
- probe->type = pdev->type;
+ ARG_DEF(struct pwc_probe, probe)
+
+ strcpy(ARGR(probe).name, pdev->vdev->name);
+ ARGR(probe).type = pdev->type;
+ ARG_OUT(probe)
break;
}
case VIDIOCPWCGSERIAL:
{
- struct pwc_serial *serial = arg;
- strcpy(serial->serial, pdev->serial);
+ ARG_DEF(struct pwc_serial, serial)
+
+ strcpy(ARGR(serial).serial, pdev->serial);
+ ARG_OUT(serial)
break;
}
case VIDIOCPWCSAGC:
{
- int *agc = arg;
- if (pwc_set_agc(pdev, *agc < 0 ? 1 : 0, *agc))
+ ARG_DEF(int, agc)
+
+ ARG_IN(agc)
+ if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc)))
ret = -EINVAL;
break;
}
case VIDIOCPWCGAGC:
{
- int *agc = arg;
+ ARG_DEF(int, agc)
- if (pwc_get_agc(pdev, agc))
+ if (pwc_get_agc(pdev, ARGA(agc)))
ret = -EINVAL;
+ ARG_OUT(agc)
break;
}
case VIDIOCPWCSSHUTTER:
{
- int *shutter_speed = arg;
- ret = pwc_set_shutter_speed(pdev, *shutter_speed < 0 ? 1 : 0, *shutter_speed);
+ ARG_DEF(int, shutter_speed)
+
+ ARG_IN(shutter_speed)
+ ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed));
break;
}
case VIDIOCPWCSAWB:
{
- struct pwc_whitebalance *wb = arg;
+ ARG_DEF(struct pwc_whitebalance, wb)
- ret = pwc_set_awb(pdev, wb->mode);
- if (ret >= 0 && wb->mode == PWC_WB_MANUAL) {
- pwc_set_red_gain(pdev, wb->manual_red);
- pwc_set_blue_gain(pdev, wb->manual_blue);
+ ARG_IN(wb)
+ ret = pwc_set_awb(pdev, ARGR(wb).mode);
+ if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) {
+ pwc_set_red_gain(pdev, ARGR(wb).manual_red);
+ pwc_set_blue_gain(pdev, ARGR(wb).manual_blue);
}
break;
}
case VIDIOCPWCGAWB:
{
- struct pwc_whitebalance *wb = arg;
+ ARG_DEF(struct pwc_whitebalance, wb)
- memset(wb, 0, sizeof(struct pwc_whitebalance));
- wb->mode = pwc_get_awb(pdev);
- if (wb->mode < 0)
+ memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance));
+ ARGR(wb).mode = pwc_get_awb(pdev);
+ if (ARGR(wb).mode < 0)
ret = -EINVAL;
else {
- if (wb->mode == PWC_WB_MANUAL) {
- ret = pwc_get_red_gain(pdev, &wb->manual_red);
+ if (ARGR(wb).mode == PWC_WB_MANUAL) {
+ ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red);
if (ret < 0)
break;
- ret = pwc_get_blue_gain(pdev, &wb->manual_blue);
+ ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue);
if (ret < 0)
break;
}
- if (wb->mode == PWC_WB_AUTO) {
- ret = pwc_read_red_gain(pdev, &wb->read_red);
+ if (ARGR(wb).mode == PWC_WB_AUTO) {
+ ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red);
if (ret < 0)
break;
- ret = pwc_read_blue_gain(pdev, &wb->read_blue);
+ ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue);
if (ret < 0)
break;
}
}
+ ARG_OUT(wb)
break;
}
case VIDIOCPWCSAWBSPEED:
{
- struct pwc_wb_speed *wbs = arg;
+ ARG_DEF(struct pwc_wb_speed, wbs)
- if (wbs->control_speed > 0) {
- ret = pwc_set_wb_speed(pdev, wbs->control_speed);
+ if (ARGR(wbs).control_speed > 0) {
+ ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
}
- if (wbs->control_delay > 0) {
- ret = pwc_set_wb_delay(pdev, wbs->control_delay);
+ if (ARGR(wbs).control_delay > 0) {
+ ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
}
break;
}
case VIDIOCPWCGAWBSPEED:
{
- struct pwc_wb_speed *wbs = arg;
+ ARG_DEF(struct pwc_wb_speed, wbs)
- ret = pwc_get_wb_speed(pdev, &wbs->control_speed);
+ ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
if (ret < 0)
break;
- ret = pwc_get_wb_delay(pdev, &wbs->control_delay);
+ ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
if (ret < 0)
break;
+ ARG_OUT(wbs)
break;
}
case VIDIOCPWCSLED:
{
- struct pwc_leds *leds = arg;
- ret = pwc_set_leds(pdev, leds->led_on, leds->led_off);
- break;
+ ARG_DEF(struct pwc_leds, leds)
+
+ ARG_IN(leds)
+ ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
+ break;
}
case VIDIOCPWCGLED:
{
- struct pwc_leds *leds = arg;
- ret = pwc_get_leds(pdev, &leds->led_on, &leds->led_off);
+ ARG_DEF(struct pwc_leds, leds)
+
+ ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
+ ARG_OUT(leds)
break;
}
case VIDIOCPWCSCONTOUR:
{
- int *contour = arg;
- ret = pwc_set_contour(pdev, *contour);
+ ARG_DEF(int, contour)
+
+ ARG_IN(contour)
+ ret = pwc_set_contour(pdev, ARGR(contour));
break;
}
case VIDIOCPWCGCONTOUR:
{
- int *contour = arg;
- ret = pwc_get_contour(pdev, contour);
+ ARG_DEF(int, contour)
+
+ ret = pwc_get_contour(pdev, ARGA(contour));
+ ARG_OUT(contour)
break;
}
case VIDIOCPWCSBACKLIGHT:
{
- int *backlight = arg;
- ret = pwc_set_backlight(pdev, *backlight);
+ ARG_DEF(int, backlight)
+
+ ARG_IN(backlight)
+ ret = pwc_set_backlight(pdev, ARGR(backlight));
break;
}
case VIDIOCPWCGBACKLIGHT:
{
- int *backlight = arg;
- ret = pwc_get_backlight(pdev, backlight);
+ ARG_DEF(int, backlight)
+
+ ret = pwc_get_backlight(pdev, ARGA(backlight));
+ ARG_OUT(backlight)
break;
}
case VIDIOCPWCSFLICKER:
{
- int *flicker = arg;
- ret = pwc_set_flicker(pdev, *flicker);
+ ARG_DEF(int, flicker)
+
+ ARG_IN(flicker)
+ ret = pwc_set_flicker(pdev, ARGR(flicker));
break;
}
case VIDIOCPWCGFLICKER:
{
- int *flicker = arg;
- ret = pwc_get_flicker(pdev, flicker);
+ ARG_DEF(int, flicker)
+
+ ret = pwc_get_flicker(pdev, ARGA(flicker));
+ ARG_OUT(flicker)
break;
}
case VIDIOCPWCSDYNNOISE:
{
- int *dynnoise = arg;
- ret = pwc_set_dynamic_noise(pdev, *dynnoise);
+ ARG_DEF(int, dynnoise)
+
+ ARG_IN(dynnoise)
+ ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise));
break;
}
case VIDIOCPWCGDYNNOISE:
{
- int *dynnoise = arg;
- ret = pwc_get_dynamic_noise(pdev, dynnoise);
+ ARG_DEF(int, dynnoise)
+
+ ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise));
+ ARG_OUT(dynnoise);
break;
}
case VIDIOCPWCGREALSIZE:
{
- struct pwc_imagesize *size = arg;
- size->width = pdev->image.x;
- size->height = pdev->image.y;
+ ARG_DEF(struct pwc_imagesize, size)
+
+ ARGR(size).width = pdev->image.x;
+ ARGR(size).height = pdev->image.y;
+ ARG_OUT(size)
break;
}
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- int *flags = arg;
+ ARG_DEF(int, flags)
- ret = pwc_mpt_reset(pdev, *flags);
- if (ret >= 0)
- {
- pdev->pan_angle = 0;
- pdev->tilt_angle = 0;
- }
+ ARG_IN(flags)
+ ret = pwc_mpt_reset(pdev, ARGR(flags));
}
else
{
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_range *range = arg;
- *range = pdev->angle_range;
+ ARG_DEF(struct pwc_mpt_range, range)
+
+ ARGR(range) = pdev->angle_range;
+ ARG_OUT(range)
}
else
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_angles *angles = arg;
+ ARG_DEF(struct pwc_mpt_angles, angles)
+
+ ARG_IN(angles)
/* The camera can only set relative angles, so
do some calculations when getting an absolute angle .
*/
- if (angles->absolute)
+ if (ARGR(angles).absolute)
{
- new_pan = angles->pan;
- new_tilt = angles->tilt;
+ new_pan = ARGR(angles).pan;
+ new_tilt = ARGR(angles).tilt;
}
else
{
- new_pan = pdev->pan_angle + angles->pan;
- new_tilt = pdev->tilt_angle + angles->tilt;
- }
- /* check absolute ranges */
- if (new_pan < pdev->angle_range.pan_min ||
- new_pan > pdev->angle_range.pan_max ||
- new_tilt < pdev->angle_range.tilt_min ||
- new_tilt > pdev->angle_range.tilt_max)
- {
- ret = -ERANGE;
- }
- else
- {
- /* go to relative range, check again */
- new_pan -= pdev->pan_angle;
- new_tilt -= pdev->tilt_angle;
- /* angles are specified in degrees * 100, thus the limit = 36000 */
- if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000)
- ret = -ERANGE;
- }
- if (ret == 0) /* no errors so far */
- {
- ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
- if (ret >= 0)
- {
- pdev->pan_angle += new_pan;
- pdev->tilt_angle += new_tilt;
- }
- if (ret == -EPIPE) /* stall -> out of range */
- ret = -ERANGE;
+ new_pan = pdev->pan_angle + ARGR(angles).pan;
+ new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
}
+ ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
}
else
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_angles *angles = arg;
+ ARG_DEF(struct pwc_mpt_angles, angles)
- angles->absolute = 1;
- angles->pan = pdev->pan_angle;
- angles->tilt = pdev->tilt_angle;
+ ARGR(angles).absolute = 1;
+ ARGR(angles).pan = pdev->pan_angle;
+ ARGR(angles).tilt = pdev->tilt_angle;
+ ARG_OUT(angles)
}
else
{
{
if (pdev->features & FEATURE_MOTOR_PANTILT)
{
- struct pwc_mpt_status *status = arg;
- ret = pwc_mpt_get_status(pdev, status);
+ ARG_DEF(struct pwc_mpt_status, status)
+
+ ret = pwc_mpt_get_status(pdev, ARGA(status));
+ ARG_OUT(status)
}
else
{
case VIDIOCPWCGVIDCMD:
{
- struct pwc_video_command *cmd = arg;
-
- cmd->type = pdev->type;
- cmd->release = pdev->release;
- cmd->command_len = pdev->cmd_len;
- memcpy(&cmd->command_buf, pdev->cmd_buf, pdev->cmd_len);
- cmd->bandlength = pdev->vbandlength;
- cmd->frame_size = pdev->frame_size;
+ ARG_DEF(struct pwc_video_command, cmd);
+
+ ARGR(cmd).type = pdev->type;
+ ARGR(cmd).release = pdev->release;
+ ARGR(cmd).command_len = pdev->cmd_len;
+ memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
+ ARGR(cmd).bandlength = pdev->vbandlength;
+ ARGR(cmd).frame_size = pdev->frame_size;
+ ARG_OUT(cmd)
break;
}
/*
case VIDIOCPWCGVIDTABLE:
{
- struct pwc_table_init_buffer *table = arg;
- table->len = pdev->cmd_len;
- memcpy(&table->buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ ARG_DEF(struct pwc_table_init_buffer, table);
+ ARGR(table).len = pdev->cmd_len;
+ memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
+ ARG_OUT(table)
break;
}
*/
}
-
+/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
--- /dev/null
+/* Linux driver for Philips webcam
+ Decompression for chipset version 1
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+#include "pwc-dec1.h"
+
+
+void pwc_dec1_init(int type, int release, void *buffer, void *table)
+{
+
+}
+
+void pwc_dec1_exit(void)
+{
+
+
+
+}
+
+int pwc_dec1_alloc(struct pwc_device *pwc)
+{
+ pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL);
+ if (pwc->decompress_data == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
--- /dev/null
+/* Linux driver for Philips webcam
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+
+
+#ifndef PWC_DEC1_H
+#define PWC_DEC1_H
+
+#include "pwc.h"
+
+struct pwc_dec1_private
+{
+ int version;
+
+};
+
+int pwc_dec1_alloc(struct pwc_device *pwc);
+void pwc_dec1_init(int type, int release, void *buffer, void *private_data);
+void pwc_dec1_exit(void);
+
+#endif
+
--- /dev/null
+/* Linux driver for Philips webcam
+ Decompression for chipset version 2 et 3
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include "pwc-timon.h"
+#include "pwc-kiara.h"
+#include "pwc-dec23.h"
+#include <media/pwc-ioctl.h>
+
+#include <linux/string.h>
+
+/*
+ * USE_LOOKUP_TABLE_TO_CLAMP
+ * 0: use a C version of this tests: { a<0?0:(a>255?255:a) }
+ * 1: use a faster lookup table for cpu with a big cache (intel)
+ */
+#define USE_LOOKUP_TABLE_TO_CLAMP 1
+/*
+ * UNROLL_LOOP_FOR_COPYING_BLOCK
+ * 0: use a loop for a smaller code (but little slower)
+ * 1: when unrolling the loop, gcc produces some faster code (perhaps only
+ * valid for intel processor class). Activating this option, automaticaly
+ * activate USE_LOOKUP_TABLE_TO_CLAMP
+ */
+#define UNROLL_LOOP_FOR_COPY 1
+#if UNROLL_LOOP_FOR_COPY
+# undef USE_LOOKUP_TABLE_TO_CLAMP
+# define USE_LOOKUP_TABLE_TO_CLAMP 1
+#endif
+
+/*
+ * ENABLE_BAYER_DECODER
+ * 0: bayer decoder is not build (save some space)
+ * 1: bayer decoder is build and can be used
+ */
+#define ENABLE_BAYER_DECODER 0
+
+static void build_subblock_pattern(struct pwc_dec23_private *pdec)
+{
+ static const unsigned int initial_values[12] = {
+ -0x526500, -0x221200, 0x221200, 0x526500,
+ -0x3de200, 0x3de200,
+ -0x6db480, -0x2d5d00, 0x2d5d00, 0x6db480,
+ -0x12c200, 0x12c200
+
+ };
+ static const unsigned int values_derivated[12] = {
+ 0xa4ca, 0x4424, -0x4424, -0xa4ca,
+ 0x7bc4, -0x7bc4,
+ 0xdb69, 0x5aba, -0x5aba, -0xdb69,
+ 0x2584, -0x2584
+ };
+ unsigned int temp_values[12];
+ int i, j;
+
+ memcpy(temp_values, initial_values, sizeof(initial_values));
+ for (i = 0; i < 256; i++) {
+ for (j = 0; j < 12; j++) {
+ pdec->table_subblock[i][j] = temp_values[j];
+ temp_values[j] += values_derivated[j];
+ }
+ }
+}
+
+static void build_bit_powermask_table(struct pwc_dec23_private *pdec)
+{
+ unsigned char *p;
+ unsigned int bit, byte, mask, val;
+ unsigned int bitpower = 1;
+
+ for (bit = 0; bit < 8; bit++) {
+ mask = bitpower - 1;
+ p = pdec->table_bitpowermask[bit];
+ for (byte = 0; byte < 256; byte++) {
+ val = (byte & mask);
+ if (byte & bitpower)
+ val = -val;
+ *p++ = val;
+ }
+ bitpower<<=1;
+ }
+}
+
+
+static void build_table_color(const unsigned int romtable[16][8],
+ unsigned char p0004[16][1024],
+ unsigned char p8004[16][256])
+{
+ int compression_mode, j, k, bit, pw;
+ unsigned char *p0, *p8;
+ const unsigned int *r;
+
+ /* We have 16 compressions tables */
+ for (compression_mode = 0; compression_mode < 16; compression_mode++) {
+ p0 = p0004[compression_mode];
+ p8 = p8004[compression_mode];
+ r = romtable[compression_mode];
+
+ for (j = 0; j < 8; j++, r++, p0 += 128) {
+
+ for (k = 0; k < 16; k++) {
+ if (k == 0)
+ bit = 1;
+ else if (k >= 1 && k < 3)
+ bit = (r[0] >> 15) & 7;
+ else if (k >= 3 && k < 6)
+ bit = (r[0] >> 12) & 7;
+ else if (k >= 6 && k < 10)
+ bit = (r[0] >> 9) & 7;
+ else if (k >= 10 && k < 13)
+ bit = (r[0] >> 6) & 7;
+ else if (k >= 13 && k < 15)
+ bit = (r[0] >> 3) & 7;
+ else
+ bit = (r[0]) & 7;
+ if (k == 0)
+ *p8++ = 8;
+ else
+ *p8++ = j - bit;
+ *p8++ = bit;
+
+ pw = 1 << bit;
+ p0[k + 0x00] = (1 * pw) + 0x80;
+ p0[k + 0x10] = (2 * pw) + 0x80;
+ p0[k + 0x20] = (3 * pw) + 0x80;
+ p0[k + 0x30] = (4 * pw) + 0x80;
+ p0[k + 0x40] = (-1 * pw) + 0x80;
+ p0[k + 0x50] = (-2 * pw) + 0x80;
+ p0[k + 0x60] = (-3 * pw) + 0x80;
+ p0[k + 0x70] = (-4 * pw) + 0x80;
+ } /* end of for (k=0; k<16; k++, p8++) */
+ } /* end of for (j=0; j<8; j++ , table++) */
+ } /* end of foreach compression_mode */
+}
+
+/*
+ *
+ */
+static void fill_table_dc00_d800(struct pwc_dec23_private *pdec)
+{
+#define SCALEBITS 15
+#define ONE_HALF (1UL << (SCALEBITS - 1))
+ int i;
+ unsigned int offset1 = ONE_HALF;
+ unsigned int offset2 = 0x0000;
+
+ for (i=0; i<256; i++) {
+ pdec->table_dc00[i] = offset1 & ~(ONE_HALF);
+ pdec->table_d800[i] = offset2;
+
+ offset1 += 0x7bc4;
+ offset2 += 0x7bc4;
+ }
+}
+
+/*
+ * To decode the stream:
+ * if look_bits(2) == 0: # op == 2 in the lookup table
+ * skip_bits(2)
+ * end of the stream
+ * elif look_bits(3) == 7: # op == 1 in the lookup table
+ * skip_bits(3)
+ * yyyy = get_bits(4)
+ * xxxx = get_bits(8)
+ * else: # op == 0 in the lookup table
+ * skip_bits(x)
+ *
+ * For speedup processing, we build a lookup table and we takes the first 6 bits.
+ *
+ * struct {
+ * unsigned char op; // operation to execute
+ * unsigned char bits; // bits use to perform operation
+ * unsigned char offset1; // offset to add to access in the table_0004 % 16
+ * unsigned char offset2; // offset to add to access in the table_0004
+ * }
+ *
+ * How to build this table ?
+ * op == 2 when (i%4)==0
+ * op == 1 when (i%8)==7
+ * op == 0 otherwise
+ *
+ */
+static const unsigned char hash_table_ops[64*4] = {
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x01, 0x30,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x20,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x02, 0x10,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x60,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x40,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x40,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x01, 0x70,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x20,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x00,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x10,
+ 0x00, 0x06, 0x02, 0x50,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x01, 0x60,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x00,
+ 0x00, 0x04, 0x01, 0x50,
+ 0x00, 0x05, 0x02, 0x40,
+ 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x03, 0x01, 0x40,
+ 0x00, 0x05, 0x03, 0x40,
+ 0x01, 0x00, 0x00, 0x00
+};
+
+/*
+ *
+ */
+static const unsigned int MulIdx[16][16] = {
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,},
+ {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3,},
+ {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,},
+ {4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4,},
+ {6, 7, 8, 9, 7, 10, 11, 8, 8, 11, 10, 7, 9, 8, 7, 6,},
+ {4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4,},
+ {1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2,},
+ {0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3,},
+ {0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3,},
+ {1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2,},
+ {7, 10, 11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8, 11, 10, 7,},
+ {4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4,},
+ {7, 9, 6, 8, 10, 8, 7, 11, 11, 7, 8, 10, 8, 6, 9, 7,},
+ {1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2,},
+ {1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2,},
+ {10, 8, 7, 11, 8, 6, 9, 7, 7, 9, 6, 8, 11, 7, 8, 10}
+};
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+#define MAX_OUTER_CROP_VALUE (512)
+static unsigned char pwc_crop_table[256 + 2*MAX_OUTER_CROP_VALUE];
+#define CLAMP(x) (pwc_crop_table[MAX_OUTER_CROP_VALUE+(x)])
+#else
+#define CLAMP(x) ((x)>255?255:((x)<0?0:x))
+#endif
+
+
+/* If the type or the command change, we rebuild the lookup table */
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd)
+{
+ int flags, version, shift, i;
+ struct pwc_dec23_private *pdec;
+
+ if (pwc->decompress_data == NULL) {
+ pdec = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+ if (pdec == NULL)
+ return -ENOMEM;
+ pwc->decompress_data = pdec;
+ }
+ pdec = pwc->decompress_data;
+
+ if (DEVICE_USE_CODEC3(type)) {
+ flags = cmd[2] & 0x18;
+ if (flags == 8)
+ pdec->nbits = 7; /* More bits, mean more bits to encode the stream, but better quality */
+ else if (flags == 0x10)
+ pdec->nbits = 8;
+ else
+ pdec->nbits = 6;
+
+ version = cmd[2] >> 5;
+ build_table_color(KiaraRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+ build_table_color(KiaraRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+
+ } else {
+
+ flags = cmd[2] & 6;
+ if (flags == 2)
+ pdec->nbits = 7;
+ else if (flags == 4)
+ pdec->nbits = 8;
+ else
+ pdec->nbits = 6;
+
+ version = cmd[2] >> 3;
+ build_table_color(TimonRomTable[version][0], pdec->table_0004_pass1, pdec->table_8004_pass1);
+ build_table_color(TimonRomTable[version][1], pdec->table_0004_pass2, pdec->table_8004_pass2);
+ }
+
+ /* Informations can be coded on a variable number of bits but never less than 8 */
+ shift = 8 - pdec->nbits;
+ pdec->scalebits = SCALEBITS - shift;
+ pdec->nbitsmask = 0xFF >> shift;
+
+ fill_table_dc00_d800(pdec);
+ build_subblock_pattern(pdec);
+ build_bit_powermask_table(pdec);
+
+#if USE_LOOKUP_TABLE_TO_CLAMP
+ /* Build the static table to clamp value [0-255] */
+ for (i=0;i<MAX_OUTER_CROP_VALUE;i++)
+ pwc_crop_table[i] = 0;
+ for (i=0; i<256; i++)
+ pwc_crop_table[MAX_OUTER_CROP_VALUE+i] = i;
+ for (i=0; i<MAX_OUTER_CROP_VALUE; i++)
+ pwc_crop_table[MAX_OUTER_CROP_VALUE+256+i] = 255;
+#endif
+
+ return 0;
+}
+
+/*
+ * Copy the 4x4 image block to Y plane buffer
+ */
+static void copy_image_block_Y(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ const int *c = src;
+ unsigned char *d = dst;
+
+ *d++ = cm[c[0] >> scalebits];
+ *d++ = cm[c[1] >> scalebits];
+ *d++ = cm[c[2] >> scalebits];
+ *d++ = cm[c[3] >> scalebits];
+
+ d = dst + bytes_per_line;
+ *d++ = cm[c[4] >> scalebits];
+ *d++ = cm[c[5] >> scalebits];
+ *d++ = cm[c[6] >> scalebits];
+ *d++ = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line*2;
+ *d++ = cm[c[8] >> scalebits];
+ *d++ = cm[c[9] >> scalebits];
+ *d++ = cm[c[10] >> scalebits];
+ *d++ = cm[c[11] >> scalebits];
+
+ d = dst + bytes_per_line*3;
+ *d++ = cm[c[12] >> scalebits];
+ *d++ = cm[c[13] >> scalebits];
+ *d++ = cm[c[14] >> scalebits];
+ *d++ = cm[c[15] >> scalebits];
+#else
+ int i;
+ const int *c = src;
+ unsigned char *d = dst;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*2;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*3;
+ for (i = 0; i < 4; i++, c++)
+ *d++ = CLAMP((*c) >> scalebits);
+#endif
+}
+
+/*
+ * Copy the 4x4 image block to a CrCb plane buffer
+ *
+ */
+static void copy_image_block_CrCb(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ const int *c = src;
+ unsigned char *d = dst;
+
+ *d++ = cm[c[0] >> scalebits];
+ *d++ = cm[c[4] >> scalebits];
+ *d++ = cm[c[1] >> scalebits];
+ *d++ = cm[c[5] >> scalebits];
+ *d++ = cm[c[2] >> scalebits];
+ *d++ = cm[c[6] >> scalebits];
+ *d++ = cm[c[3] >> scalebits];
+ *d++ = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line;
+ *d++ = cm[c[12] >> scalebits];
+ *d++ = cm[c[8] >> scalebits];
+ *d++ = cm[c[13] >> scalebits];
+ *d++ = cm[c[9] >> scalebits];
+ *d++ = cm[c[14] >> scalebits];
+ *d++ = cm[c[10] >> scalebits];
+ *d++ = cm[c[15] >> scalebits];
+ *d++ = cm[c[11] >> scalebits];
+#else
+ int i;
+ const int *c1 = src;
+ const int *c2 = src + 4;
+ unsigned char *d = dst;
+
+ for (i = 0; i < 4; i++, c1++, c2++) {
+ *d++ = CLAMP((*c1) >> scalebits);
+ *d++ = CLAMP((*c2) >> scalebits);
+ }
+ c1 = src + 12;
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c1++, c2++) {
+ *d++ = CLAMP((*c1) >> scalebits);
+ *d++ = CLAMP((*c2) >> scalebits);
+ }
+#endif
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 8x2 pixels
+ * . G . G . G . G . G . G . G
+ * . . . . . . . . . . . . . .
+ * . G . G . G . G . G . G . G
+ * . . . . . . . . . . . . . .
+ * or
+ * . . . . . . . . . . . . . .
+ * G . G . G . G . G . G . G .
+ * . . . . . . . . . . . . . .
+ * G . G . G . G . G . G . G .
+*/
+static void copy_image_block_Green(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ unsigned char *d = dst;
+ const int *c = src;
+
+ d[0] = cm[c[0] >> scalebits];
+ d[2] = cm[c[1] >> scalebits];
+ d[4] = cm[c[2] >> scalebits];
+ d[6] = cm[c[3] >> scalebits];
+ d[8] = cm[c[4] >> scalebits];
+ d[10] = cm[c[5] >> scalebits];
+ d[12] = cm[c[6] >> scalebits];
+ d[14] = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line;
+ d[0] = cm[c[8] >> scalebits];
+ d[2] = cm[c[9] >> scalebits];
+ d[4] = cm[c[10] >> scalebits];
+ d[6] = cm[c[11] >> scalebits];
+ d[8] = cm[c[12] >> scalebits];
+ d[10] = cm[c[13] >> scalebits];
+ d[12] = cm[c[14] >> scalebits];
+ d[14] = cm[c[15] >> scalebits];
+#else
+ int i;
+ unsigned char *d;
+ const int *c = src;
+
+ d = dst;
+ for (i = 0; i < 8; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 8; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Format: 4x4 pixels
+ * R . R . R . R
+ * . B . B . B .
+ * R . R . R . R
+ * . B . B . B .
+ */
+static void copy_image_block_RedBlue(const int *src, unsigned char *dst, unsigned int bytes_per_line, unsigned int scalebits)
+{
+#if UNROLL_LOOP_FOR_COPY
+ /* Unroll all loops */
+ const unsigned char *cm = pwc_crop_table+MAX_OUTER_CROP_VALUE;
+ unsigned char *d = dst;
+ const int *c = src;
+
+ d[0] = cm[c[0] >> scalebits];
+ d[2] = cm[c[1] >> scalebits];
+ d[4] = cm[c[2] >> scalebits];
+ d[6] = cm[c[3] >> scalebits];
+
+ d = dst + bytes_per_line;
+ d[1] = cm[c[4] >> scalebits];
+ d[3] = cm[c[5] >> scalebits];
+ d[5] = cm[c[6] >> scalebits];
+ d[7] = cm[c[7] >> scalebits];
+
+ d = dst + bytes_per_line*2;
+ d[0] = cm[c[8] >> scalebits];
+ d[2] = cm[c[9] >> scalebits];
+ d[4] = cm[c[10] >> scalebits];
+ d[6] = cm[c[11] >> scalebits];
+
+ d = dst + bytes_per_line*3;
+ d[1] = cm[c[12] >> scalebits];
+ d[3] = cm[c[13] >> scalebits];
+ d[5] = cm[c[14] >> scalebits];
+ d[7] = cm[c[15] >> scalebits];
+#else
+ int i;
+ unsigned char *d;
+ const int *c = src;
+
+ d = dst;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2+1] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*2;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2] = CLAMP((*c) >> scalebits);
+
+ d = dst + bytes_per_line*3;
+ for (i = 0; i < 4; i++, c++)
+ d[i*2+1] = CLAMP((*c) >> scalebits);
+#endif
+}
+#endif
+
+/*
+ * To manage the stream, we keep bits in a 32 bits register.
+ * fill_nbits(n): fill the reservoir with at least n bits
+ * skip_bits(n): discard n bits from the reservoir
+ * get_bits(n): fill the reservoir, returns the first n bits and discard the
+ * bits from the reservoir.
+ * __get_nbits(n): faster version of get_bits(n), but asumes that the reservoir
+ * contains at least n bits. bits returned is discarded.
+ */
+#define fill_nbits(pdec, nbits_wanted) do { \
+ while (pdec->nbits_in_reservoir<(nbits_wanted)) \
+ { \
+ pdec->reservoir |= (*(pdec->stream)++) << (pdec->nbits_in_reservoir); \
+ pdec->nbits_in_reservoir += 8; \
+ } \
+} while(0);
+
+#define skip_nbits(pdec, nbits_to_skip) do { \
+ pdec->reservoir >>= (nbits_to_skip); \
+ pdec->nbits_in_reservoir -= (nbits_to_skip); \
+} while(0);
+
+#define get_nbits(pdec, nbits_wanted, result) do { \
+ fill_nbits(pdec, nbits_wanted); \
+ result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+ skip_nbits(pdec, nbits_wanted); \
+} while(0);
+
+#define __get_nbits(pdec, nbits_wanted, result) do { \
+ result = (pdec->reservoir) & ((1U<<(nbits_wanted))-1); \
+ skip_nbits(pdec, nbits_wanted); \
+} while(0);
+
+#define look_nbits(pdec, nbits_wanted) \
+ ((pdec->reservoir) & ((1U<<(nbits_wanted))-1))
+
+/*
+ * Decode a 4x4 pixel block
+ */
+static void decode_block(struct pwc_dec23_private *pdec,
+ const unsigned char *ptable0004,
+ const unsigned char *ptable8004)
+{
+ unsigned int primary_color;
+ unsigned int channel_v, offset1, op;
+ int i;
+
+ fill_nbits(pdec, 16);
+ __get_nbits(pdec, pdec->nbits, primary_color);
+
+ if (look_nbits(pdec,2) == 0) {
+ skip_nbits(pdec, 2);
+ /* Very simple, the color is the same for all pixels of the square */
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] = pdec->table_dc00[primary_color];
+
+ return;
+ }
+
+ /* This block is encoded with small pattern */
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] = pdec->table_d800[primary_color];
+
+ __get_nbits(pdec, 3, channel_v);
+ channel_v = ((channel_v & 1) << 2) | (channel_v & 2) | ((channel_v & 4) >> 2);
+
+ ptable0004 += (channel_v * 128);
+ ptable8004 += (channel_v * 32);
+
+ offset1 = 0;
+ do
+ {
+ unsigned int htable_idx, rows = 0;
+ const unsigned int *block;
+
+ /* [ zzzz y x x ]
+ * xx == 00 :=> end of the block def, remove the two bits from the stream
+ * yxx == 111
+ * yxx == any other value
+ *
+ */
+ fill_nbits(pdec, 16);
+ htable_idx = look_nbits(pdec, 6);
+ op = hash_table_ops[htable_idx * 4];
+
+ if (op == 2) {
+ skip_nbits(pdec, 2);
+
+ } else if (op == 1) {
+ /* 15bits [ xxxx xxxx yyyy 111 ]
+ * yyy => offset in the table8004
+ * xxx => offset in the tabled004 (tree)
+ */
+ unsigned int mask, shift;
+ unsigned int nbits, col1;
+ unsigned int yyyy;
+
+ skip_nbits(pdec, 3);
+ /* offset1 += yyyy */
+ __get_nbits(pdec, 4, yyyy);
+ offset1 += 1 + yyyy;
+ offset1 &= 0x0F;
+ nbits = ptable8004[offset1 * 2];
+
+ /* col1 = xxxx xxxx */
+ __get_nbits(pdec, nbits+1, col1);
+
+ /* Bit mask table */
+ mask = pdec->table_bitpowermask[nbits][col1];
+ shift = ptable8004[offset1 * 2 + 1];
+ rows = ((mask << shift) + 0x80) & 0xFF;
+
+ block = pdec->table_subblock[rows];
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+ } else {
+ /* op == 0
+ * offset1 is coded on 3 bits
+ */
+ unsigned int shift;
+
+ offset1 += hash_table_ops [htable_idx * 4 + 2];
+ offset1 &= 0x0F;
+
+ rows = ptable0004[offset1 + hash_table_ops [htable_idx * 4 + 3]];
+ block = pdec->table_subblock[rows];
+ for (i = 0; i < 16; i++)
+ pdec->temp_colors[i] += block[MulIdx[offset1][i]];
+
+ shift = hash_table_ops[htable_idx * 4 + 1];
+ skip_nbits(pdec, shift);
+ }
+
+ } while (op != 2);
+
+}
+
+static void DecompressBand23(struct pwc_dec23_private *pdec,
+ const unsigned char *rawyuv,
+ unsigned char *planar_y,
+ unsigned char *planar_u,
+ unsigned char *planar_v,
+ unsigned int compressed_image_width,
+ unsigned int real_image_width)
+{
+ int compression_index, nblocks;
+ const unsigned char *ptable0004;
+ const unsigned char *ptable8004;
+
+ pdec->reservoir = 0;
+ pdec->nbits_in_reservoir = 0;
+ pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
+
+ get_nbits(pdec, 4, compression_index);
+
+ /* pass 1: uncompress Y component */
+ nblocks = compressed_image_width / 4;
+
+ ptable0004 = pdec->table_0004_pass1[compression_index];
+ ptable8004 = pdec->table_8004_pass1[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Y(pdec->temp_colors, planar_y, real_image_width, pdec->scalebits);
+ planar_y += 4;
+ nblocks--;
+ }
+
+ /* pass 2: uncompress UV component */
+ nblocks = compressed_image_width / 8;
+
+ ptable0004 = pdec->table_0004_pass2[compression_index];
+ ptable8004 = pdec->table_8004_pass2[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_CrCb(pdec->temp_colors, planar_u, real_image_width/2, pdec->scalebits);
+
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_CrCb(pdec->temp_colors, planar_v, real_image_width/2, pdec->scalebits);
+
+ planar_v += 8;
+ planar_u += 8;
+ nblocks -= 2;
+ }
+
+}
+
+#if ENABLE_BAYER_DECODER
+/*
+ * Size need to be a multiple of 8 in width
+ *
+ * Return a block of four line encoded like this:
+ *
+ * G R G R G R G R G R G R G R G R
+ * B G B G B G B G B G B G B G B G
+ * G R G R G R G R G R G R G R G R
+ * B G B G B G B G B G B G B G B G
+ *
+ */
+static void DecompressBandBayer(struct pwc_dec23_private *pdec,
+ const unsigned char *rawyuv,
+ unsigned char *rgbbayer,
+ unsigned int compressed_image_width,
+ unsigned int real_image_width)
+{
+ int compression_index, nblocks;
+ const unsigned char *ptable0004;
+ const unsigned char *ptable8004;
+ unsigned char *dest;
+
+ pdec->reservoir = 0;
+ pdec->nbits_in_reservoir = 0;
+ pdec->stream = rawyuv + 1; /* The first byte of the stream is skipped */
+
+ get_nbits(pdec, 4, compression_index);
+
+ /* pass 1: uncompress RB component */
+ nblocks = compressed_image_width / 4;
+
+ ptable0004 = pdec->table_0004_pass1[compression_index];
+ ptable8004 = pdec->table_8004_pass1[compression_index];
+ dest = rgbbayer;
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_RedBlue(pdec->temp_colors, rgbbayer, real_image_width, pdec->scalebits);
+ dest += 8;
+ nblocks--;
+ }
+
+ /* pass 2: uncompress G component */
+ nblocks = compressed_image_width / 8;
+
+ ptable0004 = pdec->table_0004_pass2[compression_index];
+ ptable8004 = pdec->table_8004_pass2[compression_index];
+
+ /* Each block decode a square of 4x4 */
+ while (nblocks) {
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Green(pdec->temp_colors, rgbbayer+1, real_image_width, pdec->scalebits);
+
+ decode_block(pdec, ptable0004, ptable8004);
+ copy_image_block_Green(pdec->temp_colors, rgbbayer+real_image_width, real_image_width, pdec->scalebits);
+
+ rgbbayer += 16;
+ nblocks -= 2;
+ }
+}
+#endif
+
+
+/**
+ *
+ * Uncompress a pwc23 buffer.
+ *
+ * pwc.view: size of the image wanted
+ * pwc.image: size of the image returned by the camera
+ * pwc.offset: (x,y) to displayer image in the view
+ *
+ * src: raw data
+ * dst: image output
+ * flags: PWCX_FLAG_PLANAR or PWCX_FLAG_BAYER
+ */
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+ const void *src,
+ void *dst,
+ int flags)
+{
+ int bandlines_left, stride, bytes_per_block;
+
+ bandlines_left = pwc->image.y / 4;
+ bytes_per_block = pwc->view.x * 4;
+
+ if (flags & PWCX_FLAG_BAYER) {
+#if ENABLE_BAYER_DECODER
+ /* RGB Bayer format */
+ unsigned char *rgbout;
+
+ stride = pwc->view.x * pwc->offset.y;
+ rgbout = dst + stride + pwc->offset.x;
+
+
+ while (bandlines_left--) {
+
+ DecompressBandBayer(pwc->decompress_data,
+ src,
+ rgbout,
+ pwc->image.x, pwc->view.x);
+
+ src += pwc->vbandlength;
+ rgbout += bytes_per_block;
+
+ }
+#else
+ memset(dst, 0, pwc->view.x * pwc->view.y);
+#endif
+
+ } else {
+ /* YUV420P image format */
+ unsigned char *pout_planar_y;
+ unsigned char *pout_planar_u;
+ unsigned char *pout_planar_v;
+ unsigned int plane_size;
+
+ plane_size = pwc->view.x * pwc->view.y;
+
+ /* offset in Y plane */
+ stride = pwc->view.x * pwc->offset.y;
+ pout_planar_y = dst + stride + pwc->offset.x;
+
+ /* offsets in U/V planes */
+ stride = (pwc->view.x * pwc->offset.y) / 4 + pwc->offset.x / 2;
+ pout_planar_u = dst + plane_size + stride;
+ pout_planar_v = dst + plane_size + plane_size / 4 + stride;
+
+ while (bandlines_left--) {
+
+ DecompressBand23(pwc->decompress_data,
+ src,
+ pout_planar_y, pout_planar_u, pout_planar_v,
+ pwc->image.x, pwc->view.x);
+ src += pwc->vbandlength;
+ pout_planar_y += bytes_per_block;
+ pout_planar_u += pwc->view.x;
+ pout_planar_v += pwc->view.x;
+
+ }
+
+ }
+
+}
+
+void pwc_dec23_exit(void)
+{
+ /* Do nothing */
+
+}
+
+/**
+ * Allocate a private structure used by lookup table.
+ * You must call kfree() to free the memory allocated.
+ */
+int pwc_dec23_alloc(struct pwc_device *pwc)
+{
+ pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
+ if (pwc->decompress_data == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
--- /dev/null
+/* Linux driver for Philips webcam
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#ifndef PWC_DEC23_H
+#define PWC_DEC23_H
+
+#include "pwc.h"
+
+struct pwc_dec23_private
+{
+ unsigned int scalebits;
+ unsigned int nbitsmask, nbits; /* Number of bits of a color in the compressed stream */
+
+ unsigned int reservoir;
+ unsigned int nbits_in_reservoir;
+ const unsigned char *stream;
+ int temp_colors[16];
+
+ unsigned char table_0004_pass1[16][1024];
+ unsigned char table_0004_pass2[16][1024];
+ unsigned char table_8004_pass1[16][256];
+ unsigned char table_8004_pass2[16][256];
+ unsigned int table_subblock[256][12];
+
+ unsigned char table_bitpowermask[8][256];
+ unsigned int table_d800[256];
+ unsigned int table_dc00[256];
+
+};
+
+
+int pwc_dec23_alloc(struct pwc_device *pwc);
+int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd);
+void pwc_dec23_exit(void);
+void pwc_dec23_decompress(const struct pwc_device *pwc,
+ const void *src,
+ void *dst,
+ int flags);
+
+
+
+#endif
+
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
+
/* Linux driver for Philips webcam
USB and Video4Linux interface part.
(C) 1999-2004 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <linux/version.h>
#include <asm/io.h>
+#include <linux/moduleparam.h>
#include "pwc.h"
-#include "pwc-ioctl.h"
#include "pwc-kiara.h"
#include "pwc-timon.h"
+#include "pwc-dec23.h"
+#include "pwc-dec1.h"
#include "pwc-uncompress.h"
/* Function prototypes and driver templates */
/* hotplug device table support */
-static struct usb_device_id pwc_device_table [] = {
+static const struct usb_device_id pwc_device_table [] = {
{ USB_DEVICE(0x0471, 0x0302) }, /* Philips models */
{ USB_DEVICE(0x0471, 0x0303) },
{ USB_DEVICE(0x0471, 0x0304) },
{ USB_DEVICE(0x0471, 0x0308) },
{ USB_DEVICE(0x0471, 0x030C) },
{ USB_DEVICE(0x0471, 0x0310) },
- { USB_DEVICE(0x0471, 0x0311) },
+ { USB_DEVICE(0x0471, 0x0311) }, /* Philips ToUcam PRO II */
{ USB_DEVICE(0x0471, 0x0312) },
{ USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */
+ { USB_DEVICE(0x0471, 0x0329) }, /* Philips SPC 900NC PC Camera */
{ USB_DEVICE(0x069A, 0x0001) }, /* Askey */
{ USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */
{ USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */
{ USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */
{ USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */
- { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */
- { USB_DEVICE(0x055D, 0x9001) },
+ { USB_DEVICE(0x055D, 0x9000) }, /* Samsung MPC-C10 */
+ { USB_DEVICE(0x055D, 0x9001) }, /* Samsung MPC-C30 */
+ { USB_DEVICE(0x055D, 0x9002) }, /* Samsung SNC-35E (Ver3.0) */
{ USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */
{ USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */
{ USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */
static int default_size = PSZ_QCIF;
static int default_fps = 10;
static int default_fbufs = 3; /* Default number of frame buffers */
-static int default_mbufs = 2; /* Default number of mmap() buffers */
- int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX;
+ int pwc_mbufs = 2; /* Default number of mmap() buffers */
+#if CONFIG_PWC_DEBUG
+ int pwc_trace = PWC_DEBUG_LEVEL;
+#endif
static int power_save = 0;
static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
-static int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */
+static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
static struct {
int type;
char serial_number[30];
static int pwc_video_open(struct inode *inode, struct file *file);
static int pwc_video_close(struct inode *inode, struct file *file);
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static unsigned int pwc_video_poll(struct file *file, poll_table *wait);
static int pwc_video_ioctl(struct inode *inode, struct file *file,
.poll = pwc_video_poll,
.mmap = pwc_video_mmap,
.ioctl = pwc_video_ioctl,
- .compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
static struct video_device pwc_template = {
/* Here we want the physical address of the memory.
* This is used when initializing the contents of the area.
*/
-static inline unsigned long kvirt_to_pa(unsigned long adr)
-{
- unsigned long kva, ret;
- kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
- kva |= adr & (PAGE_SIZE-1); /* restore the offset */
- ret = __pa(kva);
- return ret;
-}
-static void * rvmalloc(unsigned long size)
+
+static void *pwc_rvmalloc(unsigned long size)
{
void * mem;
unsigned long adr;
- size=PAGE_ALIGN(size);
mem=vmalloc_32(size);
- if (mem)
- {
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr=(unsigned long) mem;
- while (size > 0)
- {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- }
+ if (!mem)
+ return NULL;
+
+ memset(mem, 0, size); /* Clear the ram out, no junk to the user */
+ adr=(unsigned long) mem;
+ while (size > 0)
+ {
+ SetPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
return mem;
}
-static void rvfree(void * mem, unsigned long size)
+static void pwc_rvfree(void * mem, unsigned long size)
{
unsigned long adr;
- if (mem)
- {
- adr=(unsigned long) mem;
- while ((long) size > 0)
- {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr+=PAGE_SIZE;
- size-=PAGE_SIZE;
- }
- vfree(mem);
- }
+ if (!mem)
+ return;
+
+ adr=(unsigned long) mem;
+ while ((long) size > 0)
+ {
+ ClearPageReserved(vmalloc_to_page((void *)adr));
+ adr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+ vfree(mem);
}
static int pwc_allocate_buffers(struct pwc_device *pdev)
{
- int i;
+ int i, err;
void *kbuf;
- Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
+ PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev);
if (pdev == NULL)
return -ENXIO;
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("allocate_buffers(): magic failed.\n");
- return -ENXIO;
- }
-#endif
- /* Allocate Isochronous pipe buffers */
+ /* Allocate Isochronuous pipe buffers */
for (i = 0; i < MAX_ISO_BUFS; i++) {
if (pdev->sbuf[i].data == NULL) {
- kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
+ kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL);
if (kbuf == NULL) {
- Err("Failed to allocate iso buffer %d.\n", i);
+ PWC_ERROR("Failed to allocate iso buffer %d.\n", i);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf);
pdev->sbuf[i].data = kbuf;
- memset(kbuf, 0, ISO_BUFFER_SIZE);
}
}
/* Allocate frame buffer structure */
if (pdev->fbuf == NULL) {
- kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
+ kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL);
if (kbuf == NULL) {
- Err("Failed to allocate frame buffer structure.\n");
+ PWC_ERROR("Failed to allocate frame buffer structure.\n");
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf);
pdev->fbuf = kbuf;
- memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf));
}
+
/* create frame buffers, and make circular ring */
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data == NULL) {
kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
if (kbuf == NULL) {
- Err("Failed to allocate frame buffer %d.\n", i);
+ PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf);
+ PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
pdev->fbuf[i].data = kbuf;
- memset(kbuf, 128, PWC_FRAME_SIZE);
+ memset(kbuf, 0, PWC_FRAME_SIZE);
}
}
/* Allocate decompressor table space */
- kbuf = NULL;
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-#if 0
- Trace(TRACE_MEMORY,"private_data(%zu)\n",sizeof(struct pwc_dec23_private));
- kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */
- break;
- case 645:
- case 646:
- /* TODO & FIXME */
- kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL);
- break;
-#endif
- ;
- }
- pdev->decompress_data = kbuf;
+ if (DEVICE_USE_CODEC1(pdev->type))
+ err = pwc_dec1_alloc(pdev);
+ else
+ err = pwc_dec23_alloc(pdev);
+
+ if (err) {
+ PWC_ERROR("Failed to allocate decompress table.\n");
+ return err;
+ }
/* Allocate image buffer; double buffer for mmap() */
- kbuf = rvmalloc(default_mbufs * pdev->len_per_image);
+ kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image);
if (kbuf == NULL) {
- Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image);
+ PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n",
+ pwc_mbufs * pdev->len_per_image);
return -ENOMEM;
}
- Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf);
+ PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf);
pdev->image_data = kbuf;
- for (i = 0; i < default_mbufs; i++)
- pdev->image_ptr[i] = kbuf + i * pdev->len_per_image;
- for (; i < MAX_IMAGES; i++)
- pdev->image_ptr[i] = NULL;
+ for (i = 0; i < pwc_mbufs; i++) {
+ pdev->images[i].offset = i * pdev->len_per_image;
+ pdev->images[i].vma_use_count = 0;
+ }
+ for (; i < MAX_IMAGES; i++) {
+ pdev->images[i].offset = 0;
+ }
kbuf = NULL;
- Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n");
+ PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n");
return 0;
}
{
int i;
- Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev);
+ PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev);
if (pdev == NULL)
return;
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("free_buffers(): magic failed.\n");
- return;
- }
-#endif
-
/* Release Iso-pipe buffers */
for (i = 0; i < MAX_ISO_BUFS; i++)
if (pdev->sbuf[i].data != NULL) {
- Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
+ PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data);
kfree(pdev->sbuf[i].data);
pdev->sbuf[i].data = NULL;
}
if (pdev->fbuf != NULL) {
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data != NULL) {
- Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
+ PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data);
vfree(pdev->fbuf[i].data);
pdev->fbuf[i].data = NULL;
}
/* Intermediate decompression buffer & tables */
if (pdev->decompress_data != NULL) {
- Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data);
+ PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data);
kfree(pdev->decompress_data);
pdev->decompress_data = NULL;
}
- pdev->decompressor = NULL;
/* Release image buffers */
if (pdev->image_data != NULL) {
- Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data);
- rvfree(pdev->image_data, default_mbufs * pdev->len_per_image);
+ PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data);
+ pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image);
}
pdev->image_data = NULL;
- Trace(TRACE_MEMORY, "Leaving free_buffers().\n");
+ PWC_DEBUG_MEMORY("Leaving free_buffers().\n");
}
/* The frame & image buffer mess.
/**
\brief Find next frame buffer to fill. Take from empty or full list, whichever comes first.
*/
-static inline int pwc_next_fill_frame(struct pwc_device *pdev)
+static int pwc_next_fill_frame(struct pwc_device *pdev)
{
int ret;
unsigned long flags;
}
else {
/* Hmm. Take it from the full list */
-#if PWC_DEBUG
/* sanity check */
if (pdev->full_frames == NULL) {
- Err("Neither empty or full frames available!\n");
+ PWC_ERROR("Neither empty or full frames available!\n");
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return -EINVAL;
}
-#endif
pdev->fill_frame = pdev->full_frames;
pdev->full_frames = pdev->full_frames->next;
ret = 1;
}
pdev->fill_frame->next = NULL;
-#if PWC_DEBUG
- Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence);
- pdev->fill_frame->sequence = pdev->sequence++;
-#endif
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return ret;
}
int i;
unsigned long flags;
+ PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+
spin_lock_irqsave(&pdev->ptrlock, flags);
pdev->full_frames = NULL;
pdev->full_frames_tail = NULL;
pdev->image_read_pos = 0;
pdev->fill_image = 0;
spin_unlock_irqrestore(&pdev->ptrlock, flags);
+
+ PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
}
/**
\brief Do all the handling for getting one frame: get pointer, decompress, advance pointers.
*/
-static int pwc_handle_frame(struct pwc_device *pdev)
+int pwc_handle_frame(struct pwc_device *pdev)
{
int ret = 0;
unsigned long flags;
we can release the lock after this without problems */
if (pdev->read_frame != NULL) {
/* This can't theoretically happen */
- Err("Huh? Read frame still in use?\n");
+ PWC_ERROR("Huh? Read frame still in use?\n");
+ spin_unlock_irqrestore(&pdev->ptrlock, flags);
+ return ret;
+ }
+
+
+ if (pdev->full_frames == NULL) {
+ PWC_ERROR("Woops. No frames ready.\n");
}
else {
- if (pdev->full_frames == NULL) {
- Err("Woops. No frames ready.\n");
+ pdev->read_frame = pdev->full_frames;
+ pdev->full_frames = pdev->full_frames->next;
+ pdev->read_frame->next = NULL;
+ }
+
+ if (pdev->read_frame != NULL) {
+ /* Decompression is a lenghty process, so it's outside of the lock.
+ This gives the isoc_handler the opportunity to fill more frames
+ in the mean time.
+ */
+ spin_unlock_irqrestore(&pdev->ptrlock, flags);
+ ret = pwc_decompress(pdev);
+ spin_lock_irqsave(&pdev->ptrlock, flags);
+
+ /* We're done with read_buffer, tack it to the end of the empty buffer list */
+ if (pdev->empty_frames == NULL) {
+ pdev->empty_frames = pdev->read_frame;
+ pdev->empty_frames_tail = pdev->empty_frames;
}
else {
- pdev->read_frame = pdev->full_frames;
- pdev->full_frames = pdev->full_frames->next;
- pdev->read_frame->next = NULL;
- }
-
- if (pdev->read_frame != NULL) {
-#if PWC_DEBUG
- Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence);
-#endif
- /* Decompression is a lenghty process, so it's outside of the lock.
- This gives the isoc_handler the opportunity to fill more frames
- in the mean time.
- */
- spin_unlock_irqrestore(&pdev->ptrlock, flags);
- ret = pwc_decompress(pdev);
- spin_lock_irqsave(&pdev->ptrlock, flags);
-
- /* We're done with read_buffer, tack it to the end of the empty buffer list */
- if (pdev->empty_frames == NULL) {
- pdev->empty_frames = pdev->read_frame;
- pdev->empty_frames_tail = pdev->empty_frames;
- }
- else {
- pdev->empty_frames_tail->next = pdev->read_frame;
- pdev->empty_frames_tail = pdev->read_frame;
- }
- pdev->read_frame = NULL;
+ pdev->empty_frames_tail->next = pdev->read_frame;
+ pdev->empty_frames_tail = pdev->read_frame;
}
+ pdev->read_frame = NULL;
}
spin_unlock_irqrestore(&pdev->ptrlock, flags);
return ret;
/**
\brief Advance pointers of image buffer (after each user request)
*/
-static inline void pwc_next_image(struct pwc_device *pdev)
+void pwc_next_image(struct pwc_device *pdev)
{
pdev->image_used[pdev->fill_image] = 0;
- pdev->fill_image = (pdev->fill_image + 1) % default_mbufs;
+ pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs;
}
+/**
+ * Print debug information when a frame is discarded because all of our buffer
+ * is full
+ */
+static void pwc_frame_dumped(struct pwc_device *pdev)
+{
+ pdev->vframes_dumped++;
+ if (pdev->vframe_count < FRAME_LOWMARK)
+ return;
+
+ if (pdev->vframes_dumped < 20)
+ PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count);
+ else if (pdev->vframes_dumped == 20)
+ PWC_DEBUG_FLOW("Dumping frame %d (last message)\n",
+ pdev->vframe_count);
+}
+
+static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf)
+{
+ int awake = 0;
+
+ /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
+ frames on the USB wire after an exposure change. This conditition is
+ however detected in the cam and a bit is set in the header.
+ */
+ if (pdev->type == 730) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+
+ if (ptr[1] == 1 && ptr[0] & 0x10) {
+ PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n");
+ pdev->drop_frames += 2;
+ pdev->vframes_error++;
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01) {
+ pdev->snapshot_button_status = 1;
+ PWC_TRACE("Snapshot button pressed.\n");
+ }
+ else {
+ PWC_TRACE("Snapshot button released.\n");
+ }
+ }
+ if ((ptr[0] ^ pdev->vmirror) & 0x02) {
+ if (ptr[0] & 0x02)
+ PWC_TRACE("Image is mirrored.\n");
+ else
+ PWC_TRACE("Image is normal.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
+ after a short frame; this condition is filtered out specifically. A 4 byte
+ frame doesn't make sense anyway.
+ So we get either this sequence:
+ drop_bit set -> 4 byte frame -> short frame -> good frame
+ Or this one:
+ drop_bit set -> short frame -> good frame
+ So we drop either 3 or 2 frames in all!
+ */
+ if (fbuf->filled == 4)
+ pdev->drop_frames++;
+ }
+ else if (pdev->type == 740 || pdev->type == 720) {
+ unsigned char *ptr = (unsigned char *)fbuf->data;
+ if ((ptr[0] ^ pdev->vmirror) & 0x01) {
+ if (ptr[0] & 0x01) {
+ pdev->snapshot_button_status = 1;
+ PWC_TRACE("Snapshot button pressed.\n");
+ }
+ else
+ PWC_TRACE("Snapshot button released.\n");
+ }
+ pdev->vmirror = ptr[0] & 0x03;
+ }
+
+ /* In case we were instructed to drop the frame, do so silently.
+ The buffer pointers are not updated either (but the counters are reset below).
+ */
+ if (pdev->drop_frames > 0)
+ pdev->drop_frames--;
+ else {
+ /* Check for underflow first */
+ if (fbuf->filled < pdev->frame_total_size) {
+ PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);"
+ " discarded.\n", fbuf->filled);
+ pdev->vframes_error++;
+ }
+ else {
+ /* Send only once per EOF */
+ awake = 1; /* delay wake_ups */
+
+ /* Find our next frame to fill. This will always succeed, since we
+ * nick a frame from either empty or full list, but if we had to
+ * take it from the full list, it means a frame got dropped.
+ */
+ if (pwc_next_fill_frame(pdev))
+ pwc_frame_dumped(pdev);
+
+ }
+ } /* !drop_frames */
+ pdev->vframe_count++;
+ return awake;
+}
/* This gets called for the Isochronous pipe (video). This is done in
* interrupt time, so it has to be fast, not crash, and not stall. Neat.
awake = 0;
pdev = (struct pwc_device *)urb->context;
if (pdev == NULL) {
- Err("isoc_handler() called with NULL device?!\n");
- return;
- }
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("isoc_handler() called with bad magic!\n");
+ PWC_ERROR("isoc_handler() called with NULL device?!\n");
return;
}
-#endif
+
if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
- Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
+ PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a");
return;
}
if (urb->status != -EINPROGRESS && urb->status != 0) {
case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
}
- Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
+ PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
/* Give up after a number of contiguous errors on the USB bus.
Appearantly something is wrong so we simulate an unplug event.
*/
if (++pdev->visoc_errors > MAX_ISOC_ERRORS)
{
- Info("Too many ISOC errors, bailing out.\n");
+ PWC_INFO("Too many ISOC errors, bailing out.\n");
pdev->error_status = EIO;
awake = 1;
wake_up_interruptible(&pdev->frameq);
fbuf = pdev->fill_frame;
if (fbuf == NULL) {
- Err("pwc_isoc_handler without valid fill frame.\n");
+ PWC_ERROR("pwc_isoc_handler without valid fill frame.\n");
awake = 1;
goto handler_end;
}
/* ...copy data to frame buffer, if possible */
if (flen + fbuf->filled > pdev->frame_total_size) {
- Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
+ PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size);
pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */
pdev->vframes_error++;
}
/* Shorter packet... We probably have the end of an image-frame;
wake up read() process and let select()/poll() do something.
Decompression is done in user time over there.
- */
+ */
if (pdev->vsync == 2) {
- /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus
- frames on the USB wire after an exposure change. This conditition is
- however detected in the cam and a bit is set in the header.
- */
- if (pdev->type == 730) {
- unsigned char *ptr = (unsigned char *)fbuf->data;
-
- if (ptr[1] == 1 && ptr[0] & 0x10) {
-#if PWC_DEBUG
- Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence);
-#endif
- pdev->drop_frames += 2;
- pdev->vframes_error++;
- }
- if ((ptr[0] ^ pdev->vmirror) & 0x01) {
- if (ptr[0] & 0x01)
- Info("Snapshot button pressed.\n");
- else
- Info("Snapshot button released.\n");
- }
- if ((ptr[0] ^ pdev->vmirror) & 0x02) {
- if (ptr[0] & 0x02)
- Info("Image is mirrored.\n");
- else
- Info("Image is normal.\n");
- }
- pdev->vmirror = ptr[0] & 0x03;
- /* Sometimes the trailer of the 730 is still sent as a 4 byte packet
- after a short frame; this condition is filtered out specifically. A 4 byte
- frame doesn't make sense anyway.
- So we get either this sequence:
- drop_bit set -> 4 byte frame -> short frame -> good frame
- Or this one:
- drop_bit set -> short frame -> good frame
- So we drop either 3 or 2 frames in all!
- */
- if (fbuf->filled == 4)
- pdev->drop_frames++;
+ if (pwc_rcv_short_packet(pdev, fbuf)) {
+ awake = 1;
+ fbuf = pdev->fill_frame;
}
-
- /* In case we were instructed to drop the frame, do so silently.
- The buffer pointers are not updated either (but the counters are reset below).
- */
- if (pdev->drop_frames > 0)
- pdev->drop_frames--;
- else {
- /* Check for underflow first */
- if (fbuf->filled < pdev->frame_total_size) {
- Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled);
- pdev->vframes_error++;
- }
- else {
- /* Send only once per EOF */
- awake = 1; /* delay wake_ups */
-
- /* Find our next frame to fill. This will always succeed, since we
- * nick a frame from either empty or full list, but if we had to
- * take it from the full list, it means a frame got dropped.
- */
- if (pwc_next_fill_frame(pdev)) {
- pdev->vframes_dumped++;
- if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) {
- if (pdev->vframes_dumped < 20)
- Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count);
- if (pdev->vframes_dumped == 20)
- Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count);
- }
- }
- fbuf = pdev->fill_frame;
- }
- } /* !drop_frames */
- pdev->vframe_count++;
}
fbuf->filled = 0;
fillptr = fbuf->data;
pdev->vsync = 1;
- } /* .. flen < last_packet_size */
+ }
+
pdev->vlast_packet_size = flen;
} /* ..status == 0 */
-#if PWC_DEBUG
- /* This is normally not interesting to the user, unless you are really debugging something */
else {
+ /* This is normally not interesting to the user, unless
+ * you are really debugging something */
static int iso_error = 0;
iso_error++;
if (iso_error < 20)
- Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst);
+ PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
}
-#endif
}
handler_end:
urb->dev = pdev->udev;
i = usb_submit_urb(urb, GFP_ATOMIC);
if (i != 0)
- Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
+ PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i);
}
-static int pwc_isoc_init(struct pwc_device *pdev)
+int pwc_isoc_init(struct pwc_device *pdev)
{
struct usb_device *udev;
struct urb *urb;
/* Get the current alternate interface, adjust packet size */
if (!udev->actconfig)
return -EFAULT;
-
intf = usb_ifnum_to_if(udev, 0);
if (intf)
idesc = usb_altnum_to_altsetting(intf, pdev->valternate);
/* Search video endpoint */
pdev->vmax_packet_size = -1;
- for (i = 0; i < idesc->desc.bNumEndpoints; i++)
+ for (i = 0; i < idesc->desc.bNumEndpoints; i++) {
if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) {
pdev->vmax_packet_size = le16_to_cpu(idesc->endpoint[i].desc.wMaxPacketSize);
break;
}
+ }
if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) {
- Err("Failed to find packet size for video endpoint in current alternate setting.\n");
+ PWC_ERROR("Failed to find packet size for video endpoint in current alternate setting.\n");
return -ENFILE; /* Odd error, that should be noticeable */
}
/* Set alternate interface */
ret = 0;
- Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate);
+ PWC_DEBUG_OPEN("Setting alternate interface %d\n", pdev->valternate);
ret = usb_set_interface(pdev->udev, 0, pdev->valternate);
if (ret < 0)
return ret;
for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL);
if (urb == NULL) {
- Err("Failed to allocate urb %d\n", i);
+ PWC_ERROR("Failed to allocate urb %d\n", i);
ret = -ENOMEM;
break;
}
pdev->sbuf[i].urb = urb;
- Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb);
+ PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb);
}
if (ret) {
/* De-allocate in reverse order */
for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
if (ret)
- Err("isoc_init() submit_urb %d failed with error %d\n", i, ret);
+ PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
else
- Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+ PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
}
/* All is done... */
pdev->iso_init = 1;
- Trace(TRACE_OPEN, "<< pwc_isoc_init()\n");
+ PWC_DEBUG_OPEN("<< pwc_isoc_init()\n");
return 0;
}
-static void pwc_isoc_cleanup(struct pwc_device *pdev)
+void pwc_isoc_cleanup(struct pwc_device *pdev)
{
int i;
- Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n");
+ PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n");
if (pdev == NULL)
return;
+ if (pdev->iso_init == 0)
+ return;
/* Unlinking ISOC buffers one by one */
for (i = 0; i < MAX_ISO_BUFS; i++) {
urb = pdev->sbuf[i].urb;
if (urb != 0) {
if (pdev->iso_init) {
- Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb);
+ PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
usb_kill_urb(urb);
}
- Trace(TRACE_MEMORY, "Freeing URB\n");
+ PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
}
is signalled by EPIPE)
*/
if (pdev->error_status && pdev->error_status != EPIPE) {
- Trace(TRACE_OPEN, "Setting alternate interface 0.\n");
+ PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
usb_set_interface(pdev->udev, 0, 0);
}
pdev->iso_init = 0;
- Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n");
+ PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
/* Try to set video mode... */
start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
if (ret) {
- Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n");
+ PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
/* That failed... restore old mode (we know that worked) */
start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
if (start) {
- Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n");
+ PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
}
}
if (start == 0)
{
if (pwc_isoc_init(pdev) < 0)
{
- Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
+ PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
ret = -EAGAIN; /* let's try again, who knows if it works a second time */
}
}
return ret; /* Return original error code */
}
+/*********
+ * sysfs
+ *********/
+static struct pwc_device *cd_to_pwc(struct class_device *cd)
+{
+ struct video_device *vdev = to_video_device(cd);
+ return video_get_drvdata(vdev);
+}
+
+static ssize_t show_pan_tilt(struct class_device *class_dev, char *buf)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ return sprintf(buf, "%d %d\n", pdev->pan_angle, pdev->tilt_angle);
+}
+
+static ssize_t store_pan_tilt(struct class_device *class_dev, const char *buf,
+ size_t count)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ int pan, tilt;
+ int ret = -EINVAL;
+
+ if (strncmp(buf, "reset", 5) == 0)
+ ret = pwc_mpt_reset(pdev, 0x3);
+
+ else if (sscanf(buf, "%d %d", &pan, &tilt) > 0)
+ ret = pwc_mpt_set_angle(pdev, pan, tilt);
+
+ if (ret < 0)
+ return ret;
+ return strlen(buf);
+}
+static CLASS_DEVICE_ATTR(pan_tilt, S_IRUGO | S_IWUSR, show_pan_tilt,
+ store_pan_tilt);
+
+static ssize_t show_snapshot_button_status(struct class_device *class_dev, char *buf)
+{
+ struct pwc_device *pdev = cd_to_pwc(class_dev);
+ int status = pdev->snapshot_button_status;
+ pdev->snapshot_button_status = 0;
+ return sprintf(buf, "%d\n", status);
+}
+
+static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
+ NULL);
+
+static void pwc_create_sysfs_files(struct video_device *vdev)
+{
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ video_device_create_file(vdev, &class_device_attr_pan_tilt);
+ video_device_create_file(vdev, &class_device_attr_button);
+}
+
+static void pwc_remove_sysfs_files(struct video_device *vdev)
+{
+ struct pwc_device *pdev = video_get_drvdata(vdev);
+ if (pdev->features & FEATURE_MOTOR_PANTILT)
+ video_device_remove_file(vdev, &class_device_attr_pan_tilt);
+ video_device_remove_file(vdev, &class_device_attr_button);
+}
+
+#if CONFIG_PWC_DEBUG
+static const char *pwc_sensor_type_to_string(unsigned int sensor_type)
+{
+ switch(sensor_type) {
+ case 0x00:
+ return "Hyundai CMOS sensor";
+ case 0x20:
+ return "Sony CCD sensor + TDA8787";
+ case 0x2E:
+ return "Sony CCD sensor + Exas 98L59";
+ case 0x2F:
+ return "Sony CCD sensor + ADI 9804";
+ case 0x30:
+ return "Sharp CCD sensor + TDA8787";
+ case 0x3E:
+ return "Sharp CCD sensor + Exas 98L59";
+ case 0x3F:
+ return "Sharp CCD sensor + ADI 9804";
+ case 0x40:
+ return "UPA 1021 sensor";
+ case 0x100:
+ return "VGA sensor";
+ case 0x101:
+ return "PAL MR sensor";
+ default:
+ return "unknown type of sensor";
+ }
+}
+#endif
/***************************************************************************/
/* Video4Linux functions */
static int pwc_video_open(struct inode *inode, struct file *file)
{
- int i;
+ int i, ret;
struct video_device *vdev = video_devdata(file);
struct pwc_device *pdev;
- Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev);
+ PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev == NULL)
BUG();
- if (pdev->vopen)
+ if (pdev->vopen) {
+ PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n");
return -EBUSY;
+ }
down(&pdev->modlock);
if (!pdev->usb_init) {
- Trace(TRACE_OPEN, "Doing first time initialization.\n");
+ PWC_DEBUG_OPEN("Doing first time initialization.\n");
pdev->usb_init = 1;
- if (pwc_trace & TRACE_OPEN)
+ /* Query sensor type */
+ ret = pwc_get_cmos_sensor(pdev, &i);
+ if (ret >= 0)
{
- /* Query sensor type */
- const char *sensor_type = NULL;
- int ret;
-
- ret = pwc_get_cmos_sensor(pdev, &i);
- if (ret >= 0)
- {
- switch(i) {
- case 0x00: sensor_type = "Hyundai CMOS sensor"; break;
- case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break;
- case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break;
- case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break;
- case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break;
- case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break;
- case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break;
- case 0x40: sensor_type = "UPA 1021 sensor"; break;
- case 0x100: sensor_type = "VGA sensor"; break;
- case 0x101: sensor_type = "PAL MR sensor"; break;
- default: sensor_type = "unknown type of sensor"; break;
- }
- }
- if (sensor_type != NULL)
- Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i);
+ PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n",
+ pdev->vdev->name,
+ pwc_sensor_type_to_string(i), i);
}
}
if (power_save) {
i = pwc_camera_power(pdev, 1);
if (i < 0)
- Info("Failed to restore power to the camera! (%d)\n", i);
+ PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i);
}
/* Set LED on/off time */
if (pwc_set_leds(pdev, led_on, led_off) < 0)
- Info("Failed to set LED on/off time.\n");
+ PWC_DEBUG_OPEN("Failed to set LED on/off time.\n");
pwc_construct(pdev); /* set min/max sizes correct */
/* So far, so good. Allocate memory. */
i = pwc_allocate_buffers(pdev);
if (i < 0) {
- Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n");
+ PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n");
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
/* Reset buffers & parameters */
pwc_reset_buffers(pdev);
- for (i = 0; i < default_mbufs; i++)
+ for (i = 0; i < pwc_mbufs; i++)
pdev->image_used[i] = 0;
pdev->vframe_count = 0;
pdev->vframes_dumped = 0;
pdev->vframes_error = 0;
pdev->visoc_errors = 0;
pdev->error_status = 0;
-#if PWC_DEBUG
- pdev->sequence = 0;
-#endif
pwc_construct(pdev); /* set min/max sizes correct */
/* Set some defaults */
*/
i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0);
if (i) {
- Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n");
- if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750)
- i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0);
+ unsigned int default_resolution;
+ PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n");
+ if (pdev->type>= 730)
+ default_resolution = PSZ_QSIF;
else
- i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0);
+ default_resolution = PSZ_QCIF;
+
+ i = pwc_set_video_mode(pdev,
+ pwc_image_sizes[default_resolution].x,
+ pwc_image_sizes[default_resolution].y,
+ 10,
+ pdev->vcompression,
+ 0);
}
if (i) {
- Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n");
+ PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n");
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
i = pwc_isoc_init(pdev);
if (i) {
- Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i);
+ PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
+ pwc_isoc_cleanup(pdev);
+ pwc_free_buffers(pdev);
up(&pdev->modlock);
return i;
}
+ /* Initialize the webcam to sane value */
+ pwc_set_brightness(pdev, 0x7fff);
+ pwc_set_agc(pdev, 1, 0);
+
pdev->vopen++;
file->private_data = vdev;
up(&pdev->modlock);
- Trace(TRACE_OPEN, "<< video_open() returns 0.\n");
+ PWC_DEBUG_OPEN("<< video_open() returns 0.\n");
return 0;
}
struct pwc_device *pdev;
int i;
- Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev);
+ PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
pdev = (struct pwc_device *)vdev->priv;
if (pdev->vopen == 0)
- Info("video_close() called on closed device?\n");
+ PWC_DEBUG_MODULE("video_close() called on closed device?\n");
/* Dump statistics, but only if a reasonable amount of frames were
processed (to prevent endless log-entries in case of snap-shot
programs)
*/
if (pdev->vframe_count > 20)
- Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
+ PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error);
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
-/* pwc_dec23_exit(); *//* Timon & Kiara */
- break;
- case 645:
- case 646:
-/* pwc_dec1_exit(); */
- break;
- }
+ if (DEVICE_USE_CODEC1(pdev->type))
+ pwc_dec1_exit();
+ else
+ pwc_dec23_exit();
pwc_isoc_cleanup(pdev);
pwc_free_buffers(pdev);
if (pdev->error_status != EPIPE) {
/* Turn LEDs off */
if (pwc_set_leds(pdev, 0, 0) < 0)
- Info("Failed to set LED on/off time.\n");
+ PWC_DEBUG_MODULE("Failed to set LED on/off time.\n");
if (power_save) {
i = pwc_camera_power(pdev, 0);
if (i < 0)
- Err("Failed to power down camera (%d)\n", i);
+ PWC_ERROR("Failed to power down camera (%d)\n", i);
}
}
- pdev->vopen = 0;
- Trace(TRACE_OPEN, "<< video_close()\n");
+ pdev->vopen--;
+ PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen);
return 0;
}
device is tricky anyhow.
*/
-static ssize_t pwc_video_read(struct file *file, char __user * buf,
+static ssize_t pwc_video_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *vdev = file->private_data;
int noblock = file->f_flags & O_NONBLOCK;
DECLARE_WAITQUEUE(wait, current);
int bytes_to_read;
+ void *image_buffer_addr;
- Trace(TRACE_READ, "video_read(0x%p, %p, %zu) called.\n", vdev, buf, count);
+ PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n",
+ vdev, buf, count);
if (vdev == NULL)
return -EFAULT;
pdev = vdev->priv;
return -EFAULT;
}
- Trace(TRACE_READ, "Copying data to user space.\n");
+ PWC_DEBUG_READ("Copying data to user space.\n");
if (pdev->vpalette == VIDEO_PALETTE_RAW)
- bytes_to_read = pdev->frame_size;
+ bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
else
bytes_to_read = pdev->view.size;
/* copy bytes to user space; we allow for partial reads */
if (count + pdev->image_read_pos > bytes_to_read)
count = bytes_to_read - pdev->image_read_pos;
- if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count))
+ image_buffer_addr = pdev->image_data;
+ image_buffer_addr += pdev->images[pdev->fill_image].offset;
+ image_buffer_addr += pdev->image_read_pos;
+ if (copy_to_user(buf, image_buffer_addr, count))
return -EFAULT;
pdev->image_read_pos += count;
if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */
return 0;
}
-static int pwc_video_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
-{
- struct video_device *vdev = file->private_data;
- struct pwc_device *pdev;
- DECLARE_WAITQUEUE(wait, current);
-
- if (vdev == NULL)
- return -EFAULT;
- pdev = vdev->priv;
- if (pdev == NULL)
- return -EFAULT;
-
- switch (cmd) {
- /* Query cabapilities */
- case VIDIOCGCAP:
- {
- struct video_capability *caps = arg;
-
- strcpy(caps->name, vdev->name);
- caps->type = VID_TYPE_CAPTURE;
- caps->channels = 1;
- caps->audios = 1;
- caps->minwidth = pdev->view_min.x;
- caps->minheight = pdev->view_min.y;
- caps->maxwidth = pdev->view_max.x;
- caps->maxheight = pdev->view_max.y;
- break;
- }
-
- /* Channel functions (simulate 1 channel) */
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Webcam");
- return 0;
- }
-
- case VIDIOCSCHAN:
- {
- /* The spec says the argument is an integer, but
- the bttv driver uses a video_channel arg, which
- makes sense becasue it also has the norm flag.
- */
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
-
-
- /* Picture functions; contrast etc. */
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
- int val;
-
- val = pwc_get_brightness(pdev);
- if (val >= 0)
- p->brightness = val;
- else
- p->brightness = 0xffff;
- val = pwc_get_contrast(pdev);
- if (val >= 0)
- p->contrast = val;
- else
- p->contrast = 0xffff;
- /* Gamma, Whiteness, what's the difference? :) */
- val = pwc_get_gamma(pdev);
- if (val >= 0)
- p->whiteness = val;
- else
- p->whiteness = 0xffff;
- val = pwc_get_saturation(pdev);
- if (val >= 0)
- p->colour = val;
- else
- p->colour = 0xffff;
- p->depth = 24;
- p->palette = pdev->vpalette;
- p->hue = 0xFFFF; /* N/A */
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- /*
- * FIXME: Suppose we are mid read
- ANSWER: No problem: the firmware of the camera
- can handle brightness/contrast/etc
- changes at _any_ time, and the palette
- is used exactly once in the uncompress
- routine.
- */
- pwc_set_brightness(pdev, p->brightness);
- pwc_set_contrast(pdev, p->contrast);
- pwc_set_gamma(pdev, p->whiteness);
- pwc_set_saturation(pdev, p->colour);
- if (p->palette && p->palette != pdev->vpalette) {
- switch (p->palette) {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- pdev->vpalette = p->palette;
- return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- break;
- default:
- return -EINVAL;
- break;
- }
- }
- break;
- }
-
- /* Window/size parameters */
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- vw->x = 0;
- vw->y = 0;
- vw->width = pdev->view.x;
- vw->height = pdev->view.y;
- vw->chromakey = 0;
- vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
- (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
- break;
- }
-
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- int fps, snapshot, ret;
-
- fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
- snapshot = vw->flags & PWC_FPS_SNAPSHOT;
- if (fps == 0)
- fps = pdev->vframes;
- if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
- return 0;
- ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
- if (ret)
- return ret;
- break;
- }
-
- /* We don't have overlay support (yet) */
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- memset(vb,0,sizeof(*vb));
- break;
- }
-
- /* mmap() functions */
- case VIDIOCGMBUF:
- {
- /* Tell the user program how much memory is needed for a mmap() */
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = default_mbufs * pdev->len_per_image;
- vm->frames = default_mbufs; /* double buffering should be enough for most applications */
- for (i = 0; i < default_mbufs; i++)
- vm->offsets[i] = i * pdev->len_per_image;
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
- struct video_mmap *vm = arg;
-
- Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
- if (vm->frame < 0 || vm->frame >= default_mbufs)
- return -EINVAL;
-
- /* xawtv is nasty. It probes the available palettes
- by setting a very small image size and trying
- various palettes... The driver doesn't support
- such small images, so I'm working around it.
- */
- if (vm->format)
- {
- switch (vm->format)
- {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- break;
- default:
- return -EINVAL;
- break;
- }
- }
-
- if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
- (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
- int ret;
-
- Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
- ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- if (ret)
- return ret;
- } /* ... size mismatch */
-
- /* FIXME: should we lock here? */
- if (pdev->image_used[vm->frame])
- return -EBUSY; /* buffer wasn't available. Bummer */
- pdev->image_used[vm->frame] = 1;
-
- /* Okay, we're done here. In the SYNC call we wait until a
- frame comes available, then expand image into the given
- buffer.
- In contrast to the CPiA cam the Philips cams deliver a
- constant stream, almost like a grabber card. Also,
- we have separate buffers for the rawdata and the image,
- meaning we can nearly always expand into the requested buffer.
- */
- Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n");
- break;
- }
-
- case VIDIOCSYNC:
- {
- /* The doc says: "Whenever a buffer is used it should
- call VIDIOCSYNC to free this frame up and continue."
-
- The only odd thing about this whole procedure is
- that MCAPTURE flags the buffer as "in use", and
- SYNC immediately unmarks it, while it isn't
- after SYNC that you know that the buffer actually
- got filled! So you better not start a CAPTURE in
- the same frame immediately (use double buffering).
- This is not a problem for this cam, since it has
- extra intermediate buffers, but a hardware
- grabber card will then overwrite the buffer
- you're working on.
- */
- int *mbuf = arg;
- int ret;
-
- Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf);
-
- /* bounds check */
- if (*mbuf < 0 || *mbuf >= default_mbufs)
- return -EINVAL;
- /* check if this buffer was requested anyway */
- if (pdev->image_used[*mbuf] == 0)
- return -EINVAL;
-
- /* Add ourselves to the frame wait-queue.
-
- FIXME: needs auditing for safety.
- QUESTION: In what respect? I think that using the
- frameq is safe now.
- */
- add_wait_queue(&pdev->frameq, &wait);
- while (pdev->full_frames == NULL) {
- if (pdev->error_status) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -pdev->error_status;
- }
-
- if (signal_pending(current)) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -ERESTARTSYS;
- }
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
-
- /* The frame is ready. Expand in the image buffer
- requested by the user. I don't care if you
- mmap() 5 buffers and request data in this order:
- buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
- Grabber hardware may not be so forgiving.
- */
- Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n");
- pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
- /* Decompress, etc */
- ret = pwc_handle_frame(pdev);
- pdev->image_used[*mbuf] = 0;
- if (ret)
- return -EFAULT;
- break;
- }
-
- case VIDIOCGAUDIO:
- {
- struct video_audio *v = arg;
-
- strcpy(v->name, "Microphone");
- v->audio = -1; /* unknown audio minor */
- v->flags = 0;
- v->mode = VIDEO_SOUND_MONO;
- v->volume = 0;
- v->bass = 0;
- v->treble = 0;
- v->balance = 0x8000;
- v->step = 1;
- break;
- }
-
- case VIDIOCSAUDIO:
- {
- /* Dummy: nothing can be set */
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- vu->video = pdev->vdev->minor & 0x3F;
- vu->audio = -1; /* not known yet */
- vu->vbi = -1;
- vu->radio = -1;
- vu->teletext = -1;
- break;
- }
- default:
- return pwc_ioctl(pdev, cmd, arg);
- } /* ..switch */
- return 0;
-}
-
static int pwc_video_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl);
}
-
static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
+ unsigned long start;
+ unsigned long size;
+ unsigned long page, pos = 0;
+ int index;
- Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size);
+ PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
pdev = vdev->priv;
+ size = vma->vm_end - vma->vm_start;
+ start = vma->vm_start;
- vma->vm_flags |= VM_IO;
+ /* Find the idx buffer for this mapping */
+ for (index = 0; index < pwc_mbufs; index++) {
+ pos = pdev->images[index].offset;
+ if ((pos>>PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+ if (index == MAX_IMAGES)
+ return -EINVAL;
+ if (index == 0) {
+ /*
+ * Special case for v4l1. In v4l1, we map only one big buffer,
+ * but in v4l2 each buffer is mapped
+ */
+ unsigned long total_size;
+ total_size = pwc_mbufs * pdev->len_per_image;
+ if (size != pdev->len_per_image && size != total_size) {
+ PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n",
+ size, pdev->len_per_image, total_size);
+ return -EINVAL;
+ }
+ } else if (size > pdev->len_per_image)
+ return -EINVAL;
- pos = (unsigned long)pdev->image_data;
+ vma->vm_flags |= VM_IO; /* from 2.6.9-acX */
+
+ pos += (unsigned long)pdev->image_data;
while (size > 0) {
page = vmalloc_to_pfn((void *)pos);
if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
-
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
else
size = 0;
}
-
return 0;
}
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
+ vendor_id = le16_to_cpu(udev->descriptor.idVendor);
+ product_id = le16_to_cpu(udev->descriptor.idProduct);
+
/* Check if we can handle this device */
- Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct),
+ PWC_DEBUG_PROBE("probe() called [%04X %04X], if %d\n",
+ vendor_id, product_id,
intf->altsetting->desc.bInterfaceNumber);
/* the interfaces are probed one by one. We are only interested in the
if (intf->altsetting->desc.bInterfaceNumber > 0)
return -ENODEV;
- vendor_id = le16_to_cpu(udev->descriptor.idVendor);
- product_id = le16_to_cpu(udev->descriptor.idProduct);
-
if (vendor_id == 0x0471) {
switch (product_id) {
case 0x0302:
- Info("Philips PCA645VC USB webcam detected.\n");
+ PWC_INFO("Philips PCA645VC USB webcam detected.\n");
name = "Philips 645 webcam";
type_id = 645;
break;
case 0x0303:
- Info("Philips PCA646VC USB webcam detected.\n");
+ PWC_INFO("Philips PCA646VC USB webcam detected.\n");
name = "Philips 646 webcam";
type_id = 646;
break;
case 0x0304:
- Info("Askey VC010 type 2 USB webcam detected.\n");
+ PWC_INFO("Askey VC010 type 2 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 646;
break;
case 0x0307:
- Info("Philips PCVC675K (Vesta) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC675K (Vesta) USB webcam detected.\n");
name = "Philips 675 webcam";
type_id = 675;
break;
case 0x0308:
- Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC680K (Vesta Pro) USB webcam detected.\n");
name = "Philips 680 webcam";
type_id = 680;
break;
case 0x030C:
- Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n");
name = "Philips 690 webcam";
type_id = 690;
break;
case 0x0310:
- Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n");
name = "Philips 730 webcam";
type_id = 730;
break;
case 0x0311:
- Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n");
name = "Philips 740 webcam";
type_id = 740;
break;
case 0x0312:
- Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n");
name = "Philips 750 webcam";
type_id = 750;
break;
case 0x0313:
- Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
+ PWC_INFO("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n");
name = "Philips 720K/40 webcam";
type_id = 720;
break;
+ case 0x0329:
+ PWC_INFO("Philips SPC 900NC USB webcam detected.\n");
+ name = "Philips SPC 900NC webcam";
+ type_id = 720;
+ break;
default:
return -ENODEV;
break;
else if (vendor_id == 0x069A) {
switch(product_id) {
case 0x0001:
- Info("Askey VC010 type 1 USB webcam detected.\n");
+ PWC_INFO("Askey VC010 type 1 USB webcam detected.\n");
name = "Askey VC010 webcam";
type_id = 645;
break;
else if (vendor_id == 0x046d) {
switch(product_id) {
case 0x08b0:
- Info("Logitech QuickCam Pro 3000 USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Pro 3000 USB webcam detected.\n");
name = "Logitech QuickCam Pro 3000";
type_id = 740; /* CCD sensor */
break;
case 0x08b1:
- Info("Logitech QuickCam Notebook Pro USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Notebook Pro USB webcam detected.\n");
name = "Logitech QuickCam Notebook Pro";
type_id = 740; /* CCD sensor */
break;
case 0x08b2:
- Info("Logitech QuickCam 4000 Pro USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n");
name = "Logitech QuickCam Pro 4000";
type_id = 740; /* CCD sensor */
break;
case 0x08b3:
- Info("Logitech QuickCam Zoom USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
break;
case 0x08B4:
- Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n");
name = "Logitech QuickCam Zoom";
type_id = 740; /* CCD sensor */
+ power_save = 1;
break;
case 0x08b5:
- Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
+ PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n");
name = "Logitech QuickCam Orbit";
type_id = 740; /* CCD sensor */
features |= FEATURE_MOTOR_PANTILT;
case 0x08b6:
case 0x08b7:
case 0x08b8:
- Info("Logitech QuickCam detected (reserved ID).\n");
+ PWC_INFO("Logitech QuickCam detected (reserved ID).\n");
name = "Logitech QuickCam (res.)";
type_id = 730; /* Assuming CMOS */
break;
*/
switch(product_id) {
case 0x9000:
- Info("Samsung MPC-C10 USB webcam detected.\n");
+ PWC_INFO("Samsung MPC-C10 USB webcam detected.\n");
name = "Samsung MPC-C10";
type_id = 675;
break;
case 0x9001:
- Info("Samsung MPC-C30 USB webcam detected.\n");
+ PWC_INFO("Samsung MPC-C30 USB webcam detected.\n");
name = "Samsung MPC-C30";
type_id = 675;
break;
+ case 0x9002:
+ PWC_INFO("Samsung SNC-35E (v3.0) USB webcam detected.\n");
+ name = "Samsung MPC-C30";
+ type_id = 740;
+ break;
default:
return -ENODEV;
break;
else if (vendor_id == 0x041e) {
switch(product_id) {
case 0x400c:
- Info("Creative Labs Webcam 5 detected.\n");
+ PWC_INFO("Creative Labs Webcam 5 detected.\n");
name = "Creative Labs Webcam 5";
type_id = 730;
break;
case 0x4011:
- Info("Creative Labs Webcam Pro Ex detected.\n");
+ PWC_INFO("Creative Labs Webcam Pro Ex detected.\n");
name = "Creative Labs Webcam Pro Ex";
type_id = 740;
break;
else if (vendor_id == 0x04cc) {
switch(product_id) {
case 0x8116:
- Info("Sotec Afina Eye USB webcam detected.\n");
+ PWC_INFO("Sotec Afina Eye USB webcam detected.\n");
name = "Sotec Afina Eye";
type_id = 730;
break;
switch(product_id) {
case 0x8116:
/* This is essentially the same cam as the Sotec Afina Eye */
- Info("AME Co. Afina Eye USB webcam detected.\n");
+ PWC_INFO("AME Co. Afina Eye USB webcam detected.\n");
name = "AME Co. Afina Eye";
type_id = 750;
break;
else if (vendor_id == 0x0d81) {
switch(product_id) {
case 0x1900:
- Info("Visionite VCS-UC300 USB webcam detected.\n");
+ PWC_INFO("Visionite VCS-UC300 USB webcam detected.\n");
name = "Visionite VCS-UC300";
type_id = 740; /* CCD sensor */
break;
case 0x1910:
- Info("Visionite VCS-UM100 USB webcam detected.\n");
+ PWC_INFO("Visionite VCS-UM100 USB webcam detected.\n");
name = "Visionite VCS-UM100";
type_id = 730; /* CMOS sensor */
break;
memset(serial_number, 0, 30);
usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29);
- Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number);
+ PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number);
if (udev->descriptor.bNumConfigurations > 1)
- Info("Warning: more than 1 configuration available.\n");
+ PWC_WARNING("Warning: more than 1 configuration available.\n");
/* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */
pdev = kzalloc(sizeof(struct pwc_device), GFP_KERNEL);
if (pdev == NULL) {
- Err("Oops, could not allocate memory for pwc_device.\n");
+ PWC_ERROR("Oops, could not allocate memory for pwc_device.\n");
return -ENOMEM;
}
pdev->type = type_id;
pdev->vdev = video_device_alloc();
if (pdev->vdev == 0)
{
- Err("Err, cannot allocate video_device struture. Failing probe.");
+ PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
kfree(pdev);
return -ENOMEM;
}
memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template));
+ pdev->vdev->dev = &(udev->dev);
strcpy(pdev->vdev->name, name);
pdev->vdev->owner = THIS_MODULE;
video_set_drvdata(pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
- Trace(TRACE_PROBE, "Release: %04x\n", pdev->release);
+ PWC_DEBUG_PROBE("Release: %04x\n", pdev->release);
/* Now search device_hint[] table for a match, so we can hint a node number. */
for (hint = 0; hint < MAX_DEV_HINTS; hint++) {
(device_hint[hint].pdev == NULL)) {
/* so far, so good... try serial number */
if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) {
- /* match! */
- video_nr = device_hint[hint].device_node;
- Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr);
- break;
+ /* match! */
+ video_nr = device_hint[hint].device_node;
+ PWC_DEBUG_PROBE("Found hint, will try to register as /dev/video%d\n", video_nr);
+ break;
}
}
}
pdev->vdev->release = video_device_release;
i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
if (i < 0) {
- Err("Failed to register as video device (%d).\n", i);
+ PWC_ERROR("Failed to register as video device (%d).\n", i);
video_device_release(pdev->vdev); /* Drip... drip... drip... */
kfree(pdev); /* Oops, no memory leaks please */
return -EIO;
}
else {
- Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
+ PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
}
/* occupy slot */
if (hint < MAX_DEV_HINTS)
device_hint[hint].pdev = pdev;
- Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev);
+ PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
usb_set_intfdata (intf, pdev);
+ pwc_create_sysfs_files(pdev->vdev);
+
+ /* Set the leds off */
+ pwc_set_leds(pdev, 0, 0);
+ pwc_camera_power(pdev, 0);
+
return 0;
}
pdev = usb_get_intfdata (intf);
usb_set_intfdata (intf, NULL);
if (pdev == NULL) {
- Err("pwc_disconnect() Called without private pointer.\n");
+ PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
goto disconnect_out;
}
if (pdev->udev == NULL) {
- Err("pwc_disconnect() already called for %p\n", pdev);
+ PWC_ERROR("pwc_disconnect() already called for %p\n", pdev);
goto disconnect_out;
}
if (pdev->udev != interface_to_usbdev(intf)) {
- Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
- goto disconnect_out;
- }
-#ifdef PWC_MAGIC
- if (pdev->magic != PWC_MAGIC) {
- Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n");
+ PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n");
goto disconnect_out;
}
-#endif
/* We got unplugged; this is signalled by an EPIPE error code */
if (pdev->vopen) {
- Info("Disconnected while webcam is in use!\n");
+ PWC_INFO("Disconnected while webcam is in use!\n");
pdev->error_status = EPIPE;
}
while (pdev->vopen)
schedule();
/* Device is now closed, so we can safely unregister it */
- Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n");
+ PWC_DEBUG_PROBE("Unregistering video device in disconnect().\n");
+ pwc_remove_sysfs_files(pdev->vdev);
video_unregister_device(pdev->vdev);
/* Free memory (don't set pdev to 0 just yet) */
* Initialization code & module stuff
*/
-static char size[10];
-static int fps = 0;
-static int fbufs = 0;
-static int mbufs = 0;
-static int trace = -1;
+static char *size;
+static int fps;
+static int fbufs;
+static int mbufs;
static int compression = -1;
static int leds[2] = { -1, -1 };
-static char *dev_hint[MAX_DEV_HINTS] = { };
+static int leds_nargs;
+static char *dev_hint[MAX_DEV_HINTS];
+static int dev_hint_nargs;
+
+module_param(size, charp, 0444);
+module_param(fps, int, 0444);
+module_param(fbufs, int, 0444);
+module_param(mbufs, int, 0444);
+#if CONFIG_PWC_DEBUG
+module_param_named(trace, pwc_trace, int, 0644);
+#endif
+module_param(power_save, int, 0444);
+module_param(compression, int, 0444);
+module_param_array(leds, int, &leds_nargs, 0444);
+module_param_array(dev_hint, charp, &dev_hint_nargs, 0444);
-module_param_string(size, size, sizeof(size), 0);
MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga");
-module_param(fps, int, 0000);
MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30");
-module_param(fbufs, int, 0000);
MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve");
-module_param(mbufs, int, 0000);
MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers");
-module_param(trace, int, 0000);
MODULE_PARM_DESC(trace, "For debugging purposes");
-module_param(power_save, bool, 0000);
MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off");
-module_param(compression, int, 0000);
MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)");
-module_param_array(leds, int, NULL, 0000);
MODULE_PARM_DESC(leds, "LED on,off time in milliseconds");
-module_param_array(dev_hint, charp, NULL, 0000);
MODULE_PARM_DESC(dev_hint, "Device node hints");
MODULE_DESCRIPTION("Philips & OEM USB webcam driver");
MODULE_AUTHOR("Luc Saillard <luc@saillard.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("pwcx");
+MODULE_VERSION( PWC_VERSION );
static int __init usb_pwc_init(void)
{
int i, sz;
char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" };
- Info("Philips webcam module version " PWC_VERSION " loaded.\n");
- Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
- Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
- Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
+ PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n");
+ PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n");
+ PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n");
+ PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n");
if (fps) {
if (fps < 4 || fps > 30) {
- Err("Framerate out of bounds (4-30).\n");
+ PWC_ERROR("Framerate out of bounds (4-30).\n");
return -EINVAL;
}
default_fps = fps;
- Info("Default framerate set to %d.\n", default_fps);
+ PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps);
}
- if (size[0]) {
+ if (size) {
/* string; try matching with array */
for (sz = 0; sz < PSZ_MAX; sz++) {
if (!strcmp(sizenames[sz], size)) { /* Found! */
}
}
if (sz == PSZ_MAX) {
- Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
+ PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n");
return -EINVAL;
}
- Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
+ PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y);
}
if (mbufs) {
if (mbufs < 1 || mbufs > MAX_IMAGES) {
- Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
+ PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES);
return -EINVAL;
}
- default_mbufs = mbufs;
- Info("Number of image buffers set to %d.\n", default_mbufs);
+ pwc_mbufs = mbufs;
+ PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs);
}
if (fbufs) {
if (fbufs < 2 || fbufs > MAX_FRAMES) {
- Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
+ PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES);
return -EINVAL;
}
default_fbufs = fbufs;
- Info("Number of frame buffers set to %d.\n", default_fbufs);
+ PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs);
}
- if (trace >= 0) {
- Info("Trace options: 0x%04x\n", trace);
- pwc_trace = trace;
+#if CONFIG_PWC_DEBUG
+ if (pwc_trace >= 0) {
+ PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace);
}
+#endif
if (compression >= 0) {
if (compression > 3) {
- Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
+ PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n");
return -EINVAL;
}
pwc_preferred_compression = compression;
- Info("Preferred compression set to %d.\n", pwc_preferred_compression);
+ PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression);
}
if (power_save)
- Info("Enabling power save on open/close.\n");
+ PWC_DEBUG_MODULE("Enabling power save on open/close.\n");
if (leds[0] >= 0)
led_on = leds[0];
if (leds[1] >= 0)
dot++;
/* Few sanity checks */
if (*dot != '\0' && dot > colon) {
- Err("Malformed camera hint: the colon must be after the dot.\n");
+ PWC_ERROR("Malformed camera hint: the colon must be after the dot.\n");
return -EINVAL;
}
if (*colon == '\0') {
/* No colon */
if (*dot != '\0') {
- Err("Malformed camera hint: no colon + device node given.\n");
+ PWC_ERROR("Malformed camera hint: no colon + device node given.\n");
return -EINVAL;
}
else {
device_hint[i].serial_number[k] = '\0';
}
}
-#if PWC_DEBUG
- Debug("device_hint[%d]:\n", i);
- Debug(" type : %d\n", device_hint[i].type);
- Debug(" serial# : %s\n", device_hint[i].serial_number);
- Debug(" node : %d\n", device_hint[i].device_node);
-#endif
+ PWC_TRACE("device_hint[%d]:\n", i);
+ PWC_TRACE(" type : %d\n", device_hint[i].type);
+ PWC_TRACE(" serial# : %s\n", device_hint[i].serial_number);
+ PWC_TRACE(" node : %d\n", device_hint[i].device_node);
}
else
device_hint[i].type = 0; /* not filled */
} /* ..for MAX_DEV_HINTS */
- Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver);
+ PWC_DEBUG_PROBE("Registering driver at address 0x%p.\n", &pwc_driver);
return usb_register(&pwc_driver);
}
static void __exit usb_pwc_exit(void)
{
- Trace(TRACE_MODULE, "Deregistering driver.\n");
+ PWC_DEBUG_MODULE("Deregistering driver.\n");
usb_deregister(&pwc_driver);
- Info("Philips webcam module removed.\n");
+ PWC_INFO("Philips webcam module removed.\n");
}
module_init(usb_pwc_init);
module_exit(usb_pwc_exit);
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
},
};
+
+/*
+ * Rom table for kiara chips
+ *
+ * 32 roms tables (one for each resolution ?)
+ * 2 tables per roms (one for each passes) (Y, and U&V)
+ * 128 bytes per passes
+ */
+
+const unsigned int KiaraRomTable [8][2][16][8] =
+{
+ { /* version 0 */
+ { /* version 0, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009292,0x00009292,0x00009493,0x000124db},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x0000a493,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x000124db,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 0, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000001,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009292,
+ 0x00009492,0x00009493,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000126dc,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 1 */
+ { /* version 1, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 1, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000049,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 2 */
+ { /* version 2, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x0000a49b},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 2, passes 1 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x0000a49b,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 3 */
+ { /* version 3, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 3, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 4 */
+ { /* version 4, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 4, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 5 */
+ { /* version 5, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 5, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x00009252,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 6 */
+ { /* version 6, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 6, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 7 */
+ { /* version 7, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 7, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ }
+};
+
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
#ifndef PWC_KIARA_H
#define PWC_KIARA_H
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
struct Kiara_table_entry
{
unsigned char mode[12]; /* precomputed mode settings for cam */
};
-const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
-const extern unsigned int KiaraRomTable[8][2][16][8];
+extern const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4];
+extern const unsigned int KiaraRomTable[8][2][16][8];
#endif
/* Linux driver for Philips webcam
Various miscellaneous functions and tables.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/slab.h>
#include "pwc.h"
-struct pwc_coord pwc_image_sizes[PSZ_MAX] =
+const struct pwc_coord pwc_image_sizes[PSZ_MAX] =
{
- { 128, 96, 0 },
- { 160, 120, 0 },
- { 176, 144, 0 },
- { 320, 240, 0 },
- { 352, 288, 0 },
- { 640, 480, 0 },
+ { 128, 96, 0 }, /* sqcif */
+ { 160, 120, 0 }, /* qsif */
+ { 176, 144, 0 }, /* qcif */
+ { 320, 240, 0 }, /* sif */
+ { 352, 288, 0 }, /* cif */
+ { 640, 480, 0 }, /* vga */
};
/* x,y -> PSZ_ */
{
if (width > pdev->abs_max.x || height > pdev->abs_max.y)
{
- Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
+ PWC_DEBUG_SIZE("VIDEO_PALETTE_RAW: going beyond abs_max.\n");
return -1;
}
}
{
if (width > pdev->view_max.x || height > pdev->view_max.y)
{
- Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n");
+ PWC_DEBUG_SIZE("VIDEO_PALETTE_not RAW: going beyond view_max.\n");
return -1;
}
}
/* initialize variables depending on type and decompressor*/
void pwc_construct(struct pwc_device *pdev)
{
- switch(pdev->type) {
- case 645:
- case 646:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+
pdev->view_min.x = 128;
pdev->view_min.y = 96;
pdev->view_max.x = 352;
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
- break;
- case 675:
- case 680:
- case 690:
+
+ } else if (DEVICE_USE_CODEC3(pdev->type)) {
+
+ pdev->view_min.x = 160;
+ pdev->view_min.y = 120;
+ pdev->view_max.x = 640;
+ pdev->view_max.y = 480;
+ pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
+ pdev->abs_max.x = 640;
+ pdev->abs_max.y = 480;
+ pdev->vcinterface = 3;
+ pdev->vendpoint = 5;
+ pdev->frame_header_size = TOUCAM_HEADER_SIZE;
+ pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
+
+ } else /* if (DEVICE_USE_CODEC2(pdev->type)) */ {
+
pdev->view_min.x = 128;
pdev->view_min.y = 96;
/* Anthill bug #38: PWC always reports max size, even without PWCX */
pdev->vendpoint = 4;
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
- break;
- case 720:
- case 730:
- case 740:
- case 750:
- pdev->view_min.x = 160;
- pdev->view_min.y = 120;
- pdev->view_max.x = 640;
- pdev->view_max.y = 480;
- pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA;
- pdev->abs_max.x = 640;
- pdev->abs_max.y = 480;
- pdev->vcinterface = 3;
- pdev->vendpoint = 5;
- pdev->frame_header_size = TOUCAM_HEADER_SIZE;
- pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE;
- break;
}
- Debug("type = %d\n",pdev->type);
pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
/* length of image, in YUV format; always allocate enough memory. */
- pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2;
+ pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2);
}
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
},
};
+/*
+ * 16 versions:
+ * 2 tables (one for Y, and one for U&V)
+ * 16 levels of details per tables
+ * 8 blocs
+ */
+
+const unsigned int TimonRomTable [16][2][16][8] =
+{
+ { /* version 0 */
+ { /* version 0, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000001,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000001,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 0, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000001,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000001,
+ 0x00000001,0x00000009,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000009,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000009,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 1 */
+ { /* version 1, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000001,0x00000001,
+ 0x00000001,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000009,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 1, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000001,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000001,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000049,0x00000249,0x00000009,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00000049,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 2 */
+ { /* version 2, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000009,0x00000009,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009492,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 2, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000009,
+ 0x00000049,0x00000009,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000049,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x0000024a,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009292,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009292,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 3 */
+ { /* version 3, passes 0 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000001},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000049,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00009252,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 3, passes 1 */
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000},
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000001,0x00000000},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00000049,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00000001},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x00009292,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009252,0x00009292,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009292,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 4 */
+ { /* version 4, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x0000a49b},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 4, passes 1 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x0000a49b,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 5 */
+ { /* version 5, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x0000124a,0x00001252,0x00009292},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x0000124a,0x00009292,0x00009292,0x00009493},
+ {0x00000000,0x00000000,0x00000249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 5, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x000124db,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009493,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 6 */
+ { /* version 6, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x0000124a,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001b925,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 6, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 7 */
+ { /* version 7, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x000124db,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0001249b,0x000126dc,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x0002496e},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 7, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001b724,0x0001b925,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 8 */
+ { /* version 8, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009292,0x00009493,0x0000a49b,0x000124db},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x000124db,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000136e4},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000136e4,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x0001b925},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x00024b76,0x00024b77},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x00024b76,0x00025bbf},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 8, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0002496d,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 9 */
+ { /* version 9, passes 0 */
+ {0x00000000,0x00000000,0x00000049,0x00000049,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000249,0x00000249,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x0000124a,0x00009252,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009252,0x00009493,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 9, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000049,
+ 0x00000009,0x00000009,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000009,0x00000009},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000124db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 10 */
+ { /* version 10, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00000249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x00009493,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x000124db,0x000124db,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0001249b,0x000126dc,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000126dc,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009252,0x0000a49b,
+ 0x000124db,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000126dc,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 10, passes 1 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000049,0x00000049,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00000249,0x00000049,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x00009252,0x0000024a,0x00000049},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009493,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009252,
+ 0x00009492,0x00009493,0x00001252,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009493,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009493,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009493,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009252,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 11 */
+ { /* version 11, passes 0 */
+ {0x00000000,0x00000000,0x00000249,0x00000249,
+ 0x00000249,0x00000249,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009492,0x0000a49b,0x0000a49b,0x00009292},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000136e4},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 11, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00000249,
+ 0x00000249,0x00000249,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009252,0x00009252,0x0000024a,0x0000024a},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x0000a49b,0x00009292,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 12 */
+ { /* version 12, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x0000a493,0x0000a49b,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x0001b724},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000126db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 12, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x00001249,0x00009292,
+ 0x00009492,0x00009252,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000124db,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x000136e4,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000126db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 13 */
+ { /* version 13, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x00009252,0x00009292,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000126dc,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x0000a49b,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 13, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x00009492,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0000a49b,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000124db,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000124db,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000136db,
+ 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000126dc,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 14 */
+ { /* version 14, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x0000924a,
+ 0x00009292,0x00009493,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00001249,0x0000a49b,
+ 0x0000a493,0x000124db,0x000126dc,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x0000a49b},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x000136e4,0x0001b725,0x000124db},
+ {0x00000000,0x00000000,0x00009292,0x000124db,
+ 0x000126dc,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x0001c92d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0002496d,0x00024b76,0x00024b77},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 14, passes 1 */
+ {0x00000000,0x00000000,0x00001249,0x00001249,
+ 0x0000124a,0x0000124a,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x00009493,
+ 0x0000a493,0x00009292,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x0000a49b,0x00001252,0x00001252},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000136e4,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x000136e4,0x00009493,0x00009292},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x00009493},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000124db,0x0000a49b},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b724,0x000136e4,0x000126dc,0x000124db},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x0001c924,0x0001b724,0x000136e4,0x000126dc},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ },
+ { /* version 15 */
+ { /* version 15, passes 0 */
+ {0x00000000,0x00000000,0x00001249,0x00009493,
+ 0x0000a493,0x0000a49b,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0001249b,0x000126dc,0x000136e4,0x000124db},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x000126dc,0x0001b724,0x0001b725,0x000126dc},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x0001b724,0x0001b92d,0x000126dc},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x000136e4,0x0001b925,0x0001c96e,0x000136e4},
+ {0x00000000,0x00000000,0x00009492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000124db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925},
+ {0x00000000,0x00000000,0x0000a492,0x000126db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001b924,0x0002496d,0x00024b76,0x0002496e},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0002496d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002db6d,0x00036db6,0x0002efff},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ },
+ { /* version 15, passes 1 */
+ {0x00000000,0x00000000,0x0000924a,0x0000924a,
+ 0x00009292,0x00009292,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x0000a49b,
+ 0x0000a493,0x000124db,0x00009292,0x00009292},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000124db,0x0001b724,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000126dc,0x0001b724,0x00009493,0x00009493},
+ {0x00000000,0x00000000,0x0000924a,0x000124db,
+ 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009292,0x000136db,
+ 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001c924,0x0001b724,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x00009492,0x000136db,
+ 0x0001c924,0x0001b724,0x000124db,0x000124db},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b724,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000126dc,0x000126dc},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x000136e4,0x000136e4},
+ {0x00000000,0x00000000,0x0000a492,0x000136db,
+ 0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00012492,0x000136db,
+ 0x0001c924,0x0001b925,0x0001b725,0x0001b724},
+ {0x00000000,0x00000000,0x00012492,0x0001b6db,
+ 0x00024924,0x0002496d,0x0001b92d,0x0001b925},
+ {0x00000000,0x00000000,0x00000000,0x00000000,
+ 0x00000000,0x00000000,0x00000000,0x00000000}
+ }
+ }
+};
/* Linux driver for Philips webcam
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
#ifndef PWC_TIMON_H
#define PWC_TIMON_H
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
struct Timon_table_entry
{
unsigned char mode[13]; /* precomputed mode settings for cam */
};
-const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
-const extern unsigned int TimonRomTable [16][2][16][8];
+extern const struct Timon_table_entry Timon_table[PSZ_MAX][6][4];
+extern const unsigned int TimonRomTable [16][2][16][8];
#endif
/* Linux driver for Philips webcam
Decompression frontend.
(C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
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
+
+ vim: set ts=8:
*/
#include <asm/current.h>
#include "pwc.h"
#include "pwc-uncompress.h"
+#include "pwc-dec1.h"
+#include "pwc-dec23.h"
int pwc_decompress(struct pwc_device *pdev)
{
if (pdev == NULL)
return -EFAULT;
-#if defined(__KERNEL__) && defined(PWC_MAGIC)
- if (pdev->magic != PWC_MAGIC) {
- Err("pwc_decompress(): magic failed.\n");
- return -EFAULT;
- }
-#endif
fbuf = pdev->read_frame;
if (fbuf == NULL)
return -EFAULT;
- image = pdev->image_ptr[pdev->fill_image];
- if (!image)
- return -EFAULT;
+ image = pdev->image_data;
+ image += pdev->images[pdev->fill_image].offset;
yuv = fbuf->data + pdev->frame_header_size; /* Skip header */
/* Raw format; that's easy... */
if (pdev->vpalette == VIDEO_PALETTE_RAW)
{
- memcpy(image, yuv, pdev->frame_size);
+ struct pwc_raw_frame *raw_frame = image;
+ raw_frame->type = cpu_to_le16(pdev->type);
+ raw_frame->vbandlength = cpu_to_le16(pdev->vbandlength);
+ /* cmd_buf is always 4 bytes, but sometimes, only the
+ * first 3 bytes is filled (Nala case). We can
+ * determine this using the type of the webcam */
+ memcpy(raw_frame->cmd, pdev->cmd_buf, 4);
+ memcpy(raw_frame+1, yuv, pdev->frame_size);
return 0;
}
if (pdev->vbandlength == 0) {
- /* Uncompressed mode. We copy the data into the output buffer,
- using the viewport size (which may be larger than the image
- size). Unfortunately we have to do a bit of byte stuffing
- to get the desired output format/size.
+ /* Uncompressed mode.
+ * We copy the data into the output buffer, using the viewport
+ * size (which may be larger than the image size).
+ * Unfortunately we have to do a bit of byte stuffing to get
+ * the desired output format/size.
+ *
+ * We do some byte shuffling here to go from the
+ * native format to YUV420P.
*/
- /*
- * We do some byte shuffling here to go from the
- * native format to YUV420P.
- */
- src = (u16 *)yuv;
- n = pdev->view.x * pdev->view.y;
-
- /* offset in Y plane */
- stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
- dsty = (u16 *)(image + stride);
-
- /* offsets in U/V planes */
- stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
- dstu = (u16 *)(image + n + stride);
- dstv = (u16 *)(image + n + n / 4 + stride);
-
- /* increment after each line */
- stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
-
- for (line = 0; line < pdev->image.y; line++) {
- for (col = 0; col < pdev->image.x; col += 4) {
- *dsty++ = *src++;
- *dsty++ = *src++;
- if (line & 1)
- *dstv++ = *src++;
- else
- *dstu++ = *src++;
- }
- dsty += stride;
+ src = (u16 *)yuv;
+ n = pdev->view.x * pdev->view.y;
+
+ /* offset in Y plane */
+ stride = pdev->view.x * pdev->offset.y + pdev->offset.x;
+ dsty = (u16 *)(image + stride);
+
+ /* offsets in U/V planes */
+ stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2;
+ dstu = (u16 *)(image + n + stride);
+ dstv = (u16 *)(image + n + n / 4 + stride);
+
+ /* increment after each line */
+ stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */
+
+ for (line = 0; line < pdev->image.y; line++) {
+ for (col = 0; col < pdev->image.x; col += 4) {
+ *dsty++ = *src++;
+ *dsty++ = *src++;
if (line & 1)
- dstv += (stride >> 1);
+ *dstv++ = *src++;
else
- dstu += (stride >> 1);
+ *dstu++ = *src++;
}
+ dsty += stride;
+ if (line & 1)
+ dstv += (stride >> 1);
+ else
+ dstu += (stride >> 1);
+ }
+
+ return 0;
}
- else {
- /* Compressed; the decompressor routines will write the data
- in planar format immediately.
- */
- int flags;
-
- flags = PWCX_FLAG_PLANAR;
- if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot)
- {
- printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n");
- flags |= PWCX_FLAG_BAYER;
- return -ENXIO; /* No such device or address: missing decompressor */
- }
-
-#if 0
- switch (pdev->type)
- {
- case 675:
- case 680:
- case 690:
- case 720:
- case 730:
- case 740:
- case 750:
- pwc_dec23_decompress(&pdev->image, &pdev->view,
- &pdev->offset, yuv, image, flags,
- pdev->decompress_data, pdev->vbandlength);
- break;
- case 645:
- case 646:
- /* TODO & FIXME */
- return -ENXIO; /* Missing decompressor */
- break;
- }
-#endif
+
+ /*
+ * Compressed;
+ * the decompressor routines will write the data in planar format
+ * immediately.
+ */
+ if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) {
+ PWC_ERROR("Mode Bayer is not supported for now\n");
+ /* flags |= PWCX_FLAG_BAYER; */
+ return -ENXIO; /* No such device or address: missing decompressor */
+ }
+
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+
+ /* TODO & FIXME */
+ PWC_ERROR("This chipset is not supported for now\n");
+ return -ENXIO; /* No such device or address: missing decompressor */
+
+ } else {
+ pwc_dec23_decompress(pdev, yuv, image, PWCX_FLAG_PLANAR);
}
return 0;
}
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
/* (C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
#include <linux/config.h>
-#include "pwc-ioctl.h"
+#include <media/pwc-ioctl.h>
/* from pwc-dec.h */
#define PWCX_FLAG_PLANAR 0x0001
--- /dev/null
+/* Linux driver for Philips webcam
+ USB and Video4Linux interface part.
+ (C) 1999-2004 Nemosoft Unv.
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+*/
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include "pwc.h"
+
+static struct v4l2_queryctrl pwc_controls[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 128,
+ .step = 1,
+ .default_value = 64,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 64,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = -100,
+ .maximum = 100,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0,
+ .maximum = 32,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Gain",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Gain",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Shutter Speed (Exposure)",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 200,
+ },
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto Gain Enabled",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain Level",
+ .minimum = 0,
+ .maximum = 256,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_SAVE_USER,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Save User Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_RESTORE_USER,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Restore User Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
+ .type = V4L2_CTRL_TYPE_BUTTON,
+ .name = "Restore Factory Settings",
+ .minimum = 0,
+ .maximum = 0,
+ .step = 0,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_COLOUR_MODE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Colour mode",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto contour",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_CONTOUR,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contour",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_BACKLIGHT,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Backlight compensation",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_FLICKERLESS,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flickerless",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Noise reduction",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+
+static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
+{
+ memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+ f->fmt.pix.width = pdev->view.x;
+ f->fmt.pix.height = pdev->view.y;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
+ f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+ } else {
+ /* vbandlength contains 4 lines ... */
+ f->fmt.pix.bytesperline = pdev->vbandlength/4;
+ f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ if (DEVICE_USE_CODEC1(pdev->type))
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
+ else
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
+ }
+ PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
+ "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ f->fmt.pix.bytesperline,
+ f->fmt.pix.sizeimage,
+ (f->fmt.pix.pixelformat)&255,
+ (f->fmt.pix.pixelformat>>8)&255,
+ (f->fmt.pix.pixelformat>>16)&255,
+ (f->fmt.pix.pixelformat>>24)&255);
+}
+
+/* ioctl(VIDIOC_TRY_FMT) */
+static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
+ return -EINVAL;
+ }
+
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUV420:
+ break;
+ case V4L2_PIX_FMT_PWC1:
+ if (DEVICE_USE_CODEC23(pdev->type)) {
+ PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_PIX_FMT_PWC2:
+ if (DEVICE_USE_CODEC1(pdev->type)) {
+ PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
+ return -EINVAL;
+ }
+ break;
+ default:
+ PWC_DEBUG_IOCTL("Unsupported pixel format\n");
+ return -EINVAL;
+
+ }
+
+ if (f->fmt.pix.width > pdev->view_max.x)
+ f->fmt.pix.width = pdev->view_max.x;
+ else if (f->fmt.pix.width < pdev->view_min.x)
+ f->fmt.pix.width = pdev->view_min.x;
+
+ if (f->fmt.pix.height > pdev->view_max.y)
+ f->fmt.pix.height = pdev->view_max.y;
+ else if (f->fmt.pix.height < pdev->view_min.y)
+ f->fmt.pix.height = pdev->view_min.y;
+
+ return 0;
+}
+
+/* ioctl(VIDIOC_SET_FMT) */
+static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
+{
+ int ret, fps, snapshot, compression, pixelformat;
+
+ ret = pwc_vidioc_try_fmt(pdev, f);
+ if (ret<0)
+ return ret;
+
+ pixelformat = f->fmt.pix.pixelformat;
+ compression = pdev->vcompression;
+ snapshot = 0;
+ fps = pdev->vframes;
+ if (f->fmt.pix.priv) {
+ compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
+ snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
+ fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+ if (fps == 0)
+ fps = pdev->vframes;
+ }
+
+ if (pixelformat == V4L2_PIX_FMT_YUV420)
+ pdev->vpalette = VIDEO_PALETTE_YUV420P;
+ else
+ pdev->vpalette = VIDEO_PALETTE_RAW;
+
+ PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+ "compression=%d snapshot=%d format=%c%c%c%c\n",
+ f->fmt.pix.width, f->fmt.pix.height, fps,
+ compression, snapshot,
+ (pixelformat)&255,
+ (pixelformat>>8)&255,
+ (pixelformat>>16)&255,
+ (pixelformat>>24)&255);
+
+ ret = pwc_try_video_mode(pdev,
+ f->fmt.pix.width,
+ f->fmt.pix.height,
+ fps,
+ compression,
+ snapshot);
+
+ PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+
+ if (ret)
+ return ret;
+
+ pwc_vidioc_fill_fmt(pdev, f);
+
+ return 0;
+
+}
+
+int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct pwc_device *pdev;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (vdev == NULL)
+ return -EFAULT;
+ pdev = vdev->priv;
+ if (pdev == NULL)
+ return -EFAULT;
+
+#if CONFIG_PWC_DEBUG
+ if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+ v4l_printk_ioctl(cmd);
+#endif
+
+
+ switch (cmd) {
+ /* Query cabapilities */
+ case VIDIOCGCAP:
+ {
+ struct video_capability *caps = arg;
+
+ strcpy(caps->name, vdev->name);
+ caps->type = VID_TYPE_CAPTURE;
+ caps->channels = 1;
+ caps->audios = 1;
+ caps->minwidth = pdev->view_min.x;
+ caps->minheight = pdev->view_min.y;
+ caps->maxwidth = pdev->view_max.x;
+ caps->maxheight = pdev->view_max.y;
+ break;
+ }
+
+ /* Channel functions (simulate 1 channel) */
+ case VIDIOCGCHAN:
+ {
+ struct video_channel *v = arg;
+
+ if (v->channel != 0)
+ return -EINVAL;
+ v->flags = 0;
+ v->tuners = 0;
+ v->type = VIDEO_TYPE_CAMERA;
+ strcpy(v->name, "Webcam");
+ return 0;
+ }
+
+ case VIDIOCSCHAN:
+ {
+ /* The spec says the argument is an integer, but
+ the bttv driver uses a video_channel arg, which
+ makes sense becasue it also has the norm flag.
+ */
+ struct video_channel *v = arg;
+ if (v->channel != 0)
+ return -EINVAL;
+ return 0;
+ }
+
+
+ /* Picture functions; contrast etc. */
+ case VIDIOCGPICT:
+ {
+ struct video_picture *p = arg;
+ int val;
+
+ val = pwc_get_brightness(pdev);
+ if (val >= 0)
+ p->brightness = (val<<9);
+ else
+ p->brightness = 0xffff;
+ val = pwc_get_contrast(pdev);
+ if (val >= 0)
+ p->contrast = (val<<10);
+ else
+ p->contrast = 0xffff;
+ /* Gamma, Whiteness, what's the difference? :) */
+ val = pwc_get_gamma(pdev);
+ if (val >= 0)
+ p->whiteness = (val<<11);
+ else
+ p->whiteness = 0xffff;
+ if (pwc_get_saturation(pdev, &val)<0)
+ p->colour = 0xffff;
+ else
+ p->colour = 32768 + val * 327;
+ p->depth = 24;
+ p->palette = pdev->vpalette;
+ p->hue = 0xFFFF; /* N/A */
+ break;
+ }
+
+ case VIDIOCSPICT:
+ {
+ struct video_picture *p = arg;
+ /*
+ * FIXME: Suppose we are mid read
+ ANSWER: No problem: the firmware of the camera
+ can handle brightness/contrast/etc
+ changes at _any_ time, and the palette
+ is used exactly once in the uncompress
+ routine.
+ */
+ pwc_set_brightness(pdev, p->brightness);
+ pwc_set_contrast(pdev, p->contrast);
+ pwc_set_gamma(pdev, p->whiteness);
+ pwc_set_saturation(pdev, (p->colour-32768)/327);
+ if (p->palette && p->palette != pdev->vpalette) {
+ switch (p->palette) {
+ case VIDEO_PALETTE_YUV420P:
+ case VIDEO_PALETTE_RAW:
+ pdev->vpalette = p->palette;
+ return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+ break;
+ }
+
+ /* Window/size parameters */
+ case VIDIOCGWIN:
+ {
+ struct video_window *vw = arg;
+
+ vw->x = 0;
+ vw->y = 0;
+ vw->width = pdev->view.x;
+ vw->height = pdev->view.y;
+ vw->chromakey = 0;
+ vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
+ (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
+ break;
+ }
+
+ case VIDIOCSWIN:
+ {
+ struct video_window *vw = arg;
+ int fps, snapshot, ret;
+
+ fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
+ snapshot = vw->flags & PWC_FPS_SNAPSHOT;
+ if (fps == 0)
+ fps = pdev->vframes;
+ if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
+ return 0;
+ ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
+ if (ret)
+ return ret;
+ break;
+ }
+
+ /* We don't have overlay support (yet) */
+ case VIDIOCGFBUF:
+ {
+ struct video_buffer *vb = arg;
+
+ memset(vb,0,sizeof(*vb));
+ break;
+ }
+
+ /* mmap() functions */
+ case VIDIOCGMBUF:
+ {
+ /* Tell the user program how much memory is needed for a mmap() */
+ struct video_mbuf *vm = arg;
+ int i;
+
+ memset(vm, 0, sizeof(*vm));
+ vm->size = pwc_mbufs * pdev->len_per_image;
+ vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
+ for (i = 0; i < pwc_mbufs; i++)
+ vm->offsets[i] = i * pdev->len_per_image;
+ break;
+ }
+
+ case VIDIOCMCAPTURE:
+ {
+ /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
+ struct video_mmap *vm = arg;
+
+ PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
+ if (vm->frame < 0 || vm->frame >= pwc_mbufs)
+ return -EINVAL;
+
+ /* xawtv is nasty. It probes the available palettes
+ by setting a very small image size and trying
+ various palettes... The driver doesn't support
+ such small images, so I'm working around it.
+ */
+ if (vm->format)
+ {
+ switch (vm->format)
+ {
+ case VIDEO_PALETTE_YUV420P:
+ case VIDEO_PALETTE_RAW:
+ break;
+ default:
+ return -EINVAL;
+ break;
+ }
+ }
+
+ if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
+ (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
+ int ret;
+
+ PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
+ ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
+ if (ret)
+ return ret;
+ } /* ... size mismatch */
+
+ /* FIXME: should we lock here? */
+ if (pdev->image_used[vm->frame])
+ return -EBUSY; /* buffer wasn't available. Bummer */
+ pdev->image_used[vm->frame] = 1;
+
+ /* Okay, we're done here. In the SYNC call we wait until a
+ frame comes available, then expand image into the given
+ buffer.
+ In contrast to the CPiA cam the Philips cams deliver a
+ constant stream, almost like a grabber card. Also,
+ we have separate buffers for the rawdata and the image,
+ meaning we can nearly always expand into the requested buffer.
+ */
+ PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
+ break;
+ }
+
+ case VIDIOCSYNC:
+ {
+ /* The doc says: "Whenever a buffer is used it should
+ call VIDIOCSYNC to free this frame up and continue."
+
+ The only odd thing about this whole procedure is
+ that MCAPTURE flags the buffer as "in use", and
+ SYNC immediately unmarks it, while it isn't
+ after SYNC that you know that the buffer actually
+ got filled! So you better not start a CAPTURE in
+ the same frame immediately (use double buffering).
+ This is not a problem for this cam, since it has
+ extra intermediate buffers, but a hardware
+ grabber card will then overwrite the buffer
+ you're working on.
+ */
+ int *mbuf = arg;
+ int ret;
+
+ PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
+
+ /* bounds check */
+ if (*mbuf < 0 || *mbuf >= pwc_mbufs)
+ return -EINVAL;
+ /* check if this buffer was requested anyway */
+ if (pdev->image_used[*mbuf] == 0)
+ return -EINVAL;
+
+ /* Add ourselves to the frame wait-queue.
+
+ FIXME: needs auditing for safety.
+ QUESTION: In what respect? I think that using the
+ frameq is safe now.
+ */
+ add_wait_queue(&pdev->frameq, &wait);
+ while (pdev->full_frames == NULL) {
+ /* Check for unplugged/etc. here */
+ if (pdev->error_status) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -pdev->error_status;
+ }
+
+ if (signal_pending(current)) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -ERESTARTSYS;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ /* The frame is ready. Expand in the image buffer
+ requested by the user. I don't care if you
+ mmap() 5 buffers and request data in this order:
+ buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
+ Grabber hardware may not be so forgiving.
+ */
+ PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
+ pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
+ /* Decompress, etc */
+ ret = pwc_handle_frame(pdev);
+ pdev->image_used[*mbuf] = 0;
+ if (ret)
+ return -EFAULT;
+ break;
+ }
+
+ case VIDIOCGAUDIO:
+ {
+ struct video_audio *v = arg;
+
+ strcpy(v->name, "Microphone");
+ v->audio = -1; /* unknown audio minor */
+ v->flags = 0;
+ v->mode = VIDEO_SOUND_MONO;
+ v->volume = 0;
+ v->bass = 0;
+ v->treble = 0;
+ v->balance = 0x8000;
+ v->step = 1;
+ break;
+ }
+
+ case VIDIOCSAUDIO:
+ {
+ /* Dummy: nothing can be set */
+ break;
+ }
+
+ case VIDIOCGUNIT:
+ {
+ struct video_unit *vu = arg;
+
+ vu->video = pdev->vdev->minor & 0x3F;
+ vu->audio = -1; /* not known yet */
+ vu->vbi = -1;
+ vu->radio = -1;
+ vu->teletext = -1;
+ break;
+ }
+
+ /* V4L2 Layer */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
+ "try to use the v4l2 layer\n");
+ strcpy(cap->driver,PWC_NAME);
+ strlcpy(cap->card, vdev->name, sizeof(cap->card));
+ usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
+ cap->version = PWC_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ return 0;
+ }
+
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *i = arg;
+
+ if ( i->index ) /* Only one INPUT is supported */
+ return -EINVAL;
+
+ memset(i, 0, sizeof(struct v4l2_input));
+ strcpy(i->name, "usb");
+ return 0;
+ }
+
+ case VIDIOC_G_INPUT:
+ {
+ int *i = arg;
+ *i = 0; /* Only one INPUT is supported */
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ int *i = arg;
+
+ if ( *i ) { /* Only one INPUT is supported */
+ PWC_DEBUG_IOCTL("Only one input source is"\
+ " supported with this webcam.\n");
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ /* TODO: */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *c = arg;
+ int i;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
+ for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
+ if (pwc_controls[i].id == c->id) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
+ memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
+ return 0;
+ }
+ }
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
+
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *c = arg;
+ int ret;
+
+ switch (c->id)
+ {
+ case V4L2_CID_BRIGHTNESS:
+ c->value = pwc_get_brightness(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_CONTRAST:
+ c->value = pwc_get_contrast(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_SATURATION:
+ ret = pwc_get_saturation(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAMMA:
+ c->value = pwc_get_gamma(pdev);
+ if (c->value<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ ret = pwc_get_red_gain(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = pwc_get_blue_gain(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = pwc_get_awb(pdev);
+ if (ret<0)
+ return -EINVAL;
+ c->value = (ret == PWC_WB_MANUAL)?0:1;
+ return 0;
+ case V4L2_CID_GAIN:
+ ret = pwc_get_agc(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value >>= 8;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ ret = pwc_get_agc(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ c->value = (c->value < 0)?1:0;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ ret = pwc_get_shutter_speed(pdev, &c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
+ ret = pwc_get_colour_mode(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
+ ret = pwc_get_contour(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value=(c->value == -1?1:0);
+ return 0;
+ case V4L2_CID_PRIVATE_CONTOUR:
+ ret = pwc_get_contour(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value >>= 10;
+ return 0;
+ case V4L2_CID_PRIVATE_BACKLIGHT:
+ ret = pwc_get_backlight(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_FLICKERLESS:
+ ret = pwc_get_flicker(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ c->value=(c->value?1:0);
+ return 0;
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+ ret = pwc_get_dynamic_noise(pdev, &c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CID_PRIVATE_SAVE_USER:
+ case V4L2_CID_PRIVATE_RESTORE_USER:
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+ return -EINVAL;
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *c = arg;
+ int ret;
+
+ switch (c->id)
+ {
+ case V4L2_CID_BRIGHTNESS:
+ c->value <<= 9;
+ ret = pwc_set_brightness(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_CONTRAST:
+ c->value <<= 10;
+ ret = pwc_set_contrast(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_SATURATION:
+ ret = pwc_set_saturation(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAMMA:
+ c->value <<= 11;
+ ret = pwc_set_gamma(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_RED_BALANCE:
+ c->value <<= 8;
+ ret = pwc_set_red_gain(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_BLUE_BALANCE:
+ c->value <<= 8;
+ ret = pwc_set_blue_gain(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
+ ret = pwc_set_awb(pdev, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ c->value <<= 8;
+ ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_AUTOGAIN:
+ /* autogain off means nothing without a gain */
+ if (c->value == 0)
+ return 0;
+ ret = pwc_set_agc(pdev, c->value, 0);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_GAIN:
+ c->value <<= 8;
+ ret = pwc_set_agc(pdev, 0, c->value);
+ if (ret<0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_SAVE_USER:
+ if (pwc_save_user(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_RESTORE_USER:
+ if (pwc_restore_user(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_RESTORE_FACTORY:
+ if (pwc_restore_factory(pdev))
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_COLOUR_MODE:
+ ret = pwc_set_colour_mode(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_AUTOCONTOUR:
+ c->value=(c->value == 1)?-1:0;
+ ret = pwc_set_contour(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_CONTOUR:
+ c->value <<= 10;
+ ret = pwc_set_contour(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_BACKLIGHT:
+ ret = pwc_set_backlight(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+ case V4L2_CID_PRIVATE_FLICKERLESS:
+ ret = pwc_set_flicker(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ case V4L2_CID_PRIVATE_NOISE_REDUCTION:
+ ret = pwc_set_dynamic_noise(pdev, c->value);
+ if (ret < 0)
+ return -EINVAL;
+ return 0;
+
+ }
+ return -EINVAL;
+ }
+
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ int index;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* We only support two format: the raw format, and YUV */
+ index = f->index;
+ memset(f,0,sizeof(struct v4l2_fmtdesc));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->index = index;
+ switch(index)
+ {
+ case 0:
+ /* RAW format */
+ f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
+ break;
+ case 1:
+ f->pixelformat = V4L2_PIX_FMT_YUV420;
+ strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ pwc_vidioc_fill_fmt(pdev, f);
+
+ return 0;
+ }
+
+ case VIDIOC_TRY_FMT:
+ return pwc_vidioc_try_fmt(pdev, arg);
+
+ case VIDIOC_S_FMT:
+ return pwc_vidioc_set_fmt(pdev, arg);
+
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *std = arg;
+ *std = V4L2_STD_UNKNOWN;
+ return 0;
+ }
+
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *std = arg;
+ if (*std != V4L2_STD_UNKNOWN)
+ return -EINVAL;
+ return 0;
+ }
+
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *std = arg;
+ if (std->index != 0)
+ return -EINVAL;
+ std->id = V4L2_STD_UNKNOWN;
+ strncpy(std->name, "webcam", sizeof(std->name));
+ return 0;
+ }
+
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *rb = arg;
+ int nbuffers;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
+ if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (rb->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ nbuffers = rb->count;
+ if (nbuffers < 2)
+ nbuffers = 2;
+ else if (nbuffers > pwc_mbufs)
+ nbuffers = pwc_mbufs;
+ /* Force to use our # of buffers */
+ rb->count = pwc_mbufs;
+ return 0;
+ }
+
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ int index;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
+ return -EINVAL;
+ }
+ if (buf->memory != V4L2_MEMORY_MMAP) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
+ return -EINVAL;
+ }
+ index = buf->index;
+ if (index < 0 || index >= pwc_mbufs) {
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
+ return -EINVAL;
+ }
+
+ memset(buf, 0, sizeof(struct v4l2_buffer));
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->index = index;
+ buf->m.offset = index * pdev->len_per_image;
+ if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ else
+ buf->bytesused = pdev->view.size;
+ buf->field = V4L2_FIELD_NONE;
+ buf->memory = V4L2_MEMORY_MMAP;
+ //buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->length = pdev->len_per_image;
+
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
+ PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
+
+ return 0;
+ }
+
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+ if (buf->index < 0 || buf->index >= pwc_mbufs)
+ return -EINVAL;
+
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+
+ return 0;
+ }
+
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *buf = arg;
+ int ret;
+
+ PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* Add ourselves to the frame wait-queue.
+
+ FIXME: needs auditing for safety.
+ QUESTION: In what respect? I think that using the
+ frameq is safe now.
+ */
+ add_wait_queue(&pdev->frameq, &wait);
+ while (pdev->full_frames == NULL) {
+ if (pdev->error_status) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -pdev->error_status;
+ }
+
+ if (signal_pending(current)) {
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+ return -ERESTARTSYS;
+ }
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ remove_wait_queue(&pdev->frameq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
+ /* Decompress data in pdev->images[pdev->fill_image] */
+ ret = pwc_handle_frame(pdev);
+ if (ret)
+ return -EFAULT;
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
+
+ buf->index = pdev->fill_image;
+ if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
+ else
+ buf->bytesused = pdev->view.size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->field = V4L2_FIELD_NONE;
+ do_gettimeofday(&buf->timestamp);
+ buf->sequence = 0;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = pdev->fill_image * pdev->len_per_image;
+ buf->length = buf->bytesused;
+ pwc_next_image(pdev);
+
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
+ PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
+ return 0;
+
+ }
+
+ case VIDIOC_STREAMON:
+ {
+ /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
+ pwc_isoc_init(pdev);
+ return 0;
+ }
+
+ case VIDIOC_STREAMOFF:
+ {
+ pwc_isoc_cleanup(pdev);
+ return 0;
+ }
+
+ default:
+ return pwc_ioctl(pdev, cmd, arg);
+ } /* ..switch */
+ return 0;
+}
+
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
/* (C) 1999-2003 Nemosoft Unv.
- (C) 2004 Luc Saillard (luc@saillard.org)
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
driver and thus may have bugs that are not present in the original version.
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/spinlock.h>
-#include <linux/videodev.h>
#include <linux/wait.h>
#include <linux/smp_lock.h>
+#include <linux/version.h>
#include <asm/semaphore.h>
#include <asm/errno.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "pwc-uncompress.h"
-#include "pwc-ioctl.h"
-
-/* Defines and structures for the Philips webcam */
-/* Used for checking memory corruption/pointer validation */
-#define PWC_MAGIC 0x89DC10ABUL
-#undef PWC_MAGIC
+#include <media/pwc-ioctl.h>
/* Turn some debugging options on/off */
-#define PWC_DEBUG 0
+#ifndef CONFIG_PWC_DEBUG
+#define CONFIG_PWC_DEBUG 1
+#endif
+
+/* Version block */
+#define PWC_MAJOR 10
+#define PWC_MINOR 0
+#define PWC_EXTRAMINOR 12
+#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
+#define PWC_VERSION "10.0.12"
+#define PWC_NAME "pwc"
+#define PFX PWC_NAME ": "
+
/* Trace certain actions in the driver */
-#define TRACE_MODULE 0x0001
-#define TRACE_PROBE 0x0002
-#define TRACE_OPEN 0x0004
-#define TRACE_READ 0x0008
-#define TRACE_MEMORY 0x0010
-#define TRACE_FLOW 0x0020
-#define TRACE_SIZE 0x0040
-#define TRACE_PWCX 0x0080
-#define TRACE_SEQUENCE 0x1000
-
-#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A)
-#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A)
-#define Info(A...) printk(KERN_INFO PWC_NAME " " A)
-#define Err(A...) printk(KERN_ERR PWC_NAME " " A)
+#define PWC_DEBUG_LEVEL_MODULE (1<<0)
+#define PWC_DEBUG_LEVEL_PROBE (1<<1)
+#define PWC_DEBUG_LEVEL_OPEN (1<<2)
+#define PWC_DEBUG_LEVEL_READ (1<<3)
+#define PWC_DEBUG_LEVEL_MEMORY (1<<4)
+#define PWC_DEBUG_LEVEL_FLOW (1<<5)
+#define PWC_DEBUG_LEVEL_SIZE (1<<6)
+#define PWC_DEBUG_LEVEL_IOCTL (1<<7)
+#define PWC_DEBUG_LEVEL_TRACE (1<<8)
+
+#define PWC_DEBUG_MODULE(fmt, args...) PWC_DEBUG(MODULE, fmt, ##args)
+#define PWC_DEBUG_PROBE(fmt, args...) PWC_DEBUG(PROBE, fmt, ##args)
+#define PWC_DEBUG_OPEN(fmt, args...) PWC_DEBUG(OPEN, fmt, ##args)
+#define PWC_DEBUG_READ(fmt, args...) PWC_DEBUG(READ, fmt, ##args)
+#define PWC_DEBUG_MEMORY(fmt, args...) PWC_DEBUG(MEMORY, fmt, ##args)
+#define PWC_DEBUG_FLOW(fmt, args...) PWC_DEBUG(FLOW, fmt, ##args)
+#define PWC_DEBUG_SIZE(fmt, args...) PWC_DEBUG(SIZE, fmt, ##args)
+#define PWC_DEBUG_IOCTL(fmt, args...) PWC_DEBUG(IOCTL, fmt, ##args)
+#define PWC_DEBUG_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+
+#if CONFIG_PWC_DEBUG
+
+#define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE)
+
+#define PWC_DEBUG(level, fmt, args...) do {\
+ if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \
+ printk(KERN_DEBUG PFX fmt, ##args); \
+ } while(0)
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) PWC_DEBUG(TRACE, fmt, ##args)
+
+#else /* if ! CONFIG_PWC_DEBUG */
+
+#define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args)
+#define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args)
+#define PWC_INFO(fmt, args...) printk(KERN_INFO PFX fmt, ##args)
+#define PWC_TRACE(fmt, args...) do { } while(0)
+#define PWC_DEBUG(level, fmt, args...) do { } while(0)
+
+#define pwc_trace 0
+#endif
/* Defines for ToUCam cameras */
#define TOUCAM_HEADER_SIZE 8
#define TOUCAM_TRAILER_SIZE 4
#define FEATURE_MOTOR_PANTILT 0x0001
-
-/* Version block */
-#define PWC_MAJOR 9
-#define PWC_MINOR 0
-#define PWC_VERSION "9.0.2-unofficial"
-#define PWC_NAME "pwc"
+#define FEATURE_CODEC1 0x0002
+#define FEATURE_CODEC2 0x0004
/* Turn certain features on/off */
#define PWC_INT_PIPE 0
/* Absolute maximum number of buffers available for mmap() */
#define MAX_IMAGES 10
+/* Some macros to quickly find the type of a webcam */
+#define DEVICE_USE_CODEC1(x) ((x)<675)
+#define DEVICE_USE_CODEC2(x) ((x)>=675 && (x)<700)
+#define DEVICE_USE_CODEC3(x) ((x)>=700)
+#define DEVICE_USE_CODEC23(x) ((x)>=675)
+
+
+#ifndef V4L2_PIX_FMT_PWC1
+#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1')
+#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2')
+#endif
+
/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */
struct pwc_iso_buf
{
void *data;
volatile int filled; /* number of bytes filled */
struct pwc_frame_buf *next; /* list */
-#if PWC_DEBUG
- int sequence; /* Sequence number */
-#endif
+};
+
+/* additionnal informations used when dealing image between kernel and userland */
+struct pwc_imgbuf
+{
+ unsigned long offset; /* offset of this buffer in the big array of image_data */
+ int vma_use_count; /* count the number of time this memory is mapped */
};
struct pwc_device
{
struct video_device *vdev;
-#ifdef PWC_MAGIC
- int magic;
-#endif
+
/* Pointer to our usb_device */
struct usb_device *udev;
int frame_size;
int frame_total_size; /* including header & trailer */
int drop_frames;
-#if PWC_DEBUG
- int sequence; /* Debugging aid */
-#endif
/* 3: decompression */
- struct pwc_decompressor *decompressor; /* function block with decompression routines */
void *decompress_data; /* private data for decompression engine */
/* 4: image */
struct pwc_coord offset; /* offset within the viewport */
void *image_data; /* total buffer, which is subdivided into ... */
- void *image_ptr[MAX_IMAGES]; /* ...several images... */
+ struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */
int fill_image; /* ...which are rotated. */
int len_per_image; /* length per image */
int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */
struct pwc_mpt_range angle_range;
int pan_angle; /* in degrees * 100 */
int tilt_angle; /* absolute angle; 0,0 is home position */
+ int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */
/*** Misc. data ***/
wait_queue_head_t frameq; /* When waiting for a frame to finish... */
#endif
};
-
#ifdef __cplusplus
extern "C" {
#endif
-/* Global variable */
+/* Global variables */
+#if CONFIG_PWC_DEBUG
extern int pwc_trace;
+#endif
+extern int pwc_mbufs;
/** functions in pwc-if.c */
int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
+int pwc_handle_frame(struct pwc_device *pdev);
+void pwc_next_image(struct pwc_device *pdev);
+int pwc_isoc_init(struct pwc_device *pdev);
+void pwc_isoc_cleanup(struct pwc_device *pdev);
/** Functions in pwc-misc.c */
/* sizes in pixels */
-extern struct pwc_coord pwc_image_sizes[PSZ_MAX];
+extern const struct pwc_coord pwc_image_sizes[PSZ_MAX];
int pwc_decode_size(struct pwc_device *pdev, int width, int height);
void pwc_construct(struct pwc_device *pdev);
/** Functions in pwc-ctrl.c */
/* Request a certain video mode. Returns < 0 if not possible */
extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot);
+/* Calculate the number of bytes per image (not frame) */
+extern int pwc_mpt_reset(struct pwc_device *pdev, int flags);
+extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt);
/* Various controls; should be obvious. Value 0..65535, or < 0 on error */
extern int pwc_get_brightness(struct pwc_device *pdev);
extern int pwc_set_contrast(struct pwc_device *pdev, int value);
extern int pwc_get_gamma(struct pwc_device *pdev);
extern int pwc_set_gamma(struct pwc_device *pdev, int value);
-extern int pwc_get_saturation(struct pwc_device *pdev);
+extern int pwc_get_saturation(struct pwc_device *pdev, int *value);
extern int pwc_set_saturation(struct pwc_device *pdev, int value);
extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value);
extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor);
+extern int pwc_restore_user(struct pwc_device *pdev);
+extern int pwc_save_user(struct pwc_device *pdev);
+extern int pwc_restore_factory(struct pwc_device *pdev);
+
+/* exported for use by v4l2 controls */
+extern int pwc_get_red_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_red_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value);
+extern int pwc_set_blue_gain(struct pwc_device *pdev, int value);
+extern int pwc_get_awb(struct pwc_device *pdev);
+extern int pwc_set_awb(struct pwc_device *pdev, int mode);
+extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_agc(struct pwc_device *pdev, int *value);
+extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value);
+extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value);
+
+extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour);
+extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour);
+extern int pwc_set_contour(struct pwc_device *pdev, int contour);
+extern int pwc_get_contour(struct pwc_device *pdev, int *contour);
+extern int pwc_set_backlight(struct pwc_device *pdev, int backlight);
+extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight);
+extern int pwc_set_flicker(struct pwc_device *pdev, int flicker);
+extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker);
+extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise);
+extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise);
/* Power down or up the camera; not supported by all models */
extern int pwc_camera_power(struct pwc_device *pdev, int power);
/* Private ioctl()s; see pwc-ioctl.h */
extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg);
+/** Functions in pwc-v4l.c */
+extern int pwc_video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
/** pwc-uncompress.c */
/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */
#endif
+/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include "saa5246a.h"
#include <linux/i2c.h>
#include <linux/videotext.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/mutex.h>
#define I2C_NAME(s) (s)->name
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
static int debug = 0;
int sat;
enum v4l2_chip_ident ident;
u32 audclk_freq;
+ u32 crystal_freq;
+ u8 ucgc;
+ u8 cgcdiv;
+ u8 apll;
};
/* ----------------------------------------------------------------------- */
};
static const unsigned char saa7115_init_misc[] = {
- 0x38, 0x03, /* audio stuff */
- 0x39, 0x10,
- 0x3a, 0x08,
-
0x81, 0x01, /* reg 0x15,0x16 define blanking window */
0x82, 0x00,
0x83, 0x01, /* I port settings */
u32 acni;
u32 hz;
u64 f;
+ u8 acc = 0; /* reg 0x3a, audio clock control */
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
if (freq < 32000 || freq > 48000)
return -EINVAL;
+ /* The saa7113 has no audio clock */
+ if (state->ident == V4L2_IDENT_SAA7113)
+ return 0;
+
/* hz is the refresh rate times 100 */
hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
acpf = (25600 * freq) / hz;
/* acni = (256 * freq * 2^23) / crystal_frequency =
(freq * 2^(8+23)) / crystal_frequency =
- (freq << 31) / 32.11 MHz */
+ (freq << 31) / crystal_frequency */
f = freq;
f = f << 31;
- do_div(f, 32110000);
+ do_div(f, state->crystal_freq);
acni = f;
+ if (state->ucgc) {
+ acpf = acpf * state->cgcdiv / 16;
+ acni = acni * state->cgcdiv / 16;
+ acc = 0x80;
+ if (state->cgcdiv == 3)
+ acc |= 0x40;
+ }
+ if (state->apll)
+ acc |= 0x08;
+ saa7115_write(client, 0x38, 0x03);
+ saa7115_write(client, 0x39, 0x10);
+ saa7115_write(client, 0x3a, acc);
saa7115_write(client, 0x30, acpf & 0xff);
saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
/* ============ SAA7115 AUDIO settings (end) ============= */
-static struct v4l2_queryctrl saa7115_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- },
-};
-
-/* ----------------------------------------------------------------------- */
-
static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa7115_state *state = i2c_get_clientdata(client);
case VIDIOC_QUERYCTRL:
{
struct v4l2_queryctrl *qc = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(saa7115_qctrl); i++)
- if (qc->id && qc->id == saa7115_qctrl[i].id) {
- memcpy(qc, &saa7115_qctrl[i], sizeof(*qc));
- return 0;
- }
- return -EINVAL;
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill_std(qc);
+ default:
+ return -EINVAL;
+ }
}
case VIDIOC_G_STD:
break;
}
- case VIDIOC_G_INPUT:
- *(int *)arg = state->input;
- break;
-
- case VIDIOC_S_INPUT:
- v4l_dbg(1, debug, client, "decoder set input %d\n", *iarg);
- /* inputs from 0-9 are available */
- if (*iarg < 0 || *iarg > 9) {
- return -EINVAL;
- }
-
- if (state->input == *iarg)
- break;
- v4l_dbg(1, debug, client, "now setting %s input\n",
- *iarg >= 6 ? "S-Video" : "Composite");
- state->input = *iarg;
-
- /* select mode */
- saa7115_write(client, 0x02,
- (saa7115_read(client, 0x02) & 0xf0) |
- state->input);
-
- /* bypass chrominance trap for modes 6..9 */
- saa7115_write(client, 0x09,
- (saa7115_read(client, 0x09) & 0x7f) |
- (state->input < 6 ? 0x0 : 0x80));
- break;
-
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
v4l_dbg(1, debug, client, "%s output\n",
}
break;
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *freq = arg;
+
+ if (freq->freq != SAA7115_FREQ_32_11_MHZ &&
+ freq->freq != SAA7115_FREQ_24_576_MHZ)
+ return -EINVAL;
+ state->crystal_freq = freq->freq;
+ state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
+ state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
+ state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
+ saa7115_set_audio_clock_freq(client, state->audclk_freq);
+ break;
+ }
+
case VIDIOC_INT_DECODE_VBI_LINE:
saa7115_decode_vbi_line(client, arg);
break;
v4l_dbg(1, debug, client, "writing init values\n");
/* init to 60hz/48khz */
- if (state->ident == V4L2_IDENT_SAA7113)
+ if (state->ident == V4L2_IDENT_SAA7113) {
+ state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
saa7115_writeregs(client, saa7113_init_auto_input);
- else
+ } else {
+ state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
saa7115_writeregs(client, saa7115_init_auto_input);
+ }
saa7115_writeregs(client, saa7115_init_misc);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
"letterbox 16:9 top",
"invalid",
"invalid",
- "16:9 full format anamorphic"
+ "16:9 full format anamorphic",
"4:3 full format",
"invalid",
"invalid",
SAA6752HS_VF_UNKNOWN,
};
+struct saa6752hs_mpeg_params {
+ /* transport streams */
+ __u16 ts_pid_pmt;
+ __u16 ts_pid_audio;
+ __u16 ts_pid_video;
+ __u16 ts_pid_pcr;
+
+ /* audio */
+ enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate;
+
+ /* video */
+ enum v4l2_mpeg_video_aspect vi_aspect;
+ enum v4l2_mpeg_video_bitrate_mode vi_bitrate_mode;
+ __u32 vi_bitrate;
+ __u32 vi_bitrate_peak;
+};
+
static const struct v4l2_format v4l2_format_table[] =
{
[SAA6752HS_VF_D1] =
struct saa6752hs_state {
struct i2c_client client;
- struct v4l2_mpeg_compression params;
+ struct v4l2_mpeg_compression old_params;
+ struct saa6752hs_mpeg_params params;
enum saa6752hs_videoformat video_format;
v4l2_std_id standard;
};
enum saa6752hs_command {
SAA6752HS_COMMAND_RESET = 0,
- SAA6752HS_COMMAND_STOP = 1,
- SAA6752HS_COMMAND_START = 2,
- SAA6752HS_COMMAND_PAUSE = 3,
- SAA6752HS_COMMAND_RECONFIGURE = 4,
- SAA6752HS_COMMAND_SLEEP = 5,
+ SAA6752HS_COMMAND_STOP = 1,
+ SAA6752HS_COMMAND_START = 2,
+ SAA6752HS_COMMAND_PAUSE = 3,
+ SAA6752HS_COMMAND_RECONFIGURE = 4,
+ SAA6752HS_COMMAND_SLEEP = 5,
SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6,
SAA6752HS_COMMAND_MAX
0x00, 0x00, 0x00, 0x00 /* CRC32 */
};
-static struct v4l2_mpeg_compression param_defaults =
+static struct saa6752hs_mpeg_params param_defaults =
+{
+ .ts_pid_pmt = 16,
+ .ts_pid_video = 260,
+ .ts_pid_audio = 256,
+ .ts_pid_pcr = 259,
+
+ .vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3,
+ .vi_bitrate = 4000,
+ .vi_bitrate_peak = 6000,
+ .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+
+ .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+};
+
+static struct v4l2_mpeg_compression old_param_defaults =
{
.st_type = V4L2_MPEG_TS_2,
.st_bitrate = {
static int saa6752hs_set_bitrate(struct i2c_client* client,
- struct v4l2_mpeg_compression* params)
+ struct saa6752hs_mpeg_params* params)
{
u8 buf[3];
+ int tot_bitrate;
/* set the bitrate mode */
buf[0] = 0x71;
- buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1;
+ buf[1] = (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ? 0 : 1;
i2c_master_send(client, buf, 2);
/* set the video bitrate */
- if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) {
+ if (params->vi_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) {
/* set the target bitrate */
buf[0] = 0x80;
- buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[1] = params->vi_bitrate >> 8;
+ buf[2] = params->vi_bitrate & 0xff;
i2c_master_send(client, buf, 3);
/* set the max bitrate */
buf[0] = 0x81;
- buf[1] = params->vi_bitrate.max >> 8;
- buf[2] = params->vi_bitrate.max & 0xff;
+ buf[1] = params->vi_bitrate_peak >> 8;
+ buf[2] = params->vi_bitrate_peak & 0xff;
i2c_master_send(client, buf, 3);
+ tot_bitrate = params->vi_bitrate_peak;
} else {
/* set the target bitrate (no max bitrate for CBR) */
buf[0] = 0x81;
- buf[1] = params->vi_bitrate.target >> 8;
- buf[2] = params->vi_bitrate.target & 0xff;
+ buf[1] = params->vi_bitrate >> 8;
+ buf[2] = params->vi_bitrate & 0xff;
i2c_master_send(client, buf, 3);
+ tot_bitrate = params->vi_bitrate;
}
/* set the audio bitrate */
buf[0] = 0x94;
- buf[1] = (256 == params->au_bitrate.target) ? 0 : 1;
+ buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1;
i2c_master_send(client, buf, 2);
+ tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384;
+
+ /* Note: the total max bitrate is determined by adding the video and audio
+ bitrates together and also adding an extra 768kbit/s to stay on the
+ safe side. If more control should be required, then an extra MPEG control
+ should be added. */
+ tot_bitrate += 768;
+ if (tot_bitrate > MPEG_TOTAL_TARGET_BITRATE_MAX)
+ tot_bitrate = MPEG_TOTAL_TARGET_BITRATE_MAX;
/* set the total bitrate */
buf[0] = 0xb1;
- buf[1] = params->st_bitrate.target >> 8;
- buf[2] = params->st_bitrate.target & 0xff;
+ buf[1] = tot_bitrate >> 8;
+ buf[2] = tot_bitrate & 0xff;
i2c_master_send(client, buf, 3);
return 0;
}
-static void saa6752hs_set_params(struct i2c_client* client,
+static void saa6752hs_old_set_params(struct i2c_client* client,
struct v4l2_mpeg_compression* params)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
/* check PIDs */
- if (params->ts_pid_pmt <= MPEG_PID_MAX)
+ if (params->ts_pid_pmt <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_pmt = params->ts_pid_pmt;
h->params.ts_pid_pmt = params->ts_pid_pmt;
- if (params->ts_pid_pcr <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_pcr <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_pcr = params->ts_pid_pcr;
h->params.ts_pid_pcr = params->ts_pid_pcr;
- if (params->ts_pid_video <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_video <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_video = params->ts_pid_video;
h->params.ts_pid_video = params->ts_pid_video;
- if (params->ts_pid_audio <= MPEG_PID_MAX)
+ }
+ if (params->ts_pid_audio <= MPEG_PID_MAX) {
+ h->old_params.ts_pid_audio = params->ts_pid_audio;
h->params.ts_pid_audio = params->ts_pid_audio;
+ }
/* check bitrate parameters */
if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) ||
- (params->vi_bitrate.mode == V4L2_BITRATE_VBR))
- h->params.vi_bitrate.mode = params->vi_bitrate.mode;
+ (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) {
+ h->old_params.vi_bitrate.mode = params->vi_bitrate.mode;
+ h->params.vi_bitrate_mode = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ?
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR : V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ }
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.st_bitrate.target = params->st_bitrate.target;
+ h->old_params.st_bitrate.target = params->st_bitrate.target;
if (params->vi_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.vi_bitrate.target = params->vi_bitrate.target;
+ h->old_params.vi_bitrate.target = params->vi_bitrate.target;
if (params->vi_bitrate.mode == V4L2_BITRATE_VBR)
- h->params.vi_bitrate.max = params->vi_bitrate.max;
+ h->old_params.vi_bitrate.max = params->vi_bitrate.max;
if (params->au_bitrate.mode != V4L2_BITRATE_NONE)
- h->params.au_bitrate.target = params->au_bitrate.target;
+ h->old_params.au_bitrate.target = params->au_bitrate.target;
/* aspect ratio */
if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 ||
- params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9)
- h->params.vi_aspect_ratio = params->vi_aspect_ratio;
+ params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) {
+ h->old_params.vi_aspect_ratio = params->vi_aspect_ratio;
+ if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3)
+ h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ else
+ h->params.vi_aspect = V4L2_MPEG_VIDEO_ASPECT_16x9;
+ }
/* range checks */
- if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
- h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
- if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
- h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
- if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
- h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
- if (h->params.au_bitrate.target <= 256)
- h->params.au_bitrate.target = 256;
+ if (h->old_params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX)
+ h->old_params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX;
+ if (h->old_params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX)
+ h->old_params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX;
+ if (h->old_params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX)
+ h->old_params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX;
+ h->params.vi_bitrate = params->vi_bitrate.target;
+ h->params.vi_bitrate_peak = params->vi_bitrate.max;
+ if (h->old_params.au_bitrate.target <= 256) {
+ h->old_params.au_bitrate.target = 256;
+ h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+ }
+ else {
+ h->old_params.au_bitrate.target = 384;
+ h->params.au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+ }
+}
+
+static int handle_ctrl(struct saa6752hs_mpeg_params *params,
+ struct v4l2_ext_control *ctrl, int cmd)
+{
+ int old = 0, new;
+ int set = cmd == VIDIOC_S_EXT_CTRLS;
+
+ new = ctrl->value;
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ old = V4L2_MPEG_STREAM_TYPE_MPEG2_TS;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ old = params->ts_pid_pmt;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_pmt = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ old = params->ts_pid_audio;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_audio = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ old = params->ts_pid_video;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_video = new;
+ break;
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ old = params->ts_pid_pcr;
+ if (set && new > MPEG_PID_MAX)
+ return -ERANGE;
+ if (new > MPEG_PID_MAX)
+ new = MPEG_PID_MAX;
+ params->ts_pid_pcr = new;
+ break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ old = params->au_l2_bitrate;
+ if (set && new != V4L2_MPEG_AUDIO_L2_BITRATE_256K &&
+ new != V4L2_MPEG_AUDIO_L2_BITRATE_384K)
+ return -ERANGE;
+ if (new <= V4L2_MPEG_AUDIO_L2_BITRATE_256K)
+ new = V4L2_MPEG_AUDIO_L2_BITRATE_256K;
+ else
+ new = V4L2_MPEG_AUDIO_L2_BITRATE_384K;
+ params->au_l2_bitrate = new;
+ break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ old = V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (set && new != old)
+ return -ERANGE;
+ new = old;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ old = params->vi_aspect;
+ if (set && new != V4L2_MPEG_VIDEO_ASPECT_16x9 &&
+ new != V4L2_MPEG_VIDEO_ASPECT_4x3)
+ return -ERANGE;
+ if (new != V4L2_MPEG_VIDEO_ASPECT_16x9)
+ new = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ params->vi_aspect = new;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ old = params->vi_bitrate * 1000;
+ new = 1000 * (new / 1000);
+ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ return -ERANGE;
+ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+ params->vi_bitrate = new / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ old = params->vi_bitrate_peak * 1000;
+ new = 1000 * (new / 1000);
+ if (set && new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ return -ERANGE;
+ if (new > MPEG_VIDEO_TARGET_BITRATE_MAX * 1000)
+ new = MPEG_VIDEO_TARGET_BITRATE_MAX * 1000;
+ params->vi_bitrate_peak = new / 1000;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ old = params->vi_bitrate_mode;
+ params->vi_bitrate_mode = new;
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (cmd == VIDIOC_G_EXT_CTRLS)
+ ctrl->value = old;
else
- h->params.au_bitrate.target = 384;
+ ctrl->value = new;
+ return 0;
}
static int saa6752hs_init(struct i2c_client* client)
buf[2] = 0x0D;
i2c_master_send(client,buf,3);
- /* Set minimum Q-scale {4} */
+ /* Set minimum Q-scale {4} */
buf[0] = 0x82;
buf[1] = 0x04;
i2c_master_send(client,buf,2);
- /* Set maximum Q-scale {12} */
+ /* Set maximum Q-scale {12} */
buf[0] = 0x83;
buf[1] = 0x0C;
i2c_master_send(client,buf,2);
- /* Set Output Protocol */
+ /* Set Output Protocol */
buf[0] = 0xD0;
buf[1] = 0x81;
i2c_master_send(client,buf,2);
- /* Set video output stream format {TS} */
+ /* Set video output stream format {TS} */
buf[0] = 0xB0;
buf[1] = 0x05;
i2c_master_send(client,buf,2);
localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF;
localPMT[sizeof(PMT) - 1] = crc & 0xFF;
- /* Set Audio PID */
+ /* Set Audio PID */
buf[0] = 0xC1;
buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF;
buf[2] = h->params.ts_pid_audio & 0xFF;
buf[3] = 0x82;
buf[4] = 0xB0;
buf[5] = buf2[0];
- switch(h->params.vi_aspect_ratio) {
- case V4L2_MPEG_ASPECT_16_9:
+ switch(h->params.vi_aspect) {
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
buf[6] = buf2[1] | 0x40;
break;
- case V4L2_MPEG_ASPECT_4_3:
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
default:
buf[6] = buf2[1] & 0xBF;
break;
return -ENOMEM;
h->client = client_template;
h->params = param_defaults;
+ h->old_params = old_param_defaults;
h->client.adapter = adap;
h->client.addr = addr;
saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
struct saa6752hs_state *h = i2c_get_clientdata(client);
- struct v4l2_mpeg_compression *params = arg;
+ struct v4l2_ext_controls *ctrls = arg;
+ struct v4l2_mpeg_compression *old_params = arg;
+ struct saa6752hs_mpeg_params params;
int err = 0;
+ int i;
switch (cmd) {
case VIDIOC_S_MPEGCOMP:
- if (NULL == params) {
+ if (NULL == old_params) {
/* apply settings and start encoder */
saa6752hs_init(client);
break;
}
- saa6752hs_set_params(client, params);
+ saa6752hs_old_set_params(client, old_params);
/* fall through */
case VIDIOC_G_MPEGCOMP:
- *params = h->params;
+ *old_params = h->old_params;
+ break;
+ case VIDIOC_S_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ if (ctrls->count == 0) {
+ /* apply settings and start encoder */
+ saa6752hs_init(client);
+ break;
+ }
+ /* fall through */
+ case VIDIOC_TRY_EXT_CTRLS:
+ case VIDIOC_G_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ params = h->params;
+ for (i = 0; i < ctrls->count; i++) {
+ if ((err = handle_ctrl(¶ms, ctrls->controls + i, cmd))) {
+ ctrls->error_idx = i;
+ return err;
+ }
+ }
+ h->params = params;
break;
case VIDIOC_G_FMT:
{
break;
}
- /* output xbar always main channel */
+ /* output xbar always main channel */
saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, 0xbbbb10);
if (left || right) { // We've got data, turn the input on
.radio = {
.name = name_radio,
.amux = LINE2,
- },
+ },
},
[SAA7134_BOARD_GOTVIEW_7135] = {
/* Mike Baikov <mike@baikov.com> */
.gpio = 0x000000, /* GPIO21=Low for FM radio antenna */
},
},
+ [SAA7134_BOARD_FLYVIDEO3000_NTSC] = {
+ /* "Zac Bowling" <zac@zacbowling.com> */
+ .name = "LifeView FlyVIDEO3000 (NTSC)",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .gpiomask = 0xe000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .gpio = 0x8000,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x0000,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ .gpio = 0x4000,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ .gpio = 0x2000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
.subvendor = 0x153b,
.subdevice = 0x1162,
.driver_data = SAA7134_BOARD_CINERGY400_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5169,
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000_NTSC,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
+ case SAA7134_BOARD_FLYVIDEO3000_NTSC:
dev->has_remote = SAA7134_REMOTE_GPIO;
board_flyvideo(dev);
break;
return 0;
}
-static int mt352_pinnacle_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params,
- u8* pllbuf)
+static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params)
{
u8 off[] = { 0x00, 0xf1};
u8 on[] = { 0x00, 0x71};
f.tuner = 0;
f.type = V4L2_TUNER_DIGITAL_TV;
f.frequency = params->frequency / 1000 * 16 / 1000;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
msg.buf = on;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
pinnacle_antenna_pwr(dev, antenna_pwr);
/* mt352 setup */
- mt352_pinnacle_init(fe);
- pllbuf[0] = 0xc2;
- pllbuf[1] = 0x00;
- pllbuf[2] = 0x00;
- pllbuf[3] = 0x80;
- pllbuf[4] = 0x00;
- return 0;
+ return mt352_pinnacle_init(fe);
}
-static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf)
+static int mt352_aver777_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
{
- pllbuf[0] = 0xc2;
+ if (buf_len < 5)
+ return -EINVAL;
+
+ pllbuf[0] = 0x61;
dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1,
params->frequency,
params->u.ofdm.bandwidth);
- return 0;
+ return 5;
}
static struct mt352_config pinnacle_300i = {
.if2 = 36150,
.no_tuner = 1,
.demod_init = mt352_pinnacle_init,
- .pll_set = mt352_pinnacle_pll_set,
};
static struct mt352_config avermedia_777 = {
.demod_address = 0xf,
.demod_init = mt352_aver777_init,
- .pll_set = mt352_aver777_pll_set,
};
#endif
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
/* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
/* ------------------------------------------------------------------ */
-static int philips_tu1216_pll_60_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_60_init(struct dvb_frontend *fe)
{
return philips_tda6651_pll_init(0x60, fe);
}
-static int philips_tu1216_pll_60_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_60_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x60, fe, params);
}
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_60_init,
- .pll_set = philips_tu1216_pll_60_set,
- .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
/* ------------------------------------------------------------------ */
-static int philips_tu1216_pll_61_init(struct dvb_frontend *fe)
+static int philips_tu1216_tuner_61_init(struct dvb_frontend *fe)
{
return philips_tda6651_pll_init(0x61, fe);
}
-static int philips_tu1216_pll_61_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tu1216_tuner_61_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x61, fe, params);
}
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_DEFAULT,
.if_freq = TDA10046_FREQ_3617,
- .pll_init = philips_tu1216_pll_61_init,
- .pll_set = philips_tu1216_pll_61_set,
- .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
/* ------------------------------------------------------------------ */
-static int philips_europa_pll_init(struct dvb_frontend *fe)
+static int philips_europa_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 msg[] = { 0x0b, 0xf5, 0x86, 0xab };
struct i2c_msg init_msg = {.addr = 0x61,.flags = 0,.buf = msg,.len = sizeof(msg) };
/* setup PLL configuration */
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
return -EIO;
msleep(1);
init_msg.len = 0x02;
msg[0] = 0x00;
msg[1] = 0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &init_msg, 1) != 1)
return -EIO;
return 0;
}
-static int philips_td1316_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_td1316_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
return philips_tda6651_pll_set(0x61, fe, params);
}
-static void philips_europa_analog(struct dvb_frontend *fe)
+static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message actually turns the tuner back to analog mode */
analog_msg.len = 0x02;
msg[0] = 0x00;
msg[1] = 0x14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ return 0;
+}
+
+static int philips_europa_demod_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ if (dev->original_demod_sleep)
+ dev->original_demod_sleep(fe);
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ return 0;
}
static struct tda1004x_config philips_europa_config = {
.xtal_freq = TDA10046_XTAL_4M,
.agc_config = TDA10046_AGC_IFO_AUTO_POS,
.if_freq = TDA10046_FREQ_052,
- .pll_init = philips_europa_pll_init,
- .pll_set = philips_td1316_pll_set,
- .pll_sleep = philips_europa_analog,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message is to set up ATC and ALC */
static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
msleep(1);
return 0;
}
-static void philips_fmd1216_analog(struct dvb_frontend *fe)
+static int philips_fmd1216_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* this message actually turns the tuner back to analog mode */
static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
msleep(1);
fmd1216_init[2] = 0x86;
fmd1216_init[3] = 0x54;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
msleep(1);
+ return 0;
}
-static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_fmd1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[4];
tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
tuner_buf[3] = 0x40 | band;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
return 0;
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_IFO_AUTO_NEG,
.if_freq = TDA10046_FREQ_3613,
- .pll_init = philips_fmd1216_pll_init,
- .pll_set = philips_fmd1216_pll_set,
- .pll_sleep = philips_fmd1216_analog,
.request_firmware = NULL,
};
{ .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
};
-static int philips_tda827x_pll_init(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
{
return 0;
}
-static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tda827x_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
u8 tuner_buf[14];
tuner_buf[13] = 0x40;
tuner_msg.len = 14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
return -EIO;
tuner_buf[0] = 0x30;
tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
tuner_msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
return 0;
}
-static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
+static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda827x_sleep[] = { 0x30, 0xd0};
struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
.len = sizeof(tda827x_sleep) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+ return 0;
}
static struct tda1004x_config tda827x_lifeview_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = philips_tda827x_pll_init,
- .pll_set = philips_tda827x_pll_set,
- .pll_sleep = philips_tda827x_pll_sleep,
.request_firmware = NULL,
};
tuner_buf[12] = 0x00;
tuner_buf[13] = 0x39; // lpsel
msg.len = 14;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
return -EIO;
msg.len = 2;
reg2[0] = 0x60;
reg2[1] = 0x3c;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
reg2[0] = 0xa0;
reg2[1] = 0x40;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
msleep(2);
reg2[0] = 0x30;
reg2[1] = 0x10 + tda827xa_dvbt[i].scr;
msg.len = 2;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
msleep(550);
reg2[0] = 0x50;
reg2[1] = 0x4f + (tda827xa_dvbt[i].gc3 << 4);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &msg, 1);
return 0;
}
-static void philips_tda827xa_pll_sleep(u8 addr, struct dvb_frontend *fe)
+static int philips_tda827xa_tuner_sleep(u8 addr, struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda827xa_sleep[] = { 0x30, 0x90};
struct i2c_msg tuner_msg = {.addr = addr,.flags = 0,.buf = tda827xa_sleep,
.len = sizeof(tda827xa_sleep) };
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
-
+ return 0;
}
/* ------------------------------------------------------------------ */
-static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int philips_tiger_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
struct saa7134_dev *dev = fe->dvb->priv;
static u8 tda8290_close[] = { 0x21, 0xc0};
static u8 tda8290_open[] = { 0x21, 0x80};
struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+
/* close tda8290 i2c bridge */
tda8290_msg.buf = tda8290_close;
ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
return ret;
}
-static int philips_tiger_dvb_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 data[] = { 0x3c, 0x33, 0x6a};
return 0;
}
-static void philips_tiger_analog_mode(struct dvb_frontend *fe)
+static int philips_tiger_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
static u8 data[] = { 0x3c, 0x33, 0x68};
struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
i2c_transfer(&dev->i2c_adap, &msg, 1);
- philips_tda827xa_pll_sleep( 0x61, fe);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
}
static struct tda1004x_config philips_tiger_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = philips_tiger_dvb_mode,
- .pll_set = philips_tiger_pll_set,
- .pll_sleep = philips_tiger_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
return ret;
}
-static int lifeview_trio_dvb_mode(struct dvb_frontend *fe)
+static int lifeview_trio_tuner_sleep(struct dvb_frontend *fe)
{
+ philips_tda827xa_tuner_sleep(0x60, fe);
return 0;
}
-static void lifeview_trio_analog_mode(struct dvb_frontend *fe)
-{
- philips_tda827xa_pll_sleep(0x60, fe);
-}
-
static struct tda1004x_config lifeview_trio_config = {
.demod_address = 0x09,
.invert = 1,
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X_GPL,
.if_freq = TDA10046_FREQ_045,
- .pll_init = lifeview_trio_dvb_mode,
- .pll_set = lifeview_trio_pll_set,
- .pll_sleep = lifeview_trio_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int ads_duo_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
return ret;
}
-static int ads_duo_dvb_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* route TDA8275a AGC input to the channel decoder */
return 0;
}
-static void ads_duo_analog_mode(struct dvb_frontend *fe)
+static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
/* route TDA8275a AGC input to the analog IF chip*/
saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20);
- philips_tda827xa_pll_sleep( 0x61, fe);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
}
static struct tda1004x_config ads_tech_duo_config = {
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X_GPL,
.if_freq = TDA10046_FREQ_045,
- .pll_init = ads_duo_dvb_mode,
- .pll_set = ads_duo_pll_set,
- .pll_sleep = ads_duo_analog_mode,
.request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
-static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+static int tevion_dvb220rf_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
ret = philips_tda827xa_pll_set(0x60, fe, params);
return ret;
}
-static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe)
+static int tevion_dvb220rf_tuner_sleep(struct dvb_frontend *fe)
{
+ philips_tda827xa_tuner_sleep( 0x61, fe);
return 0;
}
-static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe)
-{
- philips_tda827xa_pll_sleep( 0x61, fe);
-}
-
static struct tda1004x_config tevion_dvbt220rf_config = {
.demod_address = 0x08,
.invert = 1,
.xtal_freq = TDA10046_XTAL_16M,
.agc_config = TDA10046_AGC_TDA827X,
.if_freq = TDA10046_FREQ_045,
- .pll_init = tevion_dvb220rf_pll_init,
- .pll_set = tevion_dvb220rf_pll_set,
- .pll_sleep = tevion_dvb220rf_pll_sleep,
.request_firmware = NULL,
};
#ifdef HAVE_NXT200X
static struct nxt200x_config avertvhda180 = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tdhu2,
};
static int nxt200x_set_pll_input(u8 *buf, int input)
static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
- .pll_address = 0x61,
- .pll_desc = &dvb_pll_tuv1236d,
.set_pll_input = nxt200x_set_pll_input,
};
#endif
printk("%s: pinnacle 300i dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&pinnacle_300i,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
+ }
break;
case SAA7134_BOARD_AVERMEDIA_777:
printk("%s: avertv 777 dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&avermedia_777,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
+ }
break;
#endif
#ifdef HAVE_TDA1004X
case SAA7134_BOARD_MD7134:
dev->dvb.frontend = tda10046_attach(&medion_cardbus,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBTDUO:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
dev->dvb.frontend = tda10046_attach(&philips_europa_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
dev->dvb.frontend = tda10046_attach(&philips_europa_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
+ }
break;
case SAA7134_BOARD_PHILIPS_TIGER:
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_LR301:
dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_tda827x_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVB_TRIO:
dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
+ }
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
+ }
break;
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
&dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
+ }
break;
#endif
#ifdef HAVE_NXT200X
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+ }
break;
case SAA7134_BOARD_KWORLD_ATSC110:
dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+ }
break;
#endif
default:
}
/* register everything else */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
}
static int dvb_fini(struct saa7134_dev *dev)
static int ts_init_encoder(struct saa7134_dev* dev)
{
+ struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 };
+
ts_reset_encoder(dev);
- saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL);
+ saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls);
dev->empress_started = 1;
return 0;
}
unsigned int cmd, void *arg)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_ext_controls *ctrls = arg;
if (debug > 1)
v4l_print_ioctl(dev->name,cmd);
return saa7134_common_ioctl(dev, cmd, arg);
case VIDIOC_S_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_S_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_S_EXT_CTRLS!");
saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg);
ts_init_encoder(dev);
return 0;
case VIDIOC_G_MPEGCOMP:
+ printk(KERN_WARNING "VIDIOC_G_MPEGCOMP is obsolete. "
+ "Replace with VIDIOC_G_EXT_CTRLS!");
saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg);
return 0;
+ case VIDIOC_S_EXT_CTRLS:
+ /* count == 0 is abused in saa6752hs.c, so that special
+ case is handled here explicitly. */
+ if (ctrls->count == 0)
+ return 0;
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, arg);
+ ts_init_encoder(dev);
+ return 0;
+ case VIDIOC_G_EXT_CTRLS:
+ if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, arg);
+ return 0;
default:
return -ENOIOCTLCMD;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+static int pinnacle_remote = 0;
+module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
+MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
+
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_PCTV_110i:
snprintf(ir->c.name, sizeof(ir->c.name), "Pinnacle PCTV");
- ir->get_key = get_key_pinnacle;
- ir->ir_codes = ir_codes_pinnacle;
+ if (pinnacle_remote == 0) {
+ ir->get_key = get_key_pinnacle_color;
+ ir->ir_codes = ir_codes_pinnacle_color;
+ } else {
+ ir->get_key = get_key_pinnacle_grey;
+ ir->ir_codes = ir_codes_pinnacle_grey;
+ }
break;
case SAA7134_BOARD_UPMOST_PURPLE_TV:
snprintf(ir->c.name, sizeof(ir->c.name), "Purple TV");
#include <asm/io.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
#define SAA7134_BOARD_AVERMEDIA_A169_B1 92
#define SAA7134_BOARD_MD7134_BRIDGE_2 93
#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
+#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
+ int (*original_demod_sleep)(struct dvb_frontend* fe);
};
/* ----------------------------------------------------------- */
#include <asm/uaccess.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
case VIDIOC_G_CTRL:
return sn9c102_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return sn9c102_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return sn9c102_vidioc_cropcap(cam, arg);
case VIDIOC_G_PARM:
return sn9c102_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return sn9c102_vidioc_s_parm(cam, arg);
#include <asm/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "saa7146.h"
#include "saa7146reg.h"
#include <linux/pagemap.h>
#include <linux/errno.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
struct tda9875 *t = i2c_get_clientdata(client);
dprintk("In tda9875_init\n");
tda9875_write(client, TDA9875_CFG, 0xd0 ); /*reg de config 0 (reset)*/
- tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
+ tda9875_write(client, TDA9875_MSR, 0x03 ); /* Monitor 0b00000XXX*/
tda9875_write(client, TDA9875_C1MSB, 0x00 ); /*Car1(FM) MSB XMHz*/
tda9875_write(client, TDA9875_C1MIB, 0x00 ); /*Car1(FM) MIB XMHz*/
tda9875_write(client, TDA9875_C1LSB, 0x00 ); /*Car1(FM) LSB XMHz*/
TDA9886 (PAL, SECAM, NTSC)
TDA9887 (PAL, SECAM, NTSC, FM Radio)
- found on:
- - Pinnacle PCTV (Jul.2002 Version with MT2032, bttv)
- TDA9887 (world), TDA9885 (USA)
- Note: OP2 of tda988x must be set to 1, else MT2032 is disabled!
- - KNC One TV-Station RDS (saa7134)
- - Hauppauge PVR-150/500 (possibly more)
+ Used as part of several tuners
*/
+#define tda9887_info(fmt, arg...) do {\
+ printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
+#define tda9887_dbg(fmt, arg...) do {\
+ if (tuner_debug) \
+ printk(KERN_INFO "%s %d-%04x (tda9887): " fmt, t->i2c.name, \
+ i2c_adapter_id(t->i2c.adapter), t->i2c.addr , ##arg); } while (0)
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {
- 0x84 >>1,
- 0x86 >>1,
- 0x96 >>1,
- I2C_CLIENT_END,
-};
-I2C_CLIENT_INSMOD;
-
-/* insmod options */
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_LICENSE("GPL");
/* ---------------------------------------------------------------------- */
#define UNSET (-1U)
-#define tda9887_info(fmt, arg...) do {\
- printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
- i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
-#define tda9887_dbg(fmt, arg...) do {\
- if (debug) \
- printk(KERN_INFO "%s %d-%04x: " fmt, t->client.name, \
- i2c_adapter_id(t->client.adapter), t->client.addr , ##arg); } while (0)
-
-struct tda9887 {
- struct i2c_client client;
- v4l2_std_id std;
- enum tuner_mode mode;
- unsigned int config;
- unsigned int using_v4l2;
- unsigned int radio_mode;
- unsigned char data[4];
-};
struct tvnorm {
v4l2_std_id std;
unsigned char e;
};
-static struct i2c_driver driver;
-static struct i2c_client client_template;
-
/* ---------------------------------------------------------------------- */
//
/* ---------------------------------------------------------------------- */
-static void dump_read_message(struct tda9887 *t, unsigned char *buf)
+static void dump_read_message(struct tuner *t, unsigned char *buf)
{
static char *afc[16] = {
"- 12.5 kHz",
tda9887_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low");
}
-static void dump_write_message(struct tda9887 *t, unsigned char *buf)
+static void dump_write_message(struct tuner *t, unsigned char *buf)
{
static char *sound[4] = {
"AM/TV",
/* ---------------------------------------------------------------------- */
-static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
+static int tda9887_set_tvnorm(struct tuner *t, char *buf)
{
struct tvnorm *norm = NULL;
int i;
- if (t->mode == T_RADIO) {
- if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+ if (t->mode == V4L2_TUNER_RADIO) {
+ if (t->audmode == V4L2_TUNER_MODE_MONO)
norm = &radio_mono;
else
norm = &radio_stereo;
module_param(qss, int, 0644);
module_param(adjust, int, 0644);
-static int tda9887_set_insmod(struct tda9887 *t, char *buf)
+static int tda9887_set_insmod(struct tuner *t, char *buf)
{
if (UNSET != port1) {
if (port1)
return 0;
}
-static int tda9887_set_config(struct tda9887 *t, char *buf)
+static int tda9887_set_config(struct tuner *t, char *buf)
{
- if (t->config & TDA9887_PORT1_ACTIVE)
+ if (t->tda9887_config & TDA9887_PORT1_ACTIVE)
buf[1] &= ~cOutputPort1Inactive;
- if (t->config & TDA9887_PORT1_INACTIVE)
+ if (t->tda9887_config & TDA9887_PORT1_INACTIVE)
buf[1] |= cOutputPort1Inactive;
- if (t->config & TDA9887_PORT2_ACTIVE)
+ if (t->tda9887_config & TDA9887_PORT2_ACTIVE)
buf[1] &= ~cOutputPort2Inactive;
- if (t->config & TDA9887_PORT2_INACTIVE)
+ if (t->tda9887_config & TDA9887_PORT2_INACTIVE)
buf[1] |= cOutputPort2Inactive;
- if (t->config & TDA9887_QSS)
+ if (t->tda9887_config & TDA9887_QSS)
buf[1] |= cQSS;
- if (t->config & TDA9887_INTERCARRIER)
+ if (t->tda9887_config & TDA9887_INTERCARRIER)
buf[1] &= ~cQSS;
- if (t->config & TDA9887_AUTOMUTE)
+ if (t->tda9887_config & TDA9887_AUTOMUTE)
buf[1] |= cAutoMuteFmActive;
- if (t->config & TDA9887_DEEMPHASIS_MASK) {
+ if (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
buf[2] &= ~0x60;
- switch (t->config & TDA9887_DEEMPHASIS_MASK) {
+ switch (t->tda9887_config & TDA9887_DEEMPHASIS_MASK) {
case TDA9887_DEEMPHASIS_NONE:
buf[2] |= cDeemphasisOFF;
break;
break;
}
}
- if (t->config & TDA9887_TOP_SET) {
+ if (t->tda9887_config & TDA9887_TOP_SET) {
buf[2] &= ~cTopMask;
- buf[2] |= (t->config >> 8) & cTopMask;
+ buf[2] |= (t->tda9887_config >> 8) & cTopMask;
}
- if ((t->config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
+ if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
buf[1] &= ~cQSS;
return 0;
}
/* ---------------------------------------------------------------------- */
-static char pal[] = "--";
-static char secam[] = "--";
-static char ntsc[] = "-";
-
-module_param_string(pal, pal, sizeof(pal), 0644);
-module_param_string(secam, secam, sizeof(secam), 0644);
-module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
-
-static int tda9887_fixup_std(struct tda9887 *t)
-{
- /* get more precise norm info from insmod option */
- if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
- switch (pal[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- case 'n':
- case 'N':
- if (pal[1] == 'c' || pal[1] == 'C') {
- tda9887_dbg("insmod fixup: PAL => PAL-Nc\n");
- t->std = V4L2_STD_PAL_Nc;
- } else {
- tda9887_dbg("insmod fixup: PAL => PAL-BGHN\n");
- t->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N;
- }
- break;
- case 'i':
- case 'I':
- tda9887_dbg("insmod fixup: PAL => PAL-I\n");
- t->std = V4L2_STD_PAL_I;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: PAL => PAL-DK\n");
- t->std = V4L2_STD_PAL_DK;
- break;
- case 'm':
- case 'M':
- tda9887_dbg("insmod fixup: PAL => PAL-M\n");
- t->std = V4L2_STD_PAL_M;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("pal= argument not recognised\n");
- break;
- }
- }
- if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
- switch (secam[0]) {
- case 'b':
- case 'B':
- case 'g':
- case 'G':
- case 'h':
- case 'H':
- tda9887_dbg("insmod fixup: SECAM => SECAM-BGH\n");
- t->std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
- break;
- case 'd':
- case 'D':
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: SECAM => SECAM-DK\n");
- t->std = V4L2_STD_SECAM_DK;
- break;
- case 'l':
- case 'L':
- if (secam[1] == 'c' || secam[1] == 'C') {
- tda9887_dbg("insmod fixup: SECAM => SECAM-L'\n");
- t->std = V4L2_STD_SECAM_LC;
- } else {
- tda9887_dbg("insmod fixup: SECAM => SECAM-L\n");
- t->std = V4L2_STD_SECAM_L;
- }
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("secam= argument not recognised\n");
- break;
- }
- }
- if ((t->std & V4L2_STD_NTSC) == V4L2_STD_NTSC) {
- switch (ntsc[0]) {
- case 'm':
- case 'M':
- tda9887_dbg("insmod fixup: NTSC => NTSC-M\n");
- t->std = V4L2_STD_NTSC_M;
- break;
- case 'j':
- case 'J':
- tda9887_dbg("insmod fixup: NTSC => NTSC_M_JP\n");
- t->std = V4L2_STD_NTSC_M_JP;
- break;
- case 'k':
- case 'K':
- tda9887_dbg("insmod fixup: NTSC => NTSC_M_KR\n");
- t->std = V4L2_STD_NTSC_M_KR;
- break;
- case '-':
- /* default parameter, do nothing */
- break;
- default:
- tda9887_info("ntsc= argument not recognised\n");
- break;
- }
- }
- return 0;
-}
-
-static int tda9887_status(struct tda9887 *t)
+static int tda9887_status(struct tuner *t)
{
unsigned char buf[1];
int rc;
memset(buf,0,sizeof(buf));
- if (1 != (rc = i2c_master_recv(&t->client,buf,1)))
+ if (1 != (rc = i2c_master_recv(&t->i2c,buf,1)))
tda9887_info("i2c i/o error: rc == %d (should be 1)\n",rc);
dump_read_message(t, buf);
return 0;
}
-static int tda9887_configure(struct tda9887 *t)
+static void tda9887_configure(struct i2c_client *client)
{
+ struct tuner *t = i2c_get_clientdata(client);
int rc;
- memset(t->data,0,sizeof(t->data));
- tda9887_set_tvnorm(t,t->data);
+ memset(t->tda9887_data,0,sizeof(t->tda9887_data));
+ tda9887_set_tvnorm(t,t->tda9887_data);
/* A note on the port settings:
These settings tend to depend on the specifics of the board.
the ports should be set to active (0), but, again, that may
differ depending on the precise hardware configuration.
*/
- t->data[1] |= cOutputPort1Inactive;
- t->data[1] |= cOutputPort2Inactive;
+ t->tda9887_data[1] |= cOutputPort1Inactive;
+ t->tda9887_data[1] |= cOutputPort2Inactive;
- tda9887_set_config(t,t->data);
- tda9887_set_insmod(t,t->data);
+ tda9887_set_config(t,t->tda9887_data);
+ tda9887_set_insmod(t,t->tda9887_data);
if (t->mode == T_STANDBY) {
- t->data[1] |= cForcedMuteAudioON;
+ t->tda9887_data[1] |= cForcedMuteAudioON;
}
tda9887_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n",
- t->data[1],t->data[2],t->data[3]);
- if (debug > 1)
- dump_write_message(t, t->data);
+ t->tda9887_data[1],t->tda9887_data[2],t->tda9887_data[3]);
+ if (tuner_debug > 1)
+ dump_write_message(t, t->tda9887_data);
- if (4 != (rc = i2c_master_send(&t->client,t->data,4)))
+ if (4 != (rc = i2c_master_send(&t->i2c,t->tda9887_data,4)))
tda9887_info("i2c i/o error: rc == %d (should be 4)\n",rc);
- if (debug > 2) {
+ if (tuner_debug > 2) {
msleep_interruptible(1000);
tda9887_status(t);
}
- return 0;
}
/* ---------------------------------------------------------------------- */
-static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
+static void tda9887_tuner_status(struct i2c_client *client)
{
- struct tda9887 *t;
-
- client_template.adapter = adap;
- client_template.addr = addr;
-
- if (NULL == (t = kzalloc(sizeof(*t), GFP_KERNEL)))
- return -ENOMEM;
-
- t->client = client_template;
- t->std = 0;
- t->radio_mode = V4L2_TUNER_MODE_STEREO;
-
- tda9887_info("chip found @ 0x%x (%s)\n", addr<<1, adap->name);
-
- i2c_set_clientdata(&t->client, t);
- i2c_attach_client(&t->client);
-
- return 0;
+ struct tuner *t = i2c_get_clientdata(client);
+ tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->tda9887_data[1], t->tda9887_data[2], t->tda9887_data[3]);
}
-static int tda9887_probe(struct i2c_adapter *adap)
+static int tda9887_get_afc(struct i2c_client *client)
{
- if (adap->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adap, &addr_data, tda9887_attach);
- return 0;
-}
+ struct tuner *t = i2c_get_clientdata(client);
+ static int AFC_BITS_2_kHz[] = {
+ -12500, -37500, -62500, -97500,
+ -112500, -137500, -162500, -187500,
+ 187500, 162500, 137500, 112500,
+ 97500 , 62500, 37500 , 12500
+ };
+ int afc=0;
+ __u8 reg = 0;
-static int tda9887_detach(struct i2c_client *client)
-{
- struct tda9887 *t = i2c_get_clientdata(client);
+ if (1 == i2c_master_recv(&t->i2c,®,1))
+ afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
- i2c_detach_client(client);
- kfree(t);
- return 0;
+ return afc;
}
-#define SWITCH_V4L2 if (!t->using_v4l2 && debug) \
- tda9887_info("switching to v4l2\n"); \
- t->using_v4l2 = 1;
-#define CHECK_V4L2 if (t->using_v4l2) { if (debug) \
- tda9887_info("ignore v4l1 call\n"); \
- return 0; }
-
-static int
-tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static void tda9887_standby(struct i2c_client *client)
{
- struct tda9887 *t = i2c_get_clientdata(client);
-
- switch (cmd) {
-
- /* --- configuration --- */
- case AUDC_SET_RADIO:
- {
- t->mode = T_RADIO;
- tda9887_configure(t);
- break;
- }
- case TUNER_SET_STANDBY:
- {
- t->mode = T_STANDBY;
- tda9887_configure(t);
- break;
- }
- case TDA9887_SET_CONFIG:
- {
- int *i = arg;
-
- t->config = *i;
- tda9887_configure(t);
- break;
- }
- /* --- v4l ioctls --- */
- /* take care: bttv does userspace copying, we'll get a
- kernel pointer here... */
- case VIDIOCSCHAN:
- {
- static const v4l2_std_id map[] = {
- [ VIDEO_MODE_PAL ] = V4L2_STD_PAL,
- [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M,
- [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
- [ 4 /* bttv */ ] = V4L2_STD_PAL_M,
- [ 5 /* bttv */ ] = V4L2_STD_PAL_N,
- [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
- };
- struct video_channel *vc = arg;
-
- CHECK_V4L2;
- t->mode = T_ANALOG_TV;
- if (vc->norm < ARRAY_SIZE(map))
- t->std = map[vc->norm];
- tda9887_fixup_std(t);
- tda9887_configure(t);
- break;
- }
- case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
-
- SWITCH_V4L2;
- t->mode = T_ANALOG_TV;
- t->std = *id;
- tda9887_fixup_std(t);
- tda9887_configure(t);
- break;
- }
- case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- SWITCH_V4L2;
- if (V4L2_TUNER_ANALOG_TV == f->type) {
- if (t->mode == T_ANALOG_TV)
- return 0;
- t->mode = T_ANALOG_TV;
- }
- if (V4L2_TUNER_RADIO == f->type) {
- if (t->mode == T_RADIO)
- return 0;
- t->mode = T_RADIO;
- }
- tda9887_configure(t);
- break;
- }
- case VIDIOC_G_TUNER:
- {
- static int AFC_BITS_2_kHz[] = {
- -12500, -37500, -62500, -97500,
- -112500, -137500, -162500, -187500,
- 187500, 162500, 137500, 112500,
- 97500 , 62500, 37500 , 12500
- };
- struct v4l2_tuner* tuner = arg;
-
- if (t->mode == T_RADIO) {
- __u8 reg = 0;
- tuner->afc=0;
- if (1 == i2c_master_recv(&t->client,®,1))
- tuner->afc = AFC_BITS_2_kHz[(reg>>1)&0x0f];
- }
- break;
- }
- case VIDIOC_S_TUNER:
- {
- struct v4l2_tuner* tuner = arg;
-
- if (t->mode == T_RADIO) {
- t->radio_mode = tuner->audmode;
- tda9887_configure (t);
- }
- break;
- }
- case VIDIOC_LOG_STATUS:
- {
- tda9887_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", t->data[1], t->data[2], t->data[3]);
- break;
- }
- default:
- /* nothing */
- break;
- }
- return 0;
+ tda9887_configure(client);
}
-static int tda9887_suspend(struct device * dev, pm_message_t state)
+static void tda9887_set_freq(struct i2c_client *client, unsigned int freq)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tda9887 *t = i2c_get_clientdata(c);
-
- tda9887_dbg("suspend\n");
- return 0;
+ tda9887_configure(client);
}
-static int tda9887_resume(struct device * dev)
+int tda9887_tuner_init(struct i2c_client *c)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tda9887 *t = i2c_get_clientdata(c);
+ struct tuner *t = i2c_get_clientdata(c);
- tda9887_dbg("resume\n");
- tda9887_configure(t);
- return 0;
-}
+ strlcpy(c->name, "tda9887", sizeof(c->name));
-/* ----------------------------------------------------------------------- */
-
-static struct i2c_driver driver = {
- .id = I2C_DRIVERID_TDA9887,
- .attach_adapter = tda9887_probe,
- .detach_client = tda9887_detach,
- .command = tda9887_command,
- .driver = {
- .name = "tda9887",
- .suspend = tda9887_suspend,
- .resume = tda9887_resume,
- },
-};
-static struct i2c_client client_template =
-{
- .name = "tda9887",
- .driver = &driver,
-};
+ tda9887_info("tda988[5/6/7] found @ 0x%x (%s)\n", t->i2c.addr,
+ t->i2c.driver->driver.name);
-static int __init tda9887_init_module(void)
-{
- return i2c_add_driver(&driver);
-}
+ t->set_tv_freq = tda9887_set_freq;
+ t->set_radio_freq = tda9887_set_freq;
+ t->standby = tda9887_standby;
+ t->tuner_status=tda9887_tuner_status;
+ t->get_afc=tda9887_get_afc;
-static void __exit tda9887_cleanup_module(void)
-{
- i2c_del_driver(&driver);
+ return 0;
}
-module_init(tda9887_init_module);
-module_exit(tda9887_cleanup_module);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
* I2C address is allways 0xC0.
*
*
- * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License
*
* tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
--- /dev/null
+/*
+ * tlv320aic23b - driver version 0.0.1
+ *
+ * Copyright (C) 2006 Scott Alfter <salfter@ssai.us>
+ *
+ * Based on wm8775 driver
+ *
+ * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to>
+ * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioctl.h>
+#include <asm/uaccess.h>
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/videodev.h>
+#include <media/v4l2-common.h>
+
+MODULE_DESCRIPTION("tlv320aic23b driver");
+MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static unsigned short normal_i2c[] = { 0x34 >> 1, I2C_CLIENT_END };
+
+
+I2C_CLIENT_INSMOD;
+
+/* ----------------------------------------------------------------------- */
+
+struct tlv320aic23b_state {
+ u8 muted;
+};
+
+static int tlv320aic23b_write(struct i2c_client *client, int reg, u16 val)
+{
+ int i;
+
+ if ((reg < 0 || reg > 9) && (reg != 15)) {
+ v4l_err(client, "Invalid register R%d\n", reg);
+ return -1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (i2c_smbus_write_byte_data(client, (reg << 1) |
+ (val >> 8), val & 0xff) == 0) {
+ return 0;
+ }
+ }
+ v4l_err(client, "I2C: cannot write %03x to register R%d\n", val, reg);
+ return -1;
+}
+
+static int tlv320aic23b_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ struct tlv320aic23b_state *state = i2c_get_clientdata(client);
+ struct v4l2_control *ctrl = arg;
+ u32* freq = arg;
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ switch (*freq) {
+ case 32000: /* set sample rate to 32 kHz */
+ tlv320aic23b_write(client, 8, 0x018);
+ break;
+ case 44100: /* set sample rate to 44.1 kHz */
+ tlv320aic23b_write(client, 8, 0x022);
+ break;
+ case 48000: /* set sample rate to 48 kHz */
+ tlv320aic23b_write(client, 8, 0x000);
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case VIDIOC_G_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ ctrl->value = state->muted;
+ break;
+
+ case VIDIOC_S_CTRL:
+ if (ctrl->id != V4L2_CID_AUDIO_MUTE)
+ return -EINVAL;
+ state->muted = ctrl->value;
+ tlv320aic23b_write(client, 0, 0x180); /* mute both channels */
+ /* set gain on both channels to +3.0 dB */
+ if (!state->muted)
+ tlv320aic23b_write(client, 0, 0x119);
+ break;
+
+ case VIDIOC_LOG_STATUS:
+ v4l_info(client, "Input: %s\n",
+ state->muted ? "muted" : "active");
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+static struct i2c_driver i2c_driver;
+
+static int tlv320aic23b_attach(struct i2c_adapter *adapter, int address, int kind)
+{
+ struct i2c_client *client;
+ struct tlv320aic23b_state *state;
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return 0;
+
+ client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
+ if (client == 0)
+ return -ENOMEM;
+
+ client->addr = address;
+ client->adapter = adapter;
+ client->driver = &i2c_driver;
+ snprintf(client->name, sizeof(client->name) - 1, "tlv320aic23b");
+
+ v4l_info(client, "chip found @ 0x%x (%s)\n", address << 1, adapter->name);
+
+ state = kmalloc(sizeof(struct tlv320aic23b_state), GFP_KERNEL);
+ if (state == NULL) {
+ kfree(client);
+ return -ENOMEM;
+ }
+ state->muted = 0;
+ i2c_set_clientdata(client, state);
+
+ /* initialize tlv320aic23b */
+ tlv320aic23b_write(client, 15, 0x000); /* RESET */
+ tlv320aic23b_write(client, 6, 0x00A); /* turn off DAC & mic input */
+ tlv320aic23b_write(client, 7, 0x049); /* left-justified, 24-bit, master mode */
+ tlv320aic23b_write(client, 0, 0x119); /* set gain on both channels to +3.0 dB */
+ tlv320aic23b_write(client, 8, 0x000); /* set sample rate to 48 kHz */
+ tlv320aic23b_write(client, 9, 0x001); /* activate digital interface */
+
+ i2c_attach_client(client);
+
+ return 0;
+}
+
+static int tlv320aic23b_probe(struct i2c_adapter *adapter)
+{
+ if (adapter->class & I2C_CLASS_TV_ANALOG)
+ return i2c_probe(adapter, &addr_data, tlv320aic23b_attach);
+ return 0;
+}
+
+static int tlv320aic23b_detach(struct i2c_client *client)
+{
+ int err;
+
+ err = i2c_detach_client(client);
+ if (err) {
+ return err;
+ }
+ kfree(client);
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+/* i2c implementation */
+static struct i2c_driver i2c_driver = {
+ .driver = {
+ .name = "tlv320aic23b",
+ },
+ .id = I2C_DRIVERID_TLV320AIC23B,
+ .attach_adapter = tlv320aic23b_probe,
+ .detach_client = tlv320aic23b_detach,
+ .command = tlv320aic23b_command,
+};
+
+
+static int __init tlv320aic23b_init_module(void)
+{
+ return i2c_add_driver(&i2c_driver);
+}
+
+static void __exit tlv320aic23b_cleanup_module(void)
+{
+ i2c_del_driver(&i2c_driver);
+}
+
+module_init(tlv320aic23b_init_module);
+module_exit(tlv320aic23b_cleanup_module);
#include <linux/i2c.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <media/tuner.h>
i2c_master_send(c, buffer, 4);
default_tuner_init(c);
break;
- case TUNER_LG_TDVS_H062F:
+ case TUNER_LG_TDVS_H06XF:
/* Set the Auxiliary Byte. */
buffer[2] &= ~0x20;
buffer[2] |= 0x18;
i2c_master_send(c,buffer,4);
default_tuner_init(c);
break;
+ case TUNER_TDA9887:
+ tda9887_tuner_init(c);
+ break;
default:
default_tuner_init(c);
break;
{
struct tuner *t = i2c_get_clientdata(c);
+ tuner_dbg("set addr for type %i\n", t->type);
+
if ( t->type == UNSET && ((tun_setup->addr == ADDR_UNSET &&
(t->mode_mask & tun_setup->mode_mask)) ||
tun_setup->addr == c->addr)) {
t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
t->audmode = V4L2_TUNER_MODE_STEREO;
t->mode_mask = T_UNINITIALIZED;
+ t->tuner_status = tuner_status;
if (tuner_debug_old) {
tuner_debug = tuner_debug_old;
printk(KERN_ERR "tuner: tuner_debug is deprecated and will be removed in 2.6.17.\n");
case 0x4b:
/* If chip is not tda8290, don't register.
since it can be tda9887*/
- if (tda8290_probe(&t->i2c) != 0) {
- tuner_dbg("chip at addr %x is not a tda8290\n", addr);
- kfree(t);
- return 0;
+ if (tda8290_probe(&t->i2c) == 0) {
+ tuner_dbg("chip at addr %x is a tda8290\n", addr);
+ } else {
+ /* Default is being tda9887 */
+ t->type = TUNER_TDA9887;
+ t->mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ t->mode = T_STANDBY;
+ goto register_client;
}
break;
case 0x60:
case TUNER_SET_STANDBY:
if (check_mode(t, "TUNER_SET_STANDBY") == EINVAL)
return 0;
+ t->mode = T_STANDBY;
if (t->standby)
t->standby (client);
break;
/* Should be implemented, since bttv calls it */
tuner_dbg("VIDIOCSAUDIO not implemented.\n");
break;
+ case TDA9887_SET_CONFIG:
+ {
+ int *i = arg;
+
+ t->tda9887_config = *i;
+ set_freq(client, t->tv_freq);
+ break;
+ }
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
switch_v4l2();
tuner->type = t->mode;
+ if (t->get_afc)
+ tuner->afc=t->get_afc(client);
if (t->mode == V4L2_TUNER_ANALOG_TV)
tuner->capability |= V4L2_TUNER_CAP_NORM;
if (t->mode != V4L2_TUNER_RADIO) {
break;
}
case VIDIOC_LOG_STATUS:
- tuner_status(client);
+ if (t->tuner_status)
+ t->tuner_status(client);
break;
}
switch (t->type) {
case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FM1256_IH3:
stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
break;
};
-/* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */
+/* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */
static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
{ 16 * 165.00 /*MHz*/, 0x8e, 0x01 },
};
-static struct tuner_params tuner_tua6034_params[] = {
+static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_tua6034_ntsc_ranges,
},
};
+/* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */
+
+static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = {
+ { 16 * 146.25 /*MHz*/, 0xce, 0x01, },
+ { 16 * 428.50 /*MHz*/, 0xce, 0x02, },
+ { 16 * 999.99 , 0xce, 0x08, },
+};
+
+static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges,
+ .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges),
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
.params = tuner_philips_fmd1216me_mk3_params,
.count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
},
- [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */
- .name = "LG TDVS-H062F/TUA6034",
- .params = tuner_tua6034_params,
- .count = ARRAY_SIZE(tuner_tua6034_params),
+ [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
+ .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */
+ .params = tuner_lg_tdvs_h06xf_params,
+ .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
},
[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
.name = "Ymec TVF66T5-B/DFF",
.params = tuner_thomson_fe6600_params,
.count = ARRAY_SIZE(tuner_thomson_fe6600_params),
},
+ [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
+ .name = "Samsung TCPG 6121P30A",
+ .params = tuner_samsung_tcpg_6121p30a_params,
+ .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params),
+ },
+ [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator.
+ This chip is part of some modern tuners */
+ .name = "Philips TDA988[5,6,7] IF PLL Demodulator",
+ /* see tda9887.c for details */
+ },
};
unsigned const int tuner_count = ARRAY_SIZE(tuners);
{ TUNER_ABSENT, "Philips FQ1286A MK4"},
{ TUNER_ABSENT, "Philips FQ1216ME MK5"},
{ TUNER_ABSENT, "Philips FQ1236 MK5"},
- { TUNER_ABSENT, "Samsung TCPG_6121P30A"},
+ { TUNER_SAMSUNG_TCPG_6121P30A, "Samsung TCPG 6121P30A"},
{ TUNER_TCL_2002MB, "TCL 2002MB_3H"},
{ TUNER_ABSENT, "TCL 2002MI_3H"},
{ TUNER_TCL_2002N, "TCL 2002N 5H"},
/* lock bttv in memory while the mixer is in use */
file->private_data = mix;
-#ifndef I2C_PEC
- if (client->adapter->inc_use)
- client->adapter->inc_use(client->adapter);
-#endif
if (client->adapter->owner)
try_module_get(client->adapter->owner);
return 0;
return -ENODEV;
}
-#ifndef I2C_PEC
- if (client->adapter->dec_use)
- client->adapter->dec_use(client->adapter);
-#endif
if (client->adapter->owner)
module_put(client->adapter->owner);
return 0;
#include <linux/delay.h>
#include <linux/video_decoder.h>
#include <media/v4l2-common.h>
+#include <media/tvp5150.h>
#include "tvp5150_reg.h"
struct i2c_client *client;
v4l2_std_id norm; /* Current set standard */
- int input;
+ struct v4l2_routing route;
int enable;
int bright;
int contrast;
/****************************************************************************
Basic functions
****************************************************************************/
-enum tvp5150_input {
- TVP5150_ANALOG_CH0 = 0,
- TVP5150_SVIDEO = 1,
- TVP5150_ANALOG_CH1 = 2,
- TVP5150_BLACK_SCREEN = 8
-};
-static inline void tvp5150_selmux(struct i2c_client *c,
- enum tvp5150_input input)
+static inline void tvp5150_selmux(struct i2c_client *c)
{
int opmode=0;
-
struct tvp5150 *decoder = i2c_get_clientdata(c);
+ int input = 0;
- if (!decoder->enable)
- input |= TVP5150_BLACK_SCREEN;
+ if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
+ input = 8;
switch (input) {
- case TVP5150_ANALOG_CH0:
- case TVP5150_ANALOG_CH1:
+ case TVP5150_COMPOSITE1:
+ input |= 2;
+ /* fall through */
+ case TVP5150_COMPOSITE0:
opmode=0x30; /* TV Mode */
break;
+ case TVP5150_SVIDEO:
default:
+ input |= 1;
opmode=0; /* Auto Mode */
break;
}
tvp5150_vdp_init(c, vbi_ram_default);
/* Selects decoder input */
- tvp5150_selmux(c, decoder->input);
+ tvp5150_selmux(c);
/* Initializes TVP5150 to stream enabled values */
tvp5150_write_inittab(c, tvp5150_init_enable);
case VIDIOC_INT_RESET:
tvp5150_reset(c);
break;
+ case VIDIOC_INT_G_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *route = arg;
+
+ *route = decoder->route;
+ break;
+ }
+ case VIDIOC_INT_S_VIDEO_ROUTING:
+ {
+ struct v4l2_routing *route = arg;
+
+ decoder->route = *route;
+ tvp5150_selmux(c);
+ break;
+ }
case VIDIOC_S_STD:
if (decoder->norm == *(v4l2_std_id *)arg)
break;
rv = i2c_attach_client(c);
core->norm = V4L2_STD_ALL; /* Default is autodetect */
- core->input = 2;
+ core->route.input = TVP5150_COMPOSITE1;
core->enable = 1;
core->bright = 32768;
core->contrast = 32768;
To compile this driver as a module, choose M here: the
module will be called konicawc.
+
+config USB_QUICKCAM_MESSENGER
+ tristate "USB Logitech Quickcam Messenger"
+ depends on USB && VIDEO_DEV
+ select VIDEO_USBVIDEO
+ ---help---
+ Say Y or M here to enable support for the USB Logitech Quickcam
+ Messenger webcam.
+
+ To compile this driver as a module, choose M here: the
+ module will be called quickcam_messenger.
+
obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
obj-$(CONFIG_USB_KONICAWC) += konicawc.o
obj-$(CONFIG_USB_VICAM) += vicam.o
+obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += quickcam_messenger.o
--- /dev/null
+/*
+ * Driver for Logitech Quickcam Messenger usb video camera
+ * Copyright (C) Jaya Kumar
+ *
+ * This work was sponsored by CIS(M) Sdn Bhd.
+ * History:
+ * 05/08/2006 - Jaya Kumar
+ * I wrote this based on the konicawc by Simon Evans.
+ * -
+ * Full credit for reverse engineering and creating an initial
+ * working linux driver for the VV6422 goes to the qce-ga project by
+ * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
+ * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
+ * others.
+ * ---
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/usb_input.h>
+
+#include "usbvideo.h"
+#include "quickcam_messenger.h"
+
+/*
+ * Version Information
+ */
+
+#ifdef CONFIG_USB_DEBUG
+static int debug;
+#define DEBUG(n, format, arg...) \
+ if (n <= debug) { \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ }
+#else
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define DRIVER_VERSION "v0.01"
+#define DRIVER_DESC "Logitech Quickcam Messenger USB"
+
+#define USB_LOGITECH_VENDOR_ID 0x046D
+#define USB_QCM_PRODUCT_ID 0x08F0
+
+#define MAX_CAMERAS 1
+
+#define MAX_COLOUR 32768
+#define MAX_HUE 32768
+#define MAX_BRIGHTNESS 32768
+#define MAX_CONTRAST 32768
+#define MAX_WHITENESS 32768
+
+static int size = SIZE_320X240;
+static int colour = MAX_COLOUR;
+static int hue = MAX_HUE;
+static int brightness = MAX_BRIGHTNESS;
+static int contrast = MAX_CONTRAST;
+static int whiteness = MAX_WHITENESS;
+
+static struct usbvideo *cams;
+
+static struct usb_device_id qcm_table [] = {
+ { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(usb, qcm_table);
+
+#ifdef CONFIG_INPUT
+static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
+{
+ struct input_dev *input_dev;
+
+ usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
+ strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
+
+ cam->input = input_dev = input_allocate_device();
+ if (!input_dev) {
+ warn("insufficient mem for cam input device");
+ return;
+ }
+
+ input_dev->name = "QCM button";
+ input_dev->phys = cam->input_physname;
+ usb_to_input_id(dev, &input_dev->id);
+ input_dev->cdev.dev = &dev->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY);
+ input_dev->keybit[LONG(BTN_0)] = BIT(BTN_0);
+
+ input_dev->private = cam;
+
+ input_register_device(cam->input);
+}
+
+static void qcm_unregister_input(struct qcm *cam)
+{
+ if (cam->input) {
+ input_unregister_device(cam->input);
+ cam->input = NULL;
+ }
+}
+
+static void qcm_report_buttonstat(struct qcm *cam)
+{
+ if (cam->input) {
+ input_report_key(cam->input, BTN_0, cam->button_sts);
+ input_sync(cam->input);
+ }
+}
+
+static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
+{
+ int ret;
+ struct uvd *uvd = urb->context;
+ struct qcm *cam;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return;
+
+ if (!uvd->streaming)
+ return;
+
+ uvd->stats.urb_count++;
+
+ if (urb->status < 0)
+ uvd->stats.iso_err_count++;
+ else {
+ if (urb->actual_length > 0 ) {
+ cam = (struct qcm *) uvd->user_data;
+ if (cam->button_sts_buf == 0x88)
+ cam->button_sts = 0x0;
+ else if (cam->button_sts_buf == 0x80)
+ cam->button_sts = 0x1;
+ qcm_report_buttonstat(cam);
+ }
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0)
+ err("usb_submit_urb error (%d)", ret);
+}
+
+static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
+{
+ int errflag;
+ usb_fill_int_urb(cam->button_urb, uvd->dev,
+ usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
+ &cam->button_sts_buf,
+ 1,
+ qcm_int_irq,
+ uvd, 16);
+
+ errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
+ if (errflag)
+ err ("usb_submit_int ret %d", errflag);
+ return errflag;
+}
+
+static void qcm_stop_int_data(struct qcm *cam)
+{
+ usb_kill_urb(cam->button_urb);
+}
+
+static int qcm_alloc_int_urb(struct qcm *cam)
+{
+ cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!cam->button_urb)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void qcm_free_int(struct qcm *cam)
+{
+ if (cam->button_urb)
+ usb_free_urb(cam->button_urb);
+}
+#endif /* CONFIG_INPUT */
+
+static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ reg, 0, &val, 1, 3*HZ);
+ return ret;
+}
+
+static int qcm_stv_setw(struct usb_device *dev, u16 reg, u16 val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+ reg, 0, &val, 2, 3*HZ);
+ return ret;
+}
+
+static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
+ __le16 *val)
+{
+ int ret;
+
+ /* we'll wait up to 3 slices but no more */
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
+ reg, 0, val, 2, 3*HZ);
+ return ret;
+}
+
+static int qcm_camera_on(struct uvd *uvd)
+{
+ int ret;
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
+ return 0;
+}
+
+static int qcm_camera_off(struct uvd *uvd)
+{
+ int ret;
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+ return 0;
+}
+
+static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
+{
+ unsigned int segment, valsat;
+ signed int h = (signed int) hue;
+ unsigned int s = (sat - 32768) * 2; /* rescale */
+ unsigned int v = val;
+ unsigned int p;
+
+ /*
+ the registers controling gain are 8 bit of which
+ we affect only the last 4 bits with our gain.
+ we know that if saturation is 0, (unsaturated) then
+ we're grayscale (center axis of the colour cone) so
+ we set rgb=value. we use a formula obtained from
+ wikipedia to map the cone to the RGB plane. it's
+ as follows for the human value case of h=0..360,
+ s=0..1, v=0..1
+ h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
+ q = v(1 - f*s) , t = v(1 - (1-f)s)
+ h_i==0 => r=v , g=t, b=p
+ h_i==1 => r=q , g=v, b=p
+ h_i==2 => r=p , g=v, b=t
+ h_i==3 => r=p , g=q, b=v
+ h_i==4 => r=t , g=p, b=v
+ h_i==5 => r=v , g=p, b=q
+ the bottom side (the point) and the stuff just up
+ of that is black so we simplify those two cases.
+ */
+ if (sat < 32768) {
+ /* anything less than this is unsaturated */
+ *r = val;
+ *g = val;
+ *b = val;
+ return;
+ }
+ if (val <= (0xFFFF/8)) {
+ /* anything less than this is black */
+ *r = 0;
+ *g = 0;
+ *b = 0;
+ return;
+ }
+
+ /* the rest of this code is copying tukkat's
+ implementation of the hsv2rgb conversion as taken
+ from qc-usb-messenger code. the 10923 is 0xFFFF/6
+ to divide the cone into 6 sectors. */
+
+ segment = (h + 10923) & 0xFFFF;
+ segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */
+ hue -= segment * 21845; /* -10923..10923 */
+ h = hue;
+ h *= 3;
+ valsat = v*s >> 16; /* 0..65534 */
+ p = v - valsat;
+ if (h >= 0) {
+ unsigned int t = v - (valsat * (32769 - h) >> 15);
+ switch (segment) {
+ case 0: /* R-> */
+ *r = v;
+ *g = t;
+ *b = p;
+ break;
+ case 1: /* G-> */
+ *r = p;
+ *g = v;
+ *b = t;
+ break;
+ case 2: /* B-> */
+ *r = t;
+ *g = p;
+ *b = v;
+ break;
+ }
+ } else {
+ unsigned int q = v - (valsat * (32769 + h) >> 15);
+ switch (segment) {
+ case 0: /* ->R */
+ *r = v;
+ *g = p;
+ *b = q;
+ break;
+ case 1: /* ->G */
+ *r = q;
+ *g = v;
+ *b = p;
+ break;
+ case 2: /* ->B */
+ *r = p;
+ *g = q;
+ *b = v;
+ break;
+ }
+ }
+}
+
+static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
+ u16 saturation, u16 value)
+{
+ int ret;
+ u16 r=0,g=0,b=0;
+
+ /* this code is based on qc-usb-messenger */
+ qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
+
+ r >>= 12;
+ g >>= 12;
+ b >>= 12;
+
+ /* min val is 8 */
+ r = max((u16) 8, r);
+ g = max((u16) 8, g);
+ b = max((u16) 8, b);
+
+ r |= 0x30;
+ g |= 0x30;
+ b |= 0x30;
+
+ /* set the r,g,b gain registers */
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
+
+ /* doing as qc-usb did */
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+ return 0;
+}
+
+static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
+{
+ int ret;
+ int formedval;
+
+ /* calculation was from qc-usb-messenger driver */
+ formedval = ( exposure >> 12 );
+
+ /* max value for formedval is 14 */
+ formedval = min(formedval, 14);
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+ 0x143A, 0xF0 | formedval));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+ return 0;
+}
+
+static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
+ int hue, int colour)
+{
+ int ret;
+ /* brightness is exposure, contrast is gain, colour is saturation */
+ CHECK_RET(ret,
+ qcm_sensor_set_exposure(uvd, brightness));
+ CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
+
+ return 0;
+}
+
+static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
+{
+ int ret;
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
+ return 0;
+}
+
+static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
+{
+ int ret;
+ /* some rescaling as done by the qc-usb-messenger code */
+ if (whiteness > 0xC000)
+ whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
+ (whiteness >> 8) & 0xFF));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
+ (whiteness >> 16) & 0x03));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
+
+ return 0;
+}
+
+static int qcm_sensor_init(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int ret;
+ int i;
+
+ for (i=0; i < sizeof(regval_table)/sizeof(regval_table[0]) ; i++) {
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev,
+ regval_table[i].reg,
+ regval_table[i].val));
+ }
+
+ CHECK_RET(ret, qcm_stv_setw(uvd->dev, 0x15c1,
+ cpu_to_le16(ISOC_PACKET_SIZE)));
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x15c3, 0x08));
+ CHECK_RET(ret, ret = qcm_stv_setb(uvd->dev, 0x143f, 0x01));
+
+ CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
+
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+ CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
+ uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
+
+ CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+
+ return 0;
+}
+
+static int qcm_set_camera_size(struct uvd *uvd)
+{
+ int ret;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
+ cam->width = camera_sizes[cam->size].width;
+ cam->height = camera_sizes[cam->size].height;
+ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+
+ return 0;
+}
+
+static int qcm_setup_on_open(struct uvd *uvd)
+{
+ int ret;
+
+ CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
+ uvd->vpic.colour, uvd->vpic.contrast));
+ CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
+ CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
+ CHECK_RET(ret, qcm_set_camera_size(uvd));
+ CHECK_RET(ret, qcm_camera_on(uvd));
+ return 0;
+}
+
+static void qcm_adjust_picture(struct uvd *uvd)
+{
+ int ret;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ ret = qcm_camera_off(uvd);
+ if (ret) {
+ err("can't turn camera off. abandoning pic adjustment");
+ return;
+ }
+
+ /* if there's been a change in contrast, hue, or
+ colour then we need to recalculate hsv in order
+ to update gains */
+ if ((cam->contrast != uvd->vpic.contrast) ||
+ (cam->hue != uvd->vpic.hue) ||
+ (cam->colour != uvd->vpic.colour)) {
+ cam->contrast = uvd->vpic.contrast;
+ cam->hue = uvd->vpic.hue;
+ cam->colour = uvd->vpic.colour;
+ ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
+ cam->contrast);
+ if (ret) {
+ err("can't set gains. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ if (cam->brightness != uvd->vpic.brightness) {
+ cam->brightness = uvd->vpic.brightness;
+ ret = qcm_sensor_set_exposure(uvd, cam->brightness);
+ if (ret) {
+ err("can't set exposure. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ if (cam->whiteness != uvd->vpic.whiteness) {
+ cam->whiteness = uvd->vpic.whiteness;
+ qcm_sensor_set_shutter(uvd, cam->whiteness);
+ if (ret) {
+ err("can't set shutter. abandoning pic adjustment");
+ return;
+ }
+ }
+
+ ret = qcm_camera_on(uvd);
+ if (ret) {
+ err("can't reenable camera. pic adjustment failed");
+ return;
+ }
+}
+
+static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
+{
+ int datalen;
+ int totaldata;
+ struct framehdr {
+ __be16 id;
+ __be16 len;
+ };
+ struct framehdr *fhdr;
+
+ totaldata = 0;
+ while (framelen) {
+ fhdr = (struct framehdr *) cdata;
+ datalen = be16_to_cpu(fhdr->len);
+ framelen -= 4;
+ cdata += 4;
+
+ if ((fhdr->id) == cpu_to_be16(0x8001)) {
+ RingQueue_Enqueue(&uvd->dp, marker, 4);
+ totaldata += 4;
+ continue;
+ }
+ if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
+ RingQueue_Enqueue(&uvd->dp, cdata, datalen);
+ totaldata += datalen;
+ }
+ framelen -= datalen;
+ cdata += datalen;
+ }
+ return totaldata;
+}
+
+static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
+{
+ int totlen;
+ int i;
+ unsigned char *cdata;
+
+ totlen=0;
+ for (i = 0; i < dataurb->number_of_packets; i++) {
+ int n = dataurb->iso_frame_desc[i].actual_length;
+ int st = dataurb->iso_frame_desc[i].status;
+
+ cdata = dataurb->transfer_buffer +
+ dataurb->iso_frame_desc[i].offset;
+
+ if (st < 0) {
+ warn("Data error: packet=%d. len=%d. status=%d.",
+ i, n, st);
+ uvd->stats.iso_err_count++;
+ continue;
+ }
+ if (!n)
+ continue;
+
+ totlen += qcm_process_frame(uvd, cdata, n);
+ }
+ return totlen;
+}
+
+static void resubmit_urb(struct uvd *uvd, struct urb *urb)
+{
+ int ret;
+
+ urb->dev = uvd->dev;
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ err("usb_submit_urb error (%d)", ret);
+}
+
+static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
+{
+ int len;
+ struct uvd *uvd = urb->context;
+
+ if (!CAMERA_IS_OPERATIONAL(uvd))
+ return;
+
+ if (!uvd->streaming)
+ return;
+
+ uvd->stats.urb_count++;
+
+ if (!urb->actual_length) {
+ resubmit_urb(uvd, urb);
+ return;
+ }
+
+ len = qcm_compress_iso(uvd, urb);
+ resubmit_urb(uvd, urb);
+ uvd->stats.urb_length = len;
+ uvd->stats.data_count += len;
+ if (len)
+ RingQueue_WakeUpInterruptible(&uvd->dp);
+}
+
+static int qcm_start_data(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int i;
+ int errflag;
+ int pktsz;
+ int err;
+
+ pktsz = uvd->iso_packet_len;
+ if (!CAMERA_IS_OPERATIONAL(uvd)) {
+ err("Camera is not operational");
+ return -EFAULT;
+ }
+
+ err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
+ if (err < 0) {
+ err("usb_set_interface error");
+ uvd->last_error = err;
+ return -EBUSY;
+ }
+
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ int j, k;
+ struct urb *urb = uvd->sbuf[i].urb;
+ urb->dev = uvd->dev;
+ urb->context = uvd;
+ urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
+ urb->interval = 1;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->transfer_buffer = uvd->sbuf[i].data;
+ urb->complete = qcm_isoc_irq;
+ urb->number_of_packets = FRAMES_PER_DESC;
+ urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
+ for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length = pktsz;
+ }
+ }
+
+ uvd->streaming = 1;
+ uvd->curframe = -1;
+ for (i=0; i < USBVIDEO_NUMSBUF; i++) {
+ errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
+ if (errflag)
+ err ("usb_submit_isoc(%d) ret %d", i, errflag);
+ }
+
+ CHECK_RET(err, qcm_setup_input_int(cam, uvd));
+ CHECK_RET(err, qcm_camera_on(uvd));
+ return 0;
+}
+
+static void qcm_stop_data(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int i, j;
+ int ret;
+
+ if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
+ return;
+
+ ret = qcm_camera_off(uvd);
+ if (ret)
+ warn("couldn't turn the cam off.");
+
+ uvd->streaming = 0;
+
+ /* Unschedule all of the iso td's */
+ for (i=0; i < USBVIDEO_NUMSBUF; i++)
+ usb_kill_urb(uvd->sbuf[i].urb);
+
+ qcm_stop_int_data(cam);
+
+ if (!uvd->remove_pending) {
+ /* Set packet size to 0 */
+ j = usb_set_interface(uvd->dev, uvd->iface,
+ uvd->ifaceAltInactive);
+ if (j < 0) {
+ err("usb_set_interface() error %d.", j);
+ uvd->last_error = j;
+ }
+ }
+}
+
+static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+ int x;
+ struct rgb *rgbL0;
+ struct rgb *rgbL1;
+ struct bayL0 *bayL0;
+ struct bayL1 *bayL1;
+ int hor,ver,hordel,verdel;
+ assert(frame != NULL);
+
+ switch (cam->size) {
+ case SIZE_160X120:
+ hor = 162; ver = 124; hordel = 1; verdel = 2;
+ break;
+ case SIZE_320X240:
+ default:
+ hor = 324; ver = 248; hordel = 2; verdel = 4;
+ break;
+ }
+
+ if (frame->scanstate == ScanState_Scanning) {
+ while (RingQueue_GetLength(&uvd->dp) >=
+ 4 + (hor*verdel + hordel)) {
+ if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
+ (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
+ frame->curline = 0;
+ frame->scanstate = ScanState_Lines;
+ frame->frameState = FrameState_Grabbing;
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
+ /*
+ * if we're starting, we need to discard the first
+ * 4 lines of y bayer data
+ * and the first 2 gr elements of x bayer data
+ */
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
+ (hor*verdel + hordel));
+ break;
+ }
+ RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
+ }
+ }
+
+ if (frame->scanstate == ScanState_Scanning)
+ return;
+
+ /* now we can start processing bayer data so long as we have at least
+ * 2 lines worth of data. this is the simplest demosaicing method that
+ * I could think of. I use each 2x2 bayer element without interpolation
+ * to generate 4 rgb pixels.
+ */
+ while ( frame->curline < cam->height &&
+ (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
+ /* get 2 lines of bayer for demosaicing
+ * into 2 lines of RGB */
+ RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
+ bayL0 = (struct bayL0 *) cam->scratch;
+ bayL1 = (struct bayL1 *) (cam->scratch + hor);
+ /* frame->curline is the rgb y line */
+ rgbL0 = (struct rgb *)
+ ( frame->data + (cam->width*3*frame->curline));
+ /* w/2 because we're already doing 2 pixels */
+ rgbL1 = rgbL0 + (cam->width/2);
+
+ for (x=0; x < cam->width; x+=2) {
+ rgbL0->r = bayL0->r;
+ rgbL0->g = bayL0->g;
+ rgbL0->b = bayL1->b;
+
+ rgbL0->r2 = bayL0->r;
+ rgbL0->g2 = bayL1->g;
+ rgbL0->b2 = bayL1->b;
+
+ rgbL1->r = bayL0->r;
+ rgbL1->g = bayL1->g;
+ rgbL1->b = bayL1->b;
+
+ rgbL1->r2 = bayL0->r;
+ rgbL1->g2 = bayL1->g;
+ rgbL1->b2 = bayL1->b;
+
+ rgbL0++;
+ rgbL1++;
+
+ bayL0++;
+ bayL1++;
+ }
+
+ frame->seqRead_Length += cam->width*3*2;
+ frame->curline += 2;
+ }
+ /* See if we filled the frame */
+ if (frame->curline == cam->height) {
+ frame->frameState = FrameState_Done_Hold;
+ frame->curline = 0;
+ uvd->curframe = -1;
+ uvd->stats.frame_num++;
+ }
+}
+
+/* taken from konicawc */
+static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
+{
+ int ret;
+ int newsize;
+ int oldsize;
+ int x = vw->width;
+ int y = vw->height;
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ if (x > 0 && y > 0) {
+ DEBUG(2, "trying to find size %d,%d", x, y);
+ for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
+ if ((camera_sizes[newsize].width == x) &&
+ (camera_sizes[newsize].height == y))
+ break;
+ }
+ } else
+ newsize = cam->size;
+
+ if (newsize > MAX_FRAME_SIZE) {
+ DEBUG(1, "couldn't find size %d,%d", x, y);
+ return -EINVAL;
+ }
+
+ if (newsize == cam->size) {
+ DEBUG(1, "Nothing to do");
+ return 0;
+ }
+
+ qcm_stop_data(uvd);
+
+ if (cam->size != newsize) {
+ oldsize = cam->size;
+ cam->size = newsize;
+ ret = qcm_set_camera_size(uvd);
+ if (ret) {
+ err("Couldn't set camera size, err=%d",ret);
+ /* restore the original size */
+ cam->size = oldsize;
+ return ret;
+ }
+ }
+
+ /* Flush the input queue and clear any current frame in progress */
+
+ RingQueue_Flush(&uvd->dp);
+ if (uvd->curframe != -1) {
+ uvd->frame[uvd->curframe].curline = 0;
+ uvd->frame[uvd->curframe].seqRead_Length = 0;
+ uvd->frame[uvd->curframe].seqRead_Index = 0;
+ }
+
+ CHECK_RET(ret, qcm_start_data(uvd));
+ return 0;
+}
+
+static int qcm_configure_video(struct uvd *uvd)
+{
+ int ret;
+ memset(&uvd->vpic, 0, sizeof(uvd->vpic));
+ memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
+
+ uvd->vpic.colour = colour;
+ uvd->vpic.hue = hue;
+ uvd->vpic.brightness = brightness;
+ uvd->vpic.contrast = contrast;
+ uvd->vpic.whiteness = whiteness;
+ uvd->vpic.depth = 24;
+ uvd->vpic.palette = VIDEO_PALETTE_RGB24;
+
+ memset(&uvd->vcap, 0, sizeof(uvd->vcap));
+ strcpy(uvd->vcap.name, "QCM USB Camera");
+ uvd->vcap.type = VID_TYPE_CAPTURE;
+ uvd->vcap.channels = 1;
+ uvd->vcap.audios = 0;
+
+ uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
+ uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
+ uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
+ uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
+
+ memset(&uvd->vchan, 0, sizeof(uvd->vchan));
+ uvd->vchan.flags = 0 ;
+ uvd->vchan.tuners = 0;
+ uvd->vchan.channel = 0;
+ uvd->vchan.type = VIDEO_TYPE_CAMERA;
+ strcpy(uvd->vchan.name, "Camera");
+
+ CHECK_RET(ret, qcm_sensor_init(uvd));
+ return 0;
+}
+
+static int qcm_probe(struct usb_interface *intf,
+ const struct usb_device_id *devid)
+{
+ int err;
+ struct uvd *uvd;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct qcm *cam;
+ size_t buffer_size;
+ unsigned char video_ep;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ int i,j;
+ unsigned int ifacenum, ifacenum_inact=0;
+ __le16 sensor_id;
+
+ /* we don't support multiconfig cams */
+ if (dev->descriptor.bNumConfigurations != 1)
+ return -ENODEV;
+
+ /* first check for the video interface and not
+ * the audio interface */
+ interface = &intf->cur_altsetting[0];
+ if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
+ || (interface->desc.bInterfaceSubClass !=
+ USB_CLASS_VENDOR_SPEC))
+ return -ENODEV;
+
+ /*
+ walk through each endpoint in each setting in the interface
+ stop when we find the one that's an isochronous IN endpoint.
+ */
+ for (i=0; i < intf->num_altsetting; i++) {
+ interface = &intf->cur_altsetting[i];
+ ifacenum = interface->desc.bAlternateSetting;
+ /* walk the end points */
+ for (j=0; j < interface->desc.bNumEndpoints; j++) {
+ endpoint = &interface->endpoint[j].desc;
+
+ if ((endpoint->bEndpointAddress &
+ USB_ENDPOINT_DIR_MASK) != USB_DIR_IN)
+ continue; /* not input then not good */
+
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ if (!buffer_size) {
+ ifacenum_inact = ifacenum;
+ continue; /* 0 pkt size is not what we want */
+ }
+
+ if ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_ISOC) {
+ video_ep = endpoint->bEndpointAddress;
+ /* break out of the search */
+ goto good_videoep;
+ }
+ }
+ }
+ /* failed out since nothing useful was found */
+ err("No suitable endpoint was found\n");
+ return -ENODEV;
+
+good_videoep:
+ /* disable isochronous stream before doing anything else */
+ err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
+ if (err < 0) {
+ err("Failed to disable sensor stream");
+ return -EIO;
+ }
+
+ /*
+ Check that this is the same unknown sensor that is known to work. This
+ sensor is suspected to be the ST VV6422C001. I'll check the same value
+ that the qc-usb driver checks. This value is probably not even the
+ sensor ID since it matches the USB dev ID. Oh well. If it doesn't
+ match, it's probably a diff sensor so exit and apologize.
+ */
+ err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
+ if (err < 0) {
+ err("Couldn't read sensor values. Err %d\n",err);
+ return err;
+ }
+ if (sensor_id != cpu_to_le16(0x08F0)) {
+ err("Sensor ID %x != %x. Unsupported. Sorry\n",
+ le16_to_cpu(sensor_id), (0x08F0));
+ return -ENODEV;
+ }
+
+ uvd = usbvideo_AllocateDevice(cams);
+ if (!uvd)
+ return -ENOMEM;
+
+ cam = (struct qcm *) uvd->user_data;
+
+ /* buf for doing demosaicing */
+ cam->scratch = kmalloc(324*2, GFP_KERNEL);
+ if (!cam->scratch) /* uvd freed in dereg */
+ return -ENOMEM;
+
+ /* yes, if we fail after here, cam->scratch gets freed
+ by qcm_free_uvd */
+
+ err = qcm_alloc_int_urb(cam);
+ if (err < 0)
+ return err;
+
+ /* yes, if we fail after here, int urb gets freed
+ by qcm_free_uvd */
+
+ RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
+ cam->width = camera_sizes[size].width;
+ cam->height = camera_sizes[size].height;
+ cam->size = size;
+
+ uvd->debug = debug;
+ uvd->flags = 0;
+ uvd->dev = dev;
+ uvd->iface = intf->altsetting->desc.bInterfaceNumber;
+ uvd->ifaceAltActive = ifacenum;
+ uvd->ifaceAltInactive = ifacenum_inact;
+ uvd->video_endp = video_ep;
+ uvd->iso_packet_len = buffer_size;
+ uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
+ uvd->defaultPalette = VIDEO_PALETTE_RGB24;
+ uvd->canvas = VIDEOSIZE(320, 240);
+ uvd->videosize = VIDEOSIZE(cam->width, cam->height);
+ err = qcm_configure_video(uvd);
+ if (err) {
+ err("failed to configure video settings");
+ return err;
+ }
+
+ err = usbvideo_RegisterVideoDevice(uvd);
+ if (err) { /* the uvd gets freed in Deregister */
+ err("usbvideo_RegisterVideoDevice() failed.");
+ return err;
+ }
+
+ uvd->max_frame_size = (320 * 240 * 3);
+ qcm_register_input(cam, dev);
+ usb_set_intfdata(intf, uvd);
+ return 0;
+}
+
+static void qcm_free_uvd(struct uvd *uvd)
+{
+ struct qcm *cam = (struct qcm *) uvd->user_data;
+
+ kfree(cam->scratch);
+ qcm_unregister_input(cam);
+ qcm_free_int(cam);
+}
+
+static struct usbvideo_cb qcm_driver = {
+ .probe = qcm_probe,
+ .setupOnOpen = qcm_setup_on_open,
+ .processData = qcm_process_isoc,
+ .setVideoMode = qcm_set_video_mode,
+ .startDataPump = qcm_start_data,
+ .stopDataPump = qcm_stop_data,
+ .adjustPicture = qcm_adjust_picture,
+ .userFree = qcm_free_uvd
+};
+
+static int __init qcm_init(void)
+{
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ return usbvideo_register(
+ &cams,
+ MAX_CAMERAS,
+ sizeof(struct qcm),
+ "QCM",
+ &qcm_driver,
+ THIS_MODULE,
+ qcm_table);
+}
+
+static void __exit qcm_exit(void)
+{
+ usbvideo_Deregister(&cams);
+}
+
+module_param(size, int, 0);
+MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
+module_param(colour, int, 0);
+MODULE_PARM_DESC(colour, "Initial colour");
+module_param(hue, int, 0);
+MODULE_PARM_DESC(hue, "Initial hue");
+module_param(brightness, int, 0);
+MODULE_PARM_DESC(brightness, "Initial brightness");
+module_param(contrast, int, 0);
+MODULE_PARM_DESC(contrast, "Initial contrast");
+module_param(whiteness, int, 0);
+MODULE_PARM_DESC(whiteness, "Initial whiteness");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
+#endif
+
+module_init(qcm_init);
+module_exit(qcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jaya Kumar");
+MODULE_DESCRIPTION("QCM USB Camera");
+MODULE_SUPPORTED_DEVICE("QCM USB Camera");
--- /dev/null
+#ifndef quickcam_messenger_h
+#define quickcam_messenger_h
+
+#ifndef CONFIG_INPUT
+/* if we're not using input we dummy out these functions */
+#define qcm_register_input(...)
+#define qcm_unregister_input(...)
+#define qcm_report_buttonstat(...)
+#define qcm_setup_input_int(...) 0
+#define qcm_stop_int_data(...)
+#define qcm_alloc_int_urb(...) 0
+#define qcm_free_int(...)
+#endif
+
+
+#define CHECK_RET(ret, expr) \
+ if ((ret = expr) < 0) return ret
+
+/* Control Registers for the STVV6422 ASIC
+ * - this define is taken from the qc-usb-messenger code
+ */
+#define STV_ISO_ENABLE 0x1440
+#define ISOC_PACKET_SIZE 1023
+
+/* Chip identification number including revision indicator */
+#define CMOS_SENSOR_IDREV 0xE00A
+
+struct rgb {
+ u8 b;
+ u8 g;
+ u8 r;
+ u8 b2;
+ u8 g2;
+ u8 r2;
+};
+
+struct bayL0 {
+#ifdef __BIG_ENDIAN
+ u8 r;
+ u8 g;
+#elif __LITTLE_ENDIAN
+ u8 g;
+ u8 r;
+#else
+#error not byte order defined
+#endif
+};
+
+struct bayL1 {
+#ifdef __BIG_ENDIAN
+ u8 g;
+ u8 b;
+#elif __LITTLE_ENDIAN
+ u8 b;
+ u8 g;
+#else
+#error not byte order defined
+#endif
+};
+
+struct cam_size {
+ u16 width;
+ u16 height;
+ u8 cmd;
+};
+
+static const struct cam_size camera_sizes[] = {
+ { 160, 120, 0xf },
+ { 320, 240, 0x2 },
+};
+
+enum frame_sizes {
+ SIZE_160X120 = 0,
+ SIZE_320X240 = 1,
+};
+
+#define MAX_FRAME_SIZE SIZE_320X240
+
+struct qcm {
+ u16 colour;
+ u16 hue;
+ u16 brightness;
+ u16 contrast;
+ u16 whiteness;
+
+ u8 size;
+ int height;
+ int width;
+ u8 *scratch;
+ struct urb *button_urb;
+ u8 button_sts;
+ u8 button_sts_buf;
+
+#ifdef CONFIG_INPUT
+ struct input_dev *input;
+ char input_physname[64];
+#endif
+};
+
+struct regval {
+ u16 reg;
+ u8 val;
+};
+/* this table is derived from the
+qc-usb-messenger code */
+static const struct regval regval_table[] = {
+ { STV_ISO_ENABLE, 0x00 },
+ { 0x1436, 0x00 }, { 0x1432, 0x03 },
+ { 0x143a, 0xF9 }, { 0x0509, 0x38 },
+ { 0x050a, 0x38 }, { 0x050b, 0x38 },
+ { 0x050c, 0x2A }, { 0x050d, 0x01 },
+ { 0x1431, 0x00 }, { 0x1433, 0x34 },
+ { 0x1438, 0x18 }, { 0x1439, 0x00 },
+ { 0x143b, 0x05 }, { 0x143c, 0x00 },
+ { 0x143e, 0x01 }, { 0x143d, 0x00 },
+ { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
+ { 0x1500, 0xd0 }, { 0x1500, 0x50 },
+ { 0x1501, 0xaf }, { 0x1502, 0xc2 },
+ { 0x1503, 0x45 }, { 0x1505, 0x02 },
+ { 0x150e, 0x8e }, { 0x150f, 0x37 },
+ { 0x15c0, 0x00 },
+};
+
+static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
+
+#endif /* quickcam_messenger_h */
#include <linux/config.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/div64.h>
#include <linux/video_decoder.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#ifdef CONFIG_KMOD
#if 1
[_IOC_NR(VIDIOC_G_SLICED_VBI_CAP)] = "VIDIOC_G_SLICED_VBI_CAP",
#endif
- [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS"
+ [_IOC_NR(VIDIOC_LOG_STATUS)] = "VIDIOC_LOG_STATUS",
+ [_IOC_NR(VIDIOC_G_EXT_CTRLS)] = "VIDIOC_G_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_S_EXT_CTRLS)] = "VIDIOC_S_EXT_CTRLS",
+ [_IOC_NR(VIDIOC_TRY_EXT_CTRLS)] = "VIDIOC_TRY_EXT_CTRLS"
};
#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
[_IOC_NR(VIDIOC_INT_S_AUDIO_ROUTING)] = "VIDIOC_INT_S_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_G_AUDIO_ROUTING)] = "VIDIOC_INT_G_AUDIO_ROUTING",
[_IOC_NR(VIDIOC_INT_S_VIDEO_ROUTING)] = "VIDIOC_INT_S_VIDEO_ROUTING",
- [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING"
+ [_IOC_NR(VIDIOC_INT_G_VIDEO_ROUTING)] = "VIDIOC_INT_G_VIDEO_ROUTING",
+ [_IOC_NR(VIDIOC_INT_S_CRYSTAL_FREQ)] = "VIDIOC_INT_S_CRYSTAL_FREQ"
};
#define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls)
case TUNER_SET_TYPE_ADDR:
case TUNER_SET_STANDBY:
case TDA9887_SET_CONFIG:
+#ifdef __OLD_VIDIOC_
case VIDIOC_OVERLAY_OLD:
+#endif
case VIDIOC_STREAMOFF:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_G_AUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_ENUMAUDIO:
+#ifdef __OLD_VIDIOC_
case VIDIOC_G_AUDIO_OLD:
+#endif
{
struct v4l2_audio *p=arg;
case VIDIOC_G_AUDOUT:
case VIDIOC_S_AUDOUT:
case VIDIOC_ENUMAUDOUT:
+#ifdef __OLD_VIDIOC_
case VIDIOC_G_AUDOUT_OLD:
+#endif
{
struct v4l2_audioout *p=arg;
printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s,
prt_names(p->memory,v4l2_memory_names),
p->m.userptr);
printk ("%s: timecode= %02d:%02d:%02d type=%d, "
- "flags=0x%08x, frames=%d, userbits=0x%p\n",
+ "flags=0x%08x, frames=%d, userbits=0x%08x\n",
s,tc->hours,tc->minutes,tc->seconds,
- tc->type, tc->flags, tc->frames, tc->userbits);
+ tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
break;
}
case VIDIOC_QUERYCAP:
}
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
+#ifdef __OLD_VIDIOC_
case VIDIOC_S_CTRL_OLD:
+#endif
{
struct v4l2_control *p=arg;
printk ("%s: id=%d, value=%d\n", s, p->id, p->value);
break;
}
+ case VIDIOC_G_EXT_CTRLS:
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+ int i;
+
+ printk("%s: ctrl_class=%d, count=%d\n", s, p->ctrl_class, p->count);
+ for (i = 0; i < p->count; i++) {
+ struct v4l2_ext_control *c = &p->controls[i];
+ if (cmd == VIDIOC_G_EXT_CTRLS)
+ printk("%s: id=%d\n", s, c->id);
+ else
+ printk("%s: id=%d, value=%d\n", s, c->id, c->value);
+ }
+ break;
+ }
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
{
break;
}
case VIDIOC_CROPCAP:
+#ifdef __OLD_VIDIOC_
case VIDIOC_CROPCAP_OLD:
+#endif
{
struct v4l2_cropcap *p=arg;
/*FIXME: Should also show rect structs */
printk ("%s: input=0x%x, output=0x%x\n", s, p->input, p->output);
break;
}
+ case VIDIOC_INT_S_CRYSTAL_FREQ:
+ {
+ struct v4l2_crystal_freq *p=arg;
+ printk ("%s: freq=%u, flags=0x%x\n", s, p->freq, p->flags);
+ break;
+ }
case VIDIOC_G_SLICED_VBI_CAP:
{
struct v4l2_sliced_vbi_cap *p=arg;
}
case VIDIOC_G_PARM:
case VIDIOC_S_PARM:
+#ifdef __OLD_VIDIOC_
case VIDIOC_S_PARM_OLD:
+#endif
{
struct v4l2_streamparm *p=arg;
printk ("%s: type=%d\n", s, p->type);
/* ----------------------------------------------------------------- */
+/* Helper functions for control handling */
+
+/* Check for correctness of the ctrl's value based on the data from
+ struct v4l2_queryctrl and the available menu items. Note that
+ menu_items may be NULL, in that case it is ignored. */
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char **menu_items)
+{
+ if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+ if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+ qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return 0;
+ if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+ return -ERANGE;
+ if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+ if (menu_items[ctrl->value] == NULL ||
+ menu_items[ctrl->value][0] == '\0')
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Returns NULL or a character pointer array containing the menu for
+ the given control ID. The pointer array ends with a NULL pointer.
+ An empty string signifies a menu entry that is invalid. This allows
+ drivers to disable certain options if it is not supported. */
+const char **v4l2_ctrl_get_menu(u32 id)
+{
+ static const char *mpeg_audio_sampling_freq[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz",
+ NULL
+ };
+ static const char *mpeg_audio_encoding[] = {
+ "Layer I",
+ "Layer II",
+ "Layer III",
+ NULL
+ };
+ static const char *mpeg_audio_l1_bitrate[] = {
+ "32 kbps",
+ "64 kbps",
+ "96 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "288 kbps",
+ "320 kbps",
+ "352 kbps",
+ "384 kbps",
+ "416 kbps",
+ "448 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l2_bitrate[] = {
+ "32 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_l3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ NULL
+ };
+ static const char *mpeg_audio_mode[] = {
+ "Stereo",
+ "Joint Stereo",
+ "Dual",
+ "Mono",
+ NULL
+ };
+ static const char *mpeg_audio_mode_extension[] = {
+ "Bound 4",
+ "Bound 8",
+ "Bound 12",
+ "Bound 16",
+ NULL
+ };
+ static const char *mpeg_audio_emphasis[] = {
+ "No Emphasis",
+ "50/15 us",
+ "CCITT J17",
+ NULL
+ };
+ static const char *mpeg_audio_crc[] = {
+ "No CRC",
+ "16-bit CRC",
+ NULL
+ };
+ static const char *mpeg_video_encoding[] = {
+ "MPEG-1",
+ "MPEG-2",
+ NULL
+ };
+ static const char *mpeg_video_aspect[] = {
+ "1x1",
+ "4x3",
+ "16x9",
+ "2.21x1",
+ NULL
+ };
+ static const char *mpeg_video_bitrate_mode[] = {
+ "Variable Bitrate",
+ "Constant Bitrate",
+ NULL
+ };
+ static const char *mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return mpeg_audio_sampling_freq;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return mpeg_audio_encoding;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return mpeg_audio_l1_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return mpeg_audio_l2_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return mpeg_audio_mode;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return mpeg_audio_mode_extension;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return mpeg_audio_emphasis;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return mpeg_audio_crc;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return mpeg_video_encoding;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return mpeg_video_aspect;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return mpeg_video_bitrate_mode;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return mpeg_stream_type;
+ default:
+ return NULL;
+ }
+}
+
+/* Fill in a struct v4l2_queryctrl */
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
+{
+ const char *name;
+
+ qctrl->flags = 0;
+ switch (qctrl->id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS: name = "User Controls"; break;
+ case V4L2_CID_AUDIO_VOLUME: name = "Volume"; break;
+ case V4L2_CID_AUDIO_MUTE: name = "Mute"; break;
+ case V4L2_CID_AUDIO_BALANCE: name = "Balance"; break;
+ case V4L2_CID_AUDIO_BASS: name = "Bass"; break;
+ case V4L2_CID_AUDIO_TREBLE: name = "Treble"; break;
+ case V4L2_CID_AUDIO_LOUDNESS: name = "Loudness"; break;
+ case V4L2_CID_BRIGHTNESS: name = "Brightness"; break;
+ case V4L2_CID_CONTRAST: name = "Contrast"; break;
+ case V4L2_CID_SATURATION: name = "Saturation"; break;
+ case V4L2_CID_HUE: name = "Hue"; break;
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_CLASS: name = "MPEG Encoder Controls"; break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break;
+ case V4L2_CID_MPEG_AUDIO_ENCODING: name = "Audio Encoding Layer"; break;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: name = "Audio Layer I Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: name = "Audio Layer II Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: name = "Audio Layer III Bitrate"; break;
+ case V4L2_CID_MPEG_AUDIO_MODE: name = "Audio Stereo Mode"; break;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break;
+ case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: name = "Video GOP Size"; break;
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: name = "Video GOP Closure"; break;
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: name = "Video Pulldown"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: name = "Video Bitrate Mode"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break;
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break;
+ case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break;
+ case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: name = "Stream Video Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break;
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break;
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break;
+
+ default:
+ return -EINVAL;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
+ min = 0;
+ max = step = 1;
+ break;
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ qctrl->type = V4L2_CTRL_TYPE_MENU;
+ step = 1;
+ break;
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ min = max = step = def = 0;
+ break;
+ default:
+ qctrl->type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (qctrl->id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ }
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ snprintf(qctrl->name, sizeof(qctrl->name), name);
+ return 0;
+}
+
+/* Fill in a struct v4l2_queryctrl with standard values based on
+ the control ID. */
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl)
+{
+ switch (qctrl->id) {
+ /* USER controls */
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 58880);
+ case V4L2_CID_AUDIO_MUTE:
+ case V4L2_CID_AUDIO_LOUDNESS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 65535, 65535 / 100, 32768);
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 127, 1, 64);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(qctrl, -128, 127, 1, 0);
+
+ /* MPEG controls */
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L1_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L1_BITRATE_448K, 1,
+ V4L2_MPEG_AUDIO_L1_BITRATE_256K);
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L2_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_L3_BITRATE_32K,
+ V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1,
+ V4L2_MPEG_AUDIO_L3_BITRATE_192K);
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_STEREO,
+ V4L2_MPEG_AUDIO_MODE_MONO, 1,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_AUDIO_CRC_NONE,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 1,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 1,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(qctrl, 0, 33, 1, 2);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(qctrl, 1, 34, 1, 12);
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN:
+ return v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 0);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 1,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 6000000);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ return v4l2_ctrl_query_fill(qctrl, 0, 27000000, 1, 8000000);
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(qctrl,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, 1,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ case V4L2_CID_MPEG_STREAM_PID_PMT:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 16);
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 260);
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 256);
+ case V4L2_CID_MPEG_STREAM_PID_PCR:
+ return v4l2_ctrl_query_fill(qctrl, 0, (1 << 14) - 1, 1, 259);
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO:
+ return v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 0);
+ default:
+ return -EINVAL;
+ }
+}
+
+/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
+ the menu. The qctrl pointer may be NULL, in which case it is ignored. */
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
+ const char **menu_items)
+{
+ int i;
+
+ if (menu_items == NULL ||
+ (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
+ return -EINVAL;
+ for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
+ if (menu_items[i] == NULL || menu_items[i][0] == '\0')
+ return -EINVAL;
+ snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]);
+ qmenu->reserved = 0;
+ return 0;
+}
+
+/* ctrl_classes points to an array of u32 pointers, the last element is
+ a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
+ Each array must be sorted low to high and belong to the same control
+ class. The array of u32 pointer must also be sorted, from low class IDs
+ to high class IDs.
+
+ This function returns the first ID that follows after the given ID.
+ When no more controls are available 0 is returned. */
+u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
+{
+ u32 ctrl_class;
+ const u32 *pctrl;
+
+ /* if no query is desired, then just return the control ID */
+ if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0)
+ return id;
+ if (ctrl_classes == NULL)
+ return 0;
+ id &= V4L2_CTRL_ID_MASK;
+ ctrl_class = V4L2_CTRL_ID2CLASS(id);
+ id++; /* select next control */
+ /* find first class that matches (or is greater than) the class of
+ the ID */
+ while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
+ ctrl_classes++;
+ /* no more classes */
+ if (*ctrl_classes == NULL)
+ return 0;
+ pctrl = *ctrl_classes;
+ /* find first ctrl within the class that is >= ID */
+ while (*pctrl && *pctrl < id) pctrl++;
+ if (*pctrl)
+ return *pctrl;
+ /* we are at the end of the controls of the current class. */
+ /* continue with next class if available */
+ ctrl_classes++;
+ if (*ctrl_classes == NULL)
+ return 0;
+ return **ctrl_classes;
+}
+
+/* ----------------------------------------------------------------- */
+
EXPORT_SYMBOL(v4l2_video_std_construct);
EXPORT_SYMBOL(v4l2_prio_init);
EXPORT_SYMBOL(v4l_printk_ioctl);
EXPORT_SYMBOL(v4l_printk_ioctl_arg);
+EXPORT_SYMBOL(v4l2_ctrl_next);
+EXPORT_SYMBOL(v4l2_ctrl_check);
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_menu);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill);
+EXPORT_SYMBOL(v4l2_ctrl_query_fill_std);
+
/*
* Local variables:
* c-basic-offset: 8
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
- void *adapter_priv)
+ void *adapter_priv,
+ struct device *device)
{
int result;
mutex_init(&dvb->lock);
/* register adapter */
- result = dvb_register_adapter(&dvb->adapter, dvb->name, module);
+ result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
dvb->name, result);
/*
- * Video capture interface for Linux
+ * Video capture interface for Linux version 2
*
- * A generic video device interface for the LINUX operating system
- * using a set of device structures/vectors for low level operations.
+ * A generic video device interface for the LINUX operating system
+ * using a set of device structures/vectors for low level operations.
*
- * 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 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.
*
- * Author: Alan Cox, <alan@redhat.com>
+ * Authors: Alan Cox, <alan@redhat.com> (version 1)
+ * Mauro Carvalho Chehab <mchehab@infradead.org> (version 2)
*
* Fixes: 20000516 Claudio Matsuoka <claudio@conectiva.com>
* - Added procfs support
*/
+#define dbgarg(cmd, fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk (KERN_DEBUG "%s: ", vfd->name); \
+ v4l_printk_ioctl(cmd); \
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
+#define dbgarg2(fmt, arg...) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#define __OLD_VIDIOC_ /* To allow fixing old calls*/
+#include <linux/videodev2.h>
+
+#ifdef CONFIG_VIDEO_V4L1
#include <linux/videodev.h>
+#endif
+#include <media/v4l2-common.h>
#define VIDEO_NUM_DEVICES 256
#define VIDEO_NAME "video4linux"
static ssize_t show_name(struct class_device *cd, char *buf)
{
- struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
return sprintf(buf,"%.*s\n",(int)sizeof(vfd->name),vfd->name);
}
static void video_release(struct class_device *cd)
{
- struct video_device *vfd = container_of(cd, struct video_device, class_dev);
+ struct video_device *vfd = container_of(cd, struct video_device,
+ class_dev);
#if 1
/* needed until all drivers are fixed */
}
/*
- * Open a video device.
+ * Open a video device - FIXME: Obsoleted
*/
static int video_open(struct inode *inode, struct file *file)
{
* helper function -- handles userspace copying for ioctl arguments
*/
+#ifdef __OLD_VIDIOC_
static unsigned int
video_fix_command(unsigned int cmd)
{
}
return cmd;
}
+#endif
+/*
+ * Obsolete usercopy function - Should be removed soon
+ */
int
video_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+#ifdef __OLD_VIDIOC_
cmd = video_fix_command(cmd);
+#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
goto out;
break;
}
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ /* In case of an error, tell the caller that it wasn't
+ a specific control that caused it. */
+ p->error_idx = p->count;
+ user_ptr = (void __user *)p->controls;
+ if (p->count) {
+ ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+ /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+ mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_ext_ctrl;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, ctrls_size))
+ goto out_ext_ctrl;
+ p->controls = mbuf;
+ }
+ }
/* call driver */
err = func(inode, file, cmd, parg);
if (err == -ENOIOCTLCMD)
err = -EINVAL;
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ p->controls = (void *)user_ptr;
+ if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ err = -EFAULT;
+ goto out_ext_ctrl;
+ }
if (err < 0)
goto out;
+out_ext_ctrl:
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
/*
* open/release helper functions -- handle exclusive opens
+ * Should be removed soon
*/
int video_exclusive_open(struct inode *inode, struct file *file)
{
return 0;
}
+static char *v4l2_memory_names[] = {
+ [V4L2_MEMORY_MMAP] = "mmap",
+ [V4L2_MEMORY_USERPTR] = "userptr",
+ [V4L2_MEMORY_OVERLAY] = "overlay",
+};
+
+
+/* FIXME: Those stuff are replicated also on v4l2-common.c */
+static char *v4l2_type_names_FIXME[] = {
+ [V4L2_BUF_TYPE_VIDEO_CAPTURE] = "video-cap",
+ [V4L2_BUF_TYPE_VIDEO_OVERLAY] = "video-over",
+ [V4L2_BUF_TYPE_VIDEO_OUTPUT] = "video-out",
+ [V4L2_BUF_TYPE_VBI_CAPTURE] = "vbi-cap",
+ [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_OUTPUT] = "sliced-vbi-out",
+ [V4L2_BUF_TYPE_SLICED_VBI_CAPTURE] = "sliced-vbi-capture",
+ [V4L2_BUF_TYPE_PRIVATE] = "private",
+};
+
+static char *v4l2_field_names_FIXME[] = {
+ [V4L2_FIELD_ANY] = "any",
+ [V4L2_FIELD_NONE] = "none",
+ [V4L2_FIELD_TOP] = "top",
+ [V4L2_FIELD_BOTTOM] = "bottom",
+ [V4L2_FIELD_INTERLACED] = "interlaced",
+ [V4L2_FIELD_SEQ_TB] = "seq-tb",
+ [V4L2_FIELD_SEQ_BT] = "seq-bt",
+ [V4L2_FIELD_ALTERNATE] = "alternate",
+};
+
+#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown"
+
+static void dbgbuf(unsigned int cmd, struct video_device *vfd,
+ struct v4l2_buffer *p)
+{
+ struct v4l2_timecode *tc=&p->timecode;
+
+ dbgarg (cmd, "%02ld:%02d:%02d.%08ld index=%d, type=%s, "
+ "bytesused=%d, flags=0x%08d, "
+ "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n",
+ (p->timestamp.tv_sec/3600),
+ (int)(p->timestamp.tv_sec/60)%60,
+ (int)(p->timestamp.tv_sec%60),
+ p->timestamp.tv_usec,
+ p->index,
+ prt_names(p->type,v4l2_type_names_FIXME),
+ p->bytesused,p->flags,
+ p->field,p->sequence,
+ prt_names(p->memory,v4l2_memory_names),
+ p->m.userptr);
+ dbgarg2 ("timecode= %02d:%02d:%02d type=%d, "
+ "flags=0x%08d, frames=%d, userbits=0x%08x\n",
+ tc->hours,tc->minutes,tc->seconds,
+ tc->type, tc->flags, tc->frames, *(__u32 *) tc->userbits);
+}
+
+static inline void dbgrect(struct video_device *vfd, char *s,
+ struct v4l2_rect *r)
+{
+ dbgarg2 ("%sRect start at %dx%d, size= %dx%d\n", s, r->left, r->top,
+ r->width, r->height);
+};
+
+static inline void v4l_print_pix_fmt (struct video_device *vfd,
+ struct v4l2_pix_format *fmt)
+{
+ dbgarg2 ("width=%d, height=%d, format=0x%08x, field=%s, "
+ "bytesperline=%d sizeimage=%d, colorspace=%d\n",
+ fmt->width,fmt->height,fmt->pixelformat,
+ prt_names(fmt->field,v4l2_field_names_FIXME),
+ fmt->bytesperline,fmt->sizeimage,fmt->colorspace);
+};
+
+
+static int check_fmt (struct video_device *vfd, enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_try_fmt_cap)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_try_fmt_overlay)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_capture)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_video_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ return (0);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_try_fmt_type_private)
+ return (0);
+ break;
+ }
+ return (-EINVAL);
+}
+
+static int __video_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct video_device *vfd = video_devdata(file);
+ void *fh = file->private_data;
+ int ret = -EINVAL;
+
+ if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
+ !(vfd->debug | V4L2_DEBUG_IOCTL_ARG)) {
+ v4l_print_ioctl(vfd->name, cmd);
+ }
+
+ switch(cmd) {
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = (struct v4l2_capability*)arg;
+ memset(cap, 0, sizeof(*cap));
+
+ if (!vfd->vidioc_querycap)
+ break;
+
+ ret=vfd->vidioc_querycap(file, fh, cap);
+ if (!ret)
+ dbgarg (cmd, "driver=%s, card=%s, bus=%s, "
+ "version=0x%08x, "
+ "capabilities=0x%08x\n",
+ cap->driver,cap->card,cap->bus_info,
+ cap->version,
+ cap->capabilities);
+ break;
+ }
+
+ /* --- priority ------------------------------------------ */
+ case VIDIOC_G_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+
+ if (!vfd->vidioc_g_priority)
+ break;
+ ret=vfd->vidioc_g_priority(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "priority is %d\n", *p);
+ break;
+ }
+ case VIDIOC_S_PRIORITY:
+ {
+ enum v4l2_priority *p=arg;
+
+ if (!vfd->vidioc_s_priority)
+ break;
+ dbgarg(cmd, "setting priority to %d\n", *p);
+ ret=vfd->vidioc_s_priority(file, fh, *p);
+ break;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ enum v4l2_buf_type type;
+ unsigned int index;
+
+ index = f->index;
+ type = f->type;
+ memset(f,0,sizeof(*f));
+ f->index = index;
+ f->type = type;
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_enum_fmt_cap)
+ ret=vfd->vidioc_enum_fmt_cap(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_enum_fmt_overlay)
+ ret=vfd->vidioc_enum_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_enum_fmt_vbi)
+ ret=vfd->vidioc_enum_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_enum_fmt_vbi_output)
+ ret=vfd->vidioc_enum_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_enum_fmt_vbi_capture)
+ ret=vfd->vidioc_enum_fmt_vbi_capture(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_enum_fmt_video_output)
+ ret=vfd->vidioc_enum_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_enum_fmt_vbi_output)
+ ret=vfd->vidioc_enum_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_enum_fmt_type_private)
+ ret=vfd->vidioc_enum_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+ if (!ret)
+ dbgarg (cmd, "index=%d, type=%d, flags=%d, "
+ "description=%s,"
+ " pixelformat=0x%8x\n",
+ f->index, f->type, f->flags,
+ f->description,
+ f->pixelformat);
+
+ break;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+ enum v4l2_buf_type type=f->type;
+
+ memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
+ f->type=type;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(type,
+ v4l2_type_names_FIXME));
+
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_g_fmt_cap)
+ ret=vfd->vidioc_g_fmt_cap(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_g_fmt_overlay)
+ ret=vfd->vidioc_g_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi)
+ ret=vfd->vidioc_g_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_vbi_output)
+ ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_g_fmt_vbi_capture)
+ ret=vfd->vidioc_g_fmt_vbi_capture(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_g_fmt_video_output)
+ ret=vfd->vidioc_g_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_g_fmt_vbi_output)
+ ret=vfd->vidioc_g_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_g_fmt_type_private)
+ ret=vfd->vidioc_g_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+
+ break;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(f->type,
+ v4l2_type_names_FIXME));
+
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ if (vfd->vidioc_s_fmt_cap)
+ ret=vfd->vidioc_s_fmt_cap(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_s_fmt_overlay)
+ ret=vfd->vidioc_s_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi)
+ ret=vfd->vidioc_s_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_vbi_output)
+ ret=vfd->vidioc_s_fmt_vbi_output(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_s_fmt_vbi_capture)
+ ret=vfd->vidioc_s_fmt_vbi_capture(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_s_fmt_video_output)
+ ret=vfd->vidioc_s_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_s_fmt_vbi_output)
+ ret=vfd->vidioc_s_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_s_fmt_type_private)
+ ret=vfd->vidioc_s_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+ break;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = (struct v4l2_format *)arg;
+
+ /* FIXME: Should be one dump per type */
+ dbgarg (cmd, "type=%s\n", prt_names(f->type,
+ v4l2_type_names_FIXME));
+ switch (f->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ if (vfd->vidioc_try_fmt_cap)
+ ret=vfd->vidioc_try_fmt_cap(file, fh, f);
+ if (!ret)
+ v4l_print_pix_fmt(vfd,&f->fmt.pix);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OVERLAY:
+ if (vfd->vidioc_try_fmt_overlay)
+ ret=vfd->vidioc_try_fmt_overlay(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi)
+ ret=vfd->vidioc_try_fmt_vbi(file, fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ ret=vfd->vidioc_try_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (vfd->vidioc_try_fmt_vbi_capture)
+ ret=vfd->vidioc_try_fmt_vbi_capture(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (vfd->vidioc_try_fmt_video_output)
+ ret=vfd->vidioc_try_fmt_video_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (vfd->vidioc_try_fmt_vbi_output)
+ ret=vfd->vidioc_try_fmt_vbi_output(file,
+ fh, f);
+ break;
+ case V4L2_BUF_TYPE_PRIVATE:
+ if (vfd->vidioc_try_fmt_type_private)
+ ret=vfd->vidioc_try_fmt_type_private(file,
+ fh, f);
+ break;
+ }
+
+ break;
+ }
+ /* FIXME: Those buf reqs could be handled here,
+ with some changes on videobuf to allow its header to be included at
+ videodev2.h or being merged at videodev2.
+ */
+ case VIDIOC_REQBUFS:
+ {
+ struct v4l2_requestbuffers *p=arg;
+
+ if (!vfd->vidioc_reqbufs)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_reqbufs(file, fh, p);
+ dbgarg (cmd, "count=%d, type=%s, memory=%s\n",
+ p->count,
+ prt_names(p->type,v4l2_type_names_FIXME),
+ prt_names(p->memory,v4l2_memory_names));
+ break;
+ }
+ case VIDIOC_QUERYBUF:
+ {
+ struct v4l2_buffer *p=arg;
+
+ if (!vfd->vidioc_querybuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_querybuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_QBUF:
+ {
+ struct v4l2_buffer *p=arg;
+
+ if (!vfd->vidioc_qbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_qbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_DQBUF:
+ {
+ struct v4l2_buffer *p=arg;
+ if (!vfd->vidioc_qbuf)
+ break;
+ ret = check_fmt (vfd, p->type);
+ if (ret)
+ break;
+
+ ret=vfd->vidioc_qbuf(file, fh, p);
+ if (!ret)
+ dbgbuf(cmd,vfd,p);
+ break;
+ }
+ case VIDIOC_OVERLAY:
+ {
+ int *i = arg;
+
+ if (!vfd->vidioc_overlay)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_overlay(file, fh, *i);
+ break;
+ }
+#ifdef HAVE_V4L1
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOCGMBUF:
+ {
+ struct video_mbuf *p=arg;
+
+ memset(p,0,sizeof(p));
+
+ if (!vfd->vidiocgmbuf)
+ break;
+ ret=vfd->vidiocgmbuf(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
+ p->size, p->frames,
+ (unsigned long)p->offsets);
+ break;
+ }
+#endif
+ case VIDIOC_G_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ if (!vfd->vidioc_g_fbuf)
+ break;
+ ret=vfd->vidioc_g_fbuf(file, fh, arg);
+ if (!ret) {
+ dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+ p->capability,p->flags,
+ (unsigned long)p->base);
+ v4l_print_pix_fmt (vfd, &p->fmt);
+ }
+ break;
+ }
+ case VIDIOC_S_FBUF:
+ {
+ struct v4l2_framebuffer *p=arg;
+ if (!vfd->vidioc_s_fbuf)
+ break;
+
+ dbgarg (cmd, "capability=%d, flags=%d, base=0x%08lx\n",
+ p->capability,p->flags,(unsigned long)p->base);
+ v4l_print_pix_fmt (vfd, &p->fmt);
+ ret=vfd->vidioc_s_fbuf(file, fh, arg);
+
+ break;
+ }
+ case VIDIOC_STREAMON:
+ {
+ enum v4l2_buf_type i = *(int *)arg;
+ if (!vfd->vidioc_streamon)
+ break;
+ dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ ret=vfd->vidioc_streamon(file, fh,i);
+ break;
+ }
+ case VIDIOC_STREAMOFF:
+ {
+ enum v4l2_buf_type i = *(int *)arg;
+
+ if (!vfd->vidioc_streamoff)
+ break;
+ dbgarg (cmd, "type=%s\n", prt_names(i,v4l2_type_names_FIXME));
+ ret=vfd->vidioc_streamoff(file, fh, i);
+ break;
+ }
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *p = arg;
+ unsigned int index = p->index;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ if (index<=0 || index >= vfd->tvnormsize) {
+ ret=-EINVAL;
+ break;
+ }
+ v4l2_video_std_construct(p, vfd->tvnorms[p->index].id,
+ vfd->tvnorms[p->index].name);
+ p->index = index;
+
+ dbgarg (cmd, "index=%d, id=%Ld, name=%s, fps=%d/%d, "
+ "framelines=%d\n", p->index,
+ (unsigned long long)p->id, p->name,
+ p->frameperiod.numerator,
+ p->frameperiod.denominator,
+ p->framelines);
+
+ ret=0;
+ break;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = vfd->current_norm;
+
+ dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+ ret=0;
+ break;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ dbgarg (cmd, "value=%Lu\n", (long long unsigned) *id);
+
+ /* First search for exact match */
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (*id == vfd->tvnorms[i].id)
+ break;
+ /* Then for a generic video std that contains desired std */
+ if (i == vfd->tvnormsize)
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (*id & vfd->tvnorms[i].id)
+ break;
+ if (i == vfd->tvnormsize) {
+ break;
+ }
+
+ /* Calls the specific handler */
+ if (vfd->vidioc_s_std)
+ ret=vfd->vidioc_s_std(file, fh, i);
+ else
+ ret=-EINVAL;
+
+ /* Updates standard information */
+ if (!ret)
+ vfd->current_norm=*id;
+
+ break;
+ }
+ case VIDIOC_QUERYSTD:
+ {
+ v4l2_std_id *p=arg;
+
+ if (!vfd->vidioc_querystd)
+ break;
+ ret=vfd->vidioc_querystd(file, fh, arg);
+ if (!ret)
+ dbgarg (cmd, "detected std=%Lu\n",
+ (unsigned long long)*p);
+ break;
+ }
+ /* ------ input switching ---------- */
+ /* FIXME: Inputs can be handled inside videodev2 */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct v4l2_input *p=arg;
+ int i=p->index;
+
+ if (!vfd->vidioc_enum_input)
+ break;
+ memset(p, 0, sizeof(*p));
+ p->index=i;
+
+ ret=vfd->vidioc_enum_input(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "audioset=%d, "
+ "tuner=%d, std=%Ld, status=%d\n",
+ p->index,p->name,p->type,p->audioset,
+ p->tuner,
+ (unsigned long long)p->std,
+ p->status);
+ break;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_g_input)
+ break;
+ ret=vfd->vidioc_g_input(file, fh, i);
+ if (!ret)
+ dbgarg (cmd, "value=%d\n",*i);
+ break;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_s_input)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_s_input(file, fh, *i);
+ break;
+ }
+
+ /* ------ output switching ---------- */
+ case VIDIOC_G_OUTPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_g_output)
+ break;
+ ret=vfd->vidioc_g_output(file, fh, i);
+ if (!ret)
+ dbgarg (cmd, "value=%d\n",*i);
+ break;
+ }
+ case VIDIOC_S_OUTPUT:
+ {
+ unsigned int *i = arg;
+
+ if (!vfd->vidioc_s_output)
+ break;
+ dbgarg (cmd, "value=%d\n",*i);
+ ret=vfd->vidioc_s_output(file, fh, *i);
+ break;
+ }
+
+ /* --- controls ---------------------------------------------- */
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *p=arg;
+
+ if (!vfd->vidioc_queryctrl)
+ break;
+ ret=vfd->vidioc_queryctrl(file, fh, p);
+
+ if (!ret)
+ dbgarg (cmd, "id=%d, type=%d, name=%s, "
+ "min/max=%d/%d,"
+ " step=%d, default=%d, flags=0x%08x\n",
+ p->id,p->type,p->name,p->minimum,
+ p->maximum,p->step,p->default_value,
+ p->flags);
+ break;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *p = arg;
+
+ if (!vfd->vidioc_g_ctrl)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->id);
+
+ ret=vfd->vidioc_g_ctrl(file, fh, p);
+ if (!ret)
+ dbgarg2 ( "id=%d, value=%d\n", p->id, p->value);
+ break;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *p = arg;
+
+ if (!vfd->vidioc_s_ctrl)
+ break;
+ dbgarg (cmd, "id=%d, value=%d\n", p->id, p->value);
+
+ ret=vfd->vidioc_s_ctrl(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_g_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_g_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_s_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_s_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *p = arg;
+
+ if (vfd->vidioc_try_ext_ctrls) {
+ dbgarg(cmd, "count=%d\n", p->count);
+
+ ret=vfd->vidioc_try_ext_ctrls(file, fh, p);
+ }
+ break;
+ }
+ case VIDIOC_QUERYMENU:
+ {
+ struct v4l2_querymenu *p=arg;
+ if (!vfd->vidioc_querymenu)
+ break;
+ ret=vfd->vidioc_querymenu(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "id=%d, index=%d, name=%s\n",
+ p->id,p->index,p->name);
+ break;
+ }
+ /* --- audio ---------------------------------------------- */
+ case VIDIOC_ENUMAUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_enumaudio)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_enumaudio(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n",p->index,p->name,
+ p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_g_audio)
+ break;
+ dbgarg(cmd, "Get for index=%d\n", p->index);
+ ret=vfd->vidioc_g_audio(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n",p->index,
+ p->name,p->capability, p->mode);
+ break;
+ }
+ case VIDIOC_S_AUDIO:
+ {
+ struct v4l2_audio *p=arg;
+
+ if (!vfd->vidioc_s_audio)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability, p->mode);
+ ret=vfd->vidioc_s_audio(file, fh, p);
+ break;
+ }
+ case VIDIOC_ENUMAUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_enumaudout)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_enumaudout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_G_AUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_g_audout)
+ break;
+ dbgarg(cmd, "Enum for index=%d\n", p->index);
+ ret=vfd->vidioc_g_audout(file, fh, p);
+ if (!ret)
+ dbgarg2("index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+ break;
+ }
+ case VIDIOC_S_AUDOUT:
+ {
+ struct v4l2_audioout *p=arg;
+
+ if (!vfd->vidioc_s_audout)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "mode=%d\n", p->index, p->name,
+ p->capability,p->mode);
+
+ ret=vfd->vidioc_s_audout(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ if (!vfd->vidioc_g_modulator)
+ break;
+ ret=vfd->vidioc_g_modulator(file, fh, p);
+ if (!ret)
+ dbgarg(cmd, "index=%d, name=%s, "
+ "capability=%d, rangelow=%d,"
+ " rangehigh=%d, txsubchans=%d\n",
+ p->index, p->name,p->capability,
+ p->rangelow, p->rangehigh,
+ p->txsubchans);
+ break;
+ }
+ case VIDIOC_S_MODULATOR:
+ {
+ struct v4l2_modulator *p=arg;
+ if (!vfd->vidioc_s_modulator)
+ break;
+ dbgarg(cmd, "index=%d, name=%s, capability=%d, "
+ "rangelow=%d, rangehigh=%d, txsubchans=%d\n",
+ p->index, p->name,p->capability,p->rangelow,
+ p->rangehigh,p->txsubchans);
+ ret=vfd->vidioc_s_modulator(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ if (!vfd->vidioc_g_crop)
+ break;
+ ret=vfd->vidioc_g_crop(file, fh, p);
+ if (!ret) {
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "", &p->c);
+ }
+ break;
+ }
+ case VIDIOC_S_CROP:
+ {
+ struct v4l2_crop *p=arg;
+ if (!vfd->vidioc_s_crop)
+ break;
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "", &p->c);
+ ret=vfd->vidioc_s_crop(file, fh, p);
+ break;
+ }
+ case VIDIOC_CROPCAP:
+ {
+ struct v4l2_cropcap *p=arg;
+ /*FIXME: Should also show v4l2_fract pixelaspect */
+ if (!vfd->vidioc_cropcap)
+ break;
+ dbgarg(cmd, "type=%d\n", p->type);
+ dbgrect(vfd, "bounds ", &p->bounds);
+ dbgrect(vfd, "defrect ", &p->defrect);
+ ret=vfd->vidioc_cropcap(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+
+ /*FIXME: Several fields not shown */
+ if (!vfd->vidioc_g_mpegcomp)
+ break;
+ ret=vfd->vidioc_g_mpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d,"
+ " ts_pid_video=%d, ts_pid_pcr=%d, "
+ "ps_size=%d, au_sample_rate=%d, "
+ "au_pesid=%c, vi_frame_rate=%d, "
+ "vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n",
+ p->ts_pid_pmt,p->ts_pid_audio,
+ p->ts_pid_video,p->ts_pid_pcr,
+ p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop,
+ p->vi_bframes_count, p->vi_pesid);
+ break;
+ }
+ case VIDIOC_S_MPEGCOMP:
+ {
+ struct v4l2_mpeg_compression *p=arg;
+ /*FIXME: Several fields not shown */
+ if (!vfd->vidioc_s_mpegcomp)
+ break;
+ dbgarg (cmd, "ts_pid_pmt=%d, ts_pid_audio=%d, "
+ "ts_pid_video=%d, ts_pid_pcr=%d, ps_size=%d, "
+ "au_sample_rate=%d, au_pesid=%c, "
+ "vi_frame_rate=%d, vi_frames_per_gop=%d, "
+ "vi_bframes_count=%d, vi_pesid=%c\n",
+ p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video,
+ p->ts_pid_pcr, p->ps_size, p->au_sample_rate,
+ p->au_pesid, p->vi_frame_rate,
+ p->vi_frames_per_gop, p->vi_bframes_count,
+ p->vi_pesid);
+ ret=vfd->vidioc_s_mpegcomp(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ if (!vfd->vidioc_g_jpegcomp)
+ break;
+ ret=vfd->vidioc_g_jpegcomp(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "quality=%d, APPn=%d, "
+ "APP_len=%d, COM_len=%d, "
+ "jpeg_markers=%d\n",
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ break;
+ }
+ case VIDIOC_S_JPEGCOMP:
+ {
+ struct v4l2_jpegcompression *p=arg;
+ if (!vfd->vidioc_g_jpegcomp)
+ break;
+ dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, "
+ "COM_len=%d, jpeg_markers=%d\n",
+ p->quality,p->APPn,p->APP_len,
+ p->COM_len,p->jpeg_markers);
+ ret=vfd->vidioc_s_jpegcomp(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+ if (!vfd->vidioc_g_parm)
+ break;
+ ret=vfd->vidioc_g_parm(file, fh, p);
+ dbgarg (cmd, "type=%d\n", p->type);
+ break;
+ }
+ case VIDIOC_S_PARM:
+ {
+ struct v4l2_streamparm *p=arg;
+ if (!vfd->vidioc_s_parm)
+ break;
+ dbgarg (cmd, "type=%d\n", p->type);
+ ret=vfd->vidioc_s_parm(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ if (!vfd->vidioc_g_tuner)
+ break;
+ ret=vfd->vidioc_g_tuner(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "capability=%d, rangelow=%d, "
+ "rangehigh=%d, signal=%d, afc=%d, "
+ "rxsubchans=%d, audmode=%d\n",
+ p->index, p->name, p->type,
+ p->capability, p->rangelow,
+ p->rangehigh, p->rxsubchans,
+ p->audmode, p->signal, p->afc);
+ break;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *p=arg;
+ if (!vfd->vidioc_s_tuner)
+ break;
+ dbgarg (cmd, "index=%d, name=%s, type=%d, "
+ "capability=%d, rangelow=%d, rangehigh=%d, "
+ "signal=%d, afc=%d, rxsubchans=%d, "
+ "audmode=%d\n",p->index, p->name, p->type,
+ p->capability, p->rangelow,p->rangehigh,
+ p->rxsubchans, p->audmode, p->signal,
+ p->afc);
+ ret=vfd->vidioc_s_tuner(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ if (!vfd->vidioc_g_frequency)
+ break;
+ ret=vfd->vidioc_g_frequency(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner,p->type,p->frequency);
+ break;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *p=arg;
+ if (!vfd->vidioc_s_frequency)
+ break;
+ dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n",
+ p->tuner,p->type,p->frequency);
+ ret=vfd->vidioc_s_frequency(file, fh, p);
+ break;
+ }
+ case VIDIOC_G_SLICED_VBI_CAP:
+ {
+ struct v4l2_sliced_vbi_cap *p=arg;
+ if (!vfd->vidioc_g_sliced_vbi_cap)
+ break;
+ ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p);
+ if (!ret)
+ dbgarg (cmd, "service_set=%d\n", p->service_set);
+ break;
+ }
+ case VIDIOC_LOG_STATUS:
+ {
+ if (!vfd->vidioc_log_status)
+ break;
+ ret=vfd->vidioc_log_status(file, fh);
+ break;
+ }
+
+ /* --- Others --------------------------------------------- */
+
+ default:
+ ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,__video_do_ioctl);
+ }
+
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
+ if (ret<0) {
+ printk ("%s: err:\n", vfd->name);
+ v4l_print_ioctl(vfd->name, cmd);
+ }
+ }
+
+ return ret;
+}
+
+int video_ioctl2 (struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ char sbuf[128];
+ void *mbuf = NULL;
+ void *parg = NULL;
+ int err = -EINVAL;
+ int is_ext_ctrl;
+ size_t ctrls_size = 0;
+ void __user *user_ptr = NULL;
+
+#ifdef __OLD_VIDIOC_
+ cmd = video_fix_command(cmd);
+#endif
+ is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS ||
+ cmd == VIDIOC_TRY_EXT_CTRLS);
+
+ /* Copy arguments into temp kernel buffer */
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE:
+ parg = NULL;
+ break;
+ case _IOC_READ:
+ case _IOC_WRITE:
+ case (_IOC_WRITE | _IOC_READ):
+ if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+ parg = sbuf;
+ } else {
+ /* too big to allocate from stack */
+ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+ if (NULL == mbuf)
+ return -ENOMEM;
+ parg = mbuf;
+ }
+
+ err = -EFAULT;
+ if (_IOC_DIR(cmd) & _IOC_WRITE)
+ if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+ goto out;
+ break;
+ }
+
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ /* In case of an error, tell the caller that it wasn't
+ a specific control that caused it. */
+ p->error_idx = p->count;
+ user_ptr = (void __user *)p->controls;
+ if (p->count) {
+ ctrls_size = sizeof(struct v4l2_ext_control) * p->count;
+ /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */
+ mbuf = kmalloc(ctrls_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (NULL == mbuf)
+ goto out_ext_ctrl;
+ err = -EFAULT;
+ if (copy_from_user(mbuf, user_ptr, ctrls_size))
+ goto out_ext_ctrl;
+ p->controls = mbuf;
+ }
+ }
+
+ /* Handles IOCTL */
+ err = __video_do_ioctl(inode, file, cmd, parg);
+ if (err == -ENOIOCTLCMD)
+ err = -EINVAL;
+ if (is_ext_ctrl) {
+ struct v4l2_ext_controls *p = parg;
+
+ p->controls = (void *)user_ptr;
+ if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size))
+ err = -EFAULT;
+ goto out_ext_ctrl;
+ }
+ if (err < 0)
+ goto out;
+
+out_ext_ctrl:
+ /* Copy results into user buffer */
+ switch (_IOC_DIR(cmd))
+ {
+ case _IOC_READ:
+ case (_IOC_WRITE | _IOC_READ):
+ if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+ err = -EFAULT;
+ break;
+ }
+
+out:
+ kfree(mbuf);
+ return err;
+}
+
+
static struct file_operations video_fops;
/**
mutex_unlock(&videodev_lock);
}
-
+/*
+ * Video fs operations
+ */
static struct file_operations video_fops=
{
.owner = THIS_MODULE,
{
int ret;
- printk(KERN_INFO "Linux video capture interface: v1.00\n");
+ printk(KERN_INFO "Linux video capture interface: v2.00\n");
if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) {
printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR);
return -EIO;
EXPORT_SYMBOL(video_usercopy);
EXPORT_SYMBOL(video_exclusive_open);
EXPORT_SYMBOL(video_exclusive_release);
+EXPORT_SYMBOL(video_ioctl2);
EXPORT_SYMBOL(video_device_alloc);
EXPORT_SYMBOL(video_device_release);
-MODULE_AUTHOR("Alan Cox");
-MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
+MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
MODULE_LICENSE("GPL");
#include <linux/i2c-algo-sgi.h>
#include <linux/videodev.h>
-#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
#include <linux/mutex.h>
#include "font.h"
-#ifndef kzalloc
-#define kzalloc(size, flags) \
-({ \
- void *__ret = kmalloc(size, flags); \
- if (__ret) \
- memset(__ret, 0, size); \
- __ret; \
-})
-#endif
-
-MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
-MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
-MODULE_LICENSE("Dual BSD/GPL");
-
#define VIVI_MAJOR_VERSION 0
#define VIVI_MINOR_VERSION 4
#define VIVI_RELEASE 0
#define VIVI_VERSION KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
-static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
-module_param(video_nr, int, 0);
-
-static int debug = 0;
-module_param(debug, int, 0);
-
-static unsigned int vid_limit = 16;
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+/* Declare static vars that will be used as parameters */
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+static struct video_device vivi; /* Video device */
+static int video_nr = -1; /* /dev/videoN, -1 for autodetect */
/* supported controls */
static struct v4l2_queryctrl vivi_qctrl[] = {
static int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
-#define dprintk(level,fmt, arg...) \
- do { \
- if (debug >= (level)) \
- printk(KERN_DEBUG "vivi: " fmt , ## arg); \
+#define dprintk(level,fmt, arg...) \
+ do { \
+ if (vivi.debug >= (level)) \
+ printk(KERN_DEBUG "vivi: " fmt , ## arg); \
} while (0)
/* ------------------------------------------------------------------
/* various device info */
unsigned int resources;
- struct video_device video_dev;
+ struct video_device vfd;
struct vivi_dmaqueue vidq;
#define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
#define TSTAMP_MIN_X 64
-void prep_to_addr(struct sg_to_addr to_addr[],struct videobuf_buffer *vb)
+static void prep_to_addr(struct sg_to_addr to_addr[],
+ struct videobuf_buffer *vb)
{
int i, pos=0;
}
}
-inline int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
+static int get_addr_pos(int pos, int pages, struct sg_to_addr to_addr[])
{
int p1=0,p2=pages-1,p3=pages/2;
return (p1);
}
-void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
- int hmax, int line, char *timestr)
+static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
+ int hmax, int line, char *timestr)
{
int w,i,j,pos=inipos,pgpos,oldpg,y;
char *p,*s,*basep;
dprintk(1,"%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
}
-void vivi_sleep(struct vivi_dmaqueue *dma_q)
+static void vivi_sleep(struct vivi_dmaqueue *dma_q)
{
int timeout;
DECLARE_WAITQUEUE(wait, current);
try_to_freeze();
}
-int vivi_thread(void *data)
+static int vivi_thread(void *data)
{
struct vivi_dmaqueue *dma_q=data;
return 0;
}
-int vivi_start_thread(struct vivi_dmaqueue *dma_q)
+static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
{
dma_q->frame=0;
dma_q->ini_jiffies=jiffies;
return 0;
}
-void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
+static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
{
dprintk(1,"%s\n",__FUNCTION__);
/* shutdown control thread */
return 0;
}
-void
-free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
+static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
{
dprintk(1,"%s\n",__FUNCTION__);
free_buffer(vq,buf);
}
-int vivi_map_sg (void *dev, struct scatterlist *sg, int nents,
- int direction)
+static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
+ int direction)
{
int i;
return nents;
}
-int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
+static int vivi_unmap_sg(void *dev,struct scatterlist *sglist,int nr_pages,
+ int direction)
{
dprintk(1,"%s\n",__FUNCTION__);
return 0;
}
-int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist,int nr_pages,
- int direction)
+static int vivi_dma_sync_sg(void *dev,struct scatterlist *sglist, int nr_pages,
+ int direction)
{
// dprintk(1,"%s\n",__FUNCTION__);
IOCTL handling
------------------------------------------------------------------*/
-static int vivi_try_fmt(struct vivi_dev *dev, struct vivi_fh *fh,
+
+static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+ /* is it free? */
+ down(&dev->lock);
+ if (dev->resources) {
+ /* no, someone else uses it */
+ up(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ dev->resources =1;
+ dprintk(1,"res: get\n");
+ up(&dev->lock);
+ return 1;
+}
+
+static int res_locked(struct vivi_dev *dev)
+{
+ return (dev->resources);
+}
+
+static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
+{
+ down(&dev->lock);
+ dev->resources = 0;
+ dprintk(1,"res: put\n");
+ up(&dev->lock);
+}
+
+/* ------------------------------------------------------------------
+ IOCTL vidioc handling
+ ------------------------------------------------------------------*/
+static int vidioc_querycap (struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "vivi");
+ strcpy(cap->card, "vivi");
+ cap->version = VIVI_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt_cap (struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index > 0)
+ return -EINVAL;
+
+ strlcpy(f->description,format.name,sizeof(f->description));
+ f->pixelformat = format.fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vivi_fh *fh=priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return (0);
+}
+
+static int vidioc_try_fmt_cap (struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fmt *fmt;
unsigned int maxw, maxh;
if (format.fourcc != f->fmt.pix.pixelformat) {
- dprintk(1,"Fourcc format invalid.\n");
+ dprintk(1,"Fourcc format (0x%08x) invalid. Driver accepts "
+ "only 0x%08x\n",f->fmt.pix.pixelformat,format.fourcc);
return -EINVAL;
}
fmt=&format;
return 0;
}
-static int res_get(struct vivi_dev *dev, struct vivi_fh *fh)
+/*FIXME: This seems to be generic enough to be at videodev2 */
+static int vidioc_s_fmt_cap (struct file *file, void *priv,
+ struct v4l2_format *f)
{
- /* is it free? */
- down(&dev->lock);
- if (dev->resources) {
- /* no, someone else uses it */
- up(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- dev->resources =1;
- dprintk(1,"res: get\n");
- up(&dev->lock);
- return 1;
+ struct vivi_fh *fh=priv;
+ int ret = vidioc_try_fmt_cap(file,fh,f);
+ if (ret < 0)
+ return (ret);
+
+ fh->fmt = &format;
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+
+ return (0);
}
-static inline int res_locked(struct vivi_dev *dev)
+static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
- return (dev->resources);
-}
+ struct vivi_fh *fh=priv;
-static void res_free(struct vivi_dev *dev, struct vivi_fh *fh)
-{
- down(&dev->lock);
- dev->resources = 0;
- dprintk(1,"res: put\n");
- up(&dev->lock);
+ return (videobuf_reqbufs(&fh->vb_vidq, p));
}
-static int vivi_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg)
+static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_dev *dev = fh->dev;
- int ret=0;
+ struct vivi_fh *fh=priv;
- if (debug) {
- if (_IOC_DIR(cmd) & _IOC_WRITE)
- v4l_printk_ioctl_arg("vivi(w)",cmd, arg);
- else if (!_IOC_DIR(cmd) & _IOC_READ) {
- v4l_print_ioctl("vivi", cmd);
- }
- }
+ return (videobuf_querybuf(&fh->vb_vidq, p));
+}
- switch(cmd) {
- /* --- capabilities ------------------------------------------ */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = (struct v4l2_capability*)arg;
-
- memset(cap, 0, sizeof(*cap));
-
- strcpy(cap->driver, "vivi");
- strcpy(cap->card, "vivi");
- cap->version = VIVI_VERSION;
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- break;
- }
- /* --- capture ioctls ---------------------------------------- */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *f = arg;
- enum v4l2_buf_type type;
- unsigned int index;
+static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vivi_fh *fh=priv;
- index = f->index;
- type = f->type;
+ return (videobuf_qbuf(&fh->vb_vidq, p));
+}
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct vivi_fh *fh=priv;
- switch (type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index > 0){
- ret=-EINVAL;
- break;
- }
- memset(f,0,sizeof(*f));
+ return (videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK));
+}
- f->index = index;
- f->type = type;
- strlcpy(f->description,format.name,sizeof(f->description));
- f->pixelformat = format.fourcc;
- break;
- default:
- ret=-EINVAL;
- }
- break;
+#ifdef HAVE_V4L1
+static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct vivi_fh *fh=priv;
+ struct videobuf_queue *q=&fh->vb_vidq;
+ struct v4l2_requestbuffers req;
+ unsigned int i, ret;
+
+ req.type = q->type;
+ req.count = 8;
+ req.memory = V4L2_MEMORY_MMAP;
+ ret = videobuf_reqbufs(q,&req);
+ if (ret < 0)
+ return (ret);
+
+ mbuf->frames = req.count;
+ mbuf->size = 0;
+ for (i = 0; i < mbuf->frames; i++) {
+ mbuf->offsets[i] = q->bufs[i]->boff;
+ mbuf->size += q->bufs[i]->bsize;
}
- case VIDIOC_G_FMT:
- {
- struct v4l2_format *f = (struct v4l2_format *)arg;
+ return (0);
+}
+#endif
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vivi_fh *fh=priv;
+ struct vivi_dev *dev = fh->dev;
- memset(&f->fmt.pix,0,sizeof(f->fmt.pix));
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
- f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline =
- (f->fmt.pix.width * fh->fmt->depth) >> 3;
- f->fmt.pix.sizeimage =
- f->fmt.pix.height * f->fmt.pix.bytesperline;
- break;
- }
- case VIDIOC_S_FMT:
- {
- struct v4l2_format *f = arg;
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dprintk(1,"Only capture supported.\n");
- ret=-EINVAL;
- break;
- }
+ if (!res_get(dev,fh))
+ return -EBUSY;
+ return (videobuf_streamon(&fh->vb_vidq));
+}
- ret = vivi_try_fmt(dev,fh,f);
- if (ret < 0)
- break;
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct vivi_fh *fh=priv;
+ struct vivi_dev *dev = fh->dev;
- fh->fmt = &format;
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
- fh->vb_vidq.field = f->fmt.pix.field;
- fh->type = f->type;
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (i != fh->type)
+ return -EINVAL;
- break;
- }
- case VIDIOC_TRY_FMT:
- {
- struct v4l2_format *f = arg;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(dev,fh);
- ret=vivi_try_fmt(dev,fh,f);
- break;
- }
- case VIDIOC_REQBUFS:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_reqbufs(&fh->vb_vidq, arg);
- break;
- case VIDIOC_QUERYBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_querybuf(&fh->vb_vidq, arg);
- break;
- case VIDIOC_QBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_qbuf(&fh->vb_vidq, arg);
- break;
- case VIDIOC_DQBUF:
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret=videobuf_dqbuf(&fh->vb_vidq, arg,
- file->f_flags & O_NONBLOCK);
- break;
-#ifdef HAVE_V4L1
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *mbuf = arg;
- struct videobuf_queue *q=&fh->vb_vidq;
- struct v4l2_requestbuffers req;
- unsigned int i;
-
- memset(&req,0,sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- ret = videobuf_reqbufs(q,&req);
- if (ret < 0)
- break;
- memset(mbuf,0,sizeof(*mbuf));
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- break;
- }
-#endif
- case VIDIOC_STREAMON:
- {
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (!res_get(dev,fh))
- return -EBUSY;
- ret=videobuf_streamon(&fh->vb_vidq);
- break;
- }
- case VIDIOC_STREAMOFF:
+ return (0);
+}
+
+static struct v4l2_tvnorm tvnorms[] = {
{
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- ret=-EINVAL;
- break;
- }
- ret = videobuf_streamoff(&fh->vb_vidq);
- if (ret < 0)
- break;
- res_free(dev,fh);
- break;
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
}
- /* ---------- tv norms ---------- */
- case VIDIOC_ENUMSTD:
- {
- struct v4l2_standard *e = arg;
+};
- if (e->index>0) {
- ret=-EINVAL;
- break;
- }
- ret = v4l2_video_std_construct(e, V4L2_STD_NTSC_M, "NTSC-M");
+static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id a)
+{
- /* Allows vivi to use different fps from video std */
- e->frameperiod.numerator = WAKE_NUMERATOR;
- e->frameperiod.denominator = WAKE_DENOMINATOR;
+ return 0;
+}
- break;
- }
- case VIDIOC_G_STD:
- {
- v4l2_std_id *id = arg;
+/* only one input in this sample driver */
+static int vidioc_enum_input (struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
- *id = V4L2_STD_NTSC_M;
- break;
- }
- case VIDIOC_S_STD:
- {
- break;
- }
- /* ------ input switching ---------- */
- case VIDIOC_ENUMINPUT:
- { /* only one input in this sample driver */
- struct v4l2_input *inp = arg;
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_NTSC_M;
+ strcpy(inp->name,"Camera");
- if (inp->index != 0) {
- ret=-EINVAL;
- break;
- }
- memset(inp, 0, sizeof(*inp));
+ return (0);
+}
- inp->index = 0;
- inp->type = V4L2_INPUT_TYPE_CAMERA;
- inp->std = V4L2_STD_NTSC_M;
- strcpy(inp->name,"Camera");
- break;
- }
- case VIDIOC_G_INPUT:
- {
- unsigned int *i = arg;
+static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
- *i = 0;
- break;
- }
- case VIDIOC_S_INPUT:
- {
- unsigned int *i = arg;
+ return (0);
+}
+static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
- if (*i > 0)
- ret=-EINVAL;
- break;
- }
+ return (0);
+}
/* --- controls ---------------------------------------------- */
- case VIDIOC_QUERYCTRL:
- {
- struct v4l2_queryctrl *qc = arg;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (qc->id && qc->id == vivi_qctrl[i].id) {
- memcpy(qc, &(vivi_qctrl[i]),
- sizeof(*qc));
- break;
- }
+static int vidioc_queryctrl (struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
- ret=-EINVAL;
- break;
- }
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int i;
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (qc->id && qc->id == vivi_qctrl[i].id) {
+ memcpy(qc, &(vivi_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (ctrl->id == vivi_qctrl[i].id) {
- ctrl->value=qctl_regs[i];
- break;
- }
+ return -EINVAL;
+}
- ret=-EINVAL;
- break;
- }
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- int i;
- for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
- if (ctrl->id == vivi_qctrl[i].id) {
- if (ctrl->value <
- vivi_qctrl[i].minimum
- || ctrl->value >
- vivi_qctrl[i].maximum) {
- ret=-ERANGE;
- break;
- }
- qctl_regs[i]=ctrl->value;
- break;
- }
- ret=-EINVAL;
- break;
- }
- default:
- ret=v4l_compat_translate_ioctl(inode,file,cmd,arg,vivi_do_ioctl);
- }
+static int vidioc_g_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
- if (debug) {
- if (ret<0) {
- v4l_print_ioctl("vivi(err)", cmd);
- dprintk(1,"errcode=%d\n",ret);
- } else if (_IOC_DIR(cmd) & _IOC_READ)
- v4l_printk_ioctl_arg("vivi(r)",cmd, arg);
- }
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+ ctrl->value=qctl_regs[i];
+ return (0);
+ }
- return ret;
+ return -EINVAL;
}
-
-static int vivi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int vidioc_s_ctrl (struct file *file, void *priv,
+ struct v4l2_control *ctrl)
{
- return video_usercopy(inode, file, cmd, arg, vivi_do_ioctl);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
+ if (ctrl->id == vivi_qctrl[i].id) {
+ if (ctrl->value <
+ vivi_qctrl[i].minimum
+ || ctrl->value >
+ vivi_qctrl[i].maximum) {
+ return (-ERANGE);
+ }
+ qctl_regs[i]=ctrl->value;
+ return (0);
+ }
+ return -EINVAL;
}
/* ------------------------------------------------------------------
list_for_each(list,&vivi_devlist) {
h = list_entry(list, struct vivi_dev, vivi_devlist);
- if (h->video_dev.minor == minor) {
+ if (h->vfd.minor == minor) {
dev = h;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
}
return -ENODEV;
+
/* If more than one user, mutex should be added */
dev->users++;
file->private_data = fh;
fh->dev = dev;
+
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->fmt = &format;
fh->width = 640;
static ssize_t
vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
- struct vivi_fh *fh = file->private_data;
+ struct vivi_fh *fh = file->private_data;
if (fh->type==V4L2_BUF_TYPE_VIDEO_CAPTURE) {
if (res_locked(fh->dev))
static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_buffer *buf;
+ struct vivi_fh *fh = file->private_data;
+ struct vivi_buffer *buf;
dprintk(1,"%s\n",__FUNCTION__);
static int vivi_release(struct inode *inode, struct file *file)
{
- struct vivi_fh *fh = file->private_data;
- struct vivi_dev *dev = fh->dev;
+ struct vivi_fh *fh = file->private_data;
+ struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq;
int minor = iminor(inode);
static int
vivi_mmap(struct file *file, struct vm_area_struct * vma)
{
- struct vivi_fh *fh = file->private_data;
+ struct vivi_fh *fh = file->private_data;
int ret;
dprintk (1,"mmap called, vma=0x%08lx\n",(unsigned long)vma);
.release = vivi_release,
.read = vivi_read,
.poll = vivi_poll,
- .ioctl = vivi_ioctl,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = vivi_mmap,
.llseek = no_llseek,
};
static struct video_device vivi = {
- .name = "VTM Virtual Video Capture Board",
+ .name = "vivi",
.type = VID_TYPE_CAPTURE,
.hardware = 0,
.fops = &vivi_fops,
.minor = -1,
// .release = video_device_release,
+
+ .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_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+#ifdef HAVE_V4L1
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
+ .tvnorms = tvnorms,
+ .tvnormsize = ARRAY_SIZE(tvnorms),
};
-/* ------------------------------------------------------------------
+/* -----------------------------------------------------------------
Initialization and module stuff
------------------------------------------------------------------*/
module_init(vivi_init);
module_exit(vivi_exit);
+
+MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board");
+MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_param(video_nr, int, 0);
+
+module_param_named(debug,vivi.debug, int, 0644);
+MODULE_PARM_DESC(debug,"activates debug info");
+
+module_param(vid_limit,int,0644);
+MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
+
#define I2C_NAME(x) (x)->name
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
#define I2C_VPX3220 0x86
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/parport.h>
//#define DEBUG // Undef me for production
config USB_ZC0301
- tristate "USB ZC0301 Image Processor and Control Chip support"
+ tristate "USB ZC0301[P] Image Processor and Control Chip support"
depends on USB && VIDEO_V4L1
---help---
- Say Y here if you want support for cameras based on the ZC0301
- Image Processor and Control Chip.
+ Say Y here if you want support for cameras based on the ZC0301 or
+ ZC0301P Image Processors and Control Chips.
See <file:Documentation/video4linux/zc0301.txt> for more info.
-zc0301-objs := zc0301_core.o zc0301_pas202bcb.o
+zc0301-objs := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
obj-$(CONFIG_USB_ZC0301) += zc0301.o
/***************************************************************************
- * Video4Linux2 driver for ZC0301 Image Processor and Control Chip *
+ * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
/*****************************************************************************/
-#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301 " \
+#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
"Image Processor and Control Chip"
#define ZC0301_MODULE_AUTHOR "(C) 2006 Luca Risolia"
#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.03"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3)
+#define ZC0301_MODULE_VERSION "1:1.05"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 5)
/*****************************************************************************/
static int zc0301_start_transfer(struct zc0301_device* cam)
{
struct usb_device *udev = cam->usbdev;
+ struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ usb_ifnum_to_if(udev, 0),
+ ZC0301_ALTERNATE_SETTING);
+ const unsigned int psz = altsetting->endpoint[0].desc.wMaxPacketSize;
struct urb* urb;
- const unsigned int wMaxPacketSize[] = {0, 128, 192, 256, 384,
- 512, 768, 1023};
- const unsigned int psz = wMaxPacketSize[ZC0301_ALTERNATE_SETTING];
s8 i, j;
int err = 0;
case VIDIOC_G_CTRL:
return zc0301_vidioc_g_ctrl(cam, arg);
- case VIDIOC_S_CTRL_OLD:
case VIDIOC_S_CTRL:
return zc0301_vidioc_s_ctrl(cam, arg);
- case VIDIOC_CROPCAP_OLD:
case VIDIOC_CROPCAP:
return zc0301_vidioc_cropcap(cam, arg);
case VIDIOC_G_PARM:
return zc0301_vidioc_g_parm(cam, arg);
- case VIDIOC_S_PARM_OLD:
case VIDIOC_S_PARM:
return zc0301_vidioc_s_parm(cam, arg);
mutex_init(&cam->dev_mutex);
- DBG(2, "ZC0301 Image Processor and Control Chip detected "
+ DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
"(vid/pid 0x%04X/0x%04X)",id->idVendor, id->idProduct);
for (i = 0; zc0301_sensor_table[i]; i++) {
cam->state |= DEV_MISCONFIGURED;
}
- strcpy(cam->v4ldev->name, "ZC0301 PC Camera");
+ strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
cam->v4ldev->owner = THIS_MODULE;
cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
cam->v4ldev->hardware = 0;
/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC030! Image *
+ * Plug-in for PAS202BCB image sensor connected to the ZC0301[P] Image *
* Processor and Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
- * Initialization values of the ZC0301 have been taken from the SPCA5XX *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
* driver maintained by Michel Xhaard <mxhaard@magic.fr> *
* *
* This program is free software; you can redistribute it and/or modify *
--- /dev/null
+/***************************************************************************
+ * Plug-in for PB-0330 image sensor connected to the ZC0301[P] Image *
+ * Processor and Control Chip *
+ * *
+ * Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
+ * driver maintained by Michel Xhaard <mxhaard@magic.fr> *
+ * *
+ * 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 <linux/delay.h>
+#include "zc0301_sensor.h"
+
+
+static struct zc0301_sensor pb0330;
+
+
+static int pb0330_init(struct zc0301_device* cam)
+{
+ int err = 0;
+
+ err += zc0301_write_reg(cam, 0x0000, 0x01);
+ err += zc0301_write_reg(cam, 0x0008, 0x03);
+ err += zc0301_write_reg(cam, 0x0010, 0x0A);
+ err += zc0301_write_reg(cam, 0x0002, 0x00);
+ err += zc0301_write_reg(cam, 0x0003, 0x02);
+ err += zc0301_write_reg(cam, 0x0004, 0x80);
+ err += zc0301_write_reg(cam, 0x0005, 0x01);
+ err += zc0301_write_reg(cam, 0x0006, 0xE0);
+ err += zc0301_write_reg(cam, 0x0001, 0x01);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+ err += zc0301_write_reg(cam, 0x0012, 0x07);
+ err += zc0301_write_reg(cam, 0x0098, 0x00);
+ err += zc0301_write_reg(cam, 0x009A, 0x00);
+ err += zc0301_write_reg(cam, 0x011A, 0x00);
+ err += zc0301_write_reg(cam, 0x011C, 0x00);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+
+ err += zc0301_i2c_write(cam, 0x01, 0x0006);
+ err += zc0301_i2c_write(cam, 0x02, 0x0011);
+ err += zc0301_i2c_write(cam, 0x03, 0x01E7);
+ err += zc0301_i2c_write(cam, 0x04, 0x0287);
+ err += zc0301_i2c_write(cam, 0x06, 0x0003);
+ err += zc0301_i2c_write(cam, 0x07, 0x3002);
+ err += zc0301_i2c_write(cam, 0x20, 0x1100);
+ err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
+ err += zc0301_i2c_write(cam, 0x30, 0x0005);
+ err += zc0301_i2c_write(cam, 0x31, 0x0000);
+ err += zc0301_i2c_write(cam, 0x34, 0x0100);
+ err += zc0301_i2c_write(cam, 0x35, 0x0060);
+ err += zc0301_i2c_write(cam, 0x3D, 0x068F);
+ err += zc0301_i2c_write(cam, 0x40, 0x01E0);
+ err += zc0301_i2c_write(cam, 0x58, 0x0078);
+ err += zc0301_i2c_write(cam, 0x62, 0x0411);
+
+ err += zc0301_write_reg(cam, 0x0087, 0x10);
+ err += zc0301_write_reg(cam, 0x0101, 0x37);
+ err += zc0301_write_reg(cam, 0x0012, 0x05);
+ err += zc0301_write_reg(cam, 0x0100, 0x0D);
+ err += zc0301_write_reg(cam, 0x0189, 0x06);
+ err += zc0301_write_reg(cam, 0x01AD, 0x00);
+ err += zc0301_write_reg(cam, 0x01C5, 0x03);
+ err += zc0301_write_reg(cam, 0x01CB, 0x13);
+ err += zc0301_write_reg(cam, 0x0250, 0x08);
+ err += zc0301_write_reg(cam, 0x0301, 0x08);
+ err += zc0301_write_reg(cam, 0x01A8, 0x60);
+ err += zc0301_write_reg(cam, 0x018D, 0x6C);
+ err += zc0301_write_reg(cam, 0x01AD, 0x09);
+ err += zc0301_write_reg(cam, 0x01AE, 0x15);
+ err += zc0301_write_reg(cam, 0x010A, 0x50);
+ err += zc0301_write_reg(cam, 0x010B, 0xF8);
+ err += zc0301_write_reg(cam, 0x010C, 0xF8);
+ err += zc0301_write_reg(cam, 0x010D, 0xF8);
+ err += zc0301_write_reg(cam, 0x010E, 0x50);
+ err += zc0301_write_reg(cam, 0x010F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0110, 0xF8);
+ err += zc0301_write_reg(cam, 0x0111, 0xF8);
+ err += zc0301_write_reg(cam, 0x0112, 0x50);
+ err += zc0301_write_reg(cam, 0x0008, 0x03);
+ err += zc0301_write_reg(cam, 0x01C6, 0x08);
+ err += zc0301_write_reg(cam, 0x01CB, 0x0F);
+ err += zc0301_write_reg(cam, 0x010A, 0x50);
+ err += zc0301_write_reg(cam, 0x010B, 0xF8);
+ err += zc0301_write_reg(cam, 0x010C, 0xF8);
+ err += zc0301_write_reg(cam, 0x010D, 0xF8);
+ err += zc0301_write_reg(cam, 0x010E, 0x50);
+ err += zc0301_write_reg(cam, 0x010F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0110, 0xF8);
+ err += zc0301_write_reg(cam, 0x0111, 0xF8);
+ err += zc0301_write_reg(cam, 0x0112, 0x50);
+ err += zc0301_write_reg(cam, 0x0180, 0x00);
+ err += zc0301_write_reg(cam, 0x0019, 0x00);
+
+ err += zc0301_i2c_write(cam, 0x05, 0x0066);
+ err += zc0301_i2c_write(cam, 0x09, 0x02B2);
+ err += zc0301_i2c_write(cam, 0x10, 0x0002);
+
+ err += zc0301_write_reg(cam, 0x011D, 0x60);
+ err += zc0301_write_reg(cam, 0x0190, 0x00);
+ err += zc0301_write_reg(cam, 0x0191, 0x07);
+ err += zc0301_write_reg(cam, 0x0192, 0x8C);
+ err += zc0301_write_reg(cam, 0x0195, 0x00);
+ err += zc0301_write_reg(cam, 0x0196, 0x00);
+ err += zc0301_write_reg(cam, 0x0197, 0x8A);
+ err += zc0301_write_reg(cam, 0x018C, 0x10);
+ err += zc0301_write_reg(cam, 0x018F, 0x20);
+ err += zc0301_write_reg(cam, 0x01A9, 0x14);
+ err += zc0301_write_reg(cam, 0x01AA, 0x24);
+ err += zc0301_write_reg(cam, 0x001D, 0xD7);
+ err += zc0301_write_reg(cam, 0x001E, 0xF0);
+ err += zc0301_write_reg(cam, 0x001F, 0xF8);
+ err += zc0301_write_reg(cam, 0x0020, 0xFF);
+ err += zc0301_write_reg(cam, 0x01AD, 0x09);
+ err += zc0301_write_reg(cam, 0x01AE, 0x15);
+ err += zc0301_write_reg(cam, 0x0180, 0x40);
+ err += zc0301_write_reg(cam, 0x0180, 0x42);
+
+ msleep(100);
+
+ return err;
+}
+
+
+static struct zc0301_sensor pb0330 = {
+ .name = "PB-0330",
+ .init = &pb0330_init,
+ .cropcap = {
+ .bounds = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .defrect = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ },
+ .pix_format = {
+ .width = 640,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_JPEG,
+ .priv = 8,
+ },
+};
+
+
+int zc0301_probe_pb0330(struct zc0301_device* cam)
+{
+ int r0, err = 0;
+
+ err += zc0301_write_reg(cam, 0x0000, 0x01);
+ err += zc0301_write_reg(cam, 0x0010, 0x0a);
+ err += zc0301_write_reg(cam, 0x0001, 0x01);
+ err += zc0301_write_reg(cam, 0x0012, 0x03);
+ err += zc0301_write_reg(cam, 0x0012, 0x01);
+
+ msleep(10);
+
+ r0 = zc0301_i2c_read(cam, 0x00, 2);
+
+ if (r0 < 0 || err)
+ return -EIO;
+
+ if (r0 != 0x8243)
+ return -ENODEV;
+
+ zc0301_attach_sensor(cam, &pb0330);
+
+ return 0;
+}
/***************************************************************************
- * API for image sensors connected to the ZC030! Image Processor and *
+ * API for image sensors connected to the ZC0301 Image Processor and *
* Control Chip *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
/*****************************************************************************/
extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
+extern int zc0301_probe_pb0330(struct zc0301_device* cam);
#define ZC0301_SENSOR_TABLE \
/* Weak detections must go at the end of the list */ \
static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \
&zc0301_probe_pas202bcb, \
+ &zc0301_probe_pb0330, \
NULL, \
};
#define ZC0301_ID_TABLE \
static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, \
+ { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131B */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), }, \
{ ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \
{ ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700C, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
+ { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \
- { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \
+ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */ \
+ { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */ \
{ } \
};
#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */
#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */
-#define BUZ_MAX_INPUT 8
+#define BUZ_MAX_INPUT 16
#if VIDEO_MAX_FRAME <= 32
# define V4L_MAX_FRAME 32
/* Iomega */
BUZ,
+ /* AverMedia */
+ AVS6EYES,
+
/* total number of cards */
NUM_CARDS
};
/* is the /GWS line conected? */
u8 gws_not_connected;
+ /* avs6eyes mux setting */
+ u8 input_mux;
+
void (*init) (struct zoran * zr);
};
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/delay.h>
+
#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/spinlock.h>
#include <linux/sem.h>
#include <linux/kmod.h>
MODULE_PARM_DESC(default_input,
"Default input (0=Composite, 1=S-Video, 2=Internal)");
+static int default_mux = 1; /* 6 Eyes input selection */
+module_param(default_mux, int, 0);
+MODULE_PARM_DESC(default_mux,
+ "Default 6 Eyes mux setting (Input selection)");
+
static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */
module_param(default_norm, int, 0);
MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
GPIO(zr, 2, 1); // Set Composite input/output
}
+static void
+avs6eyes_init (struct zoran *zr)
+{
+ // AverMedia 6-Eyes original driver by Christer Weinigel
+
+ // Lifted straight from Christer's old driver and
+ // modified slightly by Martin Samuelsson.
+
+ int mux = default_mux; /* 1 = BT866, 7 = VID1 */
+
+ GPIO(zr, 4, 1); /* Bt866 SLEEP on */
+ udelay(2);
+
+ GPIO(zr, 0, 1); /* ZR36060 /RESET on */
+ GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */
+ GPIO(zr, 2, mux & 1); /* MUX S0 */
+ GPIO(zr, 3, 0); /* /FRAME on */
+ GPIO(zr, 4, 0); /* Bt866 SLEEP off */
+ GPIO(zr, 5, mux & 2); /* MUX S1 */
+ GPIO(zr, 6, 0); /* ? */
+ GPIO(zr, 7, mux & 4); /* MUX S2 */
+
+}
+
static char *
i2cid_to_modulename (u16 i2c_id)
{
static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 };
static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 };
+/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I
+ * copy Maxim's left shift hack for the 6 Eyes.
+ *
+ * Christer's driver used the unshifted norms, though...
+ * /Sam */
+static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 };
+static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 };
+
static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
{
.type = DC10_old,
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = DC10_new,
.gpcs = { -1, 1},
.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10plus_init,
}, {
.type = DC10plus,
.gpcs = { -1, 1 },
.vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10plus_init,
}, {
.type = DC30,
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = DC30plus,
.gpcs = { -1, 0 },
.vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 },
.gws_not_connected = 0,
+ .input_mux = 0,
.init = &dc10_init,
}, {
.type = LML33,
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &lml33_init,
}, {
.type = LML33R10,
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &lml33_init,
}, {
.type = BUZ,
.gpcs = { 3, 1 },
.vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 },
.gws_not_connected = 1,
+ .input_mux = 0,
.init = &buz_init,
+ }, {
+ .type = AVS6EYES,
+ .name = "6-Eyes",
+ /* AverMedia chose not to brand the 6-Eyes. Thus it
+ can't be autodetected, and requires card=x. */
+ .vendor_id = -1,
+ .device_id = -1,
+ .i2c_decoder = I2C_DRIVERID_KS0127,
+ .i2c_encoder = I2C_DRIVERID_BT866,
+ .video_codec = CODEC_TYPE_ZR36060,
+
+ .inputs = 10,
+ .input = {
+ { 0, "Composite 1" },
+ { 1, "Composite 2" },
+ { 2, "Composite 3" },
+ { 4, "Composite 4" },
+ { 5, "Composite 5" },
+ { 6, "Composite 6" },
+ { 8, "S-Video 1" },
+ { 9, "S-Video 2" },
+ {10, "S-Video 3" },
+ {15, "YCbCr" }
+ },
+ .norms = 2,
+ .tvn = {
+ &f50ccir601_avs6eyes,
+ &f60ccir601_avs6eyes,
+ NULL
+ },
+ .jpeg_int = ZR36057_ISR_GIRQ1,
+ .vsync_int = ZR36057_ISR_GIRQ0,
+ .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam
+ .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam
+ .gpcs = { 3, 1 }, // Validity unknown /Sam
+ .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 }, // Validity unknown /Sam
+ .gws_not_connected = 1,
+ .input_mux = 1,
+ .init = &avs6eyes_init,
}
+
};
/*
* All error messages are internal driver checking only! */
/* video display top and bottom registers */
- reg = (u32) zr->buffer.base +
+ reg = (long) zr->buffer.base +
zr->overlay_settings.x *
((zr->overlay_settings.format->depth + 7) / 8) +
zr->overlay_settings.y *
)
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include "videocodec.h"
#include <asm/io.h>
dprintk(3, KERN_DEBUG "%s: VIDIOCGCAP\n", ZR_DEVNAME(zr));
memset(vcap, 0, sizeof(struct video_capability));
- strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name));
+ strncpy(vcap->name, ZR_DEVNAME(zr), sizeof(vcap->name)-1);
vcap->type = ZORAN_VID_TYPE;
vcap->channels = zr->card.inputs;
dprintk(3, KERN_DEBUG "%s: VIDIOC_QUERYCAP\n", ZR_DEVNAME(zr));
memset(cap, 0, sizeof(*cap));
- strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card));
- strncpy(cap->driver, "zoran", sizeof(cap->driver));
+ strncpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)-1);
+ strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(zr->pci_dev));
cap->version =
memset(fmt, 0, sizeof(*fmt));
fmt->index = index;
fmt->type = type;
- strncpy(fmt->description, zoran_formats[i].name, 31);
+ strncpy(fmt->description, zoran_formats[i].name, sizeof(fmt->description)-1);
fmt->pixelformat = zoran_formats[i].fourcc;
if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED)
fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- strncpy(ctrl->name, "Brightness", 31);
+ strncpy(ctrl->name, "Brightness", sizeof(ctrl->name)-1);
break;
case V4L2_CID_CONTRAST:
- strncpy(ctrl->name, "Contrast", 31);
+ strncpy(ctrl->name, "Contrast", sizeof(ctrl->name)-1);
break;
case V4L2_CID_SATURATION:
- strncpy(ctrl->name, "Saturation", 31);
+ strncpy(ctrl->name, "Saturation", sizeof(ctrl->name)-1);
break;
case V4L2_CID_HUE:
- strncpy(ctrl->name, "Hue", 31);
+ strncpy(ctrl->name, "Hue", sizeof(ctrl->name)-1);
break;
}
&caps);
if (caps.flags & VIDEO_DECODER_AUTO) {
std->id = V4L2_STD_ALL;
- strncpy(std->name, "Autodetect", 31);
+ strncpy(std->name, "Autodetect", sizeof(std->name)-1);
return 0;
} else
return -EINVAL;
switch (std->index) {
case 0:
std->id = V4L2_STD_PAL;
- strncpy(std->name, "PAL", 31);
+ strncpy(std->name, "PAL", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[0]->Ht;
break;
case 1:
std->id = V4L2_STD_NTSC;
- strncpy(std->name, "NTSC", 31);
+ strncpy(std->name, "NTSC", sizeof(std->name)-1);
std->frameperiod.numerator = 1001;
std->frameperiod.denominator = 30000;
std->framelines = zr->card.tvn[1]->Ht;
break;
case 2:
std->id = V4L2_STD_SECAM;
- strncpy(std->name, "SECAM", 31);
+ strncpy(std->name, "SECAM", sizeof(std->name)-1);
std->frameperiod.numerator = 1;
std->frameperiod.denominator = 25;
std->framelines = zr->card.tvn[2]->Ht;
memset(outp, 0, sizeof(*outp));
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
- strncpy(outp->name, "Autodetect", 31);
+ strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
return 0;
}
#include <linux/seq_file.h>
#include <linux/ctype.h>
+#include <linux/poll.h>
#include <asm/io.h>
#include "videocodec.h"
#include <linux/config.h>
#include <linux/version.h>
+#define __OLD_VIDIOC_
+
#include "matroxfb_base.h"
#include "matroxfb_misc.h"
#include "matroxfb_accel.h"
/* Make sure that displays are compatible */
if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel)
- && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
- && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
- ) {
+ && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual)
+ && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length)
+ ) {
switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) {
case 16:
case 32:
int matroxfb_enable_irq(WPMINFO int reenable) {
u_int32_t bm;
-
+
if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400)
bm = 0x220;
else
mga_outl(M_IEN, mga_inl(M_IEN) | bm);
} else if (reenable) {
u_int32_t ien;
-
+
ien = mga_inl(M_IEN);
if ((ien & bm) != bm) {
printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
mga_setr(M_EXTVGA_INDEX, 0x00, p2);
}
matroxfb_DAC_unlock_irqrestore(flags);
-
+
update_crtc2(PMINFO pos);
CRITEND
static int matroxfb_open(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
-
+
DBG_LOOP(__FUNCTION__)
if (ACCESS_FBINFO(dead)) {
static int matroxfb_release(struct fb_info *info, int user)
{
MINFO_FROM_INFO(info);
-
+
DBG_LOOP(__FUNCTION__)
if (user) {
vblank->flags |= FB_VBLANK_VBLANKING;
if (test_bit(0, &ACCESS_FBINFO(irq_flags))) {
vblank->flags |= FB_VBLANK_HAVE_COUNT;
- /* Only one writer, aligned int value...
+ /* Only one writer, aligned int value...
it should work without lock and without atomic_t */
vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt;
}
{
void __user *argp = (void __user *)arg;
MINFO_FROM_INFO(info);
-
+
DBG(__FUNCTION__)
if (ACCESS_FBINFO(dead)) {
case VIDIOC_QUERYCAP:
{
struct v4l2_capability r;
-
+
memset(&r, 0, sizeof(r));
strcpy(r.driver, "matroxfb");
strcpy(r.card, "Matrox");
if (copy_to_user(argp, &r, sizeof(r)))
return -EFAULT;
return 0;
-
+
}
case VIDIOC_QUERYCTRL:
{
pci_read_config_dword(ACCESS_FBINFO(pcidev), PCI_COMMAND, &cmd);
mga_option &= 0x7FFFFFFF; /* clear BIG_ENDIAN */
mga_option |= MX_OPTION_BSWAP;
- /* disable palette snooping */
- cmd &= ~PCI_COMMAND_VGA_PALETTE;
+ /* disable palette snooping */
+ cmd &= ~PCI_COMMAND_VGA_PALETTE;
if (pci_dev_present(intel_82437)) {
if (!(mga_option & 0x20000000) && !ACCESS_FBINFO(devflags.nopciretry)) {
printk(KERN_WARNING "matroxfb: Disabling PCI retries due to i82437 present\n");
if (fv) {
tmp = fv * (vesafb_defined.upper_margin + vesafb_defined.yres
- + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
+ + vesafb_defined.lower_margin + vesafb_defined.vsync_len);
if ((tmp < fh) || (fh == 0)) fh = tmp;
}
if (fh) {
tmp = fh * (vesafb_defined.left_margin + vesafb_defined.xres
- + vesafb_defined.right_margin + vesafb_defined.hsync_len);
+ + vesafb_defined.right_margin + vesafb_defined.hsync_len);
if ((tmp < maxclk) || (maxclk == 0)) maxclk = tmp;
}
tmp = (maxclk + 499) / 500;
/* there is no console on this fb... but we have to initialize hardware
* until someone tells me what is proper thing to do */
- if (!ACCESS_FBINFO(initialized)) {
- printk(KERN_INFO "fb%d: initializing hardware\n",
- ACCESS_FBINFO(fbcon.node));
- /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
- * already before, so register_framebuffer works correctly. */
- vesafb_defined.activate |= FB_ACTIVATE_FORCE;
- fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
- }
+ if (!ACCESS_FBINFO(initialized)) {
+ printk(KERN_INFO "fb%d: initializing hardware\n",
+ ACCESS_FBINFO(fbcon.node));
+ /* We have to use FB_ACTIVATE_FORCE, as we had to put vesafb_defined to the fbcon.var
+ * already before, so register_framebuffer works correctly. */
+ vesafb_defined.activate |= FB_ACTIVATE_FORCE;
+ fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined);
+ }
return 0;
failVideoIO:;
else if (!strncmp(this_opt, "dfp:", 4)) {
dfp_type = simple_strtoul(this_opt+4, NULL, 0);
dfp = 1;
- }
+ }
#ifdef CONFIG_PPC_PMAC
else if (!strncmp(this_opt, "vmode:", 6)) {
unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0);
return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
}
-struct compat_dmx_event {
- dmx_event_t event;
- compat_time_t timeStamp;
- union
- {
- dmx_scrambling_status_t scrambling;
- } u;
-};
-
-static int do_dmx_get_event(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct dmx_event kevent;
- mm_segment_t old_fs = get_fs();
- int err;
-
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long) &kevent);
- set_fs(old_fs);
-
- if (!err) {
- struct compat_dmx_event __user *up = compat_ptr(arg);
-
- err = put_user(kevent.event, &up->event);
- err |= put_user(kevent.timeStamp, &up->timeStamp);
- err |= put_user(kevent.u.scrambling, &up->u.scrambling);
- if (err)
- err = -EFAULT;
- }
-
- return err;
-}
-
struct compat_video_event {
int32_t type;
compat_time_t timestamp;
#endif
/* dvb */
-HANDLE_IOCTL(DMX_GET_EVENT, do_dmx_get_event)
HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event)
HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture)
HANDLE_IOCTL(VIDEO_SET_SPU_PALETTE, do_video_set_spu_palette)
#define DMX_PES_PCR DMX_PES_PCR0
-typedef enum
-{
- DMX_SCRAMBLING_EV,
- DMX_FRONTEND_EV
-} dmx_event_t;
-
-
-typedef enum
-{
- DMX_SCRAMBLING_OFF,
- DMX_SCRAMBLING_ON
-} dmx_scrambling_status_t;
-
-
typedef struct dmx_filter
{
__u8 filter[DMX_FILTER_SIZE];
__u32 flags;
};
-
-struct dmx_event
-{
- dmx_event_t event;
- time_t timeStamp;
- union
- {
- dmx_scrambling_status_t scrambling;
- } u;
-};
-
typedef struct dmx_caps {
__u32 caps;
int num_decoders;
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
#define DMX_SET_PES_FILTER _IOW('o', 44, struct dmx_pes_filter_params)
#define DMX_SET_BUFFER_SIZE _IO('o', 45)
-#define DMX_GET_EVENT _IOR('o', 46, struct dmx_event)
#define DMX_GET_PES_PIDS _IOR('o', 47, __u16[5])
#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
#define I2C_DRIVERID_X1205 82 /* Xicor/Intersil X1205 RTC */
#define I2C_DRIVERID_PCF8563 83 /* Philips PCF8563 RTC */
#define I2C_DRIVERID_RS5C372 84 /* Ricoh RS5C372 RTC */
+#define I2C_DRIVERID_BT866 85 /* Conexant bt866 video encoder */
+#define I2C_DRIVERID_KS0127 86 /* Samsung ks0127 video decoder */
+#define I2C_DRIVERID_TLV320AIC23B 87 /* TI TLV320AIC23B audio codec */
#define I2C_DRIVERID_I2CDEV 900
#define I2C_DRIVERID_ARP 902 /* SMBus ARP Client */
+/*
+ * Video for Linux version 1 - OBSOLETE
+ *
+ * Header file for v4l1 drivers and applications, for
+ * Linux kernels 2.2.x or 2.4.x.
+ *
+ * Provides header for legacy drivers and applications
+ *
+ * See http://linuxtv.org for more info
+ *
+ */
#ifndef __LINUX_VIDEODEV_H
#define __LINUX_VIDEODEV_H
-#include <linux/types.h>
-
#define HAVE_V4L1 1
#include <linux/videodev2.h>
-#ifdef __KERNEL__
-
-#include <linux/mm.h>
-
-extern struct video_device* video_devdata(struct file*);
-
-#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
-static inline void
-video_device_create_file(struct video_device *vfd,
- struct class_device_attribute *attr)
-{
- class_device_create_file(&vfd->class_dev, attr);
-}
-static inline void
-video_device_remove_file(struct video_device *vfd,
- struct class_device_attribute *attr)
-{
- class_device_remove_file(&vfd->class_dev, attr);
-}
-
-#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
-/* helper functions to access driver private data. */
-static inline void *video_get_drvdata(struct video_device *dev)
-{
- return dev->priv;
-}
-
-static inline void video_set_drvdata(struct video_device *dev, void *data)
-{
- dev->priv = data;
-}
-#endif
-
-extern int video_exclusive_open(struct inode *inode, struct file *file);
-extern int video_exclusive_release(struct inode *inode, struct file *file);
-#endif /* __KERNEL__ */
-
struct video_capability
{
char name[32];
#define VID_HARDWARE_SAA7114H 37
#define VID_HARDWARE_SN9C102 38
#define VID_HARDWARE_ARV 39
+
#endif /* __LINUX_VIDEODEV_H */
/*
-#ifndef __LINUX_VIDEODEV2_H
-#define __LINUX_VIDEODEV2_H
/*
* Video for Linux Two
*
- * Header file for v4l or V4L2 drivers and applications, for
- * Linux kernels 2.2.x or 2.4.x.
+ * Header file for v4l or V4L2 drivers and applications
+ * with public API.
+ * All kernel-specific stuff were moved to media/v4l2-dev.h, so
+ * no #if __KERNEL tests are allowed here
*
- * See http://bytesex.org/v4l/ for API specs and other
- * v4l2 documentation.
+ * See http://linuxtv.org for more info
*
* Author: Bill Dirks <bdirks@pacbell.net>
* Justin Schoeman
* et al.
*/
+#ifndef __LINUX_VIDEODEV2_H
+#define __LINUX_VIDEODEV2_H
#ifdef __KERNEL__
-#include <linux/time.h> /* need struct timeval */
-#include <linux/poll.h>
-#include <linux/device.h>
-#include <linux/mutex.h>
-#endif
+#include <linux/time.h> /* need struct timeval */
#include <linux/compiler.h> /* need __user */
+#else
+#define __user
+#endif
+#include <linux/types.h>
-
-#define OBSOLETE_OWNER 1 /* It will be removed for 2.6.17 */
#define HAVE_V4L2 1
/*
* Common stuff for both V4L1 and V4L2
* Moved from videodev.h
*/
-
#define VIDEO_MAX_FRAME 32
#define VID_TYPE_CAPTURE 1 /* Can capture */
#define VID_TYPE_MJPEG_DECODER 4096 /* Can decode MJPEG streams */
#define VID_TYPE_MJPEG_ENCODER 8192 /* Can encode MJPEG streams */
-#ifdef __KERNEL__
-
-/* Minor device allocation */
-#define MINOR_VFL_TYPE_GRABBER_MIN 0
-#define MINOR_VFL_TYPE_GRABBER_MAX 63
-#define MINOR_VFL_TYPE_RADIO_MIN 64
-#define MINOR_VFL_TYPE_RADIO_MAX 127
-#define MINOR_VFL_TYPE_VTX_MIN 192
-#define MINOR_VFL_TYPE_VTX_MAX 223
-#define MINOR_VFL_TYPE_VBI_MIN 224
-#define MINOR_VFL_TYPE_VBI_MAX 255
-
-#define VFL_TYPE_GRABBER 0
-#define VFL_TYPE_VBI 1
-#define VFL_TYPE_RADIO 2
-#define VFL_TYPE_VTX 3
-
-struct video_device
-{
- /* device info */
- struct device *dev;
- char name[32];
- int type; /* v4l1 */
- int type2; /* v4l2 */
- int hardware;
- int minor;
-
- /* device ops + callbacks */
- const struct file_operations *fops;
- void (*release)(struct video_device *vfd);
-
-
-#if OBSOLETE_OWNER /* to be removed in 2.6.15 */
- /* obsolete -- fops->owner is used instead */
- struct module *owner;
- /* dev->driver_data will be used instead some day.
- * Use the video_{get|set}_drvdata() helper functions,
- * so the switch over will be transparent for you.
- * Or use {pci|usb}_{get|set}_drvdata() directly. */
- void *priv;
-#endif
-
- /* for videodev.c intenal usage -- please don't touch */
- int users; /* video_exclusive_{open|close} ... */
- struct mutex lock; /* ... helper function uses these */
- char devfs_name[64]; /* devfs */
- struct class_device class_dev; /* sysfs */
-};
-
-#define VIDEO_MAJOR 81
-
-extern int video_register_device(struct video_device *, int type, int nr);
-extern void video_unregister_device(struct video_device *);
-extern int video_usercopy(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg,
- int (*func)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg));
-
-/* helper functions to alloc / release struct video_device, the
- later can be used for video_device->release() */
-struct video_device *video_device_alloc(void);
-void video_device_release(struct video_device *vfd);
-
-#endif
-
/*
* M I S C E L L A N E O U S
*/
V4L2_CTRL_TYPE_BOOLEAN = 2,
V4L2_CTRL_TYPE_MENU = 3,
V4L2_CTRL_TYPE_BUTTON = 4,
+ V4L2_CTRL_TYPE_INTEGER64 = 5,
+ V4L2_CTRL_TYPE_CTRL_CLASS = 6,
};
enum v4l2_tuner_type {
/*
* V I D E O I M A G E F O R M A T
*/
-
struct v4l2_pix_format
{
__u32 width;
__u32 priv; /* private data, depends on pixelformat */
};
-/* Pixel format FOURCC depth Description */
+/* Pixel format FOURCC depth Description */
#define V4L2_PIX_FMT_RGB332 v4l2_fourcc('R','G','B','1') /* 8 RGB-3-3-2 */
#define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R','G','B','O') /* 16 RGB-5-5-5 */
#define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R','G','B','P') /* 16 RGB-5-6-5 */
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
#define V4L2_PIX_FMT_JPEG v4l2_fourcc('J','P','E','G') /* JFIF JPEG */
#define V4L2_PIX_FMT_DV v4l2_fourcc('d','v','s','d') /* 1394 */
-#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG */
+#define V4L2_PIX_FMT_MPEG v4l2_fourcc('M','P','E','G') /* MPEG-1/2/4 */
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
-
/*
* T I M E C O D E
*/
#define V4L2_TC_USERBITS_8BITCHARS 0x0008
/* The above is based on SMPTE timecodes */
-
+#ifdef __KERNEL__
/*
* M P E G C O M P R E S S I O N P A R A M E T E R S
*
- * ### WARNING: this is still work-in-progress right now, most likely
- * ### there will be some incompatible changes.
+ * ### WARNING: This experimental MPEG compression API is obsolete.
+ * ### It is replaced by the MPEG controls API.
+ * ### This old API will disappear in the near future!
*
*/
-
-
enum v4l2_bitrate_mode {
V4L2_BITRATE_NONE = 0, /* not specified */
V4L2_BITRATE_CBR, /* constant bitrate */
/* I don't expect the above being perfect yet ;) */
__u32 reserved_5[8];
};
+#endif
struct v4l2_jpegcompression
{
* allways use APP0 */
};
-
/*
* M E M O R Y - M A P P I N G B U F F E R S
*/
void __user *bitmap;
};
-
/*
* C A P T U R E P A R A M E T E R S
*/
__u32 readbuffers; /* # of buffers for read */
__u32 reserved[4];
};
+
/* Flags for 'capability' and 'capturemode' fields */
#define V4L2_MODE_HIGHQUALITY 0x0001 /* High quality imaging mode */
#define V4L2_CAP_TIMEPERFRAME 0x1000 /* timeperframe field is supported */
/*
* I N P U T I M A G E C R O P P I N G
*/
-
struct v4l2_cropcap {
enum v4l2_buf_type type;
struct v4l2_rect bounds;
__u32 reserved[4];
};
-
/*
* V I D E O I N P U T S
*/
__u32 status;
__u32 reserved[4];
};
+
/* Values for the 'type' field */
#define V4L2_INPUT_TYPE_TUNER 1
#define V4L2_INPUT_TYPE_CAMERA 2
__s32 value;
};
+struct v4l2_ext_control
+{
+ __u32 id;
+ __u32 reserved2[2];
+ union {
+ __s32 value;
+ __s64 value64;
+ void *reserved;
+ };
+};
+
+struct v4l2_ext_controls
+{
+ __u32 ctrl_class;
+ __u32 count;
+ __u32 error_idx;
+ __u32 reserved[2];
+ struct v4l2_ext_control *controls;
+};
+
+/* Values for ctrl_class field */
+#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
+#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
+
+#define V4L2_CTRL_ID_MASK (0x0fffffff)
+#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
+#define V4L2_CTRL_DRIVER_PRIV(id) (((id) & 0xffff) >= 0x1000)
+
/* Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
struct v4l2_queryctrl
{
/* Control flags */
#define V4L2_CTRL_FLAG_DISABLED 0x0001
#define V4L2_CTRL_FLAG_GRABBED 0x0002
+#define V4L2_CTRL_FLAG_READ_ONLY 0x0004
+#define V4L2_CTRL_FLAG_UPDATE 0x0008
+#define V4L2_CTRL_FLAG_INACTIVE 0x0010
+#define V4L2_CTRL_FLAG_SLIDER 0x0020
+
+/* Query flag, to be ORed with the control ID */
+#define V4L2_CTRL_FLAG_NEXT_CTRL 0x80000000
-/* Control IDs defined by V4L2 */
-#define V4L2_CID_BASE 0x00980900
+/* User-class control IDs defined by V4L2 */
+#define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_USER_BASE V4L2_CID_BASE
/* IDs reserved for driver specific controls */
#define V4L2_CID_PRIVATE_BASE 0x08000000
+#define V4L2_CID_USER_CLASS (V4L2_CTRL_CLASS_USER | 1)
#define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
#define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
#define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */
+/* MPEG-class control IDs defined by V4L2 */
+#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
+#define V4L2_CID_MPEG_CLASS (V4L2_CTRL_CLASS_MPEG | 1)
+
+/* MPEG streams */
+#define V4L2_CID_MPEG_STREAM_TYPE (V4L2_CID_MPEG_BASE+0)
+enum v4l2_mpeg_stream_type {
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS = 0, /* MPEG-2 program stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS = 1, /* MPEG-2 transport stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG1_SS = 2, /* MPEG-1 system stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG2_DVD = 3, /* MPEG-2 DVD-compatible stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG1_VCD = 4, /* MPEG-1 VCD-compatible stream */
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD = 5, /* MPEG-2 SVCD-compatible stream */
+};
+#define V4L2_CID_MPEG_STREAM_PID_PMT (V4L2_CID_MPEG_BASE+1)
+#define V4L2_CID_MPEG_STREAM_PID_AUDIO (V4L2_CID_MPEG_BASE+2)
+#define V4L2_CID_MPEG_STREAM_PID_VIDEO (V4L2_CID_MPEG_BASE+3)
+#define V4L2_CID_MPEG_STREAM_PID_PCR (V4L2_CID_MPEG_BASE+4)
+#define V4L2_CID_MPEG_STREAM_PES_ID_AUDIO (V4L2_CID_MPEG_BASE+5)
+#define V4L2_CID_MPEG_STREAM_PES_ID_VIDEO (V4L2_CID_MPEG_BASE+6)
+
+/* MPEG audio */
+#define V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ (V4L2_CID_MPEG_BASE+100)
+enum v4l2_mpeg_audio_sampling_freq {
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100 = 0,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000 = 1,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_ENCODING (V4L2_CID_MPEG_BASE+101)
+enum v4l2_mpeg_audio_encoding {
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_1 = 0,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2 = 1,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_3 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_L1_BITRATE (V4L2_CID_MPEG_BASE+102)
+enum v4l2_mpeg_audio_l1_bitrate {
+ V4L2_MPEG_AUDIO_L1_BITRATE_32K = 0,
+ V4L2_MPEG_AUDIO_L1_BITRATE_64K = 1,
+ V4L2_MPEG_AUDIO_L1_BITRATE_96K = 2,
+ V4L2_MPEG_AUDIO_L1_BITRATE_128K = 3,
+ V4L2_MPEG_AUDIO_L1_BITRATE_160K = 4,
+ V4L2_MPEG_AUDIO_L1_BITRATE_192K = 5,
+ V4L2_MPEG_AUDIO_L1_BITRATE_224K = 6,
+ V4L2_MPEG_AUDIO_L1_BITRATE_256K = 7,
+ V4L2_MPEG_AUDIO_L1_BITRATE_288K = 8,
+ V4L2_MPEG_AUDIO_L1_BITRATE_320K = 9,
+ V4L2_MPEG_AUDIO_L1_BITRATE_352K = 10,
+ V4L2_MPEG_AUDIO_L1_BITRATE_384K = 11,
+ V4L2_MPEG_AUDIO_L1_BITRATE_416K = 12,
+ V4L2_MPEG_AUDIO_L1_BITRATE_448K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L2_BITRATE (V4L2_CID_MPEG_BASE+103)
+enum v4l2_mpeg_audio_l2_bitrate {
+ V4L2_MPEG_AUDIO_L2_BITRATE_32K = 0,
+ V4L2_MPEG_AUDIO_L2_BITRATE_48K = 1,
+ V4L2_MPEG_AUDIO_L2_BITRATE_56K = 2,
+ V4L2_MPEG_AUDIO_L2_BITRATE_64K = 3,
+ V4L2_MPEG_AUDIO_L2_BITRATE_80K = 4,
+ V4L2_MPEG_AUDIO_L2_BITRATE_96K = 5,
+ V4L2_MPEG_AUDIO_L2_BITRATE_112K = 6,
+ V4L2_MPEG_AUDIO_L2_BITRATE_128K = 7,
+ V4L2_MPEG_AUDIO_L2_BITRATE_160K = 8,
+ V4L2_MPEG_AUDIO_L2_BITRATE_192K = 9,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K = 10,
+ V4L2_MPEG_AUDIO_L2_BITRATE_256K = 11,
+ V4L2_MPEG_AUDIO_L2_BITRATE_320K = 12,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_L3_BITRATE (V4L2_CID_MPEG_BASE+104)
+enum v4l2_mpeg_audio_l3_bitrate {
+ V4L2_MPEG_AUDIO_L3_BITRATE_32K = 0,
+ V4L2_MPEG_AUDIO_L3_BITRATE_40K = 1,
+ V4L2_MPEG_AUDIO_L3_BITRATE_48K = 2,
+ V4L2_MPEG_AUDIO_L3_BITRATE_56K = 3,
+ V4L2_MPEG_AUDIO_L3_BITRATE_64K = 4,
+ V4L2_MPEG_AUDIO_L3_BITRATE_80K = 5,
+ V4L2_MPEG_AUDIO_L3_BITRATE_96K = 6,
+ V4L2_MPEG_AUDIO_L3_BITRATE_112K = 7,
+ V4L2_MPEG_AUDIO_L3_BITRATE_128K = 8,
+ V4L2_MPEG_AUDIO_L3_BITRATE_160K = 9,
+ V4L2_MPEG_AUDIO_L3_BITRATE_192K = 10,
+ V4L2_MPEG_AUDIO_L3_BITRATE_224K = 11,
+ V4L2_MPEG_AUDIO_L3_BITRATE_256K = 12,
+ V4L2_MPEG_AUDIO_L3_BITRATE_320K = 13,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE (V4L2_CID_MPEG_BASE+105)
+enum v4l2_mpeg_audio_mode {
+ V4L2_MPEG_AUDIO_MODE_STEREO = 0,
+ V4L2_MPEG_AUDIO_MODE_JOINT_STEREO = 1,
+ V4L2_MPEG_AUDIO_MODE_DUAL = 2,
+ V4L2_MPEG_AUDIO_MODE_MONO = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_MODE_EXTENSION (V4L2_CID_MPEG_BASE+106)
+enum v4l2_mpeg_audio_mode_extension {
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4 = 0,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_8 = 1,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_12 = 2,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16 = 3,
+};
+#define V4L2_CID_MPEG_AUDIO_EMPHASIS (V4L2_CID_MPEG_BASE+107)
+enum v4l2_mpeg_audio_emphasis {
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE = 0,
+ V4L2_MPEG_AUDIO_EMPHASIS_50_DIV_15_uS = 1,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17 = 2,
+};
+#define V4L2_CID_MPEG_AUDIO_CRC (V4L2_CID_MPEG_BASE+108)
+enum v4l2_mpeg_audio_crc {
+ V4L2_MPEG_AUDIO_CRC_NONE = 0,
+ V4L2_MPEG_AUDIO_CRC_CRC16 = 1,
+};
+
+/* MPEG video */
+#define V4L2_CID_MPEG_VIDEO_ENCODING (V4L2_CID_MPEG_BASE+200)
+enum v4l2_mpeg_video_encoding {
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 = 0,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2 = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_ASPECT (V4L2_CID_MPEG_BASE+201)
+enum v4l2_mpeg_video_aspect {
+ V4L2_MPEG_VIDEO_ASPECT_1x1 = 0,
+ V4L2_MPEG_VIDEO_ASPECT_4x3 = 1,
+ V4L2_MPEG_VIDEO_ASPECT_16x9 = 2,
+ V4L2_MPEG_VIDEO_ASPECT_221x100 = 3,
+};
+#define V4L2_CID_MPEG_VIDEO_B_FRAMES (V4L2_CID_MPEG_BASE+202)
+#define V4L2_CID_MPEG_VIDEO_GOP_SIZE (V4L2_CID_MPEG_BASE+203)
+#define V4L2_CID_MPEG_VIDEO_GOP_CLOSURE (V4L2_CID_MPEG_BASE+204)
+#define V4L2_CID_MPEG_VIDEO_PULLDOWN (V4L2_CID_MPEG_BASE+205)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_MODE (V4L2_CID_MPEG_BASE+206)
+enum v4l2_mpeg_video_bitrate_mode {
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR = 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR = 1,
+};
+#define V4L2_CID_MPEG_VIDEO_BITRATE (V4L2_CID_MPEG_BASE+207)
+#define V4L2_CID_MPEG_VIDEO_BITRATE_PEAK (V4L2_CID_MPEG_BASE+208)
+#define V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION (V4L2_CID_MPEG_BASE+209)
+
+/* MPEG-class control IDs specific to the CX2584x driver as defined by V4L2 */
+#define V4L2_CID_MPEG_CX2341X_BASE (V4L2_CTRL_CLASS_MPEG | 0x1000)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+0)
+enum v4l2_mpeg_cx2341x_video_spatial_filter_mode {
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL = 0,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+1)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+2)
+enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type {
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF = 0,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_VERT = 2,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_HV_SEPARABLE = 3,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+3)
+enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type {
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF = 0,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE (V4L2_CID_MPEG_CX2341X_BASE+4)
+enum v4l2_mpeg_cx2341x_video_temporal_filter_mode {
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL = 0,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO = 1,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER (V4L2_CID_MPEG_CX2341X_BASE+5)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE (V4L2_CID_MPEG_CX2341X_BASE+6)
+enum v4l2_mpeg_cx2341x_video_median_filter_type {
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF = 0,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR = 1,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_VERT = 2,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_HOR_VERT = 3,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG = 4,
+};
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+7)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+8)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM (V4L2_CID_MPEG_CX2341X_BASE+9)
+#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10)
+
/*
* T U N I N G
*/
__u32 mode;
__u32 reserved[2];
};
+
/* Flags for the 'capability' field */
#define V4L2_AUDCAP_STEREO 0x00001
#define V4L2_AUDCAP_AVL 0x00002
*/
/* Raw VBI */
-
struct v4l2_vbi_format
{
__u32 sampling_rate; /* in 1 Hz */
} parm;
};
-
-
/*
* I O C T L C O D E S F O R V I D E O D E V I C E S
*
#define VIDIOC_ENUM_FMT _IOWR ('V', 2, struct v4l2_fmtdesc)
#define VIDIOC_G_FMT _IOWR ('V', 4, struct v4l2_format)
#define VIDIOC_S_FMT _IOWR ('V', 5, struct v4l2_format)
+#ifdef __KERNEL__
#define VIDIOC_G_MPEGCOMP _IOR ('V', 6, struct v4l2_mpeg_compression)
#define VIDIOC_S_MPEGCOMP _IOW ('V', 7, struct v4l2_mpeg_compression)
+#endif
#define VIDIOC_REQBUFS _IOWR ('V', 8, struct v4l2_requestbuffers)
#define VIDIOC_QUERYBUF _IOWR ('V', 9, struct v4l2_buffer)
#define VIDIOC_G_FBUF _IOR ('V', 10, struct v4l2_framebuffer)
#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap)
#endif
#define VIDIOC_LOG_STATUS _IO ('V', 70)
+#define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls)
+#define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls)
+#define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls)
+#ifdef __OLD_VIDIOC_
/* for compatibility, will go away some day */
#define VIDIOC_OVERLAY_OLD _IOWR ('V', 14, int)
#define VIDIOC_S_PARM_OLD _IOW ('V', 22, struct v4l2_streamparm)
#define VIDIOC_G_AUDIO_OLD _IOWR ('V', 33, struct v4l2_audio)
#define VIDIOC_G_AUDOUT_OLD _IOWR ('V', 49, struct v4l2_audioout)
#define VIDIOC_CROPCAP_OLD _IOR ('V', 58, struct v4l2_cropcap)
-
-#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
-
-
-#ifdef __KERNEL__
-/*
- *
- * V 4 L 2 D R I V E R H E L P E R A P I
- *
- * Some commonly needed functions for drivers (v4l2-common.o module)
- */
-#include <linux/fs.h>
-
-/* Video standard functions */
-extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
-extern int v4l2_video_std_construct(struct v4l2_standard *vs,
- int id, char *name);
-
-/* prority handling */
-struct v4l2_prio_state {
- atomic_t prios[4];
-};
-int v4l2_prio_init(struct v4l2_prio_state *global);
-int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
- enum v4l2_priority new);
-int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
-int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
-enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
-int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
-
-/* names for fancy debug output */
-extern char *v4l2_field_names[];
-extern char *v4l2_type_names[];
-
-/* Compatibility layer interface -- v4l1-compat module */
-typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg);
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
- int cmd, void *arg, v4l2_kioctl driver_ioctl);
-#else
-#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
#endif
-/* 32 Bits compatibility layer for 64 bits processors */
-extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
- unsigned long arg);
-
+#define BASE_VIDIOC_PRIVATE 192 /* 192-255 are private */
-#endif /* __KERNEL__ */
#endif /* __LINUX_VIDEODEV2_H */
/*
--- /dev/null
+/*
+ cx23415/6 header containing common defines.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef CX2341X_H
+#define CX2341X_H
+
+enum cx2341x_port {
+ CX2341X_PORT_MEMORY = 0,
+ CX2341X_PORT_STREAMING = 1,
+ CX2341X_PORT_SERIAL = 2
+};
+
+struct cx2341x_mpeg_params {
+ /* misc */
+ enum cx2341x_port port;
+ u16 width;
+ u16 height;
+ u16 is_50hz;
+
+ /* stream */
+ enum v4l2_mpeg_stream_type stream_type;
+
+ /* audio */
+ enum v4l2_mpeg_audio_sampling_freq audio_sampling_freq;
+ enum v4l2_mpeg_audio_encoding audio_encoding;
+ enum v4l2_mpeg_audio_l2_bitrate audio_l2_bitrate;
+ enum v4l2_mpeg_audio_mode audio_mode;
+ enum v4l2_mpeg_audio_mode_extension audio_mode_extension;
+ enum v4l2_mpeg_audio_emphasis audio_emphasis;
+ enum v4l2_mpeg_audio_crc audio_crc;
+ u8 audio_properties;
+
+ /* video */
+ enum v4l2_mpeg_video_encoding video_encoding;
+ enum v4l2_mpeg_video_aspect video_aspect;
+ u16 video_b_frames;
+ u16 video_gop_size;
+ u16 video_gop_closure;
+ u16 video_pulldown;
+ enum v4l2_mpeg_video_bitrate_mode video_bitrate_mode;
+ u32 video_bitrate;
+ u32 video_bitrate_peak;
+ u16 video_temporal_decimation;
+
+ /* encoding filters */
+ enum v4l2_mpeg_cx2341x_video_spatial_filter_mode video_spatial_filter_mode;
+ u16 video_spatial_filter;
+ enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type video_luma_spatial_filter_type;
+ enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type video_chroma_spatial_filter_type;
+ enum v4l2_mpeg_cx2341x_video_temporal_filter_mode video_temporal_filter_mode;
+ u16 video_temporal_filter;
+ enum v4l2_mpeg_cx2341x_video_median_filter_type video_median_filter_type;
+ u16 video_luma_median_filter_top;
+ u16 video_luma_median_filter_bottom;
+ u16 video_chroma_median_filter_top;
+ u16 video_chroma_median_filter_bottom;
+};
+
+#define CX2341X_MBOX_MAX_DATA 16
+
+extern const u32 cx2341x_mpeg_ctrls[];
+typedef int (*cx2341x_mbox_func)(void *priv, int cmd, int in, int out,
+ u32 data[CX2341X_MBOX_MAX_DATA]);
+int cx2341x_update(void *priv, cx2341x_mbox_func func,
+ const struct cx2341x_mpeg_params *old,
+ const struct cx2341x_mpeg_params *new);
+int cx2341x_ctrl_query(struct cx2341x_mpeg_params *params,
+ struct v4l2_queryctrl *qctrl);
+const char **cx2341x_ctrl_get_menu(u32 id);
+int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params,
+ struct v4l2_ext_controls *ctrls, int cmd);
+void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
+void cx2341x_log_status(struct cx2341x_mpeg_params *p, int cardid);
+
+/* Firmware names */
+#define CX2341X_FIRM_ENC_FILENAME "v4l-cx2341x-enc.fw"
+/* Decoder firmware for the cx23415 only */
+#define CX2341X_FIRM_DEC_FILENAME "v4l-cx2341x-dec.fw"
+
+/* Firmware API commands */
+
+/* MPEG decoder API, specific to the cx23415 */
+#define CX2341X_DEC_PING_FW 0x00
+#define CX2341X_DEC_START_PLAYBACK 0x01
+#define CX2341X_DEC_STOP_PLAYBACK 0x02
+#define CX2341X_DEC_SET_PLAYBACK_SPEED 0x03
+#define CX2341X_DEC_STEP_VIDEO 0x05
+#define CX2341X_DEC_SET_DMA_BLOCK_SIZE 0x08
+#define CX2341X_DEC_GET_XFER_INFO 0x09
+#define CX2341X_DEC_GET_DMA_STATUS 0x0a
+#define CX2341X_DEC_SCHED_DMA_FROM_HOST 0x0b
+#define CX2341X_DEC_PAUSE_PLAYBACK 0x0d
+#define CX2341X_DEC_HALT_FW 0x0e
+#define CX2341X_DEC_SET_STANDARD 0x10
+#define CX2341X_DEC_GET_VERSION 0x11
+#define CX2341X_DEC_SET_STREAM_INPUT 0x14
+#define CX2341X_DEC_GET_TIMING_INFO 0x15
+#define CX2341X_DEC_SET_AUDIO_MODE 0x16
+#define CX2341X_DEC_SET_EVENT_NOTIFICATION 0x17
+#define CX2341X_DEC_SET_DISPLAY_BUFFERS 0x18
+#define CX2341X_DEC_EXTRACT_VBI 0x19
+#define CX2341X_DEC_SET_DECODER_SOURCE 0x1a
+#define CX2341X_DEC_SET_AUDIO_OUTPUT 0x1b
+#define CX2341X_DEC_SET_AV_DELAY 0x1c
+#define CX2341X_DEC_SET_PREBUFFERING 0x1e
+
+/* MPEG encoder API */
+#define CX2341X_ENC_PING_FW 0x80
+#define CX2341X_ENC_START_CAPTURE 0x81
+#define CX2341X_ENC_STOP_CAPTURE 0x82
+#define CX2341X_ENC_SET_AUDIO_ID 0x89
+#define CX2341X_ENC_SET_VIDEO_ID 0x8b
+#define CX2341X_ENC_SET_PCR_ID 0x8d
+#define CX2341X_ENC_SET_FRAME_RATE 0x8f
+#define CX2341X_ENC_SET_FRAME_SIZE 0x91
+#define CX2341X_ENC_SET_BIT_RATE 0x95
+#define CX2341X_ENC_SET_GOP_PROPERTIES 0x97
+#define CX2341X_ENC_SET_ASPECT_RATIO 0x99
+#define CX2341X_ENC_SET_DNR_FILTER_MODE 0x9b
+#define CX2341X_ENC_SET_DNR_FILTER_PROPS 0x9d
+#define CX2341X_ENC_SET_CORING_LEVELS 0x9f
+#define CX2341X_ENC_SET_SPATIAL_FILTER_TYPE 0xa1
+#define CX2341X_ENC_SET_3_2_PULLDOWN 0xb1
+#define CX2341X_ENC_SET_VBI_LINE 0xb7
+#define CX2341X_ENC_SET_STREAM_TYPE 0xb9
+#define CX2341X_ENC_SET_OUTPUT_PORT 0xbb
+#define CX2341X_ENC_SET_AUDIO_PROPERTIES 0xbd
+#define CX2341X_ENC_HALT_FW 0xc3
+#define CX2341X_ENC_GET_VERSION 0xc4
+#define CX2341X_ENC_SET_GOP_CLOSURE 0xc5
+#define CX2341X_ENC_GET_SEQ_END 0xc6
+#define CX2341X_ENC_SET_PGM_INDEX_INFO 0xc7
+#define CX2341X_ENC_SET_VBI_CONFIG 0xc8
+#define CX2341X_ENC_SET_DMA_BLOCK_SIZE 0xc9
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_10 0xca
+#define CX2341X_ENC_GET_PREV_DMA_INFO_MB_9 0xcb
+#define CX2341X_ENC_SCHED_DMA_TO_HOST 0xcc
+#define CX2341X_ENC_INITIALIZE_INPUT 0xcd
+#define CX2341X_ENC_SET_FRAME_DROP_RATE 0xd0
+#define CX2341X_ENC_PAUSE_ENCODER 0xd2
+#define CX2341X_ENC_REFRESH_INPUT 0xd3
+#define CX2341X_ENC_SET_COPYRIGHT 0xd4
+#define CX2341X_ENC_SET_EVENT_NOTIFICATION 0xd5
+#define CX2341X_ENC_SET_NUM_VSYNC_LINES 0xd6
+#define CX2341X_ENC_SET_PLACEHOLDER 0xd7
+#define CX2341X_ENC_MUTE_VIDEO 0xd9
+#define CX2341X_ENC_MUTE_AUDIO 0xda
+#define CX2341X_ENC_UNKNOWN 0xdb
+#define CX2341X_ENC_MISC 0xdc
+
+/* OSD API, specific to the cx23415 */
+#define CX2341X_OSD_GET_FRAMEBUFFER 0x41
+#define CX2341X_OSD_GET_PIXEL_FORMAT 0x42
+#define CX2341X_OSD_SET_PIXEL_FORMAT 0x43
+#define CX2341X_OSD_GET_STATE 0x44
+#define CX2341X_OSD_SET_STATE 0x45
+#define CX2341X_OSD_GET_OSD_COORDS 0x46
+#define CX2341X_OSD_SET_OSD_COORDS 0x47
+#define CX2341X_OSD_GET_SCREEN_COORDS 0x48
+#define CX2341X_OSD_SET_SCREEN_COORDS 0x49
+#define CX2341X_OSD_GET_GLOBAL_ALPHA 0x4a
+#define CX2341X_OSD_SET_GLOBAL_ALPHA 0x4b
+#define CX2341X_OSD_SET_BLEND_COORDS 0x4c
+#define CX2341X_OSD_GET_FLICKER_STATE 0x4f
+#define CX2341X_OSD_SET_FLICKER_STATE 0x50
+#define CX2341X_OSD_BLT_COPY 0x52
+#define CX2341X_OSD_BLT_FILL 0x53
+#define CX2341X_OSD_BLT_TEXT 0x54
+#define CX2341X_OSD_SET_FRAMEBUFFER_WINDOW 0x56
+#define CX2341X_OSD_SET_CHROMA_KEY 0x60
+#define CX2341X_OSD_GET_ALPHA_CONTENT_INDEX 0x61
+#define CX2341X_OSD_SET_ALPHA_CONTENT_INDEX 0x62
+
+#endif /* CX2341X_H */
extern IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_grey[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_flydvb[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_cinergy[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
-extern IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
#endif
int (*get_key)(struct IR_i2c*, u32*, u32*);
};
-int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_grey(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
+int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
#endif
#define __LINUX_OVCAMCHIP_H
#include <linux/videodev.h>
+#include <media/v4l2-common.h>
#include <linux/i2c.h>
/* --------------------------------- */
--- /dev/null
+#ifndef PWC_IOCTL_H
+#define PWC_IOCTL_H
+
+/* (C) 2001-2004 Nemosoft Unv.
+ (C) 2004-2006 Luc Saillard (luc@saillard.org)
+
+ NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
+ driver and thus may have bugs that are not present in the original version.
+ Please send bug reports and support requests to <luc@saillard.org>.
+ The decompression routines have been implemented by reverse-engineering the
+ Nemosoft binary pwcx module. Caveat emptor.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+/* This is pwc-ioctl.h belonging to PWC 10.0.10
+ It contains structures and defines to communicate from user space
+ directly to the driver.
+ */
+
+/*
+ Changes
+ 2001/08/03 Alvarado Added ioctl constants to access methods for
+ changing white balance and red/blue gains
+ 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE
+ 2003/12/13 Nemosft Unv. Some modifications to make interfacing to
+ PWCX easier
+ 2006/01/01 Luc Saillard Add raw format definition
+ */
+
+/* These are private ioctl() commands, specific for the Philips webcams.
+ They contain functions not found in other webcams, and settings not
+ specified in the Video4Linux API.
+
+ The #define names are built up like follows:
+ VIDIOC VIDeo IOCtl prefix
+ PWC Philps WebCam
+ G optional: Get
+ S optional: Set
+ ... the function
+ */
+
+#include <linux/types.h>
+#include <linux/version.h>
+
+
+ /* Enumeration of image sizes */
+#define PSZ_SQCIF 0x00
+#define PSZ_QSIF 0x01
+#define PSZ_QCIF 0x02
+#define PSZ_SIF 0x03
+#define PSZ_CIF 0x04
+#define PSZ_VGA 0x05
+#define PSZ_MAX 6
+
+
+/* The frame rate is encoded in the video_window.flags parameter using
+ the upper 16 bits, since some flags are defined nowadays. The following
+ defines provide a mask and shift to filter out this value.
+ This value can also be passing using the private flag when using v4l2 and
+ VIDIOC_S_FMT ioctl.
+
+ In 'Snapshot' mode the camera freezes its automatic exposure and colour
+ balance controls.
+ */
+#define PWC_FPS_SHIFT 16
+#define PWC_FPS_MASK 0x00FF0000
+#define PWC_FPS_FRMASK 0x003F0000
+#define PWC_FPS_SNAPSHOT 0x00400000
+#define PWC_QLT_MASK 0x03000000
+#define PWC_QLT_SHIFT 24
+
+
+/* structure for transferring x & y coordinates */
+struct pwc_coord
+{
+ int x, y; /* guess what */
+ int size; /* size, or offset */
+};
+
+
+/* Used with VIDIOCPWCPROBE */
+struct pwc_probe
+{
+ char name[32];
+ int type;
+};
+
+struct pwc_serial
+{
+ char serial[30]; /* String with serial number. Contains terminating 0 */
+};
+
+/* pwc_whitebalance.mode values */
+#define PWC_WB_INDOOR 0
+#define PWC_WB_OUTDOOR 1
+#define PWC_WB_FL 2
+#define PWC_WB_MANUAL 3
+#define PWC_WB_AUTO 4
+
+/* Used with VIDIOCPWC[SG]AWB (Auto White Balance).
+ Set mode to one of the PWC_WB_* values above.
+ *red and *blue are the respective gains of these colour components inside
+ the camera; range 0..65535
+ When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read;
+ otherwise undefined.
+ 'read_red' and 'read_blue' are read-only.
+*/
+struct pwc_whitebalance
+{
+ int mode;
+ int manual_red, manual_blue; /* R/W */
+ int read_red, read_blue; /* R/O */
+};
+
+/*
+ 'control_speed' and 'control_delay' are used in automatic whitebalance mode,
+ and tell the camera how fast it should react to changes in lighting, and
+ with how much delay. Valid values are 0..65535.
+*/
+struct pwc_wb_speed
+{
+ int control_speed;
+ int control_delay;
+
+};
+
+/* Used with VIDIOCPWC[SG]LED */
+struct pwc_leds
+{
+ int led_on; /* Led on-time; range = 0..25000 */
+ int led_off; /* Led off-time; range = 0..25000 */
+};
+
+/* Image size (used with GREALSIZE) */
+struct pwc_imagesize
+{
+ int width;
+ int height;
+};
+
+/* Defines and structures for Motorized Pan & Tilt */
+#define PWC_MPT_PAN 0x01
+#define PWC_MPT_TILT 0x02
+#define PWC_MPT_TIMEOUT 0x04 /* for status */
+
+/* Set angles; when absolute != 0, the angle is absolute and the
+ driver calculates the relative offset for you. This can only
+ be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns
+ absolute angles.
+ */
+struct pwc_mpt_angles
+{
+ int absolute; /* write-only */
+ int pan; /* degrees * 100 */
+ int tilt; /* degress * 100 */
+};
+
+/* Range of angles of the camera, both horizontally and vertically.
+ */
+struct pwc_mpt_range
+{
+ int pan_min, pan_max; /* degrees * 100 */
+ int tilt_min, tilt_max;
+};
+
+struct pwc_mpt_status
+{
+ int status;
+ int time_pan;
+ int time_tilt;
+};
+
+
+/* This is used for out-of-kernel decompression. With it, you can get
+ all the necessary information to initialize and use the decompressor
+ routines in standalone applications.
+ */
+struct pwc_video_command
+{
+ int type; /* camera type (645, 675, 730, etc.) */
+ int release; /* release number */
+
+ int size; /* one of PSZ_* */
+ int alternate;
+ int command_len; /* length of USB video command */
+ unsigned char command_buf[13]; /* Actual USB video command */
+ int bandlength; /* >0 = compressed */
+ int frame_size; /* Size of one (un)compressed frame */
+};
+
+/* Flags for PWCX subroutines. Not all modules honour all flags. */
+#define PWCX_FLAG_PLANAR 0x0001
+#define PWCX_FLAG_BAYER 0x0008
+
+
+/* IOCTL definitions */
+
+ /* Restore user settings */
+#define VIDIOCPWCRUSER _IO('v', 192)
+ /* Save user settings */
+#define VIDIOCPWCSUSER _IO('v', 193)
+ /* Restore factory settings */
+#define VIDIOCPWCFACTORY _IO('v', 194)
+
+ /* You can manipulate the compression factor. A compression preference of 0
+ means use uncompressed modes when available; 1 is low compression, 2 is
+ medium and 3 is high compression preferred. Of course, the higher the
+ compression, the lower the bandwidth used but more chance of artefacts
+ in the image. The driver automatically chooses a higher compression when
+ the preferred mode is not available.
+ */
+ /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */
+#define VIDIOCPWCSCQUAL _IOW('v', 195, int)
+ /* Get preferred compression quality */
+#define VIDIOCPWCGCQUAL _IOR('v', 195, int)
+
+
+/* Retrieve serial number of camera */
+#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial)
+
+ /* This is a probe function; since so many devices are supported, it
+ becomes difficult to include all the names in programs that want to
+ check for the enhanced Philips stuff. So in stead, try this PROBE;
+ it returns a structure with the original name, and the corresponding
+ Philips type.
+ To use, fill the structure with zeroes, call PROBE and if that succeeds,
+ compare the name with that returned from VIDIOCGCAP; they should be the
+ same. If so, you can be assured it is a Philips (OEM) cam and the type
+ is valid.
+ */
+#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe)
+
+ /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */
+#define VIDIOCPWCSAGC _IOW('v', 200, int)
+ /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCGAGC _IOR('v', 200, int)
+ /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */
+#define VIDIOCPWCSSHUTTER _IOW('v', 201, int)
+
+ /* Color compensation (Auto White Balance) */
+#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance)
+#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance)
+
+ /* Auto WB speed */
+#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed)
+#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed)
+
+ /* LEDs on/off/blink; int range 0..65535 */
+#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds)
+#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds)
+
+ /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */
+#define VIDIOCPWCSCONTOUR _IOW('v', 206, int)
+#define VIDIOCPWCGCONTOUR _IOR('v', 206, int)
+
+ /* Backlight compensation; 0 = off, otherwise on */
+#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int)
+#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int)
+
+ /* Flickerless mode; = 0 off, otherwise on */
+#define VIDIOCPWCSFLICKER _IOW('v', 208, int)
+#define VIDIOCPWCGFLICKER _IOR('v', 208, int)
+
+ /* Dynamic noise reduction; 0 off, 3 = high noise reduction */
+#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int)
+#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int)
+
+ /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */
+#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize)
+
+ /* Motorized pan & tilt functions */
+#define VIDIOCPWCMPTRESET _IOW('v', 211, int)
+#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range)
+#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles)
+#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status)
+
+ /* Get the USB set-video command; needed for initializing libpwcx */
+#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command)
+struct pwc_table_init_buffer {
+ int len;
+ char *buffer;
+
+};
+#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer)
+
+/*
+ * This is private command used when communicating with v4l2.
+ * In the future all private ioctl will be remove/replace to
+ * use interface offer by v4l2.
+ */
+
+#define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0)
+#define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4)
+#define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5)
+#define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6)
+#define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7)
+#define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8)
+
+struct pwc_raw_frame {
+ __le16 type; /* type of the webcam */
+ __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */
+ __u8 cmd[4]; /* the four byte of the command (in case of nala,
+ only the first 3 bytes is filled) */
+ __u8 rawframe[0]; /* frame_size = H/4*vbandlength */
+} __attribute__ ((packed));
+
+
+#endif
/*
- saa7115.h - definition for saa7113/4/5 inputs
+ saa7115.h - definition for saa7113/4/5 inputs and frequency flags
Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
#define SAA7115_SVIDEO2 8
#define SAA7115_SVIDEO3 9
+/* SAA7115 v4l2_crystal_freq frequency values */
+#define SAA7115_FREQ_32_11_MHZ 32110000 /* 32.11 MHz crystal, SAA7114/5 only */
+#define SAA7115_FREQ_24_576_MHZ 24576000 /* 24.576 MHz crystal */
+
+/* SAA7115 v4l2_crystal_freq audio clock control flags */
+#define SAA7115_FREQ_FL_UCGC (1 << 0) /* SA 3A[7], UCGC, SAA7115 only */
+#define SAA7115_FREQ_FL_CGCDIV (1 << 1) /* SA 3A[6], CGCDIV, SAA7115 only */
+#define SAA7115_FREQ_FL_APLL (1 << 2) /* SA 3A[3], APLL, SAA7114/5 only */
+
#endif
#define __SAA7146_VV__
#include <linux/videodev.h>
-
+#include <media/v4l2-common.h>
#include <media/saa7146.h>
#include <media/video-buf.h>
#include <linux/videodev2.h>
#include <media/tuner-types.h>
+extern int tuner_debug;
+
#define ADDR_UNSET (255)
#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */
#define TUNER_TEA5767 62 /* Only FM Radio Tuner */
#define TUNER_PHILIPS_FMD1216ME_MK3 63
-#define TUNER_LG_TDVS_H062F 64 /* DViCO FusionHDTV 5 */
+#define TUNER_LG_TDVS_H06XF 64 /* TDVS H061F, H062F, H064F */
#define TUNER_YMEC_TVF66T5_B_DFF 65 /* Acorp Y878F */
#define TUNER_LG_TALN 66
#define TUNER_PHILIPS_TD1316 67
#define TUNER_XCEIVE_XC3028 71
#define TUNER_THOMSON_FE6600 72 /* DViCO FusionHDTV DVB-T Hybrid */
+#define TUNER_SAMSUNG_TCPG_6121P30A 73 /* Hauppauge PVR-500 PAL */
+#define TUNER_TDA9887 74 /* This tuner should be used only internally */
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
int using_v4l2;
+ /* used by tda9887 */
+ unsigned int tda9887_config;
+ unsigned char tda9887_data[4];
+
/* used by MT2032 */
unsigned int xogc;
unsigned int radio_if2;
void (*set_radio_freq)(struct i2c_client *c, unsigned int freq);
int (*has_signal)(struct i2c_client *c);
int (*is_stereo)(struct i2c_client *c);
+ int (*get_afc)(struct i2c_client *c);
+ void (*tuner_status)(struct i2c_client *c);
void (*standby)(struct i2c_client *c);
};
extern int tea5767_tuner_init(struct i2c_client *c);
extern int default_tuner_init(struct i2c_client *c);
extern int tea5767_autodetection(struct i2c_client *c);
+extern int tda9887_tuner_init(struct i2c_client *c);
#define tuner_warn(fmt, arg...) do {\
printk(KERN_WARNING "%s %d-%04x: " fmt, t->i2c.driver->driver.name, \
--- /dev/null
+/*
+ tvp5150.h - definition for tvp5150 inputs
+
+ Copyright (C) 2006 Hans Verkuil (hverkuil@xs4all.nl)
+
+ 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 _TVP5150_H_
+#define _TVP5150_H_
+
+/* TVP5150 HW inputs */
+#define TVP5150_COMPOSITE0 0
+#define TVP5150_COMPOSITE1 1
+#define TVP5150_SVIDEO 2
+
+/* TVP5150 HW outputs */
+#define TVP5150_NORMAL 0
+#define TVP5150_BLACK_SCREEN 1
+
+#endif
+
#ifndef V4L2_COMMON_H_
#define V4L2_COMMON_H_
+#include <media/v4l2-dev.h>
+
/* v4l debugging and diagnostics */
+/* Debug bitmask flags to be used on V4L2 */
+#define V4L2_DEBUG_IOCTL 0x01
+#define V4L2_DEBUG_IOCTL_ARG 0x02
+
/* Common printk constucts for v4l-i2c drivers. These macros create a unique
prefix consisting of the driver name, the adapter number and the i2c
address. */
/* ------------------------------------------------------------------------- */
+/* Control helper functions */
+
+int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char **menu_items);
+const char **v4l2_ctrl_get_menu(u32 id);
+int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
+int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl);
+int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
+ struct v4l2_queryctrl *qctrl, const char **menu_items);
+u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
+
+/* ------------------------------------------------------------------------- */
+
/* Internal ioctls */
/* VIDIOC_INT_G_REGISTER and VIDIOC_INT_S_REGISTER */
V4L2_IDENT_SAA7129 = 159,
/* module cx25840: reserved range 200-249 */
+ V4L2_IDENT_CX25836 = 236,
+ V4L2_IDENT_CX25837 = 237,
V4L2_IDENT_CX25840 = 240,
V4L2_IDENT_CX25841 = 241,
V4L2_IDENT_CX25842 = 242,
#define VIDIOC_INT_S_VIDEO_ROUTING _IOW ('d', 111, struct v4l2_routing)
#define VIDIOC_INT_G_VIDEO_ROUTING _IOR ('d', 112, struct v4l2_routing)
+struct v4l2_crystal_freq {
+ u32 freq; /* frequency in Hz of the crystal */
+ u32 flags; /* device specific flags */
+};
+
+/* Sets the frequency of the crystal used to generate the clocks.
+ An extra flags field allows device specific configuration regarding
+ clock frequency dividers, etc. If not used, then set flags to 0.
+ If the frequency is not supported, then -EINVAL is returned. */
+#define VIDIOC_INT_S_CRYSTAL_FREQ _IOW ('d', 113, struct v4l2_crystal_freq)
+
#endif /* V4L2_COMMON_H_ */
--- /dev/null
+/*
+ *
+ * V 4 L 2 D R I V E R H E L P E R A P I
+ *
+ * Moved from videodev2.h
+ *
+ * Some commonly needed functions for drivers (v4l2-common.o module)
+ */
+#ifndef _V4L2_DEV_H
+#define _V4L2_DEV_H
+
+#define OBSOLETE_OWNER 1 /* to be removed soon */
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/compiler.h> /* need __user */
+#ifdef CONFIG_VIDEO_V4L1
+#include <linux/videodev.h>
+#else
+#include <linux/videodev2.h>
+#endif
+
+#include <linux/fs.h>
+
+#define VIDEO_MAJOR 81
+/* Minor device allocation */
+#define MINOR_VFL_TYPE_GRABBER_MIN 0
+#define MINOR_VFL_TYPE_GRABBER_MAX 63
+#define MINOR_VFL_TYPE_RADIO_MIN 64
+#define MINOR_VFL_TYPE_RADIO_MAX 127
+#define MINOR_VFL_TYPE_VTX_MIN 192
+#define MINOR_VFL_TYPE_VTX_MAX 223
+#define MINOR_VFL_TYPE_VBI_MIN 224
+#define MINOR_VFL_TYPE_VBI_MAX 255
+
+#define VFL_TYPE_GRABBER 0
+#define VFL_TYPE_VBI 1
+#define VFL_TYPE_RADIO 2
+#define VFL_TYPE_VTX 3
+
+/* Video standard functions */
+extern unsigned int v4l2_video_std_fps(struct v4l2_standard *vs);
+extern int v4l2_video_std_construct(struct v4l2_standard *vs,
+ int id, char *name);
+
+/* prority handling */
+struct v4l2_prio_state {
+ atomic_t prios[4];
+};
+int v4l2_prio_init(struct v4l2_prio_state *global);
+int v4l2_prio_change(struct v4l2_prio_state *global, enum v4l2_priority *local,
+ enum v4l2_priority new);
+int v4l2_prio_open(struct v4l2_prio_state *global, enum v4l2_priority *local);
+int v4l2_prio_close(struct v4l2_prio_state *global, enum v4l2_priority *local);
+enum v4l2_priority v4l2_prio_max(struct v4l2_prio_state *global);
+int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local);
+
+/* names for fancy debug output */
+extern char *v4l2_field_names[];
+extern char *v4l2_type_names[];
+
+/* Compatibility layer interface -- v4l1-compat module */
+typedef int (*v4l2_kioctl)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg);
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+int v4l_compat_translate_ioctl(struct inode *inode, struct file *file,
+ int cmd, void *arg, v4l2_kioctl driver_ioctl);
+#else
+#define v4l_compat_translate_ioctl(inode,file,cmd,arg,ioctl) -EINVAL
+#endif
+
+/* 32 Bits compatibility layer for 64 bits processors */
+extern long v4l_compat_ioctl32(struct file *file, unsigned int cmd,
+ unsigned long arg);
+
+/*
+ * Newer version of video_device, handled by videodev2.c
+ * This version moves redundant code from video device code to
+ * the common handler
+ */
+struct v4l2_tvnorm {
+ char *name;
+ v4l2_std_id id;
+
+ void *priv_data;
+};
+
+struct video_device
+{
+ /* device ops */
+ const struct file_operations *fops;
+
+ /* device info */
+ struct device *dev;
+ char name[32];
+ int type; /* v4l1 */
+ int type2; /* v4l2 */
+ int hardware;
+ int minor;
+
+ int debug; /* Activates debug level*/
+
+ /* Video standard vars */
+ int tvnormsize; /* Size of tvnorm array */
+ v4l2_std_id current_norm; /* Current tvnorm */
+ struct v4l2_tvnorm *tvnorms;
+
+ /* callbacks */
+ void (*release)(struct video_device *vfd);
+
+ /* ioctl callbacks */
+
+ /* VIDIOC_QUERYCAP handler */
+ int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
+
+ /* Priority handling */
+ int (*vidioc_g_priority) (struct file *file, void *fh,
+ enum v4l2_priority *p);
+ int (*vidioc_s_priority) (struct file *file, void *fh,
+ enum v4l2_priority p);
+
+ /* VIDIOC_ENUM_FMT handlers */
+ int (*vidioc_enum_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_vbi_capture) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+ int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f);
+
+ /* VIDIOC_G_FMT handlers */
+ int (*vidioc_g_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_vbi_capture)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_g_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ /* VIDIOC_S_FMT handlers */
+ int (*vidioc_s_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ int (*vidioc_s_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_vbi_capture)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_s_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ /* VIDIOC_TRY_FMT handlers */
+ int (*vidioc_try_fmt_cap) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_overlay) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_vbi) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_vbi_output) (struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_vbi_capture)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_video_output)(struct file *file, void *fh,
+ struct v4l2_format *f);
+ int (*vidioc_try_fmt_type_private)(struct file *file, void *fh,
+ struct v4l2_format *f);
+
+ /* Buffer handlers */
+ int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
+ int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
+ int (*vidioc_qbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
+ int (*vidioc_dqbuf) (struct file *file, void *fh, struct v4l2_buffer *b);
+
+
+ int (*vidioc_overlay) (struct file *file, void *fh, unsigned int i);
+#ifdef HAVE_V4L1
+ /* buffer type is struct vidio_mbuf * */
+ int (*vidiocgmbuf) (struct file *file, void *fh, struct video_mbuf *p);
+#endif
+ int (*vidioc_g_fbuf) (struct file *file, void *fh,
+ struct v4l2_framebuffer *a);
+ int (*vidioc_s_fbuf) (struct file *file, void *fh,
+ struct v4l2_framebuffer *a);
+
+ /* Stream on/off */
+ int (*vidioc_streamon) (struct file *file, void *fh, enum v4l2_buf_type i);
+ int (*vidioc_streamoff)(struct file *file, void *fh, enum v4l2_buf_type i);
+
+ /* Standard handling
+ G_STD and ENUMSTD are handled by videodev.c
+ */
+ int (*vidioc_s_std) (struct file *file, void *fh, v4l2_std_id a);
+ int (*vidioc_querystd) (struct file *file, void *fh, v4l2_std_id *a);
+
+ /* Input handling */
+ int (*vidioc_enum_input)(struct file *file, void *fh,
+ struct v4l2_input *inp);
+ int (*vidioc_g_input) (struct file *file, void *fh, unsigned int *i);
+ int (*vidioc_s_input) (struct file *file, void *fh, unsigned int i);
+
+ /* Output handling */
+ int (*vidioc_enumoutput) (struct file *file, void *fh,
+ struct v4l2_output *a);
+ int (*vidioc_g_output) (struct file *file, void *fh, unsigned int *i);
+ int (*vidioc_s_output) (struct file *file, void *fh, unsigned int i);
+
+ /* Control handling */
+ int (*vidioc_queryctrl) (struct file *file, void *fh,
+ struct v4l2_queryctrl *a);
+ int (*vidioc_g_ctrl) (struct file *file, void *fh,
+ struct v4l2_control *a);
+ int (*vidioc_s_ctrl) (struct file *file, void *fh,
+ struct v4l2_control *a);
+ int (*vidioc_g_ext_ctrls) (struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+ int (*vidioc_s_ext_ctrls) (struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+ int (*vidioc_try_ext_ctrls) (struct file *file, void *fh,
+ struct v4l2_ext_controls *a);
+ int (*vidioc_querymenu) (struct file *file, void *fh,
+ struct v4l2_querymenu *a);
+
+ /* Audio ioctls */
+ int (*vidioc_enumaudio) (struct file *file, void *fh,
+ struct v4l2_audio *a);
+ int (*vidioc_g_audio) (struct file *file, void *fh,
+ struct v4l2_audio *a);
+ int (*vidioc_s_audio) (struct file *file, void *fh,
+ struct v4l2_audio *a);
+
+ /* Audio out ioctls */
+ int (*vidioc_enumaudout) (struct file *file, void *fh,
+ struct v4l2_audioout *a);
+ int (*vidioc_g_audout) (struct file *file, void *fh,
+ struct v4l2_audioout *a);
+ int (*vidioc_s_audout) (struct file *file, void *fh,
+ struct v4l2_audioout *a);
+ int (*vidioc_g_modulator) (struct file *file, void *fh,
+ struct v4l2_modulator *a);
+ int (*vidioc_s_modulator) (struct file *file, void *fh,
+ struct v4l2_modulator *a);
+ /* Crop ioctls */
+ int (*vidioc_cropcap) (struct file *file, void *fh,
+ struct v4l2_cropcap *a);
+ int (*vidioc_g_crop) (struct file *file, void *fh,
+ struct v4l2_crop *a);
+ int (*vidioc_s_crop) (struct file *file, void *fh,
+ struct v4l2_crop *a);
+ /* Compression ioctls */
+ int (*vidioc_g_mpegcomp) (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *a);
+ int (*vidioc_s_mpegcomp) (struct file *file, void *fh,
+ struct v4l2_mpeg_compression *a);
+ int (*vidioc_g_jpegcomp) (struct file *file, void *fh,
+ struct v4l2_jpegcompression *a);
+ int (*vidioc_s_jpegcomp) (struct file *file, void *fh,
+ struct v4l2_jpegcompression *a);
+
+ /* Stream type-dependent parameter ioctls */
+ int (*vidioc_g_parm) (struct file *file, void *fh,
+ struct v4l2_streamparm *a);
+ int (*vidioc_s_parm) (struct file *file, void *fh,
+ struct v4l2_streamparm *a);
+
+ /* Tuner ioctls */
+ int (*vidioc_g_tuner) (struct file *file, void *fh,
+ struct v4l2_tuner *a);
+ int (*vidioc_s_tuner) (struct file *file, void *fh,
+ struct v4l2_tuner *a);
+ int (*vidioc_g_frequency) (struct file *file, void *fh,
+ struct v4l2_frequency *a);
+ int (*vidioc_s_frequency) (struct file *file, void *fh,
+ struct v4l2_frequency *a);
+
+ /* Sliced VBI cap */
+ int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh,
+ struct v4l2_sliced_vbi_cap *a);
+
+ /* Log status ioctl */
+ int (*vidioc_log_status) (struct file *file, void *fh);
+
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* obsolete -- fops->owner is used instead */
+struct module *owner;
+/* dev->driver_data will be used instead some day.
+ * Use the video_{get|set}_drvdata() helper functions,
+ * so the switch over will be transparent for you.
+ * Or use {pci|usb}_{get|set}_drvdata() directly. */
+void *priv;
+#endif
+
+ /* for videodev.c intenal usage -- please don't touch */
+ int users; /* video_exclusive_{open|close} ... */
+ struct mutex lock; /* ... helper function uses these */
+ char devfs_name[64]; /* devfs */
+ struct class_device class_dev; /* sysfs */
+};
+
+/* Version 2 functions */
+extern int video_register_device(struct video_device *vfd, int type, int nr);
+void video_unregister_device(struct video_device *);
+extern int video_ioctl2(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+/* helper functions to alloc / release struct video_device, the
+ later can be used for video_device->release() */
+struct video_device *video_device_alloc(void);
+void video_device_release(struct video_device *vfd);
+
+/* Include support for obsoleted stuff */
+extern int video_usercopy(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg,
+ int (*func)(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg));
+
+
+#ifdef HAVE_V4L1
+#include <linux/mm.h>
+
+extern struct video_device* video_devdata(struct file*);
+
+#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
+static inline void
+video_device_create_file(struct video_device *vfd,
+ struct class_device_attribute *attr)
+{
+ class_device_create_file(&vfd->class_dev, attr);
+}
+static inline void
+video_device_remove_file(struct video_device *vfd,
+ struct class_device_attribute *attr)
+{
+ class_device_remove_file(&vfd->class_dev, attr);
+}
+
+#ifdef OBSOLETE_OWNER /* to be removed soon */
+/* helper functions to access driver private data. */
+static inline void *video_get_drvdata(struct video_device *dev)
+{
+ return dev->priv;
+}
+
+static inline void video_set_drvdata(struct video_device *dev, void *data)
+{
+ dev->priv = data;
+}
+#endif
+
+extern int video_exclusive_open(struct inode *inode, struct file *file);
+extern int video_exclusive_release(struct inode *inode, struct file *file);
+#endif /* HAVE_V4L1 */
+
+#endif /* _V4L2_DEV_H */
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
- void *adapter_priv);
+ void *adapter_priv,
+ struct device *device);
void videobuf_dvb_unregister(struct videobuf_dvb *dvb);
/*
*/
#include <linux/videodev2.h>
+#include <linux/poll.h>
#define UNSET (-1U)
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
- */
+ */
#include <linux/videodev.h>
+#include <media/v4l2-dev.h>
struct snd_tea575x;