aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHuang Shijie <shijie8@gmail.com>2010-02-02 02:07:47 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-02-26 13:10:58 -0500
commit5b3f03f044ad6dffc8cd8c9c50bc5d7769cbd89f (patch)
tree3d11db7c9003c1725965149491ee959db4da6099
parent433763faec55e5f0e3aeb084da504c566134a934 (diff)
V4L/DVB: Add driver for Telegent tlg2300
pd-common.h contains the common data structures, while vendorcmds.h contains the vendor commands for firmware. [mchehab@redhat.com: Folded the 10 patches with the driver] Signed-off-by: Huang Shijie <shijie8@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--Documentation/video4linux/README.tlg2300231
-rw-r--r--MAINTAINERS8
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/tlg2300/Kconfig16
-rw-r--r--drivers/media/video/tlg2300/Makefile9
-rw-r--r--drivers/media/video/tlg2300/pd-alsa.c332
-rw-r--r--drivers/media/video/tlg2300/pd-common.h280
-rw-r--r--drivers/media/video/tlg2300/pd-dvb.c593
-rw-r--r--drivers/media/video/tlg2300/pd-main.c566
-rw-r--r--drivers/media/video/tlg2300/pd-radio.c351
-rw-r--r--drivers/media/video/tlg2300/pd-video.c1648
-rw-r--r--drivers/media/video/tlg2300/vendorcmds.h243
13 files changed, 4280 insertions, 0 deletions
diff --git a/Documentation/video4linux/README.tlg2300 b/Documentation/video4linux/README.tlg2300
new file mode 100644
index 000000000000..82417db3256f
--- /dev/null
+++ b/Documentation/video4linux/README.tlg2300
@@ -0,0 +1,231 @@
1tlg2300 release notes
2====================
3
4This is a v4l2/dvb device driver for the tlg2300 chip.
5
6
7current status
8==============
9
10video
11 - support mmap and read().(no overlay)
12
13audio
14 - The driver will register a ALSA card for the audio input.
15
16vbi
17 - Works for almost TV norms.
18
19dvb-t
20 - works for DVB-T
21
22FM
23 - Works for radio.
24
25---------------------------------------------------------------------------
26TESTED APPLICATIONS:
27
28-VLC1.0.4 test the video and dvb. The GUI is friendly to use.
29
30-Mplayer test the video.
31
32-Mplayer test the FM. The mplayer should be compiled with --enable-radio and
33 --enable-radio-capture.
34 The command runs as this(The alsa audio registers to card 1):
35 #mplayer radio://103.7/capture/ -radio adevice=hw=1,0:arate=48000 \
36 -rawaudio rate=48000:channels=2
37
38---------------------------------------------------------------------------
39KNOWN PROBLEMS:
40
41country code
42 - The firmware of the chip needs the country code to determine
43 the stardards of video and audio when it runs for analog TV or radio.
44 The DVB-T does not need the country code.
45
46 So you must set the country-code correctly. The V4L2 does not have
47 the interface,the driver has to provide a parameter `country_code'.
48
49 You could set the coutry code in two ways, take USA as example
50 (The USA's country code is 1):
51
52 [1] add the following line in /etc/modprobe.conf before you insert the
53 card into USB hub's port :
54 poseidon country_code=1
55
56 [2] You can also modify the parameter at runtime (before you run the
57 application such as VLC)
58 #echo 1 > /sys/module/poseidon/parameter/country_code
59
60 The known country codes show below:
61 country code : country
62 93 "Afghanistan"
63 355 "Albania"
64 213 "Algeria"
65 684 "American Samoa"
66 376 "Andorra"
67 244 "Angola"
68 54 "Argentina"
69 374 "Armenia"
70 61 "Australia"
71 43 "Austria"
72 994 "Azerbaijan"
73 973 "Bahrain"
74 880 "Bangladesh"
75 375 "Belarus"
76 32 "Belgium"
77 501 "Belize"
78 229 "Benin"
79 591 "Bolivia"
80 387 "Bosnia and Herzegovina"
81 267 "Botswana"
82 55 "Brazil"
83 673 "Brunei Darussalam"
84 359 "Bulgalia"
85 226 "Burkina Faso"
86 257 "Burundi"
87 237 "Cameroon"
88 1 "Canada"
89 236 "Central African Republic"
90 235 "Chad"
91 56 "Chile"
92 86 "China"
93 57 "Colombia"
94 242 "Congo"
95 243 "Congo, Dem. Rep. of "
96 506 "Costa Rica"
97 385 "Croatia"
98 53 "Cuba or Guantanamo Bay"
99 357 "Cyprus"
100 420 "Czech Republic"
101 45 "Denmark"
102 246 "Diego Garcia"
103 253 "Djibouti"
104 593 "Ecuador"
105 20 "Egypt"
106 503 "El Salvador"
107 240 "Equatorial Guinea"
108 372 "Estonia"
109 251 "Ethiopia"
110 358 "Finland"
111 33 "France"
112 594 "French Guiana"
113 689 "French Polynesia"
114 241 "Gabonese Republic"
115 220 "Gambia"
116 995 "Georgia"
117 49 "Germany"
118 233 "Ghana"
119 350 "Gibraltar"
120 30 "Greece"
121 299 "Greenland"
122 671 "Guam"
123 502 "Guatemala"
124 592 "Guyana"
125 509 "Haiti"
126 504 "Honduras"
127 852 "Hong Kong SAR, China"
128 36 "Hungary"
129 354 "Iceland"
130 91 "India"
131 98 "Iran"
132 964 "Iraq"
133 353 "Ireland"
134 972 "Israel"
135 39 "Italy or Vatican City"
136 225 "Ivory Coast"
137 81 "Japan"
138 962 "Jordan"
139 7 "Kazakhstan or Kyrgyzstan"
140 254 "Kenya"
141 686 "Kiribati"
142 965 "Kuwait"
143 856 "Laos"
144 371 "Latvia"
145 961 "Lebanon"
146 266 "Lesotho"
147 231 "Liberia"
148 218 "Libya"
149 41 "Liechtenstein or Switzerland"
150 370 "Lithuania"
151 352 "Luxembourg"
152 853 "Macau SAR, China"
153 261 "Madagascar"
154 60 "Malaysia"
155 960 "Maldives"
156 223 "Mali Republic"
157 356 "Malta"
158 692 "Marshall Islands"
159 596 "Martinique"
160 222 "Mauritania"
161 230 "Mauritus"
162 52 "Mexico"
163 691 "Micronesia"
164 373 "Moldova"
165 377 "Monaco"
166 976 "Mongolia"
167 212 "Morocco"
168 258 "Mozambique"
169 95 "Myanmar"
170 264 "Namibia"
171 674 "Nauru"
172 31 "Netherlands"
173 687 "New Caledonia"
174 64 "New Zealand"
175 505 "Nicaragua"
176 227 "Niger"
177 234 "Nigeria"
178 850 "North Korea"
179 47 "Norway"
180 968 "Oman"
181 92 "Pakistan"
182 680 "Palau"
183 507 "Panama"
184 675 "Papua New Guinea"
185 595 "Paraguay"
186 51 "Peru"
187 63 "Philippines"
188 48 "Poland"
189 351 "Portugal"
190 974 "Qatar"
191 262 "Reunion Island"
192 40 "Romania"
193 7 "Russia"
194 378 "San Marino"
195 239 "Sao Tome and Principe"
196 966 "Saudi Arabia"
197 221 "Senegal"
198 248 "Seychelles Republic"
199 232 "Sierra Leone"
200 65 "Singapore"
201 421 "Slovak Republic"
202 386 "Slovenia"
203 27 "South Africa"
204 82 "South Korea "
205 34 "Spain"
206 94 "Sri Lanka"
207 508 "St. Pierre and Miquelon"
208 249 "Sudan"
209 597 "Suriname"
210 268 "Swaziland"
211 46 "Sweden"
212 963 "Syria"
213 886 "Taiwan Region"
214 255 "Tanzania"
215 66 "Thailand"
216 228 "Togolese Republic"
217 216 "Tunisia"
218 90 "Turkey"
219 993 "Turkmenistan"
220 256 "Uganda"
221 380 "Ukraine"
222 971 "United Arab Emirates"
223 44 "United Kingdom"
224 1 "United States of America"
225 598 "Uruguay"
226 58 "Venezuela"
227 84 "Vietnam"
228 967 "Yemen"
229 260 "Zambia"
230 255 "Zanzibar"
231 263 "Zimbabwe"
diff --git a/MAINTAINERS b/MAINTAINERS
index 2533fc45a44a..f427294b85e0 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4676,6 +4676,14 @@ F: drivers/media/common/saa7146*
4676F: drivers/media/video/*7146* 4676F: drivers/media/video/*7146*
4677F: include/media/*7146* 4677F: include/media/*7146*
4678 4678
4679TLG2300 VIDEO4LINUX-2 DRIVER
4680M Huang Shijie <shijie8@gmail.com>
4681M Kang Yong <kangyong@telegent.com>
4682M Zhang Xiaobing <xbzhang@telegent.com>
4683S: Supported
4684F: drivers/media/video/tlg2300
4685
4686
4679SC1200 WDT DRIVER 4687SC1200 WDT DRIVER
4680M: Zwane Mwaikambo <zwane@arm.linux.org.uk> 4688M: Zwane Mwaikambo <zwane@arm.linux.org.uk>
4681S: Maintained 4689S: Maintained
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 64682bff228a..2f9c57d5fda3 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -949,6 +949,8 @@ source "drivers/media/video/hdpvr/Kconfig"
949 949
950source "drivers/media/video/em28xx/Kconfig" 950source "drivers/media/video/em28xx/Kconfig"
951 951
952source "drivers/media/video/tlg2300/Kconfig"
953
952source "drivers/media/video/cx231xx/Kconfig" 954source "drivers/media/video/cx231xx/Kconfig"
953 955
954source "drivers/media/video/usbvision/Kconfig" 956source "drivers/media/video/usbvision/Kconfig"
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2af68ee84122..5163289e13ee 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -99,6 +99,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
99obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ 99obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
100obj-$(CONFIG_VIDEO_CX88) += cx88/ 100obj-$(CONFIG_VIDEO_CX88) += cx88/
101obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ 101obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
102obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
102obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ 103obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
103obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ 104obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
104obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ 105obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
diff --git a/drivers/media/video/tlg2300/Kconfig b/drivers/media/video/tlg2300/Kconfig
new file mode 100644
index 000000000000..2c29ec659b4e
--- /dev/null
+++ b/drivers/media/video/tlg2300/Kconfig
@@ -0,0 +1,16 @@
1config VIDEO_TLG2300
2 tristate "Telegent TLG2300 USB video capture support"
3 depends on VIDEO_DEV && I2C && INPUT && SND && DVB_CORE
4 select VIDEO_TUNER
5 select VIDEO_TVEEPROM
6 select VIDEO_IR
7 select VIDEOBUF_VMALLOC
8 select SND_PCM
9 select VIDEOBUF_DVB
10
11 ---help---
12 This is a video4linux driver for Telegent tlg2300 based TV cards.
13 The driver supports V4L2, DVB-T and radio.
14
15 To compile this driver as a module, choose M here: the
16 module will be called poseidon
diff --git a/drivers/media/video/tlg2300/Makefile b/drivers/media/video/tlg2300/Makefile
new file mode 100644
index 000000000000..81bb7fdd1e3d
--- /dev/null
+++ b/drivers/media/video/tlg2300/Makefile
@@ -0,0 +1,9 @@
1poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o
2
3obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o
4
5EXTRA_CFLAGS += -Idrivers/media/video
6EXTRA_CFLAGS += -Idrivers/media/common/tuners
7EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
8EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
9
diff --git a/drivers/media/video/tlg2300/pd-alsa.c b/drivers/media/video/tlg2300/pd-alsa.c
new file mode 100644
index 000000000000..6f42621ad478
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-alsa.c
@@ -0,0 +1,332 @@
1#include <linux/kernel.h>
2#include <linux/usb.h>
3#include <linux/init.h>
4#include <linux/sound.h>
5#include <linux/spinlock.h>
6#include <linux/soundcard.h>
7#include <linux/slab.h>
8#include <linux/vmalloc.h>
9#include <linux/proc_fs.h>
10#include <linux/module.h>
11#include <sound/core.h>
12#include <sound/pcm.h>
13#include <sound/pcm_params.h>
14#include <sound/info.h>
15#include <sound/initval.h>
16#include <sound/control.h>
17#include <media/v4l2-common.h>
18#include "pd-common.h"
19#include "vendorcmds.h"
20
21static void complete_handler_audio(struct urb *urb);
22#define AUDIO_EP (0x83)
23#define AUDIO_BUF_SIZE (512)
24#define PERIOD_SIZE (1024 * 8)
25#define PERIOD_MIN (4)
26#define PERIOD_MAX PERIOD_MIN
27
28static struct snd_pcm_hardware snd_pd_hw_capture = {
29 .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
30 SNDRV_PCM_INFO_MMAP |
31 SNDRV_PCM_INFO_INTERLEAVED |
32 SNDRV_PCM_INFO_MMAP_VALID,
33
34 .formats = SNDRV_PCM_FMTBIT_S16_LE,
35 .rates = SNDRV_PCM_RATE_48000,
36
37 .rate_min = 48000,
38 .rate_max = 48000,
39 .channels_min = 2,
40 .channels_max = 2,
41 .buffer_bytes_max = PERIOD_SIZE * PERIOD_MIN,
42 .period_bytes_min = PERIOD_SIZE,
43 .period_bytes_max = PERIOD_SIZE,
44 .periods_min = PERIOD_MIN,
45 .periods_max = PERIOD_MAX,
46 /*
47 .buffer_bytes_max = 62720 * 8,
48 .period_bytes_min = 64,
49 .period_bytes_max = 12544,
50 .periods_min = 2,
51 .periods_max = 98
52 */
53};
54
55static int snd_pd_capture_open(struct snd_pcm_substream *substream)
56{
57 struct poseidon *p = snd_pcm_substream_chip(substream);
58 struct poseidon_audio *pa = &p->audio;
59 struct snd_pcm_runtime *runtime = substream->runtime;
60
61 if (!p)
62 return -ENODEV;
63 pa->users++;
64 pa->card_close = 0;
65 pa->capture_pcm_substream = substream;
66 runtime->private_data = p;
67
68 runtime->hw = snd_pd_hw_capture;
69 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
70 usb_autopm_get_interface(p->interface);
71 kref_get(&p->kref);
72 return 0;
73}
74
75static int snd_pd_pcm_close(struct snd_pcm_substream *substream)
76{
77 struct poseidon *p = snd_pcm_substream_chip(substream);
78 struct poseidon_audio *pa = &p->audio;
79
80 pa->users--;
81 pa->card_close = 1;
82 usb_autopm_put_interface(p->interface);
83 kref_put(&p->kref, poseidon_delete);
84 return 0;
85}
86
87static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream,
88 struct snd_pcm_hw_params *hw_params)
89{
90 struct snd_pcm_runtime *runtime = substream->runtime;
91 unsigned int size;
92
93 size = params_buffer_bytes(hw_params);
94 if (runtime->dma_area) {
95 if (runtime->dma_bytes > size)
96 return 0;
97 vfree(runtime->dma_area);
98 }
99 runtime->dma_area = vmalloc(size);
100 if (!runtime->dma_area)
101 return -ENOMEM;
102 else
103 runtime->dma_bytes = size;
104 return 0;
105}
106
107static int audio_buf_free(struct poseidon *p)
108{
109 struct poseidon_audio *pa = &p->audio;
110 int i;
111
112 for (i = 0; i < AUDIO_BUFS; i++)
113 if (pa->urb_array[i])
114 usb_kill_urb(pa->urb_array[i]);
115 free_all_urb_generic(pa->urb_array, AUDIO_BUFS);
116 logpm();
117 return 0;
118}
119
120static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream)
121{
122 struct poseidon *p = snd_pcm_substream_chip(substream);
123
124 logpm();
125 audio_buf_free(p);
126 return 0;
127}
128
129static int snd_pd_prepare(struct snd_pcm_substream *substream)
130{
131 return 0;
132}
133
134#define AUDIO_TRAILER_SIZE (16)
135static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
136{
137 struct poseidon_audio *pa = urb->context;
138 struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime;
139
140 int stride = runtime->frame_bits >> 3;
141 int len = urb->actual_length / stride;
142 unsigned char *cp = urb->transfer_buffer;
143 unsigned int oldptr = pa->rcv_position;
144
145 if (urb->actual_length == AUDIO_BUF_SIZE - 4)
146 len -= (AUDIO_TRAILER_SIZE / stride);
147
148 /* do the copy */
149 if (oldptr + len >= runtime->buffer_size) {
150 unsigned int cnt = runtime->buffer_size - oldptr;
151
152 memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride);
153 memcpy(runtime->dma_area, (cp + cnt * stride),
154 (len * stride - cnt * stride));
155 } else
156 memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
157
158 /* update the statas */
159 snd_pcm_stream_lock(pa->capture_pcm_substream);
160 pa->rcv_position += len;
161 if (pa->rcv_position >= runtime->buffer_size)
162 pa->rcv_position -= runtime->buffer_size;
163
164 pa->copied_position += (len);
165 if (pa->copied_position >= runtime->period_size) {
166 pa->copied_position -= runtime->period_size;
167 *period_elapsed = 1;
168 }
169 snd_pcm_stream_unlock(pa->capture_pcm_substream);
170}
171
172static void complete_handler_audio(struct urb *urb)
173{
174 struct poseidon_audio *pa = urb->context;
175 struct snd_pcm_substream *substream = pa->capture_pcm_substream;
176 int period_elapsed = 0;
177 int ret;
178
179 if (1 == pa->card_close || pa->capture_stream != STREAM_ON)
180 return;
181
182 if (urb->status != 0) {
183 /*if (urb->status == -ESHUTDOWN)*/
184 return;
185 }
186
187 if (substream) {
188 if (urb->actual_length) {
189 handle_audio_data(urb, &period_elapsed);
190 if (period_elapsed)
191 snd_pcm_period_elapsed(substream);
192 }
193 }
194
195 ret = usb_submit_urb(urb, GFP_ATOMIC);
196 if (ret < 0)
197 log("audio urb failed (errcod = %i)", ret);
198 return;
199}
200
201static int fire_audio_urb(struct poseidon *p)
202{
203 int i, ret = 0;
204 struct poseidon_audio *pa = &p->audio;
205
206 alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS,
207 p->udev, AUDIO_EP,
208 AUDIO_BUF_SIZE, GFP_ATOMIC,
209 complete_handler_audio, pa);
210
211 for (i = 0; i < AUDIO_BUFS; i++) {
212 ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL);
213 if (ret)
214 log("urb err : %d", ret);
215 }
216 log();
217 return ret;
218}
219
220static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd)
221{
222 struct poseidon *p = snd_pcm_substream_chip(substream);
223 struct poseidon_audio *pa = &p->audio;
224
225 if (debug_mode)
226 log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream);
227
228 switch (cmd) {
229 case SNDRV_PCM_TRIGGER_RESUME:
230 case SNDRV_PCM_TRIGGER_START:
231 if (pa->capture_stream == STREAM_ON)
232 return 0;
233
234 pa->rcv_position = pa->copied_position = 0;
235 pa->capture_stream = STREAM_ON;
236
237 if (in_hibernation(p))
238 return 0;
239 fire_audio_urb(p);
240 return 0;
241
242 case SNDRV_PCM_TRIGGER_SUSPEND:
243 pa->capture_stream = STREAM_SUSPEND;
244 return 0;
245 case SNDRV_PCM_TRIGGER_STOP:
246 pa->capture_stream = STREAM_OFF;
247 return 0;
248 default:
249 return -EINVAL;
250 }
251}
252
253static snd_pcm_uframes_t
254snd_pd_capture_pointer(struct snd_pcm_substream *substream)
255{
256 struct poseidon *p = snd_pcm_substream_chip(substream);
257 struct poseidon_audio *pa = &p->audio;
258 return pa->rcv_position;
259}
260
261static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs,
262 unsigned long offset)
263{
264 void *pageptr = subs->runtime->dma_area + offset;
265 return vmalloc_to_page(pageptr);
266}
267
268static struct snd_pcm_ops pcm_capture_ops = {
269 .open = snd_pd_capture_open,
270 .close = snd_pd_pcm_close,
271 .ioctl = snd_pcm_lib_ioctl,
272 .hw_params = snd_pd_hw_capture_params,
273 .hw_free = snd_pd_hw_capture_free,
274 .prepare = snd_pd_prepare,
275 .trigger = snd_pd_capture_trigger,
276 .pointer = snd_pd_capture_pointer,
277 .page = snd_pcm_pd_get_page,
278};
279
280#ifdef CONFIG_PM
281int pm_alsa_suspend(struct poseidon *p)
282{
283 logpm(p);
284 audio_buf_free(p);
285 return 0;
286}
287
288int pm_alsa_resume(struct poseidon *p)
289{
290 logpm(p);
291 fire_audio_urb(p);
292 return 0;
293}
294#endif
295
296int poseidon_audio_init(struct poseidon *p)
297{
298 struct poseidon_audio *pa = &p->audio;
299 struct snd_card *card;
300 struct snd_pcm *pcm;
301 int ret;
302
303 ret = snd_card_create(-1, "Telegent", THIS_MODULE, 0, &card);
304 if (ret != 0)
305 return ret;
306
307 ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm);
308 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
309 pcm->info_flags = 0;
310 pcm->private_data = p;
311 strcpy(pcm->name, "poseidon audio capture");
312
313 strcpy(card->driver, "ALSA driver");
314 strcpy(card->shortname, "poseidon Audio");
315 strcpy(card->longname, "poseidon ALSA Audio");
316
317 if (snd_card_register(card)) {
318 snd_card_free(card);
319 return -ENOMEM;
320 }
321 pa->card = card;
322 return 0;
323}
324
325int poseidon_audio_free(struct poseidon *p)
326{
327 struct poseidon_audio *pa = &p->audio;
328
329 if (pa->card)
330 snd_card_free(pa->card);
331 return 0;
332}
diff --git a/drivers/media/video/tlg2300/pd-common.h b/drivers/media/video/tlg2300/pd-common.h
new file mode 100644
index 000000000000..619fd009e965
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-common.h
@@ -0,0 +1,280 @@
1#ifndef PD_COMMON_H
2#define PD_COMMON_H
3
4#include <linux/version.h>
5#include <linux/fs.h>
6#include <linux/wait.h>
7#include <linux/list.h>
8#include <linux/videodev2.h>
9#include <linux/semaphore.h>
10#include <linux/usb.h>
11#include <linux/poll.h>
12#include <media/videobuf-vmalloc.h>
13#include <media/v4l2-device.h>
14
15#include "dvb_frontend.h"
16#include "dvbdev.h"
17#include "dvb_demux.h"
18#include "dmxdev.h"
19
20#define SBUF_NUM 8
21#define MAX_BUFFER_NUM 6
22#define PK_PER_URB 32
23#define ISO_PKT_SIZE 3072
24
25#define POSEIDON_STATE_NONE (0x0000)
26#define POSEIDON_STATE_ANALOG (0x0001)
27#define POSEIDON_STATE_FM (0x0002)
28#define POSEIDON_STATE_DVBT (0x0004)
29#define POSEIDON_STATE_VBI (0x0008)
30#define POSEIDON_STATE_DISCONNECT (0x0080)
31
32#define PM_SUSPEND_DELAY 3
33
34#define V4L_PAL_VBI_LINES 18
35#define V4L_NTSC_VBI_LINES 12
36#define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2)
37#define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2)
38
39#define TUNER_FREQ_MIN (45000000)
40#define TUNER_FREQ_MAX (862000000)
41
42struct vbi_data {
43 struct video_device *v_dev;
44 struct video_data *video;
45 struct front_face *front;
46
47 unsigned int copied;
48 unsigned int vbi_size; /* the whole size of two fields */
49 int users;
50};
51
52/*
53 * This is the running context of the video, it is useful for
54 * resume()
55 */
56struct running_context {
57 u32 freq; /* VIDIOC_S_FREQUENCY */
58 int audio_idx; /* VIDIOC_S_TUNER */
59 v4l2_std_id tvnormid; /* VIDIOC_S_STD */
60 int sig_index; /* VIDIOC_S_INPUT */
61 struct v4l2_pix_format pix; /* VIDIOC_S_FMT */
62};
63
64struct video_data {
65 /* v4l2 video device */
66 struct video_device *v_dev;
67
68 /* the working context */
69 struct running_context context;
70
71 /* for data copy */
72 int field_count;
73
74 char *dst;
75 int lines_copied;
76 int prev_left;
77
78 int lines_per_field;
79 int lines_size;
80
81 /* for communication */
82 u8 endpoint_addr;
83 struct urb *urb_array[SBUF_NUM];
84 struct vbi_data *vbi;
85 struct poseidon *pd;
86 struct front_face *front;
87
88 int is_streaming;
89 int users;
90
91 /* for bubble handler */
92 struct work_struct bubble_work;
93};
94
95enum pcm_stream_state {
96 STREAM_OFF,
97 STREAM_ON,
98 STREAM_SUSPEND,
99};
100
101#define AUDIO_BUFS (3)
102#define CAPTURE_STREAM_EN 1
103struct poseidon_audio {
104 struct urb *urb_array[AUDIO_BUFS];
105 unsigned int copied_position;
106 struct snd_pcm_substream *capture_pcm_substream;
107
108 unsigned int rcv_position;
109 struct snd_card *card;
110 int card_close;
111
112 int users;
113 int pm_state;
114 enum pcm_stream_state capture_stream;
115};
116
117struct radio_data {
118 __u32 fm_freq;
119 int users;
120 unsigned int is_radio_streaming;
121 struct video_device *fm_dev;
122};
123
124#define DVB_SBUF_NUM 4
125#define DVB_URB_BUF_SIZE 0x2000
126struct pd_dvb_adapter {
127 struct dvb_adapter dvb_adap;
128 struct dvb_frontend dvb_fe;
129 struct dmxdev dmxdev;
130 struct dvb_demux demux;
131
132 atomic_t users;
133 atomic_t active_feed;
134
135 /* data transfer */
136 s32 is_streaming;
137 struct urb *urb_array[DVB_SBUF_NUM];
138 struct poseidon *pd_device;
139 u8 ep_addr;
140 u8 reserved[3];
141
142 /* data for power resume*/
143 struct dvb_frontend_parameters fe_param;
144
145 /* for channel scanning */
146 int prev_freq;
147 int bandwidth;
148 unsigned long last_jiffies;
149};
150
151struct front_face {
152 /* use this field to distinguish VIDEO and VBI */
153 enum v4l2_buf_type type;
154
155 /* for host */
156 struct videobuf_queue q;
157
158 /* the bridge for host and device */
159 struct videobuf_buffer *curr_frame;
160
161 /* for device */
162 spinlock_t queue_lock;
163 struct list_head active;
164 struct poseidon *pd;
165};
166
167struct poseidon {
168 struct list_head device_list;
169
170 struct mutex lock;
171 struct kref kref;
172
173 /* for V4L2 */
174 struct v4l2_device v4l2_dev;
175
176 /* hardware info */
177 struct usb_device *udev;
178 struct usb_interface *interface;
179 int cur_transfer_mode;
180
181 struct video_data video_data; /* video */
182 struct vbi_data vbi_data; /* vbi */
183 struct poseidon_audio audio; /* audio (alsa) */
184 struct radio_data radio_data; /* FM */
185 struct pd_dvb_adapter dvb_data; /* DVB */
186
187 u32 state;
188 int country_code;
189 struct file *file_for_stream; /* the active stream*/
190
191#ifdef CONFIG_PM
192 int (*pm_suspend)(struct poseidon *);
193 int (*pm_resume)(struct poseidon *);
194 pm_message_t msg;
195
196 struct work_struct pm_work;
197 u8 portnum;
198#endif
199};
200
201struct poseidon_format {
202 char *name;
203 int fourcc; /* video4linux 2 */
204 int depth; /* bit/pixel */
205 int flags;
206};
207
208struct poseidon_tvnorm {
209 v4l2_std_id v4l2_id;
210 char name[12];
211 u32 tlg_tvnorm;
212};
213
214/* video */
215int pd_video_init(struct poseidon *);
216void pd_video_exit(struct poseidon *);
217int stop_all_video_stream(struct poseidon *);
218
219/* alsa audio */
220int poseidon_audio_init(struct poseidon *);
221int poseidon_audio_free(struct poseidon *);
222#ifdef CONFIG_PM
223int pm_alsa_suspend(struct poseidon *);
224int pm_alsa_resume(struct poseidon *);
225#endif
226
227/* dvb */
228int pd_dvb_usb_device_init(struct poseidon *);
229void pd_dvb_usb_device_exit(struct poseidon *);
230void pd_dvb_usb_device_cleanup(struct poseidon *);
231int pd_dvb_get_adapter_num(struct pd_dvb_adapter *);
232void dvb_stop_streaming(struct pd_dvb_adapter *);
233
234/* FM */
235int poseidon_fm_init(struct poseidon *);
236int poseidon_fm_exit(struct poseidon *);
237struct video_device *vdev_init(struct poseidon *, struct video_device *);
238
239/* vendor command ops */
240int send_set_req(struct poseidon*, u8, s32, s32*);
241int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32);
242s32 set_tuner_mode(struct poseidon*, unsigned char);
243enum tlg__analog_audio_standard get_audio_std(s32, s32);
244
245/* bulk urb alloc/free */
246int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
247 struct usb_device *udev, u8 ep_addr,
248 int buf_size, gfp_t gfp_flags,
249 usb_complete_t complete_fn, void *context);
250void free_all_urb_generic(struct urb **urb_array, int num);
251
252/* misc */
253void poseidon_delete(struct kref *kref);
254void destroy_video_device(struct video_device **v_dev);
255extern int country_code;
256extern int debug_mode;
257void set_debug_mode(struct video_device *vfd, int debug_mode);
258
259#define in_hibernation(pd) (pd->msg.event == PM_EVENT_FREEZE)
260#define get_pm_count(p) (atomic_read(&(p)->interface->pm_usage_cnt))
261
262#define log(a, ...) printk(KERN_DEBUG "\t[ %s : %.3d ] "a"\n", \
263 __func__, __LINE__, ## __VA_ARGS__)
264
265/* for power management */
266#define logpm(pd) do {\
267 if (debug_mode & 0x10)\
268 log();\
269 } while (0)
270
271#define logs(f) do { \
272 if ((debug_mode & 0x4) && \
273 (f)->type == V4L2_BUF_TYPE_VBI_CAPTURE) \
274 log("type : VBI");\
275 \
276 if ((debug_mode & 0x8) && \
277 (f)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) \
278 log("type : VIDEO");\
279 } while (0)
280#endif
diff --git a/drivers/media/video/tlg2300/pd-dvb.c b/drivers/media/video/tlg2300/pd-dvb.c
new file mode 100644
index 000000000000..4133aee568bf
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-dvb.c
@@ -0,0 +1,593 @@
1#include "pd-common.h"
2#include <linux/kernel.h>
3#include <linux/usb.h>
4#include <linux/dvb/dmx.h>
5#include <linux/delay.h>
6
7#include "vendorcmds.h"
8#include <linux/sched.h>
9#include <asm/atomic.h>
10
11static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb);
12
13static int dvb_bandwidth[][2] = {
14 { TLG_BW_8, BANDWIDTH_8_MHZ },
15 { TLG_BW_7, BANDWIDTH_7_MHZ },
16 { TLG_BW_6, BANDWIDTH_6_MHZ }
17};
18static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth);
19
20static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb);
21static int poseidon_check_mode_dvbt(struct poseidon *pd)
22{
23 s32 ret = 0, cmd_status = 0;
24
25 set_current_state(TASK_INTERRUPTIBLE);
26 schedule_timeout(HZ/4);
27
28 ret = usb_set_interface(pd->udev, 0, BULK_ALTERNATE_IFACE);
29 if (ret != 0)
30 return ret;
31
32 ret = set_tuner_mode(pd, TLG_MODE_CAPS_DVB_T);
33 if (ret)
34 return ret;
35
36 /* signal source */
37 ret = send_set_req(pd, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &cmd_status);
38 if (ret|cmd_status)
39 return ret;
40
41 return 0;
42}
43
44/* acquire :
45 * 1 == open
46 * 0 == release
47 */
48static int poseidon_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
49{
50 struct poseidon *pd = fe->demodulator_priv;
51 struct pd_dvb_adapter *pd_dvb;
52 int ret = 0;
53
54 if (!pd)
55 return -ENODEV;
56
57 pd_dvb = container_of(fe, struct pd_dvb_adapter, dvb_fe);
58 if (acquire) {
59 mutex_lock(&pd->lock);
60 if (pd->state & POSEIDON_STATE_DISCONNECT) {
61 ret = -ENODEV;
62 goto open_out;
63 }
64
65 if (pd->state && !(pd->state & POSEIDON_STATE_DVBT)) {
66 ret = -EBUSY;
67 goto open_out;
68 }
69
70 usb_autopm_get_interface(pd->interface);
71 if (0 == pd->state) {
72 ret = poseidon_check_mode_dvbt(pd);
73 if (ret < 0) {
74 usb_autopm_put_interface(pd->interface);
75 goto open_out;
76 }
77 pd->state |= POSEIDON_STATE_DVBT;
78 pd_dvb->bandwidth = 0;
79 pd_dvb->prev_freq = 0;
80 }
81 atomic_inc(&pd_dvb->users);
82 kref_get(&pd->kref);
83open_out:
84 mutex_unlock(&pd->lock);
85 } else {
86 dvb_stop_streaming(pd_dvb);
87
88 if (atomic_dec_and_test(&pd_dvb->users)) {
89 mutex_lock(&pd->lock);
90 pd->state &= ~POSEIDON_STATE_DVBT;
91 mutex_unlock(&pd->lock);
92 }
93 kref_put(&pd->kref, poseidon_delete);
94 usb_autopm_put_interface(pd->interface);
95 }
96 return ret;
97}
98
99static void poseidon_fe_release(struct dvb_frontend *fe)
100{
101 struct poseidon *pd = fe->demodulator_priv;
102
103#ifdef CONFIG_PM
104 pd->pm_suspend = NULL;
105 pd->pm_resume = NULL;
106#endif
107}
108
109static s32 poseidon_fe_sleep(struct dvb_frontend *fe)
110{
111 return 0;
112}
113
114/*
115 * return true if we can satisfy the conditions, else return false.
116 */
117static bool check_scan_ok(__u32 freq, int bandwidth,
118 struct pd_dvb_adapter *adapter)
119{
120 if (bandwidth < 0)
121 return false;
122
123 if (adapter->prev_freq == freq
124 && adapter->bandwidth == bandwidth) {
125 long nl = jiffies - adapter->last_jiffies;
126 unsigned int msec ;
127
128 msec = jiffies_to_msecs(abs(nl));
129 return msec > 15000 ? true : false;
130 }
131 return true;
132}
133
134/*
135 * Check if the firmware delays too long for an invalid frequency.
136 */
137static int fw_delay_overflow(struct pd_dvb_adapter *adapter)
138{
139 long nl = jiffies - adapter->last_jiffies;
140 unsigned int msec ;
141
142 msec = jiffies_to_msecs(abs(nl));
143 return msec > 800 ? true : false;
144}
145
146static int poseidon_set_fe(struct dvb_frontend *fe,
147 struct dvb_frontend_parameters *fep)
148{
149 s32 ret = 0, cmd_status = 0;
150 s32 i, bandwidth = -1;
151 struct poseidon *pd = fe->demodulator_priv;
152 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
153
154 if (in_hibernation(pd))
155 return -EBUSY;
156
157 mutex_lock(&pd->lock);
158 for (i = 0; i < dvb_bandwidth_length; i++)
159 if (fep->u.ofdm.bandwidth == dvb_bandwidth[i][1])
160 bandwidth = dvb_bandwidth[i][0];
161
162 if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) {
163 ret = send_set_req(pd, TUNE_FREQ_SELECT,
164 fep->frequency / 1000, &cmd_status);
165 if (ret | cmd_status) {
166 log("error line");
167 goto front_out;
168 }
169
170 ret = send_set_req(pd, DVBT_BANDW_SEL,
171 bandwidth, &cmd_status);
172 if (ret | cmd_status) {
173 log("error line");
174 goto front_out;
175 }
176
177 ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
178 if (ret | cmd_status) {
179 log("error line");
180 goto front_out;
181 }
182
183 /* save the context for future */
184 memcpy(&pd_dvb->fe_param, fep, sizeof(*fep));
185 pd_dvb->bandwidth = bandwidth;
186 pd_dvb->prev_freq = fep->frequency;
187 pd_dvb->last_jiffies = jiffies;
188 }
189front_out:
190 mutex_unlock(&pd->lock);
191 return ret;
192}
193
194#ifdef CONFIG_PM
195static int pm_dvb_suspend(struct poseidon *pd)
196{
197 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
198 dvb_stop_streaming(pd_dvb);
199 dvb_urb_cleanup(pd_dvb);
200 msleep(500);
201 return 0;
202}
203
204static int pm_dvb_resume(struct poseidon *pd)
205{
206 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
207
208 poseidon_check_mode_dvbt(pd);
209 msleep(300);
210 poseidon_set_fe(&pd_dvb->dvb_fe, &pd_dvb->fe_param);
211
212 dvb_start_streaming(pd_dvb);
213 return 0;
214}
215#endif
216
217static s32 poseidon_fe_init(struct dvb_frontend *fe)
218{
219 struct poseidon *pd = fe->demodulator_priv;
220 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
221
222#ifdef CONFIG_PM
223 pd->pm_suspend = pm_dvb_suspend;
224 pd->pm_resume = pm_dvb_resume;
225#endif
226 memset(&pd_dvb->fe_param, 0,
227 sizeof(struct dvb_frontend_parameters));
228 return 0;
229}
230
231static int poseidon_get_fe(struct dvb_frontend *fe,
232 struct dvb_frontend_parameters *fep)
233{
234 struct poseidon *pd = fe->demodulator_priv;
235 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
236
237 memcpy(fep, &pd_dvb->fe_param, sizeof(*fep));
238 return 0;
239}
240
241static int poseidon_fe_get_tune_settings(struct dvb_frontend *fe,
242 struct dvb_frontend_tune_settings *tune)
243{
244 tune->min_delay_ms = 1000;
245 return 0;
246}
247
248static int poseidon_read_status(struct dvb_frontend *fe, fe_status_t *stat)
249{
250 struct poseidon *pd = fe->demodulator_priv;
251 s32 ret = -1, cmd_status;
252 struct tuner_dtv_sig_stat_s status = {};
253
254 if (in_hibernation(pd))
255 return -EBUSY;
256 mutex_lock(&pd->lock);
257
258 ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
259 &status, &cmd_status, sizeof(status));
260 if (ret | cmd_status) {
261 log("get tuner status error");
262 goto out;
263 }
264
265 if (debug_mode)
266 log("P : %d, L %d, LB :%d", status.sig_present,
267 status.sig_locked, status.sig_lock_busy);
268
269 if (status.sig_lock_busy) {
270 goto out;
271 } else if (status.sig_present || status.sig_locked) {
272 *stat |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER
273 | FE_HAS_SYNC | FE_HAS_VITERBI;
274 } else {
275 if (fw_delay_overflow(&pd->dvb_data))
276 *stat |= FE_TIMEDOUT;
277 }
278out:
279 mutex_unlock(&pd->lock);
280 return ret;
281}
282
283static int poseidon_read_ber(struct dvb_frontend *fe, u32 *ber)
284{
285 struct poseidon *pd = fe->demodulator_priv;
286 struct tuner_ber_rate_s tlg_ber = {};
287 s32 ret = -1, cmd_status;
288
289 mutex_lock(&pd->lock);
290 ret = send_get_req(pd, TUNER_BER_RATE, 0,
291 &tlg_ber, &cmd_status, sizeof(tlg_ber));
292 if (ret | cmd_status)
293 goto out;
294 *ber = tlg_ber.ber_rate;
295out:
296 mutex_unlock(&pd->lock);
297 return ret;
298}
299
300static s32 poseidon_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
301{
302 struct poseidon *pd = fe->demodulator_priv;
303 struct tuner_dtv_sig_stat_s status = {};
304 s32 ret = 0, cmd_status;
305
306 mutex_lock(&pd->lock);
307 ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
308 &status, &cmd_status, sizeof(status));
309 if (ret | cmd_status)
310 goto out;
311 if ((status.sig_present || status.sig_locked) && !status.sig_strength)
312 *strength = 0xFFFF;
313 else
314 *strength = status.sig_strength;
315out:
316 mutex_unlock(&pd->lock);
317 return ret;
318}
319
320static int poseidon_read_snr(struct dvb_frontend *fe, u16 *snr)
321{
322 return 0;
323}
324
325static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
326{
327 *unc = 0;
328 return 0;
329}
330
331static struct dvb_frontend_ops poseidon_frontend_ops = {
332 .info = {
333 .name = "Poseidon DVB-T",
334 .type = FE_OFDM,
335 .frequency_min = 174000000,
336 .frequency_max = 862000000,
337 .frequency_stepsize = 62500,/* FIXME */
338 .caps = FE_CAN_INVERSION_AUTO |
339 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
340 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
341 FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
342 FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
343 FE_CAN_GUARD_INTERVAL_AUTO |
344 FE_CAN_RECOVER |
345 FE_CAN_HIERARCHY_AUTO,
346 },
347
348 .release = poseidon_fe_release,
349
350 .init = poseidon_fe_init,
351 .sleep = poseidon_fe_sleep,
352
353 .set_frontend = poseidon_set_fe,
354 .get_frontend = poseidon_get_fe,
355 .get_tune_settings = poseidon_fe_get_tune_settings,
356
357 .read_status = poseidon_read_status,
358 .read_ber = poseidon_read_ber,
359 .read_signal_strength = poseidon_read_signal_strength,
360 .read_snr = poseidon_read_snr,
361 .read_ucblocks = poseidon_read_unc_blocks,
362
363 .ts_bus_ctrl = poseidon_ts_bus_ctrl,
364};
365
366static void dvb_urb_irq(struct urb *urb)
367{
368 struct pd_dvb_adapter *pd_dvb = urb->context;
369 int len = urb->transfer_buffer_length;
370 struct dvb_demux *demux = &pd_dvb->demux;
371 s32 ret;
372
373 if (!pd_dvb->is_streaming || urb->status) {
374 if (urb->status == -EPROTO)
375 goto resend;
376 return;
377 }
378
379 if (urb->actual_length == len)
380 dvb_dmx_swfilter(demux, urb->transfer_buffer, len);
381 else if (urb->actual_length == len - 4) {
382 int offset;
383 u8 *buf = urb->transfer_buffer;
384
385 /*
386 * The packet size is 512,
387 * last packet contains 456 bytes tsp data
388 */
389 for (offset = 456; offset < len; offset += 512) {
390 if (!strncmp(buf + offset, "DVHS", 4)) {
391 dvb_dmx_swfilter(demux, buf, offset);
392 if (len > offset + 52 + 4) {
393 /*16 bytes trailer + 36 bytes padding */
394 buf += offset + 52;
395 len -= offset + 52 + 4;
396 dvb_dmx_swfilter(demux, buf, len);
397 }
398 break;
399 }
400 }
401 }
402
403resend:
404 ret = usb_submit_urb(urb, GFP_ATOMIC);
405 if (ret)
406 log(" usb_submit_urb failed: error %d", ret);
407}
408
409static int dvb_urb_init(struct pd_dvb_adapter *pd_dvb)
410{
411 if (pd_dvb->urb_array[0])
412 return 0;
413
414 alloc_bulk_urbs_generic(pd_dvb->urb_array, DVB_SBUF_NUM,
415 pd_dvb->pd_device->udev, pd_dvb->ep_addr,
416 DVB_URB_BUF_SIZE, GFP_KERNEL,
417 dvb_urb_irq, pd_dvb);
418 return 0;
419}
420
421static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb)
422{
423 free_all_urb_generic(pd_dvb->urb_array, DVB_SBUF_NUM);
424}
425
426static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb)
427{
428 struct poseidon *pd = pd_dvb->pd_device;
429 int ret = 0;
430
431 if (pd->state & POSEIDON_STATE_DISCONNECT)
432 return -ENODEV;
433
434 mutex_lock(&pd->lock);
435 if (!pd_dvb->is_streaming) {
436 s32 i, cmd_status = 0;
437 /*
438 * Once upon a time, there was a difficult bug lying here.
439 * ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
440 */
441
442 ret = send_set_req(pd, PLAY_SERVICE, 1, &cmd_status);
443 if (ret | cmd_status)
444 goto out;
445
446 ret = dvb_urb_init(pd_dvb);
447 if (ret < 0)
448 goto out;
449
450 pd_dvb->is_streaming = 1;
451 for (i = 0; i < DVB_SBUF_NUM; i++) {
452 ret = usb_submit_urb(pd_dvb->urb_array[i],
453 GFP_KERNEL);
454 if (ret) {
455 log(" submit urb error %d", ret);
456 goto out;
457 }
458 }
459 }
460out:
461 mutex_unlock(&pd->lock);
462 return ret;
463}
464
465void dvb_stop_streaming(struct pd_dvb_adapter *pd_dvb)
466{
467 struct poseidon *pd = pd_dvb->pd_device;
468
469 mutex_lock(&pd->lock);
470 if (pd_dvb->is_streaming) {
471 s32 i, ret, cmd_status = 0;
472
473 pd_dvb->is_streaming = 0;
474
475 for (i = 0; i < DVB_SBUF_NUM; i++)
476 if (pd_dvb->urb_array[i])
477 usb_kill_urb(pd_dvb->urb_array[i]);
478
479 ret = send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
480 &cmd_status);
481 if (ret | cmd_status)
482 log("error");
483 }
484 mutex_unlock(&pd->lock);
485}
486
487static int pd_start_feed(struct dvb_demux_feed *feed)
488{
489 struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
490 int ret = 0;
491
492 if (!pd_dvb)
493 return -1;
494 if (atomic_inc_return(&pd_dvb->active_feed) == 1)
495 ret = dvb_start_streaming(pd_dvb);
496 return ret;
497}
498
499static int pd_stop_feed(struct dvb_demux_feed *feed)
500{
501 struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
502
503 if (!pd_dvb)
504 return -1;
505 if (atomic_dec_and_test(&pd_dvb->active_feed))
506 dvb_stop_streaming(pd_dvb);
507 return 0;
508}
509
510DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
511int pd_dvb_usb_device_init(struct poseidon *pd)
512{
513 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
514 struct dvb_demux *dvbdemux;
515 int ret = 0;
516
517 pd_dvb->ep_addr = 0x82;
518 atomic_set(&pd_dvb->users, 0);
519 atomic_set(&pd_dvb->active_feed, 0);
520 pd_dvb->pd_device = pd;
521
522 ret = dvb_register_adapter(&pd_dvb->dvb_adap,
523 "Poseidon dvbt adapter",
524 THIS_MODULE,
525 NULL /* for hibernation correctly*/,
526 adapter_nr);
527 if (ret < 0)
528 goto error1;
529
530 /* register frontend */
531 pd_dvb->dvb_fe.demodulator_priv = pd;
532 memcpy(&pd_dvb->dvb_fe.ops, &poseidon_frontend_ops,
533 sizeof(struct dvb_frontend_ops));
534 ret = dvb_register_frontend(&pd_dvb->dvb_adap, &pd_dvb->dvb_fe);
535 if (ret < 0)
536 goto error2;
537
538 /* register demux device */
539 dvbdemux = &pd_dvb->demux;
540 dvbdemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
541 dvbdemux->priv = pd_dvb;
542 dvbdemux->feednum = dvbdemux->filternum = 64;
543 dvbdemux->start_feed = pd_start_feed;
544 dvbdemux->stop_feed = pd_stop_feed;
545 dvbdemux->write_to_decoder = NULL;
546
547 ret = dvb_dmx_init(dvbdemux);
548 if (ret < 0)
549 goto error3;
550
551 pd_dvb->dmxdev.filternum = pd_dvb->demux.filternum;
552 pd_dvb->dmxdev.demux = &pd_dvb->demux.dmx;
553 pd_dvb->dmxdev.capabilities = 0;
554
555 ret = dvb_dmxdev_init(&pd_dvb->dmxdev, &pd_dvb->dvb_adap);
556 if (ret < 0)
557 goto error3;
558 return 0;
559
560error3:
561 dvb_unregister_frontend(&pd_dvb->dvb_fe);
562error2:
563 dvb_unregister_adapter(&pd_dvb->dvb_adap);
564error1:
565 return ret;
566}
567
568void pd_dvb_usb_device_exit(struct poseidon *pd)
569{
570 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
571
572 while (atomic_read(&pd_dvb->users) != 0
573 || atomic_read(&pd_dvb->active_feed) != 0) {
574 set_current_state(TASK_INTERRUPTIBLE);
575 schedule_timeout(HZ);
576 }
577 dvb_dmxdev_release(&pd_dvb->dmxdev);
578 dvb_unregister_frontend(&pd_dvb->dvb_fe);
579 dvb_unregister_adapter(&pd_dvb->dvb_adap);
580 pd_dvb_usb_device_cleanup(pd);
581}
582
583void pd_dvb_usb_device_cleanup(struct poseidon *pd)
584{
585 struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
586
587 dvb_urb_cleanup(pd_dvb);
588}
589
590int pd_dvb_get_adapter_num(struct pd_dvb_adapter *pd_dvb)
591{
592 return pd_dvb->dvb_adap.num;
593}
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
new file mode 100644
index 000000000000..6df93803e3a8
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -0,0 +1,566 @@
1/*
2 * device driver for Telegent tlg2300 based TV cards
3 *
4 * Author :
5 * Kang Yong <kangyong@telegent.com>
6 * Zhang Xiaobing <xbzhang@telegent.com>
7 * Huang Shijie <zyziii@telegent.com> or <shijie8@gmail.com>
8 *
9 * (c) 2009 Telegent Systems
10 * (c) 2010 Telegent Systems
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 */
26
27#include <linux/version.h>
28#include <linux/kernel.h>
29#include <linux/errno.h>
30#include <linux/init.h>
31#include <linux/slab.h>
32#include <linux/module.h>
33#include <linux/kref.h>
34#include <linux/suspend.h>
35#include <linux/usb/quirks.h>
36#include <linux/ctype.h>
37#include <linux/string.h>
38#include <linux/types.h>
39#include <linux/firmware.h>
40#include <linux/smp_lock.h>
41
42#include "vendorcmds.h"
43#include "pd-common.h"
44
45#define VENDOR_ID 0x1B24
46#define PRODUCT_ID 0x4001
47static struct usb_device_id id_table[] = {
48 { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 0) },
49 { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 1) },
50 { },
51};
52MODULE_DEVICE_TABLE(usb, id_table);
53
54int debug_mode;
55module_param(debug_mode, int, 0644);
56MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose");
57
58const char *firmware_name = "tlg2300_firmware.bin";
59struct usb_driver poseidon_driver;
60static LIST_HEAD(pd_device_list);
61
62/*
63 * send set request to USB firmware.
64 */
65s32 send_set_req(struct poseidon *pd, u8 cmdid, s32 param, s32 *cmd_status)
66{
67 s32 ret;
68 s8 data[32] = {};
69 u16 lower_16, upper_16;
70
71 if (pd->state & POSEIDON_STATE_DISCONNECT)
72 return -ENODEV;
73
74 mdelay(30);
75
76 if (param == 0) {
77 upper_16 = lower_16 = 0;
78 } else {
79 /* send 32 bit param as two 16 bit param,little endian */
80 lower_16 = (unsigned short)(param & 0xffff);
81 upper_16 = (unsigned short)((param >> 16) & 0xffff);
82 }
83 ret = usb_control_msg(pd->udev,
84 usb_rcvctrlpipe(pd->udev, 0),
85 REQ_SET_CMD | cmdid,
86 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
87 lower_16,
88 upper_16,
89 &data,
90 sizeof(*cmd_status),
91 USB_CTRL_GET_TIMEOUT);
92
93 if (!ret) {
94 return -ENXIO;
95 } else {
96 /* 1st 4 bytes into cmd_status */
97 memcpy((char *)cmd_status, &(data[0]), sizeof(*cmd_status));
98 }
99 return 0;
100}
101
102/*
103 * send get request to Poseidon firmware.
104 */
105s32 send_get_req(struct poseidon *pd, u8 cmdid, s32 param,
106 void *buf, s32 *cmd_status, s32 datalen)
107{
108 s32 ret;
109 s8 data[128] = {};
110 u16 lower_16, upper_16;
111
112 if (pd->state & POSEIDON_STATE_DISCONNECT)
113 return -ENODEV;
114
115 mdelay(30);
116 if (param == 0) {
117 upper_16 = lower_16 = 0;
118 } else {
119 /*send 32 bit param as two 16 bit param, little endian */
120 lower_16 = (unsigned short)(param & 0xffff);
121 upper_16 = (unsigned short)((param >> 16) & 0xffff);
122 }
123 ret = usb_control_msg(pd->udev,
124 usb_rcvctrlpipe(pd->udev, 0),
125 REQ_GET_CMD | cmdid,
126 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
127 lower_16,
128 upper_16,
129 &data,
130 (datalen + sizeof(*cmd_status)),
131 USB_CTRL_GET_TIMEOUT);
132
133 if (ret < 0) {
134 return -ENXIO;
135 } else {
136 /* 1st 4 bytes into cmd_status, remaining data into cmd_data */
137 memcpy((char *)cmd_status, &data[0], sizeof(*cmd_status));
138 memcpy((char *)buf, &data[sizeof(*cmd_status)], datalen);
139 }
140 return 0;
141}
142
143static int pm_notifier_block(struct notifier_block *nb,
144 unsigned long event, void *dummy)
145{
146 struct poseidon *pd = NULL;
147 struct list_head *node, *next;
148
149 switch (event) {
150 case PM_POST_HIBERNATION:
151 list_for_each_safe(node, next, &pd_device_list) {
152 struct usb_device *udev;
153 struct usb_interface *iface;
154 int rc = 0;
155
156 pd = container_of(node, struct poseidon, device_list);
157 udev = pd->udev;
158 iface = pd->interface;
159
160 /* It will cause the system to reload the firmware */
161 rc = usb_lock_device_for_reset(udev, iface);
162 if (rc >= 0) {
163 usb_reset_device(udev);
164 usb_unlock_device(udev);
165 }
166 }
167 break;
168 default:
169 break;
170 }
171 log("event :%ld\n", event);
172 return 0;
173}
174
175static struct notifier_block pm_notifer = {
176 .notifier_call = pm_notifier_block,
177};
178
179int set_tuner_mode(struct poseidon *pd, unsigned char mode)
180{
181 s32 ret, cmd_status;
182
183 if (pd->state & POSEIDON_STATE_DISCONNECT)
184 return -ENODEV;
185
186 ret = send_set_req(pd, TUNE_MODE_SELECT, mode, &cmd_status);
187 if (ret || cmd_status)
188 return -ENXIO;
189 return 0;
190}
191
192enum tlg__analog_audio_standard get_audio_std(s32 mode, s32 country_code)
193{
194 s32 nicam[] = {27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64,
195 65, 86, 351, 352, 353, 354, 358, 372, 852, 972};
196 s32 btsc[] = {1, 52, 54, 55, 886};
197 s32 eiaj[] = {81};
198 s32 i;
199
200 if (mode == TLG_MODE_FM_RADIO) {
201 if (country_code == 1)
202 return TLG_TUNE_ASTD_FM_US;
203 else
204 return TLG_TUNE_ASTD_FM_EUR;
205 } else if (mode == TLG_MODE_ANALOG_TV_UNCOMP) {
206 for (i = 0; i < sizeof(nicam) / sizeof(s32); i++) {
207 if (country_code == nicam[i])
208 return TLG_TUNE_ASTD_NICAM;
209 }
210
211 for (i = 0; i < sizeof(btsc) / sizeof(s32); i++) {
212 if (country_code == btsc[i])
213 return TLG_TUNE_ASTD_BTSC;
214 }
215
216 for (i = 0; i < sizeof(eiaj) / sizeof(s32); i++) {
217 if (country_code == eiaj[i])
218 return TLG_TUNE_ASTD_EIAJ;
219 }
220
221 return TLG_TUNE_ASTD_A2;
222 } else {
223 return TLG_TUNE_ASTD_NONE;
224 }
225}
226
227void poseidon_delete(struct kref *kref)
228{
229 struct poseidon *pd = container_of(kref, struct poseidon, kref);
230
231 if (!pd)
232 return;
233 list_del_init(&pd->device_list);
234
235 pd_dvb_usb_device_cleanup(pd);
236 /* clean_audio_data(&pd->audio_data);*/
237
238 if (pd->udev) {
239 usb_put_dev(pd->udev);
240 pd->udev = NULL;
241 }
242 if (pd->interface) {
243 usb_put_intf(pd->interface);
244 pd->interface = NULL;
245 }
246 kfree(pd);
247 log();
248}
249
250static int firmware_download(struct usb_device *udev)
251{
252 int ret = 0, actual_length;
253 const struct firmware *fw = NULL;
254 void *fwbuf = NULL;
255 size_t fwlength = 0, offset;
256 size_t max_packet_size;
257
258 ret = request_firmware(&fw, firmware_name, &udev->dev);
259 if (ret) {
260 log("download err : %d", ret);
261 return ret;
262 }
263
264 fwlength = fw->size;
265
266 fwbuf = kzalloc(fwlength, GFP_KERNEL);
267 if (!fwbuf) {
268 ret = -ENOMEM;
269 goto out;
270 }
271 memcpy(fwbuf, fw->data, fwlength);
272
273 max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
274 log("\t\t download size : %d", (int)max_packet_size);
275
276 for (offset = 0; offset < fwlength; offset += max_packet_size) {
277 actual_length = 0;
278 ret = usb_bulk_msg(udev,
279 usb_sndbulkpipe(udev, 0x01), /* ep 1 */
280 fwbuf + offset,
281 min(max_packet_size, fwlength - offset),
282 &actual_length,
283 HZ * 10);
284 if (ret)
285 break;
286 }
287 kfree(fwbuf);
288out:
289 release_firmware(fw);
290 return ret;
291}
292
293#ifdef CONFIG_PM
294/* one-to-one map : poseidon{} <----> usb_device{}'s port */
295static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
296{
297 pd->portnum = udev->portnum;
298}
299
300static inline int get_autopm_ref(struct poseidon *pd)
301{
302 return pd->video_data.users + pd->vbi_data.users + pd->audio.users
303 + atomic_read(&pd->dvb_data.users) + pd->radio_data.users;
304}
305
306/* fixup something for poseidon */
307static inline struct poseidon *fixup(struct poseidon *pd)
308{
309 int count;
310
311 /* old udev and interface have gone, so put back reference . */
312 count = get_autopm_ref(pd);
313 log("count : %d, ref count : %d", count, get_pm_count(pd));
314 while (count--)
315 usb_autopm_put_interface(pd->interface);
316 /*usb_autopm_set_interface(pd->interface); */
317
318 usb_put_dev(pd->udev);
319 usb_put_intf(pd->interface);
320 log("event : %d\n", pd->msg.event);
321 return pd;
322}
323
324static struct poseidon *find_old_poseidon(struct usb_device *udev)
325{
326 struct poseidon *pd;
327
328 list_for_each_entry(pd, &pd_device_list, device_list) {
329 if (pd->portnum == udev->portnum && in_hibernation(pd))
330 return fixup(pd);
331 }
332 return NULL;
333}
334
335/* Is the card working now ? */
336static inline int is_working(struct poseidon *pd)
337{
338 return get_pm_count(pd) > 0;
339}
340
341static inline struct poseidon *get_pd(struct usb_interface *intf)
342{
343 return usb_get_intfdata(intf);
344}
345
346static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg)
347{
348 struct poseidon *pd = get_pd(intf);
349
350 if (!pd)
351 return 0;
352 if (!is_working(pd)) {
353 if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) {
354 pd->msg.event = PM_EVENT_AUTO_SUSPEND;
355 pd->pm_resume = NULL; /* a good guard */
356 printk(KERN_DEBUG "\n\t+ TLG2300 auto suspend +\n\n");
357 }
358 return 0;
359 }
360 pd->msg = msg; /* save it here */
361 logpm(pd);
362 return pd->pm_suspend ? pd->pm_suspend(pd) : 0;
363}
364
365static int poseidon_resume(struct usb_interface *intf)
366{
367 struct poseidon *pd = get_pd(intf);
368
369 if (!pd)
370 return 0;
371 printk(KERN_DEBUG "\n\t ++ TLG2300 resume ++\n\n");
372
373 if (!is_working(pd)) {
374 if (PM_EVENT_AUTO_SUSPEND == pd->msg.event)
375 pd->msg = PMSG_ON;
376 return 0;
377 }
378 if (in_hibernation(pd)) {
379 logpm(pd);
380 return 0;
381 }
382 logpm(pd);
383 return pd->pm_resume ? pd->pm_resume(pd) : 0;
384}
385
386static void hibernation_resume(struct work_struct *w)
387{
388 struct poseidon *pd = container_of(w, struct poseidon, pm_work);
389 int count;
390
391 pd->msg.event = 0; /* clear it here */
392 pd->state &= ~POSEIDON_STATE_DISCONNECT;
393
394 /* set the new interface's reference */
395 count = get_autopm_ref(pd);
396 while (count--)
397 usb_autopm_get_interface(pd->interface);
398
399 /* resume the context */
400 logpm(pd);
401 if (pd->pm_resume)
402 pd->pm_resume(pd);
403}
404#endif
405
406static bool check_firmware(struct usb_device *udev, int *down_firmware)
407{
408 void *buf;
409 int ret;
410 struct cmd_firmware_vers_s *cmd_firm;
411
412 buf = kzalloc(sizeof(*cmd_firm) + sizeof(u32), GFP_KERNEL);
413 if (!buf)
414 return -ENOMEM;
415 ret = usb_control_msg(udev,
416 usb_rcvctrlpipe(udev, 0),
417 REQ_GET_CMD | GET_FW_ID,
418 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
419 0,
420 0,
421 buf,
422 sizeof(*cmd_firm) + sizeof(u32),
423 USB_CTRL_GET_TIMEOUT);
424 kfree(buf);
425
426 if (ret < 0) {
427 *down_firmware = 1;
428 return firmware_download(udev);
429 }
430 return ret;
431}
432
433static int poseidon_probe(struct usb_interface *interface,
434 const struct usb_device_id *id)
435{
436 struct usb_device *udev = interface_to_usbdev(interface);
437 struct poseidon *pd = NULL;
438 int ret = 0;
439 int new_one = 0;
440
441 /* download firmware */
442 check_firmware(udev, &ret);
443 if (ret)
444 return 0;
445
446 /* Do I recovery from the hibernate ? */
447 pd = find_old_poseidon(udev);
448 if (!pd) {
449 pd = kzalloc(sizeof(*pd), GFP_KERNEL);
450 if (!pd)
451 return -ENOMEM;
452 kref_init(&pd->kref);
453 set_map_flags(pd, udev);
454 new_one = 1;
455 }
456
457 pd->udev = usb_get_dev(udev);
458 pd->interface = usb_get_intf(interface);
459 usb_set_intfdata(interface, pd);
460
461 if (new_one) {
462 struct device *dev = &interface->dev;
463
464 logpm(pd);
465 pd->country_code = 86;
466 mutex_init(&pd->lock);
467
468 /* register v4l2 device */
469 snprintf(pd->v4l2_dev.name, sizeof(pd->v4l2_dev.name), "%s %s",
470 dev->driver->name, dev_name(dev));
471 ret = v4l2_device_register(NULL, &pd->v4l2_dev);
472
473 /* register devices in directory /dev */
474 ret = pd_video_init(pd);
475 poseidon_audio_init(pd);
476 poseidon_fm_init(pd);
477 pd_dvb_usb_device_init(pd);
478
479 INIT_LIST_HEAD(&pd->device_list);
480 list_add_tail(&pd->device_list, &pd_device_list);
481 }
482
483 device_init_wakeup(&udev->dev, 1);
484#ifdef CONFIG_PM
485 pd->udev->autosuspend_disabled = 0;
486 pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
487
488 if (in_hibernation(pd)) {
489 INIT_WORK(&pd->pm_work, hibernation_resume);
490 schedule_work(&pd->pm_work);
491 }
492#endif
493 return 0;
494}
495
496static void poseidon_disconnect(struct usb_interface *interface)
497{
498 struct poseidon *pd = get_pd(interface);
499
500 if (!pd)
501 return;
502 logpm(pd);
503 if (in_hibernation(pd))
504 return;
505
506 mutex_lock(&pd->lock);
507 pd->state |= POSEIDON_STATE_DISCONNECT;
508 mutex_unlock(&pd->lock);
509
510 /* stop urb transferring */
511 stop_all_video_stream(pd);
512 dvb_stop_streaming(&pd->dvb_data);
513
514 /*unregister v4l2 device */
515 v4l2_device_unregister(&pd->v4l2_dev);
516
517 lock_kernel();
518 {
519 pd_dvb_usb_device_exit(pd);
520 poseidon_fm_exit(pd);
521
522 poseidon_audio_free(pd);
523 pd_video_exit(pd);
524 }
525 unlock_kernel();
526
527 usb_set_intfdata(interface, NULL);
528 kref_put(&pd->kref, poseidon_delete);
529}
530
531struct usb_driver poseidon_driver = {
532 .name = "poseidon",
533 .probe = poseidon_probe,
534 .disconnect = poseidon_disconnect,
535 .id_table = id_table,
536#ifdef CONFIG_PM
537 .suspend = poseidon_suspend,
538 .resume = poseidon_resume,
539#endif
540 .supports_autosuspend = 1,
541};
542
543static int __init poseidon_init(void)
544{
545 int ret;
546
547 ret = usb_register(&poseidon_driver);
548 if (ret)
549 return ret;
550 register_pm_notifier(&pm_notifer);
551 return ret;
552}
553
554static void __exit poseidon_exit(void)
555{
556 log();
557 unregister_pm_notifier(&pm_notifer);
558 usb_deregister(&poseidon_driver);
559}
560
561module_init(poseidon_init);
562module_exit(poseidon_exit);
563
564MODULE_AUTHOR("Telegent Systems");
565MODULE_DESCRIPTION("For tlg2300-based USB device ");
566MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tlg2300/pd-radio.c b/drivers/media/video/tlg2300/pd-radio.c
new file mode 100644
index 000000000000..bdbb0c11b3a9
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-radio.c
@@ -0,0 +1,351 @@
1#include <linux/init.h>
2#include <linux/list.h>
3#include <linux/module.h>
4#include <linux/kernel.h>
5#include <linux/bitmap.h>
6#include <linux/usb.h>
7#include <linux/i2c.h>
8#include <media/v4l2-dev.h>
9#include <linux/version.h>
10#include <linux/mm.h>
11#include <linux/mutex.h>
12#include <media/v4l2-ioctl.h>
13#include <linux/sched.h>
14
15#include "pd-common.h"
16#include "vendorcmds.h"
17
18static int set_frequency(struct poseidon *p, __u32 frequency);
19static int poseidon_fm_close(struct file *filp);
20static int poseidon_fm_open(struct file *filp);
21
22#define TUNER_FREQ_MIN_FM 76000000
23#define TUNER_FREQ_MAX_FM 108000000
24
25static int poseidon_check_mode_radio(struct poseidon *p)
26{
27 int ret, radiomode;
28 u32 status;
29
30 set_current_state(TASK_INTERRUPTIBLE);
31 schedule_timeout(HZ/2);
32 ret = usb_set_interface(p->udev, 0, BULK_ALTERNATE_IFACE);
33 if (ret < 0)
34 goto out;
35
36 ret = set_tuner_mode(p, TLG_MODE_FM_RADIO);
37 if (ret != 0)
38 goto out;
39
40 ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status);
41 radiomode = get_audio_std(TLG_MODE_FM_RADIO, p->country_code);
42 ret = send_set_req(p, TUNER_AUD_ANA_STD, radiomode, &status);
43 ret |= send_set_req(p, TUNER_AUD_MODE,
44 TLG_TUNE_TVAUDIO_MODE_STEREO, &status);
45 ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL,
46 ATV_AUDIO_RATE_48K, &status);
47 ret |= send_set_req(p, TUNE_FREQ_SELECT, TUNER_FREQ_MIN_FM, &status);
48out:
49 return ret;
50}
51
52#ifdef CONFIG_PM
53static int pm_fm_suspend(struct poseidon *p)
54{
55 logpm(p);
56 pm_alsa_suspend(p);
57 usb_set_interface(p->udev, 0, 0);
58 msleep(300);
59 return 0;
60}
61
62static int pm_fm_resume(struct poseidon *p)
63{
64 logpm(p);
65 poseidon_check_mode_radio(p);
66 set_frequency(p, p->radio_data.fm_freq);
67 pm_alsa_resume(p);
68 return 0;
69}
70#endif
71
72static int poseidon_fm_open(struct file *filp)
73{
74 struct video_device *vfd = video_devdata(filp);
75 struct poseidon *p = video_get_drvdata(vfd);
76 int ret = 0;
77
78 if (!p)
79 return -1;
80
81 mutex_lock(&p->lock);
82 if (p->state & POSEIDON_STATE_DISCONNECT) {
83 ret = -ENODEV;
84 goto out;
85 }
86
87 if (p->state && !(p->state & POSEIDON_STATE_FM)) {
88 ret = -EBUSY;
89 goto out;
90 }
91
92 usb_autopm_get_interface(p->interface);
93 if (0 == p->state) {
94 p->country_code = country_code;
95 set_debug_mode(vfd, debug_mode);
96
97 ret = poseidon_check_mode_radio(p);
98 if (ret < 0) {
99 usb_autopm_put_interface(p->interface);
100 goto out;
101 }
102 p->state |= POSEIDON_STATE_FM;
103 }
104 p->radio_data.users++;
105 kref_get(&p->kref);
106 filp->private_data = p;
107out:
108 mutex_unlock(&p->lock);
109 return ret;
110}
111
112static int poseidon_fm_close(struct file *filp)
113{
114 struct poseidon *p = filp->private_data;
115 struct radio_data *fm = &p->radio_data;
116 uint32_t status;
117
118 mutex_lock(&p->lock);
119 fm->users--;
120 if (0 == fm->users)
121 p->state &= ~POSEIDON_STATE_FM;
122
123 if (fm->is_radio_streaming && filp == p->file_for_stream) {
124 fm->is_radio_streaming = 0;
125 send_set_req(p, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, &status);
126 }
127 usb_autopm_put_interface(p->interface);
128 mutex_unlock(&p->lock);
129
130 kref_put(&p->kref, poseidon_delete);
131 filp->private_data = NULL;
132 return 0;
133}
134
135static int vidioc_querycap(struct file *file, void *priv,
136 struct v4l2_capability *v)
137{
138 struct poseidon *p = file->private_data;
139
140 strlcpy(v->driver, "tele-radio", sizeof(v->driver));
141 strlcpy(v->card, "Telegent Poseidon", sizeof(v->card));
142 usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info));
143 v->version = KERNEL_VERSION(0, 0, 1);
144 v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
145 return 0;
146}
147
148static const struct v4l2_file_operations poseidon_fm_fops = {
149 .owner = THIS_MODULE,
150 .open = poseidon_fm_open,
151 .release = poseidon_fm_close,
152 .ioctl = video_ioctl2,
153};
154
155int tlg_fm_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
156{
157 struct tuner_fm_sig_stat_s fm_stat = {};
158 int ret, status, count = 5;
159 struct poseidon *p = file->private_data;
160
161 if (vt->index != 0)
162 return -EINVAL;
163
164 vt->type = V4L2_TUNER_RADIO;
165 vt->capability = V4L2_TUNER_CAP_STEREO;
166 vt->rangelow = TUNER_FREQ_MIN_FM / 62500;
167 vt->rangehigh = TUNER_FREQ_MAX_FM / 62500;
168 vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
169 vt->audmode = V4L2_TUNER_MODE_STEREO;
170 vt->signal = 0;
171 vt->afc = 0;
172
173 mutex_lock(&p->lock);
174 ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
175 &fm_stat, &status, sizeof(fm_stat));
176
177 while (fm_stat.sig_lock_busy && count-- && !ret) {
178 set_current_state(TASK_INTERRUPTIBLE);
179 schedule_timeout(HZ);
180
181 ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
182 &fm_stat, &status, sizeof(fm_stat));
183 }
184 mutex_unlock(&p->lock);
185
186 if (ret || status) {
187 vt->signal = 0;
188 } else if ((fm_stat.sig_present || fm_stat.sig_locked)
189 && fm_stat.sig_strength == 0) {
190 vt->signal = 0xffff;
191 } else
192 vt->signal = (fm_stat.sig_strength * 255 / 10) << 8;
193
194 return 0;
195}
196
197int fm_get_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
198{
199 struct poseidon *p = file->private_data;
200
201 argp->frequency = p->radio_data.fm_freq;
202 return 0;
203}
204
205static int set_frequency(struct poseidon *p, __u32 frequency)
206{
207 __u32 freq ;
208 int ret, status, radiomode;
209
210 mutex_lock(&p->lock);
211
212 radiomode = get_audio_std(TLG_MODE_FM_RADIO, p->country_code);
213 /*NTSC 8,PAL 2 */
214 ret = send_set_req(p, TUNER_AUD_ANA_STD, radiomode, &status);
215
216 freq = (frequency * 125) * 500 / 1000;/* kHZ */
217 if (freq < TUNER_FREQ_MIN_FM/1000 || freq > TUNER_FREQ_MAX_FM/1000) {
218 ret = -EINVAL;
219 goto error;
220 }
221
222 ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status);
223 if (ret < 0)
224 goto error ;
225 ret = send_set_req(p, TAKE_REQUEST, 0, &status);
226
227 set_current_state(TASK_INTERRUPTIBLE);
228 schedule_timeout(HZ/4);
229 if (!p->radio_data.is_radio_streaming) {
230 ret = send_set_req(p, TAKE_REQUEST, 0, &status);
231 ret = send_set_req(p, PLAY_SERVICE,
232 TLG_TUNE_PLAY_SVC_START, &status);
233 p->radio_data.is_radio_streaming = 1;
234 }
235 p->radio_data.fm_freq = frequency;
236error:
237 mutex_unlock(&p->lock);
238 return ret;
239}
240
241int fm_set_freq(struct file *file, void *priv, struct v4l2_frequency *argp)
242{
243 struct poseidon *p = file->private_data;
244
245 p->file_for_stream = file;
246#ifdef CONFIG_PM
247 p->pm_suspend = pm_fm_suspend;
248 p->pm_resume = pm_fm_resume;
249#endif
250 return set_frequency(p, argp->frequency);
251}
252
253int tlg_fm_vidioc_g_ctrl(struct file *file, void *priv,
254 struct v4l2_control *arg)
255{
256 return 0;
257}
258
259int tlg_fm_vidioc_exts_ctrl(struct file *file, void *fh,
260 struct v4l2_ext_controls *a)
261{
262 return 0;
263}
264
265int tlg_fm_vidioc_s_ctrl(struct file *file, void *priv,
266 struct v4l2_control *arg)
267{
268 return 0;
269}
270
271int tlg_fm_vidioc_queryctrl(struct file *file, void *priv,
272 struct v4l2_queryctrl *arg)
273{
274 arg->minimum = 0;
275 arg->maximum = 65535;
276 return 0;
277}
278
279static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *vt)
280{
281 return vt->index > 0 ? -EINVAL : 0;
282}
283static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *va)
284{
285 return (va->index != 0) ? -EINVAL : 0;
286}
287
288static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
289{
290 a->index = 0;
291 a->mode = 0;
292 a->capability = V4L2_AUDCAP_STEREO;
293 strcpy(a->name, "Radio");
294 return 0;
295}
296
297static int vidioc_s_input(struct file *filp, void *priv, u32 i)
298{
299 return (i != 0) ? -EINVAL : 0;
300}
301
302static int vidioc_g_input(struct file *filp, void *priv, u32 *i)
303{
304 return (*i != 0) ? -EINVAL : 0;
305}
306
307static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = {
308 .vidioc_querycap = vidioc_querycap,
309 .vidioc_g_audio = vidioc_g_audio,
310 .vidioc_s_audio = vidioc_s_audio,
311 .vidioc_g_input = vidioc_g_input,
312 .vidioc_s_input = vidioc_s_input,
313 .vidioc_queryctrl = tlg_fm_vidioc_queryctrl,
314 .vidioc_g_ctrl = tlg_fm_vidioc_g_ctrl,
315 .vidioc_s_ctrl = tlg_fm_vidioc_s_ctrl,
316 .vidioc_s_ext_ctrls = tlg_fm_vidioc_exts_ctrl,
317 .vidioc_s_tuner = vidioc_s_tuner,
318 .vidioc_g_tuner = tlg_fm_vidioc_g_tuner,
319 .vidioc_g_frequency = fm_get_freq,
320 .vidioc_s_frequency = fm_set_freq,
321};
322
323static struct video_device poseidon_fm_template = {
324 .name = "Telegent-Radio",
325 .fops = &poseidon_fm_fops,
326 .minor = -1,
327 .release = video_device_release,
328 .ioctl_ops = &poseidon_fm_ioctl_ops,
329};
330
331int poseidon_fm_init(struct poseidon *p)
332{
333 struct video_device *fm_dev;
334
335 fm_dev = vdev_init(p, &poseidon_fm_template);
336 if (fm_dev == NULL)
337 return -1;
338
339 if (video_register_device(fm_dev, VFL_TYPE_RADIO, -1) < 0) {
340 video_device_release(fm_dev);
341 return -1;
342 }
343 p->radio_data.fm_dev = fm_dev;
344 return 0;
345}
346
347int poseidon_fm_exit(struct poseidon *p)
348{
349 destroy_video_device(&p->radio_data.fm_dev);
350 return 0;
351}
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
new file mode 100644
index 000000000000..5f0300ac465c
--- /dev/null
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -0,0 +1,1648 @@
1#include <linux/fs.h>
2#include <linux/vmalloc.h>
3#include <linux/videodev2.h>
4#include <linux/usb.h>
5#include <linux/mm.h>
6#include <linux/sched.h>
7
8#include <media/v4l2-ioctl.h>
9#include <media/v4l2-dev.h>
10
11#include "pd-common.h"
12#include "vendorcmds.h"
13
14static int pm_video_suspend(struct poseidon *pd);
15static int pm_video_resume(struct poseidon *pd);
16static void iso_bubble_handler(struct work_struct *w);
17
18int country_code = 86;
19module_param(country_code, int, 0644);
20MODULE_PARM_DESC(country_code, "country code (e.g China is 86)");
21
22int usb_transfer_mode;
23module_param(usb_transfer_mode, int, 0644);
24MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous");
25
26static const struct poseidon_format poseidon_formats[] = {
27 { "YUV 422", V4L2_PIX_FMT_YUYV, 16, 0},
28 { "RGB565", V4L2_PIX_FMT_RGB565, 16, 0},
29};
30
31static const struct poseidon_tvnorm poseidon_tvnorms[] = {
32 { V4L2_STD_PAL_D, "PAL-D", TLG_TUNE_VSTD_PAL_D },
33 { V4L2_STD_PAL_B, "PAL-B", TLG_TUNE_VSTD_PAL_B },
34 { V4L2_STD_PAL_G, "PAL-G", TLG_TUNE_VSTD_PAL_G },
35 { V4L2_STD_PAL_H, "PAL-H", TLG_TUNE_VSTD_PAL_H },
36 { V4L2_STD_PAL_I, "PAL-I", TLG_TUNE_VSTD_PAL_I },
37 { V4L2_STD_PAL_M, "PAL-M", TLG_TUNE_VSTD_PAL_M },
38 { V4L2_STD_PAL_N, "PAL-N", TLG_TUNE_VSTD_PAL_N_COMBO },
39 { V4L2_STD_PAL_Nc, "PAL-Nc", TLG_TUNE_VSTD_PAL_N_COMBO },
40 { V4L2_STD_NTSC_M, "NTSC-M", TLG_TUNE_VSTD_NTSC_M },
41 { V4L2_STD_NTSC_M_JP, "NTSC-JP", TLG_TUNE_VSTD_NTSC_M_J },
42 { V4L2_STD_SECAM_B, "SECAM-B", TLG_TUNE_VSTD_SECAM_B },
43 { V4L2_STD_SECAM_D, "SECAM-D", TLG_TUNE_VSTD_SECAM_D },
44 { V4L2_STD_SECAM_G, "SECAM-G", TLG_TUNE_VSTD_SECAM_G },
45 { V4L2_STD_SECAM_H, "SECAM-H", TLG_TUNE_VSTD_SECAM_H },
46 { V4L2_STD_SECAM_K, "SECAM-K", TLG_TUNE_VSTD_SECAM_K },
47 { V4L2_STD_SECAM_K1, "SECAM-K1", TLG_TUNE_VSTD_SECAM_K1 },
48 { V4L2_STD_SECAM_L, "SECAM-L", TLG_TUNE_VSTD_SECAM_L },
49 { V4L2_STD_SECAM_LC, "SECAM-LC", TLG_TUNE_VSTD_SECAM_L1 },
50};
51static const unsigned int POSEIDON_TVNORMS = ARRAY_SIZE(poseidon_tvnorms);
52
53struct pd_audio_mode {
54 u32 tlg_audio_mode;
55 u32 v4l2_audio_sub;
56 u32 v4l2_audio_mode;
57};
58
59static const struct pd_audio_mode pd_audio_modes[] = {
60 { TLG_TUNE_TVAUDIO_MODE_MONO, V4L2_TUNER_SUB_MONO,
61 V4L2_TUNER_MODE_MONO },
62 { TLG_TUNE_TVAUDIO_MODE_STEREO, V4L2_TUNER_SUB_STEREO,
63 V4L2_TUNER_MODE_STEREO },
64 { TLG_TUNE_TVAUDIO_MODE_LANG_A, V4L2_TUNER_SUB_LANG1,
65 V4L2_TUNER_MODE_LANG1 },
66 { TLG_TUNE_TVAUDIO_MODE_LANG_B, V4L2_TUNER_SUB_LANG2,
67 V4L2_TUNER_MODE_LANG2 },
68 { TLG_TUNE_TVAUDIO_MODE_LANG_C, V4L2_TUNER_SUB_LANG1,
69 V4L2_TUNER_MODE_LANG1_LANG2 }
70};
71static const unsigned int POSEIDON_AUDIOMODS = ARRAY_SIZE(pd_audio_modes);
72
73struct pd_input {
74 char *name;
75 uint32_t tlg_src;
76};
77
78static const struct pd_input pd_inputs[] = {
79 { "TV Antenna", TLG_SIG_SRC_ANTENNA },
80 { "TV Cable", TLG_SIG_SRC_CABLE },
81 { "TV SVideo", TLG_SIG_SRC_SVIDEO },
82 { "TV Composite", TLG_SIG_SRC_COMPOSITE }
83};
84static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs);
85
86struct poseidon_control {
87 struct v4l2_queryctrl v4l2_ctrl;
88 enum cmd_custom_param_id vc_id;
89};
90
91static struct poseidon_control controls[] = {
92 {
93 { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER,
94 "brightness", 0, 10000, 1, 100, 0, },
95 CUST_PARM_ID_BRIGHTNESS_CTRL
96 },
97
98 {
99 { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER,
100 "contrast", 0, 10000, 1, 100, 0, },
101 CUST_PARM_ID_CONTRAST_CTRL,
102 },
103
104 {
105 { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER,
106 "hue", 0, 10000, 1, 100, 0, },
107 CUST_PARM_ID_HUE_CTRL,
108 },
109
110 {
111 { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER,
112 "saturation", 0, 10000, 1, 100, 0, },
113 CUST_PARM_ID_SATURATION_CTRL,
114 },
115};
116
117static int vidioc_querycap(struct file *file, void *fh,
118 struct v4l2_capability *cap)
119{
120 struct front_face *front = fh;
121 struct poseidon *p = front->pd;
122
123 logs(front);
124
125 strcpy(cap->driver, "tele-video");
126 strcpy(cap->card, "Telegent Poseidon");
127 usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info));
128 cap->version = KERNEL_VERSION(0, 0, 1);
129 cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
130 V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
131 V4L2_CAP_READWRITE | V4L2_CAP_VBI_CAPTURE;
132 return 0;
133}
134
135/*====================================================================*/
136static void init_copy(struct video_data *video, bool index)
137{
138 struct front_face *front = video->front;
139
140 video->field_count = index;
141 video->lines_copied = 0;
142 video->prev_left = 0 ;
143 video->dst = (char *)videobuf_to_vmalloc(front->curr_frame)
144 + index * video->lines_size;
145 video->vbi->copied = 0; /* set it here */
146}
147
148static bool get_frame(struct front_face *front, int *need_init)
149{
150 struct videobuf_buffer *vb = front->curr_frame;
151
152 if (vb)
153 return true;
154
155 spin_lock(&front->queue_lock);
156 if (!list_empty(&front->active)) {
157 vb = list_entry(front->active.next,
158 struct videobuf_buffer, queue);
159 if (need_init)
160 *need_init = 1;
161 front->curr_frame = vb;
162 list_del_init(&vb->queue);
163 }
164 spin_unlock(&front->queue_lock);
165
166 return !!vb;
167}
168
169/* check if the video's buffer is ready */
170static bool get_video_frame(struct front_face *front, struct video_data *video)
171{
172 int need_init = 0;
173 bool ret = true;
174
175 ret = get_frame(front, &need_init);
176 if (ret && need_init)
177 init_copy(video, 0);
178 return ret;
179}
180
181static void submit_frame(struct front_face *front)
182{
183 struct videobuf_buffer *vb = front->curr_frame;
184
185 if (vb == NULL)
186 return;
187
188 front->curr_frame = NULL;
189 vb->state = VIDEOBUF_DONE;
190 vb->field_count++;
191 do_gettimeofday(&vb->ts);
192
193 wake_up(&vb->done);
194}
195
196/*
197 * A frame is composed of two fields. If we receive all the two fields,
198 * call the submit_frame() to submit the whole frame to applications.
199 */
200static void end_field(struct video_data *video)
201{
202 /* logs(video->front); */
203 if (1 == video->field_count)
204 submit_frame(video->front);
205 else
206 init_copy(video, 1);
207}
208
209static void copy_video_data(struct video_data *video, char *src,
210 unsigned int count)
211{
212#define copy_data(len) \
213 do { \
214 if (++video->lines_copied > video->lines_per_field) \
215 goto overflow; \
216 memcpy(video->dst, src, len);\
217 video->dst += len + video->lines_size; \
218 src += len; \
219 count -= len; \
220 } while (0)
221
222 while (count && count >= video->lines_size) {
223 if (video->prev_left) {
224 copy_data(video->prev_left);
225 video->prev_left = 0;
226 continue;
227 }
228 copy_data(video->lines_size);
229 }
230 if (count && count < video->lines_size) {
231 memcpy(video->dst, src, count);
232
233 video->prev_left = video->lines_size - count;
234 video->dst += count;
235 }
236 return;
237
238overflow:
239 end_field(video);
240}
241
242static void check_trailer(struct video_data *video, char *src, int count)
243{
244 struct vbi_data *vbi = video->vbi;
245 int offset; /* trailer's offset */
246 char *buf;
247
248 offset = (video->context.pix.sizeimage / 2 + vbi->vbi_size / 2)
249 - (vbi->copied + video->lines_size * video->lines_copied);
250 if (video->prev_left)
251 offset -= (video->lines_size - video->prev_left);
252
253 if (offset > count || offset <= 0)
254 goto short_package;
255
256 buf = src + offset;
257
258 /* trailer : (VFHS) + U32 + U32 + field_num */
259 if (!strncmp(buf, "VFHS", 4)) {
260 int field_num = *((u32 *)(buf + 12));
261
262 if ((field_num & 1) ^ video->field_count) {
263 init_copy(video, video->field_count);
264 return;
265 }
266 copy_video_data(video, src, offset);
267 }
268short_package:
269 end_field(video);
270}
271
272/* ========== Check this more carefully! =========== */
273static inline void copy_vbi_data(struct vbi_data *vbi,
274 char *src, unsigned int count)
275{
276 struct front_face *front = vbi->front;
277
278 if (front && get_frame(front, NULL)) {
279 char *buf = videobuf_to_vmalloc(front->curr_frame);
280
281 if (vbi->video->field_count)
282 buf += (vbi->vbi_size / 2);
283 memcpy(buf + vbi->copied, src, count);
284 }
285 vbi->copied += count;
286}
287
288/*
289 * Copy the normal data (VBI or VIDEO) without the trailer.
290 * VBI is not interlaced, while VIDEO is interlaced.
291 */
292static inline void copy_vbi_video_data(struct video_data *video,
293 char *src, unsigned int count)
294{
295 struct vbi_data *vbi = video->vbi;
296 unsigned int vbi_delta = (vbi->vbi_size / 2) - vbi->copied;
297
298 if (vbi_delta >= count) {
299 copy_vbi_data(vbi, src, count);
300 } else {
301 if (vbi_delta) {
302 copy_vbi_data(vbi, src, vbi_delta);
303
304 /* we receive the two fields of the VBI*/
305 if (vbi->front && video->field_count)
306 submit_frame(vbi->front);
307 }
308 copy_video_data(video, src + vbi_delta, count - vbi_delta);
309 }
310}
311
312static void urb_complete_bulk(struct urb *urb)
313{
314 struct front_face *front = urb->context;
315 struct video_data *video = &front->pd->video_data;
316 char *src = (char *)urb->transfer_buffer;
317 int count = urb->actual_length;
318 int ret = 0;
319
320 if (!video->is_streaming || urb->status) {
321 if (urb->status == -EPROTO)
322 goto resend_it;
323 return;
324 }
325 if (!get_video_frame(front, video))
326 goto resend_it;
327
328 if (count == urb->transfer_buffer_length)
329 copy_vbi_video_data(video, src, count);
330 else
331 check_trailer(video, src, count);
332
333resend_it:
334 ret = usb_submit_urb(urb, GFP_ATOMIC);
335 if (ret)
336 log(" submit failed: error %d", ret);
337}
338
339/************************* for ISO *********************/
340#define GET_SUCCESS (0)
341#define GET_TRAILER (1)
342#define GET_TOO_MUCH_BUBBLE (2)
343#define GET_NONE (3)
344static int get_chunk(int start, struct urb *urb,
345 int *head, int *tail, int *bubble_err)
346{
347 struct usb_iso_packet_descriptor *pkt = NULL;
348 int ret = GET_SUCCESS;
349
350 for (*head = *tail = -1; start < urb->number_of_packets; start++) {
351 pkt = &urb->iso_frame_desc[start];
352
353 /* handle the bubble of the Hub */
354 if (-EOVERFLOW == pkt->status) {
355 if (++*bubble_err > urb->number_of_packets / 3)
356 return GET_TOO_MUCH_BUBBLE;
357 continue;
358 }
359
360 /* This is the gap */
361 if (pkt->status || pkt->actual_length <= 0
362 || pkt->actual_length > ISO_PKT_SIZE) {
363 if (*head != -1)
364 break;
365 continue;
366 }
367
368 /* a good isochronous packet */
369 if (pkt->actual_length == ISO_PKT_SIZE) {
370 if (*head == -1)
371 *head = start;
372 *tail = start;
373 continue;
374 }
375
376 /* trailer is here */
377 if (pkt->actual_length < ISO_PKT_SIZE) {
378 if (*head == -1) {
379 *head = start;
380 *tail = start;
381 return GET_TRAILER;
382 }
383 break;
384 }
385 }
386
387 if (*head == -1 && *tail == -1)
388 ret = GET_NONE;
389 return ret;
390}
391
392/*
393 * |__|------|___|-----|_______|
394 * ^ ^
395 * | |
396 * gap gap
397 */
398static void urb_complete_iso(struct urb *urb)
399{
400 struct front_face *front = urb->context;
401 struct video_data *video = &front->pd->video_data;
402 int bubble_err = 0, head = 0, tail = 0;
403 char *src = (char *)urb->transfer_buffer;
404 int ret = 0;
405
406 if (!video->is_streaming)
407 return;
408
409 do {
410 if (!get_video_frame(front, video))
411 goto out;
412
413 switch (get_chunk(head, urb, &head, &tail, &bubble_err)) {
414 case GET_SUCCESS:
415 copy_vbi_video_data(video, src + (head * ISO_PKT_SIZE),
416 (tail - head + 1) * ISO_PKT_SIZE);
417 break;
418 case GET_TRAILER:
419 check_trailer(video, src + (head * ISO_PKT_SIZE),
420 ISO_PKT_SIZE);
421 break;
422 case GET_NONE:
423 goto out;
424 case GET_TOO_MUCH_BUBBLE:
425 log("\t We got too much bubble");
426 schedule_work(&video->bubble_work);
427 return;
428 }
429 } while (head = tail + 1, head < urb->number_of_packets);
430
431out:
432 ret = usb_submit_urb(urb, GFP_ATOMIC);
433 if (ret)
434 log("usb_submit_urb err : %d", ret);
435}
436/*============================= [ end ] =====================*/
437
438static int prepare_iso_urb(struct video_data *video)
439{
440 struct usb_device *udev = video->pd->udev;
441 int i;
442
443 if (video->urb_array[0])
444 return 0;
445
446 for (i = 0; i < SBUF_NUM; i++) {
447 struct urb *urb;
448 void *mem;
449 int j;
450
451 urb = usb_alloc_urb(PK_PER_URB, GFP_KERNEL);
452 if (urb == NULL)
453 goto out;
454
455 video->urb_array[i] = urb;
456 mem = usb_buffer_alloc(udev,
457 ISO_PKT_SIZE * PK_PER_URB,
458 GFP_KERNEL,
459 &urb->transfer_dma);
460
461 urb->complete = urb_complete_iso; /* handler */
462 urb->dev = udev;
463 urb->context = video->front;
464 urb->pipe = usb_rcvisocpipe(udev,
465 video->endpoint_addr);
466 urb->interval = 1;
467 urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
468 urb->number_of_packets = PK_PER_URB;
469 urb->transfer_buffer = mem;
470 urb->transfer_buffer_length = PK_PER_URB * ISO_PKT_SIZE;
471
472 for (j = 0; j < PK_PER_URB; j++) {
473 urb->iso_frame_desc[j].offset = ISO_PKT_SIZE * j;
474 urb->iso_frame_desc[j].length = ISO_PKT_SIZE;
475 }
476 }
477 return 0;
478out:
479 for (; i > 0; i--)
480 ;
481 return -ENOMEM;
482}
483
484/* return the succeeded number of the allocation */
485int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
486 struct usb_device *udev, u8 ep_addr,
487 int buf_size, gfp_t gfp_flags,
488 usb_complete_t complete_fn, void *context)
489{
490 struct urb *urb;
491 void *mem;
492 int i;
493
494 for (i = 0; i < num; i++) {
495 urb = usb_alloc_urb(0, gfp_flags);
496 if (urb == NULL)
497 return i;
498
499 mem = usb_buffer_alloc(udev, buf_size, gfp_flags,
500 &urb->transfer_dma);
501 if (mem == NULL)
502 return i;
503
504 usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr),
505 mem, buf_size, complete_fn, context);
506 urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
507 urb_array[i] = urb;
508 }
509 return i;
510}
511
512void free_all_urb_generic(struct urb **urb_array, int num)
513{
514 int i;
515 struct urb *urb;
516
517 for (i = 0; i < num; i++) {
518 urb = urb_array[i];
519 if (urb) {
520 usb_buffer_free(urb->dev,
521 urb->transfer_buffer_length,
522 urb->transfer_buffer,
523 urb->transfer_dma);
524 usb_free_urb(urb);
525 urb_array[i] = NULL;
526 }
527 }
528}
529
530static int prepare_bulk_urb(struct video_data *video)
531{
532 if (video->urb_array[0])
533 return 0;
534
535 alloc_bulk_urbs_generic(video->urb_array, SBUF_NUM,
536 video->pd->udev, video->endpoint_addr,
537 0x2000, GFP_KERNEL,
538 urb_complete_bulk, video->front);
539 return 0;
540}
541
542/* free the URBs */
543static void free_all_urb(struct video_data *video)
544{
545 free_all_urb_generic(video->urb_array, SBUF_NUM);
546}
547
548static void pd_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
549{
550 videobuf_vmalloc_free(vb);
551 vb->state = VIDEOBUF_NEEDS_INIT;
552}
553
554static void pd_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
555{
556 struct front_face *front = q->priv_data;
557 vb->state = VIDEOBUF_QUEUED;
558 list_add_tail(&vb->queue, &front->active);
559}
560
561static int pd_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
562 enum v4l2_field field)
563{
564 struct front_face *front = q->priv_data;
565 int rc;
566
567 switch (front->type) {
568 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
569 if (VIDEOBUF_NEEDS_INIT == vb->state) {
570 struct v4l2_pix_format *pix;
571
572 pix = &front->pd->video_data.context.pix;
573 vb->size = pix->sizeimage; /* real frame size */
574 vb->width = pix->width;
575 vb->height = pix->height;
576 rc = videobuf_iolock(q, vb, NULL);
577 if (rc < 0)
578 return rc;
579 }
580 break;
581 case V4L2_BUF_TYPE_VBI_CAPTURE:
582 if (VIDEOBUF_NEEDS_INIT == vb->state) {
583 vb->size = front->pd->vbi_data.vbi_size;
584 rc = videobuf_iolock(q, vb, NULL);
585 if (rc < 0)
586 return rc;
587 }
588 break;
589 default:
590 return -EINVAL;
591 }
592 vb->field = field;
593 vb->state = VIDEOBUF_PREPARED;
594 return 0;
595}
596
597int fire_all_urb(struct video_data *video)
598{
599 int i, ret;
600
601 video->is_streaming = 1;
602
603 for (i = 0; i < SBUF_NUM; i++) {
604 ret = usb_submit_urb(video->urb_array[i], GFP_KERNEL);
605 if (ret)
606 log("(%d) failed: error %d", i, ret);
607 }
608 return ret;
609}
610
611static int start_video_stream(struct poseidon *pd)
612{
613 struct video_data *video = &pd->video_data;
614 s32 cmd_status;
615
616 send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
617 send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_START, &cmd_status);
618
619 if (pd->cur_transfer_mode) {
620 prepare_iso_urb(video);
621 INIT_WORK(&video->bubble_work, iso_bubble_handler);
622 } else {
623 /* The bulk mode does not need a bubble handler */
624 prepare_bulk_urb(video);
625 }
626 fire_all_urb(video);
627 return 0;
628}
629
630static int pd_buf_setup(struct videobuf_queue *q, unsigned int *count,
631 unsigned int *size)
632{
633 struct front_face *front = q->priv_data;
634 struct poseidon *pd = front->pd;
635
636 switch (front->type) {
637 default:
638 return -EINVAL;
639 case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
640 struct video_data *video = &pd->video_data;
641 struct v4l2_pix_format *pix = &video->context.pix;
642
643 *size = PAGE_ALIGN(pix->sizeimage);/* page aligned frame size */
644 if (*count < 4)
645 *count = 4;
646 if (1) {
647 /* same in different altersetting */
648 video->endpoint_addr = 0x82;
649 video->vbi = &pd->vbi_data;
650 video->vbi->video = video;
651 video->pd = pd;
652 video->lines_per_field = pix->height / 2;
653 video->lines_size = pix->width * 2;
654 video->front = front;
655 }
656 return start_video_stream(pd);
657 }
658
659 case V4L2_BUF_TYPE_VBI_CAPTURE: {
660 struct vbi_data *vbi = &pd->vbi_data;
661
662 *size = PAGE_ALIGN(vbi->vbi_size);
663 log("size : %d", *size);
664 if (*count == 0)
665 *count = 4;
666 }
667 break;
668 }
669 return 0;
670}
671
672static struct videobuf_queue_ops pd_video_qops = {
673 .buf_setup = pd_buf_setup,
674 .buf_prepare = pd_buf_prepare,
675 .buf_queue = pd_buf_queue,
676 .buf_release = pd_buf_release,
677};
678
679static int vidioc_enum_fmt(struct file *file, void *fh,
680 struct v4l2_fmtdesc *f)
681{
682 if (ARRAY_SIZE(poseidon_formats) <= f->index)
683 return -EINVAL;
684 f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
685 f->flags = 0;
686 f->pixelformat = poseidon_formats[f->index].fourcc;
687 strcpy(f->description, poseidon_formats[f->index].name);
688 return 0;
689}
690
691static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
692{
693 struct front_face *front = fh;
694 struct poseidon *pd = front->pd;
695
696 logs(front);
697 f->fmt.pix = pd->video_data.context.pix;
698 return 0;
699}
700
701static int vidioc_try_fmt(struct file *file, void *fh,
702 struct v4l2_format *f)
703{
704 return 0;
705}
706
707/*
708 * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while
709 * Mplayer calls them in the reverse order.
710 */
711static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix)
712{
713 struct video_data *video = &pd->video_data;
714 struct running_context *context = &video->context;
715 struct v4l2_pix_format *pix_def = &context->pix;
716 s32 ret = 0, cmd_status = 0, vid_resol;
717
718 /* set the pixel format to firmware */
719 if (pix->pixelformat == V4L2_PIX_FMT_RGB565) {
720 vid_resol = TLG_TUNER_VID_FORMAT_RGB_565;
721 } else {
722 pix->pixelformat = V4L2_PIX_FMT_YUYV;
723 vid_resol = TLG_TUNER_VID_FORMAT_YUV;
724 }
725 ret = send_set_req(pd, VIDEO_STREAM_FMT_SEL,
726 vid_resol, &cmd_status);
727
728 /* set the resolution to firmware */
729 vid_resol = TLG_TUNE_VID_RES_720;
730 switch (pix->width) {
731 case 704:
732 vid_resol = TLG_TUNE_VID_RES_704;
733 break;
734 default:
735 pix->width = 720;
736 case 720:
737 break;
738 }
739 ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
740 vid_resol, &cmd_status);
741 if (ret || cmd_status) {
742 mutex_unlock(&pd->lock);
743 return -EBUSY;
744 }
745
746 pix_def->pixelformat = pix->pixelformat; /* save it */
747 pix->height = (context->tvnormid & V4L2_STD_525_60) ? 480 : 576;
748
749 /* Compare with the default setting */
750 if ((pix_def->width != pix->width)
751 || (pix_def->height != pix->height)) {
752 pix_def->width = pix->width;
753 pix_def->height = pix->height;
754 pix_def->bytesperline = pix->width * 2;
755 pix_def->sizeimage = pix->width * pix->height * 2;
756 }
757 *pix = *pix_def;
758
759 return 0;
760}
761
762static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
763{
764 struct front_face *front = fh;
765 struct poseidon *pd = front->pd;
766
767 logs(front);
768 /* stop VBI here */
769 if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
770 return -EINVAL;
771
772 mutex_lock(&pd->lock);
773 if (pd->file_for_stream == NULL)
774 pd->file_for_stream = file;
775 else if (file != pd->file_for_stream) {
776 mutex_unlock(&pd->lock);
777 return -EINVAL;
778 }
779
780 pd_vidioc_s_fmt(pd, &f->fmt.pix);
781 mutex_unlock(&pd->lock);
782 return 0;
783}
784
785static int vidioc_g_fmt_vbi(struct file *file, void *fh,
786 struct v4l2_format *v4l2_f)
787{
788 struct front_face *front = fh;
789 struct poseidon *pd = front->pd;
790 struct v4l2_vbi_format *vbi_fmt = &v4l2_f->fmt.vbi;
791
792 vbi_fmt->samples_per_line = 720 * 2;
793 vbi_fmt->sampling_rate = 6750000 * 4;
794 vbi_fmt->sample_format = V4L2_PIX_FMT_GREY;
795 vbi_fmt->offset = 64 * 4; /*FIXME: why offset */
796 if (pd->video_data.context.tvnormid & V4L2_STD_525_60) {
797 vbi_fmt->start[0] = 10;
798 vbi_fmt->start[1] = 264;
799 vbi_fmt->count[0] = V4L_NTSC_VBI_LINES;
800 vbi_fmt->count[1] = V4L_NTSC_VBI_LINES;
801 } else {
802 vbi_fmt->start[0] = 6;
803 vbi_fmt->start[1] = 314;
804 vbi_fmt->count[0] = V4L_PAL_VBI_LINES;
805 vbi_fmt->count[1] = V4L_PAL_VBI_LINES;
806 }
807 vbi_fmt->flags = V4L2_VBI_UNSYNC;
808 logs(front);
809 return 0;
810}
811
812static int set_std(struct poseidon *pd, v4l2_std_id *norm)
813{
814 struct video_data *video = &pd->video_data;
815 struct vbi_data *vbi = &pd->vbi_data;
816 struct running_context *context;
817 struct v4l2_pix_format *pix;
818 s32 i, ret = 0, cmd_status, param;
819 int height;
820
821 for (i = 0; i < POSEIDON_TVNORMS; i++) {
822 if (*norm & poseidon_tvnorms[i].v4l2_id) {
823 param = poseidon_tvnorms[i].tlg_tvnorm;
824 log("name : %s", poseidon_tvnorms[i].name);
825 goto found;
826 }
827 }
828 return -EINVAL;
829found:
830 mutex_lock(&pd->lock);
831 ret = send_set_req(pd, VIDEO_STD_SEL, param, &cmd_status);
832 if (ret || cmd_status)
833 goto out;
834
835 /* Set vbi size and check the height of the frame */
836 context = &video->context;
837 context->tvnormid = poseidon_tvnorms[i].v4l2_id;
838 if (context->tvnormid & V4L2_STD_525_60) {
839 vbi->vbi_size = V4L_NTSC_VBI_FRAMESIZE;
840 height = 480;
841 } else {
842 vbi->vbi_size = V4L_PAL_VBI_FRAMESIZE;
843 height = 576;
844 }
845
846 pix = &context->pix;
847 if (pix->height != height) {
848 pix->height = height;
849 pix->sizeimage = pix->width * pix->height * 2;
850 }
851
852out:
853 mutex_unlock(&pd->lock);
854 return ret;
855}
856
857int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *norm)
858{
859 struct front_face *front = fh;
860 logs(front);
861 return set_std(front->pd, norm);
862}
863
864static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in)
865{
866 struct front_face *front = fh;
867
868 if (in->index < 0 || in->index >= POSEIDON_INPUTS)
869 return -EINVAL;
870 strcpy(in->name, pd_inputs[in->index].name);
871 in->type = V4L2_INPUT_TYPE_TUNER;
872
873 /*
874 * the audio input index mixed with this video input,
875 * Poseidon only have one audio/video, set to "0"
876 */
877 in->audioset = 0;
878 in->tuner = 0;
879 in->std = V4L2_STD_ALL;
880 in->status = 0;
881 logs(front);
882 return 0;
883}
884
885static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
886{
887 struct front_face *front = fh;
888 struct poseidon *pd = front->pd;
889 struct running_context *context = &pd->video_data.context;
890
891 logs(front);
892 *i = context->sig_index;
893 return 0;
894}
895
896/* We can support several inputs */
897static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
898{
899 struct front_face *front = fh;
900 struct poseidon *pd = front->pd;
901 s32 ret, cmd_status;
902
903 if (i < 0 || i >= POSEIDON_INPUTS)
904 return -EINVAL;
905 ret = send_set_req(pd, SGNL_SRC_SEL,
906 pd_inputs[i].tlg_src, &cmd_status);
907 if (ret)
908 return ret;
909
910 pd->video_data.context.sig_index = i;
911 return 0;
912}
913
914static struct poseidon_control *check_control_id(__u32 id)
915{
916 struct poseidon_control *control = &controls[0];
917 int array_size = ARRAY_SIZE(controls);
918
919 for (; control < &controls[array_size]; control++)
920 if (control->v4l2_ctrl.id == id)
921 return control;
922 return NULL;
923}
924
925static int vidioc_queryctrl(struct file *file, void *fh,
926 struct v4l2_queryctrl *a)
927{
928 struct poseidon_control *control = NULL;
929
930 control = check_control_id(a->id);
931 if (!control)
932 return -EINVAL;
933
934 *a = control->v4l2_ctrl;
935 return 0;
936}
937
938static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
939{
940 struct front_face *front = fh;
941 struct poseidon *pd = front->pd;
942 struct poseidon_control *control = NULL;
943 struct tuner_custom_parameter_s tuner_param;
944 s32 ret = 0, cmd_status;
945
946 control = check_control_id(ctrl->id);
947 if (!control)
948 return -EINVAL;
949
950 mutex_lock(&pd->lock);
951 ret = send_get_req(pd, TUNER_CUSTOM_PARAMETER, control->vc_id,
952 &tuner_param, &cmd_status, sizeof(tuner_param));
953 mutex_unlock(&pd->lock);
954
955 if (ret || cmd_status)
956 return -1;
957
958 ctrl->value = tuner_param.param_value;
959 return 0;
960}
961
962static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
963{
964 struct tuner_custom_parameter_s param = {0};
965 struct poseidon_control *control = NULL;
966 struct front_face *front = fh;
967 struct poseidon *pd = front->pd;
968 s32 ret = 0, cmd_status, params;
969
970 control = check_control_id(a->id);
971 if (!control)
972 return -EINVAL;
973
974 param.param_value = a->value;
975 param.param_id = control->vc_id;
976 params = *(s32 *)&param; /* temp code */
977
978 mutex_lock(&pd->lock);
979 ret = send_set_req(pd, TUNER_CUSTOM_PARAMETER, params, &cmd_status);
980 ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
981 mutex_unlock(&pd->lock);
982
983 set_current_state(TASK_INTERRUPTIBLE);
984 schedule_timeout(HZ/4);
985 return ret;
986}
987
988/* Audio ioctls */
989static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
990{
991 if (0 != a->index)
992 return -EINVAL;
993 a->capability = V4L2_AUDCAP_STEREO;
994 strcpy(a->name, "USB audio in");
995 /*Poseidon have no AVL function.*/
996 a->mode = 0;
997 return 0;
998}
999
1000int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
1001{
1002 a->index = 0;
1003 a->capability = V4L2_AUDCAP_STEREO;
1004 strcpy(a->name, "USB audio in");
1005 a->mode = 0;
1006 return 0;
1007}
1008
1009int vidioc_s_audio(struct file *file, void *fh, struct v4l2_audio *a)
1010{
1011 return (0 == a->index) ? 0 : -EINVAL;
1012}
1013
1014/* Tuner ioctls */
1015static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner)
1016{
1017 struct front_face *front = fh;
1018 struct poseidon *pd = front->pd;
1019 struct tuner_atv_sig_stat_s atv_stat;
1020 s32 count = 5, ret, cmd_status;
1021 int index;
1022
1023 if (0 != tuner->index)
1024 return -EINVAL;
1025
1026 mutex_lock(&pd->lock);
1027 ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV,
1028 &atv_stat, &cmd_status, sizeof(atv_stat));
1029
1030 while (atv_stat.sig_lock_busy && count-- && !ret) {
1031 set_current_state(TASK_INTERRUPTIBLE);
1032 schedule_timeout(HZ);
1033
1034 ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV,
1035 &atv_stat, &cmd_status, sizeof(atv_stat));
1036 }
1037 mutex_unlock(&pd->lock);
1038
1039 if (debug_mode)
1040 log("P:%d,S:%d", atv_stat.sig_present, atv_stat.sig_strength);
1041
1042 if (ret || cmd_status)
1043 tuner->signal = 0;
1044 else if (atv_stat.sig_present && !atv_stat.sig_strength)
1045 tuner->signal = 0xFFFF;
1046 else
1047 tuner->signal = (atv_stat.sig_strength * 255 / 10) << 8;
1048
1049 strcpy(tuner->name, "Telegent Systems");
1050 tuner->type = V4L2_TUNER_ANALOG_TV;
1051 tuner->rangelow = TUNER_FREQ_MIN / 62500;
1052 tuner->rangehigh = TUNER_FREQ_MAX / 62500;
1053 tuner->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
1054 V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
1055 index = pd->video_data.context.audio_idx;
1056 tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub;
1057 tuner->audmode = pd_audio_modes[index].v4l2_audio_mode;
1058 tuner->afc = 0;
1059 logs(front);
1060 return 0;
1061}
1062
1063static int pd_vidioc_s_tuner(struct poseidon *pd, int index)
1064{
1065 s32 ret = 0, cmd_status, param, audiomode;
1066
1067 mutex_lock(&pd->lock);
1068 param = pd_audio_modes[index].tlg_audio_mode;
1069 ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status);
1070 audiomode = get_audio_std(TLG_MODE_ANALOG_TV, pd->country_code);
1071 ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode,
1072 &cmd_status);
1073 if (!ret)
1074 pd->video_data.context.audio_idx = index;
1075 mutex_unlock(&pd->lock);
1076 return ret;
1077}
1078
1079static int vidioc_s_tuner(struct file *file, void *fh, struct v4l2_tuner *a)
1080{
1081 struct front_face *front = fh;
1082 struct poseidon *pd = front->pd;
1083 int index;
1084
1085 if (0 != a->index)
1086 return -EINVAL;
1087 logs(front);
1088 for (index = 0; index < POSEIDON_AUDIOMODS; index++)
1089 if (a->audmode == pd_audio_modes[index].v4l2_audio_mode)
1090 return pd_vidioc_s_tuner(pd, index);
1091 return -EINVAL;
1092}
1093
1094static int vidioc_g_frequency(struct file *file, void *fh,
1095 struct v4l2_frequency *freq)
1096{
1097 struct front_face *front = fh;
1098 struct poseidon *pd = front->pd;
1099 struct running_context *context = &pd->video_data.context;
1100
1101 if (0 != freq->tuner)
1102 return -EINVAL;
1103 freq->frequency = context->freq;
1104 freq->type = V4L2_TUNER_ANALOG_TV;
1105 return 0;
1106}
1107
1108static int set_frequency(struct poseidon *pd, __u32 frequency)
1109{
1110 s32 ret = 0, param, cmd_status;
1111 struct running_context *context = &pd->video_data.context;
1112
1113 param = frequency * 62500 / 1000;
1114 if (param < TUNER_FREQ_MIN/1000 || param > TUNER_FREQ_MAX / 1000)
1115 return -EINVAL;
1116
1117 mutex_lock(&pd->lock);
1118 ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status);
1119 ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
1120
1121 msleep(250); /* wait for a while until the hardware is ready. */
1122 context->freq = frequency;
1123 mutex_unlock(&pd->lock);
1124 return ret;
1125}
1126
1127static int vidioc_s_frequency(struct file *file, void *fh,
1128 struct v4l2_frequency *freq)
1129{
1130 struct front_face *front = fh;
1131 struct poseidon *pd = front->pd;
1132
1133 logs(front);
1134#ifdef CONFIG_PM
1135 pd->pm_suspend = pm_video_suspend;
1136 pd->pm_resume = pm_video_resume;
1137#endif
1138 return set_frequency(pd, freq->frequency);
1139}
1140
1141static int vidioc_reqbufs(struct file *file, void *fh,
1142 struct v4l2_requestbuffers *b)
1143{
1144 struct front_face *front = file->private_data;
1145 logs(front);
1146 return videobuf_reqbufs(&front->q, b);
1147}
1148
1149static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
1150{
1151 struct front_face *front = file->private_data;
1152 logs(front);
1153 return videobuf_querybuf(&front->q, b);
1154}
1155
1156static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
1157{
1158 struct front_face *front = file->private_data;
1159 return videobuf_qbuf(&front->q, b);
1160}
1161
1162static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
1163{
1164 struct front_face *front = file->private_data;
1165 return videobuf_dqbuf(&front->q, b, file->f_flags & O_NONBLOCK);
1166}
1167
1168/* Just stop the URBs, do not free the URBs */
1169int usb_transfer_stop(struct video_data *video)
1170{
1171 if (video->is_streaming) {
1172 int i;
1173 s32 cmd_status;
1174 struct poseidon *pd = video->pd;
1175
1176 video->is_streaming = 0;
1177 for (i = 0; i < SBUF_NUM; ++i) {
1178 if (video->urb_array[i])
1179 usb_kill_urb(video->urb_array[i]);
1180 }
1181
1182 send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
1183 &cmd_status);
1184 }
1185 return 0;
1186}
1187
1188int stop_all_video_stream(struct poseidon *pd)
1189{
1190 struct video_data *video = &pd->video_data;
1191 struct vbi_data *vbi = &pd->vbi_data;
1192
1193 mutex_lock(&pd->lock);
1194 if (video->is_streaming) {
1195 struct front_face *front = video->front;
1196
1197 /* stop the URBs */
1198 usb_transfer_stop(video);
1199 free_all_urb(video);
1200
1201 /* stop the host side of VIDEO */
1202 videobuf_stop(&front->q);
1203 videobuf_mmap_free(&front->q);
1204
1205 /* stop the host side of VBI */
1206 front = vbi->front;
1207 if (front) {
1208 videobuf_stop(&front->q);
1209 videobuf_mmap_free(&front->q);
1210 }
1211 }
1212 mutex_unlock(&pd->lock);
1213 return 0;
1214}
1215
1216/*
1217 * The bubbles can seriously damage the video's quality,
1218 * though it occurs in very rare situation.
1219 */
1220static void iso_bubble_handler(struct work_struct *w)
1221{
1222 struct video_data *video;
1223 struct poseidon *pd;
1224
1225 video = container_of(w, struct video_data, bubble_work);
1226 pd = video->pd;
1227
1228 mutex_lock(&pd->lock);
1229 usb_transfer_stop(video);
1230 msleep(500);
1231 start_video_stream(pd);
1232 mutex_unlock(&pd->lock);
1233}
1234
1235
1236static int vidioc_streamon(struct file *file, void *fh,
1237 enum v4l2_buf_type type)
1238{
1239 struct front_face *front = fh;
1240
1241 logs(front);
1242 if (unlikely(type != front->type))
1243 return -EINVAL;
1244 return videobuf_streamon(&front->q);
1245}
1246
1247static int vidioc_streamoff(struct file *file, void *fh,
1248 enum v4l2_buf_type type)
1249{
1250 struct front_face *front = file->private_data;
1251
1252 logs(front);
1253 if (unlikely(type != front->type))
1254 return -EINVAL;
1255 return videobuf_streamoff(&front->q);
1256}
1257
1258/*
1259 * Set the firmware' default values : need altersetting and country code
1260 */
1261static int pd_video_checkmode(struct poseidon *pd)
1262{
1263 s32 ret = 0, cmd_status, audiomode;
1264
1265 set_current_state(TASK_INTERRUPTIBLE);
1266 schedule_timeout(HZ/2);
1267
1268 /* choose the altersetting */
1269 ret = usb_set_interface(pd->udev, 0,
1270 (pd->cur_transfer_mode ?
1271 ISO_3K_BULK_ALTERNATE_IFACE :
1272 BULK_ALTERNATE_IFACE));
1273 if (ret < 0)
1274 goto error;
1275
1276 /* set default parameters for PAL-D , with the VBI enabled*/
1277 ret = set_tuner_mode(pd, TLG_MODE_ANALOG_TV);
1278 ret |= send_set_req(pd, SGNL_SRC_SEL,
1279 TLG_SIG_SRC_ANTENNA, &cmd_status);
1280 ret |= send_set_req(pd, VIDEO_STD_SEL,
1281 TLG_TUNE_VSTD_PAL_D, &cmd_status);
1282 ret |= send_set_req(pd, VIDEO_STREAM_FMT_SEL,
1283 TLG_TUNER_VID_FORMAT_YUV, &cmd_status);
1284 ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
1285 TLG_TUNE_VID_RES_720, &cmd_status);
1286 ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status);
1287 ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */
1288
1289 /* need country code to set the audio */
1290 audiomode = get_audio_std(TLG_MODE_ANALOG_TV, pd->country_code);
1291 ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status);
1292 ret |= send_set_req(pd, TUNER_AUD_MODE,
1293 TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status);
1294 ret |= send_set_req(pd, AUDIO_SAMPLE_RATE_SEL,
1295 ATV_AUDIO_RATE_48K, &cmd_status);
1296error:
1297 return ret;
1298}
1299
1300#ifdef CONFIG_PM
1301static int pm_video_suspend(struct poseidon *pd)
1302{
1303 /* stop audio */
1304 pm_alsa_suspend(pd);
1305
1306 /* stop and free all the URBs */
1307 usb_transfer_stop(&pd->video_data);
1308 free_all_urb(&pd->video_data);
1309
1310 /* reset the interface */
1311 usb_set_interface(pd->udev, 0, 0);
1312 msleep(300);
1313 return 0;
1314}
1315
1316static int restore_v4l2_context(struct poseidon *pd,
1317 struct running_context *context)
1318{
1319 struct front_face *front = pd->video_data.front;
1320
1321 pd_video_checkmode(pd);
1322
1323 set_std(pd, &context->tvnormid);
1324 vidioc_s_input(NULL, front, context->sig_index);
1325 pd_vidioc_s_tuner(pd, context->audio_idx);
1326 pd_vidioc_s_fmt(pd, &context->pix);
1327 set_frequency(pd, context->freq);
1328 return 0;
1329}
1330
1331static int pm_video_resume(struct poseidon *pd)
1332{
1333 struct video_data *video = &pd->video_data;
1334
1335 /* resume the video */
1336 /* [1] restore the origin V4L2 parameters */
1337 restore_v4l2_context(pd, &video->context);
1338
1339 /* [2] initiate video copy variables */
1340 if (video->front->curr_frame)
1341 init_copy(video, 0);
1342
1343 /* [3] fire urbs */
1344 start_video_stream(pd);
1345
1346 /* resume the audio */
1347 pm_alsa_resume(pd);
1348 return 0;
1349}
1350#endif
1351
1352void set_debug_mode(struct video_device *vfd, int debug_mode)
1353{
1354 vfd->debug = 0;
1355 if (debug_mode & 0x1)
1356 vfd->debug = V4L2_DEBUG_IOCTL;
1357 if (debug_mode & 0x2)
1358 vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
1359}
1360
1361static void init_video_context(struct running_context *context)
1362{
1363 context->sig_index = 0;
1364 context->audio_idx = 1; /* stereo */
1365 context->tvnormid = V4L2_STD_PAL_D;
1366 context->pix = (struct v4l2_pix_format) {
1367 .width = 720,
1368 .height = 576,
1369 .pixelformat = V4L2_PIX_FMT_YUYV,
1370 .field = V4L2_FIELD_INTERLACED,
1371 .bytesperline = 720 * 2,
1372 .sizeimage = 720 * 576 * 2,
1373 .colorspace = V4L2_COLORSPACE_SMPTE170M,
1374 .priv = 0
1375 };
1376}
1377
1378static int pd_video_open(struct file *file)
1379{
1380 struct video_device *vfd = video_devdata(file);
1381 struct poseidon *pd = video_get_drvdata(vfd);
1382 struct front_face *front = NULL;
1383 int ret = -ENOMEM;
1384
1385 mutex_lock(&pd->lock);
1386 usb_autopm_get_interface(pd->interface);
1387
1388 if (vfd->vfl_type == VFL_TYPE_GRABBER
1389 && !(pd->state & POSEIDON_STATE_ANALOG)) {
1390 front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
1391 if (!front)
1392 goto out;
1393
1394 pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */
1395 pd->country_code = country_code;
1396 init_video_context(&pd->video_data.context);
1397
1398 ret = pd_video_checkmode(pd);
1399 if (ret < 0) {
1400 kfree(front);
1401 ret = -1;
1402 goto out;
1403 }
1404
1405 pd->state |= POSEIDON_STATE_ANALOG;
1406 front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1407 pd->video_data.users++;
1408 set_debug_mode(vfd, debug_mode);
1409
1410 videobuf_queue_vmalloc_init(&front->q, &pd_video_qops,
1411 NULL, &front->queue_lock,
1412 V4L2_BUF_TYPE_VIDEO_CAPTURE,
1413 V4L2_FIELD_INTERLACED,/* video is interlacd */
1414 sizeof(struct videobuf_buffer),/*it's enough*/
1415 front);
1416 } else if (vfd->vfl_type == VFL_TYPE_VBI
1417 && !(pd->state & POSEIDON_STATE_VBI)) {
1418 front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
1419 if (!front)
1420 goto out;
1421
1422 pd->state |= POSEIDON_STATE_VBI;
1423 front->type = V4L2_BUF_TYPE_VBI_CAPTURE;
1424 pd->vbi_data.front = front;
1425 pd->vbi_data.users++;
1426
1427 videobuf_queue_vmalloc_init(&front->q, &pd_video_qops,
1428 NULL, &front->queue_lock,
1429 V4L2_BUF_TYPE_VBI_CAPTURE,
1430 V4L2_FIELD_NONE, /* vbi is NONE mode */
1431 sizeof(struct videobuf_buffer),
1432 front);
1433 } else {
1434 /* maybe add FM support here */
1435 log("other ");
1436 ret = -EINVAL;
1437 goto out;
1438 }
1439
1440 front->pd = pd;
1441 front->curr_frame = NULL;
1442 INIT_LIST_HEAD(&front->active);
1443 spin_lock_init(&front->queue_lock);
1444
1445 file->private_data = front;
1446 kref_get(&pd->kref);
1447
1448 mutex_unlock(&pd->lock);
1449 return 0;
1450out:
1451 usb_autopm_put_interface(pd->interface);
1452 mutex_unlock(&pd->lock);
1453 return ret;
1454}
1455
1456static int pd_video_release(struct file *file)
1457{
1458 struct front_face *front = file->private_data;
1459 struct poseidon *pd = front->pd;
1460 s32 cmd_status = 0;
1461
1462 logs(front);
1463 mutex_lock(&pd->lock);
1464
1465 if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1466 pd->state &= ~POSEIDON_STATE_ANALOG;
1467
1468 /* stop the device, and free the URBs */
1469 usb_transfer_stop(&pd->video_data);
1470 free_all_urb(&pd->video_data);
1471
1472 /* stop the firmware */
1473 send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
1474 &cmd_status);
1475
1476 pd->file_for_stream = NULL;
1477 pd->video_data.users--;
1478 } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
1479 pd->state &= ~POSEIDON_STATE_VBI;
1480 pd->vbi_data.front = NULL;
1481 pd->vbi_data.users--;
1482 }
1483 videobuf_stop(&front->q);
1484 videobuf_mmap_free(&front->q);
1485
1486 usb_autopm_put_interface(pd->interface);
1487 mutex_unlock(&pd->lock);
1488
1489 kfree(front);
1490 file->private_data = NULL;
1491 kref_put(&pd->kref, poseidon_delete);
1492 return 0;
1493}
1494
1495static int pd_video_mmap(struct file *file, struct vm_area_struct *vma)
1496{
1497 struct front_face *front = file->private_data;
1498 return videobuf_mmap_mapper(&front->q, vma);
1499}
1500
1501unsigned int pd_video_poll(struct file *file, poll_table *table)
1502{
1503 struct front_face *front = file->private_data;
1504 return videobuf_poll_stream(file, &front->q, table);
1505}
1506
1507ssize_t pd_video_read(struct file *file, char __user *buffer,
1508 size_t count, loff_t *ppos)
1509{
1510 struct front_face *front = file->private_data;
1511 return videobuf_read_stream(&front->q, buffer, count, ppos,
1512 0, file->f_flags & O_NONBLOCK);
1513}
1514
1515/* This struct works for both VIDEO and VBI */
1516static const struct v4l2_file_operations pd_video_fops = {
1517 .owner = THIS_MODULE,
1518 .open = pd_video_open,
1519 .release = pd_video_release,
1520 .read = pd_video_read,
1521 .poll = pd_video_poll,
1522 .mmap = pd_video_mmap,
1523 .ioctl = video_ioctl2, /* maybe changed in future */
1524};
1525
1526static const struct v4l2_ioctl_ops pd_video_ioctl_ops = {
1527 .vidioc_querycap = vidioc_querycap,
1528
1529 /* Video format */
1530 .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
1531 .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
1532 .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
1533 .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */
1534 .vidioc_try_fmt_vid_cap = vidioc_try_fmt,
1535
1536 /* Input */
1537 .vidioc_g_input = vidioc_g_input,
1538 .vidioc_s_input = vidioc_s_input,
1539 .vidioc_enum_input = vidioc_enum_input,
1540
1541 /* Audio ioctls */
1542 .vidioc_enumaudio = vidioc_enumaudio,
1543 .vidioc_g_audio = vidioc_g_audio,
1544 .vidioc_s_audio = vidioc_s_audio,
1545
1546 /* Tuner ioctls */
1547 .vidioc_g_tuner = vidioc_g_tuner,
1548 .vidioc_s_tuner = vidioc_s_tuner,
1549 .vidioc_s_std = vidioc_s_std,
1550 .vidioc_g_frequency = vidioc_g_frequency,
1551 .vidioc_s_frequency = vidioc_s_frequency,
1552
1553 /* Buffer handlers */
1554 .vidioc_reqbufs = vidioc_reqbufs,
1555 .vidioc_querybuf = vidioc_querybuf,
1556 .vidioc_qbuf = vidioc_qbuf,
1557 .vidioc_dqbuf = vidioc_dqbuf,
1558
1559 /* Stream on/off */
1560 .vidioc_streamon = vidioc_streamon,
1561 .vidioc_streamoff = vidioc_streamoff,
1562
1563 /* Control handling */
1564 .vidioc_queryctrl = vidioc_queryctrl,
1565 .vidioc_g_ctrl = vidioc_g_ctrl,
1566 .vidioc_s_ctrl = vidioc_s_ctrl,
1567};
1568
1569static struct video_device pd_video_template = {
1570 .name = "Telegent-Video",
1571 .fops = &pd_video_fops,
1572 .minor = -1,
1573 .release = video_device_release,
1574 .tvnorms = V4L2_STD_ALL,
1575 .ioctl_ops = &pd_video_ioctl_ops,
1576};
1577
1578struct video_device *vdev_init(struct poseidon *pd, struct video_device *tmp)
1579{
1580 struct video_device *vfd;
1581
1582 vfd = video_device_alloc();
1583 if (vfd == NULL)
1584 return NULL;
1585 *vfd = *tmp;
1586 vfd->minor = -1;
1587 vfd->v4l2_dev = &pd->v4l2_dev;
1588 /*vfd->parent = &(pd->udev->dev); */
1589 vfd->release = video_device_release;
1590 video_set_drvdata(vfd, pd);
1591 return vfd;
1592}
1593
1594void destroy_video_device(struct video_device **v_dev)
1595{
1596 struct video_device *dev = *v_dev;
1597
1598 if (dev == NULL)
1599 return;
1600
1601 if (video_is_registered(dev))
1602 video_unregister_device(dev);
1603 else
1604 video_device_release(dev);
1605 *v_dev = NULL;
1606}
1607
1608void pd_video_exit(struct poseidon *pd)
1609{
1610 struct video_data *video = &pd->video_data;
1611 struct vbi_data *vbi = &pd->vbi_data;
1612
1613 destroy_video_device(&video->v_dev);
1614 destroy_video_device(&vbi->v_dev);
1615 log();
1616}
1617
1618int pd_video_init(struct poseidon *pd)
1619{
1620 struct video_data *video = &pd->video_data;
1621 struct vbi_data *vbi = &pd->vbi_data;
1622 int ret = -ENOMEM;
1623
1624 video->v_dev = vdev_init(pd, &pd_video_template);
1625 if (video->v_dev == NULL)
1626 goto out;
1627
1628 ret = video_register_device(video->v_dev, VFL_TYPE_GRABBER, -1);
1629 if (ret != 0)
1630 goto out;
1631
1632 /* VBI uses the same template as video */
1633 vbi->v_dev = vdev_init(pd, &pd_video_template);
1634 if (vbi->v_dev == NULL) {
1635 ret = -ENOMEM;
1636 goto out;
1637 }
1638 ret = video_register_device(vbi->v_dev, VFL_TYPE_VBI, -1);
1639 if (ret != 0)
1640 goto out;
1641 log("register VIDEO/VBI devices");
1642 return 0;
1643out:
1644 log("VIDEO/VBI devices register failed, : %d", ret);
1645 pd_video_exit(pd);
1646 return ret;
1647}
1648
diff --git a/drivers/media/video/tlg2300/vendorcmds.h b/drivers/media/video/tlg2300/vendorcmds.h
new file mode 100644
index 000000000000..ba6f4ae3b2c2
--- /dev/null
+++ b/drivers/media/video/tlg2300/vendorcmds.h
@@ -0,0 +1,243 @@
1#ifndef VENDOR_CMD_H_
2#define VENDOR_CMD_H_
3
4#define BULK_ALTERNATE_IFACE (2)
5#define ISO_3K_BULK_ALTERNATE_IFACE (1)
6#define REQ_SET_CMD (0X00)
7#define REQ_GET_CMD (0X80)
8
9enum tlg__analog_audio_standard {
10 TLG_TUNE_ASTD_NONE = 0x00000000,
11 TLG_TUNE_ASTD_A2 = 0x00000001,
12 TLG_TUNE_ASTD_NICAM = 0x00000002,
13 TLG_TUNE_ASTD_EIAJ = 0x00000004,
14 TLG_TUNE_ASTD_BTSC = 0x00000008,
15 TLG_TUNE_ASTD_FM_US = 0x00000010,
16 TLG_TUNE_ASTD_FM_EUR = 0x00000020,
17 TLG_TUNE_ASTD_ALL = 0x0000003f
18};
19
20/*
21 * identifiers for Custom Parameter messages.
22 * @typedef cmd_custom_param_id_t
23 */
24enum cmd_custom_param_id {
25 CUST_PARM_ID_NONE = 0x00,
26 CUST_PARM_ID_BRIGHTNESS_CTRL = 0x01,
27 CUST_PARM_ID_CONTRAST_CTRL = 0x02,
28 CUST_PARM_ID_HUE_CTRL = 0x03,
29 CUST_PARM_ID_SATURATION_CTRL = 0x04,
30 CUST_PARM_ID_AUDIO_SNR_THRESHOLD = 0x10,
31 CUST_PARM_ID_AUDIO_AGC_THRESHOLD = 0x11,
32 CUST_PARM_ID_MAX
33};
34
35struct tuner_custom_parameter_s {
36 uint16_t param_id; /* Parameter identifier */
37 uint16_t param_value; /* Parameter value */
38};
39
40struct tuner_ber_rate_s {
41 uint32_t ber_rate; /* BER sample rate in seconds */
42};
43
44struct tuner_atv_sig_stat_s {
45 uint32_t sig_present;
46 uint32_t sig_locked;
47 uint32_t sig_lock_busy;
48 uint32_t sig_strength; /* milliDb */
49 uint32_t tv_audio_chan; /* mono/stereo/sap*/
50 uint32_t mvision_stat; /* macrovision status */
51};
52
53struct tuner_dtv_sig_stat_s {
54 uint32_t sig_present; /* Boolean*/
55 uint32_t sig_locked; /* Boolean */
56 uint32_t sig_lock_busy; /* Boolean (Can this time-out?) */
57 uint32_t sig_strength; /* milliDb*/
58};
59
60struct tuner_fm_sig_stat_s {
61 uint32_t sig_present; /* Boolean*/
62 uint32_t sig_locked; /* Boolean */
63 uint32_t sig_lock_busy; /* Boolean */
64 uint32_t sig_stereo_mono;/* TBD*/
65 uint32_t sig_strength; /* milliDb*/
66};
67
68enum _tag_tlg_tune_srv_cmd {
69 TLG_TUNE_PLAY_SVC_START = 1,
70 TLG_TUNE_PLAY_SVC_STOP
71};
72
73enum _tag_tune_atv_audio_mode_caps {
74 TLG_TUNE_TVAUDIO_MODE_MONO = 0x00000001,
75 TLG_TUNE_TVAUDIO_MODE_STEREO = 0x00000002,
76 TLG_TUNE_TVAUDIO_MODE_LANG_A = 0x00000010,/* Primary language*/
77 TLG_TUNE_TVAUDIO_MODE_LANG_B = 0x00000020,/* 2nd avail language*/
78 TLG_TUNE_TVAUDIO_MODE_LANG_C = 0x00000040
79};
80
81
82enum _tag_tuner_atv_audio_rates {
83 ATV_AUDIO_RATE_NONE = 0x00,/* Audio not supported*/
84 ATV_AUDIO_RATE_32K = 0x01,/* Audio rate = 32 KHz*/
85 ATV_AUDIO_RATE_48K = 0x02, /* Audio rate = 48 KHz*/
86 ATV_AUDIO_RATE_31_25K = 0x04 /* Audio rate = 31.25KHz */
87};
88
89enum _tag_tune_atv_vid_res_caps {
90 TLG_TUNE_VID_RES_NONE = 0x00000000,
91 TLG_TUNE_VID_RES_720 = 0x00000001,
92 TLG_TUNE_VID_RES_704 = 0x00000002,
93 TLG_TUNE_VID_RES_360 = 0x00000004
94};
95
96enum _tag_tuner_analog_video_format {
97 TLG_TUNER_VID_FORMAT_YUV = 0x00000001,
98 TLG_TUNER_VID_FORMAT_YCRCB = 0x00000002,
99 TLG_TUNER_VID_FORMAT_RGB_565 = 0x00000004,
100};
101
102enum tlg_ext_audio_support {
103 TLG_EXT_AUDIO_NONE = 0x00,/* No external audio input supported */
104 TLG_EXT_AUDIO_LR = 0x01/* LR external audio inputs supported*/
105};
106
107enum {
108 TLG_MODE_NONE = 0x00, /* No Mode specified*/
109 TLG_MODE_ANALOG_TV = 0x01, /* Analog Television mode*/
110 TLG_MODE_ANALOG_TV_UNCOMP = 0x01, /* Analog Television mode*/
111 TLG_MODE_ANALOG_TV_COMP = 0x02, /* Analog TV mode (compressed)*/
112 TLG_MODE_FM_RADIO = 0x04, /* FM Radio mode*/
113 TLG_MODE_DVB_T = 0x08, /* Digital TV (DVB-T)*/
114};
115
116enum tlg_signal_sources_t {
117 TLG_SIG_SRC_NONE = 0x00,/* Signal source not specified */
118 TLG_SIG_SRC_ANTENNA = 0x01,/* Signal src is: Antenna */
119 TLG_SIG_SRC_CABLE = 0x02,/* Signal src is: Coax Cable*/
120 TLG_SIG_SRC_SVIDEO = 0x04,/* Signal src is: S_VIDEO */
121 TLG_SIG_SRC_COMPOSITE = 0x08 /* Signal src is: Composite Video */
122};
123
124enum tuner_analog_video_standard {
125 TLG_TUNE_VSTD_NONE = 0x00000000,
126 TLG_TUNE_VSTD_NTSC_M = 0x00000001,
127 TLG_TUNE_VSTD_NTSC_M_J = 0x00000002,/* Japan */
128 TLG_TUNE_VSTD_PAL_B = 0x00000010,
129 TLG_TUNE_VSTD_PAL_D = 0x00000020,
130 TLG_TUNE_VSTD_PAL_G = 0x00000040,
131 TLG_TUNE_VSTD_PAL_H = 0x00000080,
132 TLG_TUNE_VSTD_PAL_I = 0x00000100,
133 TLG_TUNE_VSTD_PAL_M = 0x00000200,
134 TLG_TUNE_VSTD_PAL_N = 0x00000400,
135 TLG_TUNE_VSTD_SECAM_B = 0x00001000,
136 TLG_TUNE_VSTD_SECAM_D = 0x00002000,
137 TLG_TUNE_VSTD_SECAM_G = 0x00004000,
138 TLG_TUNE_VSTD_SECAM_H = 0x00008000,
139 TLG_TUNE_VSTD_SECAM_K = 0x00010000,
140 TLG_TUNE_VSTD_SECAM_K1 = 0x00020000,
141 TLG_TUNE_VSTD_SECAM_L = 0x00040000,
142 TLG_TUNE_VSTD_SECAM_L1 = 0x00080000,
143 TLG_TUNE_VSTD_PAL_N_COMBO = 0x00100000
144};
145
146enum tlg_mode_caps {
147 TLG_MODE_CAPS_NONE = 0x00, /* No Mode specified */
148 TLG_MODE_CAPS_ANALOG_TV_UNCOMP = 0x01, /* Analog TV mode */
149 TLG_MODE_CAPS_ANALOG_TV_COMP = 0x02, /* Analog TV (compressed)*/
150 TLG_MODE_CAPS_FM_RADIO = 0x04, /* FM Radio mode */
151 TLG_MODE_CAPS_DVB_T = 0x08, /* Digital TV (DVB-T) */
152};
153
154enum poseidon_vendor_cmds {
155 LAST_CMD_STAT = 0x00,
156 GET_CHIP_ID = 0x01,
157 GET_FW_ID = 0x02,
158 PRODUCT_CAPS = 0x03,
159
160 TUNE_MODE_CAP_ATV = 0x10,
161 TUNE_MODE_CAP_ATVCOMP = 0X10,
162 TUNE_MODE_CAP_DVBT = 0x10,
163 TUNE_MODE_CAP_FM = 0x10,
164 TUNE_MODE_SELECT = 0x11,
165 TUNE_FREQ_SELECT = 0x12,
166 SGNL_SRC_SEL = 0x13,
167
168 VIDEO_STD_SEL = 0x14,
169 VIDEO_STREAM_FMT_SEL = 0x15,
170 VIDEO_ROSOLU_AVAIL = 0x16,
171 VIDEO_ROSOLU_SEL = 0x17,
172 VIDEO_CONT_PROTECT = 0x20,
173
174 VCR_TIMING_MODSEL = 0x21,
175 EXT_AUDIO_CAP = 0x22,
176 EXT_AUDIO_SEL = 0x23,
177 TEST_PATTERN_SEL = 0x24,
178 VBI_DATA_SEL = 0x25,
179 AUDIO_SAMPLE_RATE_CAP = 0x28,
180 AUDIO_SAMPLE_RATE_SEL = 0x29,
181 TUNER_AUD_MODE = 0x2a,
182 TUNER_AUD_MODE_AVAIL = 0x2b,
183 TUNER_AUD_ANA_STD = 0x2c,
184 TUNER_CUSTOM_PARAMETER = 0x2f,
185
186 DVBT_TUNE_MODE_SEL = 0x30,
187 DVBT_BANDW_CAP = 0x31,
188 DVBT_BANDW_SEL = 0x32,
189 DVBT_GUARD_INTERV_CAP = 0x33,
190 DVBT_GUARD_INTERV_SEL = 0x34,
191 DVBT_MODULATION_CAP = 0x35,
192 DVBT_MODULATION_SEL = 0x36,
193 DVBT_INNER_FEC_RATE_CAP = 0x37,
194 DVBT_INNER_FEC_RATE_SEL = 0x38,
195 DVBT_TRANS_MODE_CAP = 0x39,
196 DVBT_TRANS_MODE_SEL = 0x3a,
197 DVBT_SEARCH_RANG = 0x3c,
198
199 TUNER_SETUP_ANALOG = 0x40,
200 TUNER_SETUP_DIGITAL = 0x41,
201 TUNER_SETUP_FM_RADIO = 0x42,
202 TAKE_REQUEST = 0x43, /* Take effect of the command */
203 PLAY_SERVICE = 0x44, /* Play start or Play stop */
204 TUNER_STATUS = 0x45,
205 TUNE_PROP_DVBT = 0x46,
206 ERR_RATE_STATS = 0x47,
207 TUNER_BER_RATE = 0x48,
208
209 SCAN_CAPS = 0x50,
210 SCAN_SETUP = 0x51,
211 SCAN_SERVICE = 0x52,
212 SCAN_STATS = 0x53,
213
214 PID_SET = 0x58,
215 PID_UNSET = 0x59,
216 PID_LIST = 0x5a,
217
218 IRD_CAP = 0x60,
219 IRD_MODE_SEL = 0x61,
220 IRD_SETUP = 0x62,
221
222 PTM_MODE_CAP = 0x70,
223 PTM_MODE_SEL = 0x71,
224 PTM_SERVICE = 0x72,
225 TUNER_REG_SCRIPT = 0x73,
226 CMD_CHIP_RST = 0x74,
227};
228
229enum tlg_bw {
230 TLG_BW_5 = 5,
231 TLG_BW_6 = 6,
232 TLG_BW_7 = 7,
233 TLG_BW_8 = 8,
234 TLG_BW_12 = 12,
235 TLG_BW_15 = 15
236};
237
238struct cmd_firmware_vers_s {
239 uint8_t fw_rev_major;
240 uint8_t fw_rev_minor;
241 uint16_t fw_patch;
242};
243#endif /* VENDOR_CMD_H_ */