diff options
Diffstat (limited to 'drivers/media/video')
32 files changed, 5040 insertions, 476 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 199b01188858..1a3b3c7e5e99 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -333,4 +333,18 @@ config VIDEO_M32R_AR_M64278 | |||
333 | Say Y here to use the Renesas M64278E-800 camera module, | 333 | Say Y here to use the Renesas M64278E-800 camera module, |
334 | which supports VGA(640x480 pixcels) size of images. | 334 | which supports VGA(640x480 pixcels) size of images. |
335 | 335 | ||
336 | config VIDEO_AUDIO_DECODER | ||
337 | tristate "Add support for additional audio chipsets" | ||
338 | depends on VIDEO_DEV && I2C && EXPERIMENTAL | ||
339 | ---help--- | ||
340 | Say Y here to compile drivers for WM8775 and CS53L32A audio | ||
341 | decoders. | ||
342 | |||
343 | config VIDEO_DECODER | ||
344 | tristate "Add support for additional video chipsets" | ||
345 | depends on VIDEO_DEV && I2C && EXPERIMENTAL | ||
346 | ---help--- | ||
347 | Say Y here to compile drivers for SAA7115, SAA7127 and CX25840 | ||
348 | video decoders. | ||
349 | |||
336 | endmenu | 350 | endmenu |
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 3ac465992400..82060f9909d8 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -36,10 +36,11 @@ obj-$(CONFIG_VIDEO_CPIA) += cpia.o | |||
36 | obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o | 36 | obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o |
37 | obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o | 37 | obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o |
38 | obj-$(CONFIG_VIDEO_MEYE) += meye.o | 38 | obj-$(CONFIG_VIDEO_MEYE) += meye.o |
39 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ | 39 | obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ |
40 | obj-$(CONFIG_VIDEO_CX88) += cx88/ | 40 | obj-$(CONFIG_VIDEO_CX88) += cx88/ |
41 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ | 41 | obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ |
42 | obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o | 42 | obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o |
43 | obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o | ||
43 | obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ | 44 | obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ |
44 | obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o | 45 | obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o |
45 | obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o | 46 | obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o |
@@ -55,4 +56,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o | |||
55 | 56 | ||
56 | obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o | 57 | obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o |
57 | 58 | ||
59 | obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o | ||
60 | |||
58 | EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core | 61 | EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core |
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 3413bace443a..e31ebb11c468 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c | |||
@@ -2133,7 +2133,10 @@ struct tvcard bttv_tvcards[] = { | |||
2133 | .tuner_addr = ADDR_UNSET, | 2133 | .tuner_addr = ADDR_UNSET, |
2134 | .radio_addr = ADDR_UNSET, | 2134 | .radio_addr = ADDR_UNSET, |
2135 | .has_dvb = 1, | 2135 | .has_dvb = 1, |
2136 | .has_remote = 1, | ||
2137 | .gpiomask = 0x1b, | ||
2136 | .no_gpioirq = 1, | 2138 | .no_gpioirq = 1, |
2139 | .any_irq = 1, | ||
2137 | }, | 2140 | }, |
2138 | [BTTV_BOARD_PV143] = { | 2141 | [BTTV_BOARD_PV143] = { |
2139 | /* Jorge Boncompte - DTI2 <jorge@dti2.net> */ | 2142 | /* Jorge Boncompte - DTI2 <jorge@dti2.net> */ |
@@ -2796,7 +2799,24 @@ struct tvcard bttv_tvcards[] = { | |||
2796 | .tuner_addr = ADDR_UNSET, | 2799 | .tuner_addr = ADDR_UNSET, |
2797 | .radio_addr = ADDR_UNSET, | 2800 | .radio_addr = ADDR_UNSET, |
2798 | }, | 2801 | }, |
2799 | 2802 | /* ---- card 0x8e ---------------------------------- */ | |
2803 | [BTTV_BOARD_SABRENT_TVFM] = { | ||
2804 | .name = "Sabrent TV-FM (bttv version)", | ||
2805 | .video_inputs = 3, | ||
2806 | .audio_inputs = 1, | ||
2807 | .tuner = 0, | ||
2808 | .svhs = 2, | ||
2809 | .gpiomask = 0x108007, | ||
2810 | .muxsel = { 2, 3, 1, 1}, | ||
2811 | .audiomux = { 100000, 100002, 100002, 100000}, | ||
2812 | .no_msp34xx = 1, | ||
2813 | .no_tda9875 = 1, | ||
2814 | .no_tda7432 = 1, | ||
2815 | .pll = PLL_28, | ||
2816 | .tuner_type = TUNER_TNF_5335MF, | ||
2817 | .tuner_addr = ADDR_UNSET, | ||
2818 | .has_radio = 1, | ||
2819 | }, | ||
2800 | }; | 2820 | }; |
2801 | 2821 | ||
2802 | static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); | 2822 | static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); |
@@ -3367,6 +3387,8 @@ void __devinit bttv_init_card2(struct bttv *btv) | |||
3367 | btv->has_remote=1; | 3387 | btv->has_remote=1; |
3368 | if (!bttv_tvcards[btv->c.type].no_gpioirq) | 3388 | if (!bttv_tvcards[btv->c.type].no_gpioirq) |
3369 | btv->gpioirq=1; | 3389 | btv->gpioirq=1; |
3390 | if (bttv_tvcards[btv->c.type].any_irq) | ||
3391 | btv->any_irq = 1; | ||
3370 | if (bttv_tvcards[btv->c.type].audio_hook) | 3392 | if (bttv_tvcards[btv->c.type].audio_hook) |
3371 | btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; | 3393 | btv->audio_hook=bttv_tvcards[btv->c.type].audio_hook; |
3372 | 3394 | ||
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 0005741d5514..709099f03bd2 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c | |||
@@ -3667,6 +3667,10 @@ static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs) | |||
3667 | int handled = 0; | 3667 | int handled = 0; |
3668 | 3668 | ||
3669 | btv=(struct bttv *)dev_id; | 3669 | btv=(struct bttv *)dev_id; |
3670 | |||
3671 | if (btv->any_irq) | ||
3672 | handled = bttv_any_irq(&btv->c); | ||
3673 | |||
3670 | count=0; | 3674 | count=0; |
3671 | while (1) { | 3675 | while (1) { |
3672 | /* get/clear interrupt status bits */ | 3676 | /* get/clear interrupt status bits */ |
diff --git a/drivers/media/video/bttv-gpio.c b/drivers/media/video/bttv-gpio.c index 575ce8b8e714..616a5b7e510c 100644 --- a/drivers/media/video/bttv-gpio.c +++ b/drivers/media/video/bttv-gpio.c | |||
@@ -113,6 +113,24 @@ void bttv_gpio_irq(struct bttv_core *core) | |||
113 | } | 113 | } |
114 | } | 114 | } |
115 | 115 | ||
116 | int bttv_any_irq(struct bttv_core *core) | ||
117 | { | ||
118 | struct bttv_sub_driver *drv; | ||
119 | struct bttv_sub_device *dev; | ||
120 | struct list_head *item; | ||
121 | int handled = 0; | ||
122 | |||
123 | list_for_each(item,&core->subs) { | ||
124 | dev = list_entry(item,struct bttv_sub_device,list); | ||
125 | drv = to_bttv_sub_drv(dev->dev.driver); | ||
126 | if (drv && drv->any_irq) { | ||
127 | if (drv->any_irq(dev)) | ||
128 | handled = 1; | ||
129 | } | ||
130 | } | ||
131 | return handled; | ||
132 | } | ||
133 | |||
116 | /* ----------------------------------------------------------------------- */ | 134 | /* ----------------------------------------------------------------------- */ |
117 | /* external: sub-driver register/unregister */ | 135 | /* external: sub-driver register/unregister */ |
118 | 136 | ||
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h index 124ea41dada4..93298f06e019 100644 --- a/drivers/media/video/bttv.h +++ b/drivers/media/video/bttv.h | |||
@@ -162,6 +162,7 @@ | |||
162 | #define BTTV_BOARD_PV_M4900 0x8b | 162 | #define BTTV_BOARD_PV_M4900 0x8b |
163 | #define BTTV_BOARD_OSPREY440 0x8c | 163 | #define BTTV_BOARD_OSPREY440 0x8c |
164 | #define BTTV_BOARD_ASOUND_SKYEYE 0x8d | 164 | #define BTTV_BOARD_ASOUND_SKYEYE 0x8d |
165 | #define BTTV_BOARD_SABRENT_TVFM 0x8e | ||
165 | 166 | ||
166 | /* i2c address list */ | 167 | /* i2c address list */ |
167 | #define I2C_TSA5522 0xc2 | 168 | #define I2C_TSA5522 0xc2 |
@@ -234,6 +235,7 @@ struct tvcard | |||
234 | unsigned int has_dvb:1; | 235 | unsigned int has_dvb:1; |
235 | unsigned int has_remote:1; | 236 | unsigned int has_remote:1; |
236 | unsigned int no_gpioirq:1; | 237 | unsigned int no_gpioirq:1; |
238 | unsigned int any_irq:1; | ||
237 | 239 | ||
238 | /* other settings */ | 240 | /* other settings */ |
239 | unsigned int pll; | 241 | unsigned int pll; |
@@ -333,6 +335,7 @@ struct bttv_sub_driver { | |||
333 | struct device_driver drv; | 335 | struct device_driver drv; |
334 | char wanted[BUS_ID_SIZE]; | 336 | char wanted[BUS_ID_SIZE]; |
335 | void (*gpio_irq)(struct bttv_sub_device *sub); | 337 | void (*gpio_irq)(struct bttv_sub_device *sub); |
338 | int (*any_irq)(struct bttv_sub_device *sub); | ||
336 | }; | 339 | }; |
337 | #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) | 340 | #define to_bttv_sub_drv(x) container_of((x), struct bttv_sub_driver, drv) |
338 | 341 | ||
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h index 386f546f7d11..3aa9c6e4fc33 100644 --- a/drivers/media/video/bttvp.h +++ b/drivers/media/video/bttvp.h | |||
@@ -208,6 +208,7 @@ extern struct bus_type bttv_sub_bus_type; | |||
208 | int bttv_sub_add_device(struct bttv_core *core, char *name); | 208 | int bttv_sub_add_device(struct bttv_core *core, char *name); |
209 | int bttv_sub_del_devices(struct bttv_core *core); | 209 | int bttv_sub_del_devices(struct bttv_core *core); |
210 | void bttv_gpio_irq(struct bttv_core *core); | 210 | void bttv_gpio_irq(struct bttv_core *core); |
211 | int bttv_any_irq(struct bttv_core *core); | ||
211 | 212 | ||
212 | 213 | ||
213 | /* ---------------------------------------------------------- */ | 214 | /* ---------------------------------------------------------- */ |
@@ -273,6 +274,7 @@ struct bttv { | |||
273 | struct bttv_pll_info pll; | 274 | struct bttv_pll_info pll; |
274 | int triton1; | 275 | int triton1; |
275 | int gpioirq; | 276 | int gpioirq; |
277 | int any_irq; | ||
276 | int use_i2c_hw; | 278 | int use_i2c_hw; |
277 | 279 | ||
278 | /* old gpio interface */ | 280 | /* old gpio interface */ |
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile new file mode 100644 index 000000000000..543ebacdc9d7 --- /dev/null +++ b/drivers/media/video/cx25840/Makefile | |||
@@ -0,0 +1,6 @@ | |||
1 | cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ | ||
2 | cx25840-vbi.o | ||
3 | |||
4 | obj-$(CONFIG_VIDEO_DECODER) += cx25840.o | ||
5 | |||
6 | EXTRA_CFLAGS += -I$(src)/.. | ||
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c new file mode 100644 index 000000000000..740908f8027d --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-audio.c | |||
@@ -0,0 +1,368 @@ | |||
1 | /* cx25840 audio functions | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU General Public License | ||
5 | * as published by the Free Software Foundation; either version 2 | ||
6 | * of the License, or (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/videodev2.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <media/audiochip.h> | ||
22 | #include <media/v4l2-common.h> | ||
23 | |||
24 | #include "cx25840.h" | ||
25 | |||
26 | inline static int set_audclk_freq(struct i2c_client *client, | ||
27 | enum v4l2_audio_clock_freq freq) | ||
28 | { | ||
29 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
30 | |||
31 | /* assert soft reset */ | ||
32 | cx25840_and_or(client, 0x810, ~0x1, 0x01); | ||
33 | |||
34 | /* common for all inputs and rates */ | ||
35 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ | ||
36 | cx25840_write(client, 0x127, 0x50); | ||
37 | |||
38 | switch (state->audio_input) { | ||
39 | case AUDIO_TUNER: | ||
40 | switch (freq) { | ||
41 | case V4L2_AUDCLK_32_KHZ: | ||
42 | /* VID_PLL and AUX_PLL */ | ||
43 | cx25840_write4(client, 0x108, 0x0f040610); | ||
44 | |||
45 | /* AUX_PLL_FRAC */ | ||
46 | cx25840_write4(client, 0x110, 0xee39bb01); | ||
47 | |||
48 | /* src3/4/6_ctl = 0x0801f77f */ | ||
49 | cx25840_write4(client, 0x900, 0x7ff70108); | ||
50 | cx25840_write4(client, 0x904, 0x7ff70108); | ||
51 | cx25840_write4(client, 0x90c, 0x7ff70108); | ||
52 | break; | ||
53 | |||
54 | case V4L2_AUDCLK_441_KHZ: | ||
55 | /* VID_PLL and AUX_PLL */ | ||
56 | cx25840_write4(client, 0x108, 0x0f040910); | ||
57 | |||
58 | /* AUX_PLL_FRAC */ | ||
59 | cx25840_write4(client, 0x110, 0xd66bec00); | ||
60 | |||
61 | /* src3/4/6_ctl = 0x08016d59 */ | ||
62 | cx25840_write4(client, 0x900, 0x596d0108); | ||
63 | cx25840_write4(client, 0x904, 0x596d0108); | ||
64 | cx25840_write4(client, 0x90c, 0x596d0108); | ||
65 | break; | ||
66 | |||
67 | case V4L2_AUDCLK_48_KHZ: | ||
68 | /* VID_PLL and AUX_PLL */ | ||
69 | cx25840_write4(client, 0x108, 0x0f040a10); | ||
70 | |||
71 | /* AUX_PLL_FRAC */ | ||
72 | cx25840_write4(client, 0x110, 0xe5d69800); | ||
73 | |||
74 | /* src3/4/6_ctl = 0x08014faa */ | ||
75 | cx25840_write4(client, 0x900, 0xaa4f0108); | ||
76 | cx25840_write4(client, 0x904, 0xaa4f0108); | ||
77 | cx25840_write4(client, 0x90c, 0xaa4f0108); | ||
78 | break; | ||
79 | } | ||
80 | break; | ||
81 | |||
82 | case AUDIO_EXTERN_1: | ||
83 | case AUDIO_EXTERN_2: | ||
84 | case AUDIO_INTERN: | ||
85 | case AUDIO_RADIO: | ||
86 | switch (freq) { | ||
87 | case V4L2_AUDCLK_32_KHZ: | ||
88 | /* VID_PLL and AUX_PLL */ | ||
89 | cx25840_write4(client, 0x108, 0x0f04081e); | ||
90 | |||
91 | /* AUX_PLL_FRAC */ | ||
92 | cx25840_write4(client, 0x110, 0x69082a01); | ||
93 | |||
94 | /* src1_ctl = 0x08010000 */ | ||
95 | cx25840_write4(client, 0x8f8, 0x00000108); | ||
96 | |||
97 | /* src3/4/6_ctl = 0x08020000 */ | ||
98 | cx25840_write4(client, 0x900, 0x00000208); | ||
99 | cx25840_write4(client, 0x904, 0x00000208); | ||
100 | cx25840_write4(client, 0x90c, 0x00000208); | ||
101 | |||
102 | /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ | ||
103 | cx25840_write(client, 0x127, 0x54); | ||
104 | break; | ||
105 | |||
106 | case V4L2_AUDCLK_441_KHZ: | ||
107 | /* VID_PLL and AUX_PLL */ | ||
108 | cx25840_write4(client, 0x108, 0x0f040918); | ||
109 | |||
110 | /* AUX_PLL_FRAC */ | ||
111 | cx25840_write4(client, 0x110, 0xd66bec00); | ||
112 | |||
113 | /* src1_ctl = 0x08010000 */ | ||
114 | cx25840_write4(client, 0x8f8, 0xcd600108); | ||
115 | |||
116 | /* src3/4/6_ctl = 0x08020000 */ | ||
117 | cx25840_write4(client, 0x900, 0x85730108); | ||
118 | cx25840_write4(client, 0x904, 0x85730108); | ||
119 | cx25840_write4(client, 0x90c, 0x85730108); | ||
120 | break; | ||
121 | |||
122 | case V4L2_AUDCLK_48_KHZ: | ||
123 | /* VID_PLL and AUX_PLL */ | ||
124 | cx25840_write4(client, 0x108, 0x0f040a18); | ||
125 | |||
126 | /* AUX_PLL_FRAC */ | ||
127 | cx25840_write4(client, 0x110, 0xe5d69800); | ||
128 | |||
129 | /* src1_ctl = 0x08010000 */ | ||
130 | cx25840_write4(client, 0x8f8, 0x00800108); | ||
131 | |||
132 | /* src3/4/6_ctl = 0x08020000 */ | ||
133 | cx25840_write4(client, 0x900, 0x55550108); | ||
134 | cx25840_write4(client, 0x904, 0x55550108); | ||
135 | cx25840_write4(client, 0x90c, 0x55550108); | ||
136 | break; | ||
137 | } | ||
138 | break; | ||
139 | } | ||
140 | |||
141 | /* deassert soft reset */ | ||
142 | cx25840_and_or(client, 0x810, ~0x1, 0x00); | ||
143 | |||
144 | state->audclk_freq = freq; | ||
145 | |||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | static int set_input(struct i2c_client *client, int audio_input) | ||
150 | { | ||
151 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
152 | |||
153 | cx25840_dbg("set audio input (%d)\n", audio_input); | ||
154 | |||
155 | /* stop microcontroller */ | ||
156 | cx25840_and_or(client, 0x803, ~0x10, 0); | ||
157 | |||
158 | /* Mute everything to prevent the PFFT! */ | ||
159 | cx25840_write(client, 0x8d3, 0x1f); | ||
160 | |||
161 | switch (audio_input) { | ||
162 | case AUDIO_TUNER: | ||
163 | /* Set Path1 to Analog Demod Main Channel */ | ||
164 | cx25840_write4(client, 0x8d0, 0x7038061f); | ||
165 | |||
166 | /* When the microcontroller detects the | ||
167 | * audio format, it will unmute the lines */ | ||
168 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
169 | break; | ||
170 | |||
171 | case AUDIO_EXTERN_1: | ||
172 | case AUDIO_EXTERN_2: | ||
173 | case AUDIO_INTERN: | ||
174 | case AUDIO_RADIO: | ||
175 | /* Set Path1 to Serial Audio Input */ | ||
176 | cx25840_write4(client, 0x8d0, 0x12100101); | ||
177 | |||
178 | /* The microcontroller should not be started for the | ||
179 | * non-tuner inputs: autodetection is specific for | ||
180 | * TV audio. */ | ||
181 | break; | ||
182 | |||
183 | default: | ||
184 | cx25840_dbg("Invalid audio input selection %d\n", audio_input); | ||
185 | return -EINVAL; | ||
186 | } | ||
187 | |||
188 | state->audio_input = audio_input; | ||
189 | |||
190 | return set_audclk_freq(client, state->audclk_freq); | ||
191 | } | ||
192 | |||
193 | inline static int get_volume(struct i2c_client *client) | ||
194 | { | ||
195 | /* Volume runs +18dB to -96dB in 1/2dB steps | ||
196 | * change to fit the msp3400 -114dB to +12dB range */ | ||
197 | |||
198 | /* check PATH1_VOLUME */ | ||
199 | int vol = 228 - cx25840_read(client, 0x8d4); | ||
200 | vol = (vol / 2) + 23; | ||
201 | return vol << 9; | ||
202 | } | ||
203 | |||
204 | inline static void set_volume(struct i2c_client *client, int volume) | ||
205 | { | ||
206 | /* First convert the volume to msp3400 values (0-127) */ | ||
207 | int vol = volume >> 9; | ||
208 | /* now scale it up to cx25840 values | ||
209 | * -114dB to -96dB maps to 0 | ||
210 | * this should be 19, but in my testing that was 4dB too loud */ | ||
211 | if (vol <= 23) { | ||
212 | vol = 0; | ||
213 | } else { | ||
214 | vol -= 23; | ||
215 | } | ||
216 | |||
217 | /* PATH1_VOLUME */ | ||
218 | cx25840_write(client, 0x8d4, 228 - (vol * 2)); | ||
219 | } | ||
220 | |||
221 | inline static int get_bass(struct i2c_client *client) | ||
222 | { | ||
223 | /* bass is 49 steps +12dB to -12dB */ | ||
224 | |||
225 | /* check PATH1_EQ_BASS_VOL */ | ||
226 | int bass = cx25840_read(client, 0x8d9) & 0x3f; | ||
227 | bass = (((48 - bass) * 0xffff) + 47) / 48; | ||
228 | return bass; | ||
229 | } | ||
230 | |||
231 | inline static void set_bass(struct i2c_client *client, int bass) | ||
232 | { | ||
233 | /* PATH1_EQ_BASS_VOL */ | ||
234 | cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); | ||
235 | } | ||
236 | |||
237 | inline static int get_treble(struct i2c_client *client) | ||
238 | { | ||
239 | /* treble is 49 steps +12dB to -12dB */ | ||
240 | |||
241 | /* check PATH1_EQ_TREBLE_VOL */ | ||
242 | int treble = cx25840_read(client, 0x8db) & 0x3f; | ||
243 | treble = (((48 - treble) * 0xffff) + 47) / 48; | ||
244 | return treble; | ||
245 | } | ||
246 | |||
247 | inline static void set_treble(struct i2c_client *client, int treble) | ||
248 | { | ||
249 | /* PATH1_EQ_TREBLE_VOL */ | ||
250 | cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); | ||
251 | } | ||
252 | |||
253 | inline static int get_balance(struct i2c_client *client) | ||
254 | { | ||
255 | /* balance is 7 bit, 0 to -96dB */ | ||
256 | |||
257 | /* check PATH1_BAL_LEVEL */ | ||
258 | int balance = cx25840_read(client, 0x8d5) & 0x7f; | ||
259 | /* check PATH1_BAL_LEFT */ | ||
260 | if ((cx25840_read(client, 0x8d5) & 0x80) == 0) | ||
261 | balance = 0x80 - balance; | ||
262 | else | ||
263 | balance = 0x80 + balance; | ||
264 | return balance << 8; | ||
265 | } | ||
266 | |||
267 | inline static void set_balance(struct i2c_client *client, int balance) | ||
268 | { | ||
269 | int bal = balance >> 8; | ||
270 | if (bal > 0x80) { | ||
271 | /* PATH1_BAL_LEFT */ | ||
272 | cx25840_and_or(client, 0x8d5, 0x7f, 0x80); | ||
273 | /* PATH1_BAL_LEVEL */ | ||
274 | cx25840_and_or(client, 0x8d5, ~0x7f, bal & 0x7f); | ||
275 | } else { | ||
276 | /* PATH1_BAL_LEFT */ | ||
277 | cx25840_and_or(client, 0x8d5, 0x7f, 0x00); | ||
278 | /* PATH1_BAL_LEVEL */ | ||
279 | cx25840_and_or(client, 0x8d5, ~0x7f, 0x80 - bal); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | inline static int get_mute(struct i2c_client *client) | ||
284 | { | ||
285 | /* check SRC1_MUTE_EN */ | ||
286 | return cx25840_read(client, 0x8d3) & 0x2 ? 1 : 0; | ||
287 | } | ||
288 | |||
289 | inline static void set_mute(struct i2c_client *client, int mute) | ||
290 | { | ||
291 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
292 | |||
293 | if (state->audio_input == AUDIO_TUNER) { | ||
294 | /* Must turn off microcontroller in order to mute sound. | ||
295 | * Not sure if this is the best method, but it does work. | ||
296 | * If the microcontroller is running, then it will undo any | ||
297 | * changes to the mute register. */ | ||
298 | if (mute) { | ||
299 | /* disable microcontroller */ | ||
300 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
301 | cx25840_write(client, 0x8d3, 0x1f); | ||
302 | } else { | ||
303 | /* enable microcontroller */ | ||
304 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
305 | } | ||
306 | } else { | ||
307 | /* SRC1_MUTE_EN */ | ||
308 | cx25840_and_or(client, 0x8d3, ~0x2, mute ? 0x02 : 0x00); | ||
309 | } | ||
310 | } | ||
311 | |||
312 | int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg) | ||
313 | { | ||
314 | struct v4l2_control *ctrl = arg; | ||
315 | |||
316 | switch (cmd) { | ||
317 | case AUDC_SET_INPUT: | ||
318 | return set_input(client, *(int *)arg); | ||
319 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | ||
320 | return set_audclk_freq(client, *(enum v4l2_audio_clock_freq *)arg); | ||
321 | case VIDIOC_G_CTRL: | ||
322 | switch (ctrl->id) { | ||
323 | case V4L2_CID_AUDIO_VOLUME: | ||
324 | ctrl->value = get_volume(client); | ||
325 | break; | ||
326 | case V4L2_CID_AUDIO_BASS: | ||
327 | ctrl->value = get_bass(client); | ||
328 | break; | ||
329 | case V4L2_CID_AUDIO_TREBLE: | ||
330 | ctrl->value = get_treble(client); | ||
331 | break; | ||
332 | case V4L2_CID_AUDIO_BALANCE: | ||
333 | ctrl->value = get_balance(client); | ||
334 | break; | ||
335 | case V4L2_CID_AUDIO_MUTE: | ||
336 | ctrl->value = get_mute(client); | ||
337 | break; | ||
338 | default: | ||
339 | return -EINVAL; | ||
340 | } | ||
341 | break; | ||
342 | case VIDIOC_S_CTRL: | ||
343 | switch (ctrl->id) { | ||
344 | case V4L2_CID_AUDIO_VOLUME: | ||
345 | set_volume(client, ctrl->value); | ||
346 | break; | ||
347 | case V4L2_CID_AUDIO_BASS: | ||
348 | set_bass(client, ctrl->value); | ||
349 | break; | ||
350 | case V4L2_CID_AUDIO_TREBLE: | ||
351 | set_treble(client, ctrl->value); | ||
352 | break; | ||
353 | case V4L2_CID_AUDIO_BALANCE: | ||
354 | set_balance(client, ctrl->value); | ||
355 | break; | ||
356 | case V4L2_CID_AUDIO_MUTE: | ||
357 | set_mute(client, ctrl->value); | ||
358 | break; | ||
359 | default: | ||
360 | return -EINVAL; | ||
361 | } | ||
362 | break; | ||
363 | default: | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | return 0; | ||
368 | } | ||
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c new file mode 100644 index 000000000000..f6afeec499c5 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-core.c | |||
@@ -0,0 +1,1020 @@ | |||
1 | /* cx25840 - Conexant CX25840 audio/video decoder driver | ||
2 | * | ||
3 | * Copyright (C) 2004 Ulf Eklund | ||
4 | * | ||
5 | * Based on the saa7115 driver and on the first verison of Chris Kennedy's | ||
6 | * cx25840 driver. | ||
7 | * | ||
8 | * Changes by Tyler Trafford <tatrafford@comcast.net> | ||
9 | * - cleanup/rewrite for V4L2 API (2005) | ||
10 | * | ||
11 | * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This program is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | * GNU General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with this program; if not, write to the Free Software | ||
25 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
26 | */ | ||
27 | |||
28 | |||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/module.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/videodev2.h> | ||
33 | #include <linux/i2c.h> | ||
34 | #include <media/audiochip.h> | ||
35 | #include <media/v4l2-common.h> | ||
36 | |||
37 | #include "cx25840.h" | ||
38 | |||
39 | MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver"); | ||
40 | MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; | ||
44 | |||
45 | |||
46 | int cx25840_debug = 0; | ||
47 | |||
48 | module_param(cx25840_debug, bool, 0644); | ||
49 | |||
50 | MODULE_PARM_DESC(cx25840_debug, "Debugging messages [0=Off (default) 1=On]"); | ||
51 | |||
52 | I2C_CLIENT_INSMOD; | ||
53 | |||
54 | /* ----------------------------------------------------------------------- */ | ||
55 | |||
56 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value) | ||
57 | { | ||
58 | u8 buffer[3]; | ||
59 | buffer[0] = addr >> 8; | ||
60 | buffer[1] = addr & 0xff; | ||
61 | buffer[2] = value; | ||
62 | return i2c_master_send(client, buffer, 3); | ||
63 | } | ||
64 | |||
65 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value) | ||
66 | { | ||
67 | u8 buffer[6]; | ||
68 | buffer[0] = addr >> 8; | ||
69 | buffer[1] = addr & 0xff; | ||
70 | buffer[2] = value >> 24; | ||
71 | buffer[3] = (value >> 16) & 0xff; | ||
72 | buffer[4] = (value >> 8) & 0xff; | ||
73 | buffer[5] = value & 0xff; | ||
74 | return i2c_master_send(client, buffer, 6); | ||
75 | } | ||
76 | |||
77 | u8 cx25840_read(struct i2c_client * client, u16 addr) | ||
78 | { | ||
79 | u8 buffer[2]; | ||
80 | buffer[0] = addr >> 8; | ||
81 | buffer[1] = addr & 0xff; | ||
82 | |||
83 | if (i2c_master_send(client, buffer, 2) < 2) | ||
84 | return 0; | ||
85 | |||
86 | if (i2c_master_recv(client, buffer, 1) < 1) | ||
87 | return 0; | ||
88 | |||
89 | return buffer[0]; | ||
90 | } | ||
91 | |||
92 | u32 cx25840_read4(struct i2c_client * client, u16 addr) | ||
93 | { | ||
94 | u8 buffer[4]; | ||
95 | buffer[0] = addr >> 8; | ||
96 | buffer[1] = addr & 0xff; | ||
97 | |||
98 | if (i2c_master_send(client, buffer, 2) < 2) | ||
99 | return 0; | ||
100 | |||
101 | if (i2c_master_recv(client, buffer, 4) < 4) | ||
102 | return 0; | ||
103 | |||
104 | return (buffer[0] << 24) | (buffer[1] << 16) | | ||
105 | (buffer[2] << 8) | buffer[3]; | ||
106 | } | ||
107 | |||
108 | int cx25840_and_or(struct i2c_client *client, u16 addr, u8 and_mask, | ||
109 | u8 or_value) | ||
110 | { | ||
111 | return cx25840_write(client, addr, | ||
112 | (cx25840_read(client, addr) & and_mask) | | ||
113 | or_value); | ||
114 | } | ||
115 | |||
116 | /* ----------------------------------------------------------------------- */ | ||
117 | |||
118 | static int set_input(struct i2c_client *, enum cx25840_input); | ||
119 | static void input_change(struct i2c_client *); | ||
120 | static void log_status(struct i2c_client *client); | ||
121 | |||
122 | /* ----------------------------------------------------------------------- */ | ||
123 | |||
124 | static inline void init_dll1(struct i2c_client *client) | ||
125 | { | ||
126 | /* This is the Hauppauge sequence used to | ||
127 | * initialize the Delay Lock Loop 1 (ADC DLL). */ | ||
128 | cx25840_write(client, 0x159, 0x23); | ||
129 | cx25840_write(client, 0x15a, 0x87); | ||
130 | cx25840_write(client, 0x15b, 0x06); | ||
131 | cx25840_write(client, 0x159, 0xe1); | ||
132 | cx25840_write(client, 0x15a, 0x86); | ||
133 | cx25840_write(client, 0x159, 0xe0); | ||
134 | cx25840_write(client, 0x159, 0xe1); | ||
135 | cx25840_write(client, 0x15b, 0x10); | ||
136 | } | ||
137 | |||
138 | static inline void init_dll2(struct i2c_client *client) | ||
139 | { | ||
140 | /* This is the Hauppauge sequence used to | ||
141 | * initialize the Delay Lock Loop 2 (ADC DLL). */ | ||
142 | cx25840_write(client, 0x15d, 0xe3); | ||
143 | cx25840_write(client, 0x15e, 0x86); | ||
144 | cx25840_write(client, 0x15f, 0x06); | ||
145 | cx25840_write(client, 0x15d, 0xe1); | ||
146 | cx25840_write(client, 0x15d, 0xe0); | ||
147 | cx25840_write(client, 0x15d, 0xe1); | ||
148 | } | ||
149 | |||
150 | static void cx25840_initialize(struct i2c_client *client, int loadfw) | ||
151 | { | ||
152 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
153 | |||
154 | /* datasheet startup in numbered steps, refer to page 3-77 */ | ||
155 | /* 2. */ | ||
156 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
157 | /* The default of this register should be 4, but I get 0 instead. | ||
158 | * Set this register to 4 manually. */ | ||
159 | cx25840_write(client, 0x000, 0x04); | ||
160 | /* 3. */ | ||
161 | init_dll1(client); | ||
162 | init_dll2(client); | ||
163 | cx25840_write(client, 0x136, 0x0a); | ||
164 | /* 4. */ | ||
165 | cx25840_write(client, 0x13c, 0x01); | ||
166 | cx25840_write(client, 0x13c, 0x00); | ||
167 | /* 5. */ | ||
168 | if (loadfw) | ||
169 | cx25840_loadfw(client); | ||
170 | /* 6. */ | ||
171 | cx25840_write(client, 0x115, 0x8c); | ||
172 | cx25840_write(client, 0x116, 0x07); | ||
173 | cx25840_write(client, 0x118, 0x02); | ||
174 | /* 7. */ | ||
175 | cx25840_write(client, 0x4a5, 0x80); | ||
176 | cx25840_write(client, 0x4a5, 0x00); | ||
177 | cx25840_write(client, 0x402, 0x00); | ||
178 | /* 8. */ | ||
179 | cx25840_write(client, 0x401, 0x18); | ||
180 | cx25840_write(client, 0x4a2, 0x10); | ||
181 | cx25840_write(client, 0x402, 0x04); | ||
182 | /* 10. */ | ||
183 | cx25840_write(client, 0x8d3, 0x1f); | ||
184 | cx25840_write(client, 0x8e3, 0x03); | ||
185 | |||
186 | cx25840_vbi_setup(client); | ||
187 | |||
188 | /* trial and error says these are needed to get audio */ | ||
189 | cx25840_write(client, 0x914, 0xa0); | ||
190 | cx25840_write(client, 0x918, 0xa0); | ||
191 | cx25840_write(client, 0x919, 0x01); | ||
192 | |||
193 | /* stereo prefered */ | ||
194 | cx25840_write(client, 0x809, 0x04); | ||
195 | /* AC97 shift */ | ||
196 | cx25840_write(client, 0x8cf, 0x0f); | ||
197 | |||
198 | /* (re)set video input */ | ||
199 | set_input(client, state->input); | ||
200 | /* (re)set audio input */ | ||
201 | cx25840_audio(client, AUDC_SET_INPUT, &state->audio_input); | ||
202 | |||
203 | /* start microcontroller */ | ||
204 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
205 | } | ||
206 | |||
207 | /* ----------------------------------------------------------------------- */ | ||
208 | |||
209 | static void input_change(struct i2c_client *client) | ||
210 | { | ||
211 | v4l2_std_id std = cx25840_get_v4lstd(client); | ||
212 | |||
213 | if (std & V4L2_STD_PAL) { | ||
214 | /* Follow tuner change procedure for PAL */ | ||
215 | cx25840_write(client, 0x808, 0xff); | ||
216 | cx25840_write(client, 0x80b, 0x10); | ||
217 | } else if (std & V4L2_STD_SECAM) { | ||
218 | /* Select autodetect for SECAM */ | ||
219 | cx25840_write(client, 0x808, 0xff); | ||
220 | cx25840_write(client, 0x80b, 0x10); | ||
221 | } else if (std & V4L2_STD_NTSC) { | ||
222 | /* NTSC */ | ||
223 | cx25840_write(client, 0x808, 0xf6); | ||
224 | cx25840_write(client, 0x80b, 0x00); | ||
225 | } | ||
226 | |||
227 | if (cx25840_read(client, 0x803) & 0x10) { | ||
228 | /* restart audio decoder microcontroller */ | ||
229 | cx25840_and_or(client, 0x803, ~0x10, 0x00); | ||
230 | cx25840_and_or(client, 0x803, ~0x10, 0x10); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static int set_input(struct i2c_client *client, enum cx25840_input input) | ||
235 | { | ||
236 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
237 | |||
238 | cx25840_dbg("decoder set input (%d)\n", input); | ||
239 | |||
240 | switch (input) { | ||
241 | case CX25840_TUNER: | ||
242 | cx25840_dbg("now setting Tuner input\n"); | ||
243 | |||
244 | if (state->cardtype == CARDTYPE_PVR150) { | ||
245 | /* CH_SEL_ADC2=1 */ | ||
246 | cx25840_and_or(client, 0x102, ~0x2, 0x02); | ||
247 | } | ||
248 | |||
249 | /* Video Input Control */ | ||
250 | if (state->cardtype == CARDTYPE_PG600) { | ||
251 | cx25840_write(client, 0x103, 0x11); | ||
252 | } else { | ||
253 | cx25840_write(client, 0x103, 0x46); | ||
254 | } | ||
255 | |||
256 | /* INPUT_MODE=0 */ | ||
257 | cx25840_and_or(client, 0x401, ~0x6, 0x00); | ||
258 | break; | ||
259 | |||
260 | case CX25840_COMPOSITE0: | ||
261 | case CX25840_COMPOSITE1: | ||
262 | cx25840_dbg("now setting Composite input\n"); | ||
263 | |||
264 | /* Video Input Control */ | ||
265 | if (state->cardtype == CARDTYPE_PG600) { | ||
266 | cx25840_write(client, 0x103, 0x00); | ||
267 | } else { | ||
268 | cx25840_write(client, 0x103, 0x02); | ||
269 | } | ||
270 | |||
271 | /* INPUT_MODE=0 */ | ||
272 | cx25840_and_or(client, 0x401, ~0x6, 0x00); | ||
273 | break; | ||
274 | |||
275 | case CX25840_SVIDEO0: | ||
276 | case CX25840_SVIDEO1: | ||
277 | cx25840_dbg("now setting S-Video input\n"); | ||
278 | |||
279 | /* CH_SEL_ADC2=0 */ | ||
280 | cx25840_and_or(client, 0x102, ~0x2, 0x00); | ||
281 | |||
282 | /* Video Input Control */ | ||
283 | if (state->cardtype == CARDTYPE_PG600) { | ||
284 | cx25840_write(client, 0x103, 0x02); | ||
285 | } else { | ||
286 | cx25840_write(client, 0x103, 0x10); | ||
287 | } | ||
288 | |||
289 | /* INPUT_MODE=1 */ | ||
290 | cx25840_and_or(client, 0x401, ~0x6, 0x02); | ||
291 | break; | ||
292 | |||
293 | default: | ||
294 | cx25840_err("%d is not a valid input!\n", input); | ||
295 | return -EINVAL; | ||
296 | } | ||
297 | |||
298 | state->input = input; | ||
299 | input_change(client); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /* ----------------------------------------------------------------------- */ | ||
304 | |||
305 | static int set_v4lstd(struct i2c_client *client, v4l2_std_id std) | ||
306 | { | ||
307 | u8 fmt; | ||
308 | |||
309 | switch (std) { | ||
310 | /* zero is autodetect */ | ||
311 | case 0: fmt = 0x0; break; | ||
312 | /* default ntsc to ntsc-m */ | ||
313 | case V4L2_STD_NTSC: | ||
314 | case V4L2_STD_NTSC_M: fmt = 0x1; break; | ||
315 | case V4L2_STD_NTSC_M_JP: fmt = 0x2; break; | ||
316 | case V4L2_STD_NTSC_443: fmt = 0x3; break; | ||
317 | case V4L2_STD_PAL: fmt = 0x4; break; | ||
318 | case V4L2_STD_PAL_M: fmt = 0x5; break; | ||
319 | case V4L2_STD_PAL_N: fmt = 0x6; break; | ||
320 | case V4L2_STD_PAL_Nc: fmt = 0x7; break; | ||
321 | case V4L2_STD_PAL_60: fmt = 0x8; break; | ||
322 | case V4L2_STD_SECAM: fmt = 0xc; break; | ||
323 | default: | ||
324 | return -ERANGE; | ||
325 | } | ||
326 | |||
327 | cx25840_and_or(client, 0x400, ~0xf, fmt); | ||
328 | cx25840_vbi_setup(client); | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client) | ||
333 | { | ||
334 | /* check VID_FMT_SEL first */ | ||
335 | u8 fmt = cx25840_read(client, 0x400) & 0xf; | ||
336 | |||
337 | if (!fmt) { | ||
338 | /* check AFD_FMT_STAT if set to autodetect */ | ||
339 | fmt = cx25840_read(client, 0x40d) & 0xf; | ||
340 | } | ||
341 | |||
342 | switch (fmt) { | ||
343 | case 0x1: return V4L2_STD_NTSC_M; | ||
344 | case 0x2: return V4L2_STD_NTSC_M_JP; | ||
345 | case 0x3: return V4L2_STD_NTSC_443; | ||
346 | case 0x4: return V4L2_STD_PAL; | ||
347 | case 0x5: return V4L2_STD_PAL_M; | ||
348 | case 0x6: return V4L2_STD_PAL_N; | ||
349 | case 0x7: return V4L2_STD_PAL_Nc; | ||
350 | case 0x8: return V4L2_STD_PAL_60; | ||
351 | case 0xc: return V4L2_STD_SECAM; | ||
352 | default: return V4L2_STD_UNKNOWN; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | /* ----------------------------------------------------------------------- */ | ||
357 | |||
358 | static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
359 | { | ||
360 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
361 | |||
362 | switch (ctrl->id) { | ||
363 | case CX25840_CID_CARDTYPE: | ||
364 | switch (ctrl->value) { | ||
365 | case CARDTYPE_PVR150: | ||
366 | case CARDTYPE_PG600: | ||
367 | state->cardtype = ctrl->value; | ||
368 | break; | ||
369 | default: | ||
370 | return -ERANGE; | ||
371 | } | ||
372 | |||
373 | set_input(client, state->input); | ||
374 | break; | ||
375 | |||
376 | case V4L2_CID_BRIGHTNESS: | ||
377 | if (ctrl->value < 0 || ctrl->value > 255) { | ||
378 | cx25840_err("invalid brightness setting %d\n", | ||
379 | ctrl->value); | ||
380 | return -ERANGE; | ||
381 | } | ||
382 | |||
383 | cx25840_write(client, 0x414, ctrl->value - 128); | ||
384 | break; | ||
385 | |||
386 | case V4L2_CID_CONTRAST: | ||
387 | if (ctrl->value < 0 || ctrl->value > 127) { | ||
388 | cx25840_err("invalid contrast setting %d\n", | ||
389 | ctrl->value); | ||
390 | return -ERANGE; | ||
391 | } | ||
392 | |||
393 | cx25840_write(client, 0x415, ctrl->value << 1); | ||
394 | break; | ||
395 | |||
396 | case V4L2_CID_SATURATION: | ||
397 | if (ctrl->value < 0 || ctrl->value > 127) { | ||
398 | cx25840_err("invalid saturation setting %d\n", | ||
399 | ctrl->value); | ||
400 | return -ERANGE; | ||
401 | } | ||
402 | |||
403 | cx25840_write(client, 0x420, ctrl->value << 1); | ||
404 | cx25840_write(client, 0x421, ctrl->value << 1); | ||
405 | break; | ||
406 | |||
407 | case V4L2_CID_HUE: | ||
408 | if (ctrl->value < -127 || ctrl->value > 127) { | ||
409 | cx25840_err("invalid hue setting %d\n", ctrl->value); | ||
410 | return -ERANGE; | ||
411 | } | ||
412 | |||
413 | cx25840_write(client, 0x422, ctrl->value); | ||
414 | break; | ||
415 | |||
416 | case V4L2_CID_AUDIO_VOLUME: | ||
417 | case V4L2_CID_AUDIO_BASS: | ||
418 | case V4L2_CID_AUDIO_TREBLE: | ||
419 | case V4L2_CID_AUDIO_BALANCE: | ||
420 | case V4L2_CID_AUDIO_MUTE: | ||
421 | return cx25840_audio(client, VIDIOC_S_CTRL, ctrl); | ||
422 | } | ||
423 | |||
424 | return 0; | ||
425 | } | ||
426 | |||
427 | static int get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
428 | { | ||
429 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
430 | |||
431 | switch (ctrl->id) { | ||
432 | case CX25840_CID_CARDTYPE: | ||
433 | ctrl->value = state->cardtype; | ||
434 | break; | ||
435 | case V4L2_CID_BRIGHTNESS: | ||
436 | ctrl->value = cx25840_read(client, 0x414) + 128; | ||
437 | break; | ||
438 | case V4L2_CID_CONTRAST: | ||
439 | ctrl->value = cx25840_read(client, 0x415) >> 1; | ||
440 | break; | ||
441 | case V4L2_CID_SATURATION: | ||
442 | ctrl->value = cx25840_read(client, 0x420) >> 1; | ||
443 | break; | ||
444 | case V4L2_CID_HUE: | ||
445 | ctrl->value = cx25840_read(client, 0x422); | ||
446 | break; | ||
447 | case V4L2_CID_AUDIO_VOLUME: | ||
448 | case V4L2_CID_AUDIO_BASS: | ||
449 | case V4L2_CID_AUDIO_TREBLE: | ||
450 | case V4L2_CID_AUDIO_BALANCE: | ||
451 | case V4L2_CID_AUDIO_MUTE: | ||
452 | return cx25840_audio(client, VIDIOC_G_CTRL, ctrl); | ||
453 | default: | ||
454 | return -EINVAL; | ||
455 | } | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | /* ----------------------------------------------------------------------- */ | ||
461 | |||
462 | static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) | ||
463 | { | ||
464 | switch (fmt->type) { | ||
465 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
466 | return cx25840_vbi(client, VIDIOC_G_FMT, fmt); | ||
467 | default: | ||
468 | return -EINVAL; | ||
469 | } | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) | ||
475 | { | ||
476 | struct v4l2_pix_format *pix; | ||
477 | int HSC, VSC, Vsrc, Hsrc, filter, Vlines; | ||
478 | int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC); | ||
479 | |||
480 | switch (fmt->type) { | ||
481 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
482 | pix = &(fmt->fmt.pix); | ||
483 | |||
484 | Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4; | ||
485 | Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4; | ||
486 | |||
487 | Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4; | ||
488 | Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4; | ||
489 | |||
490 | Vlines = pix->height + (is_pal ? 4 : 7); | ||
491 | |||
492 | if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) || | ||
493 | (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { | ||
494 | cx25840_err("%dx%d is not a valid size!\n", | ||
495 | pix->width, pix->height); | ||
496 | return -ERANGE; | ||
497 | } | ||
498 | |||
499 | HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20); | ||
500 | VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); | ||
501 | VSC &= 0x1fff; | ||
502 | |||
503 | if (pix->width >= 385) | ||
504 | filter = 0; | ||
505 | else if (pix->width > 192) | ||
506 | filter = 1; | ||
507 | else if (pix->width > 96) | ||
508 | filter = 2; | ||
509 | else | ||
510 | filter = 3; | ||
511 | |||
512 | cx25840_dbg("decoder set size %dx%d -> scale %ux%u\n", | ||
513 | pix->width, pix->height, HSC, VSC); | ||
514 | |||
515 | /* HSCALE=HSC */ | ||
516 | cx25840_write(client, 0x418, HSC & 0xff); | ||
517 | cx25840_write(client, 0x419, (HSC >> 8) & 0xff); | ||
518 | cx25840_write(client, 0x41a, HSC >> 16); | ||
519 | /* VSCALE=VSC */ | ||
520 | cx25840_write(client, 0x41c, VSC & 0xff); | ||
521 | cx25840_write(client, 0x41d, VSC >> 8); | ||
522 | /* VS_INTRLACE=1 VFILT=filter */ | ||
523 | cx25840_write(client, 0x41e, 0x8 | filter); | ||
524 | break; | ||
525 | |||
526 | case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: | ||
527 | return cx25840_vbi(client, VIDIOC_S_FMT, fmt); | ||
528 | |||
529 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
530 | return cx25840_vbi(client, VIDIOC_S_FMT, fmt); | ||
531 | |||
532 | default: | ||
533 | return -EINVAL; | ||
534 | } | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | /* ----------------------------------------------------------------------- */ | ||
540 | |||
541 | static int cx25840_command(struct i2c_client *client, unsigned int cmd, | ||
542 | void *arg) | ||
543 | { | ||
544 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
545 | struct v4l2_tuner *vt = arg; | ||
546 | int result = 0; | ||
547 | |||
548 | switch (cmd) { | ||
549 | case 0: | ||
550 | break; | ||
551 | |||
552 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
553 | /* ioctls to allow direct access to the | ||
554 | * cx25840 registers for testing */ | ||
555 | case VIDIOC_INT_G_REGISTER: | ||
556 | { | ||
557 | struct v4l2_register *reg = arg; | ||
558 | |||
559 | if (reg->i2c_id != I2C_DRIVERID_CX25840) | ||
560 | return -EINVAL; | ||
561 | reg->val = cx25840_read(client, reg->reg & 0x0fff); | ||
562 | break; | ||
563 | } | ||
564 | |||
565 | case VIDIOC_INT_S_REGISTER: | ||
566 | { | ||
567 | struct v4l2_register *reg = arg; | ||
568 | |||
569 | if (reg->i2c_id != I2C_DRIVERID_CX25840) | ||
570 | return -EINVAL; | ||
571 | if (!capable(CAP_SYS_ADMIN)) | ||
572 | return -EPERM; | ||
573 | cx25840_write(client, reg->reg & 0x0fff, reg->val & 0xff); | ||
574 | break; | ||
575 | } | ||
576 | #endif | ||
577 | |||
578 | case VIDIOC_INT_DECODE_VBI_LINE: | ||
579 | return cx25840_vbi(client, cmd, arg); | ||
580 | |||
581 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | ||
582 | case AUDC_SET_INPUT: | ||
583 | result = cx25840_audio(client, cmd, arg); | ||
584 | break; | ||
585 | |||
586 | case VIDIOC_STREAMON: | ||
587 | cx25840_dbg("enable output\n"); | ||
588 | cx25840_write(client, 0x115, 0x8c); | ||
589 | cx25840_write(client, 0x116, 0x07); | ||
590 | break; | ||
591 | |||
592 | case VIDIOC_STREAMOFF: | ||
593 | cx25840_dbg("disable output\n"); | ||
594 | cx25840_write(client, 0x115, 0x00); | ||
595 | cx25840_write(client, 0x116, 0x00); | ||
596 | break; | ||
597 | |||
598 | case VIDIOC_LOG_STATUS: | ||
599 | log_status(client); | ||
600 | break; | ||
601 | |||
602 | case VIDIOC_G_CTRL: | ||
603 | result = get_v4lctrl(client, (struct v4l2_control *)arg); | ||
604 | break; | ||
605 | |||
606 | case VIDIOC_S_CTRL: | ||
607 | result = set_v4lctrl(client, (struct v4l2_control *)arg); | ||
608 | break; | ||
609 | |||
610 | case VIDIOC_G_STD: | ||
611 | *(v4l2_std_id *)arg = cx25840_get_v4lstd(client); | ||
612 | break; | ||
613 | |||
614 | case VIDIOC_S_STD: | ||
615 | result = set_v4lstd(client, *(v4l2_std_id *)arg); | ||
616 | break; | ||
617 | |||
618 | case VIDIOC_G_INPUT: | ||
619 | *(int *)arg = state->input; | ||
620 | break; | ||
621 | |||
622 | case VIDIOC_S_INPUT: | ||
623 | result = set_input(client, *(int *)arg); | ||
624 | break; | ||
625 | |||
626 | case VIDIOC_S_FREQUENCY: | ||
627 | input_change(client); | ||
628 | break; | ||
629 | |||
630 | case VIDIOC_G_TUNER: | ||
631 | { | ||
632 | u8 mode = cx25840_read(client, 0x804); | ||
633 | u8 pref = cx25840_read(client, 0x809) & 0xf; | ||
634 | u8 vpres = cx25840_read(client, 0x80a) & 0x10; | ||
635 | int val = 0; | ||
636 | |||
637 | vt->capability |= | ||
638 | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | | ||
639 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; | ||
640 | |||
641 | vt->signal = vpres ? 0xffff : 0x0; | ||
642 | |||
643 | /* get rxsubchans and audmode */ | ||
644 | if ((mode & 0xf) == 1) | ||
645 | val |= V4L2_TUNER_SUB_STEREO; | ||
646 | else | ||
647 | val |= V4L2_TUNER_SUB_MONO; | ||
648 | |||
649 | if (mode == 2 || mode == 4) | ||
650 | val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
651 | |||
652 | if (mode & 0x10) | ||
653 | val |= V4L2_TUNER_SUB_SAP; | ||
654 | |||
655 | vt->rxsubchans = val; | ||
656 | |||
657 | switch (pref) { | ||
658 | case 0: | ||
659 | vt->audmode = V4L2_TUNER_MODE_MONO; | ||
660 | break; | ||
661 | case 1: | ||
662 | case 2: | ||
663 | vt->audmode = V4L2_TUNER_MODE_LANG2; | ||
664 | break; | ||
665 | case 4: | ||
666 | default: | ||
667 | vt->audmode = V4L2_TUNER_MODE_STEREO; | ||
668 | } | ||
669 | break; | ||
670 | } | ||
671 | |||
672 | case VIDIOC_S_TUNER: | ||
673 | switch (vt->audmode) { | ||
674 | case V4L2_TUNER_MODE_MONO: | ||
675 | case V4L2_TUNER_MODE_LANG1: | ||
676 | /* Force PREF_MODE to MONO */ | ||
677 | cx25840_and_or(client, 0x809, ~0xf, 0x00); | ||
678 | break; | ||
679 | case V4L2_TUNER_MODE_STEREO: | ||
680 | /* Force PREF_MODE to STEREO */ | ||
681 | cx25840_and_or(client, 0x809, ~0xf, 0x04); | ||
682 | break; | ||
683 | case V4L2_TUNER_MODE_LANG2: | ||
684 | /* Force PREF_MODE to LANG2 */ | ||
685 | cx25840_and_or(client, 0x809, ~0xf, 0x01); | ||
686 | break; | ||
687 | } | ||
688 | break; | ||
689 | |||
690 | case VIDIOC_G_FMT: | ||
691 | result = get_v4lfmt(client, (struct v4l2_format *)arg); | ||
692 | break; | ||
693 | |||
694 | case VIDIOC_S_FMT: | ||
695 | result = set_v4lfmt(client, (struct v4l2_format *)arg); | ||
696 | break; | ||
697 | |||
698 | case VIDIOC_INT_RESET: | ||
699 | cx25840_initialize(client, 0); | ||
700 | break; | ||
701 | |||
702 | case VIDIOC_INT_G_CHIP_IDENT: | ||
703 | *(enum v4l2_chip_ident *)arg = | ||
704 | V4L2_IDENT_CX25840 + ((cx25840_read(client, 0x100) >> 4) & 0xf); | ||
705 | break; | ||
706 | |||
707 | default: | ||
708 | cx25840_err("invalid ioctl %x\n", cmd); | ||
709 | return -EINVAL; | ||
710 | } | ||
711 | |||
712 | return result; | ||
713 | } | ||
714 | |||
715 | /* ----------------------------------------------------------------------- */ | ||
716 | |||
717 | struct i2c_driver i2c_driver_cx25840; | ||
718 | |||
719 | static int cx25840_detect_client(struct i2c_adapter *adapter, int address, | ||
720 | int kind) | ||
721 | { | ||
722 | struct i2c_client *client; | ||
723 | struct cx25840_state *state; | ||
724 | u16 device_id; | ||
725 | |||
726 | /* Check if the adapter supports the needed features | ||
727 | * Not until kernel version 2.6.11 did the bit-algo | ||
728 | * correctly report that it would do an I2C-level xfer */ | ||
729 | if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) | ||
730 | return 0; | ||
731 | |||
732 | client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
733 | if (client == 0) | ||
734 | return -ENOMEM; | ||
735 | |||
736 | memset(client, 0, sizeof(struct i2c_client)); | ||
737 | client->addr = address; | ||
738 | client->adapter = adapter; | ||
739 | client->driver = &i2c_driver_cx25840; | ||
740 | client->flags = I2C_CLIENT_ALLOW_USE; | ||
741 | snprintf(client->name, sizeof(client->name) - 1, "cx25840"); | ||
742 | |||
743 | cx25840_dbg("detecting cx25840 client on address 0x%x\n", address << 1); | ||
744 | |||
745 | device_id = cx25840_read(client, 0x101) << 8; | ||
746 | device_id |= cx25840_read(client, 0x100); | ||
747 | |||
748 | /* The high byte of the device ID should be | ||
749 | * 0x84 if chip is present */ | ||
750 | if ((device_id & 0xff00) != 0x8400) { | ||
751 | cx25840_dbg("cx25840 not found\n"); | ||
752 | kfree(client); | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | cx25840_info("cx25%3x-2%x found @ 0x%x (%s)\n", | ||
757 | (device_id & 0xfff0) >> 4, | ||
758 | (device_id & 0x0f) < 3 ? (device_id & 0x0f) + 1 : 3, | ||
759 | address << 1, adapter->name); | ||
760 | |||
761 | state = kmalloc(sizeof(struct cx25840_state), GFP_KERNEL); | ||
762 | if (state == NULL) { | ||
763 | kfree(client); | ||
764 | return -ENOMEM; | ||
765 | } | ||
766 | |||
767 | i2c_set_clientdata(client, state); | ||
768 | memset(state, 0, sizeof(struct cx25840_state)); | ||
769 | state->input = CX25840_TUNER; | ||
770 | state->audclk_freq = V4L2_AUDCLK_48_KHZ; | ||
771 | state->audio_input = AUDIO_TUNER; | ||
772 | state->cardtype = CARDTYPE_PVR150; | ||
773 | |||
774 | cx25840_initialize(client, 1); | ||
775 | |||
776 | i2c_attach_client(client); | ||
777 | |||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static int cx25840_attach_adapter(struct i2c_adapter *adapter) | ||
782 | { | ||
783 | #ifdef I2C_CLASS_TV_ANALOG | ||
784 | if (adapter->class & I2C_CLASS_TV_ANALOG) | ||
785 | #else | ||
786 | if (adapter->id == I2C_HW_B_BT848) | ||
787 | #endif | ||
788 | return i2c_probe(adapter, &addr_data, &cx25840_detect_client); | ||
789 | return 0; | ||
790 | } | ||
791 | |||
792 | static int cx25840_detach_client(struct i2c_client *client) | ||
793 | { | ||
794 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
795 | int err; | ||
796 | |||
797 | err = i2c_detach_client(client); | ||
798 | if (err) { | ||
799 | return err; | ||
800 | } | ||
801 | |||
802 | kfree(state); | ||
803 | kfree(client); | ||
804 | |||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | /* ----------------------------------------------------------------------- */ | ||
809 | |||
810 | struct i2c_driver i2c_driver_cx25840 = { | ||
811 | .name = "cx25840", | ||
812 | |||
813 | .id = I2C_DRIVERID_CX25840, | ||
814 | .flags = I2C_DF_NOTIFY, | ||
815 | |||
816 | .attach_adapter = cx25840_attach_adapter, | ||
817 | .detach_client = cx25840_detach_client, | ||
818 | .command = cx25840_command, | ||
819 | .owner = THIS_MODULE, | ||
820 | }; | ||
821 | |||
822 | |||
823 | static int __init m__init(void) | ||
824 | { | ||
825 | return i2c_add_driver(&i2c_driver_cx25840); | ||
826 | } | ||
827 | |||
828 | static void __exit m__exit(void) | ||
829 | { | ||
830 | i2c_del_driver(&i2c_driver_cx25840); | ||
831 | } | ||
832 | |||
833 | module_init(m__init); | ||
834 | module_exit(m__exit); | ||
835 | |||
836 | /* ----------------------------------------------------------------------- */ | ||
837 | |||
838 | static void log_status(struct i2c_client *client) | ||
839 | { | ||
840 | static const char *const fmt_strs[] = { | ||
841 | "0x0", | ||
842 | "NTSC-M", "NTSC-J", "NTSC-4.43", | ||
843 | "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", | ||
844 | "0x9", "0xA", "0xB", | ||
845 | "SECAM", | ||
846 | "0xD", "0xE", "0xF" | ||
847 | }; | ||
848 | |||
849 | struct cx25840_state *state = i2c_get_clientdata(client); | ||
850 | u8 microctrl_vidfmt = cx25840_read(client, 0x80a); | ||
851 | u8 vidfmt_sel = cx25840_read(client, 0x400) & 0xf; | ||
852 | u8 gen_stat1 = cx25840_read(client, 0x40d); | ||
853 | u8 download_ctl = cx25840_read(client, 0x803); | ||
854 | u8 mod_det_stat0 = cx25840_read(client, 0x804); | ||
855 | u8 mod_det_stat1 = cx25840_read(client, 0x805); | ||
856 | u8 audio_config = cx25840_read(client, 0x808); | ||
857 | u8 pref_mode = cx25840_read(client, 0x809); | ||
858 | u8 afc0 = cx25840_read(client, 0x80b); | ||
859 | u8 mute_ctl = cx25840_read(client, 0x8d3); | ||
860 | char *p; | ||
861 | |||
862 | cx25840_info("Video signal: %spresent\n", | ||
863 | (microctrl_vidfmt & 0x10) ? "" : "not "); | ||
864 | cx25840_info("Detected format: %s\n", | ||
865 | fmt_strs[gen_stat1 & 0xf]); | ||
866 | |||
867 | switch (mod_det_stat0) { | ||
868 | case 0x00: p = "mono"; break; | ||
869 | case 0x01: p = "stereo"; break; | ||
870 | case 0x02: p = "dual"; break; | ||
871 | case 0x04: p = "tri"; break; | ||
872 | case 0x10: p = "mono with SAP"; break; | ||
873 | case 0x11: p = "stereo with SAP"; break; | ||
874 | case 0x12: p = "dual with SAP"; break; | ||
875 | case 0x14: p = "tri with SAP"; break; | ||
876 | case 0xfe: p = "forced mode"; break; | ||
877 | default: p = "not defined"; | ||
878 | } | ||
879 | cx25840_info("Detected audio mode: %s\n", p); | ||
880 | |||
881 | switch (mod_det_stat1) { | ||
882 | case 0x00: p = "not defined"; break; | ||
883 | case 0x01: p = "EIAJ"; break; | ||
884 | case 0x02: p = "A2-M"; break; | ||
885 | case 0x03: p = "A2-BG"; break; | ||
886 | case 0x04: p = "A2-DK1"; break; | ||
887 | case 0x05: p = "A2-DK2"; break; | ||
888 | case 0x06: p = "A2-DK3"; break; | ||
889 | case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; | ||
890 | case 0x08: p = "AM-L"; break; | ||
891 | case 0x09: p = "NICAM-BG"; break; | ||
892 | case 0x0a: p = "NICAM-DK"; break; | ||
893 | case 0x0b: p = "NICAM-I"; break; | ||
894 | case 0x0c: p = "NICAM-L"; break; | ||
895 | case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; | ||
896 | case 0x0e: p = "IF FM Radio"; break; | ||
897 | case 0x0f: p = "BTSC"; break; | ||
898 | case 0x10: p = "high-deviation FM"; break; | ||
899 | case 0x11: p = "very high-deviation FM"; break; | ||
900 | case 0xfd: p = "unknown audio standard"; break; | ||
901 | case 0xfe: p = "forced audio standard"; break; | ||
902 | case 0xff: p = "no detected audio standard"; break; | ||
903 | default: p = "not defined"; | ||
904 | } | ||
905 | cx25840_info("Detected audio standard: %s\n", p); | ||
906 | cx25840_info("Audio muted: %s\n", | ||
907 | (mute_ctl & 0x2) ? "yes" : "no"); | ||
908 | cx25840_info("Audio microcontroller: %s\n", | ||
909 | (download_ctl & 0x10) ? "running" : "stopped"); | ||
910 | |||
911 | switch (audio_config >> 4) { | ||
912 | case 0x00: p = "undefined"; break; | ||
913 | case 0x01: p = "BTSC"; break; | ||
914 | case 0x02: p = "EIAJ"; break; | ||
915 | case 0x03: p = "A2-M"; break; | ||
916 | case 0x04: p = "A2-BG"; break; | ||
917 | case 0x05: p = "A2-DK1"; break; | ||
918 | case 0x06: p = "A2-DK2"; break; | ||
919 | case 0x07: p = "A2-DK3"; break; | ||
920 | case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; | ||
921 | case 0x09: p = "AM-L"; break; | ||
922 | case 0x0a: p = "NICAM-BG"; break; | ||
923 | case 0x0b: p = "NICAM-DK"; break; | ||
924 | case 0x0c: p = "NICAM-I"; break; | ||
925 | case 0x0d: p = "NICAM-L"; break; | ||
926 | case 0x0e: p = "FM radio"; break; | ||
927 | case 0x0f: p = "automatic detection"; break; | ||
928 | default: p = "undefined"; | ||
929 | } | ||
930 | cx25840_info("Configured audio standard: %s\n", p); | ||
931 | |||
932 | if ((audio_config >> 4) < 0xF) { | ||
933 | switch (audio_config & 0xF) { | ||
934 | case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; | ||
935 | case 0x01: p = "MONO2 (LANGUAGE B)"; break; | ||
936 | case 0x02: p = "MONO3 (STEREO forced MONO)"; break; | ||
937 | case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; | ||
938 | case 0x04: p = "STEREO"; break; | ||
939 | case 0x05: p = "DUAL1 (AB)"; break; | ||
940 | case 0x06: p = "DUAL2 (AC) (FM)"; break; | ||
941 | case 0x07: p = "DUAL3 (BC) (FM)"; break; | ||
942 | case 0x08: p = "DUAL4 (AC) (AM)"; break; | ||
943 | case 0x09: p = "DUAL5 (BC) (AM)"; break; | ||
944 | case 0x0a: p = "SAP"; break; | ||
945 | default: p = "undefined"; | ||
946 | } | ||
947 | cx25840_info("Configured audio mode: %s\n", p); | ||
948 | } else { | ||
949 | switch (audio_config & 0xF) { | ||
950 | case 0x00: p = "BG"; break; | ||
951 | case 0x01: p = "DK1"; break; | ||
952 | case 0x02: p = "DK2"; break; | ||
953 | case 0x03: p = "DK3"; break; | ||
954 | case 0x04: p = "I"; break; | ||
955 | case 0x05: p = "L"; break; | ||
956 | case 0x06: p = "BTSC"; break; | ||
957 | case 0x07: p = "EIAJ"; break; | ||
958 | case 0x08: p = "A2-M"; break; | ||
959 | case 0x09: p = "FM Radio"; break; | ||
960 | case 0x0f: p = "automatic standard and mode detection"; break; | ||
961 | default: p = "undefined"; | ||
962 | } | ||
963 | cx25840_info("Configured audio system: %s\n", p); | ||
964 | } | ||
965 | |||
966 | cx25840_info("Specified standard: %s\n", | ||
967 | vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection"); | ||
968 | |||
969 | switch (state->input) { | ||
970 | case CX25840_COMPOSITE0: p = "Composite 0"; break; | ||
971 | case CX25840_COMPOSITE1: p = "Composite 1"; break; | ||
972 | case CX25840_SVIDEO0: p = "S-Video 0"; break; | ||
973 | case CX25840_SVIDEO1: p = "S-Video 1"; break; | ||
974 | case CX25840_TUNER: p = "Tuner"; break; | ||
975 | } | ||
976 | cx25840_info("Specified input: %s\n", p); | ||
977 | cx25840_info("Specified audio input: %s\n", | ||
978 | state->audio_input == 0 ? "Tuner" : "External"); | ||
979 | |||
980 | switch (state->audclk_freq) { | ||
981 | case V4L2_AUDCLK_441_KHZ: p = "44.1 kHz"; break; | ||
982 | case V4L2_AUDCLK_48_KHZ: p = "48 kHz"; break; | ||
983 | case V4L2_AUDCLK_32_KHZ: p = "32 kHz"; break; | ||
984 | default: p = "undefined"; | ||
985 | } | ||
986 | cx25840_info("Specified audioclock freq: %s\n", p); | ||
987 | |||
988 | switch (pref_mode & 0xf) { | ||
989 | case 0: p = "mono/language A"; break; | ||
990 | case 1: p = "language B"; break; | ||
991 | case 2: p = "language C"; break; | ||
992 | case 3: p = "analog fallback"; break; | ||
993 | case 4: p = "stereo"; break; | ||
994 | case 5: p = "language AC"; break; | ||
995 | case 6: p = "language BC"; break; | ||
996 | case 7: p = "language AB"; break; | ||
997 | default: p = "undefined"; | ||
998 | } | ||
999 | cx25840_info("Preferred audio mode: %s\n", p); | ||
1000 | |||
1001 | if ((audio_config & 0xf) == 0xf) { | ||
1002 | switch ((afc0 >> 3) & 0x3) { | ||
1003 | case 0: p = "system DK"; break; | ||
1004 | case 1: p = "system L"; break; | ||
1005 | case 2: p = "autodetect"; break; | ||
1006 | default: p = "undefined"; | ||
1007 | } | ||
1008 | cx25840_info("Selected 65 MHz format: %s\n", p); | ||
1009 | |||
1010 | switch (afc0 & 0x7) { | ||
1011 | case 0: p = "chroma"; break; | ||
1012 | case 1: p = "BTSC"; break; | ||
1013 | case 2: p = "EIAJ"; break; | ||
1014 | case 3: p = "A2-M"; break; | ||
1015 | case 4: p = "autodetect"; break; | ||
1016 | default: p = "undefined"; | ||
1017 | } | ||
1018 | cx25840_info("Selected 45 MHz format: %s\n", p); | ||
1019 | } | ||
1020 | } | ||
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c new file mode 100644 index 000000000000..df9d50a75542 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-firmware.c | |||
@@ -0,0 +1,167 @@ | |||
1 | /* cx25840 firmware functions | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU General Public License | ||
5 | * as published by the Free Software Foundation; either version 2 | ||
6 | * of the License, or (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/i2c-algo-bit.h> | ||
22 | #include <linux/firmware.h> | ||
23 | #include <media/v4l2-common.h> | ||
24 | |||
25 | #include "cx25840.h" | ||
26 | |||
27 | #define FWFILE "v4l-cx25840.fw" | ||
28 | #define FWSEND 1024 | ||
29 | |||
30 | #define FWDEV(x) &((x)->adapter->dev) | ||
31 | |||
32 | static int fastfw = 1; | ||
33 | static char *firmware = FWFILE; | ||
34 | |||
35 | module_param(fastfw, bool, 0444); | ||
36 | module_param(firmware, charp, 0444); | ||
37 | |||
38 | MODULE_PARM_DESC(fastfw, "Load firmware fast [0=100MHz 1=333MHz (default)]"); | ||
39 | MODULE_PARM_DESC(firmware, "Firmware image [default: " FWFILE "]"); | ||
40 | |||
41 | static inline void set_i2c_delay(struct i2c_client *client, int delay) | ||
42 | { | ||
43 | struct i2c_algo_bit_data *algod = client->adapter->algo_data; | ||
44 | |||
45 | /* We aren't guaranteed to be using algo_bit, | ||
46 | * so avoid the null pointer dereference | ||
47 | * and disable the 'fast firmware load' */ | ||
48 | if (algod) { | ||
49 | algod->udelay = delay; | ||
50 | } else { | ||
51 | fastfw = 0; | ||
52 | } | ||
53 | } | ||
54 | |||
55 | static inline void start_fw_load(struct i2c_client *client) | ||
56 | { | ||
57 | /* DL_ADDR_LB=0 DL_ADDR_HB=0 */ | ||
58 | cx25840_write(client, 0x800, 0x00); | ||
59 | cx25840_write(client, 0x801, 0x00); | ||
60 | // DL_MAP=3 DL_AUTO_INC=0 DL_ENABLE=1 | ||
61 | cx25840_write(client, 0x803, 0x0b); | ||
62 | /* AUTO_INC_DIS=1 */ | ||
63 | cx25840_write(client, 0x000, 0x20); | ||
64 | |||
65 | if (fastfw) | ||
66 | set_i2c_delay(client, 3); | ||
67 | } | ||
68 | |||
69 | static inline void end_fw_load(struct i2c_client *client) | ||
70 | { | ||
71 | if (fastfw) | ||
72 | set_i2c_delay(client, 10); | ||
73 | |||
74 | /* AUTO_INC_DIS=0 */ | ||
75 | cx25840_write(client, 0x000, 0x00); | ||
76 | /* DL_ENABLE=0 */ | ||
77 | cx25840_write(client, 0x803, 0x03); | ||
78 | } | ||
79 | |||
80 | static inline int check_fw_load(struct i2c_client *client, int size) | ||
81 | { | ||
82 | /* DL_ADDR_HB DL_ADDR_LB */ | ||
83 | int s = cx25840_read(client, 0x801) << 8; | ||
84 | s |= cx25840_read(client, 0x800); | ||
85 | |||
86 | if (size != s) { | ||
87 | cx25840_err("firmware %s load failed\n", firmware); | ||
88 | return -EINVAL; | ||
89 | } | ||
90 | |||
91 | cx25840_info("loaded %s firmware (%d bytes)\n", firmware, size); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static inline int fw_write(struct i2c_client *client, u8 * data, int size) | ||
96 | { | ||
97 | if (i2c_master_send(client, data, size) < size) { | ||
98 | |||
99 | if (fastfw) { | ||
100 | cx25840_err("333MHz i2c firmware load failed\n"); | ||
101 | fastfw = 0; | ||
102 | set_i2c_delay(client, 10); | ||
103 | |||
104 | if (i2c_master_send(client, data, size) < size) { | ||
105 | cx25840_err | ||
106 | ("100MHz i2c firmware load failed\n"); | ||
107 | return -ENOSYS; | ||
108 | } | ||
109 | |||
110 | } else { | ||
111 | cx25840_err("firmware load i2c failure\n"); | ||
112 | return -ENOSYS; | ||
113 | } | ||
114 | |||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | int cx25840_loadfw(struct i2c_client *client) | ||
121 | { | ||
122 | const struct firmware *fw = NULL; | ||
123 | u8 buffer[4], *ptr; | ||
124 | int size, send, retval; | ||
125 | |||
126 | if (request_firmware(&fw, firmware, FWDEV(client)) != 0) { | ||
127 | cx25840_err("unable to open firmware %s\n", firmware); | ||
128 | return -EINVAL; | ||
129 | } | ||
130 | |||
131 | start_fw_load(client); | ||
132 | |||
133 | buffer[0] = 0x08; | ||
134 | buffer[1] = 0x02; | ||
135 | buffer[2] = fw->data[0]; | ||
136 | buffer[3] = fw->data[1]; | ||
137 | retval = fw_write(client, buffer, 4); | ||
138 | |||
139 | if (retval < 0) { | ||
140 | release_firmware(fw); | ||
141 | return retval; | ||
142 | } | ||
143 | |||
144 | size = fw->size - 2; | ||
145 | ptr = fw->data; | ||
146 | while (size > 0) { | ||
147 | ptr[0] = 0x08; | ||
148 | ptr[1] = 0x02; | ||
149 | send = size > (FWSEND - 2) ? FWSEND : size + 2; | ||
150 | retval = fw_write(client, ptr, send); | ||
151 | |||
152 | if (retval < 0) { | ||
153 | release_firmware(fw); | ||
154 | return retval; | ||
155 | } | ||
156 | |||
157 | size -= FWSEND - 2; | ||
158 | ptr += FWSEND - 2; | ||
159 | } | ||
160 | |||
161 | end_fw_load(client); | ||
162 | |||
163 | size = fw->size; | ||
164 | release_firmware(fw); | ||
165 | |||
166 | return check_fw_load(client, size); | ||
167 | } | ||
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c new file mode 100644 index 000000000000..13ba4e15ddea --- /dev/null +++ b/drivers/media/video/cx25840/cx25840-vbi.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* cx25840 VBI functions | ||
2 | * | ||
3 | * This program is free software; you can redistribute it and/or | ||
4 | * modify it under the terms of the GNU General Public License | ||
5 | * as published by the Free Software Foundation; either version 2 | ||
6 | * of the License, or (at your option) any later version. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program; if not, write to the Free Software | ||
15 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include <linux/videodev2.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <media/v4l2-common.h> | ||
22 | |||
23 | #include "cx25840.h" | ||
24 | |||
25 | static inline int odd_parity(u8 c) | ||
26 | { | ||
27 | c ^= (c >> 4); | ||
28 | c ^= (c >> 2); | ||
29 | c ^= (c >> 1); | ||
30 | |||
31 | return c & 1; | ||
32 | } | ||
33 | |||
34 | static inline int decode_vps(u8 * dst, u8 * p) | ||
35 | { | ||
36 | static const u8 biphase_tbl[] = { | ||
37 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
38 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
39 | 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, | ||
40 | 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, | ||
41 | 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, | ||
42 | 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, | ||
43 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
44 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
45 | 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, | ||
46 | 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, | ||
47 | 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, | ||
48 | 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, | ||
49 | 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, | ||
50 | 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, | ||
51 | 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, | ||
52 | 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, | ||
53 | 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, | ||
54 | 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, | ||
55 | 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, | ||
56 | 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, | ||
57 | 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, | ||
58 | 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, | ||
59 | 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, | ||
60 | 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, | ||
61 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
62 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
63 | 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, | ||
64 | 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, | ||
65 | 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, | ||
66 | 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, | ||
67 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
68 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
69 | }; | ||
70 | |||
71 | u8 c, err = 0; | ||
72 | int i; | ||
73 | |||
74 | for (i = 0; i < 2 * 13; i += 2) { | ||
75 | err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; | ||
76 | c = (biphase_tbl[p[i + 1]] & 0xf) | | ||
77 | ((biphase_tbl[p[i]] & 0xf) << 4); | ||
78 | dst[i / 2] = c; | ||
79 | } | ||
80 | |||
81 | return err & 0xf0; | ||
82 | } | ||
83 | |||
84 | void cx25840_vbi_setup(struct i2c_client *client) | ||
85 | { | ||
86 | v4l2_std_id std = cx25840_get_v4lstd(client); | ||
87 | |||
88 | if (std & ~V4L2_STD_NTSC) { | ||
89 | /* datasheet startup, step 8d */ | ||
90 | cx25840_write(client, 0x49f, 0x11); | ||
91 | |||
92 | cx25840_write(client, 0x470, 0x84); | ||
93 | cx25840_write(client, 0x471, 0x00); | ||
94 | cx25840_write(client, 0x472, 0x2d); | ||
95 | cx25840_write(client, 0x473, 0x5d); | ||
96 | |||
97 | cx25840_write(client, 0x474, 0x24); | ||
98 | cx25840_write(client, 0x475, 0x40); | ||
99 | cx25840_write(client, 0x476, 0x24); | ||
100 | cx25840_write(client, 0x477, 0x28); | ||
101 | |||
102 | cx25840_write(client, 0x478, 0x1f); | ||
103 | cx25840_write(client, 0x479, 0x02); | ||
104 | |||
105 | if (std & V4L2_STD_SECAM) { | ||
106 | cx25840_write(client, 0x47a, 0x80); | ||
107 | cx25840_write(client, 0x47b, 0x00); | ||
108 | cx25840_write(client, 0x47c, 0x5f); | ||
109 | cx25840_write(client, 0x47d, 0x42); | ||
110 | } else { | ||
111 | cx25840_write(client, 0x47a, 0x90); | ||
112 | cx25840_write(client, 0x47b, 0x20); | ||
113 | cx25840_write(client, 0x47c, 0x63); | ||
114 | cx25840_write(client, 0x47d, 0x82); | ||
115 | } | ||
116 | |||
117 | cx25840_write(client, 0x47e, 0x0a); | ||
118 | cx25840_write(client, 0x47f, 0x01); | ||
119 | } else { | ||
120 | /* datasheet startup, step 8d */ | ||
121 | cx25840_write(client, 0x49f, 0x14); | ||
122 | |||
123 | cx25840_write(client, 0x470, 0x7a); | ||
124 | cx25840_write(client, 0x471, 0x00); | ||
125 | cx25840_write(client, 0x472, 0x2d); | ||
126 | cx25840_write(client, 0x473, 0x5b); | ||
127 | |||
128 | cx25840_write(client, 0x474, 0x1a); | ||
129 | cx25840_write(client, 0x475, 0x70); | ||
130 | cx25840_write(client, 0x476, 0x1e); | ||
131 | cx25840_write(client, 0x477, 0x1e); | ||
132 | |||
133 | cx25840_write(client, 0x478, 0x1f); | ||
134 | cx25840_write(client, 0x479, 0x02); | ||
135 | cx25840_write(client, 0x47a, 0x50); | ||
136 | cx25840_write(client, 0x47b, 0x66); | ||
137 | |||
138 | cx25840_write(client, 0x47c, 0x1f); | ||
139 | cx25840_write(client, 0x47d, 0x7c); | ||
140 | cx25840_write(client, 0x47e, 0x08); | ||
141 | cx25840_write(client, 0x47f, 0x00); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) | ||
146 | { | ||
147 | struct v4l2_format *fmt; | ||
148 | struct v4l2_sliced_vbi_format *svbi; | ||
149 | |||
150 | switch (cmd) { | ||
151 | case VIDIOC_G_FMT: | ||
152 | { | ||
153 | static u16 lcr2vbi[] = { | ||
154 | 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ | ||
155 | 0, V4L2_SLICED_WSS_625, 0, /* 4 */ | ||
156 | V4L2_SLICED_CAPTION_525, /* 6 */ | ||
157 | 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ | ||
158 | 0, 0, 0, 0 | ||
159 | }; | ||
160 | int i; | ||
161 | |||
162 | fmt = arg; | ||
163 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
164 | return -EINVAL; | ||
165 | svbi = &fmt->fmt.sliced; | ||
166 | memset(svbi, 0, sizeof(*svbi)); | ||
167 | /* we're done if raw VBI is active */ | ||
168 | if ((cx25840_read(client, 0x404) & 0x10) == 0) | ||
169 | break; | ||
170 | |||
171 | for (i = 7; i <= 23; i++) { | ||
172 | u8 v = cx25840_read(client, 0x424 + i - 7); | ||
173 | |||
174 | svbi->service_lines[0][i] = lcr2vbi[v >> 4]; | ||
175 | svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; | ||
176 | svbi->service_set |= | ||
177 | svbi->service_lines[0][i] | svbi->service_lines[1][i]; | ||
178 | } | ||
179 | break; | ||
180 | } | ||
181 | |||
182 | case VIDIOC_S_FMT: | ||
183 | { | ||
184 | int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_NTSC); | ||
185 | int vbi_offset = is_pal ? 1 : 0; | ||
186 | int i, x; | ||
187 | u8 lcr[24]; | ||
188 | |||
189 | fmt = arg; | ||
190 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
191 | return -EINVAL; | ||
192 | svbi = &fmt->fmt.sliced; | ||
193 | if (svbi->service_set == 0) { | ||
194 | /* raw VBI */ | ||
195 | memset(svbi, 0, sizeof(*svbi)); | ||
196 | |||
197 | /* Setup VBI */ | ||
198 | cx25840_vbi_setup(client); | ||
199 | |||
200 | /* VBI Offset */ | ||
201 | cx25840_write(client, 0x47f, vbi_offset); | ||
202 | cx25840_write(client, 0x404, 0x2e); | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | for (x = 0; x <= 23; x++) | ||
207 | lcr[x] = 0x00; | ||
208 | |||
209 | /* Setup VBI */ | ||
210 | cx25840_vbi_setup(client); | ||
211 | |||
212 | /* Sliced VBI */ | ||
213 | cx25840_write(client, 0x404, 0x36); /* Ancillery data */ | ||
214 | cx25840_write(client, 0x406, 0x13); | ||
215 | cx25840_write(client, 0x47f, vbi_offset); | ||
216 | |||
217 | if (is_pal) { | ||
218 | for (i = 0; i <= 6; i++) | ||
219 | svbi->service_lines[0][i] = | ||
220 | svbi->service_lines[1][i] = 0; | ||
221 | } else { | ||
222 | for (i = 0; i <= 9; i++) | ||
223 | svbi->service_lines[0][i] = | ||
224 | svbi->service_lines[1][i] = 0; | ||
225 | |||
226 | for (i = 22; i <= 23; i++) | ||
227 | svbi->service_lines[0][i] = | ||
228 | svbi->service_lines[1][i] = 0; | ||
229 | } | ||
230 | |||
231 | for (i = 7; i <= 23; i++) { | ||
232 | for (x = 0; x <= 1; x++) { | ||
233 | switch (svbi->service_lines[1-x][i]) { | ||
234 | case V4L2_SLICED_TELETEXT_B: | ||
235 | lcr[i] |= 1 << (4 * x); | ||
236 | break; | ||
237 | case V4L2_SLICED_WSS_625: | ||
238 | lcr[i] |= 4 << (4 * x); | ||
239 | break; | ||
240 | case V4L2_SLICED_CAPTION_525: | ||
241 | lcr[i] |= 6 << (4 * x); | ||
242 | break; | ||
243 | case V4L2_SLICED_VPS: | ||
244 | lcr[i] |= 9 << (4 * x); | ||
245 | break; | ||
246 | } | ||
247 | } | ||
248 | } | ||
249 | |||
250 | for (x = 1, i = 0x424; i <= 0x434; i++, x++) { | ||
251 | cx25840_write(client, i, lcr[6 + x]); | ||
252 | } | ||
253 | |||
254 | cx25840_write(client, 0x43c, 0x16); | ||
255 | |||
256 | if (is_pal) { | ||
257 | cx25840_write(client, 0x474, 0x2a); | ||
258 | } else { | ||
259 | cx25840_write(client, 0x474, 0x1a + 6); | ||
260 | } | ||
261 | break; | ||
262 | } | ||
263 | |||
264 | case VIDIOC_INT_DECODE_VBI_LINE: | ||
265 | { | ||
266 | struct v4l2_decode_vbi_line *vbi = arg; | ||
267 | u8 *p = vbi->p; | ||
268 | int id1, id2, l, err = 0; | ||
269 | |||
270 | if (p[0] || p[1] != 0xff || p[2] != 0xff || | ||
271 | (p[3] != 0x55 && p[3] != 0x91)) { | ||
272 | vbi->line = vbi->type = 0; | ||
273 | break; | ||
274 | } | ||
275 | |||
276 | p += 4; | ||
277 | id1 = p[-1]; | ||
278 | id2 = p[0] & 0xf; | ||
279 | l = p[2] & 0x3f; | ||
280 | l += 5; | ||
281 | p += 4; | ||
282 | |||
283 | switch (id2) { | ||
284 | case 1: | ||
285 | id2 = V4L2_SLICED_TELETEXT_B; | ||
286 | break; | ||
287 | case 4: | ||
288 | id2 = V4L2_SLICED_WSS_625; | ||
289 | break; | ||
290 | case 6: | ||
291 | id2 = V4L2_SLICED_CAPTION_525; | ||
292 | err = !odd_parity(p[0]) || !odd_parity(p[1]); | ||
293 | break; | ||
294 | case 9: | ||
295 | id2 = V4L2_SLICED_VPS; | ||
296 | if (decode_vps(p, p) != 0) { | ||
297 | err = 1; | ||
298 | } | ||
299 | break; | ||
300 | default: | ||
301 | id2 = 0; | ||
302 | err = 1; | ||
303 | break; | ||
304 | } | ||
305 | |||
306 | vbi->type = err ? 0 : id2; | ||
307 | vbi->line = err ? 0 : l; | ||
308 | vbi->is_second_field = err ? 0 : (id1 == 0x55); | ||
309 | vbi->p = p; | ||
310 | break; | ||
311 | } | ||
312 | } | ||
313 | |||
314 | return 0; | ||
315 | } | ||
diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h new file mode 100644 index 000000000000..5c3f0639fb77 --- /dev/null +++ b/drivers/media/video/cx25840/cx25840.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /* cx25840 API header | ||
2 | * | ||
3 | * Copyright (C) 2003-2004 Chris Kennedy | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
18 | */ | ||
19 | |||
20 | #ifndef _CX25840_H_ | ||
21 | #define _CX25840_H_ | ||
22 | |||
23 | |||
24 | #include <linux/videodev2.h> | ||
25 | #include <linux/i2c.h> | ||
26 | |||
27 | extern int cx25840_debug; | ||
28 | |||
29 | #define cx25840_dbg(fmt, arg...) do { if (cx25840_debug) \ | ||
30 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
31 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
32 | |||
33 | #define cx25840_err(fmt, arg...) do { \ | ||
34 | printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \ | ||
35 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
36 | |||
37 | #define cx25840_info(fmt, arg...) do { \ | ||
38 | printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \ | ||
39 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
40 | |||
41 | #define CX25840_CID_CARDTYPE (V4L2_CID_PRIVATE_BASE+0) | ||
42 | |||
43 | enum cx25840_cardtype { | ||
44 | CARDTYPE_PVR150, | ||
45 | CARDTYPE_PG600 | ||
46 | }; | ||
47 | |||
48 | enum cx25840_input { | ||
49 | CX25840_TUNER, | ||
50 | CX25840_COMPOSITE0, | ||
51 | CX25840_COMPOSITE1, | ||
52 | CX25840_SVIDEO0, | ||
53 | CX25840_SVIDEO1 | ||
54 | }; | ||
55 | |||
56 | struct cx25840_state { | ||
57 | enum cx25840_cardtype cardtype; | ||
58 | enum cx25840_input input; | ||
59 | int audio_input; | ||
60 | enum v4l2_audio_clock_freq audclk_freq; | ||
61 | }; | ||
62 | |||
63 | /* ----------------------------------------------------------------------- */ | ||
64 | /* cx25850-core.c */ | ||
65 | int cx25840_write(struct i2c_client *client, u16 addr, u8 value); | ||
66 | int cx25840_write4(struct i2c_client *client, u16 addr, u32 value); | ||
67 | u8 cx25840_read(struct i2c_client *client, u16 addr); | ||
68 | u32 cx25840_read4(struct i2c_client *client, u16 addr); | ||
69 | int cx25840_and_or(struct i2c_client *client, u16 addr, u8 mask, u8 value); | ||
70 | v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client); | ||
71 | |||
72 | /* ----------------------------------------------------------------------- */ | ||
73 | /* cx25850-firmware.c */ | ||
74 | int cx25840_loadfw(struct i2c_client *client); | ||
75 | |||
76 | /* ----------------------------------------------------------------------- */ | ||
77 | /* cx25850-audio.c */ | ||
78 | int cx25840_audio(struct i2c_client *client, unsigned int cmd, void *arg); | ||
79 | |||
80 | /* ----------------------------------------------------------------------- */ | ||
81 | /* cx25850-vbi.c */ | ||
82 | void cx25840_vbi_setup(struct i2c_client *client); | ||
83 | int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg); | ||
84 | |||
85 | #endif | ||
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index 9cce91ec334b..99ea955f5987 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c | |||
@@ -439,9 +439,6 @@ static int dvb_register(struct cx8802_dev *dev) | |||
439 | /* Put the analog decoder in standby to keep it quiet */ | 439 | /* Put the analog decoder in standby to keep it quiet */ |
440 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); | 440 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); |
441 | 441 | ||
442 | /* Put the analog decoder in standby to keep it quiet */ | ||
443 | cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL); | ||
444 | |||
445 | /* register everything */ | 442 | /* register everything */ |
446 | return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); | 443 | return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); |
447 | } | 444 | } |
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 32c49df58adc..9b94f77d6fd7 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c | |||
@@ -120,9 +120,6 @@ static int get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | |||
120 | if (buf[1]==0xff) | 120 | if (buf[1]==0xff) |
121 | return 0; | 121 | return 0; |
122 | 122 | ||
123 | /* avoid fast reapeating */ | ||
124 | if (buf[1]==ir->old) | ||
125 | return 0; | ||
126 | ir->old=buf[1]; | 123 | ir->old=buf[1]; |
127 | 124 | ||
128 | /* Rearranges bits to the right order */ | 125 | /* Rearranges bits to the right order */ |
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c index ed81934ef3cd..5abfc0fbf6de 100644 --- a/drivers/media/video/ir-kbd-gpio.c +++ b/drivers/media/video/ir-kbd-gpio.c | |||
@@ -221,24 +221,99 @@ static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = { | |||
221 | [ 24 ] = KEY_MUTE // mute/unmute | 221 | [ 24 ] = KEY_MUTE // mute/unmute |
222 | }; | 222 | }; |
223 | 223 | ||
224 | static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = { | ||
225 | [0x00] = KEY_KP0, | ||
226 | [0x01] = KEY_KP1, | ||
227 | [0x02] = KEY_KP2, | ||
228 | [0x03] = KEY_KP3, | ||
229 | [0x04] = KEY_KP4, | ||
230 | [0x05] = KEY_KP5, | ||
231 | [0x06] = KEY_KP6, | ||
232 | [0x07] = KEY_KP7, | ||
233 | [0x08] = KEY_KP8, | ||
234 | [0x09] = KEY_KP9, | ||
235 | [0x0a] = KEY_TV, | ||
236 | [0x0b] = KEY_AUX, | ||
237 | [0x0c] = KEY_DVD, | ||
238 | [0x0d] = KEY_POWER, | ||
239 | [0x0e] = KEY_MHP, /* labelled 'Picture' */ | ||
240 | [0x0f] = KEY_AUDIO, | ||
241 | [0x10] = KEY_INFO, | ||
242 | [0x11] = KEY_F13, /* 16:9 */ | ||
243 | [0x12] = KEY_F14, /* 14:9 */ | ||
244 | [0x13] = KEY_EPG, | ||
245 | [0x14] = KEY_EXIT, | ||
246 | [0x15] = KEY_MENU, | ||
247 | [0x16] = KEY_UP, | ||
248 | [0x17] = KEY_DOWN, | ||
249 | [0x18] = KEY_LEFT, | ||
250 | [0x19] = KEY_RIGHT, | ||
251 | [0x1a] = KEY_ENTER, | ||
252 | [0x1b] = KEY_CHANNELUP, | ||
253 | [0x1c] = KEY_CHANNELDOWN, | ||
254 | [0x1d] = KEY_VOLUMEUP, | ||
255 | [0x1e] = KEY_VOLUMEDOWN, | ||
256 | [0x1f] = KEY_RED, | ||
257 | [0x20] = KEY_GREEN, | ||
258 | [0x21] = KEY_YELLOW, | ||
259 | [0x22] = KEY_BLUE, | ||
260 | [0x23] = KEY_SUBTITLE, | ||
261 | [0x24] = KEY_F15, /* AD */ | ||
262 | [0x25] = KEY_TEXT, | ||
263 | [0x26] = KEY_MUTE, | ||
264 | [0x27] = KEY_REWIND, | ||
265 | [0x28] = KEY_STOP, | ||
266 | [0x29] = KEY_PLAY, | ||
267 | [0x2a] = KEY_FASTFORWARD, | ||
268 | [0x2b] = KEY_F16, /* chapter */ | ||
269 | [0x2c] = KEY_PAUSE, | ||
270 | [0x2d] = KEY_PLAY, | ||
271 | [0x2e] = KEY_RECORD, | ||
272 | [0x2f] = KEY_F17, /* picture in picture */ | ||
273 | [0x30] = KEY_KPPLUS, /* zoom in */ | ||
274 | [0x31] = KEY_KPMINUS, /* zoom out */ | ||
275 | [0x32] = KEY_F18, /* capture */ | ||
276 | [0x33] = KEY_F19, /* web */ | ||
277 | [0x34] = KEY_EMAIL, | ||
278 | [0x35] = KEY_PHONE, | ||
279 | [0x36] = KEY_PC | ||
280 | }; | ||
281 | |||
224 | struct IR { | 282 | struct IR { |
225 | struct bttv_sub_device *sub; | 283 | struct bttv_sub_device *sub; |
226 | struct input_dev *input; | 284 | struct input_dev *input; |
227 | struct ir_input_state ir; | 285 | struct ir_input_state ir; |
228 | char name[32]; | 286 | char name[32]; |
229 | char phys[32]; | 287 | char phys[32]; |
288 | |||
289 | /* Usual gpio signalling */ | ||
290 | |||
230 | u32 mask_keycode; | 291 | u32 mask_keycode; |
231 | u32 mask_keydown; | 292 | u32 mask_keydown; |
232 | u32 mask_keyup; | 293 | u32 mask_keyup; |
233 | 294 | u32 polling; | |
234 | int polling; | ||
235 | u32 last_gpio; | 295 | u32 last_gpio; |
236 | struct work_struct work; | 296 | struct work_struct work; |
237 | struct timer_list timer; | 297 | struct timer_list timer; |
298 | |||
299 | /* RC5 gpio */ | ||
300 | |||
301 | u32 rc5_gpio; | ||
302 | struct timer_list timer_end; /* timer_end for code completion */ | ||
303 | struct timer_list timer_keyup; /* timer_end for key release */ | ||
304 | u32 last_rc5; /* last good rc5 code */ | ||
305 | u32 last_bit; /* last raw bit seen */ | ||
306 | u32 code; /* raw code under construction */ | ||
307 | struct timeval base_time; /* time of last seen code */ | ||
308 | int active; /* building raw code */ | ||
238 | }; | 309 | }; |
239 | 310 | ||
240 | static int debug; | 311 | static int debug; |
241 | module_param(debug, int, 0644); /* debug level (0,1,2) */ | 312 | module_param(debug, int, 0644); /* debug level (0,1,2) */ |
313 | static int repeat_delay = 500; | ||
314 | module_param(repeat_delay, int, 0644); | ||
315 | static int repeat_period = 33; | ||
316 | module_param(repeat_period, int, 0644); | ||
242 | 317 | ||
243 | #define DEVNAME "ir-kbd-gpio" | 318 | #define DEVNAME "ir-kbd-gpio" |
244 | #define dprintk(fmt, arg...) if (debug) \ | 319 | #define dprintk(fmt, arg...) if (debug) \ |
@@ -254,7 +329,7 @@ static struct bttv_sub_driver driver = { | |||
254 | .probe = ir_probe, | 329 | .probe = ir_probe, |
255 | .remove = ir_remove, | 330 | .remove = ir_remove, |
256 | }, | 331 | }, |
257 | .gpio_irq = ir_irq, | 332 | .gpio_irq = ir_irq, |
258 | }; | 333 | }; |
259 | 334 | ||
260 | /* ---------------------------------------------------------------------- */ | 335 | /* ---------------------------------------------------------------------- */ |
@@ -327,6 +402,173 @@ static void ir_work(void *data) | |||
327 | mod_timer(&ir->timer, timeout); | 402 | mod_timer(&ir->timer, timeout); |
328 | } | 403 | } |
329 | 404 | ||
405 | /* ---------------------------------------------------------------*/ | ||
406 | |||
407 | static int rc5_remote_gap = 885; | ||
408 | module_param(rc5_remote_gap, int, 0644); | ||
409 | static int rc5_key_timeout = 200; | ||
410 | module_param(rc5_key_timeout, int, 0644); | ||
411 | |||
412 | #define RC5_START(x) (((x)>>12)&3) | ||
413 | #define RC5_TOGGLE(x) (((x)>>11)&1) | ||
414 | #define RC5_ADDR(x) (((x)>>6)&31) | ||
415 | #define RC5_INSTR(x) ((x)&63) | ||
416 | |||
417 | /* decode raw bit pattern to RC5 code */ | ||
418 | static u32 rc5_decode(unsigned int code) | ||
419 | { | ||
420 | unsigned int org_code = code; | ||
421 | unsigned int pair; | ||
422 | unsigned int rc5 = 0; | ||
423 | int i; | ||
424 | |||
425 | code = (code << 1) | 1; | ||
426 | for (i = 0; i < 14; ++i) { | ||
427 | pair = code & 0x3; | ||
428 | code >>= 2; | ||
429 | |||
430 | rc5 <<= 1; | ||
431 | switch (pair) { | ||
432 | case 0: | ||
433 | case 2: | ||
434 | break; | ||
435 | case 1: | ||
436 | rc5 |= 1; | ||
437 | break; | ||
438 | case 3: | ||
439 | dprintk("bad code: %x\n", org_code); | ||
440 | return 0; | ||
441 | } | ||
442 | } | ||
443 | dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " | ||
444 | "instr=%x\n", rc5, org_code, RC5_START(rc5), | ||
445 | RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); | ||
446 | return rc5; | ||
447 | } | ||
448 | |||
449 | static int ir_rc5_irq(struct bttv_sub_device *sub) | ||
450 | { | ||
451 | struct IR *ir = dev_get_drvdata(&sub->dev); | ||
452 | struct timeval tv; | ||
453 | u32 gpio; | ||
454 | u32 gap; | ||
455 | unsigned long current_jiffies, timeout; | ||
456 | |||
457 | /* read gpio port */ | ||
458 | gpio = bttv_gpio_read(ir->sub->core); | ||
459 | |||
460 | /* remote IRQ? */ | ||
461 | if (!(gpio & 0x20)) | ||
462 | return 0; | ||
463 | |||
464 | /* get time of bit */ | ||
465 | current_jiffies = jiffies; | ||
466 | do_gettimeofday(&tv); | ||
467 | |||
468 | /* avoid overflow with gap >1s */ | ||
469 | if (tv.tv_sec - ir->base_time.tv_sec > 1) { | ||
470 | gap = 200000; | ||
471 | } else { | ||
472 | gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + | ||
473 | tv.tv_usec - ir->base_time.tv_usec; | ||
474 | } | ||
475 | |||
476 | /* active code => add bit */ | ||
477 | if (ir->active) { | ||
478 | /* only if in the code (otherwise spurious IRQ or timer | ||
479 | late) */ | ||
480 | if (ir->last_bit < 28) { | ||
481 | ir->last_bit = (gap - rc5_remote_gap / 2) / | ||
482 | rc5_remote_gap; | ||
483 | ir->code |= 1 << ir->last_bit; | ||
484 | } | ||
485 | /* starting new code */ | ||
486 | } else { | ||
487 | ir->active = 1; | ||
488 | ir->code = 0; | ||
489 | ir->base_time = tv; | ||
490 | ir->last_bit = 0; | ||
491 | |||
492 | timeout = current_jiffies + (500 + 30 * HZ) / 1000; | ||
493 | mod_timer(&ir->timer_end, timeout); | ||
494 | } | ||
495 | |||
496 | /* toggle GPIO pin 4 to reset the irq */ | ||
497 | bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4)); | ||
498 | bttv_gpio_write(ir->sub->core, gpio | (1 << 4)); | ||
499 | return 1; | ||
500 | } | ||
501 | |||
502 | static void ir_rc5_timer_end(unsigned long data) | ||
503 | { | ||
504 | struct IR *ir = (struct IR *)data; | ||
505 | struct timeval tv; | ||
506 | unsigned long current_jiffies, timeout; | ||
507 | u32 gap; | ||
508 | |||
509 | /* get time */ | ||
510 | current_jiffies = jiffies; | ||
511 | do_gettimeofday(&tv); | ||
512 | |||
513 | /* avoid overflow with gap >1s */ | ||
514 | if (tv.tv_sec - ir->base_time.tv_sec > 1) { | ||
515 | gap = 200000; | ||
516 | } else { | ||
517 | gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + | ||
518 | tv.tv_usec - ir->base_time.tv_usec; | ||
519 | } | ||
520 | |||
521 | /* Allow some timmer jitter (RC5 is ~24ms anyway so this is ok) */ | ||
522 | if (gap < 28000) { | ||
523 | dprintk("spurious timer_end\n"); | ||
524 | return; | ||
525 | } | ||
526 | |||
527 | ir->active = 0; | ||
528 | if (ir->last_bit < 20) { | ||
529 | /* ignore spurious codes (caused by light/other remotes) */ | ||
530 | dprintk("short code: %x\n", ir->code); | ||
531 | } else { | ||
532 | u32 rc5 = rc5_decode(ir->code); | ||
533 | |||
534 | /* two start bits? */ | ||
535 | if (RC5_START(rc5) != 3) { | ||
536 | dprintk("rc5 start bits invalid: %u\n", RC5_START(rc5)); | ||
537 | |||
538 | /* right address? */ | ||
539 | } else if (RC5_ADDR(rc5) == 0x0) { | ||
540 | u32 toggle = RC5_TOGGLE(rc5); | ||
541 | u32 instr = RC5_INSTR(rc5); | ||
542 | |||
543 | /* Good code, decide if repeat/repress */ | ||
544 | if (toggle != RC5_TOGGLE(ir->last_rc5) || | ||
545 | instr != RC5_INSTR(ir->last_rc5)) { | ||
546 | dprintk("instruction %x, toggle %x\n", instr, | ||
547 | toggle); | ||
548 | ir_input_nokey(ir->input, &ir->ir); | ||
549 | ir_input_keydown(ir->input, &ir->ir, instr, | ||
550 | instr); | ||
551 | } | ||
552 | |||
553 | /* Set/reset key-up timer */ | ||
554 | timeout = current_jiffies + (500 + rc5_key_timeout | ||
555 | * HZ) / 1000; | ||
556 | mod_timer(&ir->timer_keyup, timeout); | ||
557 | |||
558 | /* Save code for repeat test */ | ||
559 | ir->last_rc5 = rc5; | ||
560 | } | ||
561 | } | ||
562 | } | ||
563 | |||
564 | static void ir_rc5_timer_keyup(unsigned long data) | ||
565 | { | ||
566 | struct IR *ir = (struct IR *)data; | ||
567 | |||
568 | dprintk("key released\n"); | ||
569 | ir_input_nokey(ir->input, &ir->ir); | ||
570 | } | ||
571 | |||
330 | /* ---------------------------------------------------------------------- */ | 572 | /* ---------------------------------------------------------------------- */ |
331 | 573 | ||
332 | static int ir_probe(struct device *dev) | 574 | static int ir_probe(struct device *dev) |
@@ -400,6 +642,12 @@ static int ir_probe(struct device *dev) | |||
400 | ir->mask_keyup = 0x006000; | 642 | ir->mask_keyup = 0x006000; |
401 | ir->polling = 50; // ms | 643 | ir->polling = 50; // ms |
402 | break; | 644 | break; |
645 | case BTTV_BOARD_NEBULA_DIGITV: | ||
646 | ir_codes = ir_codes_nebula; | ||
647 | driver.any_irq = ir_rc5_irq; | ||
648 | driver.gpio_irq = NULL; | ||
649 | ir->rc5_gpio = 1; | ||
650 | break; | ||
403 | } | 651 | } |
404 | if (NULL == ir_codes) { | 652 | if (NULL == ir_codes) { |
405 | kfree(ir); | 653 | kfree(ir); |
@@ -407,9 +655,17 @@ static int ir_probe(struct device *dev) | |||
407 | return -ENODEV; | 655 | return -ENODEV; |
408 | } | 656 | } |
409 | 657 | ||
410 | /* init hardware-specific stuff */ | 658 | if (ir->rc5_gpio) { |
411 | bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0); | 659 | u32 gpio; |
412 | ir->sub = sub; | 660 | /* enable remote irq */ |
661 | bttv_gpio_inout(sub->core, (1 << 4), 1 << 4); | ||
662 | gpio = bttv_gpio_read(sub->core); | ||
663 | bttv_gpio_write(sub->core, gpio & ~(1 << 4)); | ||
664 | bttv_gpio_write(sub->core, gpio | (1 << 4)); | ||
665 | } else { | ||
666 | /* init hardware-specific stuff */ | ||
667 | bttv_gpio_inout(sub->core, ir->mask_keycode | ir->mask_keydown, 0); | ||
668 | } | ||
413 | 669 | ||
414 | /* init input device */ | 670 | /* init input device */ |
415 | snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", | 671 | snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)", |
@@ -417,6 +673,7 @@ static int ir_probe(struct device *dev) | |||
417 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", | 673 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", |
418 | pci_name(sub->core->pci)); | 674 | pci_name(sub->core->pci)); |
419 | 675 | ||
676 | ir->sub = sub; | ||
420 | ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); | 677 | ir_input_init(input_dev, &ir->ir, ir_type, ir_codes); |
421 | input_dev->name = ir->name; | 678 | input_dev->name = ir->name; |
422 | input_dev->phys = ir->phys; | 679 | input_dev->phys = ir->phys; |
@@ -437,11 +694,25 @@ static int ir_probe(struct device *dev) | |||
437 | ir->timer.function = ir_timer; | 694 | ir->timer.function = ir_timer; |
438 | ir->timer.data = (unsigned long)ir; | 695 | ir->timer.data = (unsigned long)ir; |
439 | schedule_work(&ir->work); | 696 | schedule_work(&ir->work); |
697 | } else if (ir->rc5_gpio) { | ||
698 | /* set timer_end for code completion */ | ||
699 | init_timer(&ir->timer_end); | ||
700 | ir->timer_end.function = ir_rc5_timer_end; | ||
701 | ir->timer_end.data = (unsigned long)ir; | ||
702 | |||
703 | init_timer(&ir->timer_keyup); | ||
704 | ir->timer_keyup.function = ir_rc5_timer_keyup; | ||
705 | ir->timer_keyup.data = (unsigned long)ir; | ||
440 | } | 706 | } |
441 | 707 | ||
442 | /* all done */ | 708 | /* all done */ |
443 | dev_set_drvdata(dev, ir); | 709 | dev_set_drvdata(dev, ir); |
444 | input_register_device(ir->input); | 710 | input_register_device(ir->input); |
711 | printk(DEVNAME ": %s detected at %s\n",ir->name,ir->phys); | ||
712 | |||
713 | /* the remote isn't as bouncy as a keyboard */ | ||
714 | ir->input->rep[REP_DELAY] = repeat_delay; | ||
715 | ir->input->rep[REP_PERIOD] = repeat_period; | ||
445 | 716 | ||
446 | return 0; | 717 | return 0; |
447 | } | 718 | } |
@@ -454,6 +725,15 @@ static int ir_remove(struct device *dev) | |||
454 | del_timer(&ir->timer); | 725 | del_timer(&ir->timer); |
455 | flush_scheduled_work(); | 726 | flush_scheduled_work(); |
456 | } | 727 | } |
728 | if (ir->rc5_gpio) { | ||
729 | u32 gpio; | ||
730 | |||
731 | del_timer(&ir->timer_end); | ||
732 | flush_scheduled_work(); | ||
733 | |||
734 | gpio = bttv_gpio_read(ir->sub->core); | ||
735 | bttv_gpio_write(ir->sub->core, gpio & ~(1 << 4)); | ||
736 | } | ||
457 | 737 | ||
458 | input_unregister_device(ir->input); | 738 | input_unregister_device(ir->input); |
459 | kfree(ir); | 739 | kfree(ir); |
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 0085567a1421..801c736e9328 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c | |||
@@ -183,6 +183,58 @@ static int get_key_knc1(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | |||
183 | return 1; | 183 | return 1; |
184 | } | 184 | } |
185 | 185 | ||
186 | /* The new pinnacle PCTV remote (with the colored buttons) | ||
187 | * | ||
188 | * Ricardo Cerqueira <v4l@cerqueira.org> | ||
189 | */ | ||
190 | |||
191 | int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
192 | { | ||
193 | unsigned char b[4]; | ||
194 | unsigned int start = 0,parity = 0,code = 0; | ||
195 | |||
196 | /* poll IR chip */ | ||
197 | if (4 != i2c_master_recv(&ir->c,b,4)) { | ||
198 | dprintk(2,"read error\n"); | ||
199 | return -EIO; | ||
200 | } | ||
201 | |||
202 | for (start = 0; start<4; start++) { | ||
203 | if (b[start] == 0x80) { | ||
204 | code=b[(start+3)%4]; | ||
205 | parity=b[(start+2)%4]; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | /* Empty Request */ | ||
210 | if (parity==0) | ||
211 | return 0; | ||
212 | |||
213 | /* Repeating... */ | ||
214 | if (ir->old == parity) | ||
215 | return 0; | ||
216 | |||
217 | |||
218 | ir->old = parity; | ||
219 | |||
220 | /* Reduce code value to fit inside IR_KEYTAB_SIZE | ||
221 | * | ||
222 | * this is the only value that results in 42 unique | ||
223 | * codes < 128 | ||
224 | */ | ||
225 | |||
226 | code %= 0x88; | ||
227 | |||
228 | *ir_raw = code; | ||
229 | *ir_key = code; | ||
230 | |||
231 | dprintk(1,"Pinnacle PCTV key %02x\n", code); | ||
232 | |||
233 | return 1; | ||
234 | } | ||
235 | |||
236 | EXPORT_SYMBOL_GPL(get_key_pinnacle); | ||
237 | |||
186 | /* ----------------------------------------------------------------------- */ | 238 | /* ----------------------------------------------------------------------- */ |
187 | 239 | ||
188 | static void ir_key_poll(struct IR_i2c *ir) | 240 | static void ir_key_poll(struct IR_i2c *ir) |
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c new file mode 100644 index 000000000000..0235cef07b31 --- /dev/null +++ b/drivers/media/video/saa7115.c | |||
@@ -0,0 +1,1376 @@ | |||
1 | /* saa7115 - Philips SAA7114/SAA7115 video decoder driver | ||
2 | * | ||
3 | * Based on saa7114 driver by Maxim Yevtyushkin, which is based on | ||
4 | * the saa7111 driver by Dave Perks. | ||
5 | * | ||
6 | * Copyright (C) 1998 Dave Perks <dperks@ibm.net> | ||
7 | * Copyright (C) 2002 Maxim Yevtyushkin <max@linuxmedialabs.com> | ||
8 | * | ||
9 | * Slight changes for video timing and attachment output by | ||
10 | * Wolfgang Scherr <scherr@net4you.net> | ||
11 | * | ||
12 | * Moved over to the linux >= 2.4.x i2c protocol (1/1/2003) | ||
13 | * by Ronald Bultje <rbultje@ronald.bitfreak.net> | ||
14 | * | ||
15 | * Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com> | ||
16 | * (2/17/2003) | ||
17 | * | ||
18 | * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or | ||
21 | * modify it under the terms of the GNU General Public License | ||
22 | * as published by the Free Software Foundation; either version 2 | ||
23 | * of the License, or (at your option) any later version. | ||
24 | * | ||
25 | * This program is distributed in the hope that it will be useful, | ||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | * GNU General Public License for more details. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License | ||
31 | * along with this program; if not, write to the Free Software | ||
32 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
33 | */ | ||
34 | |||
35 | |||
36 | #include <linux/kernel.h> | ||
37 | #include <linux/module.h> | ||
38 | #include <linux/slab.h> | ||
39 | #include <linux/i2c.h> | ||
40 | #include <linux/videodev2.h> | ||
41 | #include <media/v4l2-common.h> | ||
42 | |||
43 | MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); | ||
44 | MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); | ||
45 | MODULE_LICENSE("GPL"); | ||
46 | |||
47 | static int debug = 0; | ||
48 | module_param(debug, int, 0644); | ||
49 | |||
50 | MODULE_PARM_DESC(debug, "Debug level (0-1)"); | ||
51 | |||
52 | #define saa7115_dbg(fmt,arg...) \ | ||
53 | do { \ | ||
54 | if (debug) \ | ||
55 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
56 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
57 | } while (0) | ||
58 | |||
59 | #define saa7115_err(fmt, arg...) do { \ | ||
60 | printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \ | ||
61 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
62 | #define saa7115_info(fmt, arg...) do { \ | ||
63 | printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \ | ||
64 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
65 | |||
66 | static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END }; | ||
67 | |||
68 | |||
69 | I2C_CLIENT_INSMOD; | ||
70 | |||
71 | struct saa7115_state { | ||
72 | v4l2_std_id std; | ||
73 | int input; | ||
74 | int enable; | ||
75 | int bright; | ||
76 | int contrast; | ||
77 | int hue; | ||
78 | int sat; | ||
79 | enum v4l2_chip_ident ident; | ||
80 | enum v4l2_audio_clock_freq audclk_freq; | ||
81 | }; | ||
82 | |||
83 | /* ----------------------------------------------------------------------- */ | ||
84 | |||
85 | static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value) | ||
86 | { | ||
87 | return i2c_smbus_write_byte_data(client, reg, value); | ||
88 | } | ||
89 | |||
90 | static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs) | ||
91 | { | ||
92 | unsigned char reg, data; | ||
93 | |||
94 | while (*regs != 0x00) { | ||
95 | reg = *(regs++); | ||
96 | data = *(regs++); | ||
97 | if (saa7115_write(client, reg, data) < 0) | ||
98 | return -1; | ||
99 | } | ||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static inline int saa7115_read(struct i2c_client *client, u8 reg) | ||
104 | { | ||
105 | return i2c_smbus_read_byte_data(client, reg); | ||
106 | } | ||
107 | |||
108 | /* ----------------------------------------------------------------------- */ | ||
109 | |||
110 | /* If a value differs from the Hauppauge driver values, then the comment starts with | ||
111 | 'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the | ||
112 | Hauppauge driver sets. */ | ||
113 | |||
114 | static const unsigned char saa7115_init_auto_input[] = { | ||
115 | 0x01, 0x48, /* white peak control disabled */ | ||
116 | 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */ | ||
117 | 0x04, 0x90, /* analog gain set to 0 */ | ||
118 | 0x05, 0x90, /* analog gain set to 0 */ | ||
119 | 0x06, 0xeb, /* horiz sync begin = -21 */ | ||
120 | 0x07, 0xe0, /* horiz sync stop = -17 */ | ||
121 | 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */ | ||
122 | 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */ | ||
123 | 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */ | ||
124 | 0x0d, 0x00, /* chrominance hue control */ | ||
125 | 0x0f, 0x00, /* chrominance gain control: use automicatic mode */ | ||
126 | 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */ | ||
127 | 0x11, 0x00, /* delay control */ | ||
128 | 0x12, 0x9d, /* RTS0 output control: VGATE */ | ||
129 | 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */ | ||
130 | 0x14, 0x00, /* analog/ADC/auto compatibility control */ | ||
131 | 0x18, 0x40, /* raw data gain 0x00 = nominal */ | ||
132 | 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */ | ||
133 | 0x1a, 0x77, /* color killer level control 0x77 = recommended */ | ||
134 | 0x1b, 0x42, /* misc chroma control 0x42 = recommended */ | ||
135 | 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */ | ||
136 | 0x1d, 0x01, /* combfilter control 0x01 = recommended */ | ||
137 | 0x88, 0xd0, /* reset device */ | ||
138 | 0x88, 0xf0, /* set device programmed, all in operational mode */ | ||
139 | 0x00, 0x00 | ||
140 | }; | ||
141 | |||
142 | static const unsigned char saa7115_cfg_reset_scaler[] = { | ||
143 | 0x87, 0x00, /* disable I-port output */ | ||
144 | 0x88, 0xd0, /* reset scaler */ | ||
145 | 0x88, 0xf0, /* activate scaler */ | ||
146 | 0x87, 0x01, /* enable I-port output */ | ||
147 | 0x00, 0x00 | ||
148 | }; | ||
149 | |||
150 | /* ============== SAA7715 VIDEO templates ============= */ | ||
151 | |||
152 | static const unsigned char saa7115_cfg_60hz_fullres_x[] = { | ||
153 | 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */ | ||
154 | 0xcd, 0x02, /* hsize hi (output) */ | ||
155 | |||
156 | /* Why not in 60hz-Land, too? */ | ||
157 | 0xd0, 0x01, /* downscale = 1 */ | ||
158 | 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */ | ||
159 | 0xd9, 0x04, | ||
160 | 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */ | ||
161 | 0xdd, 0x02, /* H-scaling incr chroma */ | ||
162 | |||
163 | 0x00, 0x00 | ||
164 | }; | ||
165 | static const unsigned char saa7115_cfg_60hz_fullres_y[] = { | ||
166 | 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */ | ||
167 | 0xcf, 0x00, /* vsize hi (output) */ | ||
168 | |||
169 | /* Why not in 60hz-Land, too? */ | ||
170 | 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */ | ||
171 | 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */ | ||
172 | |||
173 | 0xe0, 0x00, /* V-scaling incr luma low */ | ||
174 | 0xe1, 0x04, /* " hi */ | ||
175 | 0xe2, 0x00, /* V-scaling incr chroma low */ | ||
176 | 0xe3, 0x04, /* " hi */ | ||
177 | |||
178 | 0x00, 0x00 | ||
179 | }; | ||
180 | |||
181 | static const unsigned char saa7115_cfg_60hz_video[] = { | ||
182 | 0x80, 0x00, /* reset tasks */ | ||
183 | 0x88, 0xd0, /* reset scaler */ | ||
184 | |||
185 | 0x15, 0x03, /* VGATE pulse start */ | ||
186 | 0x16, 0x11, /* VGATE pulse stop */ | ||
187 | 0x17, 0x9c, /* VGATE MSB and other values */ | ||
188 | |||
189 | 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */ | ||
190 | 0x0e, 0x07, /* lots of different stuff... video autodetection is on */ | ||
191 | |||
192 | 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */ | ||
193 | |||
194 | /* Task A */ | ||
195 | 0x90, 0x80, /* Task Handling Control */ | ||
196 | 0x91, 0x48, /* X-port formats/config */ | ||
197 | 0x92, 0x40, /* Input Ref. signal Def. */ | ||
198 | 0x93, 0x84, /* I-port config */ | ||
199 | 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */ | ||
200 | 0x95, 0x00, /* hoffset hi (input) */ | ||
201 | 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */ | ||
202 | 0x97, 0x02, /* hsize hi (input) */ | ||
203 | 0x98, 0x05, /* voffset low (input) */ | ||
204 | 0x99, 0x00, /* voffset hi (input) */ | ||
205 | 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */ | ||
206 | 0x9b, 0x00, /* vsize hi (input) */ | ||
207 | 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */ | ||
208 | 0x9d, 0x05, /* hsize hi (output) */ | ||
209 | 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */ | ||
210 | 0x9f, 0x00, /* vsize hi (output) */ | ||
211 | |||
212 | /* Task B */ | ||
213 | 0xc0, 0x00, /* Task Handling Control */ | ||
214 | 0xc1, 0x08, /* X-port formats/config */ | ||
215 | 0xc2, 0x00, /* Input Ref. signal Def. */ | ||
216 | 0xc3, 0x80, /* I-port config */ | ||
217 | 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */ | ||
218 | 0xc5, 0x00, /* hoffset hi (input) */ | ||
219 | 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */ | ||
220 | 0xc7, 0x02, /* hsize hi (input) */ | ||
221 | 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */ | ||
222 | 0xc9, 0x00, /* voffset hi (input) */ | ||
223 | 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */ | ||
224 | 0xcb, 0x00, /* vsize hi (input) */ | ||
225 | 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */ | ||
226 | 0xcd, 0x02, /* hsize hi (output) */ | ||
227 | |||
228 | 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */ | ||
229 | 0xf1, 0x05, /* low bit with 0xF0 */ | ||
230 | 0xf5, 0xad, /* Set pulse generator register */ | ||
231 | 0xf6, 0x01, | ||
232 | |||
233 | 0x87, 0x00, /* Disable I-port output */ | ||
234 | 0x88, 0xd0, /* reset scaler */ | ||
235 | 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */ | ||
236 | 0x88, 0xf0, /* activate scaler */ | ||
237 | 0x87, 0x01, /* Enable I-port output */ | ||
238 | 0x00, 0x00 | ||
239 | }; | ||
240 | |||
241 | static const unsigned char saa7115_cfg_50hz_fullres_x[] = { | ||
242 | 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */ | ||
243 | 0xcd, 0x02, /* hsize hi (output) */ | ||
244 | |||
245 | 0xd0, 0x01, /* down scale = 1 */ | ||
246 | 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */ | ||
247 | 0xd9, 0x04, | ||
248 | 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */ | ||
249 | 0xdd, 0x02, /* H-scaling incr chroma */ | ||
250 | |||
251 | 0x00, 0x00 | ||
252 | }; | ||
253 | static const unsigned char saa7115_cfg_50hz_fullres_y[] = { | ||
254 | 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */ | ||
255 | 0xcf, 0x01, /* vsize hi (output) */ | ||
256 | |||
257 | 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */ | ||
258 | 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */ | ||
259 | |||
260 | 0xe0, 0x00, /* V-scaling incr luma low */ | ||
261 | 0xe1, 0x04, /* " hi */ | ||
262 | 0xe2, 0x00, /* V-scaling incr chroma low */ | ||
263 | 0xe3, 0x04, /* " hi */ | ||
264 | |||
265 | 0x00, 0x00 | ||
266 | }; | ||
267 | |||
268 | static const unsigned char saa7115_cfg_50hz_video[] = { | ||
269 | 0x80, 0x00, /* reset tasks */ | ||
270 | 0x88, 0xd0, /* reset scaler */ | ||
271 | |||
272 | 0x15, 0x37, /* VGATE start */ | ||
273 | 0x16, 0x16, /* VGATE stop */ | ||
274 | 0x17, 0x99, /* VGATE MSB and other values */ | ||
275 | |||
276 | 0x08, 0x28, /* 0x28 = PAL */ | ||
277 | 0x0e, 0x07, /* chrominance control 1 */ | ||
278 | |||
279 | 0x5a, 0x03, /* Vertical offset, standard 50hz value */ | ||
280 | |||
281 | /* Task A */ | ||
282 | 0x90, 0x81, /* Task Handling Control */ | ||
283 | 0x91, 0x48, /* X-port formats/config */ | ||
284 | 0x92, 0x40, /* Input Ref. signal Def. */ | ||
285 | 0x93, 0x84, /* I-port config */ | ||
286 | /* This is weird: the datasheet says that you should use 2 as the minimum value, */ | ||
287 | /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */ | ||
288 | 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */ | ||
289 | 0x95, 0x00, /* hoffset hi (input) */ | ||
290 | 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */ | ||
291 | 0x97, 0x02, /* hsize hi (input) */ | ||
292 | 0x98, 0x03, /* voffset low (input) */ | ||
293 | 0x99, 0x00, /* voffset hi (input) */ | ||
294 | 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */ | ||
295 | 0x9b, 0x00, /* vsize hi (input) */ | ||
296 | 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */ | ||
297 | 0x9d, 0x05, /* hsize hi (output) */ | ||
298 | 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */ | ||
299 | 0x9f, 0x00, /* vsize hi (output) */ | ||
300 | |||
301 | /* Task B */ | ||
302 | 0xc0, 0x00, /* Task Handling Control */ | ||
303 | 0xc1, 0x08, /* X-port formats/config */ | ||
304 | 0xc2, 0x00, /* Input Ref. signal Def. */ | ||
305 | 0xc3, 0x80, /* I-port config */ | ||
306 | 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */ | ||
307 | 0xc5, 0x00, /* hoffset hi (input) */ | ||
308 | 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */ | ||
309 | 0xc7, 0x02, /* hsize hi (input) */ | ||
310 | 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */ | ||
311 | 0xc9, 0x00, /* voffset hi (input) */ | ||
312 | 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */ | ||
313 | 0xcb, 0x01, /* vsize hi (input) */ | ||
314 | 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */ | ||
315 | 0xcd, 0x02, /* hsize hi (output) */ | ||
316 | 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */ | ||
317 | 0xcf, 0x01, /* vsize hi (output) */ | ||
318 | |||
319 | 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */ | ||
320 | 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */ | ||
321 | 0xf5, 0xb0, /* Set pulse generator register */ | ||
322 | 0xf6, 0x01, | ||
323 | |||
324 | 0x87, 0x00, /* Disable I-port output */ | ||
325 | 0x88, 0xd0, /* reset scaler (was 0xD0) */ | ||
326 | 0x80, 0x20, /* Activate only task "B" */ | ||
327 | 0x88, 0xf0, /* activate scaler */ | ||
328 | 0x87, 0x01, /* Enable I-port output */ | ||
329 | 0x00, 0x00 | ||
330 | }; | ||
331 | |||
332 | /* ============== SAA7715 VIDEO templates (end) ======= */ | ||
333 | |||
334 | static const unsigned char saa7115_cfg_vbi_on[] = { | ||
335 | 0x80, 0x00, /* reset tasks */ | ||
336 | 0x88, 0xd0, /* reset scaler */ | ||
337 | 0x80, 0x30, /* Activate both tasks */ | ||
338 | 0x88, 0xf0, /* activate scaler */ | ||
339 | 0x87, 0x01, /* Enable I-port output */ | ||
340 | 0x00, 0x00 | ||
341 | }; | ||
342 | |||
343 | static const unsigned char saa7115_cfg_vbi_off[] = { | ||
344 | 0x80, 0x00, /* reset tasks */ | ||
345 | 0x88, 0xd0, /* reset scaler */ | ||
346 | 0x80, 0x20, /* Activate only task "B" */ | ||
347 | 0x88, 0xf0, /* activate scaler */ | ||
348 | 0x87, 0x01, /* Enable I-port output */ | ||
349 | 0x00, 0x00 | ||
350 | }; | ||
351 | |||
352 | static const unsigned char saa7115_init_misc[] = { | ||
353 | 0x38, 0x03, /* audio stuff */ | ||
354 | 0x39, 0x10, | ||
355 | 0x3a, 0x08, | ||
356 | |||
357 | 0x81, 0x01, /* reg 0x15,0x16 define blanking window */ | ||
358 | 0x82, 0x00, | ||
359 | 0x83, 0x01, /* I port settings */ | ||
360 | 0x84, 0x20, | ||
361 | 0x85, 0x21, | ||
362 | 0x86, 0xc5, | ||
363 | 0x87, 0x01, | ||
364 | |||
365 | /* Task A */ | ||
366 | 0xa0, 0x01, /* down scale = 1 */ | ||
367 | 0xa1, 0x00, /* prescale accumulation length = 1 */ | ||
368 | 0xa2, 0x00, /* dc gain and fir prefilter control */ | ||
369 | 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */ | ||
370 | 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */ | ||
371 | 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */ | ||
372 | 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */ | ||
373 | 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */ | ||
374 | 0xaa, 0x00, /* H-phase offset Luma = 0 */ | ||
375 | 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */ | ||
376 | 0xad, 0x01, /* H-scaling incr chroma */ | ||
377 | 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */ | ||
378 | |||
379 | 0xb0, 0x00, /* V-scaling incr luma low */ | ||
380 | 0xb1, 0x04, /* " hi */ | ||
381 | 0xb2, 0x00, /* V-scaling incr chroma low */ | ||
382 | 0xb3, 0x04, /* " hi */ | ||
383 | 0xb4, 0x01, /* V-scaling mode control */ | ||
384 | 0xb8, 0x00, /* V-phase offset chroma 00 */ | ||
385 | 0xb9, 0x00, /* V-phase offset chroma 01 */ | ||
386 | 0xba, 0x00, /* V-phase offset chroma 10 */ | ||
387 | 0xbb, 0x00, /* V-phase offset chroma 11 */ | ||
388 | 0xbc, 0x00, /* V-phase offset luma 00 */ | ||
389 | 0xbd, 0x00, /* V-phase offset luma 01 */ | ||
390 | 0xbe, 0x00, /* V-phase offset luma 10 */ | ||
391 | 0xbf, 0x00, /* V-phase offset luma 11 */ | ||
392 | |||
393 | /* Task B */ | ||
394 | 0xd0, 0x01, /* down scale = 1 */ | ||
395 | 0xd1, 0x00, /* prescale accumulation length = 1 */ | ||
396 | 0xd2, 0x00, /* dc gain and fir prefilter control */ | ||
397 | 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */ | ||
398 | 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */ | ||
399 | 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */ | ||
400 | 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */ | ||
401 | 0xd9, 0x04, | ||
402 | 0xda, 0x00, /* H-phase offset Luma = 0 */ | ||
403 | 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */ | ||
404 | 0xdd, 0x02, /* H-scaling incr chroma */ | ||
405 | 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */ | ||
406 | |||
407 | 0xe0, 0x00, /* V-scaling incr luma low */ | ||
408 | 0xe1, 0x04, /* " hi */ | ||
409 | 0xe2, 0x00, /* V-scaling incr chroma low */ | ||
410 | 0xe3, 0x04, /* " hi */ | ||
411 | 0xe4, 0x01, /* V-scaling mode control */ | ||
412 | 0xe8, 0x00, /* V-phase offset chroma 00 */ | ||
413 | 0xe9, 0x00, /* V-phase offset chroma 01 */ | ||
414 | 0xea, 0x00, /* V-phase offset chroma 10 */ | ||
415 | 0xeb, 0x00, /* V-phase offset chroma 11 */ | ||
416 | 0xec, 0x00, /* V-phase offset luma 00 */ | ||
417 | 0xed, 0x00, /* V-phase offset luma 01 */ | ||
418 | 0xee, 0x00, /* V-phase offset luma 10 */ | ||
419 | 0xef, 0x00, /* V-phase offset luma 11 */ | ||
420 | |||
421 | 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */ | ||
422 | 0xf3, 0x46, | ||
423 | 0xf4, 0x00, | ||
424 | 0xf7, 0x4b, /* not the recommended settings! */ | ||
425 | 0xf8, 0x00, | ||
426 | 0xf9, 0x4b, | ||
427 | 0xfa, 0x00, | ||
428 | 0xfb, 0x4b, | ||
429 | 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */ | ||
430 | |||
431 | /* Turn off VBI */ | ||
432 | 0x40, 0x20, /* No framing code errors allowed. */ | ||
433 | 0x41, 0xff, | ||
434 | 0x42, 0xff, | ||
435 | 0x43, 0xff, | ||
436 | 0x44, 0xff, | ||
437 | 0x45, 0xff, | ||
438 | 0x46, 0xff, | ||
439 | 0x47, 0xff, | ||
440 | 0x48, 0xff, | ||
441 | 0x49, 0xff, | ||
442 | 0x4a, 0xff, | ||
443 | 0x4b, 0xff, | ||
444 | 0x4c, 0xff, | ||
445 | 0x4d, 0xff, | ||
446 | 0x4e, 0xff, | ||
447 | 0x4f, 0xff, | ||
448 | 0x50, 0xff, | ||
449 | 0x51, 0xff, | ||
450 | 0x52, 0xff, | ||
451 | 0x53, 0xff, | ||
452 | 0x54, 0xff, | ||
453 | 0x55, 0xff, | ||
454 | 0x56, 0xff, | ||
455 | 0x57, 0xff, | ||
456 | 0x58, 0x40, | ||
457 | 0x59, 0x47, | ||
458 | 0x5b, 0x83, | ||
459 | 0x5d, 0xbd, | ||
460 | 0x5e, 0x35, | ||
461 | |||
462 | 0x02, 0x84, /* input tuner -> input 4, amplifier active */ | ||
463 | 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */ | ||
464 | |||
465 | 0x80, 0x20, /* enable task B */ | ||
466 | 0x88, 0xd0, | ||
467 | 0x88, 0xf0, | ||
468 | 0x00, 0x00 | ||
469 | }; | ||
470 | |||
471 | /* ============== SAA7715 AUDIO settings ============= */ | ||
472 | |||
473 | /* 48.0 kHz */ | ||
474 | static const unsigned char saa7115_cfg_48_audio[] = { | ||
475 | 0x34, 0xce, | ||
476 | 0x35, 0xfb, | ||
477 | 0x36, 0x30, | ||
478 | 0x00, 0x00 | ||
479 | }; | ||
480 | |||
481 | /* 44.1 kHz */ | ||
482 | static const unsigned char saa7115_cfg_441_audio[] = { | ||
483 | 0x34, 0xf2, | ||
484 | 0x35, 0x00, | ||
485 | 0x36, 0x2d, | ||
486 | 0x00, 0x00 | ||
487 | }; | ||
488 | |||
489 | /* 32.0 kHz */ | ||
490 | static const unsigned char saa7115_cfg_32_audio[] = { | ||
491 | 0x34, 0xdf, | ||
492 | 0x35, 0xa7, | ||
493 | 0x36, 0x20, | ||
494 | 0x00, 0x00 | ||
495 | }; | ||
496 | |||
497 | /* 48.0 kHz 60hz */ | ||
498 | static const unsigned char saa7115_cfg_60hz_48_audio[] = { | ||
499 | 0x30, 0xcd, | ||
500 | 0x31, 0x20, | ||
501 | 0x32, 0x03, | ||
502 | 0x00, 0x00 | ||
503 | }; | ||
504 | |||
505 | /* 48.0 kHz 50hz */ | ||
506 | static const unsigned char saa7115_cfg_50hz_48_audio[] = { | ||
507 | 0x30, 0x00, | ||
508 | 0x31, 0xc0, | ||
509 | 0x32, 0x03, | ||
510 | 0x00, 0x00 | ||
511 | }; | ||
512 | |||
513 | /* 44.1 kHz 60hz */ | ||
514 | static const unsigned char saa7115_cfg_60hz_441_audio[] = { | ||
515 | 0x30, 0xbc, | ||
516 | 0x31, 0xdf, | ||
517 | 0x32, 0x02, | ||
518 | 0x00, 0x00 | ||
519 | }; | ||
520 | |||
521 | /* 44.1 kHz 50hz */ | ||
522 | static const unsigned char saa7115_cfg_50hz_441_audio[] = { | ||
523 | 0x30, 0x00, | ||
524 | 0x31, 0x72, | ||
525 | 0x32, 0x03, | ||
526 | 0x00, 0x00 | ||
527 | }; | ||
528 | |||
529 | /* 32.0 kHz 60hz */ | ||
530 | static const unsigned char saa7115_cfg_60hz_32_audio[] = { | ||
531 | 0x30, 0xde, | ||
532 | 0x31, 0x15, | ||
533 | 0x32, 0x02, | ||
534 | 0x00, 0x00 | ||
535 | }; | ||
536 | |||
537 | /* 32.0 kHz 50hz */ | ||
538 | static const unsigned char saa7115_cfg_50hz_32_audio[] = { | ||
539 | 0x30, 0x00, | ||
540 | 0x31, 0x80, | ||
541 | 0x32, 0x02, | ||
542 | 0x00, 0x00 | ||
543 | }; | ||
544 | |||
545 | static int saa7115_odd_parity(u8 c) | ||
546 | { | ||
547 | c ^= (c >> 4); | ||
548 | c ^= (c >> 2); | ||
549 | c ^= (c >> 1); | ||
550 | |||
551 | return c & 1; | ||
552 | } | ||
553 | |||
554 | static int saa7115_decode_vps(u8 * dst, u8 * p) | ||
555 | { | ||
556 | static const u8 biphase_tbl[] = { | ||
557 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
558 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
559 | 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, | ||
560 | 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, | ||
561 | 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, | ||
562 | 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, | ||
563 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
564 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
565 | 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, | ||
566 | 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, | ||
567 | 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, | ||
568 | 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, | ||
569 | 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, | ||
570 | 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, | ||
571 | 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, | ||
572 | 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, | ||
573 | 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, | ||
574 | 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, | ||
575 | 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, | ||
576 | 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, | ||
577 | 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, | ||
578 | 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, | ||
579 | 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, | ||
580 | 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, | ||
581 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
582 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
583 | 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, | ||
584 | 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, | ||
585 | 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, | ||
586 | 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, | ||
587 | 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, | ||
588 | 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, | ||
589 | }; | ||
590 | int i; | ||
591 | u8 c, err = 0; | ||
592 | |||
593 | for (i = 0; i < 2 * 13; i += 2) { | ||
594 | err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; | ||
595 | c = (biphase_tbl[p[i + 1]] & 0xf) | ((biphase_tbl[p[i]] & 0xf) << 4); | ||
596 | dst[i / 2] = c; | ||
597 | } | ||
598 | return err & 0xf0; | ||
599 | } | ||
600 | |||
601 | static int saa7115_decode_wss(u8 * p) | ||
602 | { | ||
603 | static const int wss_bits[8] = { | ||
604 | 0, 0, 0, 1, 0, 1, 1, 1 | ||
605 | }; | ||
606 | unsigned char parity; | ||
607 | int wss = 0; | ||
608 | int i; | ||
609 | |||
610 | for (i = 0; i < 16; i++) { | ||
611 | int b1 = wss_bits[p[i] & 7]; | ||
612 | int b2 = wss_bits[(p[i] >> 3) & 7]; | ||
613 | |||
614 | if (b1 == b2) | ||
615 | return -1; | ||
616 | wss |= b2 << i; | ||
617 | } | ||
618 | parity = wss & 15; | ||
619 | parity ^= parity >> 2; | ||
620 | parity ^= parity >> 1; | ||
621 | |||
622 | if (!(parity & 1)) | ||
623 | return -1; | ||
624 | |||
625 | return wss; | ||
626 | } | ||
627 | |||
628 | |||
629 | static int saa7115_set_audio_clock_freq(struct i2c_client *client, enum v4l2_audio_clock_freq freq) | ||
630 | { | ||
631 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
632 | |||
633 | saa7115_dbg("set audio clock freq: %d\n", freq); | ||
634 | switch (freq) { | ||
635 | case V4L2_AUDCLK_32_KHZ: | ||
636 | saa7115_writeregs(client, saa7115_cfg_32_audio); | ||
637 | if (state->std & V4L2_STD_525_60) { | ||
638 | saa7115_writeregs(client, saa7115_cfg_60hz_32_audio); | ||
639 | } else { | ||
640 | saa7115_writeregs(client, saa7115_cfg_50hz_32_audio); | ||
641 | } | ||
642 | break; | ||
643 | case V4L2_AUDCLK_441_KHZ: | ||
644 | saa7115_writeregs(client, saa7115_cfg_441_audio); | ||
645 | if (state->std & V4L2_STD_525_60) { | ||
646 | saa7115_writeregs(client, saa7115_cfg_60hz_441_audio); | ||
647 | } else { | ||
648 | saa7115_writeregs(client, saa7115_cfg_50hz_441_audio); | ||
649 | } | ||
650 | break; | ||
651 | case V4L2_AUDCLK_48_KHZ: | ||
652 | saa7115_writeregs(client, saa7115_cfg_48_audio); | ||
653 | if (state->std & V4L2_STD_525_60) { | ||
654 | saa7115_writeregs(client, saa7115_cfg_60hz_48_audio); | ||
655 | } else { | ||
656 | saa7115_writeregs(client, saa7115_cfg_50hz_48_audio); | ||
657 | } | ||
658 | break; | ||
659 | default: | ||
660 | saa7115_dbg("invalid audio setting %d\n", freq); | ||
661 | return -EINVAL; | ||
662 | } | ||
663 | state->audclk_freq = freq; | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
668 | { | ||
669 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
670 | |||
671 | switch (ctrl->id) { | ||
672 | case V4L2_CID_BRIGHTNESS: | ||
673 | if (ctrl->value < 0 || ctrl->value > 255) { | ||
674 | saa7115_err("invalid brightness setting %d\n", ctrl->value); | ||
675 | return -ERANGE; | ||
676 | } | ||
677 | |||
678 | state->bright = ctrl->value; | ||
679 | saa7115_write(client, 0x0a, state->bright); | ||
680 | break; | ||
681 | |||
682 | case V4L2_CID_CONTRAST: | ||
683 | if (ctrl->value < 0 || ctrl->value > 127) { | ||
684 | saa7115_err("invalid contrast setting %d\n", ctrl->value); | ||
685 | return -ERANGE; | ||
686 | } | ||
687 | |||
688 | state->contrast = ctrl->value; | ||
689 | saa7115_write(client, 0x0b, state->contrast); | ||
690 | break; | ||
691 | |||
692 | case V4L2_CID_SATURATION: | ||
693 | if (ctrl->value < 0 || ctrl->value > 127) { | ||
694 | saa7115_err("invalid saturation setting %d\n", ctrl->value); | ||
695 | return -ERANGE; | ||
696 | } | ||
697 | |||
698 | state->sat = ctrl->value; | ||
699 | saa7115_write(client, 0x0c, state->sat); | ||
700 | break; | ||
701 | |||
702 | case V4L2_CID_HUE: | ||
703 | if (ctrl->value < -127 || ctrl->value > 127) { | ||
704 | saa7115_err("invalid hue setting %d\n", ctrl->value); | ||
705 | return -ERANGE; | ||
706 | } | ||
707 | |||
708 | state->hue = ctrl->value; | ||
709 | saa7115_write(client, 0x0d, state->hue); | ||
710 | break; | ||
711 | } | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
717 | { | ||
718 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
719 | |||
720 | switch (ctrl->id) { | ||
721 | case V4L2_CID_BRIGHTNESS: | ||
722 | ctrl->value = state->bright; | ||
723 | break; | ||
724 | case V4L2_CID_CONTRAST: | ||
725 | ctrl->value = state->contrast; | ||
726 | break; | ||
727 | case V4L2_CID_SATURATION: | ||
728 | ctrl->value = state->sat; | ||
729 | break; | ||
730 | case V4L2_CID_HUE: | ||
731 | ctrl->value = state->hue; | ||
732 | break; | ||
733 | default: | ||
734 | return -EINVAL; | ||
735 | } | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) | ||
741 | { | ||
742 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
743 | int taskb = saa7115_read(client, 0x80) & 0x10; | ||
744 | |||
745 | // This works for NTSC-M, SECAM-L and the 50Hz PAL variants. | ||
746 | if (std & V4L2_STD_525_60) { | ||
747 | saa7115_dbg("decoder set standard 60 Hz\n"); | ||
748 | saa7115_writeregs(client, saa7115_cfg_60hz_video); | ||
749 | } else { | ||
750 | saa7115_dbg("decoder set standard 50 Hz\n"); | ||
751 | saa7115_writeregs(client, saa7115_cfg_50hz_video); | ||
752 | } | ||
753 | |||
754 | state->std = std; | ||
755 | |||
756 | /* restart task B if needed */ | ||
757 | if (taskb && state->ident == V4L2_IDENT_SAA7114) { | ||
758 | saa7115_writeregs(client, saa7115_cfg_vbi_on); | ||
759 | } | ||
760 | |||
761 | /* switch audio mode too! */ | ||
762 | saa7115_set_audio_clock_freq(client, state->audclk_freq); | ||
763 | } | ||
764 | |||
765 | static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client) | ||
766 | { | ||
767 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
768 | |||
769 | return state->std; | ||
770 | } | ||
771 | |||
772 | static void saa7115_log_status(struct i2c_client *client) | ||
773 | { | ||
774 | static const char * const audclk_freq_strs[] = { | ||
775 | "44.1 kHz", | ||
776 | "48 kHz", | ||
777 | "32 kHz" | ||
778 | }; | ||
779 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
780 | int reg1e, reg1f; | ||
781 | int signalOk; | ||
782 | int vcr; | ||
783 | |||
784 | saa7115_info("Audio frequency: %s\n", audclk_freq_strs[state->audclk_freq]); | ||
785 | if (client->name[6] == '4') { | ||
786 | /* status for the saa7114 */ | ||
787 | reg1f = saa7115_read(client, 0x1f); | ||
788 | signalOk = (reg1f & 0xc1) == 0x81; | ||
789 | saa7115_info("Video signal: %s\n", signalOk ? "ok" : "bad"); | ||
790 | saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | /* status for the saa7115 */ | ||
795 | reg1e = saa7115_read(client, 0x1e); | ||
796 | reg1f = saa7115_read(client, 0x1f); | ||
797 | |||
798 | signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80; | ||
799 | vcr = !(reg1f & 0x10); | ||
800 | |||
801 | saa7115_info("Video signal: %s\n", signalOk ? (vcr ? "VCR" : "broadcast/DVD") : "bad"); | ||
802 | saa7115_info("Frequency: %s\n", (reg1f & 0x20) ? "60Hz" : "50Hz"); | ||
803 | |||
804 | switch (reg1e & 0x03) { | ||
805 | case 1: | ||
806 | saa7115_info("Detected format: NTSC\n"); | ||
807 | break; | ||
808 | case 2: | ||
809 | saa7115_info("Detected format: PAL\n"); | ||
810 | break; | ||
811 | case 3: | ||
812 | saa7115_info("Detected format: SECAM\n"); | ||
813 | break; | ||
814 | default: | ||
815 | saa7115_info("Detected format: BW/No color\n"); | ||
816 | break; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | /* setup the sliced VBI lcr registers according to the sliced VBI format */ | ||
821 | static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt) | ||
822 | { | ||
823 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
824 | int is_50hz = (state->std & V4L2_STD_625_50); | ||
825 | u8 lcr[24]; | ||
826 | int i, x; | ||
827 | |||
828 | /* saa7114 doesn't yet support VBI */ | ||
829 | if (state->ident == V4L2_IDENT_SAA7114) | ||
830 | return; | ||
831 | |||
832 | for (i = 0; i <= 23; i++) | ||
833 | lcr[i] = 0xff; | ||
834 | |||
835 | if (fmt->service_set == 0) { | ||
836 | /* raw VBI */ | ||
837 | if (is_50hz) | ||
838 | for (i = 6; i <= 23; i++) | ||
839 | lcr[i] = 0xdd; | ||
840 | else | ||
841 | for (i = 10; i <= 21; i++) | ||
842 | lcr[i] = 0xdd; | ||
843 | } else { | ||
844 | /* sliced VBI */ | ||
845 | /* first clear lines that cannot be captured */ | ||
846 | if (is_50hz) { | ||
847 | for (i = 0; i <= 5; i++) | ||
848 | fmt->service_lines[0][i] = | ||
849 | fmt->service_lines[1][i] = 0; | ||
850 | } | ||
851 | else { | ||
852 | for (i = 0; i <= 9; i++) | ||
853 | fmt->service_lines[0][i] = | ||
854 | fmt->service_lines[1][i] = 0; | ||
855 | for (i = 22; i <= 23; i++) | ||
856 | fmt->service_lines[0][i] = | ||
857 | fmt->service_lines[1][i] = 0; | ||
858 | } | ||
859 | |||
860 | /* Now set the lcr values according to the specified service */ | ||
861 | for (i = 6; i <= 23; i++) { | ||
862 | lcr[i] = 0; | ||
863 | for (x = 0; x <= 1; x++) { | ||
864 | switch (fmt->service_lines[1-x][i]) { | ||
865 | case 0: | ||
866 | lcr[i] |= 0xf << (4 * x); | ||
867 | break; | ||
868 | case V4L2_SLICED_TELETEXT_B: | ||
869 | lcr[i] |= 1 << (4 * x); | ||
870 | break; | ||
871 | case V4L2_SLICED_CAPTION_525: | ||
872 | lcr[i] |= 4 << (4 * x); | ||
873 | break; | ||
874 | case V4L2_SLICED_WSS_625: | ||
875 | lcr[i] |= 5 << (4 * x); | ||
876 | break; | ||
877 | case V4L2_SLICED_VPS: | ||
878 | lcr[i] |= 7 << (4 * x); | ||
879 | break; | ||
880 | } | ||
881 | } | ||
882 | } | ||
883 | } | ||
884 | |||
885 | /* write the lcr registers */ | ||
886 | for (i = 2; i <= 23; i++) { | ||
887 | saa7115_write(client, i - 2 + 0x41, lcr[i]); | ||
888 | } | ||
889 | |||
890 | /* enable/disable raw VBI capturing */ | ||
891 | saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off); | ||
892 | } | ||
893 | |||
894 | static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) | ||
895 | { | ||
896 | static u16 lcr2vbi[] = { | ||
897 | 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ | ||
898 | 0, V4L2_SLICED_CAPTION_525, /* 4 */ | ||
899 | V4L2_SLICED_WSS_625, 0, /* 5 */ | ||
900 | V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */ | ||
901 | 0, 0, 0, 0 | ||
902 | }; | ||
903 | struct v4l2_sliced_vbi_format *sliced = &fmt->fmt.sliced; | ||
904 | int i; | ||
905 | |||
906 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
907 | return -EINVAL; | ||
908 | memset(sliced, 0, sizeof(*sliced)); | ||
909 | /* done if using raw VBI */ | ||
910 | if (saa7115_read(client, 0x80) & 0x10) | ||
911 | return 0; | ||
912 | for (i = 2; i <= 23; i++) { | ||
913 | u8 v = saa7115_read(client, i - 2 + 0x41); | ||
914 | |||
915 | sliced->service_lines[0][i] = lcr2vbi[v >> 4]; | ||
916 | sliced->service_lines[1][i] = lcr2vbi[v & 0xf]; | ||
917 | sliced->service_set |= | ||
918 | sliced->service_lines[0][i] | sliced->service_lines[1][i]; | ||
919 | } | ||
920 | return 0; | ||
921 | } | ||
922 | |||
923 | static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) | ||
924 | { | ||
925 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
926 | struct v4l2_pix_format *pix; | ||
927 | int HPSC, HFSC; | ||
928 | int VSCY, Vsrc; | ||
929 | int is_50hz = state->std & V4L2_STD_625_50; | ||
930 | |||
931 | if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { | ||
932 | saa7115_set_lcr(client, &fmt->fmt.sliced); | ||
933 | return 0; | ||
934 | } | ||
935 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
936 | return -EINVAL; | ||
937 | |||
938 | pix = &(fmt->fmt.pix); | ||
939 | |||
940 | saa7115_dbg("decoder set size\n"); | ||
941 | |||
942 | /* FIXME need better bounds checking here */ | ||
943 | if ((pix->width < 1) || (pix->width > 1440)) | ||
944 | return -EINVAL; | ||
945 | if ((pix->height < 1) || (pix->height > 960)) | ||
946 | return -EINVAL; | ||
947 | |||
948 | /* probably have a valid size, let's set it */ | ||
949 | /* Set output width/height */ | ||
950 | /* width */ | ||
951 | saa7115_write(client, 0xcc, (u8) (pix->width & 0xff)); | ||
952 | saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff)); | ||
953 | /* height */ | ||
954 | saa7115_write(client, 0xce, (u8) (pix->height & 0xff)); | ||
955 | saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff)); | ||
956 | |||
957 | /* Scaling settings */ | ||
958 | /* Hprescaler is floor(inres/outres) */ | ||
959 | /* FIXME hardcoding input res */ | ||
960 | if (pix->width != 720) { | ||
961 | HPSC = (int)(720 / pix->width); | ||
962 | /* 0 is not allowed (div. by zero) */ | ||
963 | HPSC = HPSC ? HPSC : 1; | ||
964 | HFSC = (int)((1024 * 720) / (HPSC * pix->width)); | ||
965 | |||
966 | saa7115_dbg("Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC); | ||
967 | /* FIXME hardcodes to "Task B" | ||
968 | * write H prescaler integer */ | ||
969 | saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f)); | ||
970 | |||
971 | /* write H fine-scaling (luminance) */ | ||
972 | saa7115_write(client, 0xd8, (u8) (HFSC & 0xff)); | ||
973 | saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff)); | ||
974 | /* write H fine-scaling (chrominance) | ||
975 | * must be lum/2, so i'll just bitshift :) */ | ||
976 | saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff)); | ||
977 | saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff)); | ||
978 | } else { | ||
979 | if (is_50hz) { | ||
980 | saa7115_dbg("Setting full 50hz width\n"); | ||
981 | saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x); | ||
982 | } else { | ||
983 | saa7115_dbg("Setting full 60hz width\n"); | ||
984 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); | ||
985 | } | ||
986 | } | ||
987 | |||
988 | Vsrc = is_50hz ? 576 : 480; | ||
989 | |||
990 | if (pix->height != Vsrc) { | ||
991 | VSCY = (int)((1024 * Vsrc) / pix->height); | ||
992 | saa7115_dbg("Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY); | ||
993 | |||
994 | /* Correct Contrast and Luminance */ | ||
995 | saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY)); | ||
996 | saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY)); | ||
997 | |||
998 | /* write V fine-scaling (luminance) */ | ||
999 | saa7115_write(client, 0xe0, (u8) (VSCY & 0xff)); | ||
1000 | saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff)); | ||
1001 | /* write V fine-scaling (chrominance) */ | ||
1002 | saa7115_write(client, 0xe2, (u8) (VSCY & 0xff)); | ||
1003 | saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff)); | ||
1004 | } else { | ||
1005 | if (is_50hz) { | ||
1006 | saa7115_dbg("Setting full 50Hz height\n"); | ||
1007 | saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y); | ||
1008 | } else { | ||
1009 | saa7115_dbg("Setting full 60hz height\n"); | ||
1010 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); | ||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | /* Decode the sliced VBI data stream as created by the saa7115. | ||
1019 | The format is described in the saa7115 datasheet in Tables 25 and 26 | ||
1020 | and in Figure 33. | ||
1021 | The current implementation uses SAV/EAV codes and not the ancillary data | ||
1022 | headers. The vbi->p pointer points to the SDID byte right after the SAV | ||
1023 | code. */ | ||
1024 | static void saa7115_decode_vbi_line(struct i2c_client *client, | ||
1025 | struct v4l2_decode_vbi_line *vbi) | ||
1026 | { | ||
1027 | static const char vbi_no_data_pattern[] = { | ||
1028 | 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0 | ||
1029 | }; | ||
1030 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
1031 | u8 *p = vbi->p; | ||
1032 | u32 wss; | ||
1033 | int id1, id2; /* the ID1 and ID2 bytes from the internal header */ | ||
1034 | |||
1035 | vbi->type = 0; /* mark result as a failure */ | ||
1036 | id1 = p[2]; | ||
1037 | id2 = p[3]; | ||
1038 | /* Note: the field bit is inverted for 60 Hz video */ | ||
1039 | if (state->std & V4L2_STD_525_60) | ||
1040 | id1 ^= 0x40; | ||
1041 | |||
1042 | /* Skip internal header, p now points to the start of the payload */ | ||
1043 | p += 4; | ||
1044 | vbi->p = p; | ||
1045 | |||
1046 | /* calculate field and line number of the VBI packet (1-23) */ | ||
1047 | vbi->is_second_field = ((id1 & 0x40) != 0); | ||
1048 | vbi->line = (id1 & 0x3f) << 3; | ||
1049 | vbi->line |= (id2 & 0x70) >> 4; | ||
1050 | |||
1051 | /* Obtain data type */ | ||
1052 | id2 &= 0xf; | ||
1053 | |||
1054 | /* If the VBI slicer does not detect any signal it will fill up | ||
1055 | the payload buffer with 0xa0 bytes. */ | ||
1056 | if (!memcmp(p, vbi_no_data_pattern, sizeof(vbi_no_data_pattern))) | ||
1057 | return; | ||
1058 | |||
1059 | /* decode payloads */ | ||
1060 | switch (id2) { | ||
1061 | case 1: | ||
1062 | vbi->type = V4L2_SLICED_TELETEXT_B; | ||
1063 | break; | ||
1064 | case 4: | ||
1065 | if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1])) | ||
1066 | return; | ||
1067 | vbi->type = V4L2_SLICED_CAPTION_525; | ||
1068 | break; | ||
1069 | case 5: | ||
1070 | wss = saa7115_decode_wss(p); | ||
1071 | if (wss == -1) | ||
1072 | return; | ||
1073 | p[0] = wss & 0xff; | ||
1074 | p[1] = wss >> 8; | ||
1075 | vbi->type = V4L2_SLICED_WSS_625; | ||
1076 | break; | ||
1077 | case 7: | ||
1078 | if (saa7115_decode_vps(p, p) != 0) | ||
1079 | return; | ||
1080 | vbi->type = V4L2_SLICED_VPS; | ||
1081 | break; | ||
1082 | default: | ||
1083 | return; | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | /* ============ SAA7115 AUDIO settings (end) ============= */ | ||
1088 | |||
1089 | static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg) | ||
1090 | { | ||
1091 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
1092 | int *iarg = arg; | ||
1093 | |||
1094 | /* ioctls to allow direct access to the saa7115 registers for testing */ | ||
1095 | switch (cmd) { | ||
1096 | case VIDIOC_S_FMT: | ||
1097 | return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg); | ||
1098 | |||
1099 | case VIDIOC_G_FMT: | ||
1100 | return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg); | ||
1101 | |||
1102 | case VIDIOC_INT_AUDIO_CLOCK_FREQ: | ||
1103 | return saa7115_set_audio_clock_freq(client, *(enum v4l2_audio_clock_freq *)arg); | ||
1104 | |||
1105 | case VIDIOC_G_TUNER: | ||
1106 | { | ||
1107 | struct v4l2_tuner *vt = arg; | ||
1108 | int status; | ||
1109 | |||
1110 | status = saa7115_read(client, 0x1f); | ||
1111 | |||
1112 | saa7115_dbg("status: 0x%02x\n", status); | ||
1113 | vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0; | ||
1114 | break; | ||
1115 | } | ||
1116 | |||
1117 | case VIDIOC_LOG_STATUS: | ||
1118 | saa7115_log_status(client); | ||
1119 | break; | ||
1120 | |||
1121 | case VIDIOC_G_CTRL: | ||
1122 | return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg); | ||
1123 | |||
1124 | case VIDIOC_S_CTRL: | ||
1125 | return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg); | ||
1126 | |||
1127 | case VIDIOC_G_STD: | ||
1128 | *(v4l2_std_id *)arg = saa7115_get_v4lstd(client); | ||
1129 | break; | ||
1130 | |||
1131 | case VIDIOC_S_STD: | ||
1132 | saa7115_set_v4lstd(client, *(v4l2_std_id *)arg); | ||
1133 | break; | ||
1134 | |||
1135 | case VIDIOC_G_INPUT: | ||
1136 | *(int *)arg = state->input; | ||
1137 | break; | ||
1138 | |||
1139 | case VIDIOC_S_INPUT: | ||
1140 | saa7115_dbg("decoder set input %d\n", *iarg); | ||
1141 | /* inputs from 0-9 are available */ | ||
1142 | if (*iarg < 0 || *iarg > 9) { | ||
1143 | return -EINVAL; | ||
1144 | } | ||
1145 | |||
1146 | if (state->input == *iarg) | ||
1147 | break; | ||
1148 | saa7115_dbg("now setting %s input\n", | ||
1149 | *iarg >= 6 ? "S-Video" : "Composite"); | ||
1150 | state->input = *iarg; | ||
1151 | |||
1152 | /* select mode */ | ||
1153 | saa7115_write(client, 0x02, | ||
1154 | (saa7115_read(client, 0x02) & 0xf0) | | ||
1155 | state->input); | ||
1156 | |||
1157 | /* bypass chrominance trap for modes 6..9 */ | ||
1158 | saa7115_write(client, 0x09, | ||
1159 | (saa7115_read(client, 0x09) & 0x7f) | | ||
1160 | (state->input < 6 ? 0x0 : 0x80)); | ||
1161 | break; | ||
1162 | |||
1163 | case VIDIOC_STREAMON: | ||
1164 | case VIDIOC_STREAMOFF: | ||
1165 | saa7115_dbg("%s output\n", | ||
1166 | (cmd == VIDIOC_STREAMON) ? "enable" : "disable"); | ||
1167 | |||
1168 | if (state->enable != (cmd == VIDIOC_STREAMON)) { | ||
1169 | state->enable = (cmd == VIDIOC_STREAMON); | ||
1170 | saa7115_write(client, 0x87, state->enable); | ||
1171 | } | ||
1172 | break; | ||
1173 | |||
1174 | case VIDIOC_INT_DECODE_VBI_LINE: | ||
1175 | saa7115_decode_vbi_line(client, arg); | ||
1176 | break; | ||
1177 | |||
1178 | case VIDIOC_INT_RESET: | ||
1179 | saa7115_dbg("decoder RESET\n"); | ||
1180 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); | ||
1181 | break; | ||
1182 | |||
1183 | case VIDIOC_INT_G_VBI_DATA: | ||
1184 | { | ||
1185 | struct v4l2_sliced_vbi_data *data = arg; | ||
1186 | |||
1187 | switch (data->id) { | ||
1188 | case V4L2_SLICED_WSS_625: | ||
1189 | if (saa7115_read(client, 0x6b) & 0xc0) | ||
1190 | return -EIO; | ||
1191 | data->data[0] = saa7115_read(client, 0x6c); | ||
1192 | data->data[1] = saa7115_read(client, 0x6d); | ||
1193 | return 0; | ||
1194 | case V4L2_SLICED_CAPTION_525: | ||
1195 | if (data->field == 0) { | ||
1196 | /* CC */ | ||
1197 | if (saa7115_read(client, 0x66) & 0xc0) | ||
1198 | return -EIO; | ||
1199 | data->data[0] = saa7115_read(client, 0x67); | ||
1200 | data->data[1] = saa7115_read(client, 0x68); | ||
1201 | return 0; | ||
1202 | } | ||
1203 | /* XDS */ | ||
1204 | if (saa7115_read(client, 0x66) & 0x30) | ||
1205 | return -EIO; | ||
1206 | data->data[0] = saa7115_read(client, 0x69); | ||
1207 | data->data[1] = saa7115_read(client, 0x6a); | ||
1208 | return 0; | ||
1209 | default: | ||
1210 | return -EINVAL; | ||
1211 | } | ||
1212 | break; | ||
1213 | } | ||
1214 | |||
1215 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
1216 | case VIDIOC_INT_G_REGISTER: | ||
1217 | { | ||
1218 | struct v4l2_register *reg = arg; | ||
1219 | |||
1220 | if (reg->i2c_id != I2C_DRIVERID_SAA711X) | ||
1221 | return -EINVAL; | ||
1222 | reg->val = saa7115_read(client, reg->reg & 0xff); | ||
1223 | break; | ||
1224 | } | ||
1225 | |||
1226 | case VIDIOC_INT_S_REGISTER: | ||
1227 | { | ||
1228 | struct v4l2_register *reg = arg; | ||
1229 | |||
1230 | if (reg->i2c_id != I2C_DRIVERID_SAA711X) | ||
1231 | return -EINVAL; | ||
1232 | if (!capable(CAP_SYS_ADMIN)) | ||
1233 | return -EPERM; | ||
1234 | saa7115_write(client, reg->reg & 0xff, reg->val & 0xff); | ||
1235 | break; | ||
1236 | } | ||
1237 | #endif | ||
1238 | |||
1239 | case VIDIOC_INT_G_CHIP_IDENT: | ||
1240 | *iarg = state->ident; | ||
1241 | break; | ||
1242 | |||
1243 | default: | ||
1244 | return -EINVAL; | ||
1245 | } | ||
1246 | |||
1247 | return 0; | ||
1248 | } | ||
1249 | |||
1250 | /* ----------------------------------------------------------------------- */ | ||
1251 | |||
1252 | static struct i2c_driver i2c_driver_saa7115; | ||
1253 | |||
1254 | static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) | ||
1255 | { | ||
1256 | struct i2c_client *client; | ||
1257 | struct saa7115_state *state; | ||
1258 | u8 chip_id; | ||
1259 | |||
1260 | /* Check if the adapter supports the needed features */ | ||
1261 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
1262 | return 0; | ||
1263 | |||
1264 | client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
1265 | if (client == 0) | ||
1266 | return -ENOMEM; | ||
1267 | memset(client, 0, sizeof(struct i2c_client)); | ||
1268 | client->addr = address; | ||
1269 | client->adapter = adapter; | ||
1270 | client->driver = &i2c_driver_saa7115; | ||
1271 | client->flags = I2C_CLIENT_ALLOW_USE; | ||
1272 | snprintf(client->name, sizeof(client->name) - 1, "saa7115"); | ||
1273 | |||
1274 | saa7115_dbg("detecting saa7115 client on address 0x%x\n", address << 1); | ||
1275 | |||
1276 | saa7115_write(client, 0, 5); | ||
1277 | chip_id = saa7115_read(client, 0) & 0x0f; | ||
1278 | if (chip_id != 4 && chip_id != 5) { | ||
1279 | saa7115_dbg("saa7115 not found\n"); | ||
1280 | kfree(client); | ||
1281 | return 0; | ||
1282 | } | ||
1283 | if (chip_id == 4) { | ||
1284 | snprintf(client->name, sizeof(client->name) - 1, "saa7114"); | ||
1285 | } | ||
1286 | saa7115_info("saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name); | ||
1287 | |||
1288 | state = kmalloc(sizeof(struct saa7115_state), GFP_KERNEL); | ||
1289 | i2c_set_clientdata(client, state); | ||
1290 | if (state == NULL) { | ||
1291 | kfree(client); | ||
1292 | return -ENOMEM; | ||
1293 | } | ||
1294 | memset(state, 0, sizeof(struct saa7115_state)); | ||
1295 | state->std = V4L2_STD_NTSC; | ||
1296 | state->input = -1; | ||
1297 | state->enable = 1; | ||
1298 | state->bright = 128; | ||
1299 | state->contrast = 64; | ||
1300 | state->hue = 0; | ||
1301 | state->sat = 64; | ||
1302 | state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; | ||
1303 | state->audclk_freq = V4L2_AUDCLK_48_KHZ; | ||
1304 | |||
1305 | saa7115_dbg("writing init values\n"); | ||
1306 | |||
1307 | /* init to 60hz/48khz */ | ||
1308 | saa7115_writeregs(client, saa7115_init_auto_input); | ||
1309 | saa7115_writeregs(client, saa7115_init_misc); | ||
1310 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); | ||
1311 | saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); | ||
1312 | saa7115_writeregs(client, saa7115_cfg_60hz_video); | ||
1313 | saa7115_writeregs(client, saa7115_cfg_48_audio); | ||
1314 | saa7115_writeregs(client, saa7115_cfg_60hz_48_audio); | ||
1315 | saa7115_writeregs(client, saa7115_cfg_reset_scaler); | ||
1316 | |||
1317 | i2c_attach_client(client); | ||
1318 | |||
1319 | saa7115_dbg("status: (1E) 0x%02x, (1F) 0x%02x\n", | ||
1320 | saa7115_read(client, 0x1e), saa7115_read(client, 0x1f)); | ||
1321 | |||
1322 | return 0; | ||
1323 | } | ||
1324 | |||
1325 | static int saa7115_probe(struct i2c_adapter *adapter) | ||
1326 | { | ||
1327 | #ifdef I2C_CLASS_TV_ANALOG | ||
1328 | if (adapter->class & I2C_CLASS_TV_ANALOG) | ||
1329 | #else | ||
1330 | if (adapter->id == I2C_HW_B_BT848) | ||
1331 | #endif | ||
1332 | return i2c_probe(adapter, &addr_data, &saa7115_attach); | ||
1333 | return 0; | ||
1334 | } | ||
1335 | |||
1336 | static int saa7115_detach(struct i2c_client *client) | ||
1337 | { | ||
1338 | struct saa7115_state *state = i2c_get_clientdata(client); | ||
1339 | int err; | ||
1340 | |||
1341 | err = i2c_detach_client(client); | ||
1342 | if (err) { | ||
1343 | return err; | ||
1344 | } | ||
1345 | |||
1346 | kfree(state); | ||
1347 | kfree(client); | ||
1348 | return 0; | ||
1349 | } | ||
1350 | |||
1351 | /* ----------------------------------------------------------------------- */ | ||
1352 | |||
1353 | /* i2c implementation */ | ||
1354 | static struct i2c_driver i2c_driver_saa7115 = { | ||
1355 | .name = "saa7115", | ||
1356 | .id = I2C_DRIVERID_SAA711X, | ||
1357 | .flags = I2C_DF_NOTIFY, | ||
1358 | .attach_adapter = saa7115_probe, | ||
1359 | .detach_client = saa7115_detach, | ||
1360 | .command = saa7115_command, | ||
1361 | .owner = THIS_MODULE, | ||
1362 | }; | ||
1363 | |||
1364 | |||
1365 | static int __init saa7115_init_module(void) | ||
1366 | { | ||
1367 | return i2c_add_driver(&i2c_driver_saa7115); | ||
1368 | } | ||
1369 | |||
1370 | static void __exit saa7115_cleanup_module(void) | ||
1371 | { | ||
1372 | i2c_del_driver(&i2c_driver_saa7115); | ||
1373 | } | ||
1374 | |||
1375 | module_init(saa7115_init_module); | ||
1376 | module_exit(saa7115_cleanup_module); | ||
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c index 9aa8827de2c3..25b30f352d84 100644 --- a/drivers/media/video/saa711x.c +++ b/drivers/media/video/saa711x.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include <asm/pgtable.h> | 36 | #include <asm/pgtable.h> |
37 | #include <asm/page.h> | 37 | #include <asm/page.h> |
38 | #include <linux/sched.h> | 38 | #include <linux/sched.h> |
39 | #include <asm/segment.h> | ||
40 | #include <linux/types.h> | 39 | #include <linux/types.h> |
41 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
42 | #include <linux/videodev.h> | 41 | #include <linux/videodev.h> |
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c new file mode 100644 index 000000000000..843431f10e3b --- /dev/null +++ b/drivers/media/video/saa7127.c | |||
@@ -0,0 +1,849 @@ | |||
1 | /* | ||
2 | * saa7127 - Philips SAA7127/SAA7129 video encoder driver | ||
3 | * | ||
4 | * Copyright (C) 2003 Roy Bulter <rbulter@hetnet.nl> | ||
5 | * | ||
6 | * Based on SAA7126 video encoder driver by Gillem & Andreas Oberritter | ||
7 | * | ||
8 | * Copyright (C) 2000-2001 Gillem <htoa@gmx.net> | ||
9 | * Copyright (C) 2002 Andreas Oberritter <obi@saftware.de> | ||
10 | * | ||
11 | * Based on Stadis 4:2:2 MPEG-2 Decoder Driver by Nathan Laredo | ||
12 | * | ||
13 | * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org> | ||
14 | * | ||
15 | * This driver is designed for the Hauppauge 250/350 Linux driver | ||
16 | * from the ivtv Project | ||
17 | * | ||
18 | * Copyright (C) 2003 Kevin Thayer <nufan_wfk@yahoo.com> | ||
19 | * | ||
20 | * Dual output support: | ||
21 | * Copyright (C) 2004 Eric Varsanyi | ||
22 | * | ||
23 | * NTSC Tuning and 7.5 IRE Setup | ||
24 | * Copyright (C) 2004 Chris Kennedy <c@groovy.org> | ||
25 | * | ||
26 | * VBI additions & cleanup: | ||
27 | * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl> | ||
28 | * | ||
29 | * Note: the saa7126 is identical to the saa7127, and the saa7128 is | ||
30 | * identical to the saa7129, except that the saa7126 and saa7128 have | ||
31 | * macrovision anti-taping support. This driver will almost certainly | ||
32 | * work find for those chips, except of course for the missing anti-taping | ||
33 | * support. | ||
34 | * | ||
35 | * This program is free software; you can redistribute it and/or modify | ||
36 | * it under the terms of the GNU General Public License as published by | ||
37 | * the Free Software Foundation; either version 2 of the License, or | ||
38 | * (at your option) any later version. | ||
39 | * | ||
40 | * This program is distributed in the hope that it will be useful, | ||
41 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
42 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
43 | * GNU General Public License for more details. | ||
44 | * | ||
45 | * You should have received a copy of the GNU General Public License | ||
46 | * along with this program; if not, write to the Free Software | ||
47 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
48 | */ | ||
49 | |||
50 | |||
51 | #include <linux/kernel.h> | ||
52 | #include <linux/module.h> | ||
53 | #include <linux/slab.h> | ||
54 | #include <linux/i2c.h> | ||
55 | #include <linux/videodev2.h> | ||
56 | #include <media/v4l2-common.h> | ||
57 | |||
58 | static int debug = 0; | ||
59 | static int test_image = 0; | ||
60 | |||
61 | MODULE_DESCRIPTION("Philips SAA7127/9 video encoder driver"); | ||
62 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil"); | ||
63 | MODULE_LICENSE("GPL"); | ||
64 | module_param(debug, int, 0644); | ||
65 | module_param(test_image, int, 0644); | ||
66 | MODULE_PARM_DESC(debug, "debug level (0-2)"); | ||
67 | MODULE_PARM_DESC(test_image, "test_image (0-1)"); | ||
68 | |||
69 | #define saa7127_dbg(fmt, arg...) \ | ||
70 | do { \ | ||
71 | if (debug >= 1) \ | ||
72 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
73 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
74 | } while (0) | ||
75 | |||
76 | /* High volume debug. Use with care. */ | ||
77 | #define saa7127_dbg_highvol(fmt, arg...) \ | ||
78 | do { \ | ||
79 | if (debug == 2) \ | ||
80 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
81 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
82 | } while (0) | ||
83 | |||
84 | #define saa7127_err(fmt, arg...) do { \ | ||
85 | printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->name, \ | ||
86 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
87 | #define saa7127_info(fmt, arg...) do { \ | ||
88 | printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->name, \ | ||
89 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
90 | |||
91 | static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; | ||
92 | |||
93 | |||
94 | I2C_CLIENT_INSMOD; | ||
95 | |||
96 | /* | ||
97 | * SAA7127 registers | ||
98 | */ | ||
99 | |||
100 | #define SAA7127_REG_STATUS 0x00 | ||
101 | #define SAA7127_REG_WIDESCREEN_CONFIG 0x26 | ||
102 | #define SAA7127_REG_WIDESCREEN_ENABLE 0x27 | ||
103 | #define SAA7127_REG_BURST_START 0x28 | ||
104 | #define SAA7127_REG_BURST_END 0x29 | ||
105 | #define SAA7127_REG_COPYGEN_0 0x2a | ||
106 | #define SAA7127_REG_COPYGEN_1 0x2b | ||
107 | #define SAA7127_REG_COPYGEN_2 0x2c | ||
108 | #define SAA7127_REG_OUTPUT_PORT_CONTROL 0x2d | ||
109 | #define SAA7127_REG_GAIN_LUMINANCE_RGB 0x38 | ||
110 | #define SAA7127_REG_GAIN_COLORDIFF_RGB 0x39 | ||
111 | #define SAA7127_REG_INPUT_PORT_CONTROL_1 0x3a | ||
112 | #define SAA7129_REG_FADE_KEY_COL2 0x4f | ||
113 | #define SAA7127_REG_CHROMA_PHASE 0x5a | ||
114 | #define SAA7127_REG_GAINU 0x5b | ||
115 | #define SAA7127_REG_GAINV 0x5c | ||
116 | #define SAA7127_REG_BLACK_LEVEL 0x5d | ||
117 | #define SAA7127_REG_BLANKING_LEVEL 0x5e | ||
118 | #define SAA7127_REG_VBI_BLANKING 0x5f | ||
119 | #define SAA7127_REG_DAC_CONTROL 0x61 | ||
120 | #define SAA7127_REG_BURST_AMP 0x62 | ||
121 | #define SAA7127_REG_SUBC3 0x63 | ||
122 | #define SAA7127_REG_SUBC2 0x64 | ||
123 | #define SAA7127_REG_SUBC1 0x65 | ||
124 | #define SAA7127_REG_SUBC0 0x66 | ||
125 | #define SAA7127_REG_LINE_21_ODD_0 0x67 | ||
126 | #define SAA7127_REG_LINE_21_ODD_1 0x68 | ||
127 | #define SAA7127_REG_LINE_21_EVEN_0 0x69 | ||
128 | #define SAA7127_REG_LINE_21_EVEN_1 0x6a | ||
129 | #define SAA7127_REG_RCV_PORT_CONTROL 0x6b | ||
130 | #define SAA7127_REG_VTRIG 0x6c | ||
131 | #define SAA7127_REG_HTRIG_HI 0x6d | ||
132 | #define SAA7127_REG_MULTI 0x6e | ||
133 | #define SAA7127_REG_CLOSED_CAPTION 0x6f | ||
134 | #define SAA7127_REG_RCV2_OUTPUT_START 0x70 | ||
135 | #define SAA7127_REG_RCV2_OUTPUT_END 0x71 | ||
136 | #define SAA7127_REG_RCV2_OUTPUT_MSBS 0x72 | ||
137 | #define SAA7127_REG_TTX_REQUEST_H_START 0x73 | ||
138 | #define SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH 0x74 | ||
139 | #define SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT 0x75 | ||
140 | #define SAA7127_REG_TTX_ODD_REQ_VERT_START 0x76 | ||
141 | #define SAA7127_REG_TTX_ODD_REQ_VERT_END 0x77 | ||
142 | #define SAA7127_REG_TTX_EVEN_REQ_VERT_START 0x78 | ||
143 | #define SAA7127_REG_TTX_EVEN_REQ_VERT_END 0x79 | ||
144 | #define SAA7127_REG_FIRST_ACTIVE 0x7a | ||
145 | #define SAA7127_REG_LAST_ACTIVE 0x7b | ||
146 | #define SAA7127_REG_MSB_VERTICAL 0x7c | ||
147 | #define SAA7127_REG_DISABLE_TTX_LINE_LO_0 0x7e | ||
148 | #define SAA7127_REG_DISABLE_TTX_LINE_LO_1 0x7f | ||
149 | |||
150 | /* | ||
151 | ********************************************************************** | ||
152 | * | ||
153 | * Arrays with configuration parameters for the SAA7127 | ||
154 | * | ||
155 | ********************************************************************** | ||
156 | */ | ||
157 | |||
158 | struct i2c_reg_value { | ||
159 | unsigned char reg; | ||
160 | unsigned char value; | ||
161 | }; | ||
162 | |||
163 | static const struct i2c_reg_value saa7129_init_config_extra[] = { | ||
164 | { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x38 }, | ||
165 | { SAA7127_REG_VTRIG, 0xfa }, | ||
166 | }; | ||
167 | |||
168 | static const struct i2c_reg_value saa7127_init_config_common[] = { | ||
169 | { SAA7127_REG_WIDESCREEN_CONFIG, 0x0d }, | ||
170 | { SAA7127_REG_WIDESCREEN_ENABLE, 0x00 }, | ||
171 | { SAA7127_REG_COPYGEN_0, 0x77 }, | ||
172 | { SAA7127_REG_COPYGEN_1, 0x41 }, | ||
173 | { SAA7127_REG_COPYGEN_2, 0x00 }, /* Macrovision enable/disable */ | ||
174 | { SAA7127_REG_OUTPUT_PORT_CONTROL, 0x9e }, | ||
175 | { SAA7127_REG_GAIN_LUMINANCE_RGB, 0x00 }, | ||
176 | { SAA7127_REG_GAIN_COLORDIFF_RGB, 0x00 }, | ||
177 | { SAA7127_REG_INPUT_PORT_CONTROL_1, 0x80 }, /* for color bars */ | ||
178 | { SAA7127_REG_LINE_21_ODD_0, 0x77 }, | ||
179 | { SAA7127_REG_LINE_21_ODD_1, 0x41 }, | ||
180 | { SAA7127_REG_LINE_21_EVEN_0, 0x88 }, | ||
181 | { SAA7127_REG_LINE_21_EVEN_1, 0x41 }, | ||
182 | { SAA7127_REG_RCV_PORT_CONTROL, 0x12 }, | ||
183 | { SAA7127_REG_VTRIG, 0xf9 }, | ||
184 | { SAA7127_REG_HTRIG_HI, 0x00 }, | ||
185 | { SAA7127_REG_RCV2_OUTPUT_START, 0x41 }, | ||
186 | { SAA7127_REG_RCV2_OUTPUT_END, 0xc3 }, | ||
187 | { SAA7127_REG_RCV2_OUTPUT_MSBS, 0x00 }, | ||
188 | { SAA7127_REG_TTX_REQUEST_H_START, 0x3e }, | ||
189 | { SAA7127_REG_TTX_REQUEST_H_DELAY_LENGTH, 0xb8 }, | ||
190 | { SAA7127_REG_CSYNC_ADVANCE_VSYNC_SHIFT, 0x03 }, | ||
191 | { SAA7127_REG_TTX_ODD_REQ_VERT_START, 0x15 }, | ||
192 | { SAA7127_REG_TTX_ODD_REQ_VERT_END, 0x16 }, | ||
193 | { SAA7127_REG_TTX_EVEN_REQ_VERT_START, 0x15 }, | ||
194 | { SAA7127_REG_TTX_EVEN_REQ_VERT_END, 0x16 }, | ||
195 | { SAA7127_REG_FIRST_ACTIVE, 0x1a }, | ||
196 | { SAA7127_REG_LAST_ACTIVE, 0x01 }, | ||
197 | { SAA7127_REG_MSB_VERTICAL, 0xc0 }, | ||
198 | { SAA7127_REG_DISABLE_TTX_LINE_LO_0, 0x00 }, | ||
199 | { SAA7127_REG_DISABLE_TTX_LINE_LO_1, 0x00 }, | ||
200 | { 0, 0 } | ||
201 | }; | ||
202 | |||
203 | #define SAA7127_60HZ_DAC_CONTROL 0x15 | ||
204 | static const struct i2c_reg_value saa7127_init_config_60hz[] = { | ||
205 | { SAA7127_REG_BURST_START, 0x19 }, | ||
206 | /* BURST_END is also used as a chip ID in saa7127_detect_client */ | ||
207 | { SAA7127_REG_BURST_END, 0x1d }, | ||
208 | { SAA7127_REG_CHROMA_PHASE, 0xa3 }, | ||
209 | { SAA7127_REG_GAINU, 0x98 }, | ||
210 | { SAA7127_REG_GAINV, 0xd3 }, | ||
211 | { SAA7127_REG_BLACK_LEVEL, 0x39 }, | ||
212 | { SAA7127_REG_BLANKING_LEVEL, 0x2e }, | ||
213 | { SAA7127_REG_VBI_BLANKING, 0x2e }, | ||
214 | { SAA7127_REG_DAC_CONTROL, 0x15 }, | ||
215 | { SAA7127_REG_BURST_AMP, 0x4d }, | ||
216 | { SAA7127_REG_SUBC3, 0x1f }, | ||
217 | { SAA7127_REG_SUBC2, 0x7c }, | ||
218 | { SAA7127_REG_SUBC1, 0xf0 }, | ||
219 | { SAA7127_REG_SUBC0, 0x21 }, | ||
220 | { SAA7127_REG_MULTI, 0x90 }, | ||
221 | { SAA7127_REG_CLOSED_CAPTION, 0x11 }, | ||
222 | { 0, 0 } | ||
223 | }; | ||
224 | |||
225 | #define SAA7127_50HZ_DAC_CONTROL 0x02 | ||
226 | struct i2c_reg_value saa7127_init_config_50hz[] = { | ||
227 | { SAA7127_REG_BURST_START, 0x21 }, | ||
228 | /* BURST_END is also used as a chip ID in saa7127_detect_client */ | ||
229 | { SAA7127_REG_BURST_END, 0x1d }, | ||
230 | { SAA7127_REG_CHROMA_PHASE, 0x3f }, | ||
231 | { SAA7127_REG_GAINU, 0x7d }, | ||
232 | { SAA7127_REG_GAINV, 0xaf }, | ||
233 | { SAA7127_REG_BLACK_LEVEL, 0x33 }, | ||
234 | { SAA7127_REG_BLANKING_LEVEL, 0x35 }, | ||
235 | { SAA7127_REG_VBI_BLANKING, 0x35 }, | ||
236 | { SAA7127_REG_DAC_CONTROL, 0x02 }, | ||
237 | { SAA7127_REG_BURST_AMP, 0x2f }, | ||
238 | { SAA7127_REG_SUBC3, 0xcb }, | ||
239 | { SAA7127_REG_SUBC2, 0x8a }, | ||
240 | { SAA7127_REG_SUBC1, 0x09 }, | ||
241 | { SAA7127_REG_SUBC0, 0x2a }, | ||
242 | { SAA7127_REG_MULTI, 0xa0 }, | ||
243 | { SAA7127_REG_CLOSED_CAPTION, 0x00 }, | ||
244 | { 0, 0 } | ||
245 | }; | ||
246 | |||
247 | /* Enumeration for the Supported input types */ | ||
248 | enum saa7127_input_type { | ||
249 | SAA7127_INPUT_TYPE_NORMAL, | ||
250 | SAA7127_INPUT_TYPE_TEST_IMAGE | ||
251 | }; | ||
252 | |||
253 | /* Enumeration for the Supported Output signal types */ | ||
254 | enum saa7127_output_type { | ||
255 | SAA7127_OUTPUT_TYPE_BOTH, | ||
256 | SAA7127_OUTPUT_TYPE_COMPOSITE, | ||
257 | SAA7127_OUTPUT_TYPE_SVIDEO, | ||
258 | SAA7127_OUTPUT_TYPE_RGB, | ||
259 | SAA7127_OUTPUT_TYPE_YUV_C, | ||
260 | SAA7127_OUTPUT_TYPE_YUV_V | ||
261 | }; | ||
262 | |||
263 | /* | ||
264 | ********************************************************************** | ||
265 | * | ||
266 | * Encoder Struct, holds the configuration state of the encoder | ||
267 | * | ||
268 | ********************************************************************** | ||
269 | */ | ||
270 | |||
271 | struct saa7127_state { | ||
272 | v4l2_std_id std; | ||
273 | enum v4l2_chip_ident ident; | ||
274 | enum saa7127_input_type input_type; | ||
275 | enum saa7127_output_type output_type; | ||
276 | int video_enable; | ||
277 | int wss_enable; | ||
278 | u16 wss_mode; | ||
279 | int cc_enable; | ||
280 | u16 cc_data; | ||
281 | int xds_enable; | ||
282 | u16 xds_data; | ||
283 | int vps_enable; | ||
284 | u8 vps_data[5]; | ||
285 | u8 reg_2d; | ||
286 | u8 reg_3a; | ||
287 | u8 reg_3a_cb; /* colorbar bit */ | ||
288 | u8 reg_61; | ||
289 | }; | ||
290 | |||
291 | static const char * const output_strs[] = | ||
292 | { | ||
293 | "S-Video + Composite", | ||
294 | "Composite", | ||
295 | "S-Video", | ||
296 | "RGB", | ||
297 | "YUV C", | ||
298 | "YUV V" | ||
299 | }; | ||
300 | |||
301 | static const char * const wss_strs[] = { | ||
302 | "invalid", | ||
303 | "letterbox 14:9 center", | ||
304 | "letterbox 14:9 top", | ||
305 | "invalid", | ||
306 | "letterbox 16:9 top", | ||
307 | "invalid", | ||
308 | "invalid", | ||
309 | "16:9 full format anamorphic" | ||
310 | "4:3 full format", | ||
311 | "invalid", | ||
312 | "invalid", | ||
313 | "letterbox 16:9 center", | ||
314 | "invalid", | ||
315 | "letterbox >16:9 center", | ||
316 | "14:9 full format center", | ||
317 | "invalid", | ||
318 | }; | ||
319 | |||
320 | /* ----------------------------------------------------------------------- */ | ||
321 | |||
322 | static int saa7127_read(struct i2c_client *client, u8 reg) | ||
323 | { | ||
324 | return i2c_smbus_read_byte_data(client, reg); | ||
325 | } | ||
326 | |||
327 | /* ----------------------------------------------------------------------- */ | ||
328 | |||
329 | static int saa7127_write(struct i2c_client *client, u8 reg, u8 val) | ||
330 | { | ||
331 | int i; | ||
332 | |||
333 | for (i = 0; i < 3; i++) { | ||
334 | if (i2c_smbus_write_byte_data(client, reg, val) == 0) | ||
335 | return 0; | ||
336 | } | ||
337 | saa7127_err("I2C Write Problem\n"); | ||
338 | return -1; | ||
339 | } | ||
340 | |||
341 | /* ----------------------------------------------------------------------- */ | ||
342 | |||
343 | static int saa7127_write_inittab(struct i2c_client *client, | ||
344 | const struct i2c_reg_value *regs) | ||
345 | { | ||
346 | while (regs->reg != 0) { | ||
347 | saa7127_write(client, regs->reg, regs->value); | ||
348 | regs++; | ||
349 | } | ||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | /* ----------------------------------------------------------------------- */ | ||
354 | |||
355 | static int saa7127_set_vps(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | ||
356 | { | ||
357 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
358 | int enable = (data->line != 0); | ||
359 | |||
360 | if (enable && (data->field != 0 || data->line != 16)) | ||
361 | return -EINVAL; | ||
362 | if (state->vps_enable != enable) { | ||
363 | saa7127_dbg("Turn VPS Signal %s\n", enable ? "on" : "off"); | ||
364 | saa7127_write(client, 0x54, enable << 7); | ||
365 | state->vps_enable = enable; | ||
366 | } | ||
367 | if (!enable) | ||
368 | return 0; | ||
369 | |||
370 | state->vps_data[0] = data->data[4]; | ||
371 | state->vps_data[1] = data->data[10]; | ||
372 | state->vps_data[2] = data->data[11]; | ||
373 | state->vps_data[3] = data->data[12]; | ||
374 | state->vps_data[4] = data->data[13]; | ||
375 | saa7127_dbg("Set VPS data %02x %02x %02x %02x %02x\n", | ||
376 | state->vps_data[0], state->vps_data[1], | ||
377 | state->vps_data[2], state->vps_data[3], | ||
378 | state->vps_data[4]); | ||
379 | saa7127_write(client, 0x55, state->vps_data[0]); | ||
380 | saa7127_write(client, 0x56, state->vps_data[1]); | ||
381 | saa7127_write(client, 0x57, state->vps_data[2]); | ||
382 | saa7127_write(client, 0x58, state->vps_data[3]); | ||
383 | saa7127_write(client, 0x59, state->vps_data[4]); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | /* ----------------------------------------------------------------------- */ | ||
388 | |||
389 | static int saa7127_set_cc(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | ||
390 | { | ||
391 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
392 | u16 cc = data->data[0] << 8 | data->data[1]; | ||
393 | int enable = (data->line != 0); | ||
394 | |||
395 | if (enable && (data->field != 0 || data->line != 21)) | ||
396 | return -EINVAL; | ||
397 | if (state->cc_enable != enable) { | ||
398 | saa7127_dbg("Turn CC %s\n", enable ? "on" : "off"); | ||
399 | saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, | ||
400 | (enable << 6) | 0x11); | ||
401 | state->cc_enable = enable; | ||
402 | } | ||
403 | if (!enable) | ||
404 | return 0; | ||
405 | |||
406 | saa7127_dbg_highvol("CC data: %04x\n", cc); | ||
407 | saa7127_write(client, SAA7127_REG_LINE_21_ODD_0, cc & 0xff); | ||
408 | saa7127_write(client, SAA7127_REG_LINE_21_ODD_1, cc >> 8); | ||
409 | state->cc_data = cc; | ||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | /* ----------------------------------------------------------------------- */ | ||
414 | |||
415 | static int saa7127_set_xds(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | ||
416 | { | ||
417 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
418 | u16 xds = data->data[1] << 8 | data->data[0]; | ||
419 | int enable = (data->line != 0); | ||
420 | |||
421 | if (enable && (data->field != 1 || data->line != 21)) | ||
422 | return -EINVAL; | ||
423 | if (state->xds_enable != enable) { | ||
424 | saa7127_dbg("Turn XDS %s\n", enable ? "on" : "off"); | ||
425 | saa7127_write(client, SAA7127_REG_CLOSED_CAPTION, | ||
426 | (enable << 7) | 0x11); | ||
427 | state->xds_enable = enable; | ||
428 | } | ||
429 | if (!enable) | ||
430 | return 0; | ||
431 | |||
432 | saa7127_dbg_highvol("XDS data: %04x\n", xds); | ||
433 | saa7127_write(client, SAA7127_REG_LINE_21_EVEN_0, xds & 0xff); | ||
434 | saa7127_write(client, SAA7127_REG_LINE_21_EVEN_1, xds >> 8); | ||
435 | state->xds_data = xds; | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | /* ----------------------------------------------------------------------- */ | ||
440 | |||
441 | static int saa7127_set_wss(struct i2c_client *client, struct v4l2_sliced_vbi_data *data) | ||
442 | { | ||
443 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
444 | int enable = (data->line != 0); | ||
445 | |||
446 | if (enable && (data->field != 0 || data->line != 23)) | ||
447 | return -EINVAL; | ||
448 | if (state->wss_enable != enable) { | ||
449 | saa7127_dbg("Turn WSS %s\n", enable ? "on" : "off"); | ||
450 | saa7127_write(client, 0x27, enable << 7); | ||
451 | state->wss_enable = enable; | ||
452 | } | ||
453 | if (!enable) | ||
454 | return 0; | ||
455 | |||
456 | saa7127_write(client, 0x26, data->data[0]); | ||
457 | saa7127_write(client, 0x27, 0x80 | (data->data[1] & 0x3f)); | ||
458 | saa7127_dbg("WSS mode: %s\n", wss_strs[data->data[0] & 0xf]); | ||
459 | state->wss_mode = (data->data[1] & 0x3f) << 8 | data->data[0]; | ||
460 | return 0; | ||
461 | } | ||
462 | |||
463 | /* ----------------------------------------------------------------------- */ | ||
464 | |||
465 | static int saa7127_set_video_enable(struct i2c_client *client, int enable) | ||
466 | { | ||
467 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
468 | |||
469 | if (enable) { | ||
470 | saa7127_dbg("Enable Video Output\n"); | ||
471 | saa7127_write(client, 0x2d, state->reg_2d); | ||
472 | saa7127_write(client, 0x61, state->reg_61); | ||
473 | } else { | ||
474 | saa7127_dbg("Disable Video Output\n"); | ||
475 | saa7127_write(client, 0x2d, (state->reg_2d & 0xf0)); | ||
476 | saa7127_write(client, 0x61, (state->reg_61 | 0xc0)); | ||
477 | } | ||
478 | state->video_enable = enable; | ||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | /* ----------------------------------------------------------------------- */ | ||
483 | |||
484 | static int saa7127_set_std(struct i2c_client *client, v4l2_std_id std) | ||
485 | { | ||
486 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
487 | const struct i2c_reg_value *inittab; | ||
488 | |||
489 | if (std & V4L2_STD_525_60) { | ||
490 | saa7127_dbg("Selecting 60 Hz video Standard\n"); | ||
491 | inittab = saa7127_init_config_60hz; | ||
492 | state->reg_61 = SAA7127_60HZ_DAC_CONTROL; | ||
493 | } else { | ||
494 | saa7127_dbg("Selecting 50 Hz video Standard\n"); | ||
495 | inittab = saa7127_init_config_50hz; | ||
496 | state->reg_61 = SAA7127_50HZ_DAC_CONTROL; | ||
497 | } | ||
498 | |||
499 | /* Write Table */ | ||
500 | saa7127_write_inittab(client, inittab); | ||
501 | state->std = std; | ||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | /* ----------------------------------------------------------------------- */ | ||
506 | |||
507 | static int saa7127_set_output_type(struct i2c_client *client, int output) | ||
508 | { | ||
509 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
510 | |||
511 | switch (output) { | ||
512 | case SAA7127_OUTPUT_TYPE_RGB: | ||
513 | state->reg_2d = 0x0f; /* RGB + CVBS (for sync) */ | ||
514 | state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ | ||
515 | break; | ||
516 | |||
517 | case SAA7127_OUTPUT_TYPE_COMPOSITE: | ||
518 | state->reg_2d = 0x08; /* 00001000 CVBS only, RGB DAC's off (high impedance mode) */ | ||
519 | state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ | ||
520 | break; | ||
521 | |||
522 | case SAA7127_OUTPUT_TYPE_SVIDEO: | ||
523 | state->reg_2d = 0xff; /* 11111111 croma -> R, luma -> CVBS + G + B */ | ||
524 | state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ | ||
525 | break; | ||
526 | |||
527 | case SAA7127_OUTPUT_TYPE_YUV_V: | ||
528 | state->reg_2d = 0x4f; /* reg 2D = 01001111, all DAC's on, RGB + VBS */ | ||
529 | state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */ | ||
530 | break; | ||
531 | |||
532 | case SAA7127_OUTPUT_TYPE_YUV_C: | ||
533 | state->reg_2d = 0x0f; /* reg 2D = 00001111, all DAC's on, RGB + CVBS */ | ||
534 | state->reg_3a = 0x0b; /* reg 3A = 00001011, bypass RGB-matrix */ | ||
535 | break; | ||
536 | |||
537 | case SAA7127_OUTPUT_TYPE_BOTH: | ||
538 | state->reg_2d = 0xbf; | ||
539 | state->reg_3a = 0x13; /* by default switch YUV to RGB-matrix on */ | ||
540 | break; | ||
541 | |||
542 | default: | ||
543 | return -EINVAL; | ||
544 | } | ||
545 | saa7127_dbg("Selecting %s output type\n", output_strs[output]); | ||
546 | |||
547 | /* Configure Encoder */ | ||
548 | saa7127_write(client, 0x2d, state->reg_2d); | ||
549 | saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb); | ||
550 | state->output_type = output; | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | /* ----------------------------------------------------------------------- */ | ||
555 | |||
556 | static int saa7127_set_input_type(struct i2c_client *client, int input) | ||
557 | { | ||
558 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
559 | |||
560 | switch (input) { | ||
561 | case SAA7127_INPUT_TYPE_NORMAL: /* avia */ | ||
562 | saa7127_dbg("Selecting Normal Encoder Input\n"); | ||
563 | state->reg_3a_cb = 0; | ||
564 | break; | ||
565 | |||
566 | case SAA7127_INPUT_TYPE_TEST_IMAGE: /* color bar */ | ||
567 | saa7127_dbg("Selecting Color Bar generator\n"); | ||
568 | state->reg_3a_cb = 0x80; | ||
569 | break; | ||
570 | |||
571 | default: | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | saa7127_write(client, 0x3a, state->reg_3a | state->reg_3a_cb); | ||
575 | state->input_type = input; | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | /* ----------------------------------------------------------------------- */ | ||
580 | |||
581 | static int saa7127_command(struct i2c_client *client, | ||
582 | unsigned int cmd, void *arg) | ||
583 | { | ||
584 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
585 | struct v4l2_format *fmt = arg; | ||
586 | int *iarg = arg; | ||
587 | |||
588 | switch (cmd) { | ||
589 | case VIDIOC_S_STD: | ||
590 | if (state->std == *(v4l2_std_id *)arg) | ||
591 | break; | ||
592 | return saa7127_set_std(client, *(v4l2_std_id *)arg); | ||
593 | |||
594 | case VIDIOC_G_STD: | ||
595 | *(v4l2_std_id *)arg = state->std; | ||
596 | break; | ||
597 | |||
598 | case VIDIOC_S_INPUT: | ||
599 | if (state->input_type == *iarg) | ||
600 | break; | ||
601 | return saa7127_set_input_type(client, *iarg); | ||
602 | |||
603 | case VIDIOC_S_OUTPUT: | ||
604 | if (state->output_type == *iarg) | ||
605 | break; | ||
606 | return saa7127_set_output_type(client, *iarg); | ||
607 | |||
608 | case VIDIOC_STREAMON: | ||
609 | case VIDIOC_STREAMOFF: | ||
610 | if (state->video_enable == (cmd == VIDIOC_STREAMON)) | ||
611 | break; | ||
612 | return saa7127_set_video_enable(client, cmd == VIDIOC_STREAMON); | ||
613 | |||
614 | case VIDIOC_G_FMT: | ||
615 | if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) | ||
616 | return -EINVAL; | ||
617 | |||
618 | memset(&fmt->fmt.sliced, 0, sizeof(fmt->fmt.sliced)); | ||
619 | if (state->vps_enable) | ||
620 | fmt->fmt.sliced.service_lines[0][16] = V4L2_SLICED_VPS; | ||
621 | if (state->wss_enable) | ||
622 | fmt->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625; | ||
623 | if (state->cc_enable) { | ||
624 | fmt->fmt.sliced.service_lines[0][21] = V4L2_SLICED_CAPTION_525; | ||
625 | fmt->fmt.sliced.service_lines[1][21] = V4L2_SLICED_CAPTION_525; | ||
626 | } | ||
627 | fmt->fmt.sliced.service_set = | ||
628 | (state->vps_enable ? V4L2_SLICED_VPS : 0) | | ||
629 | (state->wss_enable ? V4L2_SLICED_WSS_625 : 0) | | ||
630 | (state->cc_enable ? V4L2_SLICED_CAPTION_525 : 0); | ||
631 | break; | ||
632 | |||
633 | case VIDIOC_LOG_STATUS: | ||
634 | saa7127_info("Standard: %s\n", (state->std & V4L2_STD_525_60) ? "60 Hz" : "50 Hz"); | ||
635 | saa7127_info("Input: %s\n", state->input_type ? "color bars" : "normal"); | ||
636 | saa7127_info("Output: %s\n", state->video_enable ? | ||
637 | output_strs[state->output_type] : "disabled"); | ||
638 | saa7127_info("WSS: %s\n", state->wss_enable ? | ||
639 | wss_strs[state->wss_mode] : "disabled"); | ||
640 | saa7127_info("VPS: %s\n", state->vps_enable ? "enabled" : "disabled"); | ||
641 | saa7127_info("CC: %s\n", state->cc_enable ? "enabled" : "disabled"); | ||
642 | break; | ||
643 | |||
644 | #ifdef CONFIG_VIDEO_ADV_DEBUG | ||
645 | case VIDIOC_INT_G_REGISTER: | ||
646 | { | ||
647 | struct v4l2_register *reg = arg; | ||
648 | |||
649 | if (reg->i2c_id != I2C_DRIVERID_SAA7127) | ||
650 | return -EINVAL; | ||
651 | reg->val = saa7127_read(client, reg->reg & 0xff); | ||
652 | break; | ||
653 | } | ||
654 | |||
655 | case VIDIOC_INT_S_REGISTER: | ||
656 | { | ||
657 | struct v4l2_register *reg = arg; | ||
658 | |||
659 | if (reg->i2c_id != I2C_DRIVERID_SAA7127) | ||
660 | return -EINVAL; | ||
661 | if (!capable(CAP_SYS_ADMIN)) | ||
662 | return -EPERM; | ||
663 | saa7127_write(client, reg->reg & 0xff, reg->val & 0xff); | ||
664 | break; | ||
665 | } | ||
666 | #endif | ||
667 | |||
668 | case VIDIOC_INT_S_VBI_DATA: | ||
669 | { | ||
670 | struct v4l2_sliced_vbi_data *data = arg; | ||
671 | |||
672 | switch (data->id) { | ||
673 | case V4L2_SLICED_WSS_625: | ||
674 | return saa7127_set_wss(client, data); | ||
675 | case V4L2_SLICED_VPS: | ||
676 | return saa7127_set_vps(client, data); | ||
677 | case V4L2_SLICED_CAPTION_525: | ||
678 | if (data->field == 0) | ||
679 | return saa7127_set_cc(client, data); | ||
680 | return saa7127_set_xds(client, data); | ||
681 | default: | ||
682 | return -EINVAL; | ||
683 | } | ||
684 | break; | ||
685 | } | ||
686 | |||
687 | case VIDIOC_INT_G_CHIP_IDENT: | ||
688 | *(enum v4l2_chip_ident *)arg = state->ident; | ||
689 | break; | ||
690 | |||
691 | default: | ||
692 | return -EINVAL; | ||
693 | } | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | /* ----------------------------------------------------------------------- */ | ||
698 | |||
699 | struct i2c_driver i2c_driver_saa7127; | ||
700 | |||
701 | /* ----------------------------------------------------------------------- */ | ||
702 | |||
703 | static int saa7127_attach(struct i2c_adapter *adapter, int address, int kind) | ||
704 | { | ||
705 | struct i2c_client *client; | ||
706 | struct saa7127_state *state; | ||
707 | struct v4l2_sliced_vbi_data vbi = { 0, 0, 0, 0 }; /* set to disabled */ | ||
708 | int read_result = 0; | ||
709 | |||
710 | /* Check if the adapter supports the needed features */ | ||
711 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
712 | return 0; | ||
713 | |||
714 | client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); | ||
715 | if (client == 0) | ||
716 | return -ENOMEM; | ||
717 | |||
718 | memset(client, 0, sizeof(struct i2c_client)); | ||
719 | client->addr = address; | ||
720 | client->adapter = adapter; | ||
721 | client->driver = &i2c_driver_saa7127; | ||
722 | client->flags = I2C_CLIENT_ALLOW_USE; | ||
723 | snprintf(client->name, sizeof(client->name) - 1, "saa7127"); | ||
724 | |||
725 | saa7127_dbg("detecting saa7127 client on address 0x%x\n", address << 1); | ||
726 | |||
727 | /* First test register 0: Bits 5-7 are a version ID (should be 0), | ||
728 | and bit 2 should also be 0. | ||
729 | This is rather general, so the second test is more specific and | ||
730 | looks at the 'ending point of burst in clock cycles' which is | ||
731 | 0x1d after a reset and not expected to ever change. */ | ||
732 | if ((saa7127_read(client, 0) & 0xe4) != 0 || | ||
733 | (saa7127_read(client, 0x29) & 0x3f) != 0x1d) { | ||
734 | saa7127_dbg("saa7127 not found\n"); | ||
735 | kfree(client); | ||
736 | return 0; | ||
737 | } | ||
738 | state = kmalloc(sizeof(struct saa7127_state), GFP_KERNEL); | ||
739 | |||
740 | if (state == NULL) { | ||
741 | kfree(client); | ||
742 | return (-ENOMEM); | ||
743 | } | ||
744 | |||
745 | i2c_set_clientdata(client, state); | ||
746 | memset(state, 0, sizeof(struct saa7127_state)); | ||
747 | |||
748 | /* Configure Encoder */ | ||
749 | |||
750 | saa7127_dbg("Configuring encoder\n"); | ||
751 | saa7127_write_inittab(client, saa7127_init_config_common); | ||
752 | saa7127_set_std(client, V4L2_STD_NTSC); | ||
753 | saa7127_set_output_type(client, SAA7127_OUTPUT_TYPE_BOTH); | ||
754 | saa7127_set_vps(client, &vbi); | ||
755 | saa7127_set_wss(client, &vbi); | ||
756 | saa7127_set_cc(client, &vbi); | ||
757 | saa7127_set_xds(client, &vbi); | ||
758 | if (test_image == 1) { | ||
759 | /* The Encoder has an internal Colorbar generator */ | ||
760 | /* This can be used for debugging */ | ||
761 | saa7127_set_input_type(client, SAA7127_INPUT_TYPE_TEST_IMAGE); | ||
762 | } else { | ||
763 | saa7127_set_input_type(client, SAA7127_INPUT_TYPE_NORMAL); | ||
764 | } | ||
765 | saa7127_set_video_enable(client, 1); | ||
766 | |||
767 | /* Detect if it's an saa7129 */ | ||
768 | read_result = saa7127_read(client, SAA7129_REG_FADE_KEY_COL2); | ||
769 | saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, 0xaa); | ||
770 | if (saa7127_read(client, SAA7129_REG_FADE_KEY_COL2) == 0xaa) { | ||
771 | saa7127_info("saa7129 found @ 0x%x (%s)\n", address << 1, adapter->name); | ||
772 | saa7127_write(client, SAA7129_REG_FADE_KEY_COL2, read_result); | ||
773 | saa7127_write_inittab(client, saa7129_init_config_extra); | ||
774 | state->ident = V4L2_IDENT_SAA7129; | ||
775 | } else { | ||
776 | saa7127_info("saa7127 found @ 0x%x (%s)\n", address << 1, adapter->name); | ||
777 | state->ident = V4L2_IDENT_SAA7127; | ||
778 | } | ||
779 | |||
780 | i2c_attach_client(client); | ||
781 | |||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | /* ----------------------------------------------------------------------- */ | ||
786 | |||
787 | static int saa7127_probe(struct i2c_adapter *adapter) | ||
788 | { | ||
789 | #ifdef I2C_CLASS_TV_ANALOG | ||
790 | if (adapter->class & I2C_CLASS_TV_ANALOG) | ||
791 | #else | ||
792 | if (adapter->id == I2C_HW_B_BT848) | ||
793 | #endif | ||
794 | return i2c_probe(adapter, &addr_data, saa7127_attach); | ||
795 | return 0; | ||
796 | } | ||
797 | |||
798 | /* ----------------------------------------------------------------------- */ | ||
799 | |||
800 | static int saa7127_detach(struct i2c_client *client) | ||
801 | { | ||
802 | struct saa7127_state *state = i2c_get_clientdata(client); | ||
803 | int err; | ||
804 | |||
805 | /* Turn off TV output */ | ||
806 | saa7127_set_video_enable(client, 0); | ||
807 | |||
808 | err = i2c_detach_client(client); | ||
809 | |||
810 | if (err) { | ||
811 | return err; | ||
812 | } | ||
813 | |||
814 | kfree(state); | ||
815 | kfree(client); | ||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | /* ----------------------------------------------------------------------- */ | ||
820 | |||
821 | struct i2c_driver i2c_driver_saa7127 = { | ||
822 | .name = "saa7127", | ||
823 | .id = I2C_DRIVERID_SAA7127, | ||
824 | .flags = I2C_DF_NOTIFY, | ||
825 | .attach_adapter = saa7127_probe, | ||
826 | .detach_client = saa7127_detach, | ||
827 | .command = saa7127_command, | ||
828 | .owner = THIS_MODULE, | ||
829 | }; | ||
830 | |||
831 | |||
832 | /* ----------------------------------------------------------------------- */ | ||
833 | |||
834 | static int __init saa7127_init_module(void) | ||
835 | { | ||
836 | return i2c_add_driver(&i2c_driver_saa7127); | ||
837 | } | ||
838 | |||
839 | /* ----------------------------------------------------------------------- */ | ||
840 | |||
841 | static void __exit saa7127_cleanup_module(void) | ||
842 | { | ||
843 | i2c_del_driver(&i2c_driver_saa7127); | ||
844 | } | ||
845 | |||
846 | /* ----------------------------------------------------------------------- */ | ||
847 | |||
848 | module_init(saa7127_init_module); | ||
849 | module_exit(saa7127_cleanup_module); | ||
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig index 624e8808a517..7bdeabe638ca 100644 --- a/drivers/media/video/saa7134/Kconfig +++ b/drivers/media/video/saa7134/Kconfig | |||
@@ -1,10 +1,11 @@ | |||
1 | config VIDEO_SAA7134 | 1 | config VIDEO_SAA7134 |
2 | tristate "Philips SAA7134 support" | 2 | tristate "Philips SAA7134 support" |
3 | depends on VIDEO_DEV && PCI && I2C && SOUND | 3 | depends on VIDEO_DEV && PCI && I2C && SOUND && SND |
4 | select VIDEO_BUF | 4 | select VIDEO_BUF |
5 | select VIDEO_IR | 5 | select VIDEO_IR |
6 | select VIDEO_TUNER | 6 | select VIDEO_TUNER |
7 | select CRC32 | 7 | select CRC32 |
8 | select SND_PCM_OSS | ||
8 | ---help--- | 9 | ---help--- |
9 | This is a video4linux driver for Philips SAA713x based | 10 | This is a video4linux driver for Philips SAA713x based |
10 | TV cards. | 11 | TV cards. |
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile index e0b28f0533af..4226b61cc613 100644 --- a/drivers/media/video/saa7134/Makefile +++ b/drivers/media/video/saa7134/Makefile | |||
@@ -1,10 +1,11 @@ | |||
1 | 1 | ||
2 | saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ | 2 | saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ |
3 | saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \ | 3 | saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \ |
4 | saa7134-vbi.o saa7134-video.o saa7134-input.o | 4 | saa7134-video.o saa7134-input.o |
5 | 5 | ||
6 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ | 6 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o \ |
7 | saa6752hs.o saa7134-alsa.o | 7 | saa6752hs.o saa7134-alsa.o \ |
8 | saa7134-oss.o | ||
8 | obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o | 9 | obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o |
9 | 10 | ||
10 | EXTRA_CFLAGS += -I$(src)/.. | 11 | EXTRA_CFLAGS += -I$(src)/.. |
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 4f3c42354329..5707c666660b 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c | |||
@@ -30,7 +30,9 @@ | |||
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | #include <sound/control.h> | 31 | #include <sound/control.h> |
32 | #include <sound/pcm.h> | 32 | #include <sound/pcm.h> |
33 | #include <sound/pcm_params.h> | ||
33 | #include <sound/initval.h> | 34 | #include <sound/initval.h> |
35 | #include <linux/interrupt.h> | ||
34 | 36 | ||
35 | #include "saa7134.h" | 37 | #include "saa7134.h" |
36 | #include "saa7134-reg.h" | 38 | #include "saa7134-reg.h" |
@@ -56,6 +58,8 @@ static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; | |||
56 | module_param_array(index, int, NULL, 0444); | 58 | module_param_array(index, int, NULL, 0444); |
57 | MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); | 59 | MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)."); |
58 | 60 | ||
61 | int position; | ||
62 | |||
59 | #define dprintk(fmt, arg...) if (debug) \ | 63 | #define dprintk(fmt, arg...) if (debug) \ |
60 | printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg) | 64 | printk(KERN_DEBUG "%s/alsa: " fmt, dev->name , ## arg) |
61 | 65 | ||
@@ -68,7 +72,7 @@ typedef struct snd_card_saa7134 { | |||
68 | int mixer_volume[MIXER_ADDR_LAST+1][2]; | 72 | int mixer_volume[MIXER_ADDR_LAST+1][2]; |
69 | int capture_source[MIXER_ADDR_LAST+1][2]; | 73 | int capture_source[MIXER_ADDR_LAST+1][2]; |
70 | struct pci_dev *pci; | 74 | struct pci_dev *pci; |
71 | struct saa7134_dev *saadev; | 75 | struct saa7134_dev *dev; |
72 | 76 | ||
73 | unsigned long iobase; | 77 | unsigned long iobase; |
74 | int irq; | 78 | int irq; |
@@ -83,12 +87,10 @@ typedef struct snd_card_saa7134 { | |||
83 | */ | 87 | */ |
84 | 88 | ||
85 | typedef struct snd_card_saa7134_pcm { | 89 | typedef struct snd_card_saa7134_pcm { |
86 | struct saa7134_dev *saadev; | 90 | struct saa7134_dev *dev; |
87 | 91 | ||
88 | spinlock_t lock; | 92 | spinlock_t lock; |
89 | unsigned int pcm_size; /* buffer size */ | 93 | |
90 | unsigned int pcm_count; /* bytes per period */ | ||
91 | unsigned int pcm_bps; /* bytes per second */ | ||
92 | snd_pcm_substream_t *substream; | 94 | snd_pcm_substream_t *substream; |
93 | } snd_card_saa7134_pcm_t; | 95 | } snd_card_saa7134_pcm_t; |
94 | 96 | ||
@@ -100,13 +102,11 @@ static snd_card_t *snd_saa7134_cards[SNDRV_CARDS]; | |||
100 | * | 102 | * |
101 | * Called when the capture device is released or the buffer overflows | 103 | * Called when the capture device is released or the buffer overflows |
102 | * | 104 | * |
103 | * - Copied verbatim from saa7134-oss's dsp_dma_stop. Can be dropped | 105 | * - Copied verbatim from saa7134-oss's dsp_dma_stop. |
104 | * if we just share dsp_dma_stop and use it here | ||
105 | * | 106 | * |
106 | */ | 107 | */ |
107 | 108 | ||
108 | static void saa7134_dma_stop(struct saa7134_dev *dev) | 109 | static void saa7134_dma_stop(struct saa7134_dev *dev) |
109 | |||
110 | { | 110 | { |
111 | dev->dmasound.dma_blk = -1; | 111 | dev->dmasound.dma_blk = -1; |
112 | dev->dmasound.dma_running = 0; | 112 | dev->dmasound.dma_running = 0; |
@@ -118,8 +118,7 @@ static void saa7134_dma_stop(struct saa7134_dev *dev) | |||
118 | * | 118 | * |
119 | * Called when preparing the capture device for use | 119 | * Called when preparing the capture device for use |
120 | * | 120 | * |
121 | * - Copied verbatim from saa7134-oss's dsp_dma_start. Can be dropped | 121 | * - Copied verbatim from saa7134-oss's dsp_dma_start. |
122 | * if we just share dsp_dma_start and use it here | ||
123 | * | 122 | * |
124 | */ | 123 | */ |
125 | 124 | ||
@@ -170,9 +169,9 @@ void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status) | |||
170 | if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { | 169 | if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { |
171 | dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, | 170 | dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count, |
172 | dev->dmasound.bufsize, dev->dmasound.blocks); | 171 | dev->dmasound.bufsize, dev->dmasound.blocks); |
172 | spin_unlock(&dev->slock); | ||
173 | snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN); | 173 | snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN); |
174 | saa7134_dma_stop(dev); | 174 | return; |
175 | goto done; | ||
176 | } | 175 | } |
177 | 176 | ||
178 | /* next block addr */ | 177 | /* next block addr */ |
@@ -194,6 +193,7 @@ void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status) | |||
194 | snd_pcm_period_elapsed(dev->dmasound.substream); | 193 | snd_pcm_period_elapsed(dev->dmasound.substream); |
195 | spin_lock(&dev->slock); | 194 | spin_lock(&dev->slock); |
196 | } | 195 | } |
196 | |||
197 | done: | 197 | done: |
198 | spin_unlock(&dev->slock); | 198 | spin_unlock(&dev->slock); |
199 | 199 | ||
@@ -209,7 +209,9 @@ void saa7134_irq_alsa_done(struct saa7134_dev *dev, unsigned long status) | |||
209 | 209 | ||
210 | static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs) | 210 | static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs) |
211 | { | 211 | { |
212 | struct saa7134_dev *dev = (struct saa7134_dev*) dev_id; | 212 | struct saa7134_dmasound *dmasound = dev_id; |
213 | struct saa7134_dev *dev = dmasound->priv_data; | ||
214 | |||
213 | unsigned long report, status; | 215 | unsigned long report, status; |
214 | int loop, handled = 0; | 216 | int loop, handled = 0; |
215 | 217 | ||
@@ -248,56 +250,23 @@ static int snd_card_saa7134_capture_trigger(snd_pcm_substream_t * substream, | |||
248 | int cmd) | 250 | int cmd) |
249 | { | 251 | { |
250 | snd_pcm_runtime_t *runtime = substream->runtime; | 252 | snd_pcm_runtime_t *runtime = substream->runtime; |
251 | snd_card_saa7134_pcm_t *saapcm = runtime->private_data; | 253 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
252 | struct saa7134_dev *dev=saapcm->saadev; | 254 | struct saa7134_dev *dev=pcm->dev; |
253 | int err = 0; | 255 | int err = 0; |
254 | 256 | ||
255 | spin_lock_irq(&dev->slock); | 257 | spin_lock(&dev->slock); |
256 | if (cmd == SNDRV_PCM_TRIGGER_START) { | 258 | if (cmd == SNDRV_PCM_TRIGGER_START) { |
257 | /* start dma */ | 259 | /* start dma */ |
258 | saa7134_dma_start(dev); | 260 | saa7134_dma_start(dev); |
259 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { | 261 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { |
260 | /* stop dma */ | 262 | /* stop dma */ |
261 | saa7134_dma_stop(dev); | 263 | saa7134_dma_stop(dev); |
262 | } else { | 264 | } else { |
263 | err = -EINVAL; | 265 | err = -EINVAL; |
264 | } | 266 | } |
265 | spin_unlock_irq(&dev->slock); | 267 | spin_unlock(&dev->slock); |
266 | |||
267 | return err; | ||
268 | } | ||
269 | |||
270 | /* | ||
271 | * DMA buffer config | ||
272 | * | ||
273 | * Sets the values that will later be used as the size of the buffer, | ||
274 | * size of the fragments, and total number of fragments. | ||
275 | * Must be called during the preparation stage, before memory is | ||
276 | * allocated | ||
277 | * | ||
278 | * - Copied verbatim from saa7134-oss. Can be dropped | ||
279 | * if we just share dsp_buffer_conf from OSS. | ||
280 | */ | ||
281 | 268 | ||
282 | static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) | 269 | return err; |
283 | { | ||
284 | if (blksize < 0x100) | ||
285 | blksize = 0x100; | ||
286 | if (blksize > 0x10000) | ||
287 | blksize = 0x10000; | ||
288 | |||
289 | if (blocks < 2) | ||
290 | blocks = 2; | ||
291 | if ((blksize * blocks) > 1024*1024) | ||
292 | blocks = 1024*1024 / blksize; | ||
293 | |||
294 | dev->dmasound.blocks = blocks; | ||
295 | dev->dmasound.blksize = blksize; | ||
296 | dev->dmasound.bufsize = blksize * blocks; | ||
297 | |||
298 | dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", | ||
299 | blocks,blksize,blksize * blocks / 1024); | ||
300 | return 0; | ||
301 | } | 270 | } |
302 | 271 | ||
303 | /* | 272 | /* |
@@ -307,16 +276,16 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) | |||
307 | * ALSA, but I was unable to use ALSA's own DMA, and had to force the | 276 | * ALSA, but I was unable to use ALSA's own DMA, and had to force the |
308 | * usage of V4L's | 277 | * usage of V4L's |
309 | * | 278 | * |
310 | * - Copied verbatim from saa7134-oss. Can be dropped | 279 | * - Copied verbatim from saa7134-oss. |
311 | * if we just share dsp_buffer_init from OSS. | 280 | * |
312 | */ | 281 | */ |
313 | 282 | ||
314 | static int dsp_buffer_init(struct saa7134_dev *dev) | 283 | static int dsp_buffer_init(struct saa7134_dev *dev) |
315 | { | 284 | { |
316 | int err; | 285 | int err; |
317 | 286 | ||
318 | if (!dev->dmasound.bufsize) | 287 | BUG_ON(!dev->dmasound.bufsize); |
319 | BUG(); | 288 | |
320 | videobuf_dma_init(&dev->dmasound.dma); | 289 | videobuf_dma_init(&dev->dmasound.dma); |
321 | err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, | 290 | err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, |
322 | (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); | 291 | (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); |
@@ -326,6 +295,28 @@ static int dsp_buffer_init(struct saa7134_dev *dev) | |||
326 | } | 295 | } |
327 | 296 | ||
328 | /* | 297 | /* |
298 | * DMA buffer release | ||
299 | * | ||
300 | * Called after closing the device, during snd_card_saa7134_capture_close | ||
301 | * | ||
302 | */ | ||
303 | |||
304 | static int dsp_buffer_free(struct saa7134_dev *dev) | ||
305 | { | ||
306 | if (!dev->dmasound.blksize) | ||
307 | BUG(); | ||
308 | |||
309 | videobuf_dma_free(&dev->dmasound.dma); | ||
310 | |||
311 | dev->dmasound.blocks = 0; | ||
312 | dev->dmasound.blksize = 0; | ||
313 | dev->dmasound.bufsize = 0; | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | |||
319 | /* | ||
329 | * ALSA PCM preparation | 320 | * ALSA PCM preparation |
330 | * | 321 | * |
331 | * - One of the ALSA capture callbacks. | 322 | * - One of the ALSA capture callbacks. |
@@ -340,84 +331,30 @@ static int dsp_buffer_init(struct saa7134_dev *dev) | |||
340 | static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) | 331 | static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) |
341 | { | 332 | { |
342 | snd_pcm_runtime_t *runtime = substream->runtime; | 333 | snd_pcm_runtime_t *runtime = substream->runtime; |
343 | int err, bswap, sign; | 334 | int bswap, sign; |
344 | u32 fmt, control; | 335 | u32 fmt, control; |
345 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); | 336 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
346 | struct saa7134_dev *dev; | 337 | struct saa7134_dev *dev; |
347 | snd_card_saa7134_pcm_t *saapcm = runtime->private_data; | 338 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
348 | unsigned int bps; | ||
349 | unsigned long size; | ||
350 | unsigned count; | ||
351 | |||
352 | size = snd_pcm_lib_buffer_bytes(substream); | ||
353 | count = snd_pcm_lib_period_bytes(substream); | ||
354 | |||
355 | saapcm->saadev->dmasound.substream = substream; | ||
356 | bps = runtime->rate * runtime->channels; | ||
357 | bps *= snd_pcm_format_width(runtime->format); | ||
358 | bps /= 8; | ||
359 | if (bps <= 0) | ||
360 | return -EINVAL; | ||
361 | saapcm->pcm_bps = bps; | ||
362 | saapcm->pcm_size = snd_pcm_lib_buffer_bytes(substream); | ||
363 | saapcm->pcm_count = snd_pcm_lib_period_bytes(substream); | ||
364 | |||
365 | 339 | ||
366 | dev=saa7134->saadev; | 340 | pcm->dev->dmasound.substream = substream; |
367 | 341 | ||
368 | dsp_buffer_conf(dev,saapcm->pcm_count,(saapcm->pcm_size/saapcm->pcm_count)); | 342 | dev = saa7134->dev; |
369 | 343 | ||
370 | err = dsp_buffer_init(dev); | 344 | if (snd_pcm_format_width(runtime->format) == 8) |
371 | if (0 != err) | ||
372 | goto fail2; | ||
373 | |||
374 | /* prepare buffer */ | ||
375 | if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->dmasound.dma))) | ||
376 | return err; | ||
377 | if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) | ||
378 | goto fail1; | ||
379 | if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, | ||
380 | dev->dmasound.dma.sglist, | ||
381 | dev->dmasound.dma.sglen, | ||
382 | 0))) | ||
383 | goto fail2; | ||
384 | |||
385 | |||
386 | |||
387 | switch (runtime->format) { | ||
388 | case SNDRV_PCM_FORMAT_U8: | ||
389 | case SNDRV_PCM_FORMAT_S8: | ||
390 | fmt = 0x00; | 345 | fmt = 0x00; |
391 | break; | 346 | else |
392 | case SNDRV_PCM_FORMAT_U16_LE: | ||
393 | case SNDRV_PCM_FORMAT_U16_BE: | ||
394 | case SNDRV_PCM_FORMAT_S16_LE: | ||
395 | case SNDRV_PCM_FORMAT_S16_BE: | ||
396 | fmt = 0x01; | 347 | fmt = 0x01; |
397 | break; | ||
398 | default: | ||
399 | err = -EINVAL; | ||
400 | return 1; | ||
401 | } | ||
402 | 348 | ||
403 | switch (runtime->format) { | 349 | if (snd_pcm_format_signed(runtime->format)) |
404 | case SNDRV_PCM_FORMAT_S8: | ||
405 | case SNDRV_PCM_FORMAT_S16_LE: | ||
406 | case SNDRV_PCM_FORMAT_S16_BE: | ||
407 | sign = 1; | 350 | sign = 1; |
408 | break; | 351 | else |
409 | default: | ||
410 | sign = 0; | 352 | sign = 0; |
411 | break; | ||
412 | } | ||
413 | 353 | ||
414 | switch (runtime->format) { | 354 | if (snd_pcm_format_big_endian(runtime->format)) |
415 | case SNDRV_PCM_FORMAT_U16_BE: | 355 | bswap = 1; |
416 | case SNDRV_PCM_FORMAT_S16_BE: | 356 | else |
417 | bswap = 1; break; | 357 | bswap = 0; |
418 | default: | ||
419 | bswap = 0; break; | ||
420 | } | ||
421 | 358 | ||
422 | switch (dev->pci->device) { | 359 | switch (dev->pci->device) { |
423 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | 360 | case PCI_DEVICE_ID_PHILIPS_SAA7134: |
@@ -445,7 +382,6 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) | |||
445 | fmt |= 0x04; | 382 | fmt |= 0x04; |
446 | saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1); | 383 | saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1); |
447 | saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); | 384 | saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); |
448 | //saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210); | ||
449 | break; | 385 | break; |
450 | } | 386 | } |
451 | 387 | ||
@@ -459,12 +395,6 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) | |||
459 | if (bswap) | 395 | if (bswap) |
460 | control |= SAA7134_RS_CONTROL_BSWAP; | 396 | control |= SAA7134_RS_CONTROL_BSWAP; |
461 | 397 | ||
462 | /* I should be able to use runtime->dma_addr in the control | ||
463 | byte, but it doesn't work. So I allocate the DMA using the | ||
464 | V4L functions, and force ALSA to use that as the DMA area */ | ||
465 | |||
466 | runtime->dma_area = dev->dmasound.dma.vmalloc; | ||
467 | |||
468 | saa_writel(SAA7134_RS_BA1(6),0); | 398 | saa_writel(SAA7134_RS_BA1(6),0); |
469 | saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); | 399 | saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); |
470 | saa_writel(SAA7134_RS_PITCH(6),0); | 400 | saa_writel(SAA7134_RS_PITCH(6),0); |
@@ -473,12 +403,6 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) | |||
473 | dev->dmasound.rate = runtime->rate; | 403 | dev->dmasound.rate = runtime->rate; |
474 | 404 | ||
475 | return 0; | 405 | return 0; |
476 | fail2: | ||
477 | saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); | ||
478 | fail1: | ||
479 | videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma); | ||
480 | return err; | ||
481 | |||
482 | 406 | ||
483 | } | 407 | } |
484 | 408 | ||
@@ -496,10 +420,8 @@ static int snd_card_saa7134_capture_prepare(snd_pcm_substream_t * substream) | |||
496 | static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream) | 420 | static snd_pcm_uframes_t snd_card_saa7134_capture_pointer(snd_pcm_substream_t * substream) |
497 | { | 421 | { |
498 | snd_pcm_runtime_t *runtime = substream->runtime; | 422 | snd_pcm_runtime_t *runtime = substream->runtime; |
499 | snd_card_saa7134_pcm_t *saapcm = runtime->private_data; | 423 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
500 | struct saa7134_dev *dev=saapcm->saadev; | 424 | struct saa7134_dev *dev=pcm->dev; |
501 | |||
502 | |||
503 | 425 | ||
504 | if (dev->dmasound.read_count) { | 426 | if (dev->dmasound.read_count) { |
505 | dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream); | 427 | dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream); |
@@ -540,9 +462,9 @@ static snd_pcm_hardware_t snd_card_saa7134_capture = | |||
540 | 462 | ||
541 | static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime) | 463 | static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime) |
542 | { | 464 | { |
543 | snd_card_saa7134_pcm_t *saapcm = runtime->private_data; | 465 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
544 | 466 | ||
545 | kfree(saapcm); | 467 | kfree(pcm); |
546 | } | 468 | } |
547 | 469 | ||
548 | 470 | ||
@@ -552,17 +474,76 @@ static void snd_card_saa7134_runtime_free(snd_pcm_runtime_t *runtime) | |||
552 | * - One of the ALSA capture callbacks. | 474 | * - One of the ALSA capture callbacks. |
553 | * | 475 | * |
554 | * Called on initialization, right before the PCM preparation | 476 | * Called on initialization, right before the PCM preparation |
555 | * Usually used in ALSA to allocate the DMA, but since we don't use the | ||
556 | * ALSA DMA it does nothing | ||
557 | * | 477 | * |
558 | */ | 478 | */ |
559 | 479 | ||
560 | static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream, | 480 | static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream, |
561 | snd_pcm_hw_params_t * hw_params) | 481 | snd_pcm_hw_params_t * hw_params) |
562 | { | 482 | { |
483 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); | ||
484 | struct saa7134_dev *dev; | ||
485 | unsigned int period_size, periods; | ||
486 | int err; | ||
563 | 487 | ||
564 | return 0; | 488 | period_size = params_period_bytes(hw_params); |
489 | periods = params_periods(hw_params); | ||
490 | |||
491 | snd_assert(period_size >= 0x100 && period_size <= 0x10000, | ||
492 | return -EINVAL); | ||
493 | snd_assert(periods >= 2, return -EINVAL); | ||
494 | snd_assert(period_size * periods <= 1024 * 1024, return -EINVAL); | ||
565 | 495 | ||
496 | dev = saa7134->dev; | ||
497 | |||
498 | if (dev->dmasound.blocks == periods && | ||
499 | dev->dmasound.blksize == period_size) | ||
500 | return 0; | ||
501 | |||
502 | /* release the old buffer */ | ||
503 | if (substream->runtime->dma_area) { | ||
504 | saa7134_pgtable_free(dev->pci, &dev->dmasound.pt); | ||
505 | videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma); | ||
506 | dsp_buffer_free(dev); | ||
507 | substream->runtime->dma_area = NULL; | ||
508 | } | ||
509 | dev->dmasound.blocks = periods; | ||
510 | dev->dmasound.blksize = period_size; | ||
511 | dev->dmasound.bufsize = period_size * periods; | ||
512 | |||
513 | err = dsp_buffer_init(dev); | ||
514 | if (0 != err) { | ||
515 | dev->dmasound.blocks = 0; | ||
516 | dev->dmasound.blksize = 0; | ||
517 | dev->dmasound.bufsize = 0; | ||
518 | return err; | ||
519 | } | ||
520 | |||
521 | if (0 != (err = videobuf_dma_pci_map(dev->pci, &dev->dmasound.dma))) { | ||
522 | dsp_buffer_free(dev); | ||
523 | return err; | ||
524 | } | ||
525 | if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) { | ||
526 | videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma); | ||
527 | dsp_buffer_free(dev); | ||
528 | return err; | ||
529 | } | ||
530 | if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt, | ||
531 | dev->dmasound.dma.sglist, | ||
532 | dev->dmasound.dma.sglen, | ||
533 | 0))) { | ||
534 | saa7134_pgtable_free(dev->pci, &dev->dmasound.pt); | ||
535 | videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma); | ||
536 | dsp_buffer_free(dev); | ||
537 | return err; | ||
538 | } | ||
539 | |||
540 | /* I should be able to use runtime->dma_addr in the control | ||
541 | byte, but it doesn't work. So I allocate the DMA using the | ||
542 | V4L functions, and force ALSA to use that as the DMA area */ | ||
543 | |||
544 | substream->runtime->dma_area = dev->dmasound.dma.vmalloc; | ||
545 | |||
546 | return 1; | ||
566 | 547 | ||
567 | } | 548 | } |
568 | 549 | ||
@@ -572,33 +553,23 @@ static int snd_card_saa7134_hw_params(snd_pcm_substream_t * substream, | |||
572 | * - One of the ALSA capture callbacks. | 553 | * - One of the ALSA capture callbacks. |
573 | * | 554 | * |
574 | * Called after closing the device, but before snd_card_saa7134_capture_close | 555 | * Called after closing the device, but before snd_card_saa7134_capture_close |
575 | * Usually used in ALSA to free the DMA, but since we don't use the | 556 | * It stops the DMA audio and releases the buffers. |
576 | * ALSA DMA I'm almost sure this isn't necessary. | ||
577 | * | 557 | * |
578 | */ | 558 | */ |
579 | 559 | ||
580 | static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream) | 560 | static int snd_card_saa7134_hw_free(snd_pcm_substream_t * substream) |
581 | { | 561 | { |
582 | return 0; | 562 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
583 | } | 563 | struct saa7134_dev *dev; |
584 | |||
585 | /* | ||
586 | * DMA buffer release | ||
587 | * | ||
588 | * Called after closing the device, during snd_card_saa7134_capture_close | ||
589 | * | ||
590 | */ | ||
591 | |||
592 | static int dsp_buffer_free(struct saa7134_dev *dev) | ||
593 | { | ||
594 | if (!dev->dmasound.blksize) | ||
595 | BUG(); | ||
596 | 564 | ||
597 | videobuf_dma_free(&dev->dmasound.dma); | 565 | dev = saa7134->dev; |
598 | 566 | ||
599 | dev->dmasound.blocks = 0; | 567 | if (substream->runtime->dma_area) { |
600 | dev->dmasound.blksize = 0; | 568 | saa7134_pgtable_free(dev->pci, &dev->dmasound.pt); |
601 | dev->dmasound.bufsize = 0; | 569 | videobuf_dma_pci_unmap(dev->pci, &dev->dmasound.dma); |
570 | dsp_buffer_free(dev); | ||
571 | substream->runtime->dma_area = NULL; | ||
572 | } | ||
602 | 573 | ||
603 | return 0; | 574 | return 0; |
604 | } | 575 | } |
@@ -608,21 +579,12 @@ static int dsp_buffer_free(struct saa7134_dev *dev) | |||
608 | * | 579 | * |
609 | * - One of the ALSA capture callbacks. | 580 | * - One of the ALSA capture callbacks. |
610 | * | 581 | * |
611 | * Called after closing the device. It stops the DMA audio and releases | 582 | * Called after closing the device. |
612 | * the buffers | ||
613 | * | 583 | * |
614 | */ | 584 | */ |
615 | 585 | ||
616 | static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream) | 586 | static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream) |
617 | { | 587 | { |
618 | snd_card_saa7134_t *chip = snd_pcm_substream_chip(substream); | ||
619 | struct saa7134_dev *dev = chip->saadev; | ||
620 | |||
621 | /* unlock buffer */ | ||
622 | saa7134_pgtable_free(dev->pci,&dev->dmasound.pt); | ||
623 | videobuf_dma_pci_unmap(dev->pci,&dev->dmasound.dma); | ||
624 | |||
625 | dsp_buffer_free(dev); | ||
626 | return 0; | 588 | return 0; |
627 | } | 589 | } |
628 | 590 | ||
@@ -639,29 +601,28 @@ static int snd_card_saa7134_capture_close(snd_pcm_substream_t * substream) | |||
639 | static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream) | 601 | static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream) |
640 | { | 602 | { |
641 | snd_pcm_runtime_t *runtime = substream->runtime; | 603 | snd_pcm_runtime_t *runtime = substream->runtime; |
642 | snd_card_saa7134_pcm_t *saapcm; | 604 | snd_card_saa7134_pcm_t *pcm; |
643 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); | 605 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
644 | struct saa7134_dev *dev = saa7134->saadev; | 606 | struct saa7134_dev *dev = saa7134->dev; |
645 | int err; | 607 | int err; |
646 | 608 | ||
647 | down(&dev->dmasound.lock); | 609 | down(&dev->dmasound.lock); |
648 | 610 | ||
649 | dev->dmasound.afmt = SNDRV_PCM_FORMAT_U8; | ||
650 | dev->dmasound.channels = 2; | ||
651 | dev->dmasound.read_count = 0; | 611 | dev->dmasound.read_count = 0; |
652 | dev->dmasound.read_offset = 0; | 612 | dev->dmasound.read_offset = 0; |
653 | 613 | ||
654 | up(&dev->dmasound.lock); | 614 | up(&dev->dmasound.lock); |
655 | 615 | ||
656 | saapcm = kzalloc(sizeof(*saapcm), GFP_KERNEL); | 616 | pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); |
657 | if (saapcm == NULL) | 617 | if (pcm == NULL) |
658 | return -ENOMEM; | 618 | return -ENOMEM; |
659 | saapcm->saadev=saa7134->saadev; | ||
660 | 619 | ||
661 | spin_lock_init(&saapcm->lock); | 620 | pcm->dev=saa7134->dev; |
662 | 621 | ||
663 | saapcm->substream = substream; | 622 | spin_lock_init(&pcm->lock); |
664 | runtime->private_data = saapcm; | 623 | |
624 | pcm->substream = substream; | ||
625 | runtime->private_data = pcm; | ||
665 | runtime->private_free = snd_card_saa7134_runtime_free; | 626 | runtime->private_free = snd_card_saa7134_runtime_free; |
666 | runtime->hw = snd_card_saa7134_capture; | 627 | runtime->hw = snd_card_saa7134_capture; |
667 | 628 | ||
@@ -736,7 +697,6 @@ static int snd_saa7134_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ | |||
736 | static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 697 | static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
737 | { | 698 | { |
738 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); | 699 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
739 | unsigned long flags; | ||
740 | int change, addr = kcontrol->private_value; | 700 | int change, addr = kcontrol->private_value; |
741 | int left, right; | 701 | int left, right; |
742 | 702 | ||
@@ -750,12 +710,12 @@ static int snd_saa7134_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_ | |||
750 | right = 0; | 710 | right = 0; |
751 | if (right > 20) | 711 | if (right > 20) |
752 | right = 20; | 712 | right = 20; |
753 | spin_lock_irqsave(&chip->mixer_lock, flags); | 713 | spin_lock_irq(&chip->mixer_lock); |
754 | change = chip->mixer_volume[addr][0] != left || | 714 | change = chip->mixer_volume[addr][0] != left || |
755 | chip->mixer_volume[addr][1] != right; | 715 | chip->mixer_volume[addr][1] != right; |
756 | chip->mixer_volume[addr][0] = left; | 716 | chip->mixer_volume[addr][0] = left; |
757 | chip->mixer_volume[addr][1] = right; | 717 | chip->mixer_volume[addr][1] = right; |
758 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | 718 | spin_unlock_irq(&chip->mixer_lock); |
759 | return change; | 719 | return change; |
760 | } | 720 | } |
761 | 721 | ||
@@ -777,38 +737,37 @@ static int snd_saa7134_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_ | |||
777 | static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 737 | static int snd_saa7134_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
778 | { | 738 | { |
779 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); | 739 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
780 | unsigned long flags; | ||
781 | int addr = kcontrol->private_value; | 740 | int addr = kcontrol->private_value; |
782 | 741 | ||
783 | spin_lock_irqsave(&chip->mixer_lock, flags); | 742 | spin_lock_irq(&chip->mixer_lock); |
784 | ucontrol->value.integer.value[0] = chip->capture_source[addr][0]; | 743 | ucontrol->value.integer.value[0] = chip->capture_source[addr][0]; |
785 | ucontrol->value.integer.value[1] = chip->capture_source[addr][1]; | 744 | ucontrol->value.integer.value[1] = chip->capture_source[addr][1]; |
786 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | 745 | spin_unlock_irq(&chip->mixer_lock); |
746 | |||
787 | return 0; | 747 | return 0; |
788 | } | 748 | } |
789 | 749 | ||
790 | static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 750 | static int snd_saa7134_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) |
791 | { | 751 | { |
792 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); | 752 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
793 | unsigned long flags; | ||
794 | int change, addr = kcontrol->private_value; | 753 | int change, addr = kcontrol->private_value; |
795 | int left, right; | 754 | int left, right; |
796 | u32 anabar, xbarin; | 755 | u32 anabar, xbarin; |
797 | int analog_io, rate; | 756 | int analog_io, rate; |
798 | struct saa7134_dev *dev; | 757 | struct saa7134_dev *dev; |
799 | 758 | ||
800 | dev = chip->saadev; | 759 | dev = chip->dev; |
801 | 760 | ||
802 | left = ucontrol->value.integer.value[0] & 1; | 761 | left = ucontrol->value.integer.value[0] & 1; |
803 | right = ucontrol->value.integer.value[1] & 1; | 762 | right = ucontrol->value.integer.value[1] & 1; |
804 | spin_lock_irqsave(&chip->mixer_lock, flags); | 763 | spin_lock_irq(&chip->mixer_lock); |
805 | 764 | ||
806 | change = chip->capture_source[addr][0] != left || | 765 | change = chip->capture_source[addr][0] != left || |
807 | chip->capture_source[addr][1] != right; | 766 | chip->capture_source[addr][1] != right; |
808 | chip->capture_source[addr][0] = left; | 767 | chip->capture_source[addr][0] = left; |
809 | chip->capture_source[addr][1] = right; | 768 | chip->capture_source[addr][1] = right; |
810 | dev->dmasound.input=addr; | 769 | dev->dmasound.input=addr; |
811 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | 770 | spin_unlock_irq(&chip->mixer_lock); |
812 | 771 | ||
813 | 772 | ||
814 | if (change) { | 773 | if (change) { |
@@ -898,43 +857,44 @@ static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip) | |||
898 | return 0; | 857 | return 0; |
899 | } | 858 | } |
900 | 859 | ||
901 | static int snd_saa7134_free(snd_card_saa7134_t *chip) | 860 | static void snd_saa7134_free(snd_card_t * card) |
902 | { | 861 | { |
903 | return 0; | 862 | snd_card_saa7134_t *chip = card->private_data; |
904 | } | 863 | |
864 | if (chip->dev->dmasound.priv_data == NULL) | ||
865 | return; | ||
866 | |||
867 | if (chip->irq >= 0) { | ||
868 | synchronize_irq(chip->irq); | ||
869 | free_irq(chip->irq, &chip->dev->dmasound); | ||
870 | } | ||
871 | |||
872 | chip->dev->dmasound.priv_data = NULL; | ||
905 | 873 | ||
906 | static int snd_saa7134_dev_free(snd_device_t *device) | ||
907 | { | ||
908 | snd_card_saa7134_t *chip = device->device_data; | ||
909 | return snd_saa7134_free(chip); | ||
910 | } | 874 | } |
911 | 875 | ||
912 | /* | 876 | /* |
913 | * ALSA initialization | 877 | * ALSA initialization |
914 | * | 878 | * |
915 | * Called by saa7134-core, it creates the basic structures and registers | 879 | * Called by the init routine, once for each saa7134 device present, |
916 | * the ALSA devices | 880 | * it creates the basic structures and registers the ALSA devices |
917 | * | 881 | * |
918 | */ | 882 | */ |
919 | 883 | ||
920 | int alsa_card_saa7134_create (struct saa7134_dev *saadev) | 884 | int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) |
921 | { | 885 | { |
922 | static int dev; | ||
923 | 886 | ||
924 | snd_card_t *card; | 887 | snd_card_t *card; |
925 | snd_card_saa7134_t *chip; | 888 | snd_card_saa7134_t *chip; |
926 | int err; | 889 | int err; |
927 | static snd_device_ops_t ops = { | ||
928 | .dev_free = snd_saa7134_dev_free, | ||
929 | }; | ||
930 | 890 | ||
931 | 891 | ||
932 | if (dev >= SNDRV_CARDS) | 892 | if (devnum >= SNDRV_CARDS) |
933 | return -ENODEV; | 893 | return -ENODEV; |
934 | if (!enable[dev]) | 894 | if (!enable[devnum]) |
935 | return -ENODEV; | 895 | return -ENODEV; |
936 | 896 | ||
937 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); | 897 | card = snd_card_new(index[devnum], id[devnum], THIS_MODULE, sizeof(snd_card_saa7134_t)); |
938 | 898 | ||
939 | if (card == NULL) | 899 | if (card == NULL) |
940 | return -ENOMEM; | 900 | return -ENOMEM; |
@@ -943,34 +903,33 @@ int alsa_card_saa7134_create (struct saa7134_dev *saadev) | |||
943 | 903 | ||
944 | /* Card "creation" */ | 904 | /* Card "creation" */ |
945 | 905 | ||
946 | chip = kcalloc(1, sizeof(*chip), GFP_KERNEL); | 906 | card->private_free = snd_saa7134_free; |
947 | if (chip == NULL) { | 907 | chip = (snd_card_saa7134_t *) card->private_data; |
948 | return -ENOMEM; | ||
949 | } | ||
950 | 908 | ||
951 | spin_lock_init(&chip->lock); | 909 | spin_lock_init(&chip->lock); |
952 | spin_lock_init(&chip->mixer_lock); | 910 | spin_lock_init(&chip->mixer_lock); |
953 | 911 | ||
954 | chip->saadev = saadev; | 912 | chip->dev = dev; |
955 | 913 | ||
956 | chip->card = card; | 914 | chip->card = card; |
957 | 915 | ||
958 | chip->pci = saadev->pci; | 916 | chip->pci = dev->pci; |
959 | chip->irq = saadev->pci->irq; | 917 | chip->iobase = pci_resource_start(dev->pci, 0); |
960 | chip->iobase = pci_resource_start(saadev->pci, 0); | ||
961 | 918 | ||
962 | err = request_irq(saadev->pci->irq, saa7134_alsa_irq, | 919 | |
963 | SA_SHIRQ | SA_INTERRUPT, saadev->name, saadev); | 920 | err = request_irq(dev->pci->irq, saa7134_alsa_irq, |
921 | SA_SHIRQ | SA_INTERRUPT, dev->name, | ||
922 | (void*) &dev->dmasound); | ||
964 | 923 | ||
965 | if (err < 0) { | 924 | if (err < 0) { |
966 | printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n", | 925 | printk(KERN_ERR "%s: can't get IRQ %d for ALSA\n", |
967 | saadev->name, saadev->pci->irq); | 926 | dev->name, dev->pci->irq); |
968 | goto __nodev; | 927 | goto __nodev; |
969 | } | 928 | } |
970 | 929 | ||
971 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 930 | chip->irq = dev->pci->irq; |
972 | goto __nodev; | 931 | |
973 | } | 932 | init_MUTEX(&dev->dmasound.lock); |
974 | 933 | ||
975 | if ((err = snd_card_saa7134_new_mixer(chip)) < 0) | 934 | if ((err = snd_card_saa7134_new_mixer(chip)) < 0) |
976 | goto __nodev; | 935 | goto __nodev; |
@@ -984,16 +943,15 @@ int alsa_card_saa7134_create (struct saa7134_dev *saadev) | |||
984 | 943 | ||
985 | strcpy(card->shortname, "SAA7134"); | 944 | strcpy(card->shortname, "SAA7134"); |
986 | sprintf(card->longname, "%s at 0x%lx irq %d", | 945 | sprintf(card->longname, "%s at 0x%lx irq %d", |
987 | chip->saadev->name, chip->iobase, chip->irq); | 946 | chip->dev->name, chip->iobase, chip->irq); |
988 | 947 | ||
989 | if ((err = snd_card_register(card)) == 0) { | 948 | if ((err = snd_card_register(card)) == 0) { |
990 | snd_saa7134_cards[dev] = card; | 949 | snd_saa7134_cards[devnum] = card; |
991 | return 0; | 950 | return 0; |
992 | } | 951 | } |
993 | 952 | ||
994 | __nodev: | 953 | __nodev: |
995 | snd_card_free(card); | 954 | snd_card_free(card); |
996 | kfree(chip); | ||
997 | return err; | 955 | return err; |
998 | } | 956 | } |
999 | 957 | ||
@@ -1007,21 +965,29 @@ __nodev: | |||
1007 | 965 | ||
1008 | static int saa7134_alsa_init(void) | 966 | static int saa7134_alsa_init(void) |
1009 | { | 967 | { |
1010 | struct saa7134_dev *saadev = NULL; | 968 | struct saa7134_dev *dev = NULL; |
1011 | struct list_head *list; | 969 | struct list_head *list; |
1012 | 970 | ||
1013 | printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); | 971 | position = 0; |
1014 | 972 | ||
1015 | list_for_each(list,&saa7134_devlist) { | 973 | printk(KERN_INFO "saa7134 ALSA driver for DMA sound loaded\n"); |
1016 | saadev = list_entry(list, struct saa7134_dev, devlist); | ||
1017 | alsa_card_saa7134_create(saadev); | ||
1018 | } | ||
1019 | 974 | ||
1020 | if (saadev == NULL) | 975 | list_for_each(list,&saa7134_devlist) { |
976 | dev = list_entry(list, struct saa7134_dev, devlist); | ||
977 | if (dev->dmasound.priv_data == NULL) { | ||
978 | dev->dmasound.priv_data = dev; | ||
979 | alsa_card_saa7134_create(dev,position); | ||
980 | position++; | ||
981 | } else { | ||
982 | printk(KERN_ERR "saa7134 ALSA: DMA sound is being handled by OSS. ignoring %s\n",dev->name); | ||
983 | return -EBUSY; | ||
984 | } | ||
985 | } | ||
986 | |||
987 | if (dev == NULL) | ||
1021 | printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); | 988 | printk(KERN_INFO "saa7134 ALSA: no saa7134 cards found\n"); |
1022 | 989 | ||
1023 | return 0; | 990 | return 0; |
1024 | |||
1025 | } | 991 | } |
1026 | 992 | ||
1027 | /* | 993 | /* |
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 663d03e5bc67..75abc20b0ccd 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -2529,6 +2529,32 @@ struct saa7134_board saa7134_boards[] = { | |||
2529 | .amux = LINE1, | 2529 | .amux = LINE1, |
2530 | }}, | 2530 | }}, |
2531 | }, | 2531 | }, |
2532 | [SAA7134_BOARD_MSI_TVATANYWHERE_PLUS] = { | ||
2533 | .name = "MSI TV@Anywhere plus", | ||
2534 | .audio_clock = 0x00187de7, | ||
2535 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
2536 | .radio_type = UNSET, | ||
2537 | .tuner_addr = ADDR_UNSET, | ||
2538 | .radio_addr = ADDR_UNSET, | ||
2539 | .inputs = {{ | ||
2540 | .name = name_tv, | ||
2541 | .vmux = 1, | ||
2542 | .amux = TV, | ||
2543 | .tv = 1, | ||
2544 | },{ | ||
2545 | .name = name_comp1, | ||
2546 | .vmux = 3, | ||
2547 | .amux = LINE1, | ||
2548 | },{ | ||
2549 | .name = name_svideo, | ||
2550 | .vmux = 0, | ||
2551 | .amux = LINE1, | ||
2552 | }}, | ||
2553 | .radio = { | ||
2554 | .name = name_radio, | ||
2555 | .amux = LINE1, | ||
2556 | }, | ||
2557 | }, | ||
2532 | }; | 2558 | }; |
2533 | 2559 | ||
2534 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); | 2560 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); |
@@ -2970,6 +2996,12 @@ struct pci_device_id saa7134_pci_tbl[] = { | |||
2970 | .subdevice = 0x2018, | 2996 | .subdevice = 0x2018, |
2971 | .driver_data = SAA7134_BOARD_PHILIPS_TIGER, | 2997 | .driver_data = SAA7134_BOARD_PHILIPS_TIGER, |
2972 | },{ | 2998 | },{ |
2999 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
3000 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
3001 | .subvendor = 0x1462, | ||
3002 | .subdevice = 0x6231, | ||
3003 | .driver_data = SAA7134_BOARD_MSI_TVATANYWHERE_PLUS, | ||
3004 | },{ | ||
2973 | /* --- boards without eeprom + subsystem ID --- */ | 3005 | /* --- boards without eeprom + subsystem ID --- */ |
2974 | .vendor = PCI_VENDOR_ID_PHILIPS, | 3006 | .vendor = PCI_VENDOR_ID_PHILIPS, |
2975 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | 3007 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, |
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 19b88744fb31..4275d2ddb864 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -53,13 +53,13 @@ static unsigned int gpio_tracking = 0; | |||
53 | module_param(gpio_tracking, int, 0644); | 53 | module_param(gpio_tracking, int, 0644); |
54 | MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); | 54 | MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); |
55 | 55 | ||
56 | static unsigned int oss = 0; | ||
57 | module_param(oss, int, 0444); | ||
58 | MODULE_PARM_DESC(oss,"register oss devices (default: no)"); | ||
59 | |||
60 | static unsigned int alsa = 0; | 56 | static unsigned int alsa = 0; |
61 | module_param(alsa, int, 0444); | 57 | module_param(alsa, int, 0644); |
62 | MODULE_PARM_DESC(alsa,"register alsa devices (default: no)"); | 58 | MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]"); |
59 | |||
60 | static unsigned int oss = 0; | ||
61 | module_param(oss, int, 0644); | ||
62 | MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]"); | ||
63 | 63 | ||
64 | static unsigned int latency = UNSET; | 64 | static unsigned int latency = UNSET; |
65 | module_param(latency, int, 0444); | 65 | module_param(latency, int, 0444); |
@@ -68,24 +68,18 @@ MODULE_PARM_DESC(latency,"pci latency timer"); | |||
68 | static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | 68 | static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
69 | static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | 69 | static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
70 | static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | 70 | static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
71 | static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
72 | static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
73 | static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | 71 | static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
74 | static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | 72 | static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
75 | 73 | ||
76 | module_param_array(video_nr, int, NULL, 0444); | 74 | module_param_array(video_nr, int, NULL, 0444); |
77 | module_param_array(vbi_nr, int, NULL, 0444); | 75 | module_param_array(vbi_nr, int, NULL, 0444); |
78 | module_param_array(radio_nr, int, NULL, 0444); | 76 | module_param_array(radio_nr, int, NULL, 0444); |
79 | module_param_array(dsp_nr, int, NULL, 0444); | ||
80 | module_param_array(mixer_nr, int, NULL, 0444); | ||
81 | module_param_array(tuner, int, NULL, 0444); | 77 | module_param_array(tuner, int, NULL, 0444); |
82 | module_param_array(card, int, NULL, 0444); | 78 | module_param_array(card, int, NULL, 0444); |
83 | 79 | ||
84 | MODULE_PARM_DESC(video_nr, "video device number"); | 80 | MODULE_PARM_DESC(video_nr, "video device number"); |
85 | MODULE_PARM_DESC(vbi_nr, "vbi device number"); | 81 | MODULE_PARM_DESC(vbi_nr, "vbi device number"); |
86 | MODULE_PARM_DESC(radio_nr, "radio device number"); | 82 | MODULE_PARM_DESC(radio_nr, "radio device number"); |
87 | MODULE_PARM_DESC(dsp_nr, "oss dsp device number"); | ||
88 | MODULE_PARM_DESC(mixer_nr, "oss mixer device number"); | ||
89 | MODULE_PARM_DESC(tuner, "tuner type"); | 83 | MODULE_PARM_DESC(tuner, "tuner type"); |
90 | MODULE_PARM_DESC(card, "card type"); | 84 | MODULE_PARM_DESC(card, "card type"); |
91 | 85 | ||
@@ -195,6 +189,7 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) | |||
195 | static int need_empress; | 189 | static int need_empress; |
196 | static int need_dvb; | 190 | static int need_dvb; |
197 | static int need_alsa; | 191 | static int need_alsa; |
192 | static int need_oss; | ||
198 | 193 | ||
199 | static int pending_call(struct notifier_block *self, unsigned long state, | 194 | static int pending_call(struct notifier_block *self, unsigned long state, |
200 | void *module) | 195 | void *module) |
@@ -208,6 +203,8 @@ static int pending_call(struct notifier_block *self, unsigned long state, | |||
208 | request_module("saa7134-dvb"); | 203 | request_module("saa7134-dvb"); |
209 | if (need_alsa) | 204 | if (need_alsa) |
210 | request_module("saa7134-alsa"); | 205 | request_module("saa7134-alsa"); |
206 | if (need_oss) | ||
207 | request_module("saa7134-oss"); | ||
211 | return NOTIFY_DONE; | 208 | return NOTIFY_DONE; |
212 | } | 209 | } |
213 | 210 | ||
@@ -218,10 +215,11 @@ static struct notifier_block pending_notifier = { | |||
218 | 215 | ||
219 | static void request_module_depend(char *name, int *flag) | 216 | static void request_module_depend(char *name, int *flag) |
220 | { | 217 | { |
218 | int err; | ||
221 | switch (THIS_MODULE->state) { | 219 | switch (THIS_MODULE->state) { |
222 | case MODULE_STATE_COMING: | 220 | case MODULE_STATE_COMING: |
223 | if (!pending_registered) { | 221 | if (!pending_registered) { |
224 | register_module_notifier(&pending_notifier); | 222 | err = register_module_notifier(&pending_notifier); |
225 | pending_registered = 1; | 223 | pending_registered = 1; |
226 | } | 224 | } |
227 | *flag = 1; | 225 | *flag = 1; |
@@ -578,12 +576,14 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) | |||
578 | goto out; | 576 | goto out; |
579 | } | 577 | } |
580 | 578 | ||
581 | /* If alsa support is active and we get a sound report, exit | 579 | /* If dmasound support is active and we get a sound report, exit |
582 | and let the saa7134-alsa module deal with it */ | 580 | and let the saa7134-alsa/oss module deal with it */ |
583 | 581 | ||
584 | if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && alsa) { | 582 | if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && |
583 | (dev->dmasound.priv_data != NULL) ) | ||
584 | { | ||
585 | if (irq_debug > 1) | 585 | if (irq_debug > 1) |
586 | printk(KERN_DEBUG "%s/irq: ignoring interrupt for ALSA\n", | 586 | printk(KERN_DEBUG "%s/irq: ignoring interrupt for DMA sound\n", |
587 | dev->name); | 587 | dev->name); |
588 | goto out; | 588 | goto out; |
589 | } | 589 | } |
@@ -609,12 +609,6 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) | |||
609 | card_has_mpeg(dev)) | 609 | card_has_mpeg(dev)) |
610 | saa7134_irq_ts_done(dev,status); | 610 | saa7134_irq_ts_done(dev,status); |
611 | 611 | ||
612 | if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) { | ||
613 | if (oss) { | ||
614 | saa7134_irq_oss_done(dev,status); | ||
615 | } | ||
616 | } | ||
617 | |||
618 | if ((report & (SAA7134_IRQ_REPORT_GPIO16 | | 612 | if ((report & (SAA7134_IRQ_REPORT_GPIO16 | |
619 | SAA7134_IRQ_REPORT_GPIO18)) && | 613 | SAA7134_IRQ_REPORT_GPIO18)) && |
620 | dev->remote) | 614 | dev->remote) |
@@ -689,14 +683,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) | |||
689 | * audio will not work. | 683 | * audio will not work. |
690 | */ | 684 | */ |
691 | 685 | ||
692 | switch (dev->pci->device) { | ||
693 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
694 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
695 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
696 | saa7134_oss_init1(dev); | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | /* enable peripheral devices */ | 686 | /* enable peripheral devices */ |
701 | saa_writeb(SAA7134_SPECIAL_MODE, 0x01); | 687 | saa_writeb(SAA7134_SPECIAL_MODE, 0x01); |
702 | 688 | ||
@@ -728,8 +714,6 @@ static int saa7134_hwinit2(struct saa7134_dev *dev) | |||
728 | irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | | 714 | irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | |
729 | SAA7134_IRQ2_INTE_GPIO18A | | 715 | SAA7134_IRQ2_INTE_GPIO18A | |
730 | SAA7134_IRQ2_INTE_GPIO16 ); | 716 | SAA7134_IRQ2_INTE_GPIO16 ); |
731 | else if (dev->has_remote == SAA7134_REMOTE_I2C) | ||
732 | request_module("ir-kbd-i2c"); | ||
733 | 717 | ||
734 | saa_writel(SAA7134_IRQ1, 0); | 718 | saa_writel(SAA7134_IRQ1, 0); |
735 | saa_writel(SAA7134_IRQ2, irq2_mask); | 719 | saa_writel(SAA7134_IRQ2, irq2_mask); |
@@ -742,13 +726,6 @@ static int saa7134_hwfini(struct saa7134_dev *dev) | |||
742 | { | 726 | { |
743 | dprintk("hwfini\n"); | 727 | dprintk("hwfini\n"); |
744 | 728 | ||
745 | switch (dev->pci->device) { | ||
746 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
747 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
748 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
749 | saa7134_oss_fini(dev); | ||
750 | break; | ||
751 | } | ||
752 | if (card_has_mpeg(dev)) | 729 | if (card_has_mpeg(dev)) |
753 | saa7134_ts_fini(dev); | 730 | saa7134_ts_fini(dev); |
754 | saa7134_input_fini(dev); | 731 | saa7134_input_fini(dev); |
@@ -986,11 +963,12 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
986 | if (card_is_dvb(dev)) | 963 | if (card_is_dvb(dev)) |
987 | request_module_depend("saa7134-dvb",&need_dvb); | 964 | request_module_depend("saa7134-dvb",&need_dvb); |
988 | 965 | ||
989 | if (!oss && alsa) { | 966 | |
990 | dprintk("Requesting ALSA module\n"); | 967 | if (alsa) |
991 | request_module_depend("saa7134-alsa",&need_alsa); | 968 | request_module_depend("saa7134-alsa",&need_alsa); |
992 | } | ||
993 | 969 | ||
970 | if (oss) | ||
971 | request_module_depend("saa7134-oss",&need_oss); | ||
994 | 972 | ||
995 | v4l2_prio_init(&dev->prio); | 973 | v4l2_prio_init(&dev->prio); |
996 | 974 | ||
@@ -1024,32 +1002,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1024 | dev->name,dev->radio_dev->minor & 0x1f); | 1002 | dev->name,dev->radio_dev->minor & 0x1f); |
1025 | } | 1003 | } |
1026 | 1004 | ||
1027 | /* register oss devices */ | ||
1028 | switch (dev->pci->device) { | ||
1029 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
1030 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
1031 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
1032 | if (oss) { | ||
1033 | err = dev->dmasound.minor_dsp = | ||
1034 | register_sound_dsp(&saa7134_dsp_fops, | ||
1035 | dsp_nr[dev->nr]); | ||
1036 | if (err < 0) { | ||
1037 | goto fail4; | ||
1038 | } | ||
1039 | printk(KERN_INFO "%s: registered device dsp%d\n", | ||
1040 | dev->name,dev->dmasound.minor_dsp >> 4); | ||
1041 | |||
1042 | err = dev->dmasound.minor_mixer = | ||
1043 | register_sound_mixer(&saa7134_mixer_fops, | ||
1044 | mixer_nr[dev->nr]); | ||
1045 | if (err < 0) | ||
1046 | goto fail5; | ||
1047 | printk(KERN_INFO "%s: registered device mixer%d\n", | ||
1048 | dev->name,dev->dmasound.minor_mixer >> 4); | ||
1049 | } | ||
1050 | break; | ||
1051 | } | ||
1052 | |||
1053 | /* everything worked */ | 1005 | /* everything worked */ |
1054 | pci_set_drvdata(pci_dev,dev); | 1006 | pci_set_drvdata(pci_dev,dev); |
1055 | saa7134_devcount++; | 1007 | saa7134_devcount++; |
@@ -1064,17 +1016,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | |||
1064 | 1016 | ||
1065 | /* check for signal */ | 1017 | /* check for signal */ |
1066 | saa7134_irq_video_intl(dev); | 1018 | saa7134_irq_video_intl(dev); |
1019 | |||
1067 | return 0; | 1020 | return 0; |
1068 | 1021 | ||
1069 | fail5: | ||
1070 | switch (dev->pci->device) { | ||
1071 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
1072 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
1073 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
1074 | if (oss) | ||
1075 | unregister_sound_dsp(dev->dmasound.minor_dsp); | ||
1076 | break; | ||
1077 | } | ||
1078 | fail4: | 1022 | fail4: |
1079 | saa7134_unregister_video(dev); | 1023 | saa7134_unregister_video(dev); |
1080 | saa7134_i2c_unregister(dev); | 1024 | saa7134_i2c_unregister(dev); |
@@ -1125,19 +1069,16 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) | |||
1125 | saa7134_devcount--; | 1069 | saa7134_devcount--; |
1126 | 1070 | ||
1127 | saa7134_i2c_unregister(dev); | 1071 | saa7134_i2c_unregister(dev); |
1128 | switch (dev->pci->device) { | ||
1129 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
1130 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
1131 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
1132 | if (oss) { | ||
1133 | unregister_sound_mixer(dev->dmasound.minor_mixer); | ||
1134 | unregister_sound_dsp(dev->dmasound.minor_dsp); | ||
1135 | } | ||
1136 | break; | ||
1137 | } | ||
1138 | saa7134_unregister_video(dev); | 1072 | saa7134_unregister_video(dev); |
1139 | 1073 | ||
1140 | /* release ressources */ | 1074 | /* the DMA sound modules should be unloaded before reaching |
1075 | this, but just in case they are still present... */ | ||
1076 | if (dev->dmasound.priv_data != NULL) { | ||
1077 | free_irq(pci_dev->irq, &dev->dmasound); | ||
1078 | dev->dmasound.priv_data = NULL; | ||
1079 | } | ||
1080 | |||
1081 | /* release resources */ | ||
1141 | free_irq(pci_dev->irq, dev); | 1082 | free_irq(pci_dev->irq, dev); |
1142 | iounmap(dev->lmmio); | 1083 | iounmap(dev->lmmio); |
1143 | release_mem_region(pci_resource_start(pci_dev,0), | 1084 | release_mem_region(pci_resource_start(pci_dev,0), |
@@ -1225,7 +1166,7 @@ EXPORT_SYMBOL(saa7134_i2c_call_clients); | |||
1225 | EXPORT_SYMBOL(saa7134_devlist); | 1166 | EXPORT_SYMBOL(saa7134_devlist); |
1226 | EXPORT_SYMBOL(saa7134_boards); | 1167 | EXPORT_SYMBOL(saa7134_boards); |
1227 | 1168 | ||
1228 | /* ----------------- For ALSA -------------------------------- */ | 1169 | /* ----------------- for the DMA sound modules --------------- */ |
1229 | 1170 | ||
1230 | EXPORT_SYMBOL(saa7134_pgtable_free); | 1171 | EXPORT_SYMBOL(saa7134_pgtable_free); |
1231 | EXPORT_SYMBOL(saa7134_pgtable_build); | 1172 | EXPORT_SYMBOL(saa7134_pgtable_build); |
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 329accda6d45..e648cc3bc96d 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -485,64 +485,6 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { | |||
485 | 485 | ||
486 | }; | 486 | }; |
487 | 487 | ||
488 | static IR_KEYTAB_TYPE ir_codes_pinnacle[IR_KEYTAB_SIZE] = { | ||
489 | [ 0x59 ] = KEY_MUTE, | ||
490 | [ 0x4a ] = KEY_POWER, | ||
491 | |||
492 | [ 0x18 ] = KEY_TEXT, | ||
493 | [ 0x26 ] = KEY_TV, | ||
494 | [ 0x3d ] = KEY_PRINT, | ||
495 | |||
496 | [ 0x48 ] = KEY_RED, | ||
497 | [ 0x04 ] = KEY_GREEN, | ||
498 | [ 0x11 ] = KEY_YELLOW, | ||
499 | [ 0x00 ] = KEY_BLUE, | ||
500 | |||
501 | [ 0x2d ] = KEY_VOLUMEUP, | ||
502 | [ 0x1e ] = KEY_VOLUMEDOWN, | ||
503 | |||
504 | [ 0x49 ] = KEY_MENU, | ||
505 | |||
506 | [ 0x16 ] = KEY_CHANNELUP, | ||
507 | [ 0x17 ] = KEY_CHANNELDOWN, | ||
508 | |||
509 | [ 0x20 ] = KEY_UP, | ||
510 | [ 0x21 ] = KEY_DOWN, | ||
511 | [ 0x22 ] = KEY_LEFT, | ||
512 | [ 0x23 ] = KEY_RIGHT, | ||
513 | [ 0x0d ] = KEY_SELECT, | ||
514 | |||
515 | |||
516 | |||
517 | [ 0x08 ] = KEY_BACK, | ||
518 | [ 0x07 ] = KEY_REFRESH, | ||
519 | |||
520 | [ 0x2f ] = KEY_ZOOM, | ||
521 | [ 0x29 ] = KEY_RECORD, | ||
522 | |||
523 | [ 0x4b ] = KEY_PAUSE, | ||
524 | [ 0x4d ] = KEY_REWIND, | ||
525 | [ 0x2e ] = KEY_PLAY, | ||
526 | [ 0x4e ] = KEY_FORWARD, | ||
527 | [ 0x53 ] = KEY_PREVIOUS, | ||
528 | [ 0x4c ] = KEY_STOP, | ||
529 | [ 0x54 ] = KEY_NEXT, | ||
530 | |||
531 | [ 0x69 ] = KEY_KP0, | ||
532 | [ 0x6a ] = KEY_KP1, | ||
533 | [ 0x6b ] = KEY_KP2, | ||
534 | [ 0x6c ] = KEY_KP3, | ||
535 | [ 0x6d ] = KEY_KP4, | ||
536 | [ 0x6e ] = KEY_KP5, | ||
537 | [ 0x6f ] = KEY_KP6, | ||
538 | [ 0x70 ] = KEY_KP7, | ||
539 | [ 0x71 ] = KEY_KP8, | ||
540 | [ 0x72 ] = KEY_KP9, | ||
541 | |||
542 | [ 0x74 ] = KEY_CHANNEL, | ||
543 | [ 0x0a ] = KEY_BACKSPACE, | ||
544 | }; | ||
545 | |||
546 | /* Mapping for the 28 key remote control as seen at | 488 | /* Mapping for the 28 key remote control as seen at |
547 | http://www.sednacomputer.com/photo/cardbus-tv.jpg | 489 | http://www.sednacomputer.com/photo/cardbus-tv.jpg |
548 | Pavel Mihaylov <bin@bash.info> */ | 490 | Pavel Mihaylov <bin@bash.info> */ |
@@ -635,57 +577,6 @@ static int get_key_purpletv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | |||
635 | return 1; | 577 | return 1; |
636 | } | 578 | } |
637 | 579 | ||
638 | /* The new pinnacle PCTV remote (with the colored buttons) | ||
639 | * | ||
640 | * Ricardo Cerqueira <v4l@cerqueira.org> | ||
641 | */ | ||
642 | |||
643 | static int get_key_pinnacle(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) | ||
644 | { | ||
645 | unsigned char b[4]; | ||
646 | unsigned int start = 0,parity = 0,code = 0; | ||
647 | |||
648 | /* poll IR chip */ | ||
649 | if (4 != i2c_master_recv(&ir->c,b,4)) { | ||
650 | i2cdprintk("read error\n"); | ||
651 | return -EIO; | ||
652 | } | ||
653 | |||
654 | for (start = 0; start<4; start++) { | ||
655 | if (b[start] == 0x80) { | ||
656 | code=b[(start+3)%4]; | ||
657 | parity=b[(start+2)%4]; | ||
658 | } | ||
659 | } | ||
660 | |||
661 | /* Empty Request */ | ||
662 | if (parity==0) | ||
663 | return 0; | ||
664 | |||
665 | /* Repeating... */ | ||
666 | if (ir->old == parity) | ||
667 | return 0; | ||
668 | |||
669 | |||
670 | ir->old = parity; | ||
671 | |||
672 | /* Reduce code value to fit inside IR_KEYTAB_SIZE | ||
673 | * | ||
674 | * this is the only value that results in 42 unique | ||
675 | * codes < 128 | ||
676 | */ | ||
677 | |||
678 | code %= 0x88; | ||
679 | |||
680 | *ir_raw = code; | ||
681 | *ir_key = code; | ||
682 | |||
683 | i2cdprintk("Pinnacle PCTV key %02x\n", code); | ||
684 | |||
685 | return 1; | ||
686 | } | ||
687 | |||
688 | |||
689 | void saa7134_input_irq(struct saa7134_dev *dev) | 580 | void saa7134_input_irq(struct saa7134_dev *dev) |
690 | { | 581 | { |
691 | struct saa7134_ir *ir = dev->remote; | 582 | struct saa7134_ir *ir = dev->remote; |
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index fd53dfcc1644..fd9ed11ab1e2 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * oss dsp interface | 4 | * oss dsp interface |
5 | * | 5 | * |
6 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | 6 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] |
7 | * 2005 conversion to standalone module: | ||
8 | * Ricardo Cerqueira <v4l@cerqueira.org> | ||
7 | * | 9 | * |
8 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -25,7 +27,9 @@ | |||
25 | #include <linux/module.h> | 27 | #include <linux/module.h> |
26 | #include <linux/moduleparam.h> | 28 | #include <linux/moduleparam.h> |
27 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/interrupt.h> | ||
28 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/sound.h> | ||
29 | #include <linux/soundcard.h> | 33 | #include <linux/soundcard.h> |
30 | 34 | ||
31 | #include "saa7134-reg.h" | 35 | #include "saa7134-reg.h" |
@@ -33,15 +37,23 @@ | |||
33 | 37 | ||
34 | /* ------------------------------------------------------------------ */ | 38 | /* ------------------------------------------------------------------ */ |
35 | 39 | ||
36 | static unsigned int oss_debug = 0; | 40 | static unsigned int debug = 0; |
37 | module_param(oss_debug, int, 0644); | 41 | module_param(debug, int, 0644); |
38 | MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]"); | 42 | MODULE_PARM_DESC(debug,"enable debug messages [oss]"); |
39 | 43 | ||
40 | static unsigned int oss_rate = 0; | 44 | static unsigned int rate = 0; |
41 | module_param(oss_rate, int, 0444); | 45 | module_param(rate, int, 0444); |
42 | MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)"); | 46 | MODULE_PARM_DESC(rate,"sample rate (valid are: 32000,48000)"); |
43 | 47 | ||
44 | #define dprintk(fmt, arg...) if (oss_debug) \ | 48 | static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
49 | MODULE_PARM_DESC(dsp_nr, "device numbers for SAA7134 capture interface(s)."); | ||
50 | module_param_array(dsp_nr, int, NULL, 0444); | ||
51 | |||
52 | static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
53 | MODULE_PARM_DESC(mixer_nr, "mixer numbers for SAA7134 capture interface(s)."); | ||
54 | module_param_array(mixer_nr, int, NULL, 0444); | ||
55 | |||
56 | #define dprintk(fmt, arg...) if (debug) \ | ||
45 | printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) | 57 | printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) |
46 | 58 | ||
47 | 59 | ||
@@ -369,7 +381,7 @@ static int dsp_ioctl(struct inode *inode, struct file *file, | |||
369 | int __user *p = argp; | 381 | int __user *p = argp; |
370 | int val = 0; | 382 | int val = 0; |
371 | 383 | ||
372 | if (oss_debug > 1) | 384 | if (debug > 1) |
373 | saa7134_print_ioctl(dev->name,cmd); | 385 | saa7134_print_ioctl(dev->name,cmd); |
374 | switch (cmd) { | 386 | switch (cmd) { |
375 | case OSS_GETVERSION: | 387 | case OSS_GETVERSION: |
@@ -665,7 +677,7 @@ static int mixer_ioctl(struct inode *inode, struct file *file, | |||
665 | void __user *argp = (void __user *) arg; | 677 | void __user *argp = (void __user *) arg; |
666 | int __user *p = argp; | 678 | int __user *p = argp; |
667 | 679 | ||
668 | if (oss_debug > 1) | 680 | if (debug > 1) |
669 | saa7134_print_ioctl(dev->name,cmd); | 681 | saa7134_print_ioctl(dev->name,cmd); |
670 | switch (cmd) { | 682 | switch (cmd) { |
671 | case OSS_GETVERSION: | 683 | case OSS_GETVERSION: |
@@ -768,8 +780,41 @@ struct file_operations saa7134_mixer_fops = { | |||
768 | 780 | ||
769 | /* ------------------------------------------------------------------ */ | 781 | /* ------------------------------------------------------------------ */ |
770 | 782 | ||
783 | static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
784 | { | ||
785 | struct saa7134_dmasound *dmasound = dev_id; | ||
786 | struct saa7134_dev *dev = dmasound->priv_data; | ||
787 | unsigned long report, status; | ||
788 | int loop, handled = 0; | ||
789 | |||
790 | for (loop = 0; loop < 10; loop++) { | ||
791 | report = saa_readl(SAA7134_IRQ_REPORT); | ||
792 | status = saa_readl(SAA7134_IRQ_STATUS); | ||
793 | |||
794 | if (report & SAA7134_IRQ_REPORT_DONE_RA3) { | ||
795 | handled = 1; | ||
796 | saa_writel(SAA7134_IRQ_REPORT,report); | ||
797 | saa7134_irq_oss_done(dev, status); | ||
798 | } else { | ||
799 | goto out; | ||
800 | } | ||
801 | } | ||
802 | |||
803 | if (loop == 10) { | ||
804 | dprintk("error! looping IRQ!"); | ||
805 | } | ||
806 | out: | ||
807 | return IRQ_RETVAL(handled); | ||
808 | } | ||
809 | |||
771 | int saa7134_oss_init1(struct saa7134_dev *dev) | 810 | int saa7134_oss_init1(struct saa7134_dev *dev) |
772 | { | 811 | { |
812 | |||
813 | if ((request_irq(dev->pci->irq, saa7134_oss_irq, | ||
814 | SA_SHIRQ | SA_INTERRUPT, dev->name, | ||
815 | (void*) &dev->dmasound)) < 0) | ||
816 | return -1; | ||
817 | |||
773 | /* general */ | 818 | /* general */ |
774 | init_MUTEX(&dev->dmasound.lock); | 819 | init_MUTEX(&dev->dmasound.lock); |
775 | init_waitqueue_head(&dev->dmasound.wq); | 820 | init_waitqueue_head(&dev->dmasound.wq); |
@@ -785,8 +830,8 @@ int saa7134_oss_init1(struct saa7134_dev *dev) | |||
785 | 830 | ||
786 | /* dsp */ | 831 | /* dsp */ |
787 | dev->dmasound.rate = 32000; | 832 | dev->dmasound.rate = 32000; |
788 | if (oss_rate) | 833 | if (rate) |
789 | dev->dmasound.rate = oss_rate; | 834 | dev->dmasound.rate = rate; |
790 | dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000; | 835 | dev->dmasound.rate = (dev->dmasound.rate > 40000) ? 48000 : 32000; |
791 | 836 | ||
792 | /* mixer */ | 837 | /* mixer */ |
@@ -840,7 +885,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) | |||
840 | /* next block addr */ | 885 | /* next block addr */ |
841 | next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; | 886 | next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; |
842 | saa_writel(reg,next_blk * dev->dmasound.blksize); | 887 | saa_writel(reg,next_blk * dev->dmasound.blksize); |
843 | if (oss_debug > 2) | 888 | if (debug > 2) |
844 | dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", | 889 | dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", |
845 | (status & 0x10000000) ? "even" : "odd ", next_blk, | 890 | (status & 0x10000000) ? "even" : "odd ", next_blk, |
846 | next_blk * dev->dmasound.blksize); | 891 | next_blk * dev->dmasound.blksize); |
@@ -854,6 +899,98 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) | |||
854 | spin_unlock(&dev->slock); | 899 | spin_unlock(&dev->slock); |
855 | } | 900 | } |
856 | 901 | ||
902 | int saa7134_dsp_create(struct saa7134_dev *dev) | ||
903 | { | ||
904 | int err; | ||
905 | |||
906 | err = dev->dmasound.minor_dsp = | ||
907 | register_sound_dsp(&saa7134_dsp_fops, | ||
908 | dsp_nr[dev->nr]); | ||
909 | if (err < 0) { | ||
910 | goto fail; | ||
911 | } | ||
912 | printk(KERN_INFO "%s: registered device dsp%d\n", | ||
913 | dev->name,dev->dmasound.minor_dsp >> 4); | ||
914 | |||
915 | err = dev->dmasound.minor_mixer = | ||
916 | register_sound_mixer(&saa7134_mixer_fops, | ||
917 | mixer_nr[dev->nr]); | ||
918 | if (err < 0) | ||
919 | goto fail; | ||
920 | printk(KERN_INFO "%s: registered device mixer%d\n", | ||
921 | dev->name,dev->dmasound.minor_mixer >> 4); | ||
922 | |||
923 | return 0; | ||
924 | |||
925 | fail: | ||
926 | unregister_sound_dsp(dev->dmasound.minor_dsp); | ||
927 | return 0; | ||
928 | |||
929 | |||
930 | } | ||
931 | |||
932 | static int saa7134_oss_init(void) | ||
933 | { | ||
934 | struct saa7134_dev *dev = NULL; | ||
935 | struct list_head *list; | ||
936 | |||
937 | printk(KERN_INFO "saa7134 OSS driver for DMA sound loaded\n"); | ||
938 | |||
939 | list_for_each(list,&saa7134_devlist) { | ||
940 | dev = list_entry(list, struct saa7134_dev, devlist); | ||
941 | if (dev->dmasound.priv_data == NULL) { | ||
942 | dev->dmasound.priv_data = dev; | ||
943 | saa7134_oss_init1(dev); | ||
944 | saa7134_dsp_create(dev); | ||
945 | } else { | ||
946 | printk(KERN_ERR "saa7134 OSS: DMA sound is being handled by ALSA, ignoring %s\n",dev->name); | ||
947 | return -EBUSY; | ||
948 | } | ||
949 | } | ||
950 | |||
951 | if (dev == NULL) | ||
952 | printk(KERN_INFO "saa7134 OSS: no saa7134 cards found\n"); | ||
953 | |||
954 | return 0; | ||
955 | |||
956 | } | ||
957 | |||
958 | void saa7134_oss_exit(void) | ||
959 | { | ||
960 | struct saa7134_dev *dev = NULL; | ||
961 | struct list_head *list; | ||
962 | |||
963 | list_for_each(list,&saa7134_devlist) { | ||
964 | dev = list_entry(list, struct saa7134_dev, devlist); | ||
965 | |||
966 | /* Device isn't registered by OSS, probably ALSA's */ | ||
967 | if (!dev->dmasound.minor_dsp) | ||
968 | continue; | ||
969 | |||
970 | unregister_sound_mixer(dev->dmasound.minor_mixer); | ||
971 | unregister_sound_dsp(dev->dmasound.minor_dsp); | ||
972 | |||
973 | saa7134_oss_fini(dev); | ||
974 | |||
975 | if (dev->pci->irq > 0) { | ||
976 | synchronize_irq(dev->pci->irq); | ||
977 | free_irq(dev->pci->irq,&dev->dmasound); | ||
978 | } | ||
979 | |||
980 | dev->dmasound.priv_data = NULL; | ||
981 | |||
982 | } | ||
983 | |||
984 | printk(KERN_INFO "saa7134 OSS driver for DMA sound unloaded\n"); | ||
985 | |||
986 | return; | ||
987 | } | ||
988 | |||
989 | module_init(saa7134_oss_init); | ||
990 | module_exit(saa7134_oss_exit); | ||
991 | MODULE_LICENSE("GPL"); | ||
992 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
993 | |||
857 | /* ----------------------------------------------------------- */ | 994 | /* ----------------------------------------------------------- */ |
858 | /* | 995 | /* |
859 | * Local variables: | 996 | * Local variables: |
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index fb9727471661..244e1973081c 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -208,6 +208,7 @@ struct saa7134_format { | |||
208 | #define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79 | 208 | #define SAA7134_BOARD_SEDNA_PC_TV_CARDBUS 79 |
209 | #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80 | 209 | #define SAA7134_BOARD_ASUSTEK_DIGIMATRIX_TV 80 |
210 | #define SAA7134_BOARD_PHILIPS_TIGER 81 | 210 | #define SAA7134_BOARD_PHILIPS_TIGER 81 |
211 | #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82 | ||
211 | 212 | ||
212 | #define SAA7134_MAXBOARDS 8 | 213 | #define SAA7134_MAXBOARDS 8 |
213 | #define SAA7134_INPUT_MAX 8 | 214 | #define SAA7134_INPUT_MAX 8 |
@@ -383,6 +384,7 @@ struct saa7134_dmasound { | |||
383 | unsigned int dma_blk; | 384 | unsigned int dma_blk; |
384 | unsigned int read_offset; | 385 | unsigned int read_offset; |
385 | unsigned int read_count; | 386 | unsigned int read_count; |
387 | void * priv_data; | ||
386 | snd_pcm_substream_t *substream; | 388 | snd_pcm_substream_t *substream; |
387 | }; | 389 | }; |
388 | 390 | ||
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index b2dfe07e9f9d..61d94ddaff41 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c | |||
@@ -437,6 +437,10 @@ static void set_audio(struct tuner *t) | |||
437 | t->sgIF = 124; | 437 | t->sgIF = 124; |
438 | t->tda8290_easy_mode = 0x20; | 438 | t->tda8290_easy_mode = 0x20; |
439 | mode = "L"; | 439 | mode = "L"; |
440 | } else if (t->std & V4L2_STD_SECAM_LC) { | ||
441 | t->sgIF = 20; | ||
442 | t->tda8290_easy_mode = 0x40; | ||
443 | mode = "LC"; | ||
440 | } | 444 | } |
441 | tuner_dbg("setting tda8290 to system %s\n", mode); | 445 | tuner_dbg("setting tda8290 to system %s\n", mode); |
442 | } | 446 | } |
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index 73c4041c35d7..e58abdfcaab8 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c | |||
@@ -251,7 +251,7 @@ static inline int check_mode(struct tuner *t, char *cmd) | |||
251 | 251 | ||
252 | static char pal[] = "-"; | 252 | static char pal[] = "-"; |
253 | module_param_string(pal, pal, sizeof(pal), 0644); | 253 | module_param_string(pal, pal, sizeof(pal), 0644); |
254 | static char secam[] = "-"; | 254 | static char secam[] = "--"; |
255 | module_param_string(secam, secam, sizeof(secam), 0644); | 255 | module_param_string(secam, secam, sizeof(secam), 0644); |
256 | 256 | ||
257 | /* get more precise norm info from insmod option */ | 257 | /* get more precise norm info from insmod option */ |
@@ -307,8 +307,13 @@ static int tuner_fixup_std(struct tuner *t) | |||
307 | break; | 307 | break; |
308 | case 'l': | 308 | case 'l': |
309 | case 'L': | 309 | case 'L': |
310 | tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); | 310 | if ((secam[1]=='C')||(secam[1]=='c')) { |
311 | t->std = V4L2_STD_SECAM_L; | 311 | tuner_dbg ("insmod fixup: SECAM => SECAM-L'\n"); |
312 | t->std = V4L2_STD_SECAM_LC; | ||
313 | } else { | ||
314 | tuner_dbg ("insmod fixup: SECAM => SECAM-L\n"); | ||
315 | t->std = V4L2_STD_SECAM_L; | ||
316 | } | ||
312 | break; | 317 | break; |
313 | case '-': | 318 | case '-': |
314 | /* default parameter, do nothing */ | 319 | /* default parameter, do nothing */ |
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index d832205818f2..e0c9fdb9914a 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c | |||
@@ -233,7 +233,7 @@ static struct tunertype tuners[] = { | |||
233 | { "Ymec TVision TVF-5533MF", Philips, NTSC, | 233 | { "Ymec TVision TVF-5533MF", Philips, NTSC, |
234 | 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, | 234 | 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732}, |
235 | 235 | ||
236 | /* 60-68 */ | 236 | /* 60-69 */ |
237 | { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, | 237 | { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC, |
238 | 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, | 238 | 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732}, |
239 | { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, | 239 | { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL, |
@@ -252,6 +252,8 @@ static struct tunertype tuners[] = { | |||
252 | 16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 }, | 252 | 16*160.00,16*442.00,0xa1,0xa2,0xa4,0xc8,623 }, |
253 | { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC, | 253 | { "Philips TUV1236D ATSC/NTSC dual in", Philips, ATSC, |
254 | 16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 }, | 254 | 16*157.25,16*454.00,0x01,0x02,0x04,0xce,732 }, |
255 | { "Tena TNF 5335 MF", Philips, NTSC, | ||
256 | 16*157.25,16*454.00,0x01,0x02,0x04,0x8e,732 }, | ||
255 | }; | 257 | }; |
256 | 258 | ||
257 | unsigned const int tuner_count = ARRAY_SIZE(tuners); | 259 | unsigned const int tuner_count = ARRAY_SIZE(tuners); |
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c index 22f286222004..a6936ad74fcf 100644 --- a/drivers/media/video/wm8775.c +++ b/drivers/media/video/wm8775.c | |||
@@ -5,6 +5,11 @@ | |||
5 | * | 5 | * |
6 | * Based on saa7115 driver | 6 | * Based on saa7115 driver |
7 | * | 7 | * |
8 | * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> | ||
9 | * - Cleanup | ||
10 | * - V4L2 API update | ||
11 | * - sound fixes | ||
12 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | 13 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 14 | * it under the terms of the GNU General Public License as published by |
10 | * the Free Software Foundation; either version 2 of the License, or | 15 | * the Free Software Foundation; either version 2 of the License, or |
@@ -31,7 +36,7 @@ | |||
31 | #include <media/audiochip.h> | 36 | #include <media/audiochip.h> |
32 | 37 | ||
33 | MODULE_DESCRIPTION("wm8775 driver"); | 38 | MODULE_DESCRIPTION("wm8775 driver"); |
34 | MODULE_AUTHOR("Ulf Eklund"); | 39 | MODULE_AUTHOR("Ulf Eklund, Hans Verkuil"); |
35 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
36 | 41 | ||
37 | #define wm8775_err(fmt, arg...) do { \ | 42 | #define wm8775_err(fmt, arg...) do { \ |