diff options
Diffstat (limited to 'drivers/media/video/saa7134')
-rw-r--r-- | drivers/media/video/saa7134/Makefile | 11 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa6752hs.c | 543 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-cards.c | 2018 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-core.c | 1237 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-dvb.c | 266 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-empress.c | 436 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-i2c.c | 453 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-input.c | 491 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-oss.c | 857 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-reg.h | 366 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-ts.c | 243 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-tvaudio.c | 1031 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-vbi.c | 270 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134-video.c | 2406 | ||||
-rw-r--r-- | drivers/media/video/saa7134/saa7134.h | 618 |
15 files changed, 11246 insertions, 0 deletions
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile new file mode 100644 index 000000000000..e577a06b136b --- /dev/null +++ b/drivers/media/video/saa7134/Makefile | |||
@@ -0,0 +1,11 @@ | |||
1 | |||
2 | saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \ | ||
3 | saa7134-oss.o saa7134-ts.o saa7134-tvaudio.o \ | ||
4 | saa7134-vbi.o saa7134-video.o saa7134-input.o | ||
5 | |||
6 | obj-$(CONFIG_VIDEO_SAA7134) += saa7134.o saa7134-empress.o saa6752hs.o | ||
7 | obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o | ||
8 | |||
9 | EXTRA_CFLAGS += -I$(src)/.. | ||
10 | EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core | ||
11 | EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/frontends | ||
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c new file mode 100644 index 000000000000..cee13584c9cf --- /dev/null +++ b/drivers/media/video/saa7134/saa6752hs.c | |||
@@ -0,0 +1,543 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/sched.h> | ||
4 | #include <linux/string.h> | ||
5 | #include <linux/timer.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <linux/errno.h> | ||
8 | #include <linux/slab.h> | ||
9 | #include <linux/poll.h> | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/types.h> | ||
12 | #include <linux/videodev.h> | ||
13 | #include <linux/init.h> | ||
14 | #include <linux/crc32.h> | ||
15 | |||
16 | #include <media/id.h> | ||
17 | |||
18 | #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 | ||
19 | #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 | ||
20 | #define MPEG_TOTAL_TARGET_BITRATE_MAX 27000 | ||
21 | #define MPEG_PID_MAX ((1 << 14) - 1) | ||
22 | |||
23 | /* Addresses to scan */ | ||
24 | static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END}; | ||
25 | static unsigned short normal_i2c_range[] = {I2C_CLIENT_END}; | ||
26 | I2C_CLIENT_INSMOD; | ||
27 | |||
28 | MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); | ||
29 | MODULE_AUTHOR("Andrew de Quincey"); | ||
30 | MODULE_LICENSE("GPL"); | ||
31 | |||
32 | static struct i2c_driver driver; | ||
33 | static struct i2c_client client_template; | ||
34 | |||
35 | struct saa6752hs_state { | ||
36 | struct i2c_client client; | ||
37 | struct v4l2_mpeg_compression params; | ||
38 | }; | ||
39 | |||
40 | enum saa6752hs_command { | ||
41 | SAA6752HS_COMMAND_RESET = 0, | ||
42 | SAA6752HS_COMMAND_STOP = 1, | ||
43 | SAA6752HS_COMMAND_START = 2, | ||
44 | SAA6752HS_COMMAND_PAUSE = 3, | ||
45 | SAA6752HS_COMMAND_RECONFIGURE = 4, | ||
46 | SAA6752HS_COMMAND_SLEEP = 5, | ||
47 | SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6, | ||
48 | |||
49 | SAA6752HS_COMMAND_MAX | ||
50 | }; | ||
51 | |||
52 | /* ---------------------------------------------------------------------- */ | ||
53 | |||
54 | static u8 PAT[] = { | ||
55 | 0xc2, // i2c register | ||
56 | 0x00, // table number for encoder | ||
57 | |||
58 | 0x47, // sync | ||
59 | 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) | ||
60 | 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) | ||
61 | |||
62 | 0x00, // PSI pointer to start of table | ||
63 | |||
64 | 0x00, // tid(0) | ||
65 | 0xb0, 0x0d, // section_syntax_indicator(1), section_length(13) | ||
66 | |||
67 | 0x00, 0x01, // transport_stream_id(1) | ||
68 | |||
69 | 0xc1, // version_number(0), current_next_indicator(1) | ||
70 | |||
71 | 0x00, 0x00, // section_number(0), last_section_number(0) | ||
72 | |||
73 | 0x00, 0x01, // program_number(1) | ||
74 | |||
75 | 0xe0, 0x00, // PMT PID | ||
76 | |||
77 | 0x00, 0x00, 0x00, 0x00 // CRC32 | ||
78 | }; | ||
79 | |||
80 | static u8 PMT[] = { | ||
81 | 0xc2, // i2c register | ||
82 | 0x01, // table number for encoder | ||
83 | |||
84 | 0x47, // sync | ||
85 | 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid | ||
86 | 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) | ||
87 | |||
88 | 0x00, // PSI pointer to start of table | ||
89 | |||
90 | 0x02, // tid(2) | ||
91 | 0xb0, 0x17, // section_syntax_indicator(1), section_length(23) | ||
92 | |||
93 | 0x00, 0x01, // program_number(1) | ||
94 | |||
95 | 0xc1, // version_number(0), current_next_indicator(1) | ||
96 | |||
97 | 0x00, 0x00, // section_number(0), last_section_number(0) | ||
98 | |||
99 | 0xe0, 0x00, // PCR_PID | ||
100 | |||
101 | 0xf0, 0x00, // program_info_length(0) | ||
102 | |||
103 | 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid | ||
104 | 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid | ||
105 | |||
106 | 0x00, 0x00, 0x00, 0x00 // CRC32 | ||
107 | }; | ||
108 | |||
109 | static struct v4l2_mpeg_compression param_defaults = | ||
110 | { | ||
111 | .st_type = V4L2_MPEG_TS_2, | ||
112 | .st_bitrate = { | ||
113 | .mode = V4L2_BITRATE_CBR, | ||
114 | .target = 7000, | ||
115 | }, | ||
116 | |||
117 | .ts_pid_pmt = 16, | ||
118 | .ts_pid_video = 260, | ||
119 | .ts_pid_audio = 256, | ||
120 | .ts_pid_pcr = 259, | ||
121 | |||
122 | .vi_type = V4L2_MPEG_VI_2, | ||
123 | .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3, | ||
124 | .vi_bitrate = { | ||
125 | .mode = V4L2_BITRATE_VBR, | ||
126 | .target = 4000, | ||
127 | .max = 6000, | ||
128 | }, | ||
129 | |||
130 | .au_type = V4L2_MPEG_AU_2_II, | ||
131 | .au_bitrate = { | ||
132 | .mode = V4L2_BITRATE_CBR, | ||
133 | .target = 256, | ||
134 | }, | ||
135 | |||
136 | #if 0 | ||
137 | /* FIXME: size? via S_FMT? */ | ||
138 | .video_format = MPEG_VIDEO_FORMAT_D1, | ||
139 | #endif | ||
140 | }; | ||
141 | |||
142 | /* ---------------------------------------------------------------------- */ | ||
143 | |||
144 | static int saa6752hs_chip_command(struct i2c_client* client, | ||
145 | enum saa6752hs_command command) | ||
146 | { | ||
147 | unsigned char buf[3]; | ||
148 | unsigned long timeout; | ||
149 | int status = 0; | ||
150 | |||
151 | // execute the command | ||
152 | switch(command) { | ||
153 | case SAA6752HS_COMMAND_RESET: | ||
154 | buf[0] = 0x00; | ||
155 | break; | ||
156 | |||
157 | case SAA6752HS_COMMAND_STOP: | ||
158 | buf[0] = 0x03; | ||
159 | break; | ||
160 | |||
161 | case SAA6752HS_COMMAND_START: | ||
162 | buf[0] = 0x02; | ||
163 | break; | ||
164 | |||
165 | case SAA6752HS_COMMAND_PAUSE: | ||
166 | buf[0] = 0x04; | ||
167 | break; | ||
168 | |||
169 | case SAA6752HS_COMMAND_RECONFIGURE: | ||
170 | buf[0] = 0x05; | ||
171 | break; | ||
172 | |||
173 | case SAA6752HS_COMMAND_SLEEP: | ||
174 | buf[0] = 0x06; | ||
175 | break; | ||
176 | |||
177 | case SAA6752HS_COMMAND_RECONFIGURE_FORCE: | ||
178 | buf[0] = 0x07; | ||
179 | break; | ||
180 | |||
181 | default: | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | // set it and wait for it to be so | ||
186 | i2c_master_send(client, buf, 1); | ||
187 | timeout = jiffies + HZ * 3; | ||
188 | for (;;) { | ||
189 | // get the current status | ||
190 | buf[0] = 0x10; | ||
191 | i2c_master_send(client, buf, 1); | ||
192 | i2c_master_recv(client, buf, 1); | ||
193 | |||
194 | if (!(buf[0] & 0x20)) | ||
195 | break; | ||
196 | if (time_after(jiffies,timeout)) { | ||
197 | status = -ETIMEDOUT; | ||
198 | break; | ||
199 | } | ||
200 | |||
201 | // wait a bit | ||
202 | msleep(10); | ||
203 | } | ||
204 | |||
205 | // delay a bit to let encoder settle | ||
206 | msleep(50); | ||
207 | |||
208 | // done | ||
209 | return status; | ||
210 | } | ||
211 | |||
212 | |||
213 | static int saa6752hs_set_bitrate(struct i2c_client* client, | ||
214 | struct v4l2_mpeg_compression* params) | ||
215 | { | ||
216 | u8 buf[3]; | ||
217 | |||
218 | // set the bitrate mode | ||
219 | buf[0] = 0x71; | ||
220 | buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1; | ||
221 | i2c_master_send(client, buf, 2); | ||
222 | |||
223 | // set the video bitrate | ||
224 | if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) { | ||
225 | // set the target bitrate | ||
226 | buf[0] = 0x80; | ||
227 | buf[1] = params->vi_bitrate.target >> 8; | ||
228 | buf[2] = params->vi_bitrate.target & 0xff; | ||
229 | i2c_master_send(client, buf, 3); | ||
230 | |||
231 | // set the max bitrate | ||
232 | buf[0] = 0x81; | ||
233 | buf[1] = params->vi_bitrate.max >> 8; | ||
234 | buf[2] = params->vi_bitrate.max & 0xff; | ||
235 | i2c_master_send(client, buf, 3); | ||
236 | } else { | ||
237 | // set the target bitrate (no max bitrate for CBR) | ||
238 | buf[0] = 0x81; | ||
239 | buf[1] = params->vi_bitrate.target >> 8; | ||
240 | buf[2] = params->vi_bitrate.target & 0xff; | ||
241 | i2c_master_send(client, buf, 3); | ||
242 | } | ||
243 | |||
244 | // set the audio bitrate | ||
245 | buf[0] = 0x94; | ||
246 | buf[1] = (256 == params->au_bitrate.target) ? 0 : 1; | ||
247 | i2c_master_send(client, buf, 2); | ||
248 | |||
249 | // set the total bitrate | ||
250 | buf[0] = 0xb1; | ||
251 | buf[1] = params->st_bitrate.target >> 8; | ||
252 | buf[2] = params->st_bitrate.target & 0xff; | ||
253 | i2c_master_send(client, buf, 3); | ||
254 | |||
255 | // return success | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | |||
260 | static void saa6752hs_set_params(struct i2c_client* client, | ||
261 | struct v4l2_mpeg_compression* params) | ||
262 | { | ||
263 | struct saa6752hs_state *h = i2c_get_clientdata(client); | ||
264 | |||
265 | /* check PIDs */ | ||
266 | if (params->ts_pid_pmt <= MPEG_PID_MAX) | ||
267 | h->params.ts_pid_pmt = params->ts_pid_pmt; | ||
268 | if (params->ts_pid_pcr <= MPEG_PID_MAX) | ||
269 | h->params.ts_pid_pcr = params->ts_pid_pcr; | ||
270 | if (params->ts_pid_video <= MPEG_PID_MAX) | ||
271 | h->params.ts_pid_video = params->ts_pid_video; | ||
272 | if (params->ts_pid_audio <= MPEG_PID_MAX) | ||
273 | h->params.ts_pid_audio = params->ts_pid_audio; | ||
274 | |||
275 | /* check bitrate parameters */ | ||
276 | if ((params->vi_bitrate.mode == V4L2_BITRATE_CBR) || | ||
277 | (params->vi_bitrate.mode == V4L2_BITRATE_VBR)) | ||
278 | h->params.vi_bitrate.mode = params->vi_bitrate.mode; | ||
279 | if (params->vi_bitrate.mode != V4L2_BITRATE_NONE) | ||
280 | h->params.st_bitrate.target = params->st_bitrate.target; | ||
281 | if (params->vi_bitrate.mode != V4L2_BITRATE_NONE) | ||
282 | h->params.vi_bitrate.target = params->vi_bitrate.target; | ||
283 | if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) | ||
284 | h->params.vi_bitrate.max = params->vi_bitrate.max; | ||
285 | if (params->au_bitrate.mode != V4L2_BITRATE_NONE) | ||
286 | h->params.au_bitrate.target = params->au_bitrate.target; | ||
287 | |||
288 | /* aspect ratio */ | ||
289 | if (params->vi_aspect_ratio == V4L2_MPEG_ASPECT_4_3 || | ||
290 | params->vi_aspect_ratio == V4L2_MPEG_ASPECT_16_9) | ||
291 | h->params.vi_aspect_ratio = params->vi_aspect_ratio; | ||
292 | |||
293 | /* range checks */ | ||
294 | if (h->params.st_bitrate.target > MPEG_TOTAL_TARGET_BITRATE_MAX) | ||
295 | h->params.st_bitrate.target = MPEG_TOTAL_TARGET_BITRATE_MAX; | ||
296 | if (h->params.vi_bitrate.target > MPEG_VIDEO_TARGET_BITRATE_MAX) | ||
297 | h->params.vi_bitrate.target = MPEG_VIDEO_TARGET_BITRATE_MAX; | ||
298 | if (h->params.vi_bitrate.max > MPEG_VIDEO_MAX_BITRATE_MAX) | ||
299 | h->params.vi_bitrate.max = MPEG_VIDEO_MAX_BITRATE_MAX; | ||
300 | if (h->params.au_bitrate.target <= 256) | ||
301 | h->params.au_bitrate.target = 256; | ||
302 | else | ||
303 | h->params.au_bitrate.target = 384; | ||
304 | } | ||
305 | |||
306 | static int saa6752hs_init(struct i2c_client* client) | ||
307 | { | ||
308 | unsigned char buf[9], buf2[4]; | ||
309 | struct saa6752hs_state *h; | ||
310 | u32 crc; | ||
311 | unsigned char localPAT[256]; | ||
312 | unsigned char localPMT[256]; | ||
313 | |||
314 | h = i2c_get_clientdata(client); | ||
315 | |||
316 | // Set video format - must be done first as it resets other settings | ||
317 | buf[0] = 0x41; | ||
318 | buf[1] = 0 /* MPEG_VIDEO_FORMAT_D1 */; | ||
319 | i2c_master_send(client, buf, 2); | ||
320 | |||
321 | // set bitrate | ||
322 | saa6752hs_set_bitrate(client, &h->params); | ||
323 | |||
324 | // Set GOP structure {3, 13} | ||
325 | buf[0] = 0x72; | ||
326 | buf[1] = 0x03; | ||
327 | buf[2] = 0x0D; | ||
328 | i2c_master_send(client,buf,3); | ||
329 | |||
330 | // Set minimum Q-scale {4} | ||
331 | buf[0] = 0x82; | ||
332 | buf[1] = 0x04; | ||
333 | i2c_master_send(client,buf,2); | ||
334 | |||
335 | // Set maximum Q-scale {12} | ||
336 | buf[0] = 0x83; | ||
337 | buf[1] = 0x0C; | ||
338 | i2c_master_send(client,buf,2); | ||
339 | |||
340 | // Set Output Protocol | ||
341 | buf[0] = 0xD0; | ||
342 | buf[1] = 0x81; | ||
343 | i2c_master_send(client,buf,2); | ||
344 | |||
345 | // Set video output stream format {TS} | ||
346 | buf[0] = 0xB0; | ||
347 | buf[1] = 0x05; | ||
348 | i2c_master_send(client,buf,2); | ||
349 | |||
350 | /* compute PAT */ | ||
351 | memcpy(localPAT, PAT, sizeof(PAT)); | ||
352 | localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f); | ||
353 | localPAT[18] = h->params.ts_pid_pmt & 0xff; | ||
354 | crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4); | ||
355 | localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF; | ||
356 | localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF; | ||
357 | localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF; | ||
358 | localPAT[sizeof(PAT) - 1] = crc & 0xFF; | ||
359 | |||
360 | /* compute PMT */ | ||
361 | memcpy(localPMT, PMT, sizeof(PMT)); | ||
362 | localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f); | ||
363 | localPMT[4] = h->params.ts_pid_pmt & 0xff; | ||
364 | localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F); | ||
365 | localPMT[16] = h->params.ts_pid_pcr & 0xFF; | ||
366 | localPMT[20] = 0xE0 | ((h->params.ts_pid_video >> 8) & 0x0F); | ||
367 | localPMT[21] = h->params.ts_pid_video & 0xFF; | ||
368 | localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F); | ||
369 | localPMT[26] = h->params.ts_pid_audio & 0xFF; | ||
370 | crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4); | ||
371 | localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF; | ||
372 | localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF; | ||
373 | localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF; | ||
374 | localPMT[sizeof(PMT) - 1] = crc & 0xFF; | ||
375 | |||
376 | // Set Audio PID | ||
377 | buf[0] = 0xC1; | ||
378 | buf[1] = (h->params.ts_pid_audio >> 8) & 0xFF; | ||
379 | buf[2] = h->params.ts_pid_audio & 0xFF; | ||
380 | i2c_master_send(client,buf,3); | ||
381 | |||
382 | // Set Video PID | ||
383 | buf[0] = 0xC0; | ||
384 | buf[1] = (h->params.ts_pid_video >> 8) & 0xFF; | ||
385 | buf[2] = h->params.ts_pid_video & 0xFF; | ||
386 | i2c_master_send(client,buf,3); | ||
387 | |||
388 | // Set PCR PID | ||
389 | buf[0] = 0xC4; | ||
390 | buf[1] = (h->params.ts_pid_pcr >> 8) & 0xFF; | ||
391 | buf[2] = h->params.ts_pid_pcr & 0xFF; | ||
392 | i2c_master_send(client,buf,3); | ||
393 | |||
394 | // Send SI tables | ||
395 | i2c_master_send(client,localPAT,sizeof(PAT)); | ||
396 | i2c_master_send(client,localPMT,sizeof(PMT)); | ||
397 | |||
398 | // mute then unmute audio. This removes buzzing artefacts | ||
399 | buf[0] = 0xa4; | ||
400 | buf[1] = 1; | ||
401 | i2c_master_send(client, buf, 2); | ||
402 | buf[1] = 0; | ||
403 | i2c_master_send(client, buf, 2); | ||
404 | |||
405 | // start it going | ||
406 | saa6752hs_chip_command(client, SAA6752HS_COMMAND_START); | ||
407 | |||
408 | // readout current state | ||
409 | buf[0] = 0xE1; | ||
410 | buf[1] = 0xA7; | ||
411 | buf[2] = 0xFE; | ||
412 | buf[3] = 0x82; | ||
413 | buf[4] = 0xB0; | ||
414 | i2c_master_send(client, buf, 5); | ||
415 | i2c_master_recv(client, buf2, 4); | ||
416 | |||
417 | // change aspect ratio | ||
418 | buf[0] = 0xE0; | ||
419 | buf[1] = 0xA7; | ||
420 | buf[2] = 0xFE; | ||
421 | buf[3] = 0x82; | ||
422 | buf[4] = 0xB0; | ||
423 | buf[5] = buf2[0]; | ||
424 | switch(h->params.vi_aspect_ratio) { | ||
425 | case V4L2_MPEG_ASPECT_16_9: | ||
426 | buf[6] = buf2[1] | 0x40; | ||
427 | break; | ||
428 | case V4L2_MPEG_ASPECT_4_3: | ||
429 | default: | ||
430 | buf[6] = buf2[1] & 0xBF; | ||
431 | break; | ||
432 | break; | ||
433 | } | ||
434 | buf[7] = buf2[2]; | ||
435 | buf[8] = buf2[3]; | ||
436 | i2c_master_send(client, buf, 9); | ||
437 | |||
438 | // return success | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) | ||
443 | { | ||
444 | struct saa6752hs_state *h; | ||
445 | |||
446 | printk("saa6752hs: chip found @ 0x%x\n", addr<<1); | ||
447 | |||
448 | if (NULL == (h = kmalloc(sizeof(*h), GFP_KERNEL))) | ||
449 | return -ENOMEM; | ||
450 | memset(h,0,sizeof(*h)); | ||
451 | h->client = client_template; | ||
452 | h->params = param_defaults; | ||
453 | h->client.adapter = adap; | ||
454 | h->client.addr = addr; | ||
455 | |||
456 | i2c_set_clientdata(&h->client, h); | ||
457 | i2c_attach_client(&h->client); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int saa6752hs_probe(struct i2c_adapter *adap) | ||
462 | { | ||
463 | if (adap->class & I2C_CLASS_TV_ANALOG) | ||
464 | return i2c_probe(adap, &addr_data, saa6752hs_attach); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int saa6752hs_detach(struct i2c_client *client) | ||
469 | { | ||
470 | struct saa6752hs_state *h; | ||
471 | |||
472 | h = i2c_get_clientdata(client); | ||
473 | i2c_detach_client(client); | ||
474 | kfree(h); | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | static int | ||
479 | saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) | ||
480 | { | ||
481 | struct saa6752hs_state *h = i2c_get_clientdata(client); | ||
482 | struct v4l2_mpeg_compression *params = arg; | ||
483 | int err = 0; | ||
484 | |||
485 | switch (cmd) { | ||
486 | case VIDIOC_S_MPEGCOMP: | ||
487 | if (NULL == params) { | ||
488 | /* apply settings and start encoder */ | ||
489 | saa6752hs_init(client); | ||
490 | break; | ||
491 | } | ||
492 | saa6752hs_set_params(client, params); | ||
493 | /* fall through */ | ||
494 | case VIDIOC_G_MPEGCOMP: | ||
495 | *params = h->params; | ||
496 | break; | ||
497 | default: | ||
498 | /* nothing */ | ||
499 | break; | ||
500 | } | ||
501 | |||
502 | return err; | ||
503 | } | ||
504 | |||
505 | /* ----------------------------------------------------------------------- */ | ||
506 | |||
507 | static struct i2c_driver driver = { | ||
508 | .owner = THIS_MODULE, | ||
509 | .name = "i2c saa6752hs MPEG encoder", | ||
510 | .id = I2C_DRIVERID_SAA6752HS, | ||
511 | .flags = I2C_DF_NOTIFY, | ||
512 | .attach_adapter = saa6752hs_probe, | ||
513 | .detach_client = saa6752hs_detach, | ||
514 | .command = saa6752hs_command, | ||
515 | }; | ||
516 | |||
517 | static struct i2c_client client_template = | ||
518 | { | ||
519 | I2C_DEVNAME("saa6752hs"), | ||
520 | .flags = I2C_CLIENT_ALLOW_USE, | ||
521 | .driver = &driver, | ||
522 | }; | ||
523 | |||
524 | static int __init saa6752hs_init_module(void) | ||
525 | { | ||
526 | return i2c_add_driver(&driver); | ||
527 | } | ||
528 | |||
529 | static void __exit saa6752hs_cleanup_module(void) | ||
530 | { | ||
531 | i2c_del_driver(&driver); | ||
532 | } | ||
533 | |||
534 | module_init(saa6752hs_init_module); | ||
535 | module_exit(saa6752hs_cleanup_module); | ||
536 | |||
537 | /* | ||
538 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
539 | * --------------------------------------------------------------------------- | ||
540 | * Local variables: | ||
541 | * c-basic-offset: 8 | ||
542 | * End: | ||
543 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c new file mode 100644 index 000000000000..180d3175ea5b --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-cards.c | |||
@@ -0,0 +1,2018 @@ | |||
1 | |||
2 | /* | ||
3 | * $Id: saa7134-cards.c,v 1.54 2005/03/07 12:01:51 kraxel Exp $ | ||
4 | * | ||
5 | * device driver for philips saa7134 based TV cards | ||
6 | * card-specific stuff. | ||
7 | * | ||
8 | * (c) 2001-04 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/module.h> | ||
27 | |||
28 | #include "saa7134-reg.h" | ||
29 | #include "saa7134.h" | ||
30 | |||
31 | /* commly used strings */ | ||
32 | static char name_mute[] = "mute"; | ||
33 | static char name_radio[] = "Radio"; | ||
34 | static char name_tv[] = "Television"; | ||
35 | static char name_tv_mono[] = "TV (mono only)"; | ||
36 | static char name_comp1[] = "Composite1"; | ||
37 | static char name_comp2[] = "Composite2"; | ||
38 | static char name_comp3[] = "Composite3"; | ||
39 | static char name_comp4[] = "Composite4"; | ||
40 | static char name_svideo[] = "S-Video"; | ||
41 | |||
42 | /* ------------------------------------------------------------------ */ | ||
43 | /* board config info */ | ||
44 | |||
45 | struct saa7134_board saa7134_boards[] = { | ||
46 | [SAA7134_BOARD_UNKNOWN] = { | ||
47 | .name = "UNKNOWN/GENERIC", | ||
48 | .audio_clock = 0x00187de7, | ||
49 | .tuner_type = TUNER_ABSENT, | ||
50 | .inputs = {{ | ||
51 | .name = "default", | ||
52 | .vmux = 0, | ||
53 | .amux = LINE1, | ||
54 | }}, | ||
55 | }, | ||
56 | [SAA7134_BOARD_PROTEUS_PRO] = { | ||
57 | /* /me */ | ||
58 | .name = "Proteus Pro [philips reference design]", | ||
59 | .audio_clock = 0x00187de7, | ||
60 | .tuner_type = TUNER_PHILIPS_PAL, | ||
61 | .inputs = {{ | ||
62 | .name = name_comp1, | ||
63 | .vmux = 0, | ||
64 | .amux = LINE1, | ||
65 | },{ | ||
66 | .name = name_tv, | ||
67 | .vmux = 1, | ||
68 | .amux = TV, | ||
69 | .tv = 1, | ||
70 | },{ | ||
71 | .name = name_tv_mono, | ||
72 | .vmux = 1, | ||
73 | .amux = LINE2, | ||
74 | .tv = 1, | ||
75 | }}, | ||
76 | .radio = { | ||
77 | .name = name_radio, | ||
78 | .amux = LINE2, | ||
79 | }, | ||
80 | }, | ||
81 | [SAA7134_BOARD_FLYVIDEO3000] = { | ||
82 | /* "Marco d'Itri" <md@Linux.IT> */ | ||
83 | .name = "LifeView FlyVIDEO3000", | ||
84 | .audio_clock = 0x00200000, | ||
85 | .tuner_type = TUNER_PHILIPS_PAL, | ||
86 | .gpiomask = 0xe000, | ||
87 | .inputs = {{ | ||
88 | .name = name_tv, | ||
89 | .vmux = 1, | ||
90 | .amux = TV, | ||
91 | .gpio = 0x8000, | ||
92 | .tv = 1, | ||
93 | },{ | ||
94 | .name = name_tv_mono, | ||
95 | .vmux = 1, | ||
96 | .amux = LINE2, | ||
97 | .gpio = 0x0000, | ||
98 | .tv = 1, | ||
99 | },{ | ||
100 | .name = name_comp1, | ||
101 | .vmux = 0, | ||
102 | .amux = LINE2, | ||
103 | .gpio = 0x4000, | ||
104 | },{ | ||
105 | .name = name_comp2, | ||
106 | .vmux = 3, | ||
107 | .amux = LINE2, | ||
108 | .gpio = 0x4000, | ||
109 | },{ | ||
110 | .name = name_svideo, | ||
111 | .vmux = 8, | ||
112 | .amux = LINE2, | ||
113 | .gpio = 0x4000, | ||
114 | }}, | ||
115 | .radio = { | ||
116 | .name = name_radio, | ||
117 | .amux = LINE2, | ||
118 | .gpio = 0x2000, | ||
119 | }, | ||
120 | }, | ||
121 | [SAA7134_BOARD_FLYVIDEO2000] = { | ||
122 | /* "TC Wan" <tcwan@cs.usm.my> */ | ||
123 | .name = "LifeView FlyVIDEO2000", | ||
124 | .audio_clock = 0x00200000, | ||
125 | .tuner_type = TUNER_LG_PAL_NEW_TAPC, | ||
126 | .gpiomask = 0xe000, | ||
127 | .inputs = {{ | ||
128 | .name = name_tv, | ||
129 | .vmux = 1, | ||
130 | .amux = LINE2, | ||
131 | .gpio = 0x0000, | ||
132 | .tv = 1, | ||
133 | },{ | ||
134 | .name = name_comp1, | ||
135 | .vmux = 0, | ||
136 | .amux = LINE2, | ||
137 | .gpio = 0x4000, | ||
138 | },{ | ||
139 | .name = name_comp2, | ||
140 | .vmux = 3, | ||
141 | .amux = LINE2, | ||
142 | .gpio = 0x4000, | ||
143 | },{ | ||
144 | .name = name_svideo, | ||
145 | .vmux = 8, | ||
146 | .amux = LINE2, | ||
147 | .gpio = 0x4000, | ||
148 | }}, | ||
149 | .radio = { | ||
150 | .name = name_radio, | ||
151 | .amux = LINE2, | ||
152 | .gpio = 0x2000, | ||
153 | }, | ||
154 | .mute = { | ||
155 | .name = name_mute, | ||
156 | .amux = LINE2, | ||
157 | .gpio = 0x8000, | ||
158 | }, | ||
159 | }, | ||
160 | [SAA7134_BOARD_FLYTVPLATINUM_MINI] = { | ||
161 | /* "Arnaud Quette" <aquette@free.fr> */ | ||
162 | .name = "LifeView FlyTV Platinum Mini", | ||
163 | .audio_clock = 0x00200000, | ||
164 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
165 | .inputs = {{ | ||
166 | .name = name_tv, | ||
167 | .vmux = 1, | ||
168 | .amux = LINE2, | ||
169 | .tv = 1, | ||
170 | },{ | ||
171 | .name = name_comp1, | ||
172 | .vmux = 0, | ||
173 | .amux = LINE2, | ||
174 | },{ | ||
175 | .name = name_svideo, | ||
176 | .vmux = 8, | ||
177 | .amux = LINE2, | ||
178 | }}, | ||
179 | }, | ||
180 | [SAA7134_BOARD_FLYTVPLATINUM_FM] = { | ||
181 | /* LifeView FlyTV Platinum FM (LR214WF) */ | ||
182 | /* "Peter Missel <peter.missel@onlinehome.de> */ | ||
183 | .name = "LifeView FlyTV Platinum FM", | ||
184 | .audio_clock = 0x00200000, | ||
185 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
186 | // .gpiomask = 0xe000, | ||
187 | .inputs = {{ | ||
188 | .name = name_tv, | ||
189 | .vmux = 1, | ||
190 | .amux = TV, | ||
191 | // .gpio = 0x0000, | ||
192 | .tv = 1, | ||
193 | },{ | ||
194 | /* .name = name_tv_mono, | ||
195 | .vmux = 1, | ||
196 | .amux = LINE2, | ||
197 | .gpio = 0x0000, | ||
198 | .tv = 1, | ||
199 | },{ | ||
200 | */ .name = name_comp1, /* Composite signal on S-Video input */ | ||
201 | .vmux = 0, | ||
202 | .amux = LINE2, | ||
203 | // .gpio = 0x4000, | ||
204 | },{ | ||
205 | .name = name_comp2, /* Composite input */ | ||
206 | .vmux = 3, | ||
207 | .amux = LINE2, | ||
208 | // .gpio = 0x4000, | ||
209 | },{ | ||
210 | .name = name_svideo, /* S-Video signal on S-Video input */ | ||
211 | .vmux = 8, | ||
212 | .amux = LINE2, | ||
213 | // .gpio = 0x4000, | ||
214 | }}, | ||
215 | /* .radio = { | ||
216 | .name = name_radio, | ||
217 | .amux = LINE2, | ||
218 | .gpio = 0x2000, | ||
219 | }, | ||
220 | */ }, | ||
221 | [SAA7134_BOARD_EMPRESS] = { | ||
222 | /* "Gert Vervoort" <gert.vervoort@philips.com> */ | ||
223 | .name = "EMPRESS", | ||
224 | .audio_clock = 0x00187de7, | ||
225 | .tuner_type = TUNER_PHILIPS_PAL, | ||
226 | .inputs = {{ | ||
227 | .name = name_comp1, | ||
228 | .vmux = 0, | ||
229 | .amux = LINE1, | ||
230 | },{ | ||
231 | .name = name_svideo, | ||
232 | .vmux = 8, | ||
233 | .amux = LINE1, | ||
234 | },{ | ||
235 | .name = name_tv, | ||
236 | .vmux = 1, | ||
237 | .amux = LINE2, | ||
238 | .tv = 1, | ||
239 | }}, | ||
240 | .radio = { | ||
241 | .name = name_radio, | ||
242 | .amux = LINE2, | ||
243 | }, | ||
244 | .mpeg = SAA7134_MPEG_EMPRESS, | ||
245 | .video_out = CCIR656, | ||
246 | }, | ||
247 | [SAA7134_BOARD_MONSTERTV] = { | ||
248 | /* "K.Ohta" <alpha292@bremen.or.jp> */ | ||
249 | .name = "SKNet Monster TV", | ||
250 | .audio_clock = 0x00187de7, | ||
251 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
252 | .inputs = {{ | ||
253 | .name = name_tv, | ||
254 | .vmux = 1, | ||
255 | .amux = TV, | ||
256 | .tv = 1, | ||
257 | },{ | ||
258 | .name = name_comp1, | ||
259 | .vmux = 0, | ||
260 | .amux = LINE1, | ||
261 | },{ | ||
262 | .name = name_svideo, | ||
263 | .vmux = 8, | ||
264 | .amux = LINE1, | ||
265 | }}, | ||
266 | .radio = { | ||
267 | .name = name_radio, | ||
268 | .amux = LINE2, | ||
269 | }, | ||
270 | }, | ||
271 | [SAA7134_BOARD_MD9717] = { | ||
272 | .name = "Tevion MD 9717", | ||
273 | .audio_clock = 0x00200000, | ||
274 | .tuner_type = TUNER_PHILIPS_PAL, | ||
275 | .inputs = {{ | ||
276 | .name = name_tv, | ||
277 | .vmux = 1, | ||
278 | .amux = TV, | ||
279 | .tv = 1, | ||
280 | },{ | ||
281 | /* workaround for problems with normal TV sound */ | ||
282 | .name = name_tv_mono, | ||
283 | .vmux = 1, | ||
284 | .amux = LINE2, | ||
285 | .tv = 1, | ||
286 | },{ | ||
287 | .name = name_comp1, | ||
288 | .vmux = 2, | ||
289 | .amux = LINE1, | ||
290 | },{ | ||
291 | .name = name_comp2, | ||
292 | .vmux = 3, | ||
293 | .amux = LINE1, | ||
294 | },{ | ||
295 | .name = name_svideo, | ||
296 | .vmux = 8, | ||
297 | .amux = LINE1, | ||
298 | }}, | ||
299 | .radio = { | ||
300 | .name = name_radio, | ||
301 | .amux = LINE2, | ||
302 | }, | ||
303 | }, | ||
304 | [SAA7134_BOARD_TVSTATION_RDS] = { | ||
305 | /* Typhoon TV Tuner RDS: Art.Nr. 50694 */ | ||
306 | .name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS", | ||
307 | .audio_clock = 0x00200000, | ||
308 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
309 | .tda9887_conf = TDA9887_PRESENT, | ||
310 | .inputs = {{ | ||
311 | .name = name_tv, | ||
312 | .vmux = 1, | ||
313 | .amux = TV, | ||
314 | .tv = 1, | ||
315 | },{ | ||
316 | .name = name_tv_mono, | ||
317 | .vmux = 1, | ||
318 | .amux = LINE2, | ||
319 | .tv = 1, | ||
320 | },{ | ||
321 | |||
322 | .name = name_svideo, | ||
323 | .vmux = 8, | ||
324 | .amux = LINE1, | ||
325 | },{ | ||
326 | .name = name_comp1, | ||
327 | .vmux = 3, | ||
328 | .amux = LINE1, | ||
329 | },{ | ||
330 | |||
331 | .name = "CVid over SVid", | ||
332 | .vmux = 0, | ||
333 | .amux = LINE1, | ||
334 | }}, | ||
335 | .radio = { | ||
336 | .name = name_radio, | ||
337 | .amux = LINE2, | ||
338 | }, | ||
339 | }, | ||
340 | [SAA7134_BOARD_TVSTATION_DVR] = { | ||
341 | .name = "KNC One TV-Station DVR", | ||
342 | .audio_clock = 0x00200000, | ||
343 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
344 | .tda9887_conf = TDA9887_PRESENT, | ||
345 | .gpiomask = 0x820000, | ||
346 | .inputs = {{ | ||
347 | .name = name_tv, | ||
348 | .vmux = 1, | ||
349 | .amux = LINE2, | ||
350 | .tv = 1, | ||
351 | .gpio = 0x20000, | ||
352 | },{ | ||
353 | .name = name_svideo, | ||
354 | .vmux = 8, | ||
355 | .amux = LINE1, | ||
356 | .gpio = 0x20000, | ||
357 | },{ | ||
358 | .name = name_comp1, | ||
359 | .vmux = 3, | ||
360 | .amux = LINE1, | ||
361 | .gpio = 0x20000, | ||
362 | }}, | ||
363 | .radio = { | ||
364 | .name = name_radio, | ||
365 | .amux = LINE2, | ||
366 | .gpio = 0x20000, | ||
367 | }, | ||
368 | .mpeg = SAA7134_MPEG_EMPRESS, | ||
369 | .video_out = CCIR656, | ||
370 | }, | ||
371 | [SAA7134_BOARD_CINERGY400] = { | ||
372 | .name = "Terratec Cinergy 400 TV", | ||
373 | .audio_clock = 0x00200000, | ||
374 | .tuner_type = TUNER_PHILIPS_PAL, | ||
375 | .inputs = {{ | ||
376 | .name = name_tv, | ||
377 | .vmux = 1, | ||
378 | .amux = TV, | ||
379 | .tv = 1, | ||
380 | },{ | ||
381 | .name = name_comp1, | ||
382 | .vmux = 4, | ||
383 | .amux = LINE1, | ||
384 | },{ | ||
385 | .name = name_svideo, | ||
386 | .vmux = 8, | ||
387 | .amux = LINE1, | ||
388 | },{ | ||
389 | .name = name_comp2, // CVideo over SVideo Connector | ||
390 | .vmux = 0, | ||
391 | .amux = LINE1, | ||
392 | }} | ||
393 | }, | ||
394 | [SAA7134_BOARD_MD5044] = { | ||
395 | .name = "Medion 5044", | ||
396 | .audio_clock = 0x00187de7, // was: 0x00200000, | ||
397 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
398 | .tda9887_conf = TDA9887_PRESENT, | ||
399 | .inputs = {{ | ||
400 | .name = name_tv, | ||
401 | .vmux = 1, | ||
402 | .amux = TV, | ||
403 | .tv = 1, | ||
404 | },{ | ||
405 | /* workaround for problems with normal TV sound */ | ||
406 | .name = name_tv_mono, | ||
407 | .vmux = 1, | ||
408 | .amux = LINE2, | ||
409 | .tv = 1, | ||
410 | },{ | ||
411 | .name = name_comp1, | ||
412 | .vmux = 0, | ||
413 | .amux = LINE2, | ||
414 | },{ | ||
415 | .name = name_comp2, | ||
416 | .vmux = 3, | ||
417 | .amux = LINE2, | ||
418 | },{ | ||
419 | .name = name_svideo, | ||
420 | .vmux = 8, | ||
421 | .amux = LINE2, | ||
422 | }}, | ||
423 | .radio = { | ||
424 | .name = name_radio, | ||
425 | .amux = LINE2, | ||
426 | }, | ||
427 | }, | ||
428 | [SAA7134_BOARD_KWORLD] = { | ||
429 | .name = "Kworld/KuroutoShikou SAA7130-TVPCI", | ||
430 | .audio_clock = 0x00187de7, | ||
431 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
432 | .inputs = {{ | ||
433 | .name = name_svideo, | ||
434 | .vmux = 8, | ||
435 | .amux = LINE1, | ||
436 | },{ | ||
437 | .name = name_comp1, | ||
438 | .vmux = 3, | ||
439 | .amux = LINE1, | ||
440 | },{ | ||
441 | .name = name_tv, | ||
442 | .vmux = 1, | ||
443 | .amux = LINE2, | ||
444 | .tv = 1, | ||
445 | }}, | ||
446 | }, | ||
447 | [SAA7134_BOARD_CINERGY600] = { | ||
448 | .name = "Terratec Cinergy 600 TV", | ||
449 | .audio_clock = 0x00200000, | ||
450 | .tuner_type = TUNER_PHILIPS_PAL, | ||
451 | .tda9887_conf = TDA9887_PRESENT, | ||
452 | .inputs = {{ | ||
453 | .name = name_tv, | ||
454 | .vmux = 1, | ||
455 | .amux = TV, | ||
456 | .tv = 1, | ||
457 | },{ | ||
458 | .name = name_comp1, | ||
459 | .vmux = 4, | ||
460 | .amux = LINE1, | ||
461 | },{ | ||
462 | .name = name_svideo, | ||
463 | .vmux = 8, | ||
464 | .amux = LINE1, | ||
465 | },{ | ||
466 | .name = name_comp2, // CVideo over SVideo Connector | ||
467 | .vmux = 0, | ||
468 | .amux = LINE1, | ||
469 | }}, | ||
470 | .radio = { | ||
471 | .name = name_radio, | ||
472 | .amux = LINE2, | ||
473 | }, | ||
474 | }, | ||
475 | [SAA7134_BOARD_MD7134] = { | ||
476 | .name = "Medion 7134", | ||
477 | //.audio_clock = 0x00200000, | ||
478 | .audio_clock = 0x00187de7, | ||
479 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
480 | .tda9887_conf = TDA9887_PRESENT, | ||
481 | .mpeg = SAA7134_MPEG_DVB, | ||
482 | .inputs = {{ | ||
483 | .name = name_tv, | ||
484 | .vmux = 1, | ||
485 | .amux = TV, | ||
486 | .tv = 1, | ||
487 | },{ | ||
488 | .name = name_comp1, | ||
489 | .vmux = 0, | ||
490 | .amux = LINE1, | ||
491 | },{ | ||
492 | .name = name_svideo, | ||
493 | .vmux = 8, | ||
494 | .amux = LINE1, | ||
495 | }}, | ||
496 | .radio = { | ||
497 | .name = name_radio, | ||
498 | .amux = LINE2, | ||
499 | }, | ||
500 | }, | ||
501 | [SAA7134_BOARD_TYPHOON_90031] = { | ||
502 | /* aka Typhoon "TV+Radio", Art.Nr 90031 */ | ||
503 | /* Tom Zoerner <tomzo at users sourceforge net> */ | ||
504 | .name = "Typhoon TV+Radio 90031", | ||
505 | .audio_clock = 0x00200000, | ||
506 | .tuner_type = TUNER_PHILIPS_PAL, | ||
507 | .tda9887_conf = TDA9887_PRESENT, | ||
508 | .inputs = {{ | ||
509 | .name = name_tv, | ||
510 | .vmux = 1, | ||
511 | .amux = TV, | ||
512 | .tv = 1, | ||
513 | },{ | ||
514 | .name = name_comp1, | ||
515 | .vmux = 3, | ||
516 | .amux = LINE1, | ||
517 | },{ | ||
518 | .name = name_svideo, | ||
519 | .vmux = 8, | ||
520 | .amux = LINE1, | ||
521 | }}, | ||
522 | .radio = { | ||
523 | .name = name_radio, | ||
524 | .amux = LINE2, | ||
525 | }, | ||
526 | }, | ||
527 | [SAA7134_BOARD_ELSA] = { | ||
528 | .name = "ELSA EX-VISION 300TV", | ||
529 | .audio_clock = 0x00187de7, | ||
530 | .tuner_type = TUNER_HITACHI_NTSC, | ||
531 | .inputs = {{ | ||
532 | .name = name_svideo, | ||
533 | .vmux = 8, | ||
534 | .amux = LINE1, | ||
535 | },{ | ||
536 | .name = name_comp1, | ||
537 | .vmux = 0, | ||
538 | .amux = LINE1, | ||
539 | },{ | ||
540 | .name = name_tv, | ||
541 | .vmux = 4, | ||
542 | .amux = LINE2, | ||
543 | .tv = 1, | ||
544 | }}, | ||
545 | }, | ||
546 | [SAA7134_BOARD_ELSA_500TV] = { | ||
547 | .name = "ELSA EX-VISION 500TV", | ||
548 | .audio_clock = 0x00187de7, | ||
549 | .tuner_type = TUNER_HITACHI_NTSC, | ||
550 | .inputs = {{ | ||
551 | .name = name_svideo, | ||
552 | .vmux = 7, | ||
553 | .amux = LINE1, | ||
554 | },{ | ||
555 | .name = name_tv, | ||
556 | .vmux = 8, | ||
557 | .amux = TV, | ||
558 | .tv = 1, | ||
559 | },{ | ||
560 | .name = name_tv_mono, | ||
561 | .vmux = 8, | ||
562 | .amux = LINE2, | ||
563 | .tv = 1, | ||
564 | }}, | ||
565 | }, | ||
566 | [SAA7134_BOARD_ASUSTeK_TVFM7134] = { | ||
567 | .name = "ASUS TV-FM 7134", | ||
568 | .audio_clock = 0x00187de7, | ||
569 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
570 | .tda9887_conf = TDA9887_PRESENT, | ||
571 | .inputs = {{ | ||
572 | .name = name_tv, | ||
573 | .vmux = 1, | ||
574 | .amux = TV, | ||
575 | .tv = 1, | ||
576 | },{ | ||
577 | .name = name_comp1, | ||
578 | .vmux = 4, | ||
579 | .amux = LINE2, | ||
580 | },{ | ||
581 | .name = name_svideo, | ||
582 | .vmux = 6, | ||
583 | .amux = LINE2, | ||
584 | }}, | ||
585 | .radio = { | ||
586 | .name = name_radio, | ||
587 | .amux = LINE1, | ||
588 | }, | ||
589 | }, | ||
590 | [SAA7135_BOARD_ASUSTeK_TVFM7135] = { | ||
591 | .name = "ASUS TV-FM 7135", | ||
592 | .audio_clock = 0x00187de7, | ||
593 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
594 | .gpiomask = 0x200000, | ||
595 | .inputs = {{ | ||
596 | .name = name_tv, | ||
597 | .vmux = 1, | ||
598 | .amux = TV, | ||
599 | .gpio = 0x0000, | ||
600 | .tv = 1, | ||
601 | },{ | ||
602 | .name = name_comp1, | ||
603 | .vmux = 4, | ||
604 | .amux = LINE2, | ||
605 | .gpio = 0x0000, | ||
606 | },{ | ||
607 | .name = name_svideo, | ||
608 | .vmux = 6, | ||
609 | .amux = LINE2, | ||
610 | .gpio = 0x0000, | ||
611 | }}, | ||
612 | .radio = { | ||
613 | .name = name_radio, | ||
614 | .amux = TV, | ||
615 | .gpio = 0x200000, | ||
616 | }, | ||
617 | }, | ||
618 | [SAA7134_BOARD_VA1000POWER] = { | ||
619 | .name = "AOPEN VA1000 POWER", | ||
620 | .audio_clock = 0x00187de7, | ||
621 | .tuner_type = TUNER_PHILIPS_NTSC, | ||
622 | .inputs = {{ | ||
623 | .name = name_svideo, | ||
624 | .vmux = 8, | ||
625 | .amux = LINE1, | ||
626 | },{ | ||
627 | .name = name_comp1, | ||
628 | .vmux = 3, | ||
629 | .amux = LINE1, | ||
630 | },{ | ||
631 | .name = name_tv, | ||
632 | .vmux = 1, | ||
633 | .amux = LINE2, | ||
634 | .tv = 1, | ||
635 | }}, | ||
636 | }, | ||
637 | [SAA7134_BOARD_10MOONSTVMASTER] = { | ||
638 | /* "lilicheng" <llc@linuxfans.org> */ | ||
639 | .name = "10MOONS PCI TV CAPTURE CARD", | ||
640 | .audio_clock = 0x00200000, | ||
641 | .tuner_type = TUNER_LG_PAL_NEW_TAPC, | ||
642 | .gpiomask = 0xe000, | ||
643 | .inputs = {{ | ||
644 | .name = name_tv, | ||
645 | .vmux = 1, | ||
646 | .amux = LINE2, | ||
647 | .gpio = 0x0000, | ||
648 | .tv = 1, | ||
649 | },{ | ||
650 | .name = name_comp1, | ||
651 | .vmux = 0, | ||
652 | .amux = LINE2, | ||
653 | .gpio = 0x4000, | ||
654 | },{ | ||
655 | .name = name_comp2, | ||
656 | .vmux = 3, | ||
657 | .amux = LINE2, | ||
658 | .gpio = 0x4000, | ||
659 | },{ | ||
660 | .name = name_svideo, | ||
661 | .vmux = 8, | ||
662 | .amux = LINE2, | ||
663 | .gpio = 0x4000, | ||
664 | }}, | ||
665 | .radio = { | ||
666 | .name = name_radio, | ||
667 | .amux = LINE2, | ||
668 | .gpio = 0x2000, | ||
669 | }, | ||
670 | .mute = { | ||
671 | .name = name_mute, | ||
672 | .amux = LINE2, | ||
673 | .gpio = 0x8000, | ||
674 | }, | ||
675 | }, | ||
676 | [SAA7134_BOARD_BMK_MPEX_NOTUNER] = { | ||
677 | /* "Andrew de Quincey" <adq@lidskialf.net> */ | ||
678 | .name = "BMK MPEX No Tuner", | ||
679 | .audio_clock = 0x200000, | ||
680 | .tuner_type = TUNER_ABSENT, | ||
681 | .inputs = {{ | ||
682 | .name = name_comp1, | ||
683 | .vmux = 4, | ||
684 | .amux = LINE1, | ||
685 | },{ | ||
686 | .name = name_comp2, | ||
687 | .vmux = 3, | ||
688 | .amux = LINE1, | ||
689 | },{ | ||
690 | .name = name_comp3, | ||
691 | .vmux = 0, | ||
692 | .amux = LINE1, | ||
693 | },{ | ||
694 | .name = name_comp4, | ||
695 | .vmux = 1, | ||
696 | .amux = LINE1, | ||
697 | },{ | ||
698 | .name = name_svideo, | ||
699 | .vmux = 8, | ||
700 | .amux = LINE1, | ||
701 | }}, | ||
702 | .mpeg = SAA7134_MPEG_EMPRESS, | ||
703 | .video_out = CCIR656, | ||
704 | }, | ||
705 | [SAA7134_BOARD_VIDEOMATE_TV] = { | ||
706 | .name = "Compro VideoMate TV", | ||
707 | .audio_clock = 0x00187de7, | ||
708 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
709 | .inputs = {{ | ||
710 | .name = name_svideo, | ||
711 | .vmux = 8, | ||
712 | .amux = LINE1, | ||
713 | },{ | ||
714 | .name = name_comp1, | ||
715 | .vmux = 3, | ||
716 | .amux = LINE1, | ||
717 | },{ | ||
718 | .name = name_tv, | ||
719 | .vmux = 1, | ||
720 | .amux = LINE2, | ||
721 | .tv = 1, | ||
722 | }}, | ||
723 | }, | ||
724 | [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = { | ||
725 | .name = "Compro VideoMate TV Gold+", | ||
726 | .audio_clock = 0x00187de7, | ||
727 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
728 | .gpiomask = 0x800c0000, | ||
729 | .inputs = {{ | ||
730 | .name = name_svideo, | ||
731 | .vmux = 8, | ||
732 | .amux = LINE1, | ||
733 | .gpio = 0x06c00012, | ||
734 | },{ | ||
735 | .name = name_comp1, | ||
736 | .vmux = 3, | ||
737 | .amux = LINE1, | ||
738 | .gpio = 0x0ac20012, | ||
739 | },{ | ||
740 | .name = name_tv, | ||
741 | .vmux = 1, | ||
742 | .amux = LINE2, | ||
743 | .gpio = 0x08c20012, | ||
744 | .tv = 1, | ||
745 | }}, | ||
746 | }, | ||
747 | [SAA7134_BOARD_CRONOS_PLUS] = { | ||
748 | /* gpio pins: | ||
749 | 0 .. 3 BASE_ID | ||
750 | 4 .. 7 PROTECT_ID | ||
751 | 8 .. 11 USER_OUT | ||
752 | 12 .. 13 USER_IN | ||
753 | 14 .. 15 VIDIN_SEL */ | ||
754 | .name = "Matrox CronosPlus", | ||
755 | .tuner_type = TUNER_ABSENT, | ||
756 | .gpiomask = 0xcf00, | ||
757 | .inputs = {{ | ||
758 | .name = name_comp1, | ||
759 | .vmux = 0, | ||
760 | .gpio = 2 << 14, | ||
761 | },{ | ||
762 | .name = name_comp2, | ||
763 | .vmux = 0, | ||
764 | .gpio = 1 << 14, | ||
765 | },{ | ||
766 | .name = name_comp3, | ||
767 | .vmux = 0, | ||
768 | .gpio = 0 << 14, | ||
769 | },{ | ||
770 | .name = name_comp4, | ||
771 | .vmux = 0, | ||
772 | .gpio = 3 << 14, | ||
773 | },{ | ||
774 | .name = name_svideo, | ||
775 | .vmux = 8, | ||
776 | .gpio = 2 << 14, | ||
777 | }}, | ||
778 | }, | ||
779 | [SAA7134_BOARD_MD2819] = { | ||
780 | .name = "AverMedia M156 / Medion 2819", | ||
781 | .audio_clock = 0x00187de7, | ||
782 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
783 | .tda9887_conf = TDA9887_PRESENT, | ||
784 | .inputs = {{ | ||
785 | .name = name_tv, | ||
786 | .vmux = 1, | ||
787 | .amux = TV, | ||
788 | .tv = 1, | ||
789 | },{ | ||
790 | .name = name_comp1, | ||
791 | .vmux = 0, | ||
792 | .amux = LINE2, | ||
793 | },{ | ||
794 | .name = name_comp2, | ||
795 | .vmux = 3, | ||
796 | .amux = LINE2, | ||
797 | },{ | ||
798 | .name = name_svideo, | ||
799 | .vmux = 8, | ||
800 | .amux = LINE2, | ||
801 | }}, | ||
802 | .radio = { | ||
803 | .name = name_radio, | ||
804 | .amux = LINE2, | ||
805 | }, | ||
806 | }, | ||
807 | [SAA7134_BOARD_BMK_MPEX_TUNER] = { | ||
808 | /* "Greg Wickham <greg.wickham@grangenet.net> */ | ||
809 | .name = "BMK MPEX Tuner", | ||
810 | .audio_clock = 0x200000, | ||
811 | .tuner_type = TUNER_PHILIPS_PAL, | ||
812 | .inputs = {{ | ||
813 | .name = name_comp1, | ||
814 | .vmux = 1, | ||
815 | .amux = LINE1, | ||
816 | },{ | ||
817 | .name = name_svideo, | ||
818 | .vmux = 8, | ||
819 | .amux = LINE1, | ||
820 | },{ | ||
821 | .name = name_tv, | ||
822 | .vmux = 3, | ||
823 | .amux = TV, | ||
824 | .tv = 1, | ||
825 | }}, | ||
826 | .mpeg = SAA7134_MPEG_EMPRESS, | ||
827 | .video_out = CCIR656, | ||
828 | }, | ||
829 | [SAA7134_BOARD_ASUSTEK_TVFM7133] = { | ||
830 | .name = "ASUS TV-FM 7133", | ||
831 | .audio_clock = 0x00187de7, | ||
832 | // probably wrong, the 7133 one is the NTSC version ... | ||
833 | // .tuner_type = TUNER_PHILIPS_FM1236_MK3 | ||
834 | .tuner_type = TUNER_LG_NTSC_NEW_TAPC, | ||
835 | .tda9887_conf = TDA9887_PRESENT, | ||
836 | .inputs = {{ | ||
837 | .name = name_tv, | ||
838 | .vmux = 1, | ||
839 | .amux = TV, | ||
840 | .tv = 1, | ||
841 | },{ | ||
842 | .name = name_comp1, | ||
843 | .vmux = 4, | ||
844 | .amux = LINE2, | ||
845 | },{ | ||
846 | .name = name_svideo, | ||
847 | .vmux = 6, | ||
848 | .amux = LINE2, | ||
849 | }}, | ||
850 | .radio = { | ||
851 | .name = name_radio, | ||
852 | .amux = LINE1, | ||
853 | }, | ||
854 | }, | ||
855 | [SAA7134_BOARD_PINNACLE_PCTV_STEREO] = { | ||
856 | .name = "Pinnacle PCTV Stereo (saa7134)", | ||
857 | .audio_clock = 0x00187de7, | ||
858 | .tuner_type = TUNER_MT2032, | ||
859 | .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, | ||
860 | .inputs = {{ | ||
861 | .name = name_tv, | ||
862 | .vmux = 3, | ||
863 | .amux = TV, | ||
864 | .tv = 1, | ||
865 | },{ | ||
866 | .name = name_comp1, | ||
867 | .vmux = 0, | ||
868 | .amux = LINE2, | ||
869 | },{ | ||
870 | .name = name_comp2, | ||
871 | .vmux = 1, | ||
872 | .amux = LINE2, | ||
873 | },{ | ||
874 | .name = name_svideo, | ||
875 | .vmux = 8, | ||
876 | .amux = LINE2, | ||
877 | }}, | ||
878 | }, | ||
879 | [SAA7134_BOARD_MANLI_MTV002] = { | ||
880 | /* Ognjen Nastic <ognjen@logosoft.ba> */ | ||
881 | .name = "Manli MuchTV M-TV002", | ||
882 | .audio_clock = 0x00200000, | ||
883 | .tuner_type = TUNER_PHILIPS_PAL, | ||
884 | .inputs = {{ | ||
885 | .name = name_svideo, | ||
886 | .vmux = 8, | ||
887 | .amux = LINE1, | ||
888 | },{ | ||
889 | .name = name_comp1, | ||
890 | .vmux = 1, | ||
891 | .amux = LINE1, | ||
892 | },{ | ||
893 | .name = name_tv, | ||
894 | .vmux = 3, | ||
895 | .amux = LINE2, | ||
896 | .tv = 1, | ||
897 | }}, | ||
898 | .radio = { | ||
899 | .name = name_radio, | ||
900 | .amux = LINE2, | ||
901 | }, | ||
902 | .mute = { | ||
903 | .name = name_mute, | ||
904 | .amux = LINE1, | ||
905 | }, | ||
906 | }, | ||
907 | [SAA7134_BOARD_MANLI_MTV001] = { | ||
908 | /* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */ | ||
909 | .name = "Manli MuchTV M-TV001", | ||
910 | .audio_clock = 0x00200000, | ||
911 | .tuner_type = TUNER_PHILIPS_PAL, | ||
912 | .inputs = {{ | ||
913 | .name = name_svideo, | ||
914 | .vmux = 8, | ||
915 | .amux = LINE1, | ||
916 | },{ | ||
917 | .name = name_comp1, | ||
918 | .vmux = 1, | ||
919 | .amux = LINE1, | ||
920 | },{ | ||
921 | .name = name_tv, | ||
922 | .vmux = 3, | ||
923 | .amux = LINE2, | ||
924 | .tv = 1, | ||
925 | }}, | ||
926 | }, | ||
927 | [SAA7134_BOARD_TG3000TV] = { | ||
928 | /* TransGear 3000TV */ | ||
929 | .name = "Nagase Sangyo TransGear 3000TV", | ||
930 | .audio_clock = 0x00187de7, | ||
931 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
932 | .inputs = {{ | ||
933 | .name = name_tv, | ||
934 | .vmux = 1, | ||
935 | .amux = LINE2, | ||
936 | .tv = 1, | ||
937 | },{ | ||
938 | .name = name_comp1, | ||
939 | .vmux = 3, | ||
940 | .amux = LINE2, | ||
941 | },{ | ||
942 | .name = name_svideo, | ||
943 | .vmux = 8, | ||
944 | .amux = LINE2, | ||
945 | }}, | ||
946 | }, | ||
947 | [SAA7134_BOARD_ECS_TVP3XP] = { | ||
948 | .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ", | ||
949 | .audio_clock = 0x187de7, // xtal 32.1 MHz | ||
950 | .tuner_type = TUNER_PHILIPS_PAL, | ||
951 | .inputs = {{ | ||
952 | .name = name_tv, | ||
953 | .vmux = 1, | ||
954 | .amux = TV, | ||
955 | .tv = 1, | ||
956 | },{ | ||
957 | .name = name_tv_mono, | ||
958 | .vmux = 1, | ||
959 | .amux = LINE2, | ||
960 | .tv = 1, | ||
961 | },{ | ||
962 | .name = name_comp1, | ||
963 | .vmux = 3, | ||
964 | .amux = LINE1, | ||
965 | },{ | ||
966 | .name = name_svideo, | ||
967 | .vmux = 8, | ||
968 | .amux = LINE1, | ||
969 | },{ | ||
970 | .name = "CVid over SVid", | ||
971 | .vmux = 0, | ||
972 | .amux = LINE1, | ||
973 | }}, | ||
974 | .radio = { | ||
975 | .name = name_radio, | ||
976 | .amux = LINE2, | ||
977 | }, | ||
978 | }, | ||
979 | [SAA7134_BOARD_ECS_TVP3XP_4CB5] = { | ||
980 | .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)", | ||
981 | .audio_clock = 0x187de7, | ||
982 | .tuner_type = TUNER_PHILIPS_NTSC, | ||
983 | .inputs = {{ | ||
984 | .name = name_tv, | ||
985 | .vmux = 1, | ||
986 | .amux = TV, | ||
987 | .tv = 1, | ||
988 | },{ | ||
989 | .name = name_tv_mono, | ||
990 | .vmux = 1, | ||
991 | .amux = LINE2, | ||
992 | .tv = 1, | ||
993 | },{ | ||
994 | .name = name_comp1, | ||
995 | .vmux = 3, | ||
996 | .amux = LINE1, | ||
997 | },{ | ||
998 | .name = name_svideo, | ||
999 | .vmux = 8, | ||
1000 | .amux = LINE1, | ||
1001 | },{ | ||
1002 | .name = "CVid over SVid", | ||
1003 | .vmux = 0, | ||
1004 | .amux = LINE1, | ||
1005 | }}, | ||
1006 | .radio = { | ||
1007 | .name = name_radio, | ||
1008 | .amux = LINE2, | ||
1009 | }, | ||
1010 | }, | ||
1011 | [SAA7134_BOARD_AVACSSMARTTV] = { | ||
1012 | /* Roman Pszonczenko <romka@kolos.math.uni.lodz.pl> */ | ||
1013 | .name = "AVACS SmartTV", | ||
1014 | .audio_clock = 0x00187de7, | ||
1015 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1016 | .inputs = {{ | ||
1017 | .name = name_tv, | ||
1018 | .vmux = 1, | ||
1019 | .amux = TV, | ||
1020 | .tv = 1, | ||
1021 | },{ | ||
1022 | .name = name_tv_mono, | ||
1023 | .vmux = 1, | ||
1024 | .amux = LINE2, | ||
1025 | .tv = 1, | ||
1026 | },{ | ||
1027 | .name = name_comp1, | ||
1028 | .vmux = 0, | ||
1029 | .amux = LINE2, | ||
1030 | },{ | ||
1031 | .name = name_comp2, | ||
1032 | .vmux = 3, | ||
1033 | .amux = LINE2, | ||
1034 | },{ | ||
1035 | .name = name_svideo, | ||
1036 | .vmux = 8, | ||
1037 | .amux = LINE2, | ||
1038 | }}, | ||
1039 | .radio = { | ||
1040 | .name = name_radio, | ||
1041 | .amux = LINE2, | ||
1042 | .gpio = 0x200000, | ||
1043 | }, | ||
1044 | }, | ||
1045 | [SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER] = { | ||
1046 | /* Michael Smith <msmith@cbnco.com> */ | ||
1047 | .name = "AVerMedia DVD EZMaker", | ||
1048 | .audio_clock = 0x00187de7, | ||
1049 | .tuner_type = TUNER_ABSENT, | ||
1050 | .inputs = {{ | ||
1051 | .name = name_comp1, | ||
1052 | .vmux = 3, | ||
1053 | },{ | ||
1054 | .name = name_svideo, | ||
1055 | .vmux = 8, | ||
1056 | }}, | ||
1057 | }, | ||
1058 | [SAA7134_BOARD_NOVAC_PRIMETV7133] = { | ||
1059 | /* toshii@netbsd.org */ | ||
1060 | .name = "Noval Prime TV 7133", | ||
1061 | .audio_clock = 0x00200000, | ||
1062 | .tuner_type = TUNER_ALPS_TSBH1_NTSC, | ||
1063 | .inputs = {{ | ||
1064 | .name = name_comp1, | ||
1065 | .vmux = 3, | ||
1066 | },{ | ||
1067 | .name = name_tv, | ||
1068 | .vmux = 1, | ||
1069 | .amux = TV, | ||
1070 | .tv = 1, | ||
1071 | },{ | ||
1072 | .name = name_svideo, | ||
1073 | .vmux = 8, | ||
1074 | }}, | ||
1075 | }, | ||
1076 | [SAA7134_BOARD_AVERMEDIA_STUDIO_305] = { | ||
1077 | .name = "AverMedia AverTV Studio 305", | ||
1078 | .audio_clock = 0x00187de7, | ||
1079 | .tuner_type = TUNER_PHILIPS_FM1256_IH3, | ||
1080 | .tda9887_conf = TDA9887_PRESENT, | ||
1081 | .gpiomask = 0x3, | ||
1082 | .inputs = {{ | ||
1083 | .name = name_tv, | ||
1084 | .vmux = 1, | ||
1085 | .amux = LINE2, | ||
1086 | .tv = 1, | ||
1087 | },{ | ||
1088 | .name = name_comp1, | ||
1089 | .vmux = 0, | ||
1090 | .amux = LINE2, | ||
1091 | },{ | ||
1092 | .name = name_comp2, | ||
1093 | .vmux = 3, | ||
1094 | .amux = LINE2, | ||
1095 | },{ | ||
1096 | .name = name_svideo, | ||
1097 | .vmux = 8, | ||
1098 | .amux = LINE2, | ||
1099 | }}, | ||
1100 | .radio = { | ||
1101 | .name = name_radio, | ||
1102 | .amux = LINE2, | ||
1103 | }, | ||
1104 | .mute = { | ||
1105 | .name = name_mute, | ||
1106 | .amux = LINE1, | ||
1107 | }, | ||
1108 | }, | ||
1109 | [SAA7133_BOARD_UPMOST_PURPLE_TV] = { | ||
1110 | .name = "UPMOST PURPLE TV", | ||
1111 | .audio_clock = 0x00187de7, | ||
1112 | .tuner_type = TUNER_PHILIPS_FM1236_MK3, | ||
1113 | .tda9887_conf = TDA9887_PRESENT, | ||
1114 | .inputs = {{ | ||
1115 | .name = name_tv, | ||
1116 | .vmux = 7, | ||
1117 | .amux = TV, | ||
1118 | .tv = 1, | ||
1119 | },{ | ||
1120 | .name = name_svideo, | ||
1121 | .vmux = 7, | ||
1122 | .amux = LINE1, | ||
1123 | }}, | ||
1124 | }, | ||
1125 | [SAA7134_BOARD_ITEMS_MTV005] = { | ||
1126 | /* Norman Jonas <normanjonas@arcor.de> */ | ||
1127 | .name = "Items MuchTV Plus / IT-005", | ||
1128 | .audio_clock = 0x00187de7, | ||
1129 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1130 | .inputs = {{ | ||
1131 | .name = name_tv, | ||
1132 | .vmux = 3, | ||
1133 | .amux = TV, | ||
1134 | .tv = 1, | ||
1135 | },{ | ||
1136 | .name = name_comp1, | ||
1137 | .vmux = 1, | ||
1138 | .amux = LINE1, | ||
1139 | },{ | ||
1140 | .name = name_svideo, | ||
1141 | .vmux = 8, | ||
1142 | .amux = LINE1, | ||
1143 | }}, | ||
1144 | .radio = { | ||
1145 | .name = name_radio, | ||
1146 | .amux = LINE2, | ||
1147 | }, | ||
1148 | }, | ||
1149 | [SAA7134_BOARD_CINERGY200] = { | ||
1150 | .name = "Terratec Cinergy 200 TV", | ||
1151 | .audio_clock = 0x00200000, | ||
1152 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1153 | .inputs = {{ | ||
1154 | .name = name_tv, | ||
1155 | .vmux = 1, | ||
1156 | .amux = LINE2, | ||
1157 | .tv = 1, | ||
1158 | },{ | ||
1159 | .name = name_comp1, | ||
1160 | .vmux = 4, | ||
1161 | .amux = LINE1, | ||
1162 | },{ | ||
1163 | .name = name_svideo, | ||
1164 | .vmux = 8, | ||
1165 | .amux = LINE1, | ||
1166 | },{ | ||
1167 | .name = name_comp2, // CVideo over SVideo Connector | ||
1168 | .vmux = 0, | ||
1169 | .amux = LINE1, | ||
1170 | }}, | ||
1171 | .mute = { | ||
1172 | .name = name_mute, | ||
1173 | .amux = LINE2, | ||
1174 | }, | ||
1175 | }, | ||
1176 | [SAA7134_BOARD_VIDEOMATE_TV_PVR] = { | ||
1177 | /* Alain St-Denis <alain@topaze.homeip.net> */ | ||
1178 | .name = "Compro VideoMate TV PVR/FM", | ||
1179 | .audio_clock = 0x00187de7, | ||
1180 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
1181 | .gpiomask = 0x808c0080, | ||
1182 | .inputs = {{ | ||
1183 | .name = name_svideo, | ||
1184 | .vmux = 8, | ||
1185 | .amux = LINE1, | ||
1186 | .gpio = 0x00080, | ||
1187 | },{ | ||
1188 | .name = name_comp1, | ||
1189 | .vmux = 3, | ||
1190 | .amux = LINE1, | ||
1191 | .gpio = 0x00080, | ||
1192 | },{ | ||
1193 | .name = name_tv, | ||
1194 | .vmux = 1, | ||
1195 | .amux = LINE2_LEFT, | ||
1196 | .tv = 1, | ||
1197 | .gpio = 0x00080, | ||
1198 | }}, | ||
1199 | .radio = { | ||
1200 | .name = name_radio, | ||
1201 | .amux = LINE2, | ||
1202 | .gpio = 0x80000, | ||
1203 | }, | ||
1204 | .mute = { | ||
1205 | .name = name_mute, | ||
1206 | .amux = LINE2, | ||
1207 | .gpio = 0x40000, | ||
1208 | }, | ||
1209 | }, | ||
1210 | [SAA7134_BOARD_SABRENT_SBTTVFM] = { | ||
1211 | /* Michael Rodriguez-Torrent <mrtorrent@asu.edu> */ | ||
1212 | .name = "Sabrent SBT-TVFM (saa7130)", | ||
1213 | .audio_clock = 0x00187de7, | ||
1214 | .tuner_type = TUNER_PHILIPS_NTSC_M, | ||
1215 | .inputs = {{ | ||
1216 | .name = name_comp1, | ||
1217 | .vmux = 1, | ||
1218 | .amux = LINE2, | ||
1219 | },{ | ||
1220 | .name = name_tv, | ||
1221 | .vmux = 3, | ||
1222 | .amux = LINE2, | ||
1223 | .tv = 1, | ||
1224 | },{ | ||
1225 | .name = name_svideo, | ||
1226 | .vmux = 8, | ||
1227 | .amux = LINE2, | ||
1228 | }}, | ||
1229 | .radio = { | ||
1230 | .name = name_radio, | ||
1231 | .amux = LINE2, | ||
1232 | }, | ||
1233 | }, | ||
1234 | [SAA7134_BOARD_ZOLID_XPERT_TV7134] = { | ||
1235 | /* Helge Jensen <helge.jensen@slog.dk> */ | ||
1236 | .name = ":Zolid Xpert TV7134", | ||
1237 | .audio_clock = 0x00187de7, | ||
1238 | .tuner_type = TUNER_PHILIPS_NTSC, | ||
1239 | .inputs = {{ | ||
1240 | .name = name_svideo, | ||
1241 | .vmux = 8, | ||
1242 | .amux = LINE1, | ||
1243 | },{ | ||
1244 | .name = name_comp1, | ||
1245 | .vmux = 3, | ||
1246 | .amux = LINE1, | ||
1247 | },{ | ||
1248 | .name = name_tv, | ||
1249 | .vmux = 1, | ||
1250 | .amux = LINE2, | ||
1251 | .tv = 1, | ||
1252 | }}, | ||
1253 | }, | ||
1254 | [SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = { | ||
1255 | /* "Matteo Az" <matte.az@nospam.libero.it> ;-) */ | ||
1256 | .name = "Empire PCI TV-Radio LE", | ||
1257 | .audio_clock = 0x00187de7, | ||
1258 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1259 | .gpiomask = 0x4000, | ||
1260 | .inputs = {{ | ||
1261 | .name = name_tv_mono, | ||
1262 | .vmux = 1, | ||
1263 | .amux = LINE2, | ||
1264 | .gpio = 0x8000, | ||
1265 | .tv = 1, | ||
1266 | },{ | ||
1267 | .name = name_comp1, | ||
1268 | .vmux = 3, | ||
1269 | .amux = LINE1, | ||
1270 | .gpio = 0x8000, | ||
1271 | },{ | ||
1272 | .name = name_svideo, | ||
1273 | .vmux = 6, | ||
1274 | .amux = LINE1, | ||
1275 | .gpio = 0x8000, | ||
1276 | }}, | ||
1277 | .radio = { | ||
1278 | .name = name_radio, | ||
1279 | .amux = LINE1, | ||
1280 | .gpio = 0x8000, | ||
1281 | }, | ||
1282 | .mute = { | ||
1283 | .name = name_mute, | ||
1284 | .amux = TV, | ||
1285 | .gpio =0x8000, | ||
1286 | } | ||
1287 | }, | ||
1288 | [SAA7134_BOARD_AVERMEDIA_307] = { | ||
1289 | /* | ||
1290 | Nickolay V. Shmyrev <nshmyrev@yandex.ru> | ||
1291 | Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru> | ||
1292 | */ | ||
1293 | .name = "Avermedia AVerTV Studio 307", | ||
1294 | .audio_clock = 0x00187de7, | ||
1295 | .tuner_type = TUNER_PHILIPS_FM1256_IH3, | ||
1296 | .tda9887_conf = TDA9887_PRESENT, | ||
1297 | .gpiomask = 0x03, | ||
1298 | .inputs = {{ | ||
1299 | .name = name_tv, | ||
1300 | .vmux = 1, | ||
1301 | .amux = TV, | ||
1302 | .tv = 1, | ||
1303 | .gpio = 0x00, | ||
1304 | },{ | ||
1305 | .name = name_comp1, | ||
1306 | .vmux = 0, | ||
1307 | .amux = LINE2, | ||
1308 | .gpio = 0x00, | ||
1309 | },{ | ||
1310 | .name = name_comp2, | ||
1311 | .vmux = 3, | ||
1312 | .amux = LINE2, | ||
1313 | .gpio = 0x00, | ||
1314 | },{ | ||
1315 | .name = name_svideo, | ||
1316 | .vmux = 8, | ||
1317 | .amux = LINE2, | ||
1318 | .gpio = 0x00, | ||
1319 | }}, | ||
1320 | .radio = { | ||
1321 | .name = name_radio, | ||
1322 | .amux = LINE1, | ||
1323 | .gpio = 0x01, | ||
1324 | }, | ||
1325 | }, | ||
1326 | [SAA7134_BOARD_AVERMEDIA_CARDBUS] = { | ||
1327 | /* Jon Westgate <oryn@oryn.fsck.tv> */ | ||
1328 | .name = "AVerMedia Cardbus TV/Radio", | ||
1329 | .audio_clock = 0x00200000, | ||
1330 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1331 | .inputs = {{ | ||
1332 | .name = name_tv, | ||
1333 | .vmux = 1, | ||
1334 | .amux = LINE2, | ||
1335 | .tv = 1, | ||
1336 | },{ | ||
1337 | .name = name_comp1, | ||
1338 | .vmux = 3, | ||
1339 | .amux = LINE2, | ||
1340 | },{ | ||
1341 | .name = name_svideo, | ||
1342 | .vmux = 8, | ||
1343 | .amux = LINE2, | ||
1344 | }}, | ||
1345 | .radio = { | ||
1346 | .name = name_radio, | ||
1347 | .amux = LINE1, | ||
1348 | }, | ||
1349 | }, | ||
1350 | [SAA7134_BOARD_CINERGY400_CARDBUS] = { | ||
1351 | .name = "Terratec Cinergy 400 mobile", | ||
1352 | .audio_clock = 0x187de7, | ||
1353 | .tuner_type = TUNER_ALPS_TSBE5_PAL, | ||
1354 | .tda9887_conf = TDA9887_PRESENT, | ||
1355 | .inputs = {{ | ||
1356 | .name = name_tv, | ||
1357 | .vmux = 1, | ||
1358 | .amux = TV, | ||
1359 | .tv = 1, | ||
1360 | },{ | ||
1361 | .name = name_tv_mono, | ||
1362 | .vmux = 1, | ||
1363 | .amux = LINE2, | ||
1364 | .tv = 1, | ||
1365 | },{ | ||
1366 | .name = name_comp1, | ||
1367 | .vmux = 3, | ||
1368 | .amux = LINE1, | ||
1369 | },{ | ||
1370 | .name = name_svideo, | ||
1371 | .vmux = 8, | ||
1372 | .amux = LINE1, | ||
1373 | }}, | ||
1374 | }, | ||
1375 | [SAA7134_BOARD_CINERGY600_MK3] = { | ||
1376 | .name = "Terratec Cinergy 600 TV MK3", | ||
1377 | .audio_clock = 0x00200000, | ||
1378 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
1379 | .tda9887_conf = TDA9887_PRESENT, | ||
1380 | .inputs = {{ | ||
1381 | .name = name_tv, | ||
1382 | .vmux = 1, | ||
1383 | .amux = TV, | ||
1384 | .tv = 1, | ||
1385 | },{ | ||
1386 | .name = name_comp1, | ||
1387 | .vmux = 4, | ||
1388 | .amux = LINE1, | ||
1389 | },{ | ||
1390 | .name = name_svideo, | ||
1391 | .vmux = 8, | ||
1392 | .amux = LINE1, | ||
1393 | },{ | ||
1394 | .name = name_comp2, // CVideo over SVideo Connector | ||
1395 | .vmux = 0, | ||
1396 | .amux = LINE1, | ||
1397 | }}, | ||
1398 | .radio = { | ||
1399 | .name = name_radio, | ||
1400 | .amux = LINE2, | ||
1401 | }, | ||
1402 | }, | ||
1403 | [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = { | ||
1404 | /* Dylan Walkden <dylan_walkden@hotmail.com> */ | ||
1405 | .name = "Compro VideoMate Gold+ Pal", | ||
1406 | .audio_clock = 0x00187de7, | ||
1407 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1408 | .gpiomask = 0x1ce780, | ||
1409 | .inputs = {{ | ||
1410 | .name = name_svideo, | ||
1411 | .vmux = 0, // CVideo over SVideo Connector - ok? | ||
1412 | .amux = LINE1, | ||
1413 | .gpio = 0x008080, | ||
1414 | },{ | ||
1415 | .name = name_comp1, | ||
1416 | .vmux = 3, | ||
1417 | .amux = LINE1, | ||
1418 | .gpio = 0x008080, | ||
1419 | },{ | ||
1420 | .name = name_tv, | ||
1421 | .vmux = 1, | ||
1422 | .amux = TV, | ||
1423 | .tv = 1, | ||
1424 | .gpio = 0x008080, | ||
1425 | }}, | ||
1426 | .radio = { | ||
1427 | .name = name_radio, | ||
1428 | .amux = LINE2, | ||
1429 | .gpio = 0x80000, | ||
1430 | }, | ||
1431 | .mute = { | ||
1432 | .name = name_mute, | ||
1433 | .amux = LINE2, | ||
1434 | .gpio = 0x0c8000, | ||
1435 | }, | ||
1436 | }, | ||
1437 | [SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = { | ||
1438 | .name = "Pinnacle PCTV 300i DVB-T + PAL", | ||
1439 | .audio_clock = 0x00187de7, | ||
1440 | .tuner_type = TUNER_MT2032, | ||
1441 | .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER, | ||
1442 | .mpeg = SAA7134_MPEG_DVB, | ||
1443 | .inputs = {{ | ||
1444 | .name = name_tv, | ||
1445 | .vmux = 3, | ||
1446 | .amux = TV, | ||
1447 | .tv = 1, | ||
1448 | },{ | ||
1449 | .name = name_comp1, | ||
1450 | .vmux = 0, | ||
1451 | .amux = LINE2, | ||
1452 | },{ | ||
1453 | .name = name_comp2, | ||
1454 | .vmux = 1, | ||
1455 | .amux = LINE2, | ||
1456 | },{ | ||
1457 | .name = name_svideo, | ||
1458 | .vmux = 8, | ||
1459 | .amux = LINE2, | ||
1460 | }}, | ||
1461 | }, | ||
1462 | [SAA7134_BOARD_PROVIDEO_PV952] = { | ||
1463 | /* andreas.kretschmer@web.de */ | ||
1464 | .name = "ProVideo PV952", | ||
1465 | .audio_clock = 0x00187de7, | ||
1466 | .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, | ||
1467 | .tda9887_conf = TDA9887_PRESENT, | ||
1468 | .inputs = {{ | ||
1469 | .name = name_comp1, | ||
1470 | .vmux = 0, | ||
1471 | .amux = LINE1, | ||
1472 | },{ | ||
1473 | .name = name_tv, | ||
1474 | .vmux = 1, | ||
1475 | .amux = TV, | ||
1476 | .tv = 1, | ||
1477 | },{ | ||
1478 | .name = name_tv_mono, | ||
1479 | .vmux = 1, | ||
1480 | .amux = LINE2, | ||
1481 | .tv = 1, | ||
1482 | }}, | ||
1483 | .radio = { | ||
1484 | .name = name_radio, | ||
1485 | .amux = LINE2, | ||
1486 | }, | ||
1487 | }, | ||
1488 | [SAA7134_BOARD_AVERMEDIA_305] = { | ||
1489 | /* much like the "studio" version but without radio | ||
1490 | * and another tuner (sirspiritus@yandex.ru) */ | ||
1491 | .name = "AverMedia AverTV/305", | ||
1492 | .audio_clock = 0x00187de7, | ||
1493 | .tuner_type = TUNER_PHILIPS_FQ1216ME, | ||
1494 | .tda9887_conf = TDA9887_PRESENT, | ||
1495 | .gpiomask = 0x3, | ||
1496 | .inputs = {{ | ||
1497 | .name = name_tv, | ||
1498 | .vmux = 1, | ||
1499 | .amux = LINE2, | ||
1500 | .tv = 1, | ||
1501 | },{ | ||
1502 | .name = name_comp1, | ||
1503 | .vmux = 0, | ||
1504 | .amux = LINE2, | ||
1505 | },{ | ||
1506 | .name = name_comp2, | ||
1507 | .vmux = 3, | ||
1508 | .amux = LINE2, | ||
1509 | },{ | ||
1510 | .name = name_svideo, | ||
1511 | .vmux = 8, | ||
1512 | .amux = LINE2, | ||
1513 | }}, | ||
1514 | .mute = { | ||
1515 | .name = name_mute, | ||
1516 | .amux = LINE1, | ||
1517 | }, | ||
1518 | }, | ||
1519 | [SAA7134_BOARD_FLYDVBTDUO] = { | ||
1520 | /* LifeView FlyDVB-T DUO */ | ||
1521 | /* "Nico Sabbi <nsabbi@tiscali.it> */ | ||
1522 | .name = "LifeView FlyDVB-T DUO", | ||
1523 | .audio_clock = 0x00200000, | ||
1524 | .tuner_type = TUNER_PHILIPS_TDA8290, | ||
1525 | // .gpiomask = 0xe000, | ||
1526 | .inputs = {{ | ||
1527 | .name = name_tv, | ||
1528 | .vmux = 1, | ||
1529 | .amux = TV, | ||
1530 | // .gpio = 0x0000, | ||
1531 | .tv = 1, | ||
1532 | },{ | ||
1533 | .name = name_comp1, /* Composite signal on S-Video input */ | ||
1534 | .vmux = 0, | ||
1535 | .amux = LINE2, | ||
1536 | // .gpio = 0x4000, | ||
1537 | },{ | ||
1538 | .name = name_comp2, /* Composite input */ | ||
1539 | .vmux = 3, | ||
1540 | .amux = LINE2, | ||
1541 | // .gpio = 0x4000, | ||
1542 | },{ | ||
1543 | .name = name_svideo, /* S-Video signal on S-Video input */ | ||
1544 | .vmux = 8, | ||
1545 | .amux = LINE2, | ||
1546 | // .gpio = 0x4000, | ||
1547 | }}, | ||
1548 | }, | ||
1549 | }; | ||
1550 | const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); | ||
1551 | |||
1552 | /* ------------------------------------------------------------------ */ | ||
1553 | /* PCI ids + subsystem IDs */ | ||
1554 | |||
1555 | struct pci_device_id saa7134_pci_tbl[] = { | ||
1556 | { | ||
1557 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1558 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1559 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1560 | .subdevice = 0x2001, | ||
1561 | .driver_data = SAA7134_BOARD_PROTEUS_PRO, | ||
1562 | },{ | ||
1563 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1564 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1565 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1566 | .subdevice = 0x2001, | ||
1567 | .driver_data = SAA7134_BOARD_PROTEUS_PRO, | ||
1568 | },{ | ||
1569 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1570 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1571 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1572 | .subdevice = 0x6752, | ||
1573 | .driver_data = SAA7134_BOARD_EMPRESS, | ||
1574 | },{ | ||
1575 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1576 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1577 | .subvendor = 0x1131, | ||
1578 | .subdevice = 0x4e85, | ||
1579 | .driver_data = SAA7134_BOARD_MONSTERTV, | ||
1580 | },{ | ||
1581 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1582 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1583 | .subvendor = 0x153B, | ||
1584 | .subdevice = 0x1142, | ||
1585 | .driver_data = SAA7134_BOARD_CINERGY400, | ||
1586 | },{ | ||
1587 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1588 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1589 | .subvendor = 0x153B, | ||
1590 | .subdevice = 0x1143, | ||
1591 | .driver_data = SAA7134_BOARD_CINERGY600, | ||
1592 | },{ | ||
1593 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1594 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1595 | .subvendor = 0x153B, | ||
1596 | .subdevice = 0x1158, | ||
1597 | .driver_data = SAA7134_BOARD_CINERGY600_MK3, | ||
1598 | },{ | ||
1599 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1600 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1601 | .subvendor = 0x153b, | ||
1602 | .subdevice = 0x1162, | ||
1603 | .driver_data = SAA7134_BOARD_CINERGY400_CARDBUS, | ||
1604 | },{ | ||
1605 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1606 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1607 | .subvendor = 0x5168, | ||
1608 | .subdevice = 0x0138, | ||
1609 | .driver_data = SAA7134_BOARD_FLYVIDEO3000, | ||
1610 | },{ | ||
1611 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1612 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1613 | .subvendor = 0x4e42, //"Typhoon PCI Capture TV Card" Art.No. 50673 | ||
1614 | .subdevice = 0x0138, | ||
1615 | .driver_data = SAA7134_BOARD_FLYVIDEO3000, | ||
1616 | },{ | ||
1617 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1618 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1619 | .subvendor = 0x5168, | ||
1620 | .subdevice = 0x0138, | ||
1621 | .driver_data = SAA7134_BOARD_FLYVIDEO2000, | ||
1622 | },{ | ||
1623 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1624 | .device = PCI_DEVICE_ID_PHILIPS_SAA7135, | ||
1625 | .subvendor = 0x5168, | ||
1626 | .subdevice = 0x0212, /* minipci, LR212 */ | ||
1627 | .driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI, | ||
1628 | },{ | ||
1629 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1630 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1631 | .subvendor = 0x5168, | ||
1632 | .subdevice = 0x0214, /* Standard PCI, LR214WF */ | ||
1633 | .driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, | ||
1634 | },{ | ||
1635 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1636 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1637 | .subvendor = 0x16be, | ||
1638 | .subdevice = 0x0003, | ||
1639 | .driver_data = SAA7134_BOARD_MD7134, | ||
1640 | },{ | ||
1641 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1642 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1643 | .subvendor = 0x1048, | ||
1644 | .subdevice = 0x226b, | ||
1645 | .driver_data = SAA7134_BOARD_ELSA, | ||
1646 | },{ | ||
1647 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1648 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1649 | .subvendor = 0x1048, | ||
1650 | .subdevice = 0x226b, | ||
1651 | .driver_data = SAA7134_BOARD_ELSA_500TV, | ||
1652 | },{ | ||
1653 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1654 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1655 | .subvendor = PCI_VENDOR_ID_ASUSTEK, | ||
1656 | .subdevice = 0x4842, | ||
1657 | .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, | ||
1658 | },{ | ||
1659 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1660 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1661 | .subvendor = PCI_VENDOR_ID_ASUSTEK, | ||
1662 | .subdevice = 0x4845, | ||
1663 | .driver_data = SAA7135_BOARD_ASUSTeK_TVFM7135, | ||
1664 | },{ | ||
1665 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1666 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1667 | .subvendor = PCI_VENDOR_ID_ASUSTEK, | ||
1668 | .subdevice = 0x4830, | ||
1669 | .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, | ||
1670 | },{ | ||
1671 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1672 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1673 | .subvendor = PCI_VENDOR_ID_ASUSTEK, | ||
1674 | .subdevice = 0x4843, | ||
1675 | .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133, | ||
1676 | },{ | ||
1677 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1678 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1679 | .subvendor = PCI_VENDOR_ID_ASUSTEK, | ||
1680 | .subdevice = 0x4840, | ||
1681 | .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134, | ||
1682 | },{ | ||
1683 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1684 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1685 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1686 | .subdevice = 0xfe01, | ||
1687 | .driver_data = SAA7134_BOARD_TVSTATION_RDS, | ||
1688 | },{ | ||
1689 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1690 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1691 | .subvendor = 0x1894, | ||
1692 | .subdevice = 0xfe01, | ||
1693 | .driver_data = SAA7134_BOARD_TVSTATION_RDS, | ||
1694 | },{ | ||
1695 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1696 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1697 | .subvendor = 0x1894, | ||
1698 | .subdevice = 0xa006, | ||
1699 | .driver_data = SAA7134_BOARD_TVSTATION_DVR, | ||
1700 | },{ | ||
1701 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1702 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1703 | .subvendor = 0x1131, | ||
1704 | .subdevice = 0x7133, | ||
1705 | .driver_data = SAA7134_BOARD_VA1000POWER, | ||
1706 | },{ | ||
1707 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1708 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1709 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1710 | .subdevice = 0x2001, | ||
1711 | .driver_data = SAA7134_BOARD_10MOONSTVMASTER, | ||
1712 | },{ | ||
1713 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1714 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1715 | .subvendor = 0x185b, | ||
1716 | .subdevice = 0xc100, | ||
1717 | .driver_data = SAA7134_BOARD_VIDEOMATE_TV, | ||
1718 | },{ | ||
1719 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1720 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1721 | .subvendor = 0x185b, | ||
1722 | .subdevice = 0xc100, | ||
1723 | .driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS, | ||
1724 | },{ | ||
1725 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1726 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1727 | .subvendor = PCI_VENDOR_ID_MATROX, | ||
1728 | .subdevice = 0x48d0, | ||
1729 | .driver_data = SAA7134_BOARD_CRONOS_PLUS, | ||
1730 | },{ | ||
1731 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1732 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1733 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1734 | .subdevice = 0xa70b, | ||
1735 | .driver_data = SAA7134_BOARD_MD2819, | ||
1736 | },{ | ||
1737 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1738 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1739 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1740 | .subdevice = 0x2115, | ||
1741 | .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305, | ||
1742 | },{ | ||
1743 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1744 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1745 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1746 | .subdevice = 0x2108, | ||
1747 | .driver_data = SAA7134_BOARD_AVERMEDIA_305, | ||
1748 | },{ | ||
1749 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1750 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1751 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1752 | .subdevice = 0x10ff, | ||
1753 | .driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER, | ||
1754 | },{ | ||
1755 | /* AVerMedia CardBus */ | ||
1756 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1757 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1758 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1759 | .subdevice = 0xd6ee, | ||
1760 | .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS, | ||
1761 | },{ | ||
1762 | /* TransGear 3000TV */ | ||
1763 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1764 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1765 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1766 | .subdevice = 0x050c, | ||
1767 | .driver_data = SAA7134_BOARD_TG3000TV, | ||
1768 | },{ | ||
1769 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1770 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1771 | .subvendor = 0x11bd, | ||
1772 | .subdevice = 0x002b, | ||
1773 | .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO, | ||
1774 | },{ | ||
1775 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1776 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1777 | .subvendor = 0x11bd, | ||
1778 | .subdevice = 0x002d, | ||
1779 | .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL, | ||
1780 | },{ | ||
1781 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1782 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1783 | .subvendor = 0x1019, | ||
1784 | .subdevice = 0x4cb4, | ||
1785 | .driver_data = SAA7134_BOARD_ECS_TVP3XP, | ||
1786 | },{ | ||
1787 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1788 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1789 | .subvendor = 0x1019, | ||
1790 | .subdevice = 0x4cb5, | ||
1791 | .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5, | ||
1792 | },{ | ||
1793 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1794 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1795 | .subvendor = 0x12ab, | ||
1796 | .subdevice = 0x0800, | ||
1797 | .driver_data = SAA7133_BOARD_UPMOST_PURPLE_TV, | ||
1798 | },{ | ||
1799 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1800 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1801 | .subvendor = 0x153B, | ||
1802 | .subdevice = 0x1152, | ||
1803 | .driver_data = SAA7134_BOARD_CINERGY200, | ||
1804 | },{ | ||
1805 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1806 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1807 | .subvendor = 0x185b, | ||
1808 | .subdevice = 0xc100, | ||
1809 | .driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR, | ||
1810 | },{ | ||
1811 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1812 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1813 | .subvendor = 0x1131, | ||
1814 | .subdevice = 0, | ||
1815 | .driver_data = SAA7134_BOARD_SABRENT_SBTTVFM, | ||
1816 | },{ | ||
1817 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1818 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1819 | .subvendor = 0x1461, /* Avermedia Technologies Inc */ | ||
1820 | .subdevice = 0x9715, | ||
1821 | .driver_data = SAA7134_BOARD_AVERMEDIA_307, | ||
1822 | },{ | ||
1823 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1824 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1825 | .subvendor = 0x185b, | ||
1826 | .subdevice = 0xc200, | ||
1827 | .driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS, | ||
1828 | },{ | ||
1829 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1830 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1831 | .subvendor = 0x1540, | ||
1832 | .subdevice = 0x9524, | ||
1833 | .driver_data = SAA7134_BOARD_PROVIDEO_PV952, | ||
1834 | |||
1835 | },{ | ||
1836 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1837 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1838 | .subvendor = 0x5168, | ||
1839 | .subdevice = 0x0306, | ||
1840 | .driver_data = SAA7134_BOARD_FLYDVBTDUO, | ||
1841 | |||
1842 | },{ | ||
1843 | /* --- boards without eeprom + subsystem ID --- */ | ||
1844 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1845 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1846 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1847 | .subdevice = 0, | ||
1848 | .driver_data = SAA7134_BOARD_NOAUTO, | ||
1849 | },{ | ||
1850 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1851 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1852 | .subvendor = PCI_VENDOR_ID_PHILIPS, | ||
1853 | .subdevice = 0, | ||
1854 | .driver_data = SAA7134_BOARD_NOAUTO, | ||
1855 | },{ | ||
1856 | |||
1857 | /* --- default catch --- */ | ||
1858 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1859 | .device = PCI_DEVICE_ID_PHILIPS_SAA7130, | ||
1860 | .subvendor = PCI_ANY_ID, | ||
1861 | .subdevice = PCI_ANY_ID, | ||
1862 | .driver_data = SAA7134_BOARD_UNKNOWN, | ||
1863 | },{ | ||
1864 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1865 | .device = PCI_DEVICE_ID_PHILIPS_SAA7133, | ||
1866 | .subvendor = PCI_ANY_ID, | ||
1867 | .subdevice = PCI_ANY_ID, | ||
1868 | .driver_data = SAA7134_BOARD_UNKNOWN, | ||
1869 | },{ | ||
1870 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1871 | .device = PCI_DEVICE_ID_PHILIPS_SAA7134, | ||
1872 | .subvendor = PCI_ANY_ID, | ||
1873 | .subdevice = PCI_ANY_ID, | ||
1874 | .driver_data = SAA7134_BOARD_UNKNOWN, | ||
1875 | },{ | ||
1876 | .vendor = PCI_VENDOR_ID_PHILIPS, | ||
1877 | .device = PCI_DEVICE_ID_PHILIPS_SAA7135, | ||
1878 | .subvendor = PCI_ANY_ID, | ||
1879 | .subdevice = PCI_ANY_ID, | ||
1880 | .driver_data = SAA7134_BOARD_UNKNOWN, | ||
1881 | },{ | ||
1882 | /* --- end of list --- */ | ||
1883 | } | ||
1884 | }; | ||
1885 | MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl); | ||
1886 | |||
1887 | /* ----------------------------------------------------------- */ | ||
1888 | /* flyvideo tweaks */ | ||
1889 | |||
1890 | #if 0 | ||
1891 | static struct { | ||
1892 | char *model; | ||
1893 | int tuner_type; | ||
1894 | } fly_list[0x20] = { | ||
1895 | /* default catch ... */ | ||
1896 | [ 0 ... 0x1f ] = { | ||
1897 | .model = "UNKNOWN", | ||
1898 | .tuner_type = TUNER_ABSENT, | ||
1899 | }, | ||
1900 | /* ... the ones known so far */ | ||
1901 | [ 0x05 ] = { | ||
1902 | .model = "PAL-BG", | ||
1903 | .tuner_type = TUNER_LG_PAL_NEW_TAPC, | ||
1904 | }, | ||
1905 | [ 0x10 ] = { | ||
1906 | .model = "PAL-BG / PAL-DK", | ||
1907 | .tuner_type = TUNER_PHILIPS_PAL, | ||
1908 | }, | ||
1909 | [ 0x15 ] = { | ||
1910 | .model = "NTSC", | ||
1911 | .tuner_type = TUNER_ABSENT /* FIXME */, | ||
1912 | }, | ||
1913 | }; | ||
1914 | #endif | ||
1915 | |||
1916 | static void board_flyvideo(struct saa7134_dev *dev) | ||
1917 | { | ||
1918 | #if 0 | ||
1919 | /* non-working attempt to detect the correct tuner type ... */ | ||
1920 | u32 value; | ||
1921 | int index; | ||
1922 | |||
1923 | value = dev->gpio_value; | ||
1924 | index = (value & 0x1f00) >> 8; | ||
1925 | printk(KERN_INFO "%s: flyvideo: gpio is 0x%x [model=%s,tuner=%d]\n", | ||
1926 | dev->name, value, fly_list[index].model, | ||
1927 | fly_list[index].tuner_type); | ||
1928 | dev->tuner_type = fly_list[index].tuner_type; | ||
1929 | #endif | ||
1930 | printk("%s: there are different flyvideo cards with different tuners\n" | ||
1931 | "%s: out there, you might have to use the tuner=<nr> insmod\n" | ||
1932 | "%s: option to override the default value.\n", | ||
1933 | dev->name, dev->name, dev->name); | ||
1934 | } | ||
1935 | |||
1936 | /* ----------------------------------------------------------- */ | ||
1937 | |||
1938 | int saa7134_board_init1(struct saa7134_dev *dev) | ||
1939 | { | ||
1940 | // Always print gpio, often manufacturers encode tuner type and other info. | ||
1941 | saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0); | ||
1942 | dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); | ||
1943 | printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value); | ||
1944 | |||
1945 | switch (dev->board) { | ||
1946 | case SAA7134_BOARD_FLYVIDEO2000: | ||
1947 | case SAA7134_BOARD_FLYVIDEO3000: | ||
1948 | dev->has_remote = 1; | ||
1949 | board_flyvideo(dev); | ||
1950 | break; | ||
1951 | case SAA7134_BOARD_CINERGY400: | ||
1952 | case SAA7134_BOARD_CINERGY600: | ||
1953 | case SAA7134_BOARD_CINERGY600_MK3: | ||
1954 | case SAA7134_BOARD_ECS_TVP3XP: | ||
1955 | case SAA7134_BOARD_ECS_TVP3XP_4CB5: | ||
1956 | case SAA7134_BOARD_MD2819: | ||
1957 | case SAA7134_BOARD_AVERMEDIA_STUDIO_305: | ||
1958 | case SAA7134_BOARD_AVERMEDIA_305: | ||
1959 | case SAA7134_BOARD_AVERMEDIA_307: | ||
1960 | // case SAA7134_BOARD_SABRENT_SBTTVFM: /* not finished yet */ | ||
1961 | case SAA7134_BOARD_VIDEOMATE_TV_PVR: | ||
1962 | dev->has_remote = 1; | ||
1963 | break; | ||
1964 | case SAA7134_BOARD_AVACSSMARTTV: | ||
1965 | dev->has_remote = 1; | ||
1966 | break; | ||
1967 | case SAA7134_BOARD_MD5044: | ||
1968 | printk("%s: seems there are two different versions of the MD5044\n" | ||
1969 | "%s: (with the same ID) out there. If sound doesn't work for\n" | ||
1970 | "%s: you try the audio_clock_override=0x200000 insmod option.\n", | ||
1971 | dev->name,dev->name,dev->name); | ||
1972 | break; | ||
1973 | case SAA7134_BOARD_CINERGY400_CARDBUS: | ||
1974 | /* power-up tuner chip */ | ||
1975 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x00040000, 0x00040000); | ||
1976 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000); | ||
1977 | msleep(1); | ||
1978 | break; | ||
1979 | } | ||
1980 | if (dev->has_remote) | ||
1981 | dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 | | ||
1982 | SAA7134_IRQ2_INTE_GPIO18A | | ||
1983 | SAA7134_IRQ2_INTE_GPIO16 ); | ||
1984 | return 0; | ||
1985 | } | ||
1986 | |||
1987 | /* stuff which needs working i2c */ | ||
1988 | int saa7134_board_init2(struct saa7134_dev *dev) | ||
1989 | { | ||
1990 | unsigned char buf; | ||
1991 | int board; | ||
1992 | |||
1993 | switch (dev->board) { | ||
1994 | case SAA7134_BOARD_BMK_MPEX_NOTUNER: | ||
1995 | case SAA7134_BOARD_BMK_MPEX_TUNER: | ||
1996 | dev->i2c_client.addr = 0x60; | ||
1997 | board = (i2c_master_recv(&dev->i2c_client,&buf,0) < 0) | ||
1998 | ? SAA7134_BOARD_BMK_MPEX_NOTUNER | ||
1999 | : SAA7134_BOARD_BMK_MPEX_TUNER; | ||
2000 | if (board == dev->board) | ||
2001 | break; | ||
2002 | dev->board = board; | ||
2003 | printk("%s: board type fixup: %s\n", dev->name, | ||
2004 | saa7134_boards[dev->board].name); | ||
2005 | dev->tuner_type = saa7134_boards[dev->board].tuner_type; | ||
2006 | if (TUNER_ABSENT != dev->tuner_type) | ||
2007 | saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&dev->tuner_type); | ||
2008 | break; | ||
2009 | } | ||
2010 | return 0; | ||
2011 | } | ||
2012 | |||
2013 | /* ----------------------------------------------------------- */ | ||
2014 | /* | ||
2015 | * Local variables: | ||
2016 | * c-basic-offset: 8 | ||
2017 | * End: | ||
2018 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c new file mode 100644 index 000000000000..d506cafba8ff --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-core.c | |||
@@ -0,0 +1,1237 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-core.c,v 1.28 2005/02/22 09:56:29 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * driver core | ||
6 | * | ||
7 | * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/config.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/module.h> | ||
28 | #include <linux/moduleparam.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/slab.h> | ||
31 | #include <linux/kmod.h> | ||
32 | #include <linux/sound.h> | ||
33 | #include <linux/interrupt.h> | ||
34 | #include <linux/delay.h> | ||
35 | |||
36 | #include "saa7134-reg.h" | ||
37 | #include "saa7134.h" | ||
38 | |||
39 | MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); | ||
40 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
41 | MODULE_LICENSE("GPL"); | ||
42 | |||
43 | /* ------------------------------------------------------------------ */ | ||
44 | |||
45 | static unsigned int irq_debug = 0; | ||
46 | module_param(irq_debug, int, 0644); | ||
47 | MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); | ||
48 | |||
49 | static unsigned int core_debug = 0; | ||
50 | module_param(core_debug, int, 0644); | ||
51 | MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); | ||
52 | |||
53 | static unsigned int gpio_tracking = 0; | ||
54 | module_param(gpio_tracking, int, 0644); | ||
55 | MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); | ||
56 | |||
57 | static unsigned int oss = 0; | ||
58 | module_param(oss, int, 0444); | ||
59 | MODULE_PARM_DESC(oss,"register oss devices (default: no)"); | ||
60 | |||
61 | static unsigned int latency = UNSET; | ||
62 | module_param(latency, int, 0444); | ||
63 | MODULE_PARM_DESC(latency,"pci latency timer"); | ||
64 | |||
65 | static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
66 | static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
67 | static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
68 | static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
69 | static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
70 | static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
71 | static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
72 | |||
73 | module_param_array(video_nr, int, NULL, 0444); | ||
74 | module_param_array(vbi_nr, int, NULL, 0444); | ||
75 | module_param_array(radio_nr, int, NULL, 0444); | ||
76 | module_param_array(dsp_nr, int, NULL, 0444); | ||
77 | module_param_array(mixer_nr, int, NULL, 0444); | ||
78 | module_param_array(tuner, int, NULL, 0444); | ||
79 | module_param_array(card, int, NULL, 0444); | ||
80 | |||
81 | MODULE_PARM_DESC(video_nr, "video device number"); | ||
82 | MODULE_PARM_DESC(vbi_nr, "vbi device number"); | ||
83 | MODULE_PARM_DESC(radio_nr, "radio device number"); | ||
84 | MODULE_PARM_DESC(dsp_nr, "oss dsp device number"); | ||
85 | MODULE_PARM_DESC(mixer_nr, "oss mixer device number"); | ||
86 | MODULE_PARM_DESC(tuner, "tuner type"); | ||
87 | MODULE_PARM_DESC(card, "card type"); | ||
88 | |||
89 | static DECLARE_MUTEX(devlist_lock); | ||
90 | LIST_HEAD(saa7134_devlist); | ||
91 | static LIST_HEAD(mops_list); | ||
92 | static unsigned int saa7134_devcount; | ||
93 | |||
94 | #define dprintk(fmt, arg...) if (core_debug) \ | ||
95 | printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) | ||
96 | |||
97 | /* ------------------------------------------------------------------ */ | ||
98 | /* debug help functions */ | ||
99 | |||
100 | static const char *v4l1_ioctls[] = { | ||
101 | "0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", | ||
102 | "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", | ||
103 | "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", | ||
104 | "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", | ||
105 | "SMICROCODE", "GVBIFMT", "SVBIFMT" }; | ||
106 | #define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) | ||
107 | |||
108 | static const char *v4l2_ioctls[] = { | ||
109 | "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", | ||
110 | "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", | ||
111 | "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", | ||
112 | "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", | ||
113 | "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", | ||
114 | "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", | ||
115 | "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", | ||
116 | "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", | ||
117 | "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", | ||
118 | "S_MODULATOR" | ||
119 | }; | ||
120 | #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) | ||
121 | |||
122 | static const char *osspcm_ioctls[] = { | ||
123 | "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", | ||
124 | "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", | ||
125 | "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", | ||
126 | "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", | ||
127 | "SETDUPLEX", "GETODELAY" | ||
128 | }; | ||
129 | #define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls) | ||
130 | |||
131 | void saa7134_print_ioctl(char *name, unsigned int cmd) | ||
132 | { | ||
133 | char *dir; | ||
134 | |||
135 | switch (_IOC_DIR(cmd)) { | ||
136 | case _IOC_NONE: dir = "--"; break; | ||
137 | case _IOC_READ: dir = "r-"; break; | ||
138 | case _IOC_WRITE: dir = "-w"; break; | ||
139 | case _IOC_READ | _IOC_WRITE: dir = "rw"; break; | ||
140 | default: dir = "??"; break; | ||
141 | } | ||
142 | switch (_IOC_TYPE(cmd)) { | ||
143 | case 'v': | ||
144 | printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n", | ||
145 | name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ? | ||
146 | v4l1_ioctls[_IOC_NR(cmd)] : "???"); | ||
147 | break; | ||
148 | case 'V': | ||
149 | printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n", | ||
150 | name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ? | ||
151 | v4l2_ioctls[_IOC_NR(cmd)] : "???"); | ||
152 | break; | ||
153 | case 'P': | ||
154 | printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", | ||
155 | name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? | ||
156 | osspcm_ioctls[_IOC_NR(cmd)] : "???"); | ||
157 | break; | ||
158 | case 'M': | ||
159 | printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", | ||
160 | name, cmd, dir, _IOC_NR(cmd)); | ||
161 | break; | ||
162 | default: | ||
163 | printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", | ||
164 | name, cmd, dir, _IOC_NR(cmd)); | ||
165 | } | ||
166 | } | ||
167 | |||
168 | void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) | ||
169 | { | ||
170 | unsigned long mode,status; | ||
171 | |||
172 | if (!gpio_tracking) | ||
173 | return; | ||
174 | /* rising SAA7134_GPIO_GPRESCAN reads the status */ | ||
175 | saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0); | ||
176 | saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN); | ||
177 | mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff; | ||
178 | status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff; | ||
179 | printk(KERN_DEBUG | ||
180 | "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", | ||
181 | dev->name, mode, (~mode) & status, mode & status, msg); | ||
182 | } | ||
183 | |||
184 | /* ------------------------------------------------------------------ */ | ||
185 | |||
186 | #if 0 | ||
187 | static char *dec1_bits[8] = { | ||
188 | "DCSTD0", "DCSCT1", "WIPA", "GLIMB", | ||
189 | "GLIMT", "SLTCA", "HLCK" | ||
190 | }; | ||
191 | static char *dec2_bits[8] = { | ||
192 | "RDCAP", "COPRO", "COLSTR", "TYPE3", | ||
193 | NULL, "FIDT", "HLVLN", "INTL" | ||
194 | }; | ||
195 | static char *scale1_bits[8] = { | ||
196 | "VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B" | ||
197 | }; | ||
198 | static char *scale2_bits[8] = { | ||
199 | "TRERR", "CFERR", "LDERR", "WASRST", | ||
200 | "FIDSCI", "FIDSCO", "D6^D5", "TASK" | ||
201 | }; | ||
202 | |||
203 | static void dump_statusreg(struct saa7134_dev *dev, int reg, | ||
204 | char *regname, char **bits) | ||
205 | { | ||
206 | int value,i; | ||
207 | |||
208 | value = saa_readb(reg); | ||
209 | printk(KERN_DEBUG "%s: %s:", dev->name, regname); | ||
210 | for (i = 7; i >= 0; i--) { | ||
211 | if (NULL == bits[i]) | ||
212 | continue; | ||
213 | printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0); | ||
214 | } | ||
215 | printk("\n"); | ||
216 | } | ||
217 | |||
218 | static void dump_statusregs(struct saa7134_dev *dev) | ||
219 | { | ||
220 | dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits); | ||
221 | dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits); | ||
222 | dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits); | ||
223 | dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits); | ||
224 | } | ||
225 | #endif | ||
226 | |||
227 | /* ----------------------------------------------------------- */ | ||
228 | /* delayed request_module */ | ||
229 | |||
230 | #ifdef CONFIG_MODULES | ||
231 | |||
232 | static int need_empress; | ||
233 | static int need_dvb; | ||
234 | |||
235 | static int pending_call(struct notifier_block *self, unsigned long state, | ||
236 | void *module) | ||
237 | { | ||
238 | if (module != THIS_MODULE || state != MODULE_STATE_LIVE) | ||
239 | return NOTIFY_DONE; | ||
240 | |||
241 | if (need_empress) | ||
242 | request_module("saa7134-empress"); | ||
243 | if (need_dvb) | ||
244 | request_module("saa7134-dvb"); | ||
245 | return NOTIFY_DONE; | ||
246 | } | ||
247 | |||
248 | static int pending_registered; | ||
249 | static struct notifier_block pending_notifier = { | ||
250 | .notifier_call = pending_call, | ||
251 | }; | ||
252 | |||
253 | static void request_module_depend(char *name, int *flag) | ||
254 | { | ||
255 | switch (THIS_MODULE->state) { | ||
256 | case MODULE_STATE_COMING: | ||
257 | if (!pending_registered) { | ||
258 | register_module_notifier(&pending_notifier); | ||
259 | pending_registered = 1; | ||
260 | } | ||
261 | *flag = 1; | ||
262 | break; | ||
263 | case MODULE_STATE_LIVE: | ||
264 | request_module(name); | ||
265 | break; | ||
266 | default: | ||
267 | /* nothing */; | ||
268 | break; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | #else | ||
273 | |||
274 | #define request_module_depend(name,flag) | ||
275 | |||
276 | #endif /* CONFIG_MODULES */ | ||
277 | |||
278 | /* ------------------------------------------------------------------ */ | ||
279 | |||
280 | /* nr of (saa7134-)pages for the given buffer size */ | ||
281 | static int saa7134_buffer_pages(int size) | ||
282 | { | ||
283 | size = PAGE_ALIGN(size); | ||
284 | size += PAGE_SIZE; /* for non-page-aligned buffers */ | ||
285 | size /= 4096; | ||
286 | return size; | ||
287 | } | ||
288 | |||
289 | /* calc max # of buffers from size (must not exceed the 4MB virtual | ||
290 | * address space per DMA channel) */ | ||
291 | int saa7134_buffer_count(unsigned int size, unsigned int count) | ||
292 | { | ||
293 | unsigned int maxcount; | ||
294 | |||
295 | maxcount = 1024 / saa7134_buffer_pages(size); | ||
296 | if (count > maxcount) | ||
297 | count = maxcount; | ||
298 | return count; | ||
299 | } | ||
300 | |||
301 | int saa7134_buffer_startpage(struct saa7134_buf *buf) | ||
302 | { | ||
303 | return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i; | ||
304 | } | ||
305 | |||
306 | unsigned long saa7134_buffer_base(struct saa7134_buf *buf) | ||
307 | { | ||
308 | unsigned long base; | ||
309 | |||
310 | base = saa7134_buffer_startpage(buf) * 4096; | ||
311 | base += buf->vb.dma.sglist[0].offset; | ||
312 | return base; | ||
313 | } | ||
314 | |||
315 | /* ------------------------------------------------------------------ */ | ||
316 | |||
317 | int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) | ||
318 | { | ||
319 | u32 *cpu; | ||
320 | dma_addr_t dma_addr; | ||
321 | |||
322 | cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); | ||
323 | if (NULL == cpu) | ||
324 | return -ENOMEM; | ||
325 | pt->size = SAA7134_PGTABLE_SIZE; | ||
326 | pt->cpu = cpu; | ||
327 | pt->dma = dma_addr; | ||
328 | return 0; | ||
329 | } | ||
330 | |||
331 | int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, | ||
332 | struct scatterlist *list, unsigned int length, | ||
333 | unsigned int startpage) | ||
334 | { | ||
335 | u32 *ptr; | ||
336 | unsigned int i,p; | ||
337 | |||
338 | BUG_ON(NULL == pt || NULL == pt->cpu); | ||
339 | |||
340 | ptr = pt->cpu + startpage; | ||
341 | for (i = 0; i < length; i++, list++) | ||
342 | for (p = 0; p * 4096 < list->length; p++, ptr++) | ||
343 | *ptr = sg_dma_address(list) - list->offset; | ||
344 | return 0; | ||
345 | } | ||
346 | |||
347 | void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) | ||
348 | { | ||
349 | if (NULL == pt->cpu) | ||
350 | return; | ||
351 | pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); | ||
352 | pt->cpu = NULL; | ||
353 | } | ||
354 | |||
355 | /* ------------------------------------------------------------------ */ | ||
356 | |||
357 | void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf) | ||
358 | { | ||
359 | if (in_interrupt()) | ||
360 | BUG(); | ||
361 | |||
362 | videobuf_waiton(&buf->vb,0,0); | ||
363 | videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); | ||
364 | videobuf_dma_free(&buf->vb.dma); | ||
365 | buf->vb.state = STATE_NEEDS_INIT; | ||
366 | } | ||
367 | |||
368 | /* ------------------------------------------------------------------ */ | ||
369 | |||
370 | int saa7134_buffer_queue(struct saa7134_dev *dev, | ||
371 | struct saa7134_dmaqueue *q, | ||
372 | struct saa7134_buf *buf) | ||
373 | { | ||
374 | struct saa7134_buf *next = NULL; | ||
375 | |||
376 | assert_spin_locked(&dev->slock); | ||
377 | dprintk("buffer_queue %p\n",buf); | ||
378 | if (NULL == q->curr) { | ||
379 | if (!q->need_two) { | ||
380 | q->curr = buf; | ||
381 | buf->activate(dev,buf,NULL); | ||
382 | } else if (list_empty(&q->queue)) { | ||
383 | list_add_tail(&buf->vb.queue,&q->queue); | ||
384 | buf->vb.state = STATE_QUEUED; | ||
385 | } else { | ||
386 | next = list_entry(q->queue.next,struct saa7134_buf, | ||
387 | vb.queue); | ||
388 | q->curr = buf; | ||
389 | buf->activate(dev,buf,next); | ||
390 | } | ||
391 | } else { | ||
392 | list_add_tail(&buf->vb.queue,&q->queue); | ||
393 | buf->vb.state = STATE_QUEUED; | ||
394 | } | ||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | void saa7134_buffer_finish(struct saa7134_dev *dev, | ||
399 | struct saa7134_dmaqueue *q, | ||
400 | unsigned int state) | ||
401 | { | ||
402 | assert_spin_locked(&dev->slock); | ||
403 | dprintk("buffer_finish %p\n",q->curr); | ||
404 | |||
405 | /* finish current buffer */ | ||
406 | q->curr->vb.state = state; | ||
407 | do_gettimeofday(&q->curr->vb.ts); | ||
408 | wake_up(&q->curr->vb.done); | ||
409 | q->curr = NULL; | ||
410 | } | ||
411 | |||
412 | void saa7134_buffer_next(struct saa7134_dev *dev, | ||
413 | struct saa7134_dmaqueue *q) | ||
414 | { | ||
415 | struct saa7134_buf *buf,*next = NULL; | ||
416 | |||
417 | assert_spin_locked(&dev->slock); | ||
418 | BUG_ON(NULL != q->curr); | ||
419 | |||
420 | if (!list_empty(&q->queue)) { | ||
421 | /* activate next one from queue */ | ||
422 | buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue); | ||
423 | dprintk("buffer_next %p [prev=%p/next=%p]\n", | ||
424 | buf,q->queue.prev,q->queue.next); | ||
425 | list_del(&buf->vb.queue); | ||
426 | if (!list_empty(&q->queue)) | ||
427 | next = list_entry(q->queue.next,struct saa7134_buf, | ||
428 | vb.queue); | ||
429 | q->curr = buf; | ||
430 | buf->activate(dev,buf,next); | ||
431 | dprintk("buffer_next #2 prev=%p/next=%p\n", | ||
432 | q->queue.prev,q->queue.next); | ||
433 | } else { | ||
434 | /* nothing to do -- just stop DMA */ | ||
435 | dprintk("buffer_next %p\n",NULL); | ||
436 | saa7134_set_dmabits(dev); | ||
437 | del_timer(&q->timeout); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | void saa7134_buffer_timeout(unsigned long data) | ||
442 | { | ||
443 | struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data; | ||
444 | struct saa7134_dev *dev = q->dev; | ||
445 | unsigned long flags; | ||
446 | |||
447 | spin_lock_irqsave(&dev->slock,flags); | ||
448 | |||
449 | /* try to reset the hardware (SWRST) */ | ||
450 | saa_writeb(SAA7134_REGION_ENABLE, 0x00); | ||
451 | saa_writeb(SAA7134_REGION_ENABLE, 0x80); | ||
452 | saa_writeb(SAA7134_REGION_ENABLE, 0x00); | ||
453 | |||
454 | /* flag current buffer as failed, | ||
455 | try to start over with the next one. */ | ||
456 | if (q->curr) { | ||
457 | dprintk("timeout on %p\n",q->curr); | ||
458 | saa7134_buffer_finish(dev,q,STATE_ERROR); | ||
459 | } | ||
460 | saa7134_buffer_next(dev,q); | ||
461 | spin_unlock_irqrestore(&dev->slock,flags); | ||
462 | } | ||
463 | |||
464 | /* ------------------------------------------------------------------ */ | ||
465 | |||
466 | int saa7134_set_dmabits(struct saa7134_dev *dev) | ||
467 | { | ||
468 | u32 split, task=0, ctrl=0, irq=0; | ||
469 | enum v4l2_field cap = V4L2_FIELD_ANY; | ||
470 | enum v4l2_field ov = V4L2_FIELD_ANY; | ||
471 | |||
472 | assert_spin_locked(&dev->slock); | ||
473 | |||
474 | /* video capture -- dma 0 + video task A */ | ||
475 | if (dev->video_q.curr) { | ||
476 | task |= 0x01; | ||
477 | ctrl |= SAA7134_MAIN_CTRL_TE0; | ||
478 | irq |= SAA7134_IRQ1_INTE_RA0_1 | | ||
479 | SAA7134_IRQ1_INTE_RA0_0; | ||
480 | cap = dev->video_q.curr->vb.field; | ||
481 | } | ||
482 | |||
483 | /* video capture -- dma 1+2 (planar modes) */ | ||
484 | if (dev->video_q.curr && | ||
485 | dev->video_q.curr->fmt->planar) { | ||
486 | ctrl |= SAA7134_MAIN_CTRL_TE4 | | ||
487 | SAA7134_MAIN_CTRL_TE5; | ||
488 | } | ||
489 | |||
490 | /* screen overlay -- dma 0 + video task B */ | ||
491 | if (dev->ovenable) { | ||
492 | task |= 0x10; | ||
493 | ctrl |= SAA7134_MAIN_CTRL_TE1; | ||
494 | ov = dev->ovfield; | ||
495 | } | ||
496 | |||
497 | /* vbi capture -- dma 0 + vbi task A+B */ | ||
498 | if (dev->vbi_q.curr) { | ||
499 | task |= 0x22; | ||
500 | ctrl |= SAA7134_MAIN_CTRL_TE2 | | ||
501 | SAA7134_MAIN_CTRL_TE3; | ||
502 | irq |= SAA7134_IRQ1_INTE_RA0_7 | | ||
503 | SAA7134_IRQ1_INTE_RA0_6 | | ||
504 | SAA7134_IRQ1_INTE_RA0_5 | | ||
505 | SAA7134_IRQ1_INTE_RA0_4; | ||
506 | } | ||
507 | |||
508 | /* audio capture -- dma 3 */ | ||
509 | if (dev->oss.dma_running) { | ||
510 | ctrl |= SAA7134_MAIN_CTRL_TE6; | ||
511 | irq |= SAA7134_IRQ1_INTE_RA3_1 | | ||
512 | SAA7134_IRQ1_INTE_RA3_0; | ||
513 | } | ||
514 | |||
515 | /* TS capture -- dma 5 */ | ||
516 | if (dev->ts_q.curr) { | ||
517 | ctrl |= SAA7134_MAIN_CTRL_TE5; | ||
518 | irq |= SAA7134_IRQ1_INTE_RA2_3 | | ||
519 | SAA7134_IRQ1_INTE_RA2_2 | | ||
520 | SAA7134_IRQ1_INTE_RA2_1 | | ||
521 | SAA7134_IRQ1_INTE_RA2_0; | ||
522 | } | ||
523 | |||
524 | /* set task conditions + field handling */ | ||
525 | if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) { | ||
526 | /* default config -- use full frames */ | ||
527 | saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d); | ||
528 | saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d); | ||
529 | saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x02); | ||
530 | saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x02); | ||
531 | split = 0; | ||
532 | } else { | ||
533 | /* split fields between tasks */ | ||
534 | if (V4L2_FIELD_TOP == cap) { | ||
535 | /* odd A, even B, repeat */ | ||
536 | saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d); | ||
537 | saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0e); | ||
538 | } else { | ||
539 | /* odd B, even A, repeat */ | ||
540 | saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0e); | ||
541 | saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d); | ||
542 | } | ||
543 | saa_writeb(SAA7134_FIELD_HANDLING(TASK_A), 0x01); | ||
544 | saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x01); | ||
545 | split = 1; | ||
546 | } | ||
547 | |||
548 | /* irqs */ | ||
549 | saa_writeb(SAA7134_REGION_ENABLE, task); | ||
550 | saa_writel(SAA7134_IRQ1, irq); | ||
551 | saa_andorl(SAA7134_MAIN_CTRL, | ||
552 | SAA7134_MAIN_CTRL_TE0 | | ||
553 | SAA7134_MAIN_CTRL_TE1 | | ||
554 | SAA7134_MAIN_CTRL_TE2 | | ||
555 | SAA7134_MAIN_CTRL_TE3 | | ||
556 | SAA7134_MAIN_CTRL_TE4 | | ||
557 | SAA7134_MAIN_CTRL_TE5 | | ||
558 | SAA7134_MAIN_CTRL_TE6, | ||
559 | ctrl); | ||
560 | dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n", | ||
561 | task, ctrl, irq, split ? "no" : "yes"); | ||
562 | |||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | /* ------------------------------------------------------------------ */ | ||
567 | /* IRQ handler + helpers */ | ||
568 | |||
569 | static char *irqbits[] = { | ||
570 | "DONE_RA0", "DONE_RA1", "DONE_RA2", "DONE_RA3", | ||
571 | "AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC", | ||
572 | "TRIG_ERR", "CONF_ERR", "LOAD_ERR", | ||
573 | "GPIO16?", "GPIO18", "GPIO22", "GPIO23" | ||
574 | }; | ||
575 | #define IRQBITS ARRAY_SIZE(irqbits) | ||
576 | |||
577 | static void print_irqstatus(struct saa7134_dev *dev, int loop, | ||
578 | unsigned long report, unsigned long status) | ||
579 | { | ||
580 | unsigned int i; | ||
581 | |||
582 | printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx", | ||
583 | dev->name,loop,jiffies,report,status); | ||
584 | for (i = 0; i < IRQBITS; i++) { | ||
585 | if (!(report & (1 << i))) | ||
586 | continue; | ||
587 | printk(" %s",irqbits[i]); | ||
588 | } | ||
589 | if (report & SAA7134_IRQ_REPORT_DONE_RA0) { | ||
590 | printk(" | RA0=%s,%s,%s,%ld", | ||
591 | (status & 0x40) ? "vbi" : "video", | ||
592 | (status & 0x20) ? "b" : "a", | ||
593 | (status & 0x10) ? "odd" : "even", | ||
594 | (status & 0x0f)); | ||
595 | } | ||
596 | printk("\n"); | ||
597 | } | ||
598 | |||
599 | static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) | ||
600 | { | ||
601 | struct saa7134_dev *dev = (struct saa7134_dev*) dev_id; | ||
602 | unsigned long report,status; | ||
603 | int loop, handled = 0; | ||
604 | |||
605 | for (loop = 0; loop < 10; loop++) { | ||
606 | report = saa_readl(SAA7134_IRQ_REPORT); | ||
607 | status = saa_readl(SAA7134_IRQ_STATUS); | ||
608 | if (0 == report) { | ||
609 | if (irq_debug > 1) | ||
610 | printk(KERN_DEBUG "%s/irq: no (more) work\n", | ||
611 | dev->name); | ||
612 | goto out; | ||
613 | } | ||
614 | handled = 1; | ||
615 | saa_writel(SAA7134_IRQ_REPORT,report); | ||
616 | if (irq_debug) | ||
617 | print_irqstatus(dev,loop,report,status); | ||
618 | |||
619 | #if 0 | ||
620 | if (report & SAA7134_IRQ_REPORT_CONF_ERR) | ||
621 | dump_statusregs(dev); | ||
622 | #endif | ||
623 | |||
624 | if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) | ||
625 | saa7134_irq_video_intl(dev); | ||
626 | |||
627 | if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && | ||
628 | (status & 0x60) == 0) | ||
629 | saa7134_irq_video_done(dev,status); | ||
630 | |||
631 | if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && | ||
632 | (status & 0x40) == 0x40) | ||
633 | saa7134_irq_vbi_done(dev,status); | ||
634 | |||
635 | if ((report & SAA7134_IRQ_REPORT_DONE_RA2) && | ||
636 | card_has_mpeg(dev)) | ||
637 | saa7134_irq_ts_done(dev,status); | ||
638 | |||
639 | if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) | ||
640 | saa7134_irq_oss_done(dev,status); | ||
641 | |||
642 | if ((report & (SAA7134_IRQ_REPORT_GPIO16 | | ||
643 | SAA7134_IRQ_REPORT_GPIO18)) && | ||
644 | dev->remote) | ||
645 | saa7134_input_irq(dev); | ||
646 | } | ||
647 | |||
648 | if (10 == loop) { | ||
649 | print_irqstatus(dev,loop,report,status); | ||
650 | if (report & SAA7134_IRQ_REPORT_PE) { | ||
651 | /* disable all parity error */ | ||
652 | printk(KERN_WARNING "%s/irq: looping -- " | ||
653 | "clearing PE (parity error!) enable bit\n",dev->name); | ||
654 | saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); | ||
655 | } else if (report & (SAA7134_IRQ_REPORT_GPIO16 | | ||
656 | SAA7134_IRQ_REPORT_GPIO18)) { | ||
657 | /* disable gpio IRQs */ | ||
658 | printk(KERN_WARNING "%s/irq: looping -- " | ||
659 | "clearing GPIO enable bits\n",dev->name); | ||
660 | saa_clearl(SAA7134_IRQ2, (SAA7134_IRQ2_INTE_GPIO16 | | ||
661 | SAA7134_IRQ2_INTE_GPIO18)); | ||
662 | } else { | ||
663 | /* disable all irqs */ | ||
664 | printk(KERN_WARNING "%s/irq: looping -- " | ||
665 | "clearing all enable bits\n",dev->name); | ||
666 | saa_writel(SAA7134_IRQ1,0); | ||
667 | saa_writel(SAA7134_IRQ2,0); | ||
668 | } | ||
669 | } | ||
670 | |||
671 | out: | ||
672 | return IRQ_RETVAL(handled); | ||
673 | } | ||
674 | |||
675 | /* ------------------------------------------------------------------ */ | ||
676 | |||
677 | /* early init (no i2c, no irq) */ | ||
678 | static int saa7134_hwinit1(struct saa7134_dev *dev) | ||
679 | { | ||
680 | dprintk("hwinit1\n"); | ||
681 | |||
682 | saa_writel(SAA7134_IRQ1, 0); | ||
683 | saa_writel(SAA7134_IRQ2, 0); | ||
684 | init_MUTEX(&dev->lock); | ||
685 | spin_lock_init(&dev->slock); | ||
686 | |||
687 | saa7134_track_gpio(dev,"pre-init"); | ||
688 | saa7134_video_init1(dev); | ||
689 | saa7134_vbi_init1(dev); | ||
690 | if (card_has_mpeg(dev)) | ||
691 | saa7134_ts_init1(dev); | ||
692 | saa7134_input_init1(dev); | ||
693 | |||
694 | switch (dev->pci->device) { | ||
695 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
696 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
697 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
698 | saa7134_oss_init1(dev); | ||
699 | break; | ||
700 | } | ||
701 | |||
702 | /* RAM FIFO config */ | ||
703 | saa_writel(SAA7134_FIFO_SIZE, 0x08070503); | ||
704 | saa_writel(SAA7134_THRESHOULD,0x02020202); | ||
705 | |||
706 | /* enable audio + video processing */ | ||
707 | saa_writel(SAA7134_MAIN_CTRL, | ||
708 | SAA7134_MAIN_CTRL_VPLLE | | ||
709 | SAA7134_MAIN_CTRL_APLLE | | ||
710 | SAA7134_MAIN_CTRL_EXOSC | | ||
711 | SAA7134_MAIN_CTRL_EVFE1 | | ||
712 | SAA7134_MAIN_CTRL_EVFE2 | | ||
713 | SAA7134_MAIN_CTRL_ESFE | | ||
714 | SAA7134_MAIN_CTRL_EBADC | | ||
715 | SAA7134_MAIN_CTRL_EBDAC); | ||
716 | |||
717 | /* enable peripheral devices */ | ||
718 | saa_writeb(SAA7134_SPECIAL_MODE, 0x01); | ||
719 | |||
720 | /* set vertical line numbering start (vbi needs this) */ | ||
721 | saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); | ||
722 | |||
723 | return 0; | ||
724 | } | ||
725 | |||
726 | /* late init (with i2c + irq) */ | ||
727 | static int saa7134_hwinit2(struct saa7134_dev *dev) | ||
728 | { | ||
729 | dprintk("hwinit2\n"); | ||
730 | |||
731 | saa7134_video_init2(dev); | ||
732 | saa7134_tvaudio_init2(dev); | ||
733 | |||
734 | /* enable IRQ's */ | ||
735 | saa_writel(SAA7134_IRQ1, 0); | ||
736 | saa_writel(SAA7134_IRQ2, dev->irq2_mask); | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | /* shutdown */ | ||
742 | static int saa7134_hwfini(struct saa7134_dev *dev) | ||
743 | { | ||
744 | dprintk("hwfini\n"); | ||
745 | |||
746 | switch (dev->pci->device) { | ||
747 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
748 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
749 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
750 | saa7134_oss_fini(dev); | ||
751 | break; | ||
752 | } | ||
753 | if (card_has_mpeg(dev)) | ||
754 | saa7134_ts_fini(dev); | ||
755 | saa7134_input_fini(dev); | ||
756 | saa7134_vbi_fini(dev); | ||
757 | saa7134_video_fini(dev); | ||
758 | saa7134_tvaudio_fini(dev); | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static void __devinit must_configure_manually(void) | ||
763 | { | ||
764 | unsigned int i,p; | ||
765 | |||
766 | printk(KERN_WARNING | ||
767 | "saa7134: <rant>\n" | ||
768 | "saa7134: Congratulations! Your TV card vendor saved a few\n" | ||
769 | "saa7134: cents for a eeprom, thus your pci board has no\n" | ||
770 | "saa7134: subsystem ID and I can't identify it automatically\n" | ||
771 | "saa7134: </rant>\n" | ||
772 | "saa7134: I feel better now. Ok, here are the good news:\n" | ||
773 | "saa7134: You can use the card=<nr> insmod option to specify\n" | ||
774 | "saa7134: which board do you have. The list:\n"); | ||
775 | for (i = 0; i < saa7134_bcount; i++) { | ||
776 | printk(KERN_WARNING "saa7134: card=%d -> %-40.40s", | ||
777 | i,saa7134_boards[i].name); | ||
778 | for (p = 0; saa7134_pci_tbl[p].driver_data; p++) { | ||
779 | if (saa7134_pci_tbl[p].driver_data != i) | ||
780 | continue; | ||
781 | printk(" %04x:%04x", | ||
782 | saa7134_pci_tbl[p].subvendor, | ||
783 | saa7134_pci_tbl[p].subdevice); | ||
784 | } | ||
785 | printk("\n"); | ||
786 | } | ||
787 | } | ||
788 | |||
789 | static struct video_device *vdev_init(struct saa7134_dev *dev, | ||
790 | struct video_device *template, | ||
791 | char *type) | ||
792 | { | ||
793 | struct video_device *vfd; | ||
794 | |||
795 | vfd = video_device_alloc(); | ||
796 | if (NULL == vfd) | ||
797 | return NULL; | ||
798 | *vfd = *template; | ||
799 | vfd->minor = -1; | ||
800 | vfd->dev = &dev->pci->dev; | ||
801 | vfd->release = video_device_release; | ||
802 | snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", | ||
803 | dev->name, type, saa7134_boards[dev->board].name); | ||
804 | return vfd; | ||
805 | } | ||
806 | |||
807 | static void saa7134_unregister_video(struct saa7134_dev *dev) | ||
808 | { | ||
809 | if (dev->video_dev) { | ||
810 | if (-1 != dev->video_dev->minor) | ||
811 | video_unregister_device(dev->video_dev); | ||
812 | else | ||
813 | video_device_release(dev->video_dev); | ||
814 | dev->video_dev = NULL; | ||
815 | } | ||
816 | if (dev->vbi_dev) { | ||
817 | if (-1 != dev->vbi_dev->minor) | ||
818 | video_unregister_device(dev->vbi_dev); | ||
819 | else | ||
820 | video_device_release(dev->vbi_dev); | ||
821 | dev->vbi_dev = NULL; | ||
822 | } | ||
823 | if (dev->radio_dev) { | ||
824 | if (-1 != dev->radio_dev->minor) | ||
825 | video_unregister_device(dev->radio_dev); | ||
826 | else | ||
827 | video_device_release(dev->radio_dev); | ||
828 | dev->radio_dev = NULL; | ||
829 | } | ||
830 | } | ||
831 | |||
832 | static void mpeg_ops_attach(struct saa7134_mpeg_ops *ops, | ||
833 | struct saa7134_dev *dev) | ||
834 | { | ||
835 | int err; | ||
836 | |||
837 | if (NULL != dev->mops) | ||
838 | return; | ||
839 | if (saa7134_boards[dev->board].mpeg != ops->type) | ||
840 | return; | ||
841 | err = ops->init(dev); | ||
842 | if (0 != err) | ||
843 | return; | ||
844 | dev->mops = ops; | ||
845 | } | ||
846 | |||
847 | static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops, | ||
848 | struct saa7134_dev *dev) | ||
849 | { | ||
850 | if (NULL == dev->mops) | ||
851 | return; | ||
852 | if (dev->mops != ops) | ||
853 | return; | ||
854 | dev->mops->fini(dev); | ||
855 | dev->mops = NULL; | ||
856 | } | ||
857 | |||
858 | static int __devinit saa7134_initdev(struct pci_dev *pci_dev, | ||
859 | const struct pci_device_id *pci_id) | ||
860 | { | ||
861 | struct saa7134_dev *dev; | ||
862 | struct list_head *item; | ||
863 | struct saa7134_mpeg_ops *mops; | ||
864 | int err; | ||
865 | |||
866 | dev = kmalloc(sizeof(*dev),GFP_KERNEL); | ||
867 | if (NULL == dev) | ||
868 | return -ENOMEM; | ||
869 | memset(dev,0,sizeof(*dev)); | ||
870 | |||
871 | /* pci init */ | ||
872 | dev->pci = pci_dev; | ||
873 | if (pci_enable_device(pci_dev)) { | ||
874 | err = -EIO; | ||
875 | goto fail1; | ||
876 | } | ||
877 | |||
878 | dev->nr = saa7134_devcount; | ||
879 | sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr); | ||
880 | |||
881 | /* pci quirks */ | ||
882 | if (pci_pci_problems) { | ||
883 | if (pci_pci_problems & PCIPCI_TRITON) | ||
884 | printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name); | ||
885 | if (pci_pci_problems & PCIPCI_NATOMA) | ||
886 | printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name); | ||
887 | if (pci_pci_problems & PCIPCI_VIAETBF) | ||
888 | printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name); | ||
889 | if (pci_pci_problems & PCIPCI_VSFX) | ||
890 | printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name); | ||
891 | #ifdef PCIPCI_ALIMAGIK | ||
892 | if (pci_pci_problems & PCIPCI_ALIMAGIK) { | ||
893 | printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", | ||
894 | dev->name); | ||
895 | latency = 0x0A; | ||
896 | } | ||
897 | #endif | ||
898 | } | ||
899 | if (UNSET != latency) { | ||
900 | printk(KERN_INFO "%s: setting pci latency timer to %d\n", | ||
901 | dev->name,latency); | ||
902 | pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); | ||
903 | } | ||
904 | |||
905 | /* print pci info */ | ||
906 | pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); | ||
907 | pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); | ||
908 | printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " | ||
909 | "latency: %d, mmio: 0x%lx\n", dev->name, | ||
910 | pci_name(pci_dev), dev->pci_rev, pci_dev->irq, | ||
911 | dev->pci_lat,pci_resource_start(pci_dev,0)); | ||
912 | pci_set_master(pci_dev); | ||
913 | if (!pci_dma_supported(pci_dev,0xffffffff)) { | ||
914 | printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); | ||
915 | err = -EIO; | ||
916 | goto fail1; | ||
917 | } | ||
918 | |||
919 | /* board config */ | ||
920 | dev->board = pci_id->driver_data; | ||
921 | if (card[dev->nr] >= 0 && | ||
922 | card[dev->nr] < saa7134_bcount) | ||
923 | dev->board = card[dev->nr]; | ||
924 | if (SAA7134_BOARD_NOAUTO == dev->board) { | ||
925 | must_configure_manually(); | ||
926 | dev->board = SAA7134_BOARD_UNKNOWN; | ||
927 | } | ||
928 | dev->tuner_type = saa7134_boards[dev->board].tuner_type; | ||
929 | dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; | ||
930 | if (UNSET != tuner[dev->nr]) | ||
931 | dev->tuner_type = tuner[dev->nr]; | ||
932 | printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", | ||
933 | dev->name,pci_dev->subsystem_vendor, | ||
934 | pci_dev->subsystem_device,saa7134_boards[dev->board].name, | ||
935 | dev->board, card[dev->nr] == dev->board ? | ||
936 | "insmod option" : "autodetected"); | ||
937 | |||
938 | /* get mmio */ | ||
939 | if (!request_mem_region(pci_resource_start(pci_dev,0), | ||
940 | pci_resource_len(pci_dev,0), | ||
941 | dev->name)) { | ||
942 | err = -EBUSY; | ||
943 | printk(KERN_ERR "%s: can't get MMIO memory @ 0x%lx\n", | ||
944 | dev->name,pci_resource_start(pci_dev,0)); | ||
945 | goto fail1; | ||
946 | } | ||
947 | dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000); | ||
948 | dev->bmmio = (__u8 __iomem *)dev->lmmio; | ||
949 | if (NULL == dev->lmmio) { | ||
950 | err = -EIO; | ||
951 | printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", | ||
952 | dev->name); | ||
953 | goto fail2; | ||
954 | } | ||
955 | |||
956 | /* initialize hardware #1 */ | ||
957 | dev->irq2_mask = | ||
958 | SAA7134_IRQ2_INTE_DEC3 | | ||
959 | SAA7134_IRQ2_INTE_DEC2 | | ||
960 | SAA7134_IRQ2_INTE_DEC1 | | ||
961 | SAA7134_IRQ2_INTE_DEC0 | | ||
962 | SAA7134_IRQ2_INTE_PE | | ||
963 | SAA7134_IRQ2_INTE_AR; | ||
964 | saa7134_board_init1(dev); | ||
965 | saa7134_hwinit1(dev); | ||
966 | |||
967 | /* get irq */ | ||
968 | err = request_irq(pci_dev->irq, saa7134_irq, | ||
969 | SA_SHIRQ | SA_INTERRUPT, dev->name, dev); | ||
970 | if (err < 0) { | ||
971 | printk(KERN_ERR "%s: can't get IRQ %d\n", | ||
972 | dev->name,pci_dev->irq); | ||
973 | goto fail3; | ||
974 | } | ||
975 | |||
976 | /* wait a bit, register i2c bus */ | ||
977 | msleep(100); | ||
978 | saa7134_i2c_register(dev); | ||
979 | |||
980 | /* initialize hardware #2 */ | ||
981 | saa7134_board_init2(dev); | ||
982 | saa7134_hwinit2(dev); | ||
983 | |||
984 | /* load i2c helpers */ | ||
985 | if (TUNER_ABSENT != dev->tuner_type) | ||
986 | request_module("tuner"); | ||
987 | if (dev->tda9887_conf) | ||
988 | request_module("tda9887"); | ||
989 | if (card_is_empress(dev)) { | ||
990 | request_module("saa6752hs"); | ||
991 | request_module_depend("saa7134-empress",&need_empress); | ||
992 | } | ||
993 | if (card_is_dvb(dev)) | ||
994 | request_module_depend("saa7134-dvb",&need_dvb); | ||
995 | |||
996 | v4l2_prio_init(&dev->prio); | ||
997 | |||
998 | /* register v4l devices */ | ||
999 | dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); | ||
1000 | err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, | ||
1001 | video_nr[dev->nr]); | ||
1002 | if (err < 0) { | ||
1003 | printk(KERN_INFO "%s: can't register video device\n", | ||
1004 | dev->name); | ||
1005 | goto fail4; | ||
1006 | } | ||
1007 | printk(KERN_INFO "%s: registered device video%d [v4l2]\n", | ||
1008 | dev->name,dev->video_dev->minor & 0x1f); | ||
1009 | |||
1010 | dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi"); | ||
1011 | err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, | ||
1012 | vbi_nr[dev->nr]); | ||
1013 | if (err < 0) | ||
1014 | goto fail4; | ||
1015 | printk(KERN_INFO "%s: registered device vbi%d\n", | ||
1016 | dev->name,dev->vbi_dev->minor & 0x1f); | ||
1017 | |||
1018 | if (card_has_radio(dev)) { | ||
1019 | dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); | ||
1020 | err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, | ||
1021 | radio_nr[dev->nr]); | ||
1022 | if (err < 0) | ||
1023 | goto fail4; | ||
1024 | printk(KERN_INFO "%s: registered device radio%d\n", | ||
1025 | dev->name,dev->radio_dev->minor & 0x1f); | ||
1026 | } | ||
1027 | |||
1028 | /* register oss devices */ | ||
1029 | switch (dev->pci->device) { | ||
1030 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
1031 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
1032 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
1033 | if (oss) { | ||
1034 | err = dev->oss.minor_dsp = | ||
1035 | register_sound_dsp(&saa7134_dsp_fops, | ||
1036 | dsp_nr[dev->nr]); | ||
1037 | if (err < 0) { | ||
1038 | goto fail4; | ||
1039 | } | ||
1040 | printk(KERN_INFO "%s: registered device dsp%d\n", | ||
1041 | dev->name,dev->oss.minor_dsp >> 4); | ||
1042 | |||
1043 | err = dev->oss.minor_mixer = | ||
1044 | register_sound_mixer(&saa7134_mixer_fops, | ||
1045 | mixer_nr[dev->nr]); | ||
1046 | if (err < 0) | ||
1047 | goto fail5; | ||
1048 | printk(KERN_INFO "%s: registered device mixer%d\n", | ||
1049 | dev->name,dev->oss.minor_mixer >> 4); | ||
1050 | } | ||
1051 | break; | ||
1052 | } | ||
1053 | |||
1054 | /* everything worked */ | ||
1055 | pci_set_drvdata(pci_dev,dev); | ||
1056 | saa7134_devcount++; | ||
1057 | |||
1058 | down(&devlist_lock); | ||
1059 | list_for_each(item,&mops_list) { | ||
1060 | mops = list_entry(item, struct saa7134_mpeg_ops, next); | ||
1061 | mpeg_ops_attach(mops, dev); | ||
1062 | } | ||
1063 | list_add_tail(&dev->devlist,&saa7134_devlist); | ||
1064 | up(&devlist_lock); | ||
1065 | |||
1066 | /* check for signal */ | ||
1067 | saa7134_irq_video_intl(dev); | ||
1068 | return 0; | ||
1069 | |||
1070 | fail5: | ||
1071 | switch (dev->pci->device) { | ||
1072 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
1073 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
1074 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
1075 | if (oss) | ||
1076 | unregister_sound_dsp(dev->oss.minor_dsp); | ||
1077 | break; | ||
1078 | } | ||
1079 | fail4: | ||
1080 | saa7134_unregister_video(dev); | ||
1081 | saa7134_i2c_unregister(dev); | ||
1082 | free_irq(pci_dev->irq, dev); | ||
1083 | fail3: | ||
1084 | saa7134_hwfini(dev); | ||
1085 | iounmap(dev->lmmio); | ||
1086 | fail2: | ||
1087 | release_mem_region(pci_resource_start(pci_dev,0), | ||
1088 | pci_resource_len(pci_dev,0)); | ||
1089 | fail1: | ||
1090 | kfree(dev); | ||
1091 | return err; | ||
1092 | } | ||
1093 | |||
1094 | static void __devexit saa7134_finidev(struct pci_dev *pci_dev) | ||
1095 | { | ||
1096 | struct saa7134_dev *dev = pci_get_drvdata(pci_dev); | ||
1097 | struct list_head *item; | ||
1098 | struct saa7134_mpeg_ops *mops; | ||
1099 | |||
1100 | /* debugging ... */ | ||
1101 | if (irq_debug) { | ||
1102 | u32 report = saa_readl(SAA7134_IRQ_REPORT); | ||
1103 | u32 status = saa_readl(SAA7134_IRQ_STATUS); | ||
1104 | print_irqstatus(dev,42,report,status); | ||
1105 | } | ||
1106 | |||
1107 | /* disable peripheral devices */ | ||
1108 | saa_writeb(SAA7134_SPECIAL_MODE,0); | ||
1109 | |||
1110 | /* shutdown hardware */ | ||
1111 | saa_writel(SAA7134_IRQ1,0); | ||
1112 | saa_writel(SAA7134_IRQ2,0); | ||
1113 | saa_writel(SAA7134_MAIN_CTRL,0); | ||
1114 | |||
1115 | /* shutdown subsystems */ | ||
1116 | saa7134_hwfini(dev); | ||
1117 | |||
1118 | /* unregister */ | ||
1119 | down(&devlist_lock); | ||
1120 | list_del(&dev->devlist); | ||
1121 | list_for_each(item,&mops_list) { | ||
1122 | mops = list_entry(item, struct saa7134_mpeg_ops, next); | ||
1123 | mpeg_ops_detach(mops, dev); | ||
1124 | } | ||
1125 | up(&devlist_lock); | ||
1126 | saa7134_devcount--; | ||
1127 | |||
1128 | saa7134_i2c_unregister(dev); | ||
1129 | switch (dev->pci->device) { | ||
1130 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
1131 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
1132 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
1133 | if (oss) { | ||
1134 | unregister_sound_mixer(dev->oss.minor_mixer); | ||
1135 | unregister_sound_dsp(dev->oss.minor_dsp); | ||
1136 | } | ||
1137 | break; | ||
1138 | } | ||
1139 | saa7134_unregister_video(dev); | ||
1140 | |||
1141 | /* release ressources */ | ||
1142 | free_irq(pci_dev->irq, dev); | ||
1143 | iounmap(dev->lmmio); | ||
1144 | release_mem_region(pci_resource_start(pci_dev,0), | ||
1145 | pci_resource_len(pci_dev,0)); | ||
1146 | |||
1147 | #if 0 /* causes some trouble when reinserting the driver ... */ | ||
1148 | pci_disable_device(pci_dev); | ||
1149 | #endif | ||
1150 | pci_set_drvdata(pci_dev, NULL); | ||
1151 | |||
1152 | /* free memory */ | ||
1153 | kfree(dev); | ||
1154 | } | ||
1155 | |||
1156 | /* ----------------------------------------------------------- */ | ||
1157 | |||
1158 | int saa7134_ts_register(struct saa7134_mpeg_ops *ops) | ||
1159 | { | ||
1160 | struct list_head *item; | ||
1161 | struct saa7134_dev *dev; | ||
1162 | |||
1163 | down(&devlist_lock); | ||
1164 | list_for_each(item,&saa7134_devlist) { | ||
1165 | dev = list_entry(item, struct saa7134_dev, devlist); | ||
1166 | mpeg_ops_attach(ops, dev); | ||
1167 | } | ||
1168 | list_add_tail(&ops->next,&mops_list); | ||
1169 | up(&devlist_lock); | ||
1170 | return 0; | ||
1171 | } | ||
1172 | |||
1173 | void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) | ||
1174 | { | ||
1175 | struct list_head *item; | ||
1176 | struct saa7134_dev *dev; | ||
1177 | |||
1178 | down(&devlist_lock); | ||
1179 | list_del(&ops->next); | ||
1180 | list_for_each(item,&saa7134_devlist) { | ||
1181 | dev = list_entry(item, struct saa7134_dev, devlist); | ||
1182 | mpeg_ops_detach(ops, dev); | ||
1183 | } | ||
1184 | up(&devlist_lock); | ||
1185 | } | ||
1186 | |||
1187 | EXPORT_SYMBOL(saa7134_ts_register); | ||
1188 | EXPORT_SYMBOL(saa7134_ts_unregister); | ||
1189 | |||
1190 | /* ----------------------------------------------------------- */ | ||
1191 | |||
1192 | static struct pci_driver saa7134_pci_driver = { | ||
1193 | .name = "saa7134", | ||
1194 | .id_table = saa7134_pci_tbl, | ||
1195 | .probe = saa7134_initdev, | ||
1196 | .remove = __devexit_p(saa7134_finidev), | ||
1197 | }; | ||
1198 | |||
1199 | static int saa7134_init(void) | ||
1200 | { | ||
1201 | INIT_LIST_HEAD(&saa7134_devlist); | ||
1202 | printk(KERN_INFO "saa7130/34: v4l2 driver version %d.%d.%d loaded\n", | ||
1203 | (SAA7134_VERSION_CODE >> 16) & 0xff, | ||
1204 | (SAA7134_VERSION_CODE >> 8) & 0xff, | ||
1205 | SAA7134_VERSION_CODE & 0xff); | ||
1206 | #ifdef SNAPSHOT | ||
1207 | printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n", | ||
1208 | SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); | ||
1209 | #endif | ||
1210 | return pci_module_init(&saa7134_pci_driver); | ||
1211 | } | ||
1212 | |||
1213 | static void saa7134_fini(void) | ||
1214 | { | ||
1215 | #ifdef CONFIG_MODULES | ||
1216 | if (pending_registered) | ||
1217 | unregister_module_notifier(&pending_notifier); | ||
1218 | #endif | ||
1219 | pci_unregister_driver(&saa7134_pci_driver); | ||
1220 | } | ||
1221 | |||
1222 | module_init(saa7134_init); | ||
1223 | module_exit(saa7134_fini); | ||
1224 | |||
1225 | /* ----------------------------------------------------------- */ | ||
1226 | |||
1227 | EXPORT_SYMBOL(saa7134_print_ioctl); | ||
1228 | EXPORT_SYMBOL(saa7134_i2c_call_clients); | ||
1229 | EXPORT_SYMBOL(saa7134_devlist); | ||
1230 | EXPORT_SYMBOL(saa7134_boards); | ||
1231 | |||
1232 | /* ----------------------------------------------------------- */ | ||
1233 | /* | ||
1234 | * Local variables: | ||
1235 | * c-basic-offset: 8 | ||
1236 | * End: | ||
1237 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c new file mode 100644 index 000000000000..dd4a6c8ee65f --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-dvb.c | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-dvb.c,v 1.12 2005/02/18 12:28:29 kraxel Exp $ | ||
3 | * | ||
4 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/kthread.h> | ||
28 | #include <linux/suspend.h> | ||
29 | |||
30 | #include "saa7134-reg.h" | ||
31 | #include "saa7134.h" | ||
32 | |||
33 | #include "dvb-pll.h" | ||
34 | #include "mt352.h" | ||
35 | #include "mt352_priv.h" /* FIXME */ | ||
36 | #include "tda1004x.h" | ||
37 | |||
38 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
39 | MODULE_LICENSE("GPL"); | ||
40 | |||
41 | static unsigned int antenna_pwr = 0; | ||
42 | module_param(antenna_pwr, int, 0444); | ||
43 | MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)"); | ||
44 | |||
45 | /* ------------------------------------------------------------------ */ | ||
46 | |||
47 | static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on) | ||
48 | { | ||
49 | u32 ok; | ||
50 | |||
51 | if (!on) { | ||
52 | saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26)); | ||
53 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 26)); | ||
58 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); | ||
59 | udelay(10); | ||
60 | |||
61 | saa_setl(SAA7134_GPIO_GPMODE0 >> 2, (1 << 28)); | ||
62 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); | ||
63 | udelay(10); | ||
64 | saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28)); | ||
65 | udelay(10); | ||
66 | ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27); | ||
67 | printk("%s: %s %s\n", dev->name, __FUNCTION__, | ||
68 | ok ? "on" : "off"); | ||
69 | |||
70 | if (!ok) | ||
71 | saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26)); | ||
72 | return ok; | ||
73 | } | ||
74 | |||
75 | static int mt352_pinnacle_init(struct dvb_frontend* fe) | ||
76 | { | ||
77 | static u8 clock_config [] = { CLOCK_CTL, 0x3d, 0x28 }; | ||
78 | static u8 reset [] = { RESET, 0x80 }; | ||
79 | static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; | ||
80 | static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 }; | ||
81 | static u8 capt_range_cfg[] = { CAPT_RANGE, 0x31 }; | ||
82 | static u8 fsm_ctl_cfg[] = { 0x7b, 0x04 }; | ||
83 | static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x0f }; | ||
84 | static u8 scan_ctl_cfg [] = { SCAN_CTL, 0x0d }; | ||
85 | static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 }; | ||
86 | struct saa7134_dev *dev= fe->dvb->priv; | ||
87 | |||
88 | printk("%s: %s called\n",dev->name,__FUNCTION__); | ||
89 | |||
90 | mt352_write(fe, clock_config, sizeof(clock_config)); | ||
91 | udelay(200); | ||
92 | mt352_write(fe, reset, sizeof(reset)); | ||
93 | mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); | ||
94 | mt352_write(fe, agc_cfg, sizeof(agc_cfg)); | ||
95 | mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); | ||
96 | mt352_write(fe, gpp_ctl_cfg, sizeof(gpp_ctl_cfg)); | ||
97 | |||
98 | mt352_write(fe, fsm_ctl_cfg, sizeof(fsm_ctl_cfg)); | ||
99 | mt352_write(fe, scan_ctl_cfg, sizeof(scan_ctl_cfg)); | ||
100 | mt352_write(fe, irq_cfg, sizeof(irq_cfg)); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int mt352_pinnacle_pll_set(struct dvb_frontend* fe, | ||
105 | struct dvb_frontend_parameters* params, | ||
106 | u8* pllbuf) | ||
107 | { | ||
108 | static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; | ||
109 | static int off = TDA9887_PRESENT | TDA9887_PORT2_ACTIVE; | ||
110 | struct saa7134_dev *dev = fe->dvb->priv; | ||
111 | struct v4l2_frequency f; | ||
112 | |||
113 | /* set frequency (mt2050) */ | ||
114 | f.tuner = 0; | ||
115 | f.type = V4L2_TUNER_DIGITAL_TV; | ||
116 | f.frequency = params->frequency / 1000 * 16 / 1000; | ||
117 | saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); | ||
118 | saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); | ||
119 | saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&off); | ||
120 | |||
121 | pinnacle_antenna_pwr(dev, antenna_pwr); | ||
122 | |||
123 | /* mt352 setup */ | ||
124 | mt352_pinnacle_init(fe); | ||
125 | pllbuf[0] = 0xc2; | ||
126 | pllbuf[1] = 0x00; | ||
127 | pllbuf[2] = 0x00; | ||
128 | pllbuf[3] = 0x80; | ||
129 | pllbuf[4] = 0x00; | ||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static struct mt352_config pinnacle_300i = { | ||
134 | .demod_address = 0x3c >> 1, | ||
135 | .adc_clock = 20333, | ||
136 | .if2 = 36150, | ||
137 | .no_tuner = 1, | ||
138 | .demod_init = mt352_pinnacle_init, | ||
139 | .pll_set = mt352_pinnacle_pll_set, | ||
140 | }; | ||
141 | |||
142 | /* ------------------------------------------------------------------ */ | ||
143 | |||
144 | static int medion_cardbus_init(struct dvb_frontend* fe) | ||
145 | { | ||
146 | /* anything to do here ??? */ | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int medion_cardbus_pll_set(struct dvb_frontend* fe, | ||
151 | struct dvb_frontend_parameters* params) | ||
152 | { | ||
153 | struct saa7134_dev *dev = fe->dvb->priv; | ||
154 | struct v4l2_frequency f; | ||
155 | |||
156 | /* | ||
157 | * this instructs tuner.o to set the frequency, the call will | ||
158 | * end up in tuner_command(), VIDIOC_S_FREQUENCY switch. | ||
159 | * tda9887.o will see that as well. | ||
160 | */ | ||
161 | f.tuner = 0; | ||
162 | f.type = V4L2_TUNER_DIGITAL_TV; | ||
163 | f.frequency = params->frequency / 1000 * 16 / 1000; | ||
164 | saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f); | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int fe_request_firmware(struct dvb_frontend* fe, | ||
169 | const struct firmware **fw, char* name) | ||
170 | { | ||
171 | struct saa7134_dev *dev = fe->dvb->priv; | ||
172 | return request_firmware(fw, name, &dev->pci->dev); | ||
173 | } | ||
174 | |||
175 | struct tda1004x_config medion_cardbus = { | ||
176 | .demod_address = 0x08, /* not sure this is correct */ | ||
177 | .invert = 0, | ||
178 | .invert_oclk = 0, | ||
179 | .pll_init = medion_cardbus_init, | ||
180 | .pll_set = medion_cardbus_pll_set, | ||
181 | .request_firmware = fe_request_firmware, | ||
182 | }; | ||
183 | |||
184 | /* ------------------------------------------------------------------ */ | ||
185 | |||
186 | static int dvb_init(struct saa7134_dev *dev) | ||
187 | { | ||
188 | /* init struct videobuf_dvb */ | ||
189 | dev->ts.nr_bufs = 32; | ||
190 | dev->ts.nr_packets = 32*4; | ||
191 | dev->dvb.name = dev->name; | ||
192 | videobuf_queue_init(&dev->dvb.dvbq, &saa7134_ts_qops, | ||
193 | dev->pci, &dev->slock, | ||
194 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
195 | V4L2_FIELD_ALTERNATE, | ||
196 | sizeof(struct saa7134_buf), | ||
197 | dev); | ||
198 | |||
199 | switch (dev->board) { | ||
200 | case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: | ||
201 | printk("%s: pinnacle 300i dvb setup\n",dev->name); | ||
202 | dev->dvb.frontend = mt352_attach(&pinnacle_300i, | ||
203 | &dev->i2c_adap); | ||
204 | break; | ||
205 | case SAA7134_BOARD_MD7134: | ||
206 | dev->dvb.frontend = tda10046_attach(&medion_cardbus, | ||
207 | &dev->i2c_adap); | ||
208 | if (NULL == dev->dvb.frontend) | ||
209 | printk("%s: Hmm, looks like this is the old MD7134 " | ||
210 | "version without DVB-T support\n",dev->name); | ||
211 | break; | ||
212 | default: | ||
213 | printk("%s: Huh? unknown DVB card?\n",dev->name); | ||
214 | break; | ||
215 | } | ||
216 | |||
217 | if (NULL == dev->dvb.frontend) { | ||
218 | printk("%s: frontend initialization failed\n",dev->name); | ||
219 | return -1; | ||
220 | } | ||
221 | |||
222 | /* register everything else */ | ||
223 | return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev); | ||
224 | } | ||
225 | |||
226 | static int dvb_fini(struct saa7134_dev *dev) | ||
227 | { | ||
228 | static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE; | ||
229 | |||
230 | printk("%s: %s\n",dev->name,__FUNCTION__); | ||
231 | |||
232 | switch (dev->board) { | ||
233 | case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL: | ||
234 | /* otherwise we don't detect the tuner on next insmod */ | ||
235 | saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&on); | ||
236 | break; | ||
237 | }; | ||
238 | videobuf_dvb_unregister(&dev->dvb); | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static struct saa7134_mpeg_ops dvb_ops = { | ||
243 | .type = SAA7134_MPEG_DVB, | ||
244 | .init = dvb_init, | ||
245 | .fini = dvb_fini, | ||
246 | }; | ||
247 | |||
248 | static int __init dvb_register(void) | ||
249 | { | ||
250 | return saa7134_ts_register(&dvb_ops); | ||
251 | } | ||
252 | |||
253 | static void __exit dvb_unregister(void) | ||
254 | { | ||
255 | saa7134_ts_unregister(&dvb_ops); | ||
256 | } | ||
257 | |||
258 | module_init(dvb_register); | ||
259 | module_exit(dvb_unregister); | ||
260 | |||
261 | /* ------------------------------------------------------------------ */ | ||
262 | /* | ||
263 | * Local variables: | ||
264 | * c-basic-offset: 8 | ||
265 | * End: | ||
266 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c new file mode 100644 index 000000000000..2021e099e35a --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-empress.c | |||
@@ -0,0 +1,436 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-empress.c,v 1.10 2005/02/03 10:24:33 kraxel Exp $ | ||
3 | * | ||
4 | * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/moduleparam.h> | ||
25 | #include <linux/kernel.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include "saa7134-reg.h" | ||
30 | #include "saa7134.h" | ||
31 | |||
32 | #include <media/saa6752hs.h> | ||
33 | |||
34 | /* ------------------------------------------------------------------ */ | ||
35 | |||
36 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | |||
39 | static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | ||
40 | module_param_array(empress_nr, int, NULL, 0444); | ||
41 | MODULE_PARM_DESC(empress_nr,"ts device number"); | ||
42 | |||
43 | static unsigned int debug = 0; | ||
44 | module_param(debug, int, 0644); | ||
45 | MODULE_PARM_DESC(debug,"enable debug messages"); | ||
46 | |||
47 | #define dprintk(fmt, arg...) if (debug) \ | ||
48 | printk(KERN_DEBUG "%s/empress: " fmt, dev->name , ## arg) | ||
49 | |||
50 | /* ------------------------------------------------------------------ */ | ||
51 | |||
52 | static void ts_reset_encoder(struct saa7134_dev* dev) | ||
53 | { | ||
54 | if (!dev->empress_started) | ||
55 | return; | ||
56 | |||
57 | saa_writeb(SAA7134_SPECIAL_MODE, 0x00); | ||
58 | msleep(10); | ||
59 | saa_writeb(SAA7134_SPECIAL_MODE, 0x01); | ||
60 | msleep(100); | ||
61 | dev->empress_started = 0; | ||
62 | } | ||
63 | |||
64 | static int ts_init_encoder(struct saa7134_dev* dev) | ||
65 | { | ||
66 | ts_reset_encoder(dev); | ||
67 | saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, NULL); | ||
68 | dev->empress_started = 1; | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | /* ------------------------------------------------------------------ */ | ||
73 | |||
74 | static int ts_open(struct inode *inode, struct file *file) | ||
75 | { | ||
76 | int minor = iminor(inode); | ||
77 | struct saa7134_dev *h,*dev = NULL; | ||
78 | struct list_head *list; | ||
79 | int err; | ||
80 | |||
81 | list_for_each(list,&saa7134_devlist) { | ||
82 | h = list_entry(list, struct saa7134_dev, devlist); | ||
83 | if (h->empress_dev && h->empress_dev->minor == minor) | ||
84 | dev = h; | ||
85 | } | ||
86 | if (NULL == dev) | ||
87 | return -ENODEV; | ||
88 | |||
89 | dprintk("open minor=%d\n",minor); | ||
90 | err = -EBUSY; | ||
91 | if (down_trylock(&dev->empress_tsq.lock)) | ||
92 | goto done; | ||
93 | if (dev->empress_users) | ||
94 | goto done_up; | ||
95 | |||
96 | dev->empress_users++; | ||
97 | file->private_data = dev; | ||
98 | err = 0; | ||
99 | |||
100 | done_up: | ||
101 | up(&dev->empress_tsq.lock); | ||
102 | done: | ||
103 | return err; | ||
104 | } | ||
105 | |||
106 | static int ts_release(struct inode *inode, struct file *file) | ||
107 | { | ||
108 | struct saa7134_dev *dev = file->private_data; | ||
109 | |||
110 | if (dev->empress_tsq.streaming) | ||
111 | videobuf_streamoff(&dev->empress_tsq); | ||
112 | down(&dev->empress_tsq.lock); | ||
113 | if (dev->empress_tsq.reading) | ||
114 | videobuf_read_stop(&dev->empress_tsq); | ||
115 | videobuf_mmap_free(&dev->empress_tsq); | ||
116 | dev->empress_users--; | ||
117 | |||
118 | /* stop the encoder */ | ||
119 | ts_reset_encoder(dev); | ||
120 | |||
121 | up(&dev->empress_tsq.lock); | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | static ssize_t | ||
126 | ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
127 | { | ||
128 | struct saa7134_dev *dev = file->private_data; | ||
129 | |||
130 | if (!dev->empress_started) | ||
131 | ts_init_encoder(dev); | ||
132 | |||
133 | return videobuf_read_stream(&dev->empress_tsq, | ||
134 | data, count, ppos, 0, | ||
135 | file->f_flags & O_NONBLOCK); | ||
136 | } | ||
137 | |||
138 | static unsigned int | ||
139 | ts_poll(struct file *file, struct poll_table_struct *wait) | ||
140 | { | ||
141 | struct saa7134_dev *dev = file->private_data; | ||
142 | |||
143 | return videobuf_poll_stream(file, &dev->empress_tsq, wait); | ||
144 | } | ||
145 | |||
146 | |||
147 | static int | ||
148 | ts_mmap(struct file *file, struct vm_area_struct * vma) | ||
149 | { | ||
150 | struct saa7134_dev *dev = file->private_data; | ||
151 | |||
152 | return videobuf_mmap_mapper(&dev->empress_tsq, vma); | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * This function is _not_ called directly, but from | ||
157 | * video_generic_ioctl (and maybe others). userspace | ||
158 | * copying is done already, arg is a kernel pointer. | ||
159 | */ | ||
160 | static int ts_do_ioctl(struct inode *inode, struct file *file, | ||
161 | unsigned int cmd, void *arg) | ||
162 | { | ||
163 | struct saa7134_dev *dev = file->private_data; | ||
164 | |||
165 | if (debug > 1) | ||
166 | saa7134_print_ioctl(dev->name,cmd); | ||
167 | switch (cmd) { | ||
168 | case VIDIOC_QUERYCAP: | ||
169 | { | ||
170 | struct v4l2_capability *cap = arg; | ||
171 | |||
172 | memset(cap,0,sizeof(*cap)); | ||
173 | strcpy(cap->driver, "saa7134"); | ||
174 | strlcpy(cap->card, saa7134_boards[dev->board].name, | ||
175 | sizeof(cap->card)); | ||
176 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | ||
177 | cap->version = SAA7134_VERSION_CODE; | ||
178 | cap->capabilities = | ||
179 | V4L2_CAP_VIDEO_CAPTURE | | ||
180 | V4L2_CAP_READWRITE | | ||
181 | V4L2_CAP_STREAMING; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /* --- input switching --------------------------------------- */ | ||
186 | case VIDIOC_ENUMINPUT: | ||
187 | { | ||
188 | struct v4l2_input *i = arg; | ||
189 | |||
190 | if (i->index != 0) | ||
191 | return -EINVAL; | ||
192 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
193 | strcpy(i->name,"CCIR656"); | ||
194 | return 0; | ||
195 | } | ||
196 | case VIDIOC_G_INPUT: | ||
197 | { | ||
198 | int *i = arg; | ||
199 | *i = 0; | ||
200 | return 0; | ||
201 | } | ||
202 | case VIDIOC_S_INPUT: | ||
203 | { | ||
204 | int *i = arg; | ||
205 | |||
206 | if (*i != 0) | ||
207 | return -EINVAL; | ||
208 | return 0; | ||
209 | } | ||
210 | /* --- capture ioctls ---------------------------------------- */ | ||
211 | |||
212 | case VIDIOC_ENUM_FMT: | ||
213 | { | ||
214 | struct v4l2_fmtdesc *f = arg; | ||
215 | int index; | ||
216 | |||
217 | index = f->index; | ||
218 | if (index != 0) | ||
219 | return -EINVAL; | ||
220 | |||
221 | memset(f,0,sizeof(*f)); | ||
222 | f->index = index; | ||
223 | strlcpy(f->description, "MPEG TS", sizeof(f->description)); | ||
224 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
225 | f->pixelformat = V4L2_PIX_FMT_MPEG; | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | case VIDIOC_G_FMT: | ||
230 | { | ||
231 | struct v4l2_format *f = arg; | ||
232 | |||
233 | memset(f,0,sizeof(*f)); | ||
234 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
235 | |||
236 | /* FIXME: translate subsampling type EMPRESS into | ||
237 | * width/height: */ | ||
238 | f->fmt.pix.width = 720; /* D1 */ | ||
239 | f->fmt.pix.height = 576; | ||
240 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
241 | f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets; | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | case VIDIOC_S_FMT: | ||
246 | { | ||
247 | struct v4l2_format *f = arg; | ||
248 | |||
249 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
250 | return -EINVAL; | ||
251 | |||
252 | /* | ||
253 | FIXME: translate and round width/height into EMPRESS | ||
254 | subsample type: | ||
255 | |||
256 | type | PAL | NTSC | ||
257 | --------------------------- | ||
258 | SIF | 352x288 | 352x240 | ||
259 | 1/2 D1 | 352x576 | 352x480 | ||
260 | 2/3 D1 | 480x576 | 480x480 | ||
261 | D1 | 720x576 | 720x480 | ||
262 | */ | ||
263 | |||
264 | f->fmt.pix.width = 720; /* D1 */ | ||
265 | f->fmt.pix.height = 576; | ||
266 | f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; | ||
267 | f->fmt.pix.sizeimage = TS_PACKET_SIZE* dev->ts.nr_packets; | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | case VIDIOC_REQBUFS: | ||
272 | return videobuf_reqbufs(&dev->empress_tsq,arg); | ||
273 | |||
274 | case VIDIOC_QUERYBUF: | ||
275 | return videobuf_querybuf(&dev->empress_tsq,arg); | ||
276 | |||
277 | case VIDIOC_QBUF: | ||
278 | return videobuf_qbuf(&dev->empress_tsq,arg); | ||
279 | |||
280 | case VIDIOC_DQBUF: | ||
281 | return videobuf_dqbuf(&dev->empress_tsq,arg, | ||
282 | file->f_flags & O_NONBLOCK); | ||
283 | |||
284 | case VIDIOC_STREAMON: | ||
285 | return videobuf_streamon(&dev->empress_tsq); | ||
286 | |||
287 | case VIDIOC_STREAMOFF: | ||
288 | return videobuf_streamoff(&dev->empress_tsq); | ||
289 | |||
290 | case VIDIOC_QUERYCTRL: | ||
291 | case VIDIOC_G_CTRL: | ||
292 | case VIDIOC_S_CTRL: | ||
293 | return saa7134_common_ioctl(dev, cmd, arg); | ||
294 | |||
295 | case VIDIOC_S_MPEGCOMP: | ||
296 | saa7134_i2c_call_clients(dev, VIDIOC_S_MPEGCOMP, arg); | ||
297 | ts_init_encoder(dev); | ||
298 | return 0; | ||
299 | case VIDIOC_G_MPEGCOMP: | ||
300 | saa7134_i2c_call_clients(dev, VIDIOC_G_MPEGCOMP, arg); | ||
301 | return 0; | ||
302 | |||
303 | default: | ||
304 | return -ENOIOCTLCMD; | ||
305 | } | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int ts_ioctl(struct inode *inode, struct file *file, | ||
310 | unsigned int cmd, unsigned long arg) | ||
311 | { | ||
312 | return video_usercopy(inode, file, cmd, arg, ts_do_ioctl); | ||
313 | } | ||
314 | |||
315 | static struct file_operations ts_fops = | ||
316 | { | ||
317 | .owner = THIS_MODULE, | ||
318 | .open = ts_open, | ||
319 | .release = ts_release, | ||
320 | .read = ts_read, | ||
321 | .poll = ts_poll, | ||
322 | .mmap = ts_mmap, | ||
323 | .ioctl = ts_ioctl, | ||
324 | .llseek = no_llseek, | ||
325 | }; | ||
326 | |||
327 | /* ----------------------------------------------------------- */ | ||
328 | |||
329 | static struct video_device saa7134_empress_template = | ||
330 | { | ||
331 | .name = "saa7134-empress", | ||
332 | .type = 0 /* FIXME */, | ||
333 | .type2 = 0 /* FIXME */, | ||
334 | .hardware = 0, | ||
335 | .fops = &ts_fops, | ||
336 | .minor = -1, | ||
337 | }; | ||
338 | |||
339 | static void empress_signal_update(void* data) | ||
340 | { | ||
341 | struct saa7134_dev* dev = (struct saa7134_dev*) data; | ||
342 | |||
343 | if (dev->nosignal) { | ||
344 | dprintk("no video signal\n"); | ||
345 | ts_reset_encoder(dev); | ||
346 | } else { | ||
347 | dprintk("video signal acquired\n"); | ||
348 | if (dev->empress_users) | ||
349 | ts_init_encoder(dev); | ||
350 | } | ||
351 | } | ||
352 | |||
353 | static void empress_signal_change(struct saa7134_dev *dev) | ||
354 | { | ||
355 | schedule_work(&dev->empress_workqueue); | ||
356 | } | ||
357 | |||
358 | |||
359 | static int empress_init(struct saa7134_dev *dev) | ||
360 | { | ||
361 | int err; | ||
362 | |||
363 | dprintk("%s: %s\n",dev->name,__FUNCTION__); | ||
364 | dev->empress_dev = video_device_alloc(); | ||
365 | if (NULL == dev->empress_dev) | ||
366 | return -ENOMEM; | ||
367 | *(dev->empress_dev) = saa7134_empress_template; | ||
368 | dev->empress_dev->dev = &dev->pci->dev; | ||
369 | dev->empress_dev->release = video_device_release; | ||
370 | snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name), | ||
371 | "%s empress (%s)", dev->name, | ||
372 | saa7134_boards[dev->board].name); | ||
373 | |||
374 | INIT_WORK(&dev->empress_workqueue, empress_signal_update, (void*) dev); | ||
375 | |||
376 | err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER, | ||
377 | empress_nr[dev->nr]); | ||
378 | if (err < 0) { | ||
379 | printk(KERN_INFO "%s: can't register video device\n", | ||
380 | dev->name); | ||
381 | video_device_release(dev->empress_dev); | ||
382 | dev->empress_dev = NULL; | ||
383 | return err; | ||
384 | } | ||
385 | printk(KERN_INFO "%s: registered device video%d [mpeg]\n", | ||
386 | dev->name,dev->empress_dev->minor & 0x1f); | ||
387 | |||
388 | videobuf_queue_init(&dev->empress_tsq, &saa7134_ts_qops, | ||
389 | dev->pci, &dev->slock, | ||
390 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
391 | V4L2_FIELD_ALTERNATE, | ||
392 | sizeof(struct saa7134_buf), | ||
393 | dev); | ||
394 | |||
395 | empress_signal_update(dev); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int empress_fini(struct saa7134_dev *dev) | ||
400 | { | ||
401 | dprintk("%s: %s\n",dev->name,__FUNCTION__); | ||
402 | |||
403 | if (NULL == dev->empress_dev) | ||
404 | return 0; | ||
405 | flush_scheduled_work(); | ||
406 | video_unregister_device(dev->empress_dev); | ||
407 | dev->empress_dev = NULL; | ||
408 | return 0; | ||
409 | } | ||
410 | |||
411 | static struct saa7134_mpeg_ops empress_ops = { | ||
412 | .type = SAA7134_MPEG_EMPRESS, | ||
413 | .init = empress_init, | ||
414 | .fini = empress_fini, | ||
415 | .signal_change = empress_signal_change, | ||
416 | }; | ||
417 | |||
418 | static int __init empress_register(void) | ||
419 | { | ||
420 | return saa7134_ts_register(&empress_ops); | ||
421 | } | ||
422 | |||
423 | static void __exit empress_unregister(void) | ||
424 | { | ||
425 | saa7134_ts_unregister(&empress_ops); | ||
426 | } | ||
427 | |||
428 | module_init(empress_register); | ||
429 | module_exit(empress_unregister); | ||
430 | |||
431 | /* ----------------------------------------------------------- */ | ||
432 | /* | ||
433 | * Local variables: | ||
434 | * c-basic-offset: 8 | ||
435 | * End: | ||
436 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c new file mode 100644 index 000000000000..702bb63d9813 --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-i2c.c | |||
@@ -0,0 +1,453 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-i2c.c,v 1.10 2005/01/24 17:37:23 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * i2c interface support | ||
6 | * | ||
7 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include "saa7134-reg.h" | ||
33 | #include "saa7134.h" | ||
34 | |||
35 | /* ----------------------------------------------------------- */ | ||
36 | |||
37 | static unsigned int i2c_debug = 0; | ||
38 | module_param(i2c_debug, int, 0644); | ||
39 | MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); | ||
40 | |||
41 | static unsigned int i2c_scan = 0; | ||
42 | module_param(i2c_scan, int, 0444); | ||
43 | MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); | ||
44 | |||
45 | #define d1printk if (1 == i2c_debug) printk | ||
46 | #define d2printk if (2 == i2c_debug) printk | ||
47 | |||
48 | #define I2C_WAIT_DELAY 32 | ||
49 | #define I2C_WAIT_RETRY 16 | ||
50 | |||
51 | /* ----------------------------------------------------------- */ | ||
52 | |||
53 | static char *str_i2c_status[] = { | ||
54 | "IDLE", "DONE_STOP", "BUSY", "TO_SCL", "TO_ARB", "DONE_WRITE", | ||
55 | "DONE_READ", "DONE_WRITE_TO", "DONE_READ_TO", "NO_DEVICE", | ||
56 | "NO_ACKN", "BUS_ERR", "ARB_LOST", "SEQ_ERR", "ST_ERR", "SW_ERR" | ||
57 | }; | ||
58 | |||
59 | enum i2c_status { | ||
60 | IDLE = 0, // no I2C command pending | ||
61 | DONE_STOP = 1, // I2C command done and STOP executed | ||
62 | BUSY = 2, // executing I2C command | ||
63 | TO_SCL = 3, // executing I2C command, time out on clock stretching | ||
64 | TO_ARB = 4, // time out on arbitration trial, still trying | ||
65 | DONE_WRITE = 5, // I2C command done and awaiting next write command | ||
66 | DONE_READ = 6, // I2C command done and awaiting next read command | ||
67 | DONE_WRITE_TO = 7, // see 5, and time out on status echo | ||
68 | DONE_READ_TO = 8, // see 6, and time out on status echo | ||
69 | NO_DEVICE = 9, // no acknowledge on device slave address | ||
70 | NO_ACKN = 10, // no acknowledge after data byte transfer | ||
71 | BUS_ERR = 11, // bus error | ||
72 | ARB_LOST = 12, // arbitration lost during transfer | ||
73 | SEQ_ERR = 13, // erroneous programming sequence | ||
74 | ST_ERR = 14, // wrong status echoing | ||
75 | SW_ERR = 15 // software error | ||
76 | }; | ||
77 | |||
78 | static char *str_i2c_attr[] = { | ||
79 | "NOP", "STOP", "CONTINUE", "START" | ||
80 | }; | ||
81 | |||
82 | enum i2c_attr { | ||
83 | NOP = 0, // no operation on I2C bus | ||
84 | STOP = 1, // stop condition, no associated byte transfer | ||
85 | CONTINUE = 2, // continue with byte transfer | ||
86 | START = 3 // start condition with byte transfer | ||
87 | }; | ||
88 | |||
89 | static inline enum i2c_status i2c_get_status(struct saa7134_dev *dev) | ||
90 | { | ||
91 | enum i2c_status status; | ||
92 | |||
93 | status = saa_readb(SAA7134_I2C_ATTR_STATUS) & 0x0f; | ||
94 | d2printk(KERN_DEBUG "%s: i2c stat <= %s\n",dev->name, | ||
95 | str_i2c_status[status]); | ||
96 | return status; | ||
97 | } | ||
98 | |||
99 | static inline void i2c_set_status(struct saa7134_dev *dev, | ||
100 | enum i2c_status status) | ||
101 | { | ||
102 | d2printk(KERN_DEBUG "%s: i2c stat => %s\n",dev->name, | ||
103 | str_i2c_status[status]); | ||
104 | saa_andorb(SAA7134_I2C_ATTR_STATUS,0x0f,status); | ||
105 | } | ||
106 | |||
107 | static inline void i2c_set_attr(struct saa7134_dev *dev, enum i2c_attr attr) | ||
108 | { | ||
109 | d2printk(KERN_DEBUG "%s: i2c attr => %s\n",dev->name, | ||
110 | str_i2c_attr[attr]); | ||
111 | saa_andorb(SAA7134_I2C_ATTR_STATUS,0xc0,attr << 6); | ||
112 | } | ||
113 | |||
114 | static inline int i2c_is_error(enum i2c_status status) | ||
115 | { | ||
116 | switch (status) { | ||
117 | case NO_DEVICE: | ||
118 | case NO_ACKN: | ||
119 | case BUS_ERR: | ||
120 | case ARB_LOST: | ||
121 | case SEQ_ERR: | ||
122 | case ST_ERR: | ||
123 | return TRUE; | ||
124 | default: | ||
125 | return FALSE; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static inline int i2c_is_idle(enum i2c_status status) | ||
130 | { | ||
131 | switch (status) { | ||
132 | case IDLE: | ||
133 | case DONE_STOP: | ||
134 | return TRUE; | ||
135 | default: | ||
136 | return FALSE; | ||
137 | } | ||
138 | } | ||
139 | |||
140 | static inline int i2c_is_busy(enum i2c_status status) | ||
141 | { | ||
142 | switch (status) { | ||
143 | case BUSY: | ||
144 | return TRUE; | ||
145 | default: | ||
146 | return FALSE; | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static int i2c_is_busy_wait(struct saa7134_dev *dev) | ||
151 | { | ||
152 | enum i2c_status status; | ||
153 | int count; | ||
154 | |||
155 | for (count = 0; count < I2C_WAIT_RETRY; count++) { | ||
156 | status = i2c_get_status(dev); | ||
157 | if (!i2c_is_busy(status)) | ||
158 | break; | ||
159 | saa_wait(I2C_WAIT_DELAY); | ||
160 | } | ||
161 | if (I2C_WAIT_RETRY == count) | ||
162 | return FALSE; | ||
163 | return TRUE; | ||
164 | } | ||
165 | |||
166 | static int i2c_reset(struct saa7134_dev *dev) | ||
167 | { | ||
168 | enum i2c_status status; | ||
169 | int count; | ||
170 | |||
171 | d2printk(KERN_DEBUG "%s: i2c reset\n",dev->name); | ||
172 | status = i2c_get_status(dev); | ||
173 | if (!i2c_is_error(status)) | ||
174 | return TRUE; | ||
175 | i2c_set_status(dev,status); | ||
176 | |||
177 | for (count = 0; count < I2C_WAIT_RETRY; count++) { | ||
178 | status = i2c_get_status(dev); | ||
179 | if (!i2c_is_error(status)) | ||
180 | break; | ||
181 | udelay(I2C_WAIT_DELAY); | ||
182 | } | ||
183 | if (I2C_WAIT_RETRY == count) | ||
184 | return FALSE; | ||
185 | |||
186 | if (!i2c_is_idle(status)) | ||
187 | return FALSE; | ||
188 | |||
189 | i2c_set_attr(dev,NOP); | ||
190 | return TRUE; | ||
191 | } | ||
192 | |||
193 | static inline int i2c_send_byte(struct saa7134_dev *dev, | ||
194 | enum i2c_attr attr, | ||
195 | unsigned char data) | ||
196 | { | ||
197 | enum i2c_status status; | ||
198 | __u32 dword; | ||
199 | |||
200 | #if 0 | ||
201 | i2c_set_attr(dev,attr); | ||
202 | saa_writeb(SAA7134_I2C_DATA, data); | ||
203 | #else | ||
204 | /* have to write both attr + data in one 32bit word */ | ||
205 | dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2); | ||
206 | dword &= 0x0f; | ||
207 | dword |= (attr << 6); | ||
208 | dword |= ((__u32)data << 8); | ||
209 | dword |= 0x00 << 16; /* 100 kHz */ | ||
210 | // dword |= 0x40 << 16; /* 400 kHz */ | ||
211 | dword |= 0xf0 << 24; | ||
212 | saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword); | ||
213 | #endif | ||
214 | d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data); | ||
215 | |||
216 | if (!i2c_is_busy_wait(dev)) | ||
217 | return -EIO; | ||
218 | status = i2c_get_status(dev); | ||
219 | if (i2c_is_error(status)) | ||
220 | return -EIO; | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static inline int i2c_recv_byte(struct saa7134_dev *dev) | ||
225 | { | ||
226 | enum i2c_status status; | ||
227 | unsigned char data; | ||
228 | |||
229 | i2c_set_attr(dev,CONTINUE); | ||
230 | if (!i2c_is_busy_wait(dev)) | ||
231 | return -EIO; | ||
232 | status = i2c_get_status(dev); | ||
233 | if (i2c_is_error(status)) | ||
234 | return -EIO; | ||
235 | data = saa_readb(SAA7134_I2C_DATA); | ||
236 | d2printk(KERN_DEBUG "%s: i2c data <= 0x%x\n",dev->name,data); | ||
237 | return data; | ||
238 | } | ||
239 | |||
240 | static int saa7134_i2c_xfer(struct i2c_adapter *i2c_adap, | ||
241 | struct i2c_msg *msgs, int num) | ||
242 | { | ||
243 | struct saa7134_dev *dev = i2c_adap->algo_data; | ||
244 | enum i2c_status status; | ||
245 | unsigned char data; | ||
246 | int addr,rc,i,byte; | ||
247 | |||
248 | status = i2c_get_status(dev); | ||
249 | if (!i2c_is_idle(status)) | ||
250 | if (!i2c_reset(dev)) | ||
251 | return -EIO; | ||
252 | |||
253 | d2printk("start xfer\n"); | ||
254 | d1printk(KERN_DEBUG "%s: i2c xfer:",dev->name); | ||
255 | for (i = 0; i < num; i++) { | ||
256 | if (!(msgs[i].flags & I2C_M_NOSTART) || 0 == i) { | ||
257 | /* send address */ | ||
258 | d2printk("send address\n"); | ||
259 | addr = msgs[i].addr << 1; | ||
260 | if (msgs[i].flags & I2C_M_RD) | ||
261 | addr |= 1; | ||
262 | if (i > 0 && msgs[i].flags & I2C_M_RD) { | ||
263 | /* workaround for a saa7134 i2c bug | ||
264 | * needed to talk to the mt352 demux | ||
265 | * thanks to pinnacle for the hint */ | ||
266 | int quirk = 0xfd; | ||
267 | d1printk(" [%02x quirk]",quirk); | ||
268 | i2c_send_byte(dev,START,quirk); | ||
269 | i2c_recv_byte(dev); | ||
270 | } | ||
271 | d1printk(" < %02x", addr); | ||
272 | rc = i2c_send_byte(dev,START,addr); | ||
273 | if (rc < 0) | ||
274 | goto err; | ||
275 | } | ||
276 | if (msgs[i].flags & I2C_M_RD) { | ||
277 | /* read bytes */ | ||
278 | d2printk("read bytes\n"); | ||
279 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
280 | d1printk(" ="); | ||
281 | rc = i2c_recv_byte(dev); | ||
282 | if (rc < 0) | ||
283 | goto err; | ||
284 | d1printk("%02x", rc); | ||
285 | msgs[i].buf[byte] = rc; | ||
286 | } | ||
287 | } else { | ||
288 | /* write bytes */ | ||
289 | d2printk("write bytes\n"); | ||
290 | for (byte = 0; byte < msgs[i].len; byte++) { | ||
291 | data = msgs[i].buf[byte]; | ||
292 | d1printk(" %02x", data); | ||
293 | rc = i2c_send_byte(dev,CONTINUE,data); | ||
294 | if (rc < 0) | ||
295 | goto err; | ||
296 | } | ||
297 | } | ||
298 | } | ||
299 | d2printk("xfer done\n"); | ||
300 | d1printk(" >"); | ||
301 | i2c_set_attr(dev,STOP); | ||
302 | rc = -EIO; | ||
303 | if (!i2c_is_busy_wait(dev)) | ||
304 | goto err; | ||
305 | status = i2c_get_status(dev); | ||
306 | if (i2c_is_error(status)) | ||
307 | goto err; | ||
308 | |||
309 | d1printk("\n"); | ||
310 | return num; | ||
311 | err: | ||
312 | if (1 == i2c_debug) { | ||
313 | status = i2c_get_status(dev); | ||
314 | printk(" ERROR: %s\n",str_i2c_status[status]); | ||
315 | } | ||
316 | return rc; | ||
317 | } | ||
318 | |||
319 | /* ----------------------------------------------------------- */ | ||
320 | |||
321 | static int algo_control(struct i2c_adapter *adapter, | ||
322 | unsigned int cmd, unsigned long arg) | ||
323 | { | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static u32 functionality(struct i2c_adapter *adap) | ||
328 | { | ||
329 | return I2C_FUNC_SMBUS_EMUL; | ||
330 | } | ||
331 | |||
332 | static int attach_inform(struct i2c_client *client) | ||
333 | { | ||
334 | struct saa7134_dev *dev = client->adapter->algo_data; | ||
335 | int tuner = dev->tuner_type; | ||
336 | int conf = dev->tda9887_conf; | ||
337 | |||
338 | saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner); | ||
339 | saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG,&conf); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static struct i2c_algorithm saa7134_algo = { | ||
344 | .name = "saa7134", | ||
345 | .id = I2C_ALGO_SAA7134, | ||
346 | .master_xfer = saa7134_i2c_xfer, | ||
347 | .algo_control = algo_control, | ||
348 | .functionality = functionality, | ||
349 | }; | ||
350 | |||
351 | static struct i2c_adapter saa7134_adap_template = { | ||
352 | .owner = THIS_MODULE, | ||
353 | #ifdef I2C_CLASS_TV_ANALOG | ||
354 | .class = I2C_CLASS_TV_ANALOG, | ||
355 | #endif | ||
356 | I2C_DEVNAME("saa7134"), | ||
357 | .id = I2C_ALGO_SAA7134, | ||
358 | .algo = &saa7134_algo, | ||
359 | .client_register = attach_inform, | ||
360 | }; | ||
361 | |||
362 | static struct i2c_client saa7134_client_template = { | ||
363 | I2C_DEVNAME("saa7134 internal"), | ||
364 | }; | ||
365 | |||
366 | /* ----------------------------------------------------------- */ | ||
367 | |||
368 | static int | ||
369 | saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) | ||
370 | { | ||
371 | unsigned char buf; | ||
372 | int i,err; | ||
373 | |||
374 | dev->i2c_client.addr = 0xa0 >> 1; | ||
375 | buf = 0; | ||
376 | if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { | ||
377 | printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", | ||
378 | dev->name,err); | ||
379 | return -1; | ||
380 | } | ||
381 | if (len != (err = i2c_master_recv(&dev->i2c_client,eedata,len))) { | ||
382 | printk(KERN_WARNING "%s: i2c eeprom read error (err=%d)\n", | ||
383 | dev->name,err); | ||
384 | return -1; | ||
385 | } | ||
386 | for (i = 0; i < len; i++) { | ||
387 | if (0 == (i % 16)) | ||
388 | printk(KERN_INFO "%s: i2c eeprom %02x:",dev->name,i); | ||
389 | printk(" %02x",eedata[i]); | ||
390 | if (15 == (i % 16)) | ||
391 | printk("\n"); | ||
392 | } | ||
393 | return 0; | ||
394 | } | ||
395 | |||
396 | static char *i2c_devs[128] = { | ||
397 | [ 0x20 ] = "mpeg encoder (saa6752hs)", | ||
398 | [ 0xa0 >> 1 ] = "eeprom", | ||
399 | [ 0xc0 >> 1 ] = "tuner (analog)", | ||
400 | [ 0x86 >> 1 ] = "tda9887", | ||
401 | }; | ||
402 | |||
403 | static void do_i2c_scan(char *name, struct i2c_client *c) | ||
404 | { | ||
405 | unsigned char buf; | ||
406 | int i,rc; | ||
407 | |||
408 | for (i = 0; i < 128; i++) { | ||
409 | c->addr = i; | ||
410 | rc = i2c_master_recv(c,&buf,0); | ||
411 | if (rc < 0) | ||
412 | continue; | ||
413 | printk("%s: i2c scan: found device @ 0x%x [%s]\n", | ||
414 | name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); | ||
415 | } | ||
416 | } | ||
417 | |||
418 | void saa7134_i2c_call_clients(struct saa7134_dev *dev, | ||
419 | unsigned int cmd, void *arg) | ||
420 | { | ||
421 | BUG_ON(NULL == dev->i2c_adap.algo_data); | ||
422 | i2c_clients_command(&dev->i2c_adap, cmd, arg); | ||
423 | } | ||
424 | |||
425 | int saa7134_i2c_register(struct saa7134_dev *dev) | ||
426 | { | ||
427 | dev->i2c_adap = saa7134_adap_template; | ||
428 | dev->i2c_adap.dev.parent = &dev->pci->dev; | ||
429 | strcpy(dev->i2c_adap.name,dev->name); | ||
430 | dev->i2c_adap.algo_data = dev; | ||
431 | i2c_add_adapter(&dev->i2c_adap); | ||
432 | |||
433 | dev->i2c_client = saa7134_client_template; | ||
434 | dev->i2c_client.adapter = &dev->i2c_adap; | ||
435 | |||
436 | saa7134_i2c_eeprom(dev,dev->eedata,sizeof(dev->eedata)); | ||
437 | if (i2c_scan) | ||
438 | do_i2c_scan(dev->name,&dev->i2c_client); | ||
439 | return 0; | ||
440 | } | ||
441 | |||
442 | int saa7134_i2c_unregister(struct saa7134_dev *dev) | ||
443 | { | ||
444 | i2c_del_adapter(&dev->i2c_adap); | ||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | /* ----------------------------------------------------------- */ | ||
449 | /* | ||
450 | * Local variables: | ||
451 | * c-basic-offset: 8 | ||
452 | * End: | ||
453 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c new file mode 100644 index 000000000000..727d437e07df --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-input.c | |||
@@ -0,0 +1,491 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-input.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $ | ||
3 | * | ||
4 | * handle saa7134 IR remotes via linux kernel input layer. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/moduleparam.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/interrupt.h> | ||
28 | #include <linux/input.h> | ||
29 | |||
30 | #include "saa7134-reg.h" | ||
31 | #include "saa7134.h" | ||
32 | |||
33 | static unsigned int disable_ir = 0; | ||
34 | module_param(disable_ir, int, 0444); | ||
35 | MODULE_PARM_DESC(disable_ir,"disable infrared remote support"); | ||
36 | |||
37 | static unsigned int ir_debug = 0; | ||
38 | module_param(ir_debug, int, 0644); | ||
39 | MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); | ||
40 | |||
41 | #define dprintk(fmt, arg...) if (ir_debug) \ | ||
42 | printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg) | ||
43 | |||
44 | /* ---------------------------------------------------------------------- */ | ||
45 | |||
46 | static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = { | ||
47 | [ 15 ] = KEY_KP0, | ||
48 | [ 3 ] = KEY_KP1, | ||
49 | [ 4 ] = KEY_KP2, | ||
50 | [ 5 ] = KEY_KP3, | ||
51 | [ 7 ] = KEY_KP4, | ||
52 | [ 8 ] = KEY_KP5, | ||
53 | [ 9 ] = KEY_KP6, | ||
54 | [ 11 ] = KEY_KP7, | ||
55 | [ 12 ] = KEY_KP8, | ||
56 | [ 13 ] = KEY_KP9, | ||
57 | |||
58 | [ 14 ] = KEY_TUNER, // Air/Cable | ||
59 | [ 17 ] = KEY_VIDEO, // Video | ||
60 | [ 21 ] = KEY_AUDIO, // Audio | ||
61 | [ 0 ] = KEY_POWER, // Pover | ||
62 | [ 2 ] = KEY_ZOOM, // Fullscreen | ||
63 | [ 27 ] = KEY_MUTE, // Mute | ||
64 | [ 20 ] = KEY_VOLUMEUP, | ||
65 | [ 23 ] = KEY_VOLUMEDOWN, | ||
66 | [ 18 ] = KEY_CHANNELUP, // Channel + | ||
67 | [ 19 ] = KEY_CHANNELDOWN, // Channel - | ||
68 | [ 6 ] = KEY_AGAIN, // Recal | ||
69 | [ 16 ] = KEY_KPENTER, // Enter | ||
70 | |||
71 | #if 1 /* FIXME */ | ||
72 | [ 26 ] = KEY_F22, // Stereo | ||
73 | [ 24 ] = KEY_EDIT, // AV Source | ||
74 | #endif | ||
75 | }; | ||
76 | |||
77 | static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = { | ||
78 | [ 0 ] = KEY_KP0, | ||
79 | [ 1 ] = KEY_KP1, | ||
80 | [ 2 ] = KEY_KP2, | ||
81 | [ 3 ] = KEY_KP3, | ||
82 | [ 4 ] = KEY_KP4, | ||
83 | [ 5 ] = KEY_KP5, | ||
84 | [ 6 ] = KEY_KP6, | ||
85 | [ 7 ] = KEY_KP7, | ||
86 | [ 8 ] = KEY_KP8, | ||
87 | [ 9 ] = KEY_KP9, | ||
88 | |||
89 | [ 0x0a ] = KEY_POWER, | ||
90 | [ 0x0b ] = KEY_PROG1, // app | ||
91 | [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen | ||
92 | [ 0x0d ] = KEY_CHANNELUP, // channel | ||
93 | [ 0x0e ] = KEY_CHANNELDOWN, // channel- | ||
94 | [ 0x0f ] = KEY_VOLUMEUP, | ||
95 | [ 0x10 ] = KEY_VOLUMEDOWN, | ||
96 | [ 0x11 ] = KEY_TUNER, // AV | ||
97 | [ 0x12 ] = KEY_NUMLOCK, // -/-- | ||
98 | [ 0x13 ] = KEY_AUDIO, // audio | ||
99 | [ 0x14 ] = KEY_MUTE, | ||
100 | [ 0x15 ] = KEY_UP, | ||
101 | [ 0x16 ] = KEY_DOWN, | ||
102 | [ 0x17 ] = KEY_LEFT, | ||
103 | [ 0x18 ] = KEY_RIGHT, | ||
104 | [ 0x19 ] = BTN_LEFT, | ||
105 | [ 0x1a ] = BTN_RIGHT, | ||
106 | [ 0x1b ] = KEY_WWW, // text | ||
107 | [ 0x1c ] = KEY_REWIND, | ||
108 | [ 0x1d ] = KEY_FORWARD, | ||
109 | [ 0x1e ] = KEY_RECORD, | ||
110 | [ 0x1f ] = KEY_PLAY, | ||
111 | [ 0x20 ] = KEY_PREVIOUSSONG, | ||
112 | [ 0x21 ] = KEY_NEXTSONG, | ||
113 | [ 0x22 ] = KEY_PAUSE, | ||
114 | [ 0x23 ] = KEY_STOP, | ||
115 | }; | ||
116 | |||
117 | /* Alfons Geser <a.geser@cox.net> | ||
118 | * updates from Job D. R. Borges <jobdrb@ig.com.br> */ | ||
119 | static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { | ||
120 | [ 18 ] = KEY_POWER, | ||
121 | [ 1 ] = KEY_TV, // DVR | ||
122 | [ 21 ] = KEY_DVD, // DVD | ||
123 | [ 23 ] = KEY_AUDIO, // music | ||
124 | // DVR mode / DVD mode / music mode | ||
125 | |||
126 | [ 27 ] = KEY_MUTE, // mute | ||
127 | [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek | ||
128 | [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek | ||
129 | [ 22 ] = KEY_ZOOM, // full screen | ||
130 | [ 28 ] = KEY_VIDEO, // video source / eject / delall | ||
131 | [ 29 ] = KEY_RESTART, // playback / angle / del | ||
132 | [ 47 ] = KEY_SEARCH, // scan / menu / playlist | ||
133 | [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo | ||
134 | |||
135 | [ 49 ] = KEY_HELP, // help | ||
136 | [ 50 ] = KEY_MODE, // num/memo | ||
137 | [ 51 ] = KEY_ESC, // cancel | ||
138 | |||
139 | [ 12 ] = KEY_UP, // up | ||
140 | [ 16 ] = KEY_DOWN, // down | ||
141 | [ 8 ] = KEY_LEFT, // left | ||
142 | [ 4 ] = KEY_RIGHT, // right | ||
143 | [ 3 ] = KEY_SELECT, // select | ||
144 | |||
145 | [ 31 ] = KEY_REWIND, // rewind | ||
146 | [ 32 ] = KEY_PLAYPAUSE, // play/pause | ||
147 | [ 41 ] = KEY_FORWARD, // forward | ||
148 | [ 20 ] = KEY_AGAIN, // repeat | ||
149 | [ 43 ] = KEY_RECORD, // recording | ||
150 | [ 44 ] = KEY_STOP, // stop | ||
151 | [ 45 ] = KEY_PLAY, // play | ||
152 | [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle | ||
153 | |||
154 | [ 0 ] = KEY_KP0, | ||
155 | [ 5 ] = KEY_KP1, | ||
156 | [ 6 ] = KEY_KP2, | ||
157 | [ 7 ] = KEY_KP3, | ||
158 | [ 9 ] = KEY_KP4, | ||
159 | [ 10 ] = KEY_KP5, | ||
160 | [ 11 ] = KEY_KP6, | ||
161 | [ 13 ] = KEY_KP7, | ||
162 | [ 14 ] = KEY_KP8, | ||
163 | [ 15 ] = KEY_KP9, | ||
164 | |||
165 | [ 42 ] = KEY_VOLUMEUP, | ||
166 | [ 17 ] = KEY_VOLUMEDOWN, | ||
167 | [ 24 ] = KEY_CHANNELUP, // CH.tracking up | ||
168 | [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down | ||
169 | |||
170 | [ 19 ] = KEY_KPENTER, // enter | ||
171 | [ 33 ] = KEY_KPDOT, // . (decimal dot) | ||
172 | }; | ||
173 | |||
174 | static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = { | ||
175 | [ 30 ] = KEY_POWER, // power | ||
176 | [ 28 ] = KEY_SEARCH, // scan | ||
177 | [ 7 ] = KEY_SELECT, // source | ||
178 | |||
179 | [ 22 ] = KEY_VOLUMEUP, | ||
180 | [ 20 ] = KEY_VOLUMEDOWN, | ||
181 | [ 31 ] = KEY_CHANNELUP, | ||
182 | [ 23 ] = KEY_CHANNELDOWN, | ||
183 | [ 24 ] = KEY_MUTE, | ||
184 | |||
185 | [ 2 ] = KEY_KP0, | ||
186 | [ 1 ] = KEY_KP1, | ||
187 | [ 11 ] = KEY_KP2, | ||
188 | [ 27 ] = KEY_KP3, | ||
189 | [ 5 ] = KEY_KP4, | ||
190 | [ 9 ] = KEY_KP5, | ||
191 | [ 21 ] = KEY_KP6, | ||
192 | [ 6 ] = KEY_KP7, | ||
193 | [ 10 ] = KEY_KP8, | ||
194 | [ 18 ] = KEY_KP9, | ||
195 | [ 16 ] = KEY_KPDOT, | ||
196 | |||
197 | [ 3 ] = KEY_TUNER, // tv/fm | ||
198 | [ 4 ] = KEY_REWIND, // fm tuning left or function left | ||
199 | [ 12 ] = KEY_FORWARD, // fm tuning right or function right | ||
200 | |||
201 | [ 0 ] = KEY_RECORD, | ||
202 | [ 8 ] = KEY_STOP, | ||
203 | [ 17 ] = KEY_PLAY, | ||
204 | |||
205 | [ 25 ] = KEY_ZOOM, | ||
206 | [ 14 ] = KEY_MENU, // function | ||
207 | [ 19 ] = KEY_AGAIN, // recall | ||
208 | [ 29 ] = KEY_RESTART, // reset | ||
209 | |||
210 | // FIXME | ||
211 | [ 13 ] = KEY_F21, // mts | ||
212 | [ 15 ] = KEY_F22, // min | ||
213 | [ 26 ] = KEY_F23, // freeze | ||
214 | }; | ||
215 | |||
216 | /* Alex Hermann <gaaf@gmx.net> */ | ||
217 | static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = { | ||
218 | [ 40 ] = KEY_KP1, | ||
219 | [ 24 ] = KEY_KP2, | ||
220 | [ 56 ] = KEY_KP3, | ||
221 | [ 36 ] = KEY_KP4, | ||
222 | [ 20 ] = KEY_KP5, | ||
223 | [ 52 ] = KEY_KP6, | ||
224 | [ 44 ] = KEY_KP7, | ||
225 | [ 28 ] = KEY_KP8, | ||
226 | [ 60 ] = KEY_KP9, | ||
227 | [ 34 ] = KEY_KP0, | ||
228 | |||
229 | [ 32 ] = KEY_TV, // TV/FM | ||
230 | [ 16 ] = KEY_CD, // CD | ||
231 | [ 48 ] = KEY_TEXT, // TELETEXT | ||
232 | [ 0 ] = KEY_POWER, // POWER | ||
233 | |||
234 | [ 8 ] = KEY_VIDEO, // VIDEO | ||
235 | [ 4 ] = KEY_AUDIO, // AUDIO | ||
236 | [ 12 ] = KEY_ZOOM, // FULL SCREEN | ||
237 | |||
238 | [ 18 ] = KEY_SUBTITLE, // DISPLAY - ??? | ||
239 | [ 50 ] = KEY_REWIND, // LOOP - ??? | ||
240 | [ 2 ] = KEY_PRINT, // PREVIEW - ??? | ||
241 | |||
242 | [ 42 ] = KEY_SEARCH, // AUTOSCAN | ||
243 | [ 26 ] = KEY_SLEEP, // FREEZE - ??? | ||
244 | [ 58 ] = KEY_SHUFFLE, // SNAPSHOT - ??? | ||
245 | [ 10 ] = KEY_MUTE, // MUTE | ||
246 | |||
247 | [ 38 ] = KEY_RECORD, // RECORD | ||
248 | [ 22 ] = KEY_PAUSE, // PAUSE | ||
249 | [ 54 ] = KEY_STOP, // STOP | ||
250 | [ 6 ] = KEY_PLAY, // PLAY | ||
251 | |||
252 | [ 46 ] = KEY_RED, // <RED> | ||
253 | [ 33 ] = KEY_GREEN, // <GREEN> | ||
254 | [ 14 ] = KEY_YELLOW, // <YELLOW> | ||
255 | [ 1 ] = KEY_BLUE, // <BLUE> | ||
256 | |||
257 | [ 30 ] = KEY_VOLUMEDOWN, // VOLUME- | ||
258 | [ 62 ] = KEY_VOLUMEUP, // VOLUME+ | ||
259 | [ 17 ] = KEY_CHANNELDOWN, // CHANNEL/PAGE- | ||
260 | [ 49 ] = KEY_CHANNELUP // CHANNEL/PAGE+ | ||
261 | }; | ||
262 | |||
263 | static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = { | ||
264 | [ 20 ] = KEY_MUTE, | ||
265 | [ 36 ] = KEY_ZOOM, | ||
266 | |||
267 | [ 1 ] = KEY_DVD, | ||
268 | [ 35 ] = KEY_RADIO, | ||
269 | [ 0 ] = KEY_TV, | ||
270 | |||
271 | [ 10 ] = KEY_REWIND, | ||
272 | [ 8 ] = KEY_PLAYPAUSE, | ||
273 | [ 15 ] = KEY_FORWARD, | ||
274 | |||
275 | [ 2 ] = KEY_PREVIOUS, | ||
276 | [ 7 ] = KEY_STOP, | ||
277 | [ 6 ] = KEY_NEXT, | ||
278 | |||
279 | [ 12 ] = KEY_UP, | ||
280 | [ 14 ] = KEY_DOWN, | ||
281 | [ 11 ] = KEY_LEFT, | ||
282 | [ 13 ] = KEY_RIGHT, | ||
283 | [ 17 ] = KEY_OK, | ||
284 | |||
285 | [ 3 ] = KEY_MENU, | ||
286 | [ 9 ] = KEY_SETUP, | ||
287 | [ 5 ] = KEY_VIDEO, | ||
288 | [ 34 ] = KEY_CHANNEL, | ||
289 | |||
290 | [ 18 ] = KEY_VOLUMEUP, | ||
291 | [ 21 ] = KEY_VOLUMEDOWN, | ||
292 | [ 16 ] = KEY_CHANNELUP, | ||
293 | [ 19 ] = KEY_CHANNELDOWN, | ||
294 | |||
295 | [ 4 ] = KEY_RECORD, | ||
296 | |||
297 | [ 22 ] = KEY_KP1, | ||
298 | [ 23 ] = KEY_KP2, | ||
299 | [ 24 ] = KEY_KP3, | ||
300 | [ 25 ] = KEY_KP4, | ||
301 | [ 26 ] = KEY_KP5, | ||
302 | [ 27 ] = KEY_KP6, | ||
303 | [ 28 ] = KEY_KP7, | ||
304 | [ 29 ] = KEY_KP8, | ||
305 | [ 30 ] = KEY_KP9, | ||
306 | [ 31 ] = KEY_KP0, | ||
307 | |||
308 | [ 32 ] = KEY_LANGUAGE, | ||
309 | [ 33 ] = KEY_SLEEP, | ||
310 | }; | ||
311 | /* ---------------------------------------------------------------------- */ | ||
312 | |||
313 | static int build_key(struct saa7134_dev *dev) | ||
314 | { | ||
315 | struct saa7134_ir *ir = dev->remote; | ||
316 | u32 gpio, data; | ||
317 | |||
318 | /* rising SAA7134_GPIO_GPRESCAN reads the status */ | ||
319 | saa_clearb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); | ||
320 | saa_setb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN); | ||
321 | |||
322 | gpio = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2); | ||
323 | if (ir->polling) { | ||
324 | if (ir->last_gpio == gpio) | ||
325 | return 0; | ||
326 | ir->last_gpio = gpio; | ||
327 | } | ||
328 | |||
329 | data = ir_extract_bits(gpio, ir->mask_keycode); | ||
330 | dprintk("build_key gpio=0x%x mask=0x%x data=%d\n", | ||
331 | gpio, ir->mask_keycode, data); | ||
332 | |||
333 | if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) || | ||
334 | (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) { | ||
335 | ir_input_keydown(&ir->dev,&ir->ir,data,data); | ||
336 | } else { | ||
337 | ir_input_nokey(&ir->dev,&ir->ir); | ||
338 | } | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | /* ---------------------------------------------------------------------- */ | ||
343 | |||
344 | void saa7134_input_irq(struct saa7134_dev *dev) | ||
345 | { | ||
346 | struct saa7134_ir *ir = dev->remote; | ||
347 | |||
348 | if (!ir->polling) | ||
349 | build_key(dev); | ||
350 | } | ||
351 | |||
352 | static void saa7134_input_timer(unsigned long data) | ||
353 | { | ||
354 | struct saa7134_dev *dev = (struct saa7134_dev*)data; | ||
355 | struct saa7134_ir *ir = dev->remote; | ||
356 | unsigned long timeout; | ||
357 | |||
358 | build_key(dev); | ||
359 | timeout = jiffies + (ir->polling * HZ / 1000); | ||
360 | mod_timer(&ir->timer, timeout); | ||
361 | } | ||
362 | |||
363 | int saa7134_input_init1(struct saa7134_dev *dev) | ||
364 | { | ||
365 | struct saa7134_ir *ir; | ||
366 | IR_KEYTAB_TYPE *ir_codes = NULL; | ||
367 | u32 mask_keycode = 0; | ||
368 | u32 mask_keydown = 0; | ||
369 | u32 mask_keyup = 0; | ||
370 | int polling = 0; | ||
371 | int ir_type = IR_TYPE_OTHER; | ||
372 | |||
373 | if (!dev->has_remote) | ||
374 | return -ENODEV; | ||
375 | if (disable_ir) | ||
376 | return -ENODEV; | ||
377 | |||
378 | /* detect & configure */ | ||
379 | switch (dev->board) { | ||
380 | case SAA7134_BOARD_FLYVIDEO2000: | ||
381 | case SAA7134_BOARD_FLYVIDEO3000: | ||
382 | ir_codes = flyvideo_codes; | ||
383 | mask_keycode = 0xEC00000; | ||
384 | mask_keydown = 0x0040000; | ||
385 | break; | ||
386 | case SAA7134_BOARD_CINERGY400: | ||
387 | case SAA7134_BOARD_CINERGY600: | ||
388 | case SAA7134_BOARD_CINERGY600_MK3: | ||
389 | ir_codes = cinergy_codes; | ||
390 | mask_keycode = 0x00003f; | ||
391 | mask_keyup = 0x040000; | ||
392 | break; | ||
393 | case SAA7134_BOARD_ECS_TVP3XP: | ||
394 | case SAA7134_BOARD_ECS_TVP3XP_4CB5: | ||
395 | ir_codes = eztv_codes; | ||
396 | mask_keycode = 0x00017c; | ||
397 | mask_keyup = 0x000002; | ||
398 | polling = 50; // ms | ||
399 | break; | ||
400 | case SAA7134_BOARD_AVACSSMARTTV: | ||
401 | ir_codes = avacssmart_codes; | ||
402 | mask_keycode = 0x00001F; | ||
403 | mask_keyup = 0x000020; | ||
404 | polling = 50; // ms | ||
405 | break; | ||
406 | case SAA7134_BOARD_MD2819: | ||
407 | case SAA7134_BOARD_AVERMEDIA_305: | ||
408 | case SAA7134_BOARD_AVERMEDIA_307: | ||
409 | ir_codes = md2819_codes; | ||
410 | mask_keycode = 0x0007C8; | ||
411 | mask_keydown = 0x000010; | ||
412 | polling = 50; // ms | ||
413 | /* Set GPIO pin2 to high to enable the IR controller */ | ||
414 | saa_setb(SAA7134_GPIO_GPMODE0, 0x4); | ||
415 | saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); | ||
416 | break; | ||
417 | case SAA7134_BOARD_VIDEOMATE_TV_PVR: | ||
418 | ir_codes = videomate_tv_pvr_codes; | ||
419 | mask_keycode = 0x00003F; | ||
420 | mask_keyup = 0x400000; | ||
421 | polling = 50; // ms | ||
422 | break; | ||
423 | } | ||
424 | if (NULL == ir_codes) { | ||
425 | printk("%s: Oops: IR config error [card=%d]\n", | ||
426 | dev->name, dev->board); | ||
427 | return -ENODEV; | ||
428 | } | ||
429 | |||
430 | ir = kmalloc(sizeof(*ir),GFP_KERNEL); | ||
431 | if (NULL == ir) | ||
432 | return -ENOMEM; | ||
433 | memset(ir,0,sizeof(*ir)); | ||
434 | |||
435 | /* init hardware-specific stuff */ | ||
436 | ir->mask_keycode = mask_keycode; | ||
437 | ir->mask_keydown = mask_keydown; | ||
438 | ir->mask_keyup = mask_keyup; | ||
439 | ir->polling = polling; | ||
440 | |||
441 | /* init input device */ | ||
442 | snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", | ||
443 | saa7134_boards[dev->board].name); | ||
444 | snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", | ||
445 | pci_name(dev->pci)); | ||
446 | |||
447 | ir_input_init(&ir->dev, &ir->ir, ir_type, ir_codes); | ||
448 | ir->dev.name = ir->name; | ||
449 | ir->dev.phys = ir->phys; | ||
450 | ir->dev.id.bustype = BUS_PCI; | ||
451 | ir->dev.id.version = 1; | ||
452 | if (dev->pci->subsystem_vendor) { | ||
453 | ir->dev.id.vendor = dev->pci->subsystem_vendor; | ||
454 | ir->dev.id.product = dev->pci->subsystem_device; | ||
455 | } else { | ||
456 | ir->dev.id.vendor = dev->pci->vendor; | ||
457 | ir->dev.id.product = dev->pci->device; | ||
458 | } | ||
459 | |||
460 | /* all done */ | ||
461 | dev->remote = ir; | ||
462 | if (ir->polling) { | ||
463 | init_timer(&ir->timer); | ||
464 | ir->timer.function = saa7134_input_timer; | ||
465 | ir->timer.data = (unsigned long)dev; | ||
466 | ir->timer.expires = jiffies + HZ; | ||
467 | add_timer(&ir->timer); | ||
468 | } | ||
469 | |||
470 | input_register_device(&dev->remote->dev); | ||
471 | printk("%s: registered input device for IR\n",dev->name); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | void saa7134_input_fini(struct saa7134_dev *dev) | ||
476 | { | ||
477 | if (NULL == dev->remote) | ||
478 | return; | ||
479 | |||
480 | input_unregister_device(&dev->remote->dev); | ||
481 | if (dev->remote->polling) | ||
482 | del_timer_sync(&dev->remote->timer); | ||
483 | kfree(dev->remote); | ||
484 | dev->remote = NULL; | ||
485 | } | ||
486 | |||
487 | /* ---------------------------------------------------------------------- | ||
488 | * Local variables: | ||
489 | * c-basic-offset: 8 | ||
490 | * End: | ||
491 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c new file mode 100644 index 000000000000..6b6a643bf1cd --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-oss.c | |||
@@ -0,0 +1,857 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-oss.c,v 1.13 2004/12/10 12:33:39 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * oss dsp interface | ||
6 | * | ||
7 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/soundcard.h> | ||
31 | |||
32 | #include "saa7134-reg.h" | ||
33 | #include "saa7134.h" | ||
34 | |||
35 | /* ------------------------------------------------------------------ */ | ||
36 | |||
37 | static unsigned int oss_debug = 0; | ||
38 | module_param(oss_debug, int, 0644); | ||
39 | MODULE_PARM_DESC(oss_debug,"enable debug messages [oss]"); | ||
40 | |||
41 | static unsigned int oss_rate = 0; | ||
42 | module_param(oss_rate, int, 0444); | ||
43 | MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)"); | ||
44 | |||
45 | #define dprintk(fmt, arg...) if (oss_debug) \ | ||
46 | printk(KERN_DEBUG "%s/oss: " fmt, dev->name , ## arg) | ||
47 | |||
48 | /* ------------------------------------------------------------------ */ | ||
49 | |||
50 | static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks) | ||
51 | { | ||
52 | blksize &= ~0xff; | ||
53 | if (blksize < 0x100) | ||
54 | blksize = 0x100; | ||
55 | if (blksize > 0x10000) | ||
56 | blksize = 0x10000; | ||
57 | |||
58 | if (blocks < 2) | ||
59 | blocks = 2; | ||
60 | while ((blksize * blocks) & ~PAGE_MASK) | ||
61 | blocks++; | ||
62 | if ((blksize * blocks) > 1024*1024) | ||
63 | blocks = 1024*1024 / blksize; | ||
64 | |||
65 | dev->oss.blocks = blocks; | ||
66 | dev->oss.blksize = blksize; | ||
67 | dev->oss.bufsize = blksize * blocks; | ||
68 | |||
69 | dprintk("buffer config: %d blocks / %d bytes, %d kB total\n", | ||
70 | blocks,blksize,blksize * blocks / 1024); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int dsp_buffer_init(struct saa7134_dev *dev) | ||
75 | { | ||
76 | int err; | ||
77 | |||
78 | if (!dev->oss.bufsize) | ||
79 | BUG(); | ||
80 | videobuf_dma_init(&dev->oss.dma); | ||
81 | err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE, | ||
82 | dev->oss.bufsize >> PAGE_SHIFT); | ||
83 | if (0 != err) | ||
84 | return err; | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int dsp_buffer_free(struct saa7134_dev *dev) | ||
89 | { | ||
90 | if (!dev->oss.blksize) | ||
91 | BUG(); | ||
92 | videobuf_dma_free(&dev->oss.dma); | ||
93 | dev->oss.blocks = 0; | ||
94 | dev->oss.blksize = 0; | ||
95 | dev->oss.bufsize = 0; | ||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static void dsp_dma_start(struct saa7134_dev *dev) | ||
100 | { | ||
101 | dev->oss.dma_blk = 0; | ||
102 | dev->oss.dma_running = 1; | ||
103 | saa7134_set_dmabits(dev); | ||
104 | } | ||
105 | |||
106 | static void dsp_dma_stop(struct saa7134_dev *dev) | ||
107 | { | ||
108 | dev->oss.dma_blk = -1; | ||
109 | dev->oss.dma_running = 0; | ||
110 | saa7134_set_dmabits(dev); | ||
111 | } | ||
112 | |||
113 | static int dsp_rec_start(struct saa7134_dev *dev) | ||
114 | { | ||
115 | int err, bswap, sign; | ||
116 | u32 fmt, control; | ||
117 | unsigned long flags; | ||
118 | |||
119 | /* prepare buffer */ | ||
120 | if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma))) | ||
121 | return err; | ||
122 | if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->oss.pt))) | ||
123 | goto fail1; | ||
124 | if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->oss.pt, | ||
125 | dev->oss.dma.sglist, | ||
126 | dev->oss.dma.sglen, | ||
127 | 0))) | ||
128 | goto fail2; | ||
129 | |||
130 | /* sample format */ | ||
131 | switch (dev->oss.afmt) { | ||
132 | case AFMT_U8: | ||
133 | case AFMT_S8: fmt = 0x00; break; | ||
134 | case AFMT_U16_LE: | ||
135 | case AFMT_U16_BE: | ||
136 | case AFMT_S16_LE: | ||
137 | case AFMT_S16_BE: fmt = 0x01; break; | ||
138 | default: | ||
139 | err = -EINVAL; | ||
140 | goto fail2; | ||
141 | } | ||
142 | |||
143 | switch (dev->oss.afmt) { | ||
144 | case AFMT_S8: | ||
145 | case AFMT_S16_LE: | ||
146 | case AFMT_S16_BE: sign = 1; break; | ||
147 | default: sign = 0; break; | ||
148 | } | ||
149 | |||
150 | switch (dev->oss.afmt) { | ||
151 | case AFMT_U16_BE: | ||
152 | case AFMT_S16_BE: bswap = 1; break; | ||
153 | default: bswap = 0; break; | ||
154 | } | ||
155 | |||
156 | switch (dev->pci->device) { | ||
157 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
158 | if (1 == dev->oss.channels) | ||
159 | fmt |= (1 << 3); | ||
160 | if (2 == dev->oss.channels) | ||
161 | fmt |= (3 << 3); | ||
162 | if (sign) | ||
163 | fmt |= 0x04; | ||
164 | fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80; | ||
165 | |||
166 | saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff)); | ||
167 | saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >> 8); | ||
168 | saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16); | ||
169 | saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); | ||
170 | break; | ||
171 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
172 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
173 | if (1 == dev->oss.channels) | ||
174 | fmt |= (1 << 4); | ||
175 | if (2 == dev->oss.channels) | ||
176 | fmt |= (2 << 4); | ||
177 | if (!sign) | ||
178 | fmt |= 0x04; | ||
179 | saa_writel(0x588 >> 2, dev->oss.blksize -4); | ||
180 | saa_writel(0x58c >> 2, 0x543210 | (fmt << 24)); | ||
181 | break; | ||
182 | } | ||
183 | dprintk("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n", | ||
184 | dev->oss.afmt, dev->oss.channels, fmt, | ||
185 | bswap ? 'b' : '-'); | ||
186 | |||
187 | /* dma: setup channel 6 (= AUDIO) */ | ||
188 | control = SAA7134_RS_CONTROL_BURST_16 | | ||
189 | SAA7134_RS_CONTROL_ME | | ||
190 | (dev->oss.pt.dma >> 12); | ||
191 | if (bswap) | ||
192 | control |= SAA7134_RS_CONTROL_BSWAP; | ||
193 | saa_writel(SAA7134_RS_BA1(6),0); | ||
194 | saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize); | ||
195 | saa_writel(SAA7134_RS_PITCH(6),0); | ||
196 | saa_writel(SAA7134_RS_CONTROL(6),control); | ||
197 | |||
198 | /* start dma */ | ||
199 | dev->oss.recording_on = 1; | ||
200 | spin_lock_irqsave(&dev->slock,flags); | ||
201 | dsp_dma_start(dev); | ||
202 | spin_unlock_irqrestore(&dev->slock,flags); | ||
203 | return 0; | ||
204 | |||
205 | fail2: | ||
206 | saa7134_pgtable_free(dev->pci,&dev->oss.pt); | ||
207 | fail1: | ||
208 | videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma); | ||
209 | return err; | ||
210 | } | ||
211 | |||
212 | static int dsp_rec_stop(struct saa7134_dev *dev) | ||
213 | { | ||
214 | unsigned long flags; | ||
215 | |||
216 | dprintk("rec_stop dma_blk=%d\n",dev->oss.dma_blk); | ||
217 | |||
218 | /* stop dma */ | ||
219 | dev->oss.recording_on = 0; | ||
220 | spin_lock_irqsave(&dev->slock,flags); | ||
221 | dsp_dma_stop(dev); | ||
222 | spin_unlock_irqrestore(&dev->slock,flags); | ||
223 | |||
224 | /* unlock buffer */ | ||
225 | saa7134_pgtable_free(dev->pci,&dev->oss.pt); | ||
226 | videobuf_dma_pci_unmap(dev->pci,&dev->oss.dma); | ||
227 | return 0; | ||
228 | } | ||
229 | |||
230 | /* ------------------------------------------------------------------ */ | ||
231 | |||
232 | static int dsp_open(struct inode *inode, struct file *file) | ||
233 | { | ||
234 | int minor = iminor(inode); | ||
235 | struct saa7134_dev *h,*dev = NULL; | ||
236 | struct list_head *list; | ||
237 | int err; | ||
238 | |||
239 | list_for_each(list,&saa7134_devlist) { | ||
240 | h = list_entry(list, struct saa7134_dev, devlist); | ||
241 | if (h->oss.minor_dsp == minor) | ||
242 | dev = h; | ||
243 | } | ||
244 | if (NULL == dev) | ||
245 | return -ENODEV; | ||
246 | |||
247 | down(&dev->oss.lock); | ||
248 | err = -EBUSY; | ||
249 | if (dev->oss.users_dsp) | ||
250 | goto fail1; | ||
251 | dev->oss.users_dsp++; | ||
252 | file->private_data = dev; | ||
253 | |||
254 | dev->oss.afmt = AFMT_U8; | ||
255 | dev->oss.channels = 1; | ||
256 | dev->oss.read_count = 0; | ||
257 | dev->oss.read_offset = 0; | ||
258 | dsp_buffer_conf(dev,PAGE_SIZE,64); | ||
259 | err = dsp_buffer_init(dev); | ||
260 | if (0 != err) | ||
261 | goto fail2; | ||
262 | |||
263 | up(&dev->oss.lock); | ||
264 | return 0; | ||
265 | |||
266 | fail2: | ||
267 | dev->oss.users_dsp--; | ||
268 | fail1: | ||
269 | up(&dev->oss.lock); | ||
270 | return err; | ||
271 | } | ||
272 | |||
273 | static int dsp_release(struct inode *inode, struct file *file) | ||
274 | { | ||
275 | struct saa7134_dev *dev = file->private_data; | ||
276 | |||
277 | down(&dev->oss.lock); | ||
278 | if (dev->oss.recording_on) | ||
279 | dsp_rec_stop(dev); | ||
280 | dsp_buffer_free(dev); | ||
281 | dev->oss.users_dsp--; | ||
282 | file->private_data = NULL; | ||
283 | up(&dev->oss.lock); | ||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | static ssize_t dsp_read(struct file *file, char __user *buffer, | ||
288 | size_t count, loff_t *ppos) | ||
289 | { | ||
290 | struct saa7134_dev *dev = file->private_data; | ||
291 | DECLARE_WAITQUEUE(wait, current); | ||
292 | unsigned int bytes; | ||
293 | unsigned long flags; | ||
294 | int err,ret = 0; | ||
295 | |||
296 | add_wait_queue(&dev->oss.wq, &wait); | ||
297 | down(&dev->oss.lock); | ||
298 | while (count > 0) { | ||
299 | /* wait for data if needed */ | ||
300 | if (0 == dev->oss.read_count) { | ||
301 | if (!dev->oss.recording_on) { | ||
302 | err = dsp_rec_start(dev); | ||
303 | if (err < 0) { | ||
304 | if (0 == ret) | ||
305 | ret = err; | ||
306 | break; | ||
307 | } | ||
308 | } | ||
309 | if (dev->oss.recording_on && | ||
310 | !dev->oss.dma_running) { | ||
311 | /* recover from overruns */ | ||
312 | spin_lock_irqsave(&dev->slock,flags); | ||
313 | dsp_dma_start(dev); | ||
314 | spin_unlock_irqrestore(&dev->slock,flags); | ||
315 | } | ||
316 | if (file->f_flags & O_NONBLOCK) { | ||
317 | if (0 == ret) | ||
318 | ret = -EAGAIN; | ||
319 | break; | ||
320 | } | ||
321 | up(&dev->oss.lock); | ||
322 | set_current_state(TASK_INTERRUPTIBLE); | ||
323 | if (0 == dev->oss.read_count) | ||
324 | schedule(); | ||
325 | set_current_state(TASK_RUNNING); | ||
326 | down(&dev->oss.lock); | ||
327 | if (signal_pending(current)) { | ||
328 | if (0 == ret) | ||
329 | ret = -EINTR; | ||
330 | break; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | /* copy data to userspace */ | ||
335 | bytes = count; | ||
336 | if (bytes > dev->oss.read_count) | ||
337 | bytes = dev->oss.read_count; | ||
338 | if (bytes > dev->oss.bufsize - dev->oss.read_offset) | ||
339 | bytes = dev->oss.bufsize - dev->oss.read_offset; | ||
340 | if (copy_to_user(buffer + ret, | ||
341 | dev->oss.dma.vmalloc + dev->oss.read_offset, | ||
342 | bytes)) { | ||
343 | if (0 == ret) | ||
344 | ret = -EFAULT; | ||
345 | break; | ||
346 | } | ||
347 | |||
348 | ret += bytes; | ||
349 | count -= bytes; | ||
350 | dev->oss.read_count -= bytes; | ||
351 | dev->oss.read_offset += bytes; | ||
352 | if (dev->oss.read_offset == dev->oss.bufsize) | ||
353 | dev->oss.read_offset = 0; | ||
354 | } | ||
355 | up(&dev->oss.lock); | ||
356 | remove_wait_queue(&dev->oss.wq, &wait); | ||
357 | return ret; | ||
358 | } | ||
359 | |||
360 | static ssize_t dsp_write(struct file *file, const char __user *buffer, | ||
361 | size_t count, loff_t *ppos) | ||
362 | { | ||
363 | return -EINVAL; | ||
364 | } | ||
365 | |||
366 | static int dsp_ioctl(struct inode *inode, struct file *file, | ||
367 | unsigned int cmd, unsigned long arg) | ||
368 | { | ||
369 | struct saa7134_dev *dev = file->private_data; | ||
370 | void __user *argp = (void __user *) arg; | ||
371 | int __user *p = argp; | ||
372 | int val = 0; | ||
373 | |||
374 | if (oss_debug > 1) | ||
375 | saa7134_print_ioctl(dev->name,cmd); | ||
376 | switch (cmd) { | ||
377 | case OSS_GETVERSION: | ||
378 | return put_user(SOUND_VERSION, p); | ||
379 | case SNDCTL_DSP_GETCAPS: | ||
380 | return 0; | ||
381 | |||
382 | case SNDCTL_DSP_SPEED: | ||
383 | if (get_user(val, p)) | ||
384 | return -EFAULT; | ||
385 | /* fall through */ | ||
386 | case SOUND_PCM_READ_RATE: | ||
387 | return put_user(dev->oss.rate, p); | ||
388 | |||
389 | case SNDCTL_DSP_STEREO: | ||
390 | if (get_user(val, p)) | ||
391 | return -EFAULT; | ||
392 | down(&dev->oss.lock); | ||
393 | dev->oss.channels = val ? 2 : 1; | ||
394 | if (dev->oss.recording_on) { | ||
395 | dsp_rec_stop(dev); | ||
396 | dsp_rec_start(dev); | ||
397 | } | ||
398 | up(&dev->oss.lock); | ||
399 | return put_user(dev->oss.channels-1, p); | ||
400 | |||
401 | case SNDCTL_DSP_CHANNELS: | ||
402 | if (get_user(val, p)) | ||
403 | return -EFAULT; | ||
404 | if (val != 1 && val != 2) | ||
405 | return -EINVAL; | ||
406 | down(&dev->oss.lock); | ||
407 | dev->oss.channels = val; | ||
408 | if (dev->oss.recording_on) { | ||
409 | dsp_rec_stop(dev); | ||
410 | dsp_rec_start(dev); | ||
411 | } | ||
412 | up(&dev->oss.lock); | ||
413 | /* fall through */ | ||
414 | case SOUND_PCM_READ_CHANNELS: | ||
415 | return put_user(dev->oss.channels, p); | ||
416 | |||
417 | case SNDCTL_DSP_GETFMTS: /* Returns a mask */ | ||
418 | return put_user(AFMT_U8 | AFMT_S8 | | ||
419 | AFMT_U16_LE | AFMT_U16_BE | | ||
420 | AFMT_S16_LE | AFMT_S16_BE, p); | ||
421 | |||
422 | case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */ | ||
423 | if (get_user(val, p)) | ||
424 | return -EFAULT; | ||
425 | switch (val) { | ||
426 | case AFMT_QUERY: | ||
427 | /* nothing to do */ | ||
428 | break; | ||
429 | case AFMT_U8: | ||
430 | case AFMT_S8: | ||
431 | case AFMT_U16_LE: | ||
432 | case AFMT_U16_BE: | ||
433 | case AFMT_S16_LE: | ||
434 | case AFMT_S16_BE: | ||
435 | down(&dev->oss.lock); | ||
436 | dev->oss.afmt = val; | ||
437 | if (dev->oss.recording_on) { | ||
438 | dsp_rec_stop(dev); | ||
439 | dsp_rec_start(dev); | ||
440 | } | ||
441 | up(&dev->oss.lock); | ||
442 | return put_user(dev->oss.afmt, p); | ||
443 | default: | ||
444 | return -EINVAL; | ||
445 | } | ||
446 | |||
447 | case SOUND_PCM_READ_BITS: | ||
448 | switch (dev->oss.afmt) { | ||
449 | case AFMT_U8: | ||
450 | case AFMT_S8: | ||
451 | return put_user(8, p); | ||
452 | case AFMT_U16_LE: | ||
453 | case AFMT_U16_BE: | ||
454 | case AFMT_S16_LE: | ||
455 | case AFMT_S16_BE: | ||
456 | return put_user(16, p); | ||
457 | default: | ||
458 | return -EINVAL; | ||
459 | } | ||
460 | |||
461 | case SNDCTL_DSP_NONBLOCK: | ||
462 | file->f_flags |= O_NONBLOCK; | ||
463 | return 0; | ||
464 | |||
465 | case SNDCTL_DSP_RESET: | ||
466 | down(&dev->oss.lock); | ||
467 | if (dev->oss.recording_on) | ||
468 | dsp_rec_stop(dev); | ||
469 | up(&dev->oss.lock); | ||
470 | return 0; | ||
471 | case SNDCTL_DSP_GETBLKSIZE: | ||
472 | return put_user(dev->oss.blksize, p); | ||
473 | |||
474 | case SNDCTL_DSP_SETFRAGMENT: | ||
475 | if (get_user(val, p)) | ||
476 | return -EFAULT; | ||
477 | if (dev->oss.recording_on) | ||
478 | return -EBUSY; | ||
479 | dsp_buffer_free(dev); | ||
480 | /* used to be arg >> 16 instead of val >> 16; fixed */ | ||
481 | dsp_buffer_conf(dev,1 << (val & 0xffff), (val >> 16) & 0xffff); | ||
482 | dsp_buffer_init(dev); | ||
483 | return 0; | ||
484 | |||
485 | case SNDCTL_DSP_SYNC: | ||
486 | /* NOP */ | ||
487 | return 0; | ||
488 | |||
489 | case SNDCTL_DSP_GETISPACE: | ||
490 | { | ||
491 | audio_buf_info info; | ||
492 | info.fragsize = dev->oss.blksize; | ||
493 | info.fragstotal = dev->oss.blocks; | ||
494 | info.bytes = dev->oss.read_count; | ||
495 | info.fragments = info.bytes / info.fragsize; | ||
496 | if (copy_to_user(argp, &info, sizeof(info))) | ||
497 | return -EFAULT; | ||
498 | return 0; | ||
499 | } | ||
500 | default: | ||
501 | return -EINVAL; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) | ||
506 | { | ||
507 | struct saa7134_dev *dev = file->private_data; | ||
508 | unsigned int mask = 0; | ||
509 | |||
510 | poll_wait(file, &dev->oss.wq, wait); | ||
511 | |||
512 | if (0 == dev->oss.read_count) { | ||
513 | down(&dev->oss.lock); | ||
514 | if (!dev->oss.recording_on) | ||
515 | dsp_rec_start(dev); | ||
516 | up(&dev->oss.lock); | ||
517 | } else | ||
518 | mask |= (POLLIN | POLLRDNORM); | ||
519 | return mask; | ||
520 | } | ||
521 | |||
522 | struct file_operations saa7134_dsp_fops = { | ||
523 | .owner = THIS_MODULE, | ||
524 | .open = dsp_open, | ||
525 | .release = dsp_release, | ||
526 | .read = dsp_read, | ||
527 | .write = dsp_write, | ||
528 | .ioctl = dsp_ioctl, | ||
529 | .poll = dsp_poll, | ||
530 | .llseek = no_llseek, | ||
531 | }; | ||
532 | |||
533 | /* ------------------------------------------------------------------ */ | ||
534 | |||
535 | static int | ||
536 | mixer_recsrc_7134(struct saa7134_dev *dev) | ||
537 | { | ||
538 | int analog_io,rate; | ||
539 | |||
540 | switch (dev->oss.input) { | ||
541 | case TV: | ||
542 | saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0); | ||
543 | saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00); | ||
544 | break; | ||
545 | case LINE1: | ||
546 | case LINE2: | ||
547 | case LINE2_LEFT: | ||
548 | analog_io = (LINE1 == dev->oss.input) ? 0x00 : 0x08; | ||
549 | rate = (32000 == dev->oss.rate) ? 0x01 : 0x03; | ||
550 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, analog_io); | ||
551 | saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0x80); | ||
552 | saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate); | ||
553 | break; | ||
554 | } | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int | ||
559 | mixer_recsrc_7133(struct saa7134_dev *dev) | ||
560 | { | ||
561 | u32 value = 0xbbbbbb; | ||
562 | |||
563 | switch (dev->oss.input) { | ||
564 | case TV: | ||
565 | value = 0xbbbb10; /* MAIN */ | ||
566 | break; | ||
567 | case LINE1: | ||
568 | value = 0xbbbb32; /* AUX1 */ | ||
569 | break; | ||
570 | case LINE2: | ||
571 | case LINE2_LEFT: | ||
572 | value = 0xbbbb54; /* AUX2 */ | ||
573 | break; | ||
574 | } | ||
575 | saa_dsp_writel(dev, 0x46c >> 2, value); | ||
576 | return 0; | ||
577 | } | ||
578 | |||
579 | static int | ||
580 | mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src) | ||
581 | { | ||
582 | static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" }; | ||
583 | |||
584 | dev->oss.count++; | ||
585 | dev->oss.input = src; | ||
586 | dprintk("mixer input = %s\n",iname[dev->oss.input]); | ||
587 | |||
588 | switch (dev->pci->device) { | ||
589 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
590 | mixer_recsrc_7134(dev); | ||
591 | break; | ||
592 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
593 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
594 | mixer_recsrc_7133(dev); | ||
595 | break; | ||
596 | } | ||
597 | return 0; | ||
598 | } | ||
599 | |||
600 | static int | ||
601 | mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level) | ||
602 | { | ||
603 | switch (dev->pci->device) { | ||
604 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
605 | switch (src) { | ||
606 | case TV: | ||
607 | /* nothing */ | ||
608 | break; | ||
609 | case LINE1: | ||
610 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, | ||
611 | (100 == level) ? 0x00 : 0x10); | ||
612 | break; | ||
613 | case LINE2: | ||
614 | case LINE2_LEFT: | ||
615 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, | ||
616 | (100 == level) ? 0x00 : 0x20); | ||
617 | break; | ||
618 | } | ||
619 | break; | ||
620 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
621 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
622 | /* nothing */ | ||
623 | break; | ||
624 | } | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | /* ------------------------------------------------------------------ */ | ||
629 | |||
630 | static int mixer_open(struct inode *inode, struct file *file) | ||
631 | { | ||
632 | int minor = iminor(inode); | ||
633 | struct saa7134_dev *h,*dev = NULL; | ||
634 | struct list_head *list; | ||
635 | |||
636 | list_for_each(list,&saa7134_devlist) { | ||
637 | h = list_entry(list, struct saa7134_dev, devlist); | ||
638 | if (h->oss.minor_mixer == minor) | ||
639 | dev = h; | ||
640 | } | ||
641 | if (NULL == dev) | ||
642 | return -ENODEV; | ||
643 | |||
644 | file->private_data = dev; | ||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static int mixer_release(struct inode *inode, struct file *file) | ||
649 | { | ||
650 | file->private_data = NULL; | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static int mixer_ioctl(struct inode *inode, struct file *file, | ||
655 | unsigned int cmd, unsigned long arg) | ||
656 | { | ||
657 | struct saa7134_dev *dev = file->private_data; | ||
658 | enum saa7134_audio_in input; | ||
659 | int val,ret; | ||
660 | void __user *argp = (void __user *) arg; | ||
661 | int __user *p = argp; | ||
662 | |||
663 | if (oss_debug > 1) | ||
664 | saa7134_print_ioctl(dev->name,cmd); | ||
665 | switch (cmd) { | ||
666 | case OSS_GETVERSION: | ||
667 | return put_user(SOUND_VERSION, p); | ||
668 | case SOUND_MIXER_INFO: | ||
669 | { | ||
670 | mixer_info info; | ||
671 | memset(&info,0,sizeof(info)); | ||
672 | strlcpy(info.id, "TV audio", sizeof(info.id)); | ||
673 | strlcpy(info.name, dev->name, sizeof(info.name)); | ||
674 | info.modify_counter = dev->oss.count; | ||
675 | if (copy_to_user(argp, &info, sizeof(info))) | ||
676 | return -EFAULT; | ||
677 | return 0; | ||
678 | } | ||
679 | case SOUND_OLD_MIXER_INFO: | ||
680 | { | ||
681 | _old_mixer_info info; | ||
682 | memset(&info,0,sizeof(info)); | ||
683 | strlcpy(info.id, "TV audio", sizeof(info.id)); | ||
684 | strlcpy(info.name, dev->name, sizeof(info.name)); | ||
685 | if (copy_to_user(argp, &info, sizeof(info))) | ||
686 | return -EFAULT; | ||
687 | return 0; | ||
688 | } | ||
689 | case MIXER_READ(SOUND_MIXER_CAPS): | ||
690 | return put_user(SOUND_CAP_EXCL_INPUT, p); | ||
691 | case MIXER_READ(SOUND_MIXER_STEREODEVS): | ||
692 | return put_user(0, p); | ||
693 | case MIXER_READ(SOUND_MIXER_RECMASK): | ||
694 | case MIXER_READ(SOUND_MIXER_DEVMASK): | ||
695 | val = SOUND_MASK_LINE1 | SOUND_MASK_LINE2; | ||
696 | if (32000 == dev->oss.rate) | ||
697 | val |= SOUND_MASK_VIDEO; | ||
698 | return put_user(val, p); | ||
699 | |||
700 | case MIXER_WRITE(SOUND_MIXER_RECSRC): | ||
701 | if (get_user(val, p)) | ||
702 | return -EFAULT; | ||
703 | input = dev->oss.input; | ||
704 | if (32000 == dev->oss.rate && | ||
705 | val & SOUND_MASK_VIDEO && dev->oss.input != TV) | ||
706 | input = TV; | ||
707 | if (val & SOUND_MASK_LINE1 && dev->oss.input != LINE1) | ||
708 | input = LINE1; | ||
709 | if (val & SOUND_MASK_LINE2 && dev->oss.input != LINE2) | ||
710 | input = LINE2; | ||
711 | if (input != dev->oss.input) | ||
712 | mixer_recsrc(dev,input); | ||
713 | /* fall throuth */ | ||
714 | case MIXER_READ(SOUND_MIXER_RECSRC): | ||
715 | switch (dev->oss.input) { | ||
716 | case TV: ret = SOUND_MASK_VIDEO; break; | ||
717 | case LINE1: ret = SOUND_MASK_LINE1; break; | ||
718 | case LINE2: ret = SOUND_MASK_LINE2; break; | ||
719 | default: ret = 0; | ||
720 | } | ||
721 | return put_user(ret, p); | ||
722 | |||
723 | case MIXER_WRITE(SOUND_MIXER_VIDEO): | ||
724 | case MIXER_READ(SOUND_MIXER_VIDEO): | ||
725 | if (32000 != dev->oss.rate) | ||
726 | return -EINVAL; | ||
727 | return put_user(100 | 100 << 8, p); | ||
728 | |||
729 | case MIXER_WRITE(SOUND_MIXER_LINE1): | ||
730 | if (get_user(val, p)) | ||
731 | return -EFAULT; | ||
732 | val &= 0xff; | ||
733 | val = (val <= 50) ? 50 : 100; | ||
734 | dev->oss.line1 = val; | ||
735 | mixer_level(dev,LINE1,dev->oss.line1); | ||
736 | /* fall throuth */ | ||
737 | case MIXER_READ(SOUND_MIXER_LINE1): | ||
738 | return put_user(dev->oss.line1 | dev->oss.line1 << 8, p); | ||
739 | |||
740 | case MIXER_WRITE(SOUND_MIXER_LINE2): | ||
741 | if (get_user(val, p)) | ||
742 | return -EFAULT; | ||
743 | val &= 0xff; | ||
744 | val = (val <= 50) ? 50 : 100; | ||
745 | dev->oss.line2 = val; | ||
746 | mixer_level(dev,LINE2,dev->oss.line2); | ||
747 | /* fall throuth */ | ||
748 | case MIXER_READ(SOUND_MIXER_LINE2): | ||
749 | return put_user(dev->oss.line2 | dev->oss.line2 << 8, p); | ||
750 | |||
751 | default: | ||
752 | return -EINVAL; | ||
753 | } | ||
754 | } | ||
755 | |||
756 | struct file_operations saa7134_mixer_fops = { | ||
757 | .owner = THIS_MODULE, | ||
758 | .open = mixer_open, | ||
759 | .release = mixer_release, | ||
760 | .ioctl = mixer_ioctl, | ||
761 | .llseek = no_llseek, | ||
762 | }; | ||
763 | |||
764 | /* ------------------------------------------------------------------ */ | ||
765 | |||
766 | int saa7134_oss_init1(struct saa7134_dev *dev) | ||
767 | { | ||
768 | /* general */ | ||
769 | init_MUTEX(&dev->oss.lock); | ||
770 | init_waitqueue_head(&dev->oss.wq); | ||
771 | |||
772 | switch (dev->pci->device) { | ||
773 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
774 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
775 | saa_writel(0x588 >> 2, 0x00000fff); | ||
776 | saa_writel(0x58c >> 2, 0x00543210); | ||
777 | saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb); | ||
778 | break; | ||
779 | } | ||
780 | |||
781 | /* dsp */ | ||
782 | dev->oss.rate = 32000; | ||
783 | if (oss_rate) | ||
784 | dev->oss.rate = oss_rate; | ||
785 | dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000; | ||
786 | |||
787 | /* mixer */ | ||
788 | dev->oss.line1 = 50; | ||
789 | dev->oss.line2 = 50; | ||
790 | mixer_level(dev,LINE1,dev->oss.line1); | ||
791 | mixer_level(dev,LINE2,dev->oss.line2); | ||
792 | mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | int saa7134_oss_fini(struct saa7134_dev *dev) | ||
798 | { | ||
799 | /* nothing */ | ||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status) | ||
804 | { | ||
805 | int next_blk, reg = 0; | ||
806 | |||
807 | spin_lock(&dev->slock); | ||
808 | if (UNSET == dev->oss.dma_blk) { | ||
809 | dprintk("irq: recording stopped\n"); | ||
810 | goto done; | ||
811 | } | ||
812 | if (0 != (status & 0x0f000000)) | ||
813 | dprintk("irq: lost %ld\n", (status >> 24) & 0x0f); | ||
814 | if (0 == (status & 0x10000000)) { | ||
815 | /* odd */ | ||
816 | if (0 == (dev->oss.dma_blk & 0x01)) | ||
817 | reg = SAA7134_RS_BA1(6); | ||
818 | } else { | ||
819 | /* even */ | ||
820 | if (0 == (dev->oss.dma_blk & 0x00)) | ||
821 | reg = SAA7134_RS_BA2(6); | ||
822 | } | ||
823 | if (0 == reg) { | ||
824 | dprintk("irq: field oops [%s]\n", | ||
825 | (status & 0x10000000) ? "even" : "odd"); | ||
826 | goto done; | ||
827 | } | ||
828 | if (dev->oss.read_count >= dev->oss.blksize * (dev->oss.blocks-2)) { | ||
829 | dprintk("irq: overrun [full=%d/%d]\n",dev->oss.read_count, | ||
830 | dev->oss.bufsize); | ||
831 | dsp_dma_stop(dev); | ||
832 | goto done; | ||
833 | } | ||
834 | |||
835 | /* next block addr */ | ||
836 | next_blk = (dev->oss.dma_blk + 2) % dev->oss.blocks; | ||
837 | saa_writel(reg,next_blk * dev->oss.blksize); | ||
838 | if (oss_debug > 2) | ||
839 | dprintk("irq: ok, %s, next_blk=%d, addr=%x\n", | ||
840 | (status & 0x10000000) ? "even" : "odd ", next_blk, | ||
841 | next_blk * dev->oss.blksize); | ||
842 | |||
843 | /* update status & wake waiting readers */ | ||
844 | dev->oss.dma_blk = (dev->oss.dma_blk + 1) % dev->oss.blocks; | ||
845 | dev->oss.read_count += dev->oss.blksize; | ||
846 | wake_up(&dev->oss.wq); | ||
847 | |||
848 | done: | ||
849 | spin_unlock(&dev->slock); | ||
850 | } | ||
851 | |||
852 | /* ----------------------------------------------------------- */ | ||
853 | /* | ||
854 | * Local variables: | ||
855 | * c-basic-offset: 8 | ||
856 | * End: | ||
857 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h new file mode 100644 index 000000000000..87734f22af7d --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-reg.h | |||
@@ -0,0 +1,366 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-reg.h,v 1.2 2004/09/15 16:15:24 kraxel Exp $ | ||
3 | * | ||
4 | * philips saa7134 registers | ||
5 | */ | ||
6 | |||
7 | /* ------------------------------------------------------------------ */ | ||
8 | /* | ||
9 | * PCI ID's | ||
10 | */ | ||
11 | #ifndef PCI_DEVICE_ID_PHILIPS_SAA7130 | ||
12 | # define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130 | ||
13 | #endif | ||
14 | #ifndef PCI_DEVICE_ID_PHILIPS_SAA7133 | ||
15 | # define PCI_DEVICE_ID_PHILIPS_SAA7133 0x7133 | ||
16 | #endif | ||
17 | #ifndef PCI_DEVICE_ID_PHILIPS_SAA7134 | ||
18 | # define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134 | ||
19 | #endif | ||
20 | #ifndef PCI_DEVICE_ID_PHILIPS_SAA7135 | ||
21 | # define PCI_DEVICE_ID_PHILIPS_SAA7135 0x7135 | ||
22 | #endif | ||
23 | |||
24 | /* ------------------------------------------------------------------ */ | ||
25 | /* | ||
26 | * registers -- 32 bit | ||
27 | */ | ||
28 | |||
29 | /* DMA channels, n = 0 ... 6 */ | ||
30 | #define SAA7134_RS_BA1(n) ((0x200 >> 2) + 4*n) | ||
31 | #define SAA7134_RS_BA2(n) ((0x204 >> 2) + 4*n) | ||
32 | #define SAA7134_RS_PITCH(n) ((0x208 >> 2) + 4*n) | ||
33 | #define SAA7134_RS_CONTROL(n) ((0x20c >> 2) + 4*n) | ||
34 | #define SAA7134_RS_CONTROL_WSWAP (0x01 << 25) | ||
35 | #define SAA7134_RS_CONTROL_BSWAP (0x01 << 24) | ||
36 | #define SAA7134_RS_CONTROL_BURST_2 (0x01 << 21) | ||
37 | #define SAA7134_RS_CONTROL_BURST_4 (0x02 << 21) | ||
38 | #define SAA7134_RS_CONTROL_BURST_8 (0x03 << 21) | ||
39 | #define SAA7134_RS_CONTROL_BURST_16 (0x04 << 21) | ||
40 | #define SAA7134_RS_CONTROL_BURST_32 (0x05 << 21) | ||
41 | #define SAA7134_RS_CONTROL_BURST_64 (0x06 << 21) | ||
42 | #define SAA7134_RS_CONTROL_BURST_MAX (0x07 << 21) | ||
43 | #define SAA7134_RS_CONTROL_ME (0x01 << 20) | ||
44 | #define SAA7134_FIFO_SIZE (0x2a0 >> 2) | ||
45 | #define SAA7134_THRESHOULD (0x2a4 >> 2) | ||
46 | |||
47 | /* main control */ | ||
48 | #define SAA7134_MAIN_CTRL (0x2a8 >> 2) | ||
49 | #define SAA7134_MAIN_CTRL_VPLLE (1 << 15) | ||
50 | #define SAA7134_MAIN_CTRL_APLLE (1 << 14) | ||
51 | #define SAA7134_MAIN_CTRL_EXOSC (1 << 13) | ||
52 | #define SAA7134_MAIN_CTRL_EVFE1 (1 << 12) | ||
53 | #define SAA7134_MAIN_CTRL_EVFE2 (1 << 11) | ||
54 | #define SAA7134_MAIN_CTRL_ESFE (1 << 10) | ||
55 | #define SAA7134_MAIN_CTRL_EBADC (1 << 9) | ||
56 | #define SAA7134_MAIN_CTRL_EBDAC (1 << 8) | ||
57 | #define SAA7134_MAIN_CTRL_TE6 (1 << 6) | ||
58 | #define SAA7134_MAIN_CTRL_TE5 (1 << 5) | ||
59 | #define SAA7134_MAIN_CTRL_TE4 (1 << 4) | ||
60 | #define SAA7134_MAIN_CTRL_TE3 (1 << 3) | ||
61 | #define SAA7134_MAIN_CTRL_TE2 (1 << 2) | ||
62 | #define SAA7134_MAIN_CTRL_TE1 (1 << 1) | ||
63 | #define SAA7134_MAIN_CTRL_TE0 (1 << 0) | ||
64 | |||
65 | /* DMA status */ | ||
66 | #define SAA7134_DMA_STATUS (0x2ac >> 2) | ||
67 | |||
68 | /* audio / video status */ | ||
69 | #define SAA7134_AV_STATUS (0x2c0 >> 2) | ||
70 | #define SAA7134_AV_STATUS_STEREO (1 << 17) | ||
71 | #define SAA7134_AV_STATUS_DUAL (1 << 16) | ||
72 | #define SAA7134_AV_STATUS_PILOT (1 << 15) | ||
73 | #define SAA7134_AV_STATUS_SMB (1 << 14) | ||
74 | #define SAA7134_AV_STATUS_DMB (1 << 13) | ||
75 | #define SAA7134_AV_STATUS_VDSP (1 << 12) | ||
76 | #define SAA7134_AV_STATUS_IIC_STATUS (3 << 10) | ||
77 | #define SAA7134_AV_STATUS_MVM (7 << 7) | ||
78 | #define SAA7134_AV_STATUS_FIDT (1 << 6) | ||
79 | #define SAA7134_AV_STATUS_INTL (1 << 5) | ||
80 | #define SAA7134_AV_STATUS_RDCAP (1 << 4) | ||
81 | #define SAA7134_AV_STATUS_PWR_ON (1 << 3) | ||
82 | #define SAA7134_AV_STATUS_LOAD_ERR (1 << 2) | ||
83 | #define SAA7134_AV_STATUS_TRIG_ERR (1 << 1) | ||
84 | #define SAA7134_AV_STATUS_CONF_ERR (1 << 0) | ||
85 | |||
86 | /* interrupt */ | ||
87 | #define SAA7134_IRQ1 (0x2c4 >> 2) | ||
88 | #define SAA7134_IRQ1_INTE_RA3_1 (1 << 25) | ||
89 | #define SAA7134_IRQ1_INTE_RA3_0 (1 << 24) | ||
90 | #define SAA7134_IRQ1_INTE_RA2_3 (1 << 19) | ||
91 | #define SAA7134_IRQ1_INTE_RA2_2 (1 << 18) | ||
92 | #define SAA7134_IRQ1_INTE_RA2_1 (1 << 17) | ||
93 | #define SAA7134_IRQ1_INTE_RA2_0 (1 << 16) | ||
94 | #define SAA7134_IRQ1_INTE_RA1_3 (1 << 11) | ||
95 | #define SAA7134_IRQ1_INTE_RA1_2 (1 << 10) | ||
96 | #define SAA7134_IRQ1_INTE_RA1_1 (1 << 9) | ||
97 | #define SAA7134_IRQ1_INTE_RA1_0 (1 << 8) | ||
98 | #define SAA7134_IRQ1_INTE_RA0_7 (1 << 7) | ||
99 | #define SAA7134_IRQ1_INTE_RA0_6 (1 << 6) | ||
100 | #define SAA7134_IRQ1_INTE_RA0_5 (1 << 5) | ||
101 | #define SAA7134_IRQ1_INTE_RA0_4 (1 << 4) | ||
102 | #define SAA7134_IRQ1_INTE_RA0_3 (1 << 3) | ||
103 | #define SAA7134_IRQ1_INTE_RA0_2 (1 << 2) | ||
104 | #define SAA7134_IRQ1_INTE_RA0_1 (1 << 1) | ||
105 | #define SAA7134_IRQ1_INTE_RA0_0 (1 << 0) | ||
106 | |||
107 | #define SAA7134_IRQ2 (0x2c8 >> 2) | ||
108 | #define SAA7134_IRQ2_INTE_GPIO23A (1 << 17) | ||
109 | #define SAA7134_IRQ2_INTE_GPIO23 (1 << 16) | ||
110 | #define SAA7134_IRQ2_INTE_GPIO22A (1 << 15) | ||
111 | #define SAA7134_IRQ2_INTE_GPIO22 (1 << 14) | ||
112 | #define SAA7134_IRQ2_INTE_GPIO18A (1 << 13) | ||
113 | #define SAA7134_IRQ2_INTE_GPIO18 (1 << 12) | ||
114 | #define SAA7134_IRQ2_INTE_GPIO16 (1 << 11) /* not certain */ | ||
115 | #define SAA7134_IRQ2_INTE_SC2 (1 << 10) | ||
116 | #define SAA7134_IRQ2_INTE_SC1 (1 << 9) | ||
117 | #define SAA7134_IRQ2_INTE_SC0 (1 << 8) | ||
118 | #define SAA7134_IRQ2_INTE_DEC5 (1 << 7) | ||
119 | #define SAA7134_IRQ2_INTE_DEC4 (1 << 6) | ||
120 | #define SAA7134_IRQ2_INTE_DEC3 (1 << 5) | ||
121 | #define SAA7134_IRQ2_INTE_DEC2 (1 << 4) | ||
122 | #define SAA7134_IRQ2_INTE_DEC1 (1 << 3) | ||
123 | #define SAA7134_IRQ2_INTE_DEC0 (1 << 2) | ||
124 | #define SAA7134_IRQ2_INTE_PE (1 << 1) | ||
125 | #define SAA7134_IRQ2_INTE_AR (1 << 0) | ||
126 | |||
127 | #define SAA7134_IRQ_REPORT (0x2cc >> 2) | ||
128 | #define SAA7134_IRQ_REPORT_GPIO23 (1 << 17) | ||
129 | #define SAA7134_IRQ_REPORT_GPIO22 (1 << 16) | ||
130 | #define SAA7134_IRQ_REPORT_GPIO18 (1 << 15) | ||
131 | #define SAA7134_IRQ_REPORT_GPIO16 (1 << 14) /* not certain */ | ||
132 | #define SAA7134_IRQ_REPORT_LOAD_ERR (1 << 13) | ||
133 | #define SAA7134_IRQ_REPORT_CONF_ERR (1 << 12) | ||
134 | #define SAA7134_IRQ_REPORT_TRIG_ERR (1 << 11) | ||
135 | #define SAA7134_IRQ_REPORT_MMC (1 << 10) | ||
136 | #define SAA7134_IRQ_REPORT_FIDT (1 << 9) | ||
137 | #define SAA7134_IRQ_REPORT_INTL (1 << 8) | ||
138 | #define SAA7134_IRQ_REPORT_RDCAP (1 << 7) | ||
139 | #define SAA7134_IRQ_REPORT_PWR_ON (1 << 6) | ||
140 | #define SAA7134_IRQ_REPORT_PE (1 << 5) | ||
141 | #define SAA7134_IRQ_REPORT_AR (1 << 4) | ||
142 | #define SAA7134_IRQ_REPORT_DONE_RA3 (1 << 3) | ||
143 | #define SAA7134_IRQ_REPORT_DONE_RA2 (1 << 2) | ||
144 | #define SAA7134_IRQ_REPORT_DONE_RA1 (1 << 1) | ||
145 | #define SAA7134_IRQ_REPORT_DONE_RA0 (1 << 0) | ||
146 | #define SAA7134_IRQ_STATUS (0x2d0 >> 2) | ||
147 | |||
148 | |||
149 | /* ------------------------------------------------------------------ */ | ||
150 | /* | ||
151 | * registers -- 8 bit | ||
152 | */ | ||
153 | |||
154 | /* video decoder */ | ||
155 | #define SAA7134_INCR_DELAY 0x101 | ||
156 | #define SAA7134_ANALOG_IN_CTRL1 0x102 | ||
157 | #define SAA7134_ANALOG_IN_CTRL2 0x103 | ||
158 | #define SAA7134_ANALOG_IN_CTRL3 0x104 | ||
159 | #define SAA7134_ANALOG_IN_CTRL4 0x105 | ||
160 | #define SAA7134_HSYNC_START 0x106 | ||
161 | #define SAA7134_HSYNC_STOP 0x107 | ||
162 | #define SAA7134_SYNC_CTRL 0x108 | ||
163 | #define SAA7134_LUMA_CTRL 0x109 | ||
164 | #define SAA7134_DEC_LUMA_BRIGHT 0x10a | ||
165 | #define SAA7134_DEC_LUMA_CONTRAST 0x10b | ||
166 | #define SAA7134_DEC_CHROMA_SATURATION 0x10c | ||
167 | #define SAA7134_DEC_CHROMA_HUE 0x10d | ||
168 | #define SAA7134_CHROMA_CTRL1 0x10e | ||
169 | #define SAA7134_CHROMA_GAIN 0x10f | ||
170 | #define SAA7134_CHROMA_CTRL2 0x110 | ||
171 | #define SAA7134_MODE_DELAY_CTRL 0x111 | ||
172 | |||
173 | #define SAA7134_ANALOG_ADC 0x114 | ||
174 | #define SAA7134_VGATE_START 0x115 | ||
175 | #define SAA7134_VGATE_STOP 0x116 | ||
176 | #define SAA7134_MISC_VGATE_MSB 0x117 | ||
177 | #define SAA7134_RAW_DATA_GAIN 0x118 | ||
178 | #define SAA7134_RAW_DATA_OFFSET 0x119 | ||
179 | #define SAA7134_STATUS_VIDEO1 0x11e | ||
180 | #define SAA7134_STATUS_VIDEO2 0x11f | ||
181 | |||
182 | /* video scaler */ | ||
183 | #define SAA7134_SOURCE_TIMING1 0x000 | ||
184 | #define SAA7134_SOURCE_TIMING2 0x001 | ||
185 | #define SAA7134_REGION_ENABLE 0x004 | ||
186 | #define SAA7134_SCALER_STATUS0 0x006 | ||
187 | #define SAA7134_SCALER_STATUS1 0x007 | ||
188 | #define SAA7134_START_GREEN 0x00c | ||
189 | #define SAA7134_START_BLUE 0x00d | ||
190 | #define SAA7134_START_RED 0x00e | ||
191 | #define SAA7134_GREEN_PATH(x) (0x010 +x) | ||
192 | #define SAA7134_BLUE_PATH(x) (0x020 +x) | ||
193 | #define SAA7134_RED_PATH(x) (0x030 +x) | ||
194 | |||
195 | #define TASK_A 0x040 | ||
196 | #define TASK_B 0x080 | ||
197 | #define SAA7134_TASK_CONDITIONS(t) (0x000 +t) | ||
198 | #define SAA7134_FIELD_HANDLING(t) (0x001 +t) | ||
199 | #define SAA7134_DATA_PATH(t) (0x002 +t) | ||
200 | #define SAA7134_VBI_H_START1(t) (0x004 +t) | ||
201 | #define SAA7134_VBI_H_START2(t) (0x005 +t) | ||
202 | #define SAA7134_VBI_H_STOP1(t) (0x006 +t) | ||
203 | #define SAA7134_VBI_H_STOP2(t) (0x007 +t) | ||
204 | #define SAA7134_VBI_V_START1(t) (0x008 +t) | ||
205 | #define SAA7134_VBI_V_START2(t) (0x009 +t) | ||
206 | #define SAA7134_VBI_V_STOP1(t) (0x00a +t) | ||
207 | #define SAA7134_VBI_V_STOP2(t) (0x00b +t) | ||
208 | #define SAA7134_VBI_H_LEN1(t) (0x00c +t) | ||
209 | #define SAA7134_VBI_H_LEN2(t) (0x00d +t) | ||
210 | #define SAA7134_VBI_V_LEN1(t) (0x00e +t) | ||
211 | #define SAA7134_VBI_V_LEN2(t) (0x00f +t) | ||
212 | |||
213 | #define SAA7134_VIDEO_H_START1(t) (0x014 +t) | ||
214 | #define SAA7134_VIDEO_H_START2(t) (0x015 +t) | ||
215 | #define SAA7134_VIDEO_H_STOP1(t) (0x016 +t) | ||
216 | #define SAA7134_VIDEO_H_STOP2(t) (0x017 +t) | ||
217 | #define SAA7134_VIDEO_V_START1(t) (0x018 +t) | ||
218 | #define SAA7134_VIDEO_V_START2(t) (0x019 +t) | ||
219 | #define SAA7134_VIDEO_V_STOP1(t) (0x01a +t) | ||
220 | #define SAA7134_VIDEO_V_STOP2(t) (0x01b +t) | ||
221 | #define SAA7134_VIDEO_PIXELS1(t) (0x01c +t) | ||
222 | #define SAA7134_VIDEO_PIXELS2(t) (0x01d +t) | ||
223 | #define SAA7134_VIDEO_LINES1(t) (0x01e +t) | ||
224 | #define SAA7134_VIDEO_LINES2(t) (0x01f +t) | ||
225 | |||
226 | #define SAA7134_H_PRESCALE(t) (0x020 +t) | ||
227 | #define SAA7134_ACC_LENGTH(t) (0x021 +t) | ||
228 | #define SAA7134_LEVEL_CTRL(t) (0x022 +t) | ||
229 | #define SAA7134_FIR_PREFILTER_CTRL(t) (0x023 +t) | ||
230 | #define SAA7134_LUMA_BRIGHT(t) (0x024 +t) | ||
231 | #define SAA7134_LUMA_CONTRAST(t) (0x025 +t) | ||
232 | #define SAA7134_CHROMA_SATURATION(t) (0x026 +t) | ||
233 | #define SAA7134_VBI_H_SCALE_INC1(t) (0x028 +t) | ||
234 | #define SAA7134_VBI_H_SCALE_INC2(t) (0x029 +t) | ||
235 | #define SAA7134_VBI_PHASE_OFFSET_LUMA(t) (0x02a +t) | ||
236 | #define SAA7134_VBI_PHASE_OFFSET_CHROMA(t) (0x02b +t) | ||
237 | #define SAA7134_H_SCALE_INC1(t) (0x02c +t) | ||
238 | #define SAA7134_H_SCALE_INC2(t) (0x02d +t) | ||
239 | #define SAA7134_H_PHASE_OFF_LUMA(t) (0x02e +t) | ||
240 | #define SAA7134_H_PHASE_OFF_CHROMA(t) (0x02f +t) | ||
241 | #define SAA7134_V_SCALE_RATIO1(t) (0x030 +t) | ||
242 | #define SAA7134_V_SCALE_RATIO2(t) (0x031 +t) | ||
243 | #define SAA7134_V_FILTER(t) (0x032 +t) | ||
244 | #define SAA7134_V_PHASE_OFFSET0(t) (0x034 +t) | ||
245 | #define SAA7134_V_PHASE_OFFSET1(t) (0x035 +t) | ||
246 | #define SAA7134_V_PHASE_OFFSET2(t) (0x036 +t) | ||
247 | #define SAA7134_V_PHASE_OFFSET3(t) (0x037 +t) | ||
248 | |||
249 | /* clipping & dma */ | ||
250 | #define SAA7134_OFMT_VIDEO_A 0x300 | ||
251 | #define SAA7134_OFMT_DATA_A 0x301 | ||
252 | #define SAA7134_OFMT_VIDEO_B 0x302 | ||
253 | #define SAA7134_OFMT_DATA_B 0x303 | ||
254 | #define SAA7134_ALPHA_NOCLIP 0x304 | ||
255 | #define SAA7134_ALPHA_CLIP 0x305 | ||
256 | #define SAA7134_UV_PIXEL 0x308 | ||
257 | #define SAA7134_CLIP_RED 0x309 | ||
258 | #define SAA7134_CLIP_GREEN 0x30a | ||
259 | #define SAA7134_CLIP_BLUE 0x30b | ||
260 | |||
261 | /* i2c bus */ | ||
262 | #define SAA7134_I2C_ATTR_STATUS 0x180 | ||
263 | #define SAA7134_I2C_DATA 0x181 | ||
264 | #define SAA7134_I2C_CLOCK_SELECT 0x182 | ||
265 | #define SAA7134_I2C_TIMER 0x183 | ||
266 | |||
267 | /* audio */ | ||
268 | #define SAA7134_NICAM_ADD_DATA1 0x140 | ||
269 | #define SAA7134_NICAM_ADD_DATA2 0x141 | ||
270 | #define SAA7134_NICAM_STATUS 0x142 | ||
271 | #define SAA7134_AUDIO_STATUS 0x143 | ||
272 | #define SAA7134_NICAM_ERROR_COUNT 0x144 | ||
273 | #define SAA7134_IDENT_SIF 0x145 | ||
274 | #define SAA7134_LEVEL_READOUT1 0x146 | ||
275 | #define SAA7134_LEVEL_READOUT2 0x147 | ||
276 | #define SAA7134_NICAM_ERROR_LOW 0x148 | ||
277 | #define SAA7134_NICAM_ERROR_HIGH 0x149 | ||
278 | #define SAA7134_DCXO_IDENT_CTRL 0x14a | ||
279 | #define SAA7134_DEMODULATOR 0x14b | ||
280 | #define SAA7134_AGC_GAIN_SELECT 0x14c | ||
281 | #define SAA7134_CARRIER1_FREQ0 0x150 | ||
282 | #define SAA7134_CARRIER1_FREQ1 0x151 | ||
283 | #define SAA7134_CARRIER1_FREQ2 0x152 | ||
284 | #define SAA7134_CARRIER2_FREQ0 0x154 | ||
285 | #define SAA7134_CARRIER2_FREQ1 0x155 | ||
286 | #define SAA7134_CARRIER2_FREQ2 0x156 | ||
287 | #define SAA7134_NUM_SAMPLES0 0x158 | ||
288 | #define SAA7134_NUM_SAMPLES1 0x159 | ||
289 | #define SAA7134_NUM_SAMPLES2 0x15a | ||
290 | #define SAA7134_AUDIO_FORMAT_CTRL 0x15b | ||
291 | #define SAA7134_MONITOR_SELECT 0x160 | ||
292 | #define SAA7134_FM_DEEMPHASIS 0x161 | ||
293 | #define SAA7134_FM_DEMATRIX 0x162 | ||
294 | #define SAA7134_CHANNEL1_LEVEL 0x163 | ||
295 | #define SAA7134_CHANNEL2_LEVEL 0x164 | ||
296 | #define SAA7134_NICAM_CONFIG 0x165 | ||
297 | #define SAA7134_NICAM_LEVEL_ADJUST 0x166 | ||
298 | #define SAA7134_STEREO_DAC_OUTPUT_SELECT 0x167 | ||
299 | #define SAA7134_I2S_OUTPUT_FORMAT 0x168 | ||
300 | #define SAA7134_I2S_OUTPUT_SELECT 0x169 | ||
301 | #define SAA7134_I2S_OUTPUT_LEVEL 0x16a | ||
302 | #define SAA7134_DSP_OUTPUT_SELECT 0x16b | ||
303 | #define SAA7134_AUDIO_MUTE_CTRL 0x16c | ||
304 | #define SAA7134_SIF_SAMPLE_FREQ 0x16d | ||
305 | #define SAA7134_ANALOG_IO_SELECT 0x16e | ||
306 | #define SAA7134_AUDIO_CLOCK0 0x170 | ||
307 | #define SAA7134_AUDIO_CLOCK1 0x171 | ||
308 | #define SAA7134_AUDIO_CLOCK2 0x172 | ||
309 | #define SAA7134_AUDIO_PLL_CTRL 0x173 | ||
310 | #define SAA7134_AUDIO_CLOCKS_PER_FIELD0 0x174 | ||
311 | #define SAA7134_AUDIO_CLOCKS_PER_FIELD1 0x175 | ||
312 | #define SAA7134_AUDIO_CLOCKS_PER_FIELD2 0x176 | ||
313 | |||
314 | /* video port output */ | ||
315 | #define SAA7134_VIDEO_PORT_CTRL0 0x190 | ||
316 | #define SAA7134_VIDEO_PORT_CTRL1 0x191 | ||
317 | #define SAA7134_VIDEO_PORT_CTRL2 0x192 | ||
318 | #define SAA7134_VIDEO_PORT_CTRL3 0x193 | ||
319 | #define SAA7134_VIDEO_PORT_CTRL4 0x194 | ||
320 | #define SAA7134_VIDEO_PORT_CTRL5 0x195 | ||
321 | #define SAA7134_VIDEO_PORT_CTRL6 0x196 | ||
322 | #define SAA7134_VIDEO_PORT_CTRL7 0x197 | ||
323 | #define SAA7134_VIDEO_PORT_CTRL8 0x198 | ||
324 | |||
325 | /* transport stream interface */ | ||
326 | #define SAA7134_TS_PARALLEL 0x1a0 | ||
327 | #define SAA7134_TS_PARALLEL_SERIAL 0x1a1 | ||
328 | #define SAA7134_TS_SERIAL0 0x1a2 | ||
329 | #define SAA7134_TS_SERIAL1 0x1a3 | ||
330 | #define SAA7134_TS_DMA0 0x1a4 | ||
331 | #define SAA7134_TS_DMA1 0x1a5 | ||
332 | #define SAA7134_TS_DMA2 0x1a6 | ||
333 | |||
334 | /* GPIO Controls */ | ||
335 | #define SAA7134_GPIO_GPRESCAN 0x80 | ||
336 | #define SAA7134_GPIO_27_25 0x0E | ||
337 | |||
338 | #define SAA7134_GPIO_GPMODE0 0x1B0 | ||
339 | #define SAA7134_GPIO_GPMODE1 0x1B1 | ||
340 | #define SAA7134_GPIO_GPMODE2 0x1B2 | ||
341 | #define SAA7134_GPIO_GPMODE3 0x1B3 | ||
342 | #define SAA7134_GPIO_GPSTATUS0 0x1B4 | ||
343 | #define SAA7134_GPIO_GPSTATUS1 0x1B5 | ||
344 | #define SAA7134_GPIO_GPSTATUS2 0x1B6 | ||
345 | #define SAA7134_GPIO_GPSTATUS3 0x1B7 | ||
346 | |||
347 | /* I2S output */ | ||
348 | #define SAA7134_I2S_AUDIO_OUTPUT 0x1c0 | ||
349 | |||
350 | /* test modes */ | ||
351 | #define SAA7134_SPECIAL_MODE 0x1d0 | ||
352 | |||
353 | /* audio -- saa7133 + saa7135 only */ | ||
354 | #define SAA7135_DSP_RWSTATE 0x580 | ||
355 | #define SAA7135_DSP_RWSTATE_ERR (1 << 3) | ||
356 | #define SAA7135_DSP_RWSTATE_IDA (1 << 2) | ||
357 | #define SAA7135_DSP_RWSTATE_RDB (1 << 1) | ||
358 | #define SAA7135_DSP_RWSTATE_WRR (1 << 0) | ||
359 | |||
360 | /* ------------------------------------------------------------------ */ | ||
361 | /* | ||
362 | * Local variables: | ||
363 | * c-basic-offset: 8 | ||
364 | * End: | ||
365 | */ | ||
366 | |||
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c new file mode 100644 index 000000000000..345eb2a8c28d --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-ts.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * video4linux video interface | ||
6 | * | ||
7 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | |||
32 | #include "saa7134-reg.h" | ||
33 | #include "saa7134.h" | ||
34 | |||
35 | /* ------------------------------------------------------------------ */ | ||
36 | |||
37 | static unsigned int ts_debug = 0; | ||
38 | module_param(ts_debug, int, 0644); | ||
39 | MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]"); | ||
40 | |||
41 | #define dprintk(fmt, arg...) if (ts_debug) \ | ||
42 | printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg) | ||
43 | |||
44 | /* ------------------------------------------------------------------ */ | ||
45 | |||
46 | static int buffer_activate(struct saa7134_dev *dev, | ||
47 | struct saa7134_buf *buf, | ||
48 | struct saa7134_buf *next) | ||
49 | { | ||
50 | u32 control; | ||
51 | |||
52 | dprintk("buffer_activate [%p]",buf); | ||
53 | buf->vb.state = STATE_ACTIVE; | ||
54 | buf->top_seen = 0; | ||
55 | |||
56 | /* dma: setup channel 5 (= TS) */ | ||
57 | control = SAA7134_RS_CONTROL_BURST_16 | | ||
58 | SAA7134_RS_CONTROL_ME | | ||
59 | (buf->pt->dma >> 12); | ||
60 | |||
61 | if (NULL == next) | ||
62 | next = buf; | ||
63 | if (V4L2_FIELD_TOP == buf->vb.field) { | ||
64 | dprintk("- [top] buf=%p next=%p\n",buf,next); | ||
65 | saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf)); | ||
66 | saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next)); | ||
67 | } else { | ||
68 | dprintk("- [bottom] buf=%p next=%p\n",buf,next); | ||
69 | saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next)); | ||
70 | saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf)); | ||
71 | } | ||
72 | saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); | ||
73 | saa_writel(SAA7134_RS_CONTROL(5),control); | ||
74 | |||
75 | /* start DMA */ | ||
76 | saa7134_set_dmabits(dev); | ||
77 | |||
78 | mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, | ||
83 | enum v4l2_field field) | ||
84 | { | ||
85 | struct saa7134_dev *dev = q->priv_data; | ||
86 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
87 | unsigned int lines, llength, size; | ||
88 | int err; | ||
89 | |||
90 | dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]); | ||
91 | |||
92 | llength = TS_PACKET_SIZE; | ||
93 | lines = dev->ts.nr_packets; | ||
94 | |||
95 | size = lines * llength; | ||
96 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
97 | return -EINVAL; | ||
98 | |||
99 | if (buf->vb.size != size) { | ||
100 | saa7134_dma_free(dev,buf); | ||
101 | } | ||
102 | |||
103 | if (STATE_NEEDS_INIT == buf->vb.state) { | ||
104 | buf->vb.width = llength; | ||
105 | buf->vb.height = lines; | ||
106 | buf->vb.size = size; | ||
107 | buf->pt = &dev->ts.pt_ts; | ||
108 | |||
109 | err = videobuf_iolock(dev->pci,&buf->vb,NULL); | ||
110 | if (err) | ||
111 | goto oops; | ||
112 | err = saa7134_pgtable_build(dev->pci,buf->pt, | ||
113 | buf->vb.dma.sglist, | ||
114 | buf->vb.dma.sglen, | ||
115 | saa7134_buffer_startpage(buf)); | ||
116 | if (err) | ||
117 | goto oops; | ||
118 | } | ||
119 | buf->vb.state = STATE_PREPARED; | ||
120 | buf->activate = buffer_activate; | ||
121 | buf->vb.field = field; | ||
122 | return 0; | ||
123 | |||
124 | oops: | ||
125 | saa7134_dma_free(dev,buf); | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | static int | ||
130 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
131 | { | ||
132 | struct saa7134_dev *dev = q->priv_data; | ||
133 | |||
134 | *size = TS_PACKET_SIZE * dev->ts.nr_packets; | ||
135 | if (0 == *count) | ||
136 | *count = dev->ts.nr_bufs; | ||
137 | *count = saa7134_buffer_count(*size,*count); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
142 | { | ||
143 | struct saa7134_dev *dev = q->priv_data; | ||
144 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
145 | |||
146 | saa7134_buffer_queue(dev,&dev->ts_q,buf); | ||
147 | } | ||
148 | |||
149 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
150 | { | ||
151 | struct saa7134_dev *dev = q->priv_data; | ||
152 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
153 | |||
154 | saa7134_dma_free(dev,buf); | ||
155 | } | ||
156 | |||
157 | struct videobuf_queue_ops saa7134_ts_qops = { | ||
158 | .buf_setup = buffer_setup, | ||
159 | .buf_prepare = buffer_prepare, | ||
160 | .buf_queue = buffer_queue, | ||
161 | .buf_release = buffer_release, | ||
162 | }; | ||
163 | EXPORT_SYMBOL_GPL(saa7134_ts_qops); | ||
164 | |||
165 | /* ----------------------------------------------------------- */ | ||
166 | /* exported stuff */ | ||
167 | |||
168 | static unsigned int tsbufs = 4; | ||
169 | module_param(tsbufs, int, 0444); | ||
170 | MODULE_PARM_DESC(tsbufs,"number of ts buffers, range 2-32"); | ||
171 | |||
172 | static unsigned int ts_nr_packets = 30; | ||
173 | module_param(ts_nr_packets, int, 0444); | ||
174 | MODULE_PARM_DESC(ts_nr_packets,"size of a ts buffers (in ts packets)"); | ||
175 | |||
176 | int saa7134_ts_init1(struct saa7134_dev *dev) | ||
177 | { | ||
178 | /* sanitycheck insmod options */ | ||
179 | if (tsbufs < 2) | ||
180 | tsbufs = 2; | ||
181 | if (tsbufs > VIDEO_MAX_FRAME) | ||
182 | tsbufs = VIDEO_MAX_FRAME; | ||
183 | if (ts_nr_packets < 4) | ||
184 | ts_nr_packets = 4; | ||
185 | if (ts_nr_packets > 312) | ||
186 | ts_nr_packets = 312; | ||
187 | dev->ts.nr_bufs = tsbufs; | ||
188 | dev->ts.nr_packets = ts_nr_packets; | ||
189 | |||
190 | INIT_LIST_HEAD(&dev->ts_q.queue); | ||
191 | init_timer(&dev->ts_q.timeout); | ||
192 | dev->ts_q.timeout.function = saa7134_buffer_timeout; | ||
193 | dev->ts_q.timeout.data = (unsigned long)(&dev->ts_q); | ||
194 | dev->ts_q.dev = dev; | ||
195 | dev->ts_q.need_two = 1; | ||
196 | saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts); | ||
197 | |||
198 | /* init TS hw */ | ||
199 | saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* deactivate TS softreset */ | ||
200 | saa_writeb(SAA7134_TS_PARALLEL, 0xec); /* TSSOP high active, TSVAL high active, TSLOCK ignored */ | ||
201 | saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); | ||
202 | saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); | ||
203 | saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); | ||
204 | saa_writeb(SAA7134_TS_DMA2, ((((dev->ts.nr_packets-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ | ||
205 | |||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | int saa7134_ts_fini(struct saa7134_dev *dev) | ||
210 | { | ||
211 | saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | |||
216 | void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status) | ||
217 | { | ||
218 | enum v4l2_field field; | ||
219 | |||
220 | spin_lock(&dev->slock); | ||
221 | if (dev->ts_q.curr) { | ||
222 | field = dev->ts_q.curr->vb.field; | ||
223 | if (field == V4L2_FIELD_TOP) { | ||
224 | if ((status & 0x100000) != 0x000000) | ||
225 | goto done; | ||
226 | } else { | ||
227 | if ((status & 0x100000) != 0x100000) | ||
228 | goto done; | ||
229 | } | ||
230 | saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE); | ||
231 | } | ||
232 | saa7134_buffer_next(dev,&dev->ts_q); | ||
233 | |||
234 | done: | ||
235 | spin_unlock(&dev->slock); | ||
236 | } | ||
237 | |||
238 | /* ----------------------------------------------------------- */ | ||
239 | /* | ||
240 | * Local variables: | ||
241 | * c-basic-offset: 8 | ||
242 | * End: | ||
243 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c new file mode 100644 index 000000000000..ecac13c006d5 --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c | |||
@@ -0,0 +1,1031 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-tvaudio.c,v 1.22 2005/01/07 13:11:19 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * tv audio decoder (fm stereo, nicam, ...) | ||
6 | * | ||
7 | * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/smp_lock.h> | ||
32 | #include <asm/div64.h> | ||
33 | |||
34 | #include "saa7134-reg.h" | ||
35 | #include "saa7134.h" | ||
36 | |||
37 | /* ------------------------------------------------------------------ */ | ||
38 | |||
39 | static unsigned int audio_debug = 0; | ||
40 | module_param(audio_debug, int, 0644); | ||
41 | MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]"); | ||
42 | |||
43 | static unsigned int audio_ddep = 0; | ||
44 | module_param(audio_ddep, int, 0644); | ||
45 | MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite"); | ||
46 | |||
47 | static int audio_clock_override = UNSET; | ||
48 | module_param(audio_clock_override, int, 0644); | ||
49 | |||
50 | static int audio_clock_tweak = 0; | ||
51 | module_param(audio_clock_tweak, int, 0644); | ||
52 | MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])"); | ||
53 | |||
54 | #define dprintk(fmt, arg...) if (audio_debug) \ | ||
55 | printk(KERN_DEBUG "%s/audio: " fmt, dev->name , ## arg) | ||
56 | #define d2printk(fmt, arg...) if (audio_debug > 1) \ | ||
57 | printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg) | ||
58 | |||
59 | #define print_regb(reg) printk("%s: reg 0x%03x [%-16s]: 0x%02x\n", \ | ||
60 | dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg))) | ||
61 | |||
62 | /* msecs */ | ||
63 | #define SCAN_INITIAL_DELAY 1000 | ||
64 | #define SCAN_SAMPLE_DELAY 200 | ||
65 | #define SCAN_SUBCARRIER_DELAY 2000 | ||
66 | |||
67 | /* ------------------------------------------------------------------ */ | ||
68 | /* saa7134 code */ | ||
69 | |||
70 | static struct mainscan { | ||
71 | char *name; | ||
72 | v4l2_std_id std; | ||
73 | int carr; | ||
74 | } mainscan[] = { | ||
75 | { | ||
76 | .name = "M", | ||
77 | .std = V4L2_STD_NTSC | V4L2_STD_PAL_M, | ||
78 | .carr = 4500, | ||
79 | },{ | ||
80 | .name = "BG", | ||
81 | .std = V4L2_STD_PAL_BG, | ||
82 | .carr = 5500, | ||
83 | },{ | ||
84 | .name = "I", | ||
85 | .std = V4L2_STD_PAL_I, | ||
86 | .carr = 6000, | ||
87 | },{ | ||
88 | .name = "DKL", | ||
89 | .std = V4L2_STD_PAL_DK | V4L2_STD_SECAM, | ||
90 | .carr = 6500, | ||
91 | } | ||
92 | }; | ||
93 | |||
94 | static struct saa7134_tvaudio tvaudio[] = { | ||
95 | { | ||
96 | .name = "PAL-B/G FM-stereo", | ||
97 | .std = V4L2_STD_PAL, | ||
98 | .mode = TVAUDIO_FM_BG_STEREO, | ||
99 | .carr1 = 5500, | ||
100 | .carr2 = 5742, | ||
101 | },{ | ||
102 | .name = "PAL-D/K1 FM-stereo", | ||
103 | .std = V4L2_STD_PAL, | ||
104 | .carr1 = 6500, | ||
105 | .carr2 = 6258, | ||
106 | .mode = TVAUDIO_FM_BG_STEREO, | ||
107 | },{ | ||
108 | .name = "PAL-D/K2 FM-stereo", | ||
109 | .std = V4L2_STD_PAL, | ||
110 | .carr1 = 6500, | ||
111 | .carr2 = 6742, | ||
112 | .mode = TVAUDIO_FM_BG_STEREO, | ||
113 | },{ | ||
114 | .name = "PAL-D/K3 FM-stereo", | ||
115 | .std = V4L2_STD_PAL, | ||
116 | .carr1 = 6500, | ||
117 | .carr2 = 5742, | ||
118 | .mode = TVAUDIO_FM_BG_STEREO, | ||
119 | },{ | ||
120 | .name = "PAL-B/G NICAM", | ||
121 | .std = V4L2_STD_PAL, | ||
122 | .carr1 = 5500, | ||
123 | .carr2 = 5850, | ||
124 | .mode = TVAUDIO_NICAM_FM, | ||
125 | },{ | ||
126 | .name = "PAL-I NICAM", | ||
127 | .std = V4L2_STD_PAL, | ||
128 | .carr1 = 6000, | ||
129 | .carr2 = 6552, | ||
130 | .mode = TVAUDIO_NICAM_FM, | ||
131 | },{ | ||
132 | .name = "PAL-D/K NICAM", | ||
133 | .std = V4L2_STD_PAL, | ||
134 | .carr1 = 6500, | ||
135 | .carr2 = 5850, | ||
136 | .mode = TVAUDIO_NICAM_FM, | ||
137 | },{ | ||
138 | .name = "SECAM-L NICAM", | ||
139 | .std = V4L2_STD_SECAM, | ||
140 | .carr1 = 6500, | ||
141 | .carr2 = 5850, | ||
142 | .mode = TVAUDIO_NICAM_AM, | ||
143 | },{ | ||
144 | .name = "SECAM-D/K", | ||
145 | .std = V4L2_STD_SECAM, | ||
146 | .carr1 = 6500, | ||
147 | .carr2 = -1, | ||
148 | .mode = TVAUDIO_FM_MONO, | ||
149 | },{ | ||
150 | .name = "NTSC-M", | ||
151 | .std = V4L2_STD_NTSC, | ||
152 | .carr1 = 4500, | ||
153 | .carr2 = -1, | ||
154 | .mode = TVAUDIO_FM_MONO, | ||
155 | },{ | ||
156 | .name = "NTSC-A2 FM-stereo", | ||
157 | .std = V4L2_STD_NTSC, | ||
158 | .carr1 = 4500, | ||
159 | .carr2 = 4724, | ||
160 | .mode = TVAUDIO_FM_K_STEREO, | ||
161 | } | ||
162 | }; | ||
163 | #define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio)) | ||
164 | |||
165 | /* ------------------------------------------------------------------ */ | ||
166 | |||
167 | static void tvaudio_init(struct saa7134_dev *dev) | ||
168 | { | ||
169 | int clock = saa7134_boards[dev->board].audio_clock; | ||
170 | |||
171 | if (UNSET != audio_clock_override) | ||
172 | clock = audio_clock_override; | ||
173 | |||
174 | /* init all audio registers */ | ||
175 | saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00); | ||
176 | if (need_resched()) | ||
177 | schedule(); | ||
178 | else | ||
179 | udelay(10); | ||
180 | |||
181 | saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff); | ||
182 | saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff); | ||
183 | saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff); | ||
184 | saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01); | ||
185 | |||
186 | saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14); | ||
187 | saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50); | ||
188 | saa_writeb(SAA7134_MONITOR_SELECT, 0xa0); | ||
189 | saa_writeb(SAA7134_FM_DEMATRIX, 0x80); | ||
190 | } | ||
191 | |||
192 | static u32 tvaudio_carr2reg(u32 carrier) | ||
193 | { | ||
194 | u64 a = carrier; | ||
195 | |||
196 | a <<= 24; | ||
197 | do_div(a,12288); | ||
198 | return a; | ||
199 | } | ||
200 | |||
201 | static void tvaudio_setcarrier(struct saa7134_dev *dev, | ||
202 | int primary, int secondary) | ||
203 | { | ||
204 | if (-1 == secondary) | ||
205 | secondary = primary; | ||
206 | saa_writel(SAA7134_CARRIER1_FREQ0 >> 2, tvaudio_carr2reg(primary)); | ||
207 | saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary)); | ||
208 | } | ||
209 | |||
210 | static void mute_input_7134(struct saa7134_dev *dev) | ||
211 | { | ||
212 | unsigned int mute; | ||
213 | struct saa7134_input *in; | ||
214 | int ausel=0, ics=0, ocs=0; | ||
215 | int mask; | ||
216 | |||
217 | /* look what is to do ... */ | ||
218 | in = dev->input; | ||
219 | mute = (dev->ctl_mute || | ||
220 | (dev->automute && (&card(dev).radio) != in)); | ||
221 | if (PCI_DEVICE_ID_PHILIPS_SAA7130 == dev->pci->device && | ||
222 | card(dev).mute.name) { | ||
223 | /* 7130 - we'll mute using some unconnected audio input */ | ||
224 | if (mute) | ||
225 | in = &card(dev).mute; | ||
226 | } | ||
227 | if (dev->hw_mute == mute && | ||
228 | dev->hw_input == in) { | ||
229 | dprintk("mute/input: nothing to do [mute=%d,input=%s]\n", | ||
230 | mute,in->name); | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | dprintk("ctl_mute=%d automute=%d input=%s => mute=%d input=%s\n", | ||
235 | dev->ctl_mute,dev->automute,dev->input->name,mute,in->name); | ||
236 | dev->hw_mute = mute; | ||
237 | dev->hw_input = in; | ||
238 | |||
239 | if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device) | ||
240 | /* 7134 mute */ | ||
241 | saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xbf : 0xbb); | ||
242 | |||
243 | /* switch internal audio mux */ | ||
244 | switch (in->amux) { | ||
245 | case TV: ausel=0xc0; ics=0x00; ocs=0x02; break; | ||
246 | case LINE1: ausel=0x80; ics=0x00; ocs=0x00; break; | ||
247 | case LINE2: ausel=0x80; ics=0x08; ocs=0x01; break; | ||
248 | case LINE2_LEFT: ausel=0x80; ics=0x08; ocs=0x05; break; | ||
249 | } | ||
250 | saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel); | ||
251 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics); | ||
252 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs); | ||
253 | |||
254 | /* switch gpio-connected external audio mux */ | ||
255 | if (0 == card(dev).gpiomask) | ||
256 | return; | ||
257 | mask = card(dev).gpiomask; | ||
258 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); | ||
259 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio); | ||
260 | saa7134_track_gpio(dev,in->name); | ||
261 | } | ||
262 | |||
263 | static void tvaudio_setmode(struct saa7134_dev *dev, | ||
264 | struct saa7134_tvaudio *audio, | ||
265 | char *note) | ||
266 | { | ||
267 | int acpf, tweak = 0; | ||
268 | |||
269 | if (dev->tvnorm->id == V4L2_STD_NTSC) { | ||
270 | acpf = 0x19066; | ||
271 | } else { | ||
272 | acpf = 0x1e000; | ||
273 | } | ||
274 | if (audio_clock_tweak > -1024 && audio_clock_tweak < 1024) | ||
275 | tweak = audio_clock_tweak; | ||
276 | |||
277 | if (note) | ||
278 | dprintk("tvaudio_setmode: %s %s [%d.%03d/%d.%03d MHz] acpf=%d%+d\n", | ||
279 | note,audio->name, | ||
280 | audio->carr1 / 1000, audio->carr1 % 1000, | ||
281 | audio->carr2 / 1000, audio->carr2 % 1000, | ||
282 | acpf, tweak); | ||
283 | |||
284 | acpf += tweak; | ||
285 | saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD0, (acpf & 0x0000ff) >> 0); | ||
286 | saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD1, (acpf & 0x00ff00) >> 8); | ||
287 | saa_writeb(SAA7134_AUDIO_CLOCKS_PER_FIELD2, (acpf & 0x030000) >> 16); | ||
288 | tvaudio_setcarrier(dev,audio->carr1,audio->carr2); | ||
289 | |||
290 | switch (audio->mode) { | ||
291 | case TVAUDIO_FM_MONO: | ||
292 | case TVAUDIO_FM_BG_STEREO: | ||
293 | saa_writeb(SAA7134_DEMODULATOR, 0x00); | ||
294 | saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); | ||
295 | saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22); | ||
296 | saa_writeb(SAA7134_FM_DEMATRIX, 0x80); | ||
297 | saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); | ||
298 | break; | ||
299 | case TVAUDIO_FM_K_STEREO: | ||
300 | saa_writeb(SAA7134_DEMODULATOR, 0x00); | ||
301 | saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x01); | ||
302 | saa_writeb(SAA7134_FM_DEEMPHASIS, 0x22); | ||
303 | saa_writeb(SAA7134_FM_DEMATRIX, 0x80); | ||
304 | saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); | ||
305 | break; | ||
306 | case TVAUDIO_NICAM_FM: | ||
307 | saa_writeb(SAA7134_DEMODULATOR, 0x10); | ||
308 | saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); | ||
309 | saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); | ||
310 | saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); | ||
311 | saa_writeb(SAA7134_NICAM_CONFIG, 0x00); | ||
312 | break; | ||
313 | case TVAUDIO_NICAM_AM: | ||
314 | saa_writeb(SAA7134_DEMODULATOR, 0x12); | ||
315 | saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); | ||
316 | saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); | ||
317 | saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); | ||
318 | saa_writeb(SAA7134_NICAM_CONFIG, 0x00); | ||
319 | break; | ||
320 | case TVAUDIO_FM_SAT_STEREO: | ||
321 | /* not implemented (yet) */ | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | |||
326 | static int tvaudio_sleep(struct saa7134_dev *dev, int timeout) | ||
327 | { | ||
328 | DECLARE_WAITQUEUE(wait, current); | ||
329 | |||
330 | add_wait_queue(&dev->thread.wq, &wait); | ||
331 | if (dev->thread.scan1 == dev->thread.scan2 && !dev->thread.shutdown) { | ||
332 | if (timeout < 0) { | ||
333 | set_current_state(TASK_INTERRUPTIBLE); | ||
334 | schedule(); | ||
335 | } else { | ||
336 | #if 0 | ||
337 | /* hmm, that one doesn't return on wakeup ... */ | ||
338 | msleep_interruptible(timeout); | ||
339 | #else | ||
340 | set_current_state(TASK_INTERRUPTIBLE); | ||
341 | schedule_timeout(msecs_to_jiffies(timeout)); | ||
342 | #endif | ||
343 | } | ||
344 | } | ||
345 | remove_wait_queue(&dev->thread.wq, &wait); | ||
346 | return dev->thread.scan1 != dev->thread.scan2; | ||
347 | } | ||
348 | |||
349 | static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan) | ||
350 | { | ||
351 | __s32 left,right,value; | ||
352 | |||
353 | if (audio_debug > 1) { | ||
354 | int i; | ||
355 | dprintk("debug %d:",scan->carr); | ||
356 | for (i = -150; i <= 150; i += 30) { | ||
357 | tvaudio_setcarrier(dev,scan->carr+i,scan->carr+i); | ||
358 | saa_readl(SAA7134_LEVEL_READOUT1 >> 2); | ||
359 | if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) | ||
360 | return -1; | ||
361 | value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); | ||
362 | if (0 == i) | ||
363 | printk(" # %6d # ",value >> 16); | ||
364 | else | ||
365 | printk(" %6d",value >> 16); | ||
366 | } | ||
367 | printk("\n"); | ||
368 | } | ||
369 | |||
370 | if (dev->tvnorm->id & scan->std) { | ||
371 | tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90); | ||
372 | saa_readl(SAA7134_LEVEL_READOUT1 >> 2); | ||
373 | if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) | ||
374 | return -1; | ||
375 | left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); | ||
376 | |||
377 | tvaudio_setcarrier(dev,scan->carr+90,scan->carr+90); | ||
378 | saa_readl(SAA7134_LEVEL_READOUT1 >> 2); | ||
379 | if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY)) | ||
380 | return -1; | ||
381 | right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2); | ||
382 | |||
383 | left >>= 16; | ||
384 | right >>= 16; | ||
385 | value = left > right ? left - right : right - left; | ||
386 | dprintk("scanning %d.%03d MHz [%4s] => dc is %5d [%d/%d]\n", | ||
387 | scan->carr / 1000, scan->carr % 1000, | ||
388 | scan->name, value, left, right); | ||
389 | } else { | ||
390 | value = 0; | ||
391 | dprintk("skipping %d.%03d MHz [%4s]\n", | ||
392 | scan->carr / 1000, scan->carr % 1000, scan->name); | ||
393 | } | ||
394 | return value; | ||
395 | } | ||
396 | |||
397 | #if 0 | ||
398 | static void sifdebug_dump_regs(struct saa7134_dev *dev) | ||
399 | { | ||
400 | print_regb(AUDIO_STATUS); | ||
401 | print_regb(IDENT_SIF); | ||
402 | print_regb(LEVEL_READOUT1); | ||
403 | print_regb(LEVEL_READOUT2); | ||
404 | print_regb(DCXO_IDENT_CTRL); | ||
405 | print_regb(DEMODULATOR); | ||
406 | print_regb(AGC_GAIN_SELECT); | ||
407 | print_regb(MONITOR_SELECT); | ||
408 | print_regb(FM_DEEMPHASIS); | ||
409 | print_regb(FM_DEMATRIX); | ||
410 | print_regb(SIF_SAMPLE_FREQ); | ||
411 | print_regb(ANALOG_IO_SELECT); | ||
412 | } | ||
413 | #endif | ||
414 | |||
415 | static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio) | ||
416 | { | ||
417 | __u32 idp,nicam; | ||
418 | int retval = -1; | ||
419 | |||
420 | switch (audio->mode) { | ||
421 | case TVAUDIO_FM_MONO: | ||
422 | return V4L2_TUNER_SUB_MONO; | ||
423 | case TVAUDIO_FM_K_STEREO: | ||
424 | case TVAUDIO_FM_BG_STEREO: | ||
425 | idp = (saa_readb(SAA7134_IDENT_SIF) & 0xe0) >> 5; | ||
426 | dprintk("getstereo: fm/stereo: idp=0x%x\n",idp); | ||
427 | if (0x03 == (idp & 0x03)) | ||
428 | retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
429 | else if (0x05 == (idp & 0x05)) | ||
430 | retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
431 | else if (0x01 == (idp & 0x01)) | ||
432 | retval = V4L2_TUNER_SUB_MONO; | ||
433 | break; | ||
434 | case TVAUDIO_FM_SAT_STEREO: | ||
435 | /* not implemented (yet) */ | ||
436 | break; | ||
437 | case TVAUDIO_NICAM_FM: | ||
438 | case TVAUDIO_NICAM_AM: | ||
439 | nicam = saa_readb(SAA7134_NICAM_STATUS); | ||
440 | dprintk("getstereo: nicam=0x%x\n",nicam); | ||
441 | switch (nicam & 0x0b) { | ||
442 | case 0x09: | ||
443 | retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
444 | break; | ||
445 | case 0x0a: | ||
446 | retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
447 | break; | ||
448 | case 0x08: | ||
449 | default: | ||
450 | retval = V4L2_TUNER_SUB_MONO; | ||
451 | break; | ||
452 | } | ||
453 | break; | ||
454 | } | ||
455 | if (retval != -1) | ||
456 | dprintk("found audio subchannels:%s%s%s%s\n", | ||
457 | (retval & V4L2_TUNER_SUB_MONO) ? " mono" : "", | ||
458 | (retval & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", | ||
459 | (retval & V4L2_TUNER_SUB_LANG1) ? " lang1" : "", | ||
460 | (retval & V4L2_TUNER_SUB_LANG2) ? " lang2" : ""); | ||
461 | return retval; | ||
462 | } | ||
463 | |||
464 | static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio, | ||
465 | u32 mode) | ||
466 | { | ||
467 | static char *name[] = { | ||
468 | [ V4L2_TUNER_MODE_MONO ] = "mono", | ||
469 | [ V4L2_TUNER_MODE_STEREO ] = "stereo", | ||
470 | [ V4L2_TUNER_MODE_LANG1 ] = "lang1", | ||
471 | [ V4L2_TUNER_MODE_LANG2 ] = "lang2", | ||
472 | }; | ||
473 | static u32 fm[] = { | ||
474 | [ V4L2_TUNER_MODE_MONO ] = 0x00, /* ch1 */ | ||
475 | [ V4L2_TUNER_MODE_STEREO ] = 0x80, /* auto */ | ||
476 | [ V4L2_TUNER_MODE_LANG1 ] = 0x00, /* ch1 */ | ||
477 | [ V4L2_TUNER_MODE_LANG2 ] = 0x01, /* ch2 */ | ||
478 | }; | ||
479 | u32 reg; | ||
480 | |||
481 | switch (audio->mode) { | ||
482 | case TVAUDIO_FM_MONO: | ||
483 | /* nothing to do ... */ | ||
484 | break; | ||
485 | case TVAUDIO_FM_K_STEREO: | ||
486 | case TVAUDIO_FM_BG_STEREO: | ||
487 | dprintk("setstereo [fm] => %s\n", | ||
488 | name[ mode % ARRAY_SIZE(name) ]); | ||
489 | reg = fm[ mode % ARRAY_SIZE(fm) ]; | ||
490 | saa_writeb(SAA7134_FM_DEMATRIX, reg); | ||
491 | break; | ||
492 | case TVAUDIO_FM_SAT_STEREO: | ||
493 | case TVAUDIO_NICAM_AM: | ||
494 | case TVAUDIO_NICAM_FM: | ||
495 | /* FIXME */ | ||
496 | break; | ||
497 | } | ||
498 | return 0; | ||
499 | } | ||
500 | |||
501 | static int tvaudio_thread(void *data) | ||
502 | { | ||
503 | struct saa7134_dev *dev = data; | ||
504 | int carr_vals[ARRAY_SIZE(mainscan)]; | ||
505 | unsigned int i, audio, nscan; | ||
506 | int max1,max2,carrier,rx,mode,lastmode,default_carrier; | ||
507 | |||
508 | daemonize("%s", dev->name); | ||
509 | allow_signal(SIGTERM); | ||
510 | for (;;) { | ||
511 | tvaudio_sleep(dev,-1); | ||
512 | if (dev->thread.shutdown || signal_pending(current)) | ||
513 | goto done; | ||
514 | |||
515 | restart: | ||
516 | dev->thread.scan1 = dev->thread.scan2; | ||
517 | dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); | ||
518 | dev->tvaudio = NULL; | ||
519 | tvaudio_init(dev); | ||
520 | if (dev->ctl_automute) | ||
521 | dev->automute = 1; | ||
522 | mute_input_7134(dev); | ||
523 | |||
524 | /* give the tuner some time */ | ||
525 | if (tvaudio_sleep(dev,SCAN_INITIAL_DELAY)) | ||
526 | goto restart; | ||
527 | |||
528 | max1 = 0; | ||
529 | max2 = 0; | ||
530 | nscan = 0; | ||
531 | carrier = 0; | ||
532 | default_carrier = 0; | ||
533 | for (i = 0; i < ARRAY_SIZE(mainscan); i++) { | ||
534 | if (!(dev->tvnorm->id & mainscan[i].std)) | ||
535 | continue; | ||
536 | if (!default_carrier) | ||
537 | default_carrier = mainscan[i].carr; | ||
538 | nscan++; | ||
539 | } | ||
540 | |||
541 | if (1 == nscan) { | ||
542 | /* only one candidate -- skip scan ;) */ | ||
543 | max1 = 12345; | ||
544 | carrier = default_carrier; | ||
545 | } else { | ||
546 | /* scan for the main carrier */ | ||
547 | saa_writeb(SAA7134_MONITOR_SELECT,0x00); | ||
548 | tvaudio_setmode(dev,&tvaudio[0],NULL); | ||
549 | for (i = 0; i < ARRAY_SIZE(mainscan); i++) { | ||
550 | carr_vals[i] = tvaudio_checkcarrier(dev, mainscan+i); | ||
551 | if (dev->thread.scan1 != dev->thread.scan2) | ||
552 | goto restart; | ||
553 | } | ||
554 | for (max1 = 0, max2 = 0, i = 0; i < ARRAY_SIZE(mainscan); i++) { | ||
555 | if (max1 < carr_vals[i]) { | ||
556 | max2 = max1; | ||
557 | max1 = carr_vals[i]; | ||
558 | carrier = mainscan[i].carr; | ||
559 | } else if (max2 < carr_vals[i]) { | ||
560 | max2 = carr_vals[i]; | ||
561 | } | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (0 != carrier && max1 > 2000 && max1 > max2*3) { | ||
566 | /* found good carrier */ | ||
567 | dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n", | ||
568 | dev->tvnorm->name, carrier/1000, carrier%1000, | ||
569 | max1, max2); | ||
570 | dev->last_carrier = carrier; | ||
571 | |||
572 | } else if (0 != dev->last_carrier) { | ||
573 | /* no carrier -- try last detected one as fallback */ | ||
574 | carrier = dev->last_carrier; | ||
575 | printk(KERN_WARNING "%s/audio: audio carrier scan failed, " | ||
576 | "using %d.%03d MHz [last detected]\n", | ||
577 | dev->name, carrier/1000, carrier%1000); | ||
578 | |||
579 | } else { | ||
580 | /* no carrier + no fallback -- use default */ | ||
581 | carrier = default_carrier; | ||
582 | printk(KERN_WARNING "%s/audio: audio carrier scan failed, " | ||
583 | "using %d.%03d MHz [default]\n", | ||
584 | dev->name, carrier/1000, carrier%1000); | ||
585 | } | ||
586 | tvaudio_setcarrier(dev,carrier,carrier); | ||
587 | dev->automute = 0; | ||
588 | saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00); | ||
589 | saa7134_tvaudio_setmute(dev); | ||
590 | |||
591 | /* find the exact tv audio norm */ | ||
592 | for (audio = UNSET, i = 0; i < TVAUDIO; i++) { | ||
593 | if (dev->tvnorm->id != UNSET && | ||
594 | !(dev->tvnorm->id & tvaudio[i].std)) | ||
595 | continue; | ||
596 | if (tvaudio[i].carr1 != carrier) | ||
597 | continue; | ||
598 | |||
599 | if (UNSET == audio) | ||
600 | audio = i; | ||
601 | tvaudio_setmode(dev,&tvaudio[i],"trying"); | ||
602 | if (tvaudio_sleep(dev,SCAN_SUBCARRIER_DELAY)) | ||
603 | goto restart; | ||
604 | if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) { | ||
605 | audio = i; | ||
606 | break; | ||
607 | } | ||
608 | } | ||
609 | saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30); | ||
610 | if (UNSET == audio) | ||
611 | continue; | ||
612 | tvaudio_setmode(dev,&tvaudio[audio],"using"); | ||
613 | tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO); | ||
614 | dev->tvaudio = &tvaudio[audio]; | ||
615 | |||
616 | lastmode = 42; | ||
617 | for (;;) { | ||
618 | if (tvaudio_sleep(dev,5000)) | ||
619 | goto restart; | ||
620 | if (dev->thread.shutdown || signal_pending(current)) | ||
621 | break; | ||
622 | if (UNSET == dev->thread.mode) { | ||
623 | rx = tvaudio_getstereo(dev,&tvaudio[i]); | ||
624 | mode = saa7134_tvaudio_rx2mode(rx); | ||
625 | } else { | ||
626 | mode = dev->thread.mode; | ||
627 | } | ||
628 | if (lastmode != mode) { | ||
629 | tvaudio_setstereo(dev,&tvaudio[audio],mode); | ||
630 | lastmode = mode; | ||
631 | } | ||
632 | } | ||
633 | } | ||
634 | |||
635 | done: | ||
636 | complete_and_exit(&dev->thread.exit, 0); | ||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | /* ------------------------------------------------------------------ */ | ||
641 | /* saa7133 / saa7135 code */ | ||
642 | |||
643 | static char *stdres[0x20] = { | ||
644 | [0x00] = "no standard detected", | ||
645 | [0x01] = "B/G (in progress)", | ||
646 | [0x02] = "D/K (in progress)", | ||
647 | [0x03] = "M (in progress)", | ||
648 | |||
649 | [0x04] = "B/G A2", | ||
650 | [0x05] = "B/G NICAM", | ||
651 | [0x06] = "D/K A2 (1)", | ||
652 | [0x07] = "D/K A2 (2)", | ||
653 | [0x08] = "D/K A2 (3)", | ||
654 | [0x09] = "D/K NICAM", | ||
655 | [0x0a] = "L NICAM", | ||
656 | [0x0b] = "I NICAM", | ||
657 | |||
658 | [0x0c] = "M Korea", | ||
659 | [0x0d] = "M BTSC ", | ||
660 | [0x0e] = "M EIAJ", | ||
661 | |||
662 | [0x0f] = "FM radio / IF 10.7 / 50 deemp", | ||
663 | [0x10] = "FM radio / IF 10.7 / 75 deemp", | ||
664 | [0x11] = "FM radio / IF sel / 50 deemp", | ||
665 | [0x12] = "FM radio / IF sel / 75 deemp", | ||
666 | |||
667 | [0x13 ... 0x1e ] = "unknown", | ||
668 | [0x1f] = "??? [in progress]", | ||
669 | }; | ||
670 | |||
671 | #define DSP_RETRY 32 | ||
672 | #define DSP_DELAY 16 | ||
673 | |||
674 | static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit) | ||
675 | { | ||
676 | int state, count = DSP_RETRY; | ||
677 | |||
678 | state = saa_readb(SAA7135_DSP_RWSTATE); | ||
679 | if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) { | ||
680 | printk("%s: dsp access error\n",dev->name); | ||
681 | /* FIXME: send ack ... */ | ||
682 | return -EIO; | ||
683 | } | ||
684 | while (0 == (state & bit)) { | ||
685 | if (unlikely(0 == count)) { | ||
686 | printk("%s: dsp access wait timeout [bit=%s]\n", | ||
687 | dev->name, | ||
688 | (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" : | ||
689 | (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" : | ||
690 | (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" : | ||
691 | "???"); | ||
692 | return -EIO; | ||
693 | } | ||
694 | saa_wait(DSP_DELAY); | ||
695 | state = saa_readb(SAA7135_DSP_RWSTATE); | ||
696 | count--; | ||
697 | } | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | #if 0 | ||
702 | static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value) | ||
703 | { | ||
704 | int err; | ||
705 | |||
706 | d2printk("dsp read reg 0x%x\n", reg<<2); | ||
707 | saa_readl(reg); | ||
708 | err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB); | ||
709 | if (err < 0) | ||
710 | return err; | ||
711 | *value = saa_readl(reg); | ||
712 | d2printk("dsp read => 0x%06x\n", *value & 0xffffff); | ||
713 | err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA); | ||
714 | if (err < 0) | ||
715 | return err; | ||
716 | return 0; | ||
717 | } | ||
718 | #endif | ||
719 | |||
720 | int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value) | ||
721 | { | ||
722 | int err; | ||
723 | |||
724 | d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value); | ||
725 | err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); | ||
726 | if (err < 0) | ||
727 | return err; | ||
728 | saa_writel(reg,value); | ||
729 | err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR); | ||
730 | if (err < 0) | ||
731 | return err; | ||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | static int getstereo_7133(struct saa7134_dev *dev) | ||
736 | { | ||
737 | int retval = V4L2_TUNER_SUB_MONO; | ||
738 | u32 value; | ||
739 | |||
740 | value = saa_readl(0x528 >> 2); | ||
741 | if (value & 0x20) | ||
742 | retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
743 | if (value & 0x40) | ||
744 | retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
745 | return retval; | ||
746 | } | ||
747 | |||
748 | static int mute_input_7133(struct saa7134_dev *dev) | ||
749 | { | ||
750 | u32 reg = 0; | ||
751 | int mask; | ||
752 | |||
753 | switch (dev->input->amux) { | ||
754 | case TV: | ||
755 | reg = 0x02; | ||
756 | break; | ||
757 | case LINE1: | ||
758 | reg = 0x00; | ||
759 | break; | ||
760 | case LINE2: | ||
761 | case LINE2_LEFT: | ||
762 | reg = 0x01; | ||
763 | break; | ||
764 | } | ||
765 | if (dev->ctl_mute) | ||
766 | reg = 0x07; | ||
767 | saa_writel(0x594 >> 2, reg); | ||
768 | |||
769 | /* switch gpio-connected external audio mux */ | ||
770 | if (0 != card(dev).gpiomask) { | ||
771 | mask = card(dev).gpiomask; | ||
772 | saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask); | ||
773 | saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, dev->input->gpio); | ||
774 | saa7134_track_gpio(dev,dev->input->name); | ||
775 | } | ||
776 | return 0; | ||
777 | } | ||
778 | |||
779 | static int tvaudio_thread_ddep(void *data) | ||
780 | { | ||
781 | struct saa7134_dev *dev = data; | ||
782 | u32 value, norms, clock; | ||
783 | |||
784 | daemonize("%s", dev->name); | ||
785 | allow_signal(SIGTERM); | ||
786 | |||
787 | clock = saa7134_boards[dev->board].audio_clock; | ||
788 | if (UNSET != audio_clock_override) | ||
789 | clock = audio_clock_override; | ||
790 | saa_writel(0x598 >> 2, clock); | ||
791 | |||
792 | /* unmute */ | ||
793 | saa_dsp_writel(dev, 0x474 >> 2, 0x00); | ||
794 | saa_dsp_writel(dev, 0x450 >> 2, 0x00); | ||
795 | |||
796 | for (;;) { | ||
797 | tvaudio_sleep(dev,-1); | ||
798 | if (dev->thread.shutdown || signal_pending(current)) | ||
799 | goto done; | ||
800 | |||
801 | restart: | ||
802 | dev->thread.scan1 = dev->thread.scan2; | ||
803 | dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1); | ||
804 | |||
805 | if (audio_ddep >= 0x04 && audio_ddep <= 0x0e) { | ||
806 | /* insmod option override */ | ||
807 | norms = (audio_ddep << 2) | 0x01; | ||
808 | dprintk("ddep override: %s\n",stdres[audio_ddep]); | ||
809 | } else if (&card(dev).radio == dev->input) { | ||
810 | dprintk("FM Radio\n"); | ||
811 | norms = (0x0f << 2) | 0x01; | ||
812 | } else { | ||
813 | /* (let chip) scan for sound carrier */ | ||
814 | norms = 0; | ||
815 | if (dev->tvnorm->id & V4L2_STD_PAL) { | ||
816 | dprintk("PAL scan\n"); | ||
817 | norms |= 0x2c; /* B/G + D/K + I */ | ||
818 | } | ||
819 | if (dev->tvnorm->id & V4L2_STD_NTSC) { | ||
820 | dprintk("NTSC scan\n"); | ||
821 | norms |= 0x40; /* M */ | ||
822 | } | ||
823 | if (dev->tvnorm->id & V4L2_STD_SECAM) { | ||
824 | dprintk("SECAM scan\n"); | ||
825 | norms |= 0x18; /* L + D/K */ | ||
826 | } | ||
827 | if (0 == norms) | ||
828 | norms = 0x7c; /* all */ | ||
829 | dprintk("scanning:%s%s%s%s%s\n", | ||
830 | (norms & 0x04) ? " B/G" : "", | ||
831 | (norms & 0x08) ? " D/K" : "", | ||
832 | (norms & 0x10) ? " L/L'" : "", | ||
833 | (norms & 0x20) ? " I" : "", | ||
834 | (norms & 0x40) ? " M" : ""); | ||
835 | } | ||
836 | |||
837 | /* kick automatic standard detection */ | ||
838 | saa_dsp_writel(dev, 0x454 >> 2, 0); | ||
839 | saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80); | ||
840 | |||
841 | /* setup crossbars */ | ||
842 | saa_dsp_writel(dev, 0x464 >> 2, 0x000000); | ||
843 | saa_dsp_writel(dev, 0x470 >> 2, 0x101010); | ||
844 | |||
845 | if (tvaudio_sleep(dev,3000)) | ||
846 | goto restart; | ||
847 | value = saa_readl(0x528 >> 2) & 0xffffff; | ||
848 | |||
849 | dprintk("tvaudio thread status: 0x%x [%s%s%s]\n", | ||
850 | value, stdres[value & 0x1f], | ||
851 | (value & 0x000020) ? ",stereo" : "", | ||
852 | (value & 0x000040) ? ",dual" : ""); | ||
853 | dprintk("detailed status: " | ||
854 | "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n", | ||
855 | (value & 0x000080) ? " A2/EIAJ pilot tone " : "", | ||
856 | (value & 0x000100) ? " A2/EIAJ dual " : "", | ||
857 | (value & 0x000200) ? " A2/EIAJ stereo " : "", | ||
858 | (value & 0x000400) ? " A2/EIAJ noise mute " : "", | ||
859 | |||
860 | (value & 0x000800) ? " BTSC/FM radio pilot " : "", | ||
861 | (value & 0x001000) ? " SAP carrier " : "", | ||
862 | (value & 0x002000) ? " BTSC stereo noise mute " : "", | ||
863 | (value & 0x004000) ? " SAP noise mute " : "", | ||
864 | (value & 0x008000) ? " VDSP " : "", | ||
865 | |||
866 | (value & 0x010000) ? " NICST " : "", | ||
867 | (value & 0x020000) ? " NICDU " : "", | ||
868 | (value & 0x040000) ? " NICAM muted " : "", | ||
869 | (value & 0x080000) ? " NICAM reserve sound " : "", | ||
870 | |||
871 | (value & 0x100000) ? " init done " : ""); | ||
872 | } | ||
873 | |||
874 | done: | ||
875 | complete_and_exit(&dev->thread.exit, 0); | ||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | /* ------------------------------------------------------------------ */ | ||
880 | /* common stuff + external entry points */ | ||
881 | |||
882 | static void saa7134_enable_i2s(struct saa7134_dev *dev) | ||
883 | { | ||
884 | int i2s_format; | ||
885 | |||
886 | if (!card_is_empress(dev)) | ||
887 | return; | ||
888 | i2s_format = (dev->input->amux == TV) ? 0x00 : 0x01; | ||
889 | |||
890 | /* enable I2S audio output for the mpeg encoder */ | ||
891 | saa_writeb(SAA7134_I2S_OUTPUT_SELECT, 0x80); | ||
892 | saa_writeb(SAA7134_I2S_OUTPUT_FORMAT, i2s_format); | ||
893 | saa_writeb(SAA7134_I2S_OUTPUT_LEVEL, 0x0F); | ||
894 | saa_writeb(SAA7134_I2S_AUDIO_OUTPUT, 0x01); | ||
895 | } | ||
896 | |||
897 | int saa7134_tvaudio_rx2mode(u32 rx) | ||
898 | { | ||
899 | u32 mode; | ||
900 | |||
901 | mode = V4L2_TUNER_MODE_MONO; | ||
902 | if (rx & V4L2_TUNER_SUB_STEREO) | ||
903 | mode = V4L2_TUNER_MODE_STEREO; | ||
904 | else if (rx & V4L2_TUNER_SUB_LANG1) | ||
905 | mode = V4L2_TUNER_MODE_LANG1; | ||
906 | else if (rx & V4L2_TUNER_SUB_LANG2) | ||
907 | mode = V4L2_TUNER_MODE_LANG2; | ||
908 | return mode; | ||
909 | } | ||
910 | |||
911 | void saa7134_tvaudio_setmute(struct saa7134_dev *dev) | ||
912 | { | ||
913 | switch (dev->pci->device) { | ||
914 | case PCI_DEVICE_ID_PHILIPS_SAA7130: | ||
915 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
916 | mute_input_7134(dev); | ||
917 | break; | ||
918 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
919 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
920 | mute_input_7133(dev); | ||
921 | break; | ||
922 | } | ||
923 | } | ||
924 | |||
925 | void saa7134_tvaudio_setinput(struct saa7134_dev *dev, | ||
926 | struct saa7134_input *in) | ||
927 | { | ||
928 | dev->input = in; | ||
929 | switch (dev->pci->device) { | ||
930 | case PCI_DEVICE_ID_PHILIPS_SAA7130: | ||
931 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
932 | mute_input_7134(dev); | ||
933 | break; | ||
934 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
935 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
936 | mute_input_7133(dev); | ||
937 | break; | ||
938 | } | ||
939 | saa7134_enable_i2s(dev); | ||
940 | } | ||
941 | |||
942 | void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level) | ||
943 | { | ||
944 | switch (dev->pci->device) { | ||
945 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
946 | saa_writeb(SAA7134_CHANNEL1_LEVEL, level & 0x1f); | ||
947 | saa_writeb(SAA7134_CHANNEL2_LEVEL, level & 0x1f); | ||
948 | saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f); | ||
949 | break; | ||
950 | } | ||
951 | } | ||
952 | |||
953 | int saa7134_tvaudio_getstereo(struct saa7134_dev *dev) | ||
954 | { | ||
955 | int retval = V4L2_TUNER_SUB_MONO; | ||
956 | |||
957 | switch (dev->pci->device) { | ||
958 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
959 | if (dev->tvaudio) | ||
960 | retval = tvaudio_getstereo(dev,dev->tvaudio); | ||
961 | break; | ||
962 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
963 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
964 | retval = getstereo_7133(dev); | ||
965 | break; | ||
966 | } | ||
967 | return retval; | ||
968 | } | ||
969 | |||
970 | int saa7134_tvaudio_init2(struct saa7134_dev *dev) | ||
971 | { | ||
972 | DECLARE_MUTEX_LOCKED(sem); | ||
973 | int (*my_thread)(void *data) = NULL; | ||
974 | |||
975 | switch (dev->pci->device) { | ||
976 | case PCI_DEVICE_ID_PHILIPS_SAA7134: | ||
977 | my_thread = tvaudio_thread; | ||
978 | break; | ||
979 | case PCI_DEVICE_ID_PHILIPS_SAA7133: | ||
980 | case PCI_DEVICE_ID_PHILIPS_SAA7135: | ||
981 | my_thread = tvaudio_thread_ddep; | ||
982 | break; | ||
983 | } | ||
984 | |||
985 | dev->thread.pid = -1; | ||
986 | if (my_thread) { | ||
987 | /* start tvaudio thread */ | ||
988 | init_waitqueue_head(&dev->thread.wq); | ||
989 | init_completion(&dev->thread.exit); | ||
990 | dev->thread.pid = kernel_thread(my_thread,dev,0); | ||
991 | if (dev->thread.pid < 0) | ||
992 | printk(KERN_WARNING "%s: kernel_thread() failed\n", | ||
993 | dev->name); | ||
994 | saa7134_tvaudio_do_scan(dev); | ||
995 | } | ||
996 | |||
997 | saa7134_enable_i2s(dev); | ||
998 | return 0; | ||
999 | } | ||
1000 | |||
1001 | int saa7134_tvaudio_fini(struct saa7134_dev *dev) | ||
1002 | { | ||
1003 | /* shutdown tvaudio thread */ | ||
1004 | if (dev->thread.pid >= 0) { | ||
1005 | dev->thread.shutdown = 1; | ||
1006 | wake_up_interruptible(&dev->thread.wq); | ||
1007 | wait_for_completion(&dev->thread.exit); | ||
1008 | } | ||
1009 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, 0x00); /* LINE1 */ | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | int saa7134_tvaudio_do_scan(struct saa7134_dev *dev) | ||
1014 | { | ||
1015 | if (dev->thread.pid >= 0) { | ||
1016 | dev->thread.mode = UNSET; | ||
1017 | dev->thread.scan2++; | ||
1018 | wake_up_interruptible(&dev->thread.wq); | ||
1019 | } else { | ||
1020 | dev->automute = 0; | ||
1021 | saa7134_tvaudio_setmute(dev); | ||
1022 | } | ||
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | /* ----------------------------------------------------------- */ | ||
1027 | /* | ||
1028 | * Local variables: | ||
1029 | * c-basic-offset: 8 | ||
1030 | * End: | ||
1031 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c new file mode 100644 index 000000000000..86954cc7c377 --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-vbi.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-vbi.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * video4linux video interface | ||
6 | * | ||
7 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include "saa7134-reg.h" | ||
32 | #include "saa7134.h" | ||
33 | |||
34 | /* ------------------------------------------------------------------ */ | ||
35 | |||
36 | static unsigned int vbi_debug = 0; | ||
37 | module_param(vbi_debug, int, 0644); | ||
38 | MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); | ||
39 | |||
40 | static unsigned int vbibufs = 4; | ||
41 | module_param(vbibufs, int, 0444); | ||
42 | MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32"); | ||
43 | |||
44 | #define dprintk(fmt, arg...) if (vbi_debug) \ | ||
45 | printk(KERN_DEBUG "%s/vbi: " fmt, dev->name , ## arg) | ||
46 | |||
47 | /* ------------------------------------------------------------------ */ | ||
48 | |||
49 | #define VBI_LINE_COUNT 16 | ||
50 | #define VBI_LINE_LENGTH 2048 | ||
51 | #define VBI_SCALE 0x200 | ||
52 | |||
53 | static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf, | ||
54 | int task) | ||
55 | { | ||
56 | struct saa7134_tvnorm *norm = dev->tvnorm; | ||
57 | |||
58 | /* setup video scaler */ | ||
59 | saa_writeb(SAA7134_VBI_H_START1(task), norm->h_start & 0xff); | ||
60 | saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start >> 8); | ||
61 | saa_writeb(SAA7134_VBI_H_STOP1(task), norm->h_stop & 0xff); | ||
62 | saa_writeb(SAA7134_VBI_H_STOP2(task), norm->h_stop >> 8); | ||
63 | saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start & 0xff); | ||
64 | saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start >> 8); | ||
65 | saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop & 0xff); | ||
66 | saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop >> 8); | ||
67 | |||
68 | saa_writeb(SAA7134_VBI_H_SCALE_INC1(task), VBI_SCALE & 0xff); | ||
69 | saa_writeb(SAA7134_VBI_H_SCALE_INC2(task), VBI_SCALE >> 8); | ||
70 | saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task), 0x00); | ||
71 | saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00); | ||
72 | |||
73 | saa_writeb(SAA7134_VBI_H_LEN1(task), buf->vb.width & 0xff); | ||
74 | saa_writeb(SAA7134_VBI_H_LEN2(task), buf->vb.width >> 8); | ||
75 | saa_writeb(SAA7134_VBI_V_LEN1(task), buf->vb.height & 0xff); | ||
76 | saa_writeb(SAA7134_VBI_V_LEN2(task), buf->vb.height >> 8); | ||
77 | |||
78 | saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00); | ||
79 | } | ||
80 | |||
81 | /* ------------------------------------------------------------------ */ | ||
82 | |||
83 | static int buffer_activate(struct saa7134_dev *dev, | ||
84 | struct saa7134_buf *buf, | ||
85 | struct saa7134_buf *next) | ||
86 | { | ||
87 | unsigned long control,base; | ||
88 | |||
89 | dprintk("buffer_activate [%p]\n",buf); | ||
90 | buf->vb.state = STATE_ACTIVE; | ||
91 | buf->top_seen = 0; | ||
92 | |||
93 | task_init(dev,buf,TASK_A); | ||
94 | task_init(dev,buf,TASK_B); | ||
95 | saa_writeb(SAA7134_OFMT_DATA_A, 0x06); | ||
96 | saa_writeb(SAA7134_OFMT_DATA_B, 0x06); | ||
97 | |||
98 | /* DMA: setup channel 2+3 (= VBI Task A+B) */ | ||
99 | base = saa7134_buffer_base(buf); | ||
100 | control = SAA7134_RS_CONTROL_BURST_16 | | ||
101 | SAA7134_RS_CONTROL_ME | | ||
102 | (buf->pt->dma >> 12); | ||
103 | saa_writel(SAA7134_RS_BA1(2),base); | ||
104 | saa_writel(SAA7134_RS_BA2(2),base + buf->vb.size/2); | ||
105 | saa_writel(SAA7134_RS_PITCH(2),buf->vb.width); | ||
106 | saa_writel(SAA7134_RS_CONTROL(2),control); | ||
107 | saa_writel(SAA7134_RS_BA1(3),base); | ||
108 | saa_writel(SAA7134_RS_BA2(3),base + buf->vb.size/2); | ||
109 | saa_writel(SAA7134_RS_PITCH(3),buf->vb.width); | ||
110 | saa_writel(SAA7134_RS_CONTROL(3),control); | ||
111 | |||
112 | /* start DMA */ | ||
113 | saa7134_set_dmabits(dev); | ||
114 | mod_timer(&dev->vbi_q.timeout, jiffies+BUFFER_TIMEOUT); | ||
115 | |||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | static int buffer_prepare(struct videobuf_queue *q, | ||
120 | struct videobuf_buffer *vb, | ||
121 | enum v4l2_field field) | ||
122 | { | ||
123 | struct saa7134_fh *fh = q->priv_data; | ||
124 | struct saa7134_dev *dev = fh->dev; | ||
125 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
126 | struct saa7134_tvnorm *norm = dev->tvnorm; | ||
127 | unsigned int lines, llength, size; | ||
128 | int err; | ||
129 | |||
130 | lines = norm->vbi_v_stop - norm->vbi_v_start +1; | ||
131 | if (lines > VBI_LINE_COUNT) | ||
132 | lines = VBI_LINE_COUNT; | ||
133 | #if 1 | ||
134 | llength = VBI_LINE_LENGTH; | ||
135 | #else | ||
136 | llength = (norm->h_stop - norm->h_start +1) * 2; | ||
137 | if (llength > VBI_LINE_LENGTH) | ||
138 | llength = VBI_LINE_LENGTH; | ||
139 | #endif | ||
140 | size = lines * llength * 2; | ||
141 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
142 | return -EINVAL; | ||
143 | |||
144 | if (buf->vb.size != size) | ||
145 | saa7134_dma_free(dev,buf); | ||
146 | |||
147 | if (STATE_NEEDS_INIT == buf->vb.state) { | ||
148 | buf->vb.width = llength; | ||
149 | buf->vb.height = lines; | ||
150 | buf->vb.size = size; | ||
151 | buf->pt = &fh->pt_vbi; | ||
152 | |||
153 | err = videobuf_iolock(dev->pci,&buf->vb,NULL); | ||
154 | if (err) | ||
155 | goto oops; | ||
156 | err = saa7134_pgtable_build(dev->pci,buf->pt, | ||
157 | buf->vb.dma.sglist, | ||
158 | buf->vb.dma.sglen, | ||
159 | saa7134_buffer_startpage(buf)); | ||
160 | if (err) | ||
161 | goto oops; | ||
162 | } | ||
163 | buf->vb.state = STATE_PREPARED; | ||
164 | buf->activate = buffer_activate; | ||
165 | buf->vb.field = field; | ||
166 | return 0; | ||
167 | |||
168 | oops: | ||
169 | saa7134_dma_free(dev,buf); | ||
170 | return err; | ||
171 | } | ||
172 | |||
173 | static int | ||
174 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
175 | { | ||
176 | struct saa7134_fh *fh = q->priv_data; | ||
177 | struct saa7134_dev *dev = fh->dev; | ||
178 | int llength,lines; | ||
179 | |||
180 | lines = dev->tvnorm->vbi_v_stop - dev->tvnorm->vbi_v_start +1; | ||
181 | #if 1 | ||
182 | llength = VBI_LINE_LENGTH; | ||
183 | #else | ||
184 | llength = (norm->h_stop - norm->h_start +1) * 2; | ||
185 | if (llength > VBI_LINE_LENGTH) | ||
186 | llength = VBI_LINE_LENGTH; | ||
187 | #endif | ||
188 | *size = lines * llength * 2; | ||
189 | if (0 == *count) | ||
190 | *count = vbibufs; | ||
191 | *count = saa7134_buffer_count(*size,*count); | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
196 | { | ||
197 | struct saa7134_fh *fh = q->priv_data; | ||
198 | struct saa7134_dev *dev = fh->dev; | ||
199 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
200 | |||
201 | saa7134_buffer_queue(dev,&dev->vbi_q,buf); | ||
202 | } | ||
203 | |||
204 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
205 | { | ||
206 | struct saa7134_fh *fh = q->priv_data; | ||
207 | struct saa7134_dev *dev = fh->dev; | ||
208 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
209 | |||
210 | saa7134_dma_free(dev,buf); | ||
211 | } | ||
212 | |||
213 | struct videobuf_queue_ops saa7134_vbi_qops = { | ||
214 | .buf_setup = buffer_setup, | ||
215 | .buf_prepare = buffer_prepare, | ||
216 | .buf_queue = buffer_queue, | ||
217 | .buf_release = buffer_release, | ||
218 | }; | ||
219 | |||
220 | /* ------------------------------------------------------------------ */ | ||
221 | |||
222 | int saa7134_vbi_init1(struct saa7134_dev *dev) | ||
223 | { | ||
224 | INIT_LIST_HEAD(&dev->vbi_q.queue); | ||
225 | init_timer(&dev->vbi_q.timeout); | ||
226 | dev->vbi_q.timeout.function = saa7134_buffer_timeout; | ||
227 | dev->vbi_q.timeout.data = (unsigned long)(&dev->vbi_q); | ||
228 | dev->vbi_q.dev = dev; | ||
229 | |||
230 | if (vbibufs < 2) | ||
231 | vbibufs = 2; | ||
232 | if (vbibufs > VIDEO_MAX_FRAME) | ||
233 | vbibufs = VIDEO_MAX_FRAME; | ||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | int saa7134_vbi_fini(struct saa7134_dev *dev) | ||
238 | { | ||
239 | /* nothing */ | ||
240 | return 0; | ||
241 | } | ||
242 | |||
243 | void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status) | ||
244 | { | ||
245 | spin_lock(&dev->slock); | ||
246 | if (dev->vbi_q.curr) { | ||
247 | dev->vbi_fieldcount++; | ||
248 | /* make sure we have seen both fields */ | ||
249 | if ((status & 0x10) == 0x00) { | ||
250 | dev->vbi_q.curr->top_seen = 1; | ||
251 | goto done; | ||
252 | } | ||
253 | if (!dev->vbi_q.curr->top_seen) | ||
254 | goto done; | ||
255 | |||
256 | dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount; | ||
257 | saa7134_buffer_finish(dev,&dev->vbi_q,STATE_DONE); | ||
258 | } | ||
259 | saa7134_buffer_next(dev,&dev->vbi_q); | ||
260 | |||
261 | done: | ||
262 | spin_unlock(&dev->slock); | ||
263 | } | ||
264 | |||
265 | /* ----------------------------------------------------------- */ | ||
266 | /* | ||
267 | * Local variables: | ||
268 | * c-basic-offset: 8 | ||
269 | * End: | ||
270 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c new file mode 100644 index 000000000000..5d66060026ff --- /dev/null +++ b/drivers/media/video/saa7134/saa7134-video.c | |||
@@ -0,0 +1,2406 @@ | |||
1 | /* | ||
2 | * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $ | ||
3 | * | ||
4 | * device driver for philips saa7134 based TV cards | ||
5 | * video4linux video interface | ||
6 | * | ||
7 | * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/init.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/moduleparam.h> | ||
28 | #include <linux/kernel.h> | ||
29 | #include <linux/slab.h> | ||
30 | |||
31 | #include "saa7134-reg.h" | ||
32 | #include "saa7134.h" | ||
33 | |||
34 | #define V4L2_I2C_CLIENTS 1 | ||
35 | |||
36 | /* ------------------------------------------------------------------ */ | ||
37 | |||
38 | static unsigned int video_debug = 0; | ||
39 | static unsigned int gbuffers = 8; | ||
40 | static unsigned int noninterlaced = 0; | ||
41 | static unsigned int gbufsize = 720*576*4; | ||
42 | static unsigned int gbufsize_max = 720*576*4; | ||
43 | module_param(video_debug, int, 0644); | ||
44 | MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); | ||
45 | module_param(gbuffers, int, 0444); | ||
46 | MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32"); | ||
47 | module_param(noninterlaced, int, 0644); | ||
48 | MODULE_PARM_DESC(noninterlaced,"video input is noninterlaced"); | ||
49 | |||
50 | #define dprintk(fmt, arg...) if (video_debug) \ | ||
51 | printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg) | ||
52 | |||
53 | /* ------------------------------------------------------------------ */ | ||
54 | /* data structs for video */ | ||
55 | |||
56 | static int video_out[][9] = { | ||
57 | [CCIR656] = { 0x00, 0xb1, 0x00, 0xa1, 0x00, 0x04, 0x06, 0x00, 0x00 }, | ||
58 | }; | ||
59 | |||
60 | static struct saa7134_format formats[] = { | ||
61 | { | ||
62 | .name = "8 bpp gray", | ||
63 | .fourcc = V4L2_PIX_FMT_GREY, | ||
64 | .depth = 8, | ||
65 | .pm = 0x06, | ||
66 | },{ | ||
67 | .name = "15 bpp RGB, le", | ||
68 | .fourcc = V4L2_PIX_FMT_RGB555, | ||
69 | .depth = 16, | ||
70 | .pm = 0x13 | 0x80, | ||
71 | },{ | ||
72 | .name = "15 bpp RGB, be", | ||
73 | .fourcc = V4L2_PIX_FMT_RGB555X, | ||
74 | .depth = 16, | ||
75 | .pm = 0x13 | 0x80, | ||
76 | .bswap = 1, | ||
77 | },{ | ||
78 | .name = "16 bpp RGB, le", | ||
79 | .fourcc = V4L2_PIX_FMT_RGB565, | ||
80 | .depth = 16, | ||
81 | .pm = 0x10 | 0x80, | ||
82 | },{ | ||
83 | .name = "16 bpp RGB, be", | ||
84 | .fourcc = V4L2_PIX_FMT_RGB565X, | ||
85 | .depth = 16, | ||
86 | .pm = 0x10 | 0x80, | ||
87 | .bswap = 1, | ||
88 | },{ | ||
89 | .name = "24 bpp RGB, le", | ||
90 | .fourcc = V4L2_PIX_FMT_BGR24, | ||
91 | .depth = 24, | ||
92 | .pm = 0x11, | ||
93 | },{ | ||
94 | .name = "24 bpp RGB, be", | ||
95 | .fourcc = V4L2_PIX_FMT_RGB24, | ||
96 | .depth = 24, | ||
97 | .pm = 0x11, | ||
98 | .bswap = 1, | ||
99 | },{ | ||
100 | .name = "32 bpp RGB, le", | ||
101 | .fourcc = V4L2_PIX_FMT_BGR32, | ||
102 | .depth = 32, | ||
103 | .pm = 0x12, | ||
104 | },{ | ||
105 | .name = "32 bpp RGB, be", | ||
106 | .fourcc = V4L2_PIX_FMT_RGB32, | ||
107 | .depth = 32, | ||
108 | .pm = 0x12, | ||
109 | .bswap = 1, | ||
110 | .wswap = 1, | ||
111 | },{ | ||
112 | .name = "4:2:2 packed, YUYV", | ||
113 | .fourcc = V4L2_PIX_FMT_YUYV, | ||
114 | .depth = 16, | ||
115 | .pm = 0x00, | ||
116 | .bswap = 1, | ||
117 | .yuv = 1, | ||
118 | },{ | ||
119 | .name = "4:2:2 packed, UYVY", | ||
120 | .fourcc = V4L2_PIX_FMT_UYVY, | ||
121 | .depth = 16, | ||
122 | .pm = 0x00, | ||
123 | .yuv = 1, | ||
124 | },{ | ||
125 | .name = "4:2:2 planar, Y-Cb-Cr", | ||
126 | .fourcc = V4L2_PIX_FMT_YUV422P, | ||
127 | .depth = 16, | ||
128 | .pm = 0x09, | ||
129 | .yuv = 1, | ||
130 | .planar = 1, | ||
131 | .hshift = 1, | ||
132 | .vshift = 0, | ||
133 | },{ | ||
134 | .name = "4:2:0 planar, Y-Cb-Cr", | ||
135 | .fourcc = V4L2_PIX_FMT_YUV420, | ||
136 | .depth = 12, | ||
137 | .pm = 0x0a, | ||
138 | .yuv = 1, | ||
139 | .planar = 1, | ||
140 | .hshift = 1, | ||
141 | .vshift = 1, | ||
142 | },{ | ||
143 | .name = "4:2:0 planar, Y-Cb-Cr", | ||
144 | .fourcc = V4L2_PIX_FMT_YVU420, | ||
145 | .depth = 12, | ||
146 | .pm = 0x0a, | ||
147 | .yuv = 1, | ||
148 | .planar = 1, | ||
149 | .uvswap = 1, | ||
150 | .hshift = 1, | ||
151 | .vshift = 1, | ||
152 | } | ||
153 | }; | ||
154 | #define FORMATS ARRAY_SIZE(formats) | ||
155 | |||
156 | #define NORM_625_50 \ | ||
157 | .h_start = 0, \ | ||
158 | .h_stop = 719, \ | ||
159 | .video_v_start = 24, \ | ||
160 | .video_v_stop = 311, \ | ||
161 | .vbi_v_start = 7, \ | ||
162 | .vbi_v_stop = 22, \ | ||
163 | .src_timing = 4 | ||
164 | |||
165 | #define NORM_525_60 \ | ||
166 | .h_start = 0, \ | ||
167 | .h_stop = 703, \ | ||
168 | .video_v_start = 22, \ | ||
169 | .video_v_stop = 22+239, \ | ||
170 | .vbi_v_start = 10, /* FIXME */ \ | ||
171 | .vbi_v_stop = 21, /* FIXME */ \ | ||
172 | .src_timing = 1 | ||
173 | |||
174 | static struct saa7134_tvnorm tvnorms[] = { | ||
175 | { | ||
176 | .name = "PAL", /* autodetect */ | ||
177 | .id = V4L2_STD_PAL, | ||
178 | NORM_625_50, | ||
179 | |||
180 | .sync_control = 0x18, | ||
181 | .luma_control = 0x40, | ||
182 | .chroma_ctrl1 = 0x81, | ||
183 | .chroma_gain = 0x2a, | ||
184 | .chroma_ctrl2 = 0x06, | ||
185 | .vgate_misc = 0x1c, | ||
186 | |||
187 | },{ | ||
188 | .name = "PAL-BG", | ||
189 | .id = V4L2_STD_PAL_BG, | ||
190 | NORM_625_50, | ||
191 | |||
192 | .sync_control = 0x18, | ||
193 | .luma_control = 0x40, | ||
194 | .chroma_ctrl1 = 0x81, | ||
195 | .chroma_gain = 0x2a, | ||
196 | .chroma_ctrl2 = 0x06, | ||
197 | .vgate_misc = 0x1c, | ||
198 | |||
199 | },{ | ||
200 | .name = "PAL-I", | ||
201 | .id = V4L2_STD_PAL_I, | ||
202 | NORM_625_50, | ||
203 | |||
204 | .sync_control = 0x18, | ||
205 | .luma_control = 0x40, | ||
206 | .chroma_ctrl1 = 0x81, | ||
207 | .chroma_gain = 0x2a, | ||
208 | .chroma_ctrl2 = 0x06, | ||
209 | .vgate_misc = 0x1c, | ||
210 | |||
211 | },{ | ||
212 | .name = "PAL-DK", | ||
213 | .id = V4L2_STD_PAL_DK, | ||
214 | NORM_625_50, | ||
215 | |||
216 | .sync_control = 0x18, | ||
217 | .luma_control = 0x40, | ||
218 | .chroma_ctrl1 = 0x81, | ||
219 | .chroma_gain = 0x2a, | ||
220 | .chroma_ctrl2 = 0x06, | ||
221 | .vgate_misc = 0x1c, | ||
222 | |||
223 | },{ | ||
224 | .name = "NTSC", | ||
225 | .id = V4L2_STD_NTSC, | ||
226 | NORM_525_60, | ||
227 | |||
228 | .sync_control = 0x59, | ||
229 | .luma_control = 0x40, | ||
230 | .chroma_ctrl1 = 0x89, | ||
231 | .chroma_gain = 0x2a, | ||
232 | .chroma_ctrl2 = 0x0e, | ||
233 | .vgate_misc = 0x18, | ||
234 | |||
235 | },{ | ||
236 | .name = "SECAM", | ||
237 | .id = V4L2_STD_SECAM, | ||
238 | NORM_625_50, | ||
239 | |||
240 | .sync_control = 0x18, /* old: 0x58, */ | ||
241 | .luma_control = 0x1b, | ||
242 | .chroma_ctrl1 = 0xd1, | ||
243 | .chroma_gain = 0x80, | ||
244 | .chroma_ctrl2 = 0x00, | ||
245 | .vgate_misc = 0x1c, | ||
246 | |||
247 | },{ | ||
248 | .name = "PAL-M", | ||
249 | .id = V4L2_STD_PAL_M, | ||
250 | NORM_525_60, | ||
251 | |||
252 | .sync_control = 0x59, | ||
253 | .luma_control = 0x40, | ||
254 | .chroma_ctrl1 = 0xb9, | ||
255 | .chroma_gain = 0x2a, | ||
256 | .chroma_ctrl2 = 0x0e, | ||
257 | .vgate_misc = 0x18, | ||
258 | |||
259 | },{ | ||
260 | .name = "PAL-Nc", | ||
261 | .id = V4L2_STD_PAL_Nc, | ||
262 | NORM_625_50, | ||
263 | |||
264 | .sync_control = 0x18, | ||
265 | .luma_control = 0x40, | ||
266 | .chroma_ctrl1 = 0xa1, | ||
267 | .chroma_gain = 0x2a, | ||
268 | .chroma_ctrl2 = 0x06, | ||
269 | .vgate_misc = 0x1c, | ||
270 | |||
271 | },{ | ||
272 | .name = "PAL-60", | ||
273 | .id = V4L2_STD_PAL_60, | ||
274 | |||
275 | .h_start = 0, | ||
276 | .h_stop = 719, | ||
277 | .video_v_start = 22, | ||
278 | .video_v_stop = 22+239, | ||
279 | .vbi_v_start = 10, /* FIXME */ | ||
280 | .vbi_v_stop = 21, /* FIXME */ | ||
281 | .src_timing = 1, | ||
282 | |||
283 | .sync_control = 0x18, | ||
284 | .luma_control = 0x40, | ||
285 | .chroma_ctrl1 = 0x81, | ||
286 | .chroma_gain = 0x2a, | ||
287 | .chroma_ctrl2 = 0x06, | ||
288 | .vgate_misc = 0x1c, | ||
289 | } | ||
290 | }; | ||
291 | #define TVNORMS ARRAY_SIZE(tvnorms) | ||
292 | |||
293 | #define V4L2_CID_PRIVATE_INVERT (V4L2_CID_PRIVATE_BASE + 0) | ||
294 | #define V4L2_CID_PRIVATE_Y_ODD (V4L2_CID_PRIVATE_BASE + 1) | ||
295 | #define V4L2_CID_PRIVATE_Y_EVEN (V4L2_CID_PRIVATE_BASE + 2) | ||
296 | #define V4L2_CID_PRIVATE_AUTOMUTE (V4L2_CID_PRIVATE_BASE + 3) | ||
297 | #define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 4) | ||
298 | |||
299 | static const struct v4l2_queryctrl no_ctrl = { | ||
300 | .name = "42", | ||
301 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
302 | }; | ||
303 | static const struct v4l2_queryctrl video_ctrls[] = { | ||
304 | /* --- video --- */ | ||
305 | { | ||
306 | .id = V4L2_CID_BRIGHTNESS, | ||
307 | .name = "Brightness", | ||
308 | .minimum = 0, | ||
309 | .maximum = 255, | ||
310 | .step = 1, | ||
311 | .default_value = 128, | ||
312 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
313 | },{ | ||
314 | .id = V4L2_CID_CONTRAST, | ||
315 | .name = "Contrast", | ||
316 | .minimum = 0, | ||
317 | .maximum = 127, | ||
318 | .step = 1, | ||
319 | .default_value = 68, | ||
320 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
321 | },{ | ||
322 | .id = V4L2_CID_SATURATION, | ||
323 | .name = "Saturation", | ||
324 | .minimum = 0, | ||
325 | .maximum = 127, | ||
326 | .step = 1, | ||
327 | .default_value = 64, | ||
328 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
329 | },{ | ||
330 | .id = V4L2_CID_HUE, | ||
331 | .name = "Hue", | ||
332 | .minimum = -128, | ||
333 | .maximum = 127, | ||
334 | .step = 1, | ||
335 | .default_value = 0, | ||
336 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
337 | },{ | ||
338 | .id = V4L2_CID_VFLIP, | ||
339 | .name = "vertical flip", | ||
340 | .minimum = 0, | ||
341 | .maximum = 1, | ||
342 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
343 | }, | ||
344 | /* --- audio --- */ | ||
345 | { | ||
346 | .id = V4L2_CID_AUDIO_MUTE, | ||
347 | .name = "Mute", | ||
348 | .minimum = 0, | ||
349 | .maximum = 1, | ||
350 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
351 | },{ | ||
352 | .id = V4L2_CID_AUDIO_VOLUME, | ||
353 | .name = "Volume", | ||
354 | .minimum = -15, | ||
355 | .maximum = 15, | ||
356 | .step = 1, | ||
357 | .default_value = 0, | ||
358 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
359 | }, | ||
360 | /* --- private --- */ | ||
361 | { | ||
362 | .id = V4L2_CID_PRIVATE_INVERT, | ||
363 | .name = "Invert", | ||
364 | .minimum = 0, | ||
365 | .maximum = 1, | ||
366 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
367 | },{ | ||
368 | .id = V4L2_CID_PRIVATE_Y_ODD, | ||
369 | .name = "y offset odd field", | ||
370 | .minimum = 0, | ||
371 | .maximum = 128, | ||
372 | .default_value = 0, | ||
373 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
374 | },{ | ||
375 | .id = V4L2_CID_PRIVATE_Y_EVEN, | ||
376 | .name = "y offset even field", | ||
377 | .minimum = 0, | ||
378 | .maximum = 128, | ||
379 | .default_value = 0, | ||
380 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
381 | },{ | ||
382 | .id = V4L2_CID_PRIVATE_AUTOMUTE, | ||
383 | .name = "automute", | ||
384 | .minimum = 0, | ||
385 | .maximum = 1, | ||
386 | .default_value = 1, | ||
387 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
388 | } | ||
389 | }; | ||
390 | static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls); | ||
391 | |||
392 | static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id) | ||
393 | { | ||
394 | unsigned int i; | ||
395 | |||
396 | for (i = 0; i < CTRLS; i++) | ||
397 | if (video_ctrls[i].id == id) | ||
398 | return video_ctrls+i; | ||
399 | return NULL; | ||
400 | } | ||
401 | |||
402 | static struct saa7134_format* format_by_fourcc(unsigned int fourcc) | ||
403 | { | ||
404 | unsigned int i; | ||
405 | |||
406 | for (i = 0; i < FORMATS; i++) | ||
407 | if (formats[i].fourcc == fourcc) | ||
408 | return formats+i; | ||
409 | return NULL; | ||
410 | } | ||
411 | |||
412 | /* ----------------------------------------------------------------------- */ | ||
413 | /* resource management */ | ||
414 | |||
415 | static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit) | ||
416 | { | ||
417 | if (fh->resources & bit) | ||
418 | /* have it already allocated */ | ||
419 | return 1; | ||
420 | |||
421 | /* is it free? */ | ||
422 | down(&dev->lock); | ||
423 | if (dev->resources & bit) { | ||
424 | /* no, someone else uses it */ | ||
425 | up(&dev->lock); | ||
426 | return 0; | ||
427 | } | ||
428 | /* it's free, grab it */ | ||
429 | fh->resources |= bit; | ||
430 | dev->resources |= bit; | ||
431 | dprintk("res: get %d\n",bit); | ||
432 | up(&dev->lock); | ||
433 | return 1; | ||
434 | } | ||
435 | |||
436 | static | ||
437 | int res_check(struct saa7134_fh *fh, unsigned int bit) | ||
438 | { | ||
439 | return (fh->resources & bit); | ||
440 | } | ||
441 | |||
442 | static | ||
443 | int res_locked(struct saa7134_dev *dev, unsigned int bit) | ||
444 | { | ||
445 | return (dev->resources & bit); | ||
446 | } | ||
447 | |||
448 | static | ||
449 | void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) | ||
450 | { | ||
451 | if ((fh->resources & bits) != bits) | ||
452 | BUG(); | ||
453 | |||
454 | down(&dev->lock); | ||
455 | fh->resources &= ~bits; | ||
456 | dev->resources &= ~bits; | ||
457 | dprintk("res: put %d\n",bits); | ||
458 | up(&dev->lock); | ||
459 | } | ||
460 | |||
461 | /* ------------------------------------------------------------------ */ | ||
462 | |||
463 | static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm) | ||
464 | { | ||
465 | int luma_control,sync_control,mux; | ||
466 | |||
467 | dprintk("set tv norm = %s\n",norm->name); | ||
468 | dev->tvnorm = norm; | ||
469 | |||
470 | mux = card_in(dev,dev->ctl_input).vmux; | ||
471 | luma_control = norm->luma_control; | ||
472 | sync_control = norm->sync_control; | ||
473 | |||
474 | if (mux > 5) | ||
475 | luma_control |= 0x80; /* svideo */ | ||
476 | if (noninterlaced || dev->nosignal) | ||
477 | sync_control |= 0x20; | ||
478 | |||
479 | /* setup cropping */ | ||
480 | dev->crop_bounds.left = norm->h_start; | ||
481 | dev->crop_defrect.left = norm->h_start; | ||
482 | dev->crop_bounds.width = norm->h_stop - norm->h_start +1; | ||
483 | dev->crop_defrect.width = norm->h_stop - norm->h_start +1; | ||
484 | |||
485 | dev->crop_bounds.top = (norm->vbi_v_stop+1)*2; | ||
486 | dev->crop_defrect.top = norm->video_v_start*2; | ||
487 | dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624) | ||
488 | - dev->crop_bounds.top; | ||
489 | dev->crop_defrect.height = (norm->video_v_stop - norm->video_v_start +1)*2; | ||
490 | |||
491 | dev->crop_current = dev->crop_defrect; | ||
492 | |||
493 | /* setup video decoder */ | ||
494 | saa_writeb(SAA7134_INCR_DELAY, 0x08); | ||
495 | saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux); | ||
496 | saa_writeb(SAA7134_ANALOG_IN_CTRL2, 0x00); | ||
497 | |||
498 | saa_writeb(SAA7134_ANALOG_IN_CTRL3, 0x90); | ||
499 | saa_writeb(SAA7134_ANALOG_IN_CTRL4, 0x90); | ||
500 | saa_writeb(SAA7134_HSYNC_START, 0xeb); | ||
501 | saa_writeb(SAA7134_HSYNC_STOP, 0xe0); | ||
502 | saa_writeb(SAA7134_SOURCE_TIMING1, norm->src_timing); | ||
503 | |||
504 | saa_writeb(SAA7134_SYNC_CTRL, sync_control); | ||
505 | saa_writeb(SAA7134_LUMA_CTRL, luma_control); | ||
506 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); | ||
507 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, dev->ctl_contrast); | ||
508 | |||
509 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, dev->ctl_saturation); | ||
510 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); | ||
511 | saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1); | ||
512 | saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain); | ||
513 | |||
514 | saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2); | ||
515 | saa_writeb(SAA7134_MODE_DELAY_CTRL, 0x00); | ||
516 | |||
517 | saa_writeb(SAA7134_ANALOG_ADC, 0x01); | ||
518 | saa_writeb(SAA7134_VGATE_START, 0x11); | ||
519 | saa_writeb(SAA7134_VGATE_STOP, 0xfe); | ||
520 | saa_writeb(SAA7134_MISC_VGATE_MSB, norm->vgate_misc); | ||
521 | saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40); | ||
522 | saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80); | ||
523 | |||
524 | #ifdef V4L2_I2C_CLIENTS | ||
525 | saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id); | ||
526 | #else | ||
527 | { | ||
528 | /* pass down info to the i2c chips (v4l1) */ | ||
529 | struct video_channel c; | ||
530 | memset(&c,0,sizeof(c)); | ||
531 | c.channel = dev->ctl_input; | ||
532 | c.norm = VIDEO_MODE_PAL; | ||
533 | if (norm->id & V4L2_STD_NTSC) | ||
534 | c.norm = VIDEO_MODE_NTSC; | ||
535 | if (norm->id & V4L2_STD_SECAM) | ||
536 | c.norm = VIDEO_MODE_SECAM; | ||
537 | saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c); | ||
538 | } | ||
539 | #endif | ||
540 | } | ||
541 | |||
542 | static void video_mux(struct saa7134_dev *dev, int input) | ||
543 | { | ||
544 | dprintk("video input = %d [%s]\n",input,card_in(dev,input).name); | ||
545 | dev->ctl_input = input; | ||
546 | set_tvnorm(dev,dev->tvnorm); | ||
547 | saa7134_tvaudio_setinput(dev,&card_in(dev,input)); | ||
548 | } | ||
549 | |||
550 | static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale) | ||
551 | { | ||
552 | static const struct { | ||
553 | int xpsc; | ||
554 | int xacl; | ||
555 | int xc2_1; | ||
556 | int xdcg; | ||
557 | int vpfy; | ||
558 | } vals[] = { | ||
559 | /* XPSC XACL XC2_1 XDCG VPFY */ | ||
560 | { 1, 0, 0, 0, 0 }, | ||
561 | { 2, 2, 1, 2, 2 }, | ||
562 | { 3, 4, 1, 3, 2 }, | ||
563 | { 4, 8, 1, 4, 2 }, | ||
564 | { 5, 8, 1, 4, 2 }, | ||
565 | { 6, 8, 1, 4, 3 }, | ||
566 | { 7, 8, 1, 4, 3 }, | ||
567 | { 8, 15, 0, 4, 3 }, | ||
568 | { 9, 15, 0, 4, 3 }, | ||
569 | { 10, 16, 1, 5, 3 }, | ||
570 | }; | ||
571 | static const int count = ARRAY_SIZE(vals); | ||
572 | int i; | ||
573 | |||
574 | for (i = 0; i < count; i++) | ||
575 | if (vals[i].xpsc == prescale) | ||
576 | break; | ||
577 | if (i == count) | ||
578 | return; | ||
579 | |||
580 | saa_writeb(SAA7134_H_PRESCALE(task), vals[i].xpsc); | ||
581 | saa_writeb(SAA7134_ACC_LENGTH(task), vals[i].xacl); | ||
582 | saa_writeb(SAA7134_LEVEL_CTRL(task), | ||
583 | (vals[i].xc2_1 << 3) | (vals[i].xdcg)); | ||
584 | saa_andorb(SAA7134_FIR_PREFILTER_CTRL(task), 0x0f, | ||
585 | (vals[i].vpfy << 2) | vals[i].vpfy); | ||
586 | } | ||
587 | |||
588 | static void set_v_scale(struct saa7134_dev *dev, int task, int yscale) | ||
589 | { | ||
590 | int val,mirror; | ||
591 | |||
592 | saa_writeb(SAA7134_V_SCALE_RATIO1(task), yscale & 0xff); | ||
593 | saa_writeb(SAA7134_V_SCALE_RATIO2(task), yscale >> 8); | ||
594 | |||
595 | mirror = (dev->ctl_mirror) ? 0x02 : 0x00; | ||
596 | if (yscale < 2048) { | ||
597 | /* LPI */ | ||
598 | dprintk("yscale LPI yscale=%d\n",yscale); | ||
599 | saa_writeb(SAA7134_V_FILTER(task), 0x00 | mirror); | ||
600 | saa_writeb(SAA7134_LUMA_CONTRAST(task), 0x40); | ||
601 | saa_writeb(SAA7134_CHROMA_SATURATION(task), 0x40); | ||
602 | } else { | ||
603 | /* ACM */ | ||
604 | val = 0x40 * 1024 / yscale; | ||
605 | dprintk("yscale ACM yscale=%d val=0x%x\n",yscale,val); | ||
606 | saa_writeb(SAA7134_V_FILTER(task), 0x01 | mirror); | ||
607 | saa_writeb(SAA7134_LUMA_CONTRAST(task), val); | ||
608 | saa_writeb(SAA7134_CHROMA_SATURATION(task), val); | ||
609 | } | ||
610 | saa_writeb(SAA7134_LUMA_BRIGHT(task), 0x80); | ||
611 | } | ||
612 | |||
613 | static void set_size(struct saa7134_dev *dev, int task, | ||
614 | int width, int height, int interlace) | ||
615 | { | ||
616 | int prescale,xscale,yscale,y_even,y_odd; | ||
617 | int h_start, h_stop, v_start, v_stop; | ||
618 | int div = interlace ? 2 : 1; | ||
619 | |||
620 | /* setup video scaler */ | ||
621 | h_start = dev->crop_current.left; | ||
622 | v_start = dev->crop_current.top/2; | ||
623 | h_stop = (dev->crop_current.left + dev->crop_current.width -1); | ||
624 | v_stop = (dev->crop_current.top + dev->crop_current.height -1)/2; | ||
625 | |||
626 | saa_writeb(SAA7134_VIDEO_H_START1(task), h_start & 0xff); | ||
627 | saa_writeb(SAA7134_VIDEO_H_START2(task), h_start >> 8); | ||
628 | saa_writeb(SAA7134_VIDEO_H_STOP1(task), h_stop & 0xff); | ||
629 | saa_writeb(SAA7134_VIDEO_H_STOP2(task), h_stop >> 8); | ||
630 | saa_writeb(SAA7134_VIDEO_V_START1(task), v_start & 0xff); | ||
631 | saa_writeb(SAA7134_VIDEO_V_START2(task), v_start >> 8); | ||
632 | saa_writeb(SAA7134_VIDEO_V_STOP1(task), v_stop & 0xff); | ||
633 | saa_writeb(SAA7134_VIDEO_V_STOP2(task), v_stop >> 8); | ||
634 | |||
635 | prescale = dev->crop_current.width / width; | ||
636 | if (0 == prescale) | ||
637 | prescale = 1; | ||
638 | xscale = 1024 * dev->crop_current.width / prescale / width; | ||
639 | yscale = 512 * div * dev->crop_current.height / height; | ||
640 | dprintk("prescale=%d xscale=%d yscale=%d\n",prescale,xscale,yscale); | ||
641 | set_h_prescale(dev,task,prescale); | ||
642 | saa_writeb(SAA7134_H_SCALE_INC1(task), xscale & 0xff); | ||
643 | saa_writeb(SAA7134_H_SCALE_INC2(task), xscale >> 8); | ||
644 | set_v_scale(dev,task,yscale); | ||
645 | |||
646 | saa_writeb(SAA7134_VIDEO_PIXELS1(task), width & 0xff); | ||
647 | saa_writeb(SAA7134_VIDEO_PIXELS2(task), width >> 8); | ||
648 | saa_writeb(SAA7134_VIDEO_LINES1(task), height/div & 0xff); | ||
649 | saa_writeb(SAA7134_VIDEO_LINES2(task), height/div >> 8); | ||
650 | |||
651 | /* deinterlace y offsets */ | ||
652 | y_odd = dev->ctl_y_odd; | ||
653 | y_even = dev->ctl_y_even; | ||
654 | saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd); | ||
655 | saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even); | ||
656 | saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd); | ||
657 | saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even); | ||
658 | } | ||
659 | |||
660 | /* ------------------------------------------------------------------ */ | ||
661 | |||
662 | struct cliplist { | ||
663 | __u16 position; | ||
664 | __u8 enable; | ||
665 | __u8 disable; | ||
666 | }; | ||
667 | |||
668 | static void sort_cliplist(struct cliplist *cl, int entries) | ||
669 | { | ||
670 | struct cliplist swap; | ||
671 | int i,j,n; | ||
672 | |||
673 | for (i = entries-2; i >= 0; i--) { | ||
674 | for (n = 0, j = 0; j <= i; j++) { | ||
675 | if (cl[j].position > cl[j+1].position) { | ||
676 | swap = cl[j]; | ||
677 | cl[j] = cl[j+1]; | ||
678 | cl[j+1] = swap; | ||
679 | n++; | ||
680 | } | ||
681 | } | ||
682 | if (0 == n) | ||
683 | break; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | static void set_cliplist(struct saa7134_dev *dev, int reg, | ||
688 | struct cliplist *cl, int entries, char *name) | ||
689 | { | ||
690 | __u8 winbits = 0; | ||
691 | int i; | ||
692 | |||
693 | for (i = 0; i < entries; i++) { | ||
694 | winbits |= cl[i].enable; | ||
695 | winbits &= ~cl[i].disable; | ||
696 | if (i < 15 && cl[i].position == cl[i+1].position) | ||
697 | continue; | ||
698 | saa_writeb(reg + 0, winbits); | ||
699 | saa_writeb(reg + 2, cl[i].position & 0xff); | ||
700 | saa_writeb(reg + 3, cl[i].position >> 8); | ||
701 | dprintk("clip: %s winbits=%02x pos=%d\n", | ||
702 | name,winbits,cl[i].position); | ||
703 | reg += 8; | ||
704 | } | ||
705 | for (; reg < 0x400; reg += 8) { | ||
706 | saa_writeb(reg+ 0, 0); | ||
707 | saa_writeb(reg + 1, 0); | ||
708 | saa_writeb(reg + 2, 0); | ||
709 | saa_writeb(reg + 3, 0); | ||
710 | } | ||
711 | } | ||
712 | |||
713 | static int clip_range(int val) | ||
714 | { | ||
715 | if (val < 0) | ||
716 | val = 0; | ||
717 | return val; | ||
718 | } | ||
719 | |||
720 | static int setup_clipping(struct saa7134_dev *dev, struct v4l2_clip *clips, | ||
721 | int nclips, int interlace) | ||
722 | { | ||
723 | struct cliplist col[16], row[16]; | ||
724 | int cols, rows, i; | ||
725 | int div = interlace ? 2 : 1; | ||
726 | |||
727 | memset(col,0,sizeof(col)); cols = 0; | ||
728 | memset(row,0,sizeof(row)); rows = 0; | ||
729 | for (i = 0; i < nclips && i < 8; i++) { | ||
730 | col[cols].position = clip_range(clips[i].c.left); | ||
731 | col[cols].enable = (1 << i); | ||
732 | cols++; | ||
733 | col[cols].position = clip_range(clips[i].c.left+clips[i].c.width); | ||
734 | col[cols].disable = (1 << i); | ||
735 | cols++; | ||
736 | row[rows].position = clip_range(clips[i].c.top / div); | ||
737 | row[rows].enable = (1 << i); | ||
738 | rows++; | ||
739 | row[rows].position = clip_range((clips[i].c.top + clips[i].c.height) | ||
740 | / div); | ||
741 | row[rows].disable = (1 << i); | ||
742 | rows++; | ||
743 | } | ||
744 | sort_cliplist(col,cols); | ||
745 | sort_cliplist(row,rows); | ||
746 | set_cliplist(dev,0x380,col,cols,"cols"); | ||
747 | set_cliplist(dev,0x384,row,rows,"rows"); | ||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win) | ||
752 | { | ||
753 | enum v4l2_field field; | ||
754 | int maxw, maxh; | ||
755 | |||
756 | if (NULL == dev->ovbuf.base) | ||
757 | return -EINVAL; | ||
758 | if (NULL == dev->ovfmt) | ||
759 | return -EINVAL; | ||
760 | if (win->w.width < 48 || win->w.height < 32) | ||
761 | return -EINVAL; | ||
762 | if (win->clipcount > 2048) | ||
763 | return -EINVAL; | ||
764 | |||
765 | field = win->field; | ||
766 | maxw = dev->crop_current.width; | ||
767 | maxh = dev->crop_current.height; | ||
768 | |||
769 | if (V4L2_FIELD_ANY == field) { | ||
770 | field = (win->w.height > maxh/2) | ||
771 | ? V4L2_FIELD_INTERLACED | ||
772 | : V4L2_FIELD_TOP; | ||
773 | } | ||
774 | switch (field) { | ||
775 | case V4L2_FIELD_TOP: | ||
776 | case V4L2_FIELD_BOTTOM: | ||
777 | maxh = maxh / 2; | ||
778 | break; | ||
779 | case V4L2_FIELD_INTERLACED: | ||
780 | break; | ||
781 | default: | ||
782 | return -EINVAL; | ||
783 | } | ||
784 | |||
785 | win->field = field; | ||
786 | if (win->w.width > maxw) | ||
787 | win->w.width = maxw; | ||
788 | if (win->w.height > maxh) | ||
789 | win->w.height = maxh; | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | ||
794 | { | ||
795 | unsigned long base,control,bpl; | ||
796 | int err; | ||
797 | |||
798 | err = verify_preview(dev,&fh->win); | ||
799 | if (0 != err) | ||
800 | return err; | ||
801 | |||
802 | dev->ovfield = fh->win.field; | ||
803 | dprintk("start_preview %dx%d+%d+%d %s field=%s\n", | ||
804 | fh->win.w.width,fh->win.w.height, | ||
805 | fh->win.w.left,fh->win.w.top, | ||
806 | dev->ovfmt->name,v4l2_field_names[dev->ovfield]); | ||
807 | |||
808 | /* setup window + clipping */ | ||
809 | set_size(dev,TASK_B,fh->win.w.width,fh->win.w.height, | ||
810 | V4L2_FIELD_HAS_BOTH(dev->ovfield)); | ||
811 | setup_clipping(dev,fh->clips,fh->nclips, | ||
812 | V4L2_FIELD_HAS_BOTH(dev->ovfield)); | ||
813 | if (dev->ovfmt->yuv) | ||
814 | saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x03); | ||
815 | else | ||
816 | saa_andorb(SAA7134_DATA_PATH(TASK_B), 0x3f, 0x01); | ||
817 | saa_writeb(SAA7134_OFMT_VIDEO_B, dev->ovfmt->pm | 0x20); | ||
818 | |||
819 | /* dma: setup channel 1 (= Video Task B) */ | ||
820 | base = (unsigned long)dev->ovbuf.base; | ||
821 | base += dev->ovbuf.fmt.bytesperline * fh->win.w.top; | ||
822 | base += dev->ovfmt->depth/8 * fh->win.w.left; | ||
823 | bpl = dev->ovbuf.fmt.bytesperline; | ||
824 | control = SAA7134_RS_CONTROL_BURST_16; | ||
825 | if (dev->ovfmt->bswap) | ||
826 | control |= SAA7134_RS_CONTROL_BSWAP; | ||
827 | if (dev->ovfmt->wswap) | ||
828 | control |= SAA7134_RS_CONTROL_WSWAP; | ||
829 | if (V4L2_FIELD_HAS_BOTH(dev->ovfield)) { | ||
830 | saa_writel(SAA7134_RS_BA1(1),base); | ||
831 | saa_writel(SAA7134_RS_BA2(1),base+bpl); | ||
832 | saa_writel(SAA7134_RS_PITCH(1),bpl*2); | ||
833 | saa_writel(SAA7134_RS_CONTROL(1),control); | ||
834 | } else { | ||
835 | saa_writel(SAA7134_RS_BA1(1),base); | ||
836 | saa_writel(SAA7134_RS_BA2(1),base); | ||
837 | saa_writel(SAA7134_RS_PITCH(1),bpl); | ||
838 | saa_writel(SAA7134_RS_CONTROL(1),control); | ||
839 | } | ||
840 | |||
841 | /* start dma */ | ||
842 | dev->ovenable = 1; | ||
843 | saa7134_set_dmabits(dev); | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | |||
848 | static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh) | ||
849 | { | ||
850 | dev->ovenable = 0; | ||
851 | saa7134_set_dmabits(dev); | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | /* ------------------------------------------------------------------ */ | ||
856 | |||
857 | static int buffer_activate(struct saa7134_dev *dev, | ||
858 | struct saa7134_buf *buf, | ||
859 | struct saa7134_buf *next) | ||
860 | { | ||
861 | unsigned long base,control,bpl; | ||
862 | unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */ | ||
863 | |||
864 | dprintk("buffer_activate buf=%p\n",buf); | ||
865 | buf->vb.state = STATE_ACTIVE; | ||
866 | buf->top_seen = 0; | ||
867 | |||
868 | set_size(dev,TASK_A,buf->vb.width,buf->vb.height, | ||
869 | V4L2_FIELD_HAS_BOTH(buf->vb.field)); | ||
870 | if (buf->fmt->yuv) | ||
871 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03); | ||
872 | else | ||
873 | saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01); | ||
874 | saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm); | ||
875 | |||
876 | /* DMA: setup channel 0 (= Video Task A0) */ | ||
877 | base = saa7134_buffer_base(buf); | ||
878 | if (buf->fmt->planar) | ||
879 | bpl = buf->vb.width; | ||
880 | else | ||
881 | bpl = (buf->vb.width * buf->fmt->depth) / 8; | ||
882 | control = SAA7134_RS_CONTROL_BURST_16 | | ||
883 | SAA7134_RS_CONTROL_ME | | ||
884 | (buf->pt->dma >> 12); | ||
885 | if (buf->fmt->bswap) | ||
886 | control |= SAA7134_RS_CONTROL_BSWAP; | ||
887 | if (buf->fmt->wswap) | ||
888 | control |= SAA7134_RS_CONTROL_WSWAP; | ||
889 | if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { | ||
890 | /* interlaced */ | ||
891 | saa_writel(SAA7134_RS_BA1(0),base); | ||
892 | saa_writel(SAA7134_RS_BA2(0),base+bpl); | ||
893 | saa_writel(SAA7134_RS_PITCH(0),bpl*2); | ||
894 | } else { | ||
895 | /* non-interlaced */ | ||
896 | saa_writel(SAA7134_RS_BA1(0),base); | ||
897 | saa_writel(SAA7134_RS_BA2(0),base); | ||
898 | saa_writel(SAA7134_RS_PITCH(0),bpl); | ||
899 | } | ||
900 | saa_writel(SAA7134_RS_CONTROL(0),control); | ||
901 | |||
902 | if (buf->fmt->planar) { | ||
903 | /* DMA: setup channel 4+5 (= planar task A) */ | ||
904 | bpl_uv = bpl >> buf->fmt->hshift; | ||
905 | lines_uv = buf->vb.height >> buf->fmt->vshift; | ||
906 | base2 = base + bpl * buf->vb.height; | ||
907 | base3 = base2 + bpl_uv * lines_uv; | ||
908 | if (buf->fmt->uvswap) | ||
909 | tmp = base2, base2 = base3, base3 = tmp; | ||
910 | dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n", | ||
911 | bpl_uv,lines_uv,base2,base3); | ||
912 | if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) { | ||
913 | /* interlaced */ | ||
914 | saa_writel(SAA7134_RS_BA1(4),base2); | ||
915 | saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv); | ||
916 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv*2); | ||
917 | saa_writel(SAA7134_RS_BA1(5),base3); | ||
918 | saa_writel(SAA7134_RS_BA2(5),base3+bpl_uv); | ||
919 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv*2); | ||
920 | } else { | ||
921 | /* non-interlaced */ | ||
922 | saa_writel(SAA7134_RS_BA1(4),base2); | ||
923 | saa_writel(SAA7134_RS_BA2(4),base2); | ||
924 | saa_writel(SAA7134_RS_PITCH(4),bpl_uv); | ||
925 | saa_writel(SAA7134_RS_BA1(5),base3); | ||
926 | saa_writel(SAA7134_RS_BA2(5),base3); | ||
927 | saa_writel(SAA7134_RS_PITCH(5),bpl_uv); | ||
928 | } | ||
929 | saa_writel(SAA7134_RS_CONTROL(4),control); | ||
930 | saa_writel(SAA7134_RS_CONTROL(5),control); | ||
931 | } | ||
932 | |||
933 | /* start DMA */ | ||
934 | saa7134_set_dmabits(dev); | ||
935 | mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT); | ||
936 | return 0; | ||
937 | } | ||
938 | |||
939 | static int buffer_prepare(struct videobuf_queue *q, | ||
940 | struct videobuf_buffer *vb, | ||
941 | enum v4l2_field field) | ||
942 | { | ||
943 | struct saa7134_fh *fh = q->priv_data; | ||
944 | struct saa7134_dev *dev = fh->dev; | ||
945 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
946 | unsigned int size; | ||
947 | int err; | ||
948 | |||
949 | /* sanity checks */ | ||
950 | if (NULL == fh->fmt) | ||
951 | return -EINVAL; | ||
952 | if (fh->width < 48 || | ||
953 | fh->height < 32 || | ||
954 | fh->width/4 > dev->crop_current.width || | ||
955 | fh->height/4 > dev->crop_current.height || | ||
956 | fh->width > dev->crop_bounds.width || | ||
957 | fh->height > dev->crop_bounds.height) | ||
958 | return -EINVAL; | ||
959 | size = (fh->width * fh->height * fh->fmt->depth) >> 3; | ||
960 | if (0 != buf->vb.baddr && buf->vb.bsize < size) | ||
961 | return -EINVAL; | ||
962 | |||
963 | dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n", | ||
964 | vb->i,fh->width,fh->height,size,v4l2_field_names[field], | ||
965 | fh->fmt->name); | ||
966 | if (buf->vb.width != fh->width || | ||
967 | buf->vb.height != fh->height || | ||
968 | buf->vb.size != size || | ||
969 | buf->vb.field != field || | ||
970 | buf->fmt != fh->fmt) { | ||
971 | saa7134_dma_free(dev,buf); | ||
972 | } | ||
973 | |||
974 | if (STATE_NEEDS_INIT == buf->vb.state) { | ||
975 | buf->vb.width = fh->width; | ||
976 | buf->vb.height = fh->height; | ||
977 | buf->vb.size = size; | ||
978 | buf->vb.field = field; | ||
979 | buf->fmt = fh->fmt; | ||
980 | buf->pt = &fh->pt_cap; | ||
981 | |||
982 | err = videobuf_iolock(dev->pci,&buf->vb,&dev->ovbuf); | ||
983 | if (err) | ||
984 | goto oops; | ||
985 | err = saa7134_pgtable_build(dev->pci,buf->pt, | ||
986 | buf->vb.dma.sglist, | ||
987 | buf->vb.dma.sglen, | ||
988 | saa7134_buffer_startpage(buf)); | ||
989 | if (err) | ||
990 | goto oops; | ||
991 | } | ||
992 | buf->vb.state = STATE_PREPARED; | ||
993 | buf->activate = buffer_activate; | ||
994 | return 0; | ||
995 | |||
996 | oops: | ||
997 | saa7134_dma_free(dev,buf); | ||
998 | return err; | ||
999 | } | ||
1000 | |||
1001 | static int | ||
1002 | buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) | ||
1003 | { | ||
1004 | struct saa7134_fh *fh = q->priv_data; | ||
1005 | |||
1006 | *size = fh->fmt->depth * fh->width * fh->height >> 3; | ||
1007 | if (0 == *count) | ||
1008 | *count = gbuffers; | ||
1009 | *count = saa7134_buffer_count(*size,*count); | ||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
1014 | { | ||
1015 | struct saa7134_fh *fh = q->priv_data; | ||
1016 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
1017 | |||
1018 | saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf); | ||
1019 | } | ||
1020 | |||
1021 | static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) | ||
1022 | { | ||
1023 | struct saa7134_fh *fh = q->priv_data; | ||
1024 | struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); | ||
1025 | |||
1026 | saa7134_dma_free(fh->dev,buf); | ||
1027 | } | ||
1028 | |||
1029 | static struct videobuf_queue_ops video_qops = { | ||
1030 | .buf_setup = buffer_setup, | ||
1031 | .buf_prepare = buffer_prepare, | ||
1032 | .buf_queue = buffer_queue, | ||
1033 | .buf_release = buffer_release, | ||
1034 | }; | ||
1035 | |||
1036 | /* ------------------------------------------------------------------ */ | ||
1037 | |||
1038 | static int get_control(struct saa7134_dev *dev, struct v4l2_control *c) | ||
1039 | { | ||
1040 | const struct v4l2_queryctrl* ctrl; | ||
1041 | |||
1042 | ctrl = ctrl_by_id(c->id); | ||
1043 | if (NULL == ctrl) | ||
1044 | return -EINVAL; | ||
1045 | switch (c->id) { | ||
1046 | case V4L2_CID_BRIGHTNESS: | ||
1047 | c->value = dev->ctl_bright; | ||
1048 | break; | ||
1049 | case V4L2_CID_HUE: | ||
1050 | c->value = dev->ctl_hue; | ||
1051 | break; | ||
1052 | case V4L2_CID_CONTRAST: | ||
1053 | c->value = dev->ctl_contrast; | ||
1054 | break; | ||
1055 | case V4L2_CID_SATURATION: | ||
1056 | c->value = dev->ctl_saturation; | ||
1057 | break; | ||
1058 | case V4L2_CID_AUDIO_MUTE: | ||
1059 | c->value = dev->ctl_mute; | ||
1060 | break; | ||
1061 | case V4L2_CID_AUDIO_VOLUME: | ||
1062 | c->value = dev->ctl_volume; | ||
1063 | break; | ||
1064 | case V4L2_CID_PRIVATE_INVERT: | ||
1065 | c->value = dev->ctl_invert; | ||
1066 | break; | ||
1067 | case V4L2_CID_VFLIP: | ||
1068 | c->value = dev->ctl_mirror; | ||
1069 | break; | ||
1070 | case V4L2_CID_PRIVATE_Y_EVEN: | ||
1071 | c->value = dev->ctl_y_even; | ||
1072 | break; | ||
1073 | case V4L2_CID_PRIVATE_Y_ODD: | ||
1074 | c->value = dev->ctl_y_odd; | ||
1075 | break; | ||
1076 | case V4L2_CID_PRIVATE_AUTOMUTE: | ||
1077 | c->value = dev->ctl_automute; | ||
1078 | break; | ||
1079 | default: | ||
1080 | return -EINVAL; | ||
1081 | } | ||
1082 | return 0; | ||
1083 | } | ||
1084 | |||
1085 | static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh, | ||
1086 | struct v4l2_control *c) | ||
1087 | { | ||
1088 | const struct v4l2_queryctrl* ctrl; | ||
1089 | unsigned long flags; | ||
1090 | int restart_overlay = 0; | ||
1091 | |||
1092 | ctrl = ctrl_by_id(c->id); | ||
1093 | if (NULL == ctrl) | ||
1094 | return -EINVAL; | ||
1095 | dprintk("set_control name=%s val=%d\n",ctrl->name,c->value); | ||
1096 | switch (ctrl->type) { | ||
1097 | case V4L2_CTRL_TYPE_BOOLEAN: | ||
1098 | case V4L2_CTRL_TYPE_MENU: | ||
1099 | case V4L2_CTRL_TYPE_INTEGER: | ||
1100 | if (c->value < ctrl->minimum) | ||
1101 | c->value = ctrl->minimum; | ||
1102 | if (c->value > ctrl->maximum) | ||
1103 | c->value = ctrl->maximum; | ||
1104 | break; | ||
1105 | default: | ||
1106 | /* nothing */; | ||
1107 | }; | ||
1108 | switch (c->id) { | ||
1109 | case V4L2_CID_BRIGHTNESS: | ||
1110 | dev->ctl_bright = c->value; | ||
1111 | saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright); | ||
1112 | break; | ||
1113 | case V4L2_CID_HUE: | ||
1114 | dev->ctl_hue = c->value; | ||
1115 | saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue); | ||
1116 | break; | ||
1117 | case V4L2_CID_CONTRAST: | ||
1118 | dev->ctl_contrast = c->value; | ||
1119 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | ||
1120 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | ||
1121 | break; | ||
1122 | case V4L2_CID_SATURATION: | ||
1123 | dev->ctl_saturation = c->value; | ||
1124 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | ||
1125 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | ||
1126 | break; | ||
1127 | case V4L2_CID_AUDIO_MUTE: | ||
1128 | dev->ctl_mute = c->value; | ||
1129 | saa7134_tvaudio_setmute(dev); | ||
1130 | break; | ||
1131 | case V4L2_CID_AUDIO_VOLUME: | ||
1132 | dev->ctl_volume = c->value; | ||
1133 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); | ||
1134 | break; | ||
1135 | case V4L2_CID_PRIVATE_INVERT: | ||
1136 | dev->ctl_invert = c->value; | ||
1137 | saa_writeb(SAA7134_DEC_LUMA_CONTRAST, | ||
1138 | dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast); | ||
1139 | saa_writeb(SAA7134_DEC_CHROMA_SATURATION, | ||
1140 | dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation); | ||
1141 | break; | ||
1142 | case V4L2_CID_VFLIP: | ||
1143 | dev->ctl_mirror = c->value; | ||
1144 | restart_overlay = 1; | ||
1145 | break; | ||
1146 | case V4L2_CID_PRIVATE_Y_EVEN: | ||
1147 | dev->ctl_y_even = c->value; | ||
1148 | restart_overlay = 1; | ||
1149 | break; | ||
1150 | case V4L2_CID_PRIVATE_Y_ODD: | ||
1151 | dev->ctl_y_odd = c->value; | ||
1152 | restart_overlay = 1; | ||
1153 | break; | ||
1154 | case V4L2_CID_PRIVATE_AUTOMUTE: | ||
1155 | dev->ctl_automute = c->value; | ||
1156 | if (dev->tda9887_conf) { | ||
1157 | if (dev->ctl_automute) | ||
1158 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | ||
1159 | else | ||
1160 | dev->tda9887_conf &= ~TDA9887_AUTOMUTE; | ||
1161 | saa7134_i2c_call_clients(dev, TDA9887_SET_CONFIG, | ||
1162 | &dev->tda9887_conf); | ||
1163 | } | ||
1164 | break; | ||
1165 | default: | ||
1166 | return -EINVAL; | ||
1167 | } | ||
1168 | if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) { | ||
1169 | spin_lock_irqsave(&dev->slock,flags); | ||
1170 | stop_preview(dev,fh); | ||
1171 | start_preview(dev,fh); | ||
1172 | spin_unlock_irqrestore(&dev->slock,flags); | ||
1173 | } | ||
1174 | return 0; | ||
1175 | } | ||
1176 | |||
1177 | /* ------------------------------------------------------------------ */ | ||
1178 | |||
1179 | static struct videobuf_queue* saa7134_queue(struct saa7134_fh *fh) | ||
1180 | { | ||
1181 | struct videobuf_queue* q = NULL; | ||
1182 | |||
1183 | switch (fh->type) { | ||
1184 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1185 | q = &fh->cap; | ||
1186 | break; | ||
1187 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1188 | q = &fh->vbi; | ||
1189 | break; | ||
1190 | default: | ||
1191 | BUG(); | ||
1192 | } | ||
1193 | return q; | ||
1194 | } | ||
1195 | |||
1196 | static int saa7134_resource(struct saa7134_fh *fh) | ||
1197 | { | ||
1198 | int res = 0; | ||
1199 | |||
1200 | switch (fh->type) { | ||
1201 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1202 | res = RESOURCE_VIDEO; | ||
1203 | break; | ||
1204 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1205 | res = RESOURCE_VBI; | ||
1206 | break; | ||
1207 | default: | ||
1208 | BUG(); | ||
1209 | } | ||
1210 | return res; | ||
1211 | } | ||
1212 | |||
1213 | static int video_open(struct inode *inode, struct file *file) | ||
1214 | { | ||
1215 | int minor = iminor(inode); | ||
1216 | struct saa7134_dev *h,*dev = NULL; | ||
1217 | struct saa7134_fh *fh; | ||
1218 | struct list_head *list; | ||
1219 | enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1220 | int radio = 0; | ||
1221 | |||
1222 | list_for_each(list,&saa7134_devlist) { | ||
1223 | h = list_entry(list, struct saa7134_dev, devlist); | ||
1224 | if (h->video_dev && (h->video_dev->minor == minor)) | ||
1225 | dev = h; | ||
1226 | if (h->radio_dev && (h->radio_dev->minor == minor)) { | ||
1227 | radio = 1; | ||
1228 | dev = h; | ||
1229 | } | ||
1230 | if (h->vbi_dev && (h->vbi_dev->minor == minor)) { | ||
1231 | type = V4L2_BUF_TYPE_VBI_CAPTURE; | ||
1232 | dev = h; | ||
1233 | } | ||
1234 | } | ||
1235 | if (NULL == dev) | ||
1236 | return -ENODEV; | ||
1237 | |||
1238 | dprintk("open minor=%d radio=%d type=%s\n",minor,radio, | ||
1239 | v4l2_type_names[type]); | ||
1240 | |||
1241 | /* allocate + initialize per filehandle data */ | ||
1242 | fh = kmalloc(sizeof(*fh),GFP_KERNEL); | ||
1243 | if (NULL == fh) | ||
1244 | return -ENOMEM; | ||
1245 | memset(fh,0,sizeof(*fh)); | ||
1246 | file->private_data = fh; | ||
1247 | fh->dev = dev; | ||
1248 | fh->radio = radio; | ||
1249 | fh->type = type; | ||
1250 | fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); | ||
1251 | fh->width = 720; | ||
1252 | fh->height = 576; | ||
1253 | v4l2_prio_open(&dev->prio,&fh->prio); | ||
1254 | |||
1255 | videobuf_queue_init(&fh->cap, &video_qops, | ||
1256 | dev->pci, &dev->slock, | ||
1257 | V4L2_BUF_TYPE_VIDEO_CAPTURE, | ||
1258 | V4L2_FIELD_INTERLACED, | ||
1259 | sizeof(struct saa7134_buf), | ||
1260 | fh); | ||
1261 | videobuf_queue_init(&fh->vbi, &saa7134_vbi_qops, | ||
1262 | dev->pci, &dev->slock, | ||
1263 | V4L2_BUF_TYPE_VBI_CAPTURE, | ||
1264 | V4L2_FIELD_SEQ_TB, | ||
1265 | sizeof(struct saa7134_buf), | ||
1266 | fh); | ||
1267 | saa7134_pgtable_alloc(dev->pci,&fh->pt_cap); | ||
1268 | saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi); | ||
1269 | |||
1270 | if (fh->radio) { | ||
1271 | /* switch to radio mode */ | ||
1272 | saa7134_tvaudio_setinput(dev,&card(dev).radio); | ||
1273 | saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL); | ||
1274 | } else { | ||
1275 | /* switch to video/vbi mode */ | ||
1276 | video_mux(dev,dev->ctl_input); | ||
1277 | } | ||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | static ssize_t | ||
1282 | video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | ||
1283 | { | ||
1284 | struct saa7134_fh *fh = file->private_data; | ||
1285 | |||
1286 | switch (fh->type) { | ||
1287 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1288 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | ||
1289 | return -EBUSY; | ||
1290 | return videobuf_read_one(saa7134_queue(fh), | ||
1291 | data, count, ppos, | ||
1292 | file->f_flags & O_NONBLOCK); | ||
1293 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1294 | if (!res_get(fh->dev,fh,RESOURCE_VBI)) | ||
1295 | return -EBUSY; | ||
1296 | return videobuf_read_stream(saa7134_queue(fh), | ||
1297 | data, count, ppos, 1, | ||
1298 | file->f_flags & O_NONBLOCK); | ||
1299 | break; | ||
1300 | default: | ||
1301 | BUG(); | ||
1302 | return 0; | ||
1303 | } | ||
1304 | } | ||
1305 | |||
1306 | static unsigned int | ||
1307 | video_poll(struct file *file, struct poll_table_struct *wait) | ||
1308 | { | ||
1309 | struct saa7134_fh *fh = file->private_data; | ||
1310 | struct videobuf_buffer *buf = NULL; | ||
1311 | |||
1312 | if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) | ||
1313 | return videobuf_poll_stream(file, &fh->vbi, wait); | ||
1314 | |||
1315 | if (res_check(fh,RESOURCE_VIDEO)) { | ||
1316 | if (!list_empty(&fh->cap.stream)) | ||
1317 | buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); | ||
1318 | } else { | ||
1319 | down(&fh->cap.lock); | ||
1320 | if (UNSET == fh->cap.read_off) { | ||
1321 | /* need to capture a new frame */ | ||
1322 | if (res_locked(fh->dev,RESOURCE_VIDEO)) { | ||
1323 | up(&fh->cap.lock); | ||
1324 | return POLLERR; | ||
1325 | } | ||
1326 | if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { | ||
1327 | up(&fh->cap.lock); | ||
1328 | return POLLERR; | ||
1329 | } | ||
1330 | fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); | ||
1331 | fh->cap.read_off = 0; | ||
1332 | } | ||
1333 | up(&fh->cap.lock); | ||
1334 | buf = fh->cap.read_buf; | ||
1335 | } | ||
1336 | |||
1337 | if (!buf) | ||
1338 | return POLLERR; | ||
1339 | |||
1340 | poll_wait(file, &buf->done, wait); | ||
1341 | if (buf->state == STATE_DONE || | ||
1342 | buf->state == STATE_ERROR) | ||
1343 | return POLLIN|POLLRDNORM; | ||
1344 | return 0; | ||
1345 | } | ||
1346 | |||
1347 | static int video_release(struct inode *inode, struct file *file) | ||
1348 | { | ||
1349 | struct saa7134_fh *fh = file->private_data; | ||
1350 | struct saa7134_dev *dev = fh->dev; | ||
1351 | unsigned long flags; | ||
1352 | |||
1353 | /* turn off overlay */ | ||
1354 | if (res_check(fh, RESOURCE_OVERLAY)) { | ||
1355 | spin_lock_irqsave(&dev->slock,flags); | ||
1356 | stop_preview(dev,fh); | ||
1357 | spin_unlock_irqrestore(&dev->slock,flags); | ||
1358 | res_free(dev,fh,RESOURCE_OVERLAY); | ||
1359 | } | ||
1360 | |||
1361 | /* stop video capture */ | ||
1362 | if (res_check(fh, RESOURCE_VIDEO)) { | ||
1363 | videobuf_streamoff(&fh->cap); | ||
1364 | res_free(dev,fh,RESOURCE_VIDEO); | ||
1365 | } | ||
1366 | if (fh->cap.read_buf) { | ||
1367 | buffer_release(&fh->cap,fh->cap.read_buf); | ||
1368 | kfree(fh->cap.read_buf); | ||
1369 | } | ||
1370 | |||
1371 | /* stop vbi capture */ | ||
1372 | if (res_check(fh, RESOURCE_VBI)) { | ||
1373 | if (fh->vbi.streaming) | ||
1374 | videobuf_streamoff(&fh->vbi); | ||
1375 | if (fh->vbi.reading) | ||
1376 | videobuf_read_stop(&fh->vbi); | ||
1377 | res_free(dev,fh,RESOURCE_VBI); | ||
1378 | } | ||
1379 | |||
1380 | /* free stuff */ | ||
1381 | videobuf_mmap_free(&fh->cap); | ||
1382 | videobuf_mmap_free(&fh->vbi); | ||
1383 | saa7134_pgtable_free(dev->pci,&fh->pt_cap); | ||
1384 | saa7134_pgtable_free(dev->pci,&fh->pt_vbi); | ||
1385 | |||
1386 | v4l2_prio_close(&dev->prio,&fh->prio); | ||
1387 | file->private_data = NULL; | ||
1388 | kfree(fh); | ||
1389 | return 0; | ||
1390 | } | ||
1391 | |||
1392 | static int | ||
1393 | video_mmap(struct file *file, struct vm_area_struct * vma) | ||
1394 | { | ||
1395 | struct saa7134_fh *fh = file->private_data; | ||
1396 | |||
1397 | return videobuf_mmap_mapper(saa7134_queue(fh), vma); | ||
1398 | } | ||
1399 | |||
1400 | /* ------------------------------------------------------------------ */ | ||
1401 | |||
1402 | static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f) | ||
1403 | { | ||
1404 | struct saa7134_tvnorm *norm = dev->tvnorm; | ||
1405 | |||
1406 | f->fmt.vbi.sampling_rate = 6750000 * 4; | ||
1407 | f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */; | ||
1408 | f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY; | ||
1409 | f->fmt.vbi.offset = 64 * 4; | ||
1410 | f->fmt.vbi.start[0] = norm->vbi_v_start; | ||
1411 | f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1; | ||
1412 | f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1; | ||
1413 | f->fmt.vbi.count[1] = f->fmt.vbi.count[0]; | ||
1414 | f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */ | ||
1415 | |||
1416 | #if 0 | ||
1417 | if (V4L2_STD_PAL == norm->id) { | ||
1418 | /* FIXME */ | ||
1419 | f->fmt.vbi.start[0] += 3; | ||
1420 | f->fmt.vbi.start[1] += 3*2; | ||
1421 | } | ||
1422 | #endif | ||
1423 | } | ||
1424 | |||
1425 | static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, | ||
1426 | struct v4l2_format *f) | ||
1427 | { | ||
1428 | switch (f->type) { | ||
1429 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1430 | memset(&f->fmt.pix,0,sizeof(f->fmt.pix)); | ||
1431 | f->fmt.pix.width = fh->width; | ||
1432 | f->fmt.pix.height = fh->height; | ||
1433 | f->fmt.pix.field = fh->cap.field; | ||
1434 | f->fmt.pix.pixelformat = fh->fmt->fourcc; | ||
1435 | f->fmt.pix.bytesperline = | ||
1436 | (f->fmt.pix.width * fh->fmt->depth) >> 3; | ||
1437 | f->fmt.pix.sizeimage = | ||
1438 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1439 | return 0; | ||
1440 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
1441 | f->fmt.win = fh->win; | ||
1442 | return 0; | ||
1443 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1444 | saa7134_vbi_fmt(dev,f); | ||
1445 | return 0; | ||
1446 | default: | ||
1447 | return -EINVAL; | ||
1448 | } | ||
1449 | } | ||
1450 | |||
1451 | static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, | ||
1452 | struct v4l2_format *f) | ||
1453 | { | ||
1454 | int err; | ||
1455 | |||
1456 | switch (f->type) { | ||
1457 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1458 | { | ||
1459 | struct saa7134_format *fmt; | ||
1460 | enum v4l2_field field; | ||
1461 | unsigned int maxw, maxh; | ||
1462 | |||
1463 | fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
1464 | if (NULL == fmt) | ||
1465 | return -EINVAL; | ||
1466 | |||
1467 | field = f->fmt.pix.field; | ||
1468 | maxw = min(dev->crop_current.width*4, dev->crop_bounds.width); | ||
1469 | maxh = min(dev->crop_current.height*4, dev->crop_bounds.height); | ||
1470 | |||
1471 | if (V4L2_FIELD_ANY == field) { | ||
1472 | field = (f->fmt.pix.height > maxh/2) | ||
1473 | ? V4L2_FIELD_INTERLACED | ||
1474 | : V4L2_FIELD_BOTTOM; | ||
1475 | } | ||
1476 | switch (field) { | ||
1477 | case V4L2_FIELD_TOP: | ||
1478 | case V4L2_FIELD_BOTTOM: | ||
1479 | maxh = maxh / 2; | ||
1480 | break; | ||
1481 | case V4L2_FIELD_INTERLACED: | ||
1482 | break; | ||
1483 | default: | ||
1484 | return -EINVAL; | ||
1485 | } | ||
1486 | |||
1487 | f->fmt.pix.field = field; | ||
1488 | if (f->fmt.pix.width < 48) | ||
1489 | f->fmt.pix.width = 48; | ||
1490 | if (f->fmt.pix.height < 32) | ||
1491 | f->fmt.pix.height = 32; | ||
1492 | if (f->fmt.pix.width > maxw) | ||
1493 | f->fmt.pix.width = maxw; | ||
1494 | if (f->fmt.pix.height > maxh) | ||
1495 | f->fmt.pix.height = maxh; | ||
1496 | f->fmt.pix.width &= ~0x03; | ||
1497 | f->fmt.pix.bytesperline = | ||
1498 | (f->fmt.pix.width * fmt->depth) >> 3; | ||
1499 | f->fmt.pix.sizeimage = | ||
1500 | f->fmt.pix.height * f->fmt.pix.bytesperline; | ||
1501 | |||
1502 | return 0; | ||
1503 | } | ||
1504 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
1505 | err = verify_preview(dev,&f->fmt.win); | ||
1506 | if (0 != err) | ||
1507 | return err; | ||
1508 | return 0; | ||
1509 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1510 | saa7134_vbi_fmt(dev,f); | ||
1511 | return 0; | ||
1512 | default: | ||
1513 | return -EINVAL; | ||
1514 | } | ||
1515 | } | ||
1516 | |||
1517 | static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, | ||
1518 | struct v4l2_format *f) | ||
1519 | { | ||
1520 | unsigned long flags; | ||
1521 | int err; | ||
1522 | |||
1523 | switch (f->type) { | ||
1524 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1525 | err = saa7134_try_fmt(dev,fh,f); | ||
1526 | if (0 != err) | ||
1527 | return err; | ||
1528 | |||
1529 | fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); | ||
1530 | fh->width = f->fmt.pix.width; | ||
1531 | fh->height = f->fmt.pix.height; | ||
1532 | fh->cap.field = f->fmt.pix.field; | ||
1533 | return 0; | ||
1534 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
1535 | err = verify_preview(dev,&f->fmt.win); | ||
1536 | if (0 != err) | ||
1537 | return err; | ||
1538 | |||
1539 | down(&dev->lock); | ||
1540 | fh->win = f->fmt.win; | ||
1541 | fh->nclips = f->fmt.win.clipcount; | ||
1542 | if (fh->nclips > 8) | ||
1543 | fh->nclips = 8; | ||
1544 | if (copy_from_user(fh->clips,f->fmt.win.clips, | ||
1545 | sizeof(struct v4l2_clip)*fh->nclips)) { | ||
1546 | up(&dev->lock); | ||
1547 | return -EFAULT; | ||
1548 | } | ||
1549 | |||
1550 | if (res_check(fh, RESOURCE_OVERLAY)) { | ||
1551 | spin_lock_irqsave(&dev->slock,flags); | ||
1552 | stop_preview(dev,fh); | ||
1553 | start_preview(dev,fh); | ||
1554 | spin_unlock_irqrestore(&dev->slock,flags); | ||
1555 | } | ||
1556 | up(&dev->lock); | ||
1557 | return 0; | ||
1558 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1559 | saa7134_vbi_fmt(dev,f); | ||
1560 | return 0; | ||
1561 | default: | ||
1562 | return -EINVAL; | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | int saa7134_common_ioctl(struct saa7134_dev *dev, | ||
1567 | unsigned int cmd, void *arg) | ||
1568 | { | ||
1569 | int err; | ||
1570 | |||
1571 | switch (cmd) { | ||
1572 | case VIDIOC_QUERYCTRL: | ||
1573 | { | ||
1574 | const struct v4l2_queryctrl *ctrl; | ||
1575 | struct v4l2_queryctrl *c = arg; | ||
1576 | |||
1577 | if ((c->id < V4L2_CID_BASE || | ||
1578 | c->id >= V4L2_CID_LASTP1) && | ||
1579 | (c->id < V4L2_CID_PRIVATE_BASE || | ||
1580 | c->id >= V4L2_CID_PRIVATE_LASTP1)) | ||
1581 | return -EINVAL; | ||
1582 | ctrl = ctrl_by_id(c->id); | ||
1583 | *c = (NULL != ctrl) ? *ctrl : no_ctrl; | ||
1584 | return 0; | ||
1585 | } | ||
1586 | case VIDIOC_G_CTRL: | ||
1587 | return get_control(dev,arg); | ||
1588 | case VIDIOC_S_CTRL: | ||
1589 | { | ||
1590 | down(&dev->lock); | ||
1591 | err = set_control(dev,NULL,arg); | ||
1592 | up(&dev->lock); | ||
1593 | return err; | ||
1594 | } | ||
1595 | /* --- input switching --------------------------------------- */ | ||
1596 | case VIDIOC_ENUMINPUT: | ||
1597 | { | ||
1598 | struct v4l2_input *i = arg; | ||
1599 | unsigned int n; | ||
1600 | |||
1601 | n = i->index; | ||
1602 | if (n >= SAA7134_INPUT_MAX) | ||
1603 | return -EINVAL; | ||
1604 | if (NULL == card_in(dev,i->index).name) | ||
1605 | return -EINVAL; | ||
1606 | memset(i,0,sizeof(*i)); | ||
1607 | i->index = n; | ||
1608 | i->type = V4L2_INPUT_TYPE_CAMERA; | ||
1609 | strcpy(i->name,card_in(dev,n).name); | ||
1610 | if (card_in(dev,n).tv) | ||
1611 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1612 | i->audioset = 1; | ||
1613 | if (n == dev->ctl_input) { | ||
1614 | int v1 = saa_readb(SAA7134_STATUS_VIDEO1); | ||
1615 | int v2 = saa_readb(SAA7134_STATUS_VIDEO2); | ||
1616 | |||
1617 | if (0 != (v1 & 0x40)) | ||
1618 | i->status |= V4L2_IN_ST_NO_H_LOCK; | ||
1619 | if (0 != (v2 & 0x40)) | ||
1620 | i->status |= V4L2_IN_ST_NO_SYNC; | ||
1621 | if (0 != (v2 & 0x0e)) | ||
1622 | i->status |= V4L2_IN_ST_MACROVISION; | ||
1623 | } | ||
1624 | for (n = 0; n < TVNORMS; n++) | ||
1625 | i->std |= tvnorms[n].id; | ||
1626 | return 0; | ||
1627 | } | ||
1628 | case VIDIOC_G_INPUT: | ||
1629 | { | ||
1630 | int *i = arg; | ||
1631 | *i = dev->ctl_input; | ||
1632 | return 0; | ||
1633 | } | ||
1634 | case VIDIOC_S_INPUT: | ||
1635 | { | ||
1636 | int *i = arg; | ||
1637 | |||
1638 | if (*i < 0 || *i >= SAA7134_INPUT_MAX) | ||
1639 | return -EINVAL; | ||
1640 | if (NULL == card_in(dev,*i).name) | ||
1641 | return -EINVAL; | ||
1642 | down(&dev->lock); | ||
1643 | video_mux(dev,*i); | ||
1644 | up(&dev->lock); | ||
1645 | return 0; | ||
1646 | } | ||
1647 | |||
1648 | } | ||
1649 | return 0; | ||
1650 | } | ||
1651 | EXPORT_SYMBOL(saa7134_common_ioctl); | ||
1652 | |||
1653 | /* | ||
1654 | * This function is _not_ called directly, but from | ||
1655 | * video_generic_ioctl (and maybe others). userspace | ||
1656 | * copying is done already, arg is a kernel pointer. | ||
1657 | */ | ||
1658 | static int video_do_ioctl(struct inode *inode, struct file *file, | ||
1659 | unsigned int cmd, void *arg) | ||
1660 | { | ||
1661 | struct saa7134_fh *fh = file->private_data; | ||
1662 | struct saa7134_dev *dev = fh->dev; | ||
1663 | unsigned long flags; | ||
1664 | int err; | ||
1665 | |||
1666 | if (video_debug > 1) | ||
1667 | saa7134_print_ioctl(dev->name,cmd); | ||
1668 | |||
1669 | switch (cmd) { | ||
1670 | case VIDIOC_S_CTRL: | ||
1671 | case VIDIOC_S_STD: | ||
1672 | case VIDIOC_S_INPUT: | ||
1673 | case VIDIOC_S_TUNER: | ||
1674 | case VIDIOC_S_FREQUENCY: | ||
1675 | err = v4l2_prio_check(&dev->prio,&fh->prio); | ||
1676 | if (0 != err) | ||
1677 | return err; | ||
1678 | } | ||
1679 | |||
1680 | switch (cmd) { | ||
1681 | case VIDIOC_QUERYCAP: | ||
1682 | { | ||
1683 | struct v4l2_capability *cap = arg; | ||
1684 | |||
1685 | memset(cap,0,sizeof(*cap)); | ||
1686 | strcpy(cap->driver, "saa7134"); | ||
1687 | strlcpy(cap->card, saa7134_boards[dev->board].name, | ||
1688 | sizeof(cap->card)); | ||
1689 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | ||
1690 | cap->version = SAA7134_VERSION_CODE; | ||
1691 | cap->capabilities = | ||
1692 | V4L2_CAP_VIDEO_CAPTURE | | ||
1693 | V4L2_CAP_VIDEO_OVERLAY | | ||
1694 | V4L2_CAP_VBI_CAPTURE | | ||
1695 | V4L2_CAP_TUNER | | ||
1696 | V4L2_CAP_READWRITE | | ||
1697 | V4L2_CAP_STREAMING; | ||
1698 | return 0; | ||
1699 | } | ||
1700 | |||
1701 | /* --- tv standards ------------------------------------------ */ | ||
1702 | case VIDIOC_ENUMSTD: | ||
1703 | { | ||
1704 | struct v4l2_standard *e = arg; | ||
1705 | unsigned int i; | ||
1706 | |||
1707 | i = e->index; | ||
1708 | if (i >= TVNORMS) | ||
1709 | return -EINVAL; | ||
1710 | err = v4l2_video_std_construct(e, tvnorms[e->index].id, | ||
1711 | tvnorms[e->index].name); | ||
1712 | e->index = i; | ||
1713 | if (err < 0) | ||
1714 | return err; | ||
1715 | return 0; | ||
1716 | } | ||
1717 | case VIDIOC_G_STD: | ||
1718 | { | ||
1719 | v4l2_std_id *id = arg; | ||
1720 | |||
1721 | *id = dev->tvnorm->id; | ||
1722 | return 0; | ||
1723 | } | ||
1724 | case VIDIOC_S_STD: | ||
1725 | { | ||
1726 | v4l2_std_id *id = arg; | ||
1727 | unsigned int i; | ||
1728 | |||
1729 | for (i = 0; i < TVNORMS; i++) | ||
1730 | if (*id == tvnorms[i].id) | ||
1731 | break; | ||
1732 | if (i == TVNORMS) | ||
1733 | for (i = 0; i < TVNORMS; i++) | ||
1734 | if (*id & tvnorms[i].id) | ||
1735 | break; | ||
1736 | if (i == TVNORMS) | ||
1737 | return -EINVAL; | ||
1738 | |||
1739 | down(&dev->lock); | ||
1740 | if (res_check(fh, RESOURCE_OVERLAY)) { | ||
1741 | spin_lock_irqsave(&dev->slock,flags); | ||
1742 | stop_preview(dev,fh); | ||
1743 | set_tvnorm(dev,&tvnorms[i]); | ||
1744 | start_preview(dev,fh); | ||
1745 | spin_unlock_irqrestore(&dev->slock,flags); | ||
1746 | } else | ||
1747 | set_tvnorm(dev,&tvnorms[i]); | ||
1748 | saa7134_tvaudio_do_scan(dev); | ||
1749 | up(&dev->lock); | ||
1750 | return 0; | ||
1751 | } | ||
1752 | |||
1753 | case VIDIOC_CROPCAP: | ||
1754 | { | ||
1755 | struct v4l2_cropcap *cap = arg; | ||
1756 | |||
1757 | if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | ||
1758 | cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | ||
1759 | return -EINVAL; | ||
1760 | cap->bounds = dev->crop_bounds; | ||
1761 | cap->defrect = dev->crop_defrect; | ||
1762 | cap->pixelaspect.numerator = 1; | ||
1763 | cap->pixelaspect.denominator = 1; | ||
1764 | if (dev->tvnorm->id & V4L2_STD_525_60) { | ||
1765 | cap->pixelaspect.numerator = 11; | ||
1766 | cap->pixelaspect.denominator = 10; | ||
1767 | } | ||
1768 | if (dev->tvnorm->id & V4L2_STD_625_50) { | ||
1769 | cap->pixelaspect.numerator = 54; | ||
1770 | cap->pixelaspect.denominator = 59; | ||
1771 | } | ||
1772 | return 0; | ||
1773 | } | ||
1774 | |||
1775 | case VIDIOC_G_CROP: | ||
1776 | { | ||
1777 | struct v4l2_crop * crop = arg; | ||
1778 | |||
1779 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | ||
1780 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | ||
1781 | return -EINVAL; | ||
1782 | crop->c = dev->crop_current; | ||
1783 | return 0; | ||
1784 | } | ||
1785 | case VIDIOC_S_CROP: | ||
1786 | { | ||
1787 | struct v4l2_crop *crop = arg; | ||
1788 | struct v4l2_rect *b = &dev->crop_bounds; | ||
1789 | |||
1790 | if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE && | ||
1791 | crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) | ||
1792 | return -EINVAL; | ||
1793 | if (crop->c.height < 0) | ||
1794 | return -EINVAL; | ||
1795 | if (crop->c.width < 0) | ||
1796 | return -EINVAL; | ||
1797 | |||
1798 | if (res_locked(fh->dev,RESOURCE_OVERLAY)) | ||
1799 | return -EBUSY; | ||
1800 | if (res_locked(fh->dev,RESOURCE_VIDEO)) | ||
1801 | return -EBUSY; | ||
1802 | |||
1803 | if (crop->c.top < b->top) | ||
1804 | crop->c.top = b->top; | ||
1805 | if (crop->c.top > b->top + b->height) | ||
1806 | crop->c.top = b->top + b->height; | ||
1807 | if (crop->c.height > b->top - crop->c.top + b->height) | ||
1808 | crop->c.height = b->top - crop->c.top + b->height; | ||
1809 | |||
1810 | if (crop->c.left < b->left) | ||
1811 | crop->c.top = b->left; | ||
1812 | if (crop->c.left > b->left + b->width) | ||
1813 | crop->c.top = b->left + b->width; | ||
1814 | if (crop->c.width > b->left - crop->c.left + b->width) | ||
1815 | crop->c.width = b->left - crop->c.left + b->width; | ||
1816 | |||
1817 | dev->crop_current = crop->c; | ||
1818 | return 0; | ||
1819 | } | ||
1820 | |||
1821 | /* --- tuner ioctls ------------------------------------------ */ | ||
1822 | case VIDIOC_G_TUNER: | ||
1823 | { | ||
1824 | struct v4l2_tuner *t = arg; | ||
1825 | int n; | ||
1826 | |||
1827 | if (0 != t->index) | ||
1828 | return -EINVAL; | ||
1829 | memset(t,0,sizeof(*t)); | ||
1830 | for (n = 0; n < SAA7134_INPUT_MAX; n++) | ||
1831 | if (card_in(dev,n).tv) | ||
1832 | break; | ||
1833 | if (NULL != card_in(dev,n).name) { | ||
1834 | strcpy(t->name, "Television"); | ||
1835 | t->capability = V4L2_TUNER_CAP_NORM | | ||
1836 | V4L2_TUNER_CAP_STEREO | | ||
1837 | V4L2_TUNER_CAP_LANG1 | | ||
1838 | V4L2_TUNER_CAP_LANG2; | ||
1839 | t->rangehigh = 0xffffffffUL; | ||
1840 | t->rxsubchans = saa7134_tvaudio_getstereo(dev); | ||
1841 | t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans); | ||
1842 | } | ||
1843 | if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03)) | ||
1844 | t->signal = 0xffff; | ||
1845 | return 0; | ||
1846 | } | ||
1847 | case VIDIOC_S_TUNER: | ||
1848 | { | ||
1849 | struct v4l2_tuner *t = arg; | ||
1850 | int rx,mode; | ||
1851 | |||
1852 | mode = dev->thread.mode; | ||
1853 | if (UNSET == mode) { | ||
1854 | rx = saa7134_tvaudio_getstereo(dev); | ||
1855 | mode = saa7134_tvaudio_rx2mode(t->rxsubchans); | ||
1856 | } | ||
1857 | if (mode != t->audmode) { | ||
1858 | dev->thread.mode = t->audmode; | ||
1859 | } | ||
1860 | return 0; | ||
1861 | } | ||
1862 | case VIDIOC_G_FREQUENCY: | ||
1863 | { | ||
1864 | struct v4l2_frequency *f = arg; | ||
1865 | |||
1866 | memset(f,0,sizeof(*f)); | ||
1867 | f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; | ||
1868 | f->frequency = dev->ctl_freq; | ||
1869 | return 0; | ||
1870 | } | ||
1871 | case VIDIOC_S_FREQUENCY: | ||
1872 | { | ||
1873 | struct v4l2_frequency *f = arg; | ||
1874 | |||
1875 | if (0 != f->tuner) | ||
1876 | return -EINVAL; | ||
1877 | if (0 == fh->radio && V4L2_TUNER_ANALOG_TV != f->type) | ||
1878 | return -EINVAL; | ||
1879 | if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) | ||
1880 | return -EINVAL; | ||
1881 | down(&dev->lock); | ||
1882 | dev->ctl_freq = f->frequency; | ||
1883 | #ifdef V4L2_I2C_CLIENTS | ||
1884 | saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); | ||
1885 | #else | ||
1886 | saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq); | ||
1887 | #endif | ||
1888 | saa7134_tvaudio_do_scan(dev); | ||
1889 | up(&dev->lock); | ||
1890 | return 0; | ||
1891 | } | ||
1892 | |||
1893 | /* --- control ioctls ---------------------------------------- */ | ||
1894 | case VIDIOC_ENUMINPUT: | ||
1895 | case VIDIOC_G_INPUT: | ||
1896 | case VIDIOC_S_INPUT: | ||
1897 | case VIDIOC_QUERYCTRL: | ||
1898 | case VIDIOC_G_CTRL: | ||
1899 | case VIDIOC_S_CTRL: | ||
1900 | return saa7134_common_ioctl(dev, cmd, arg); | ||
1901 | |||
1902 | case VIDIOC_G_AUDIO: | ||
1903 | { | ||
1904 | struct v4l2_audio *a = arg; | ||
1905 | |||
1906 | memset(a,0,sizeof(*a)); | ||
1907 | strcpy(a->name,"audio"); | ||
1908 | return 0; | ||
1909 | } | ||
1910 | case VIDIOC_S_AUDIO: | ||
1911 | return 0; | ||
1912 | case VIDIOC_G_PARM: | ||
1913 | { | ||
1914 | struct v4l2_captureparm *parm = arg; | ||
1915 | memset(parm,0,sizeof(*parm)); | ||
1916 | return 0; | ||
1917 | } | ||
1918 | |||
1919 | case VIDIOC_G_PRIORITY: | ||
1920 | { | ||
1921 | enum v4l2_priority *p = arg; | ||
1922 | |||
1923 | *p = v4l2_prio_max(&dev->prio); | ||
1924 | return 0; | ||
1925 | } | ||
1926 | case VIDIOC_S_PRIORITY: | ||
1927 | { | ||
1928 | enum v4l2_priority *prio = arg; | ||
1929 | |||
1930 | return v4l2_prio_change(&dev->prio, &fh->prio, *prio); | ||
1931 | } | ||
1932 | |||
1933 | /* --- preview ioctls ---------------------------------------- */ | ||
1934 | case VIDIOC_ENUM_FMT: | ||
1935 | { | ||
1936 | struct v4l2_fmtdesc *f = arg; | ||
1937 | enum v4l2_buf_type type; | ||
1938 | unsigned int index; | ||
1939 | |||
1940 | index = f->index; | ||
1941 | type = f->type; | ||
1942 | switch (type) { | ||
1943 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: | ||
1944 | case V4L2_BUF_TYPE_VIDEO_OVERLAY: | ||
1945 | if (index >= FORMATS) | ||
1946 | return -EINVAL; | ||
1947 | if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && | ||
1948 | formats[index].planar) | ||
1949 | return -EINVAL; | ||
1950 | memset(f,0,sizeof(*f)); | ||
1951 | f->index = index; | ||
1952 | f->type = type; | ||
1953 | strlcpy(f->description,formats[index].name,sizeof(f->description)); | ||
1954 | f->pixelformat = formats[index].fourcc; | ||
1955 | break; | ||
1956 | case V4L2_BUF_TYPE_VBI_CAPTURE: | ||
1957 | if (0 != index) | ||
1958 | return -EINVAL; | ||
1959 | memset(f,0,sizeof(*f)); | ||
1960 | f->index = index; | ||
1961 | f->type = type; | ||
1962 | f->pixelformat = V4L2_PIX_FMT_GREY; | ||
1963 | strcpy(f->description,"vbi data"); | ||
1964 | break; | ||
1965 | default: | ||
1966 | return -EINVAL; | ||
1967 | } | ||
1968 | return 0; | ||
1969 | } | ||
1970 | case VIDIOC_G_FBUF: | ||
1971 | { | ||
1972 | struct v4l2_framebuffer *fb = arg; | ||
1973 | |||
1974 | *fb = dev->ovbuf; | ||
1975 | fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; | ||
1976 | return 0; | ||
1977 | } | ||
1978 | case VIDIOC_S_FBUF: | ||
1979 | { | ||
1980 | struct v4l2_framebuffer *fb = arg; | ||
1981 | struct saa7134_format *fmt; | ||
1982 | |||
1983 | if(!capable(CAP_SYS_ADMIN) && | ||
1984 | !capable(CAP_SYS_RAWIO)) | ||
1985 | return -EPERM; | ||
1986 | |||
1987 | /* check args */ | ||
1988 | fmt = format_by_fourcc(fb->fmt.pixelformat); | ||
1989 | if (NULL == fmt) | ||
1990 | return -EINVAL; | ||
1991 | |||
1992 | /* ok, accept it */ | ||
1993 | dev->ovbuf = *fb; | ||
1994 | dev->ovfmt = fmt; | ||
1995 | if (0 == dev->ovbuf.fmt.bytesperline) | ||
1996 | dev->ovbuf.fmt.bytesperline = | ||
1997 | dev->ovbuf.fmt.width*fmt->depth/8; | ||
1998 | return 0; | ||
1999 | } | ||
2000 | case VIDIOC_OVERLAY: | ||
2001 | { | ||
2002 | int *on = arg; | ||
2003 | |||
2004 | if (*on) { | ||
2005 | if (!res_get(dev,fh,RESOURCE_OVERLAY)) | ||
2006 | return -EBUSY; | ||
2007 | spin_lock_irqsave(&dev->slock,flags); | ||
2008 | start_preview(dev,fh); | ||
2009 | spin_unlock_irqrestore(&dev->slock,flags); | ||
2010 | } | ||
2011 | if (!*on) { | ||
2012 | if (!res_check(fh, RESOURCE_OVERLAY)) | ||
2013 | return -EINVAL; | ||
2014 | spin_lock_irqsave(&dev->slock,flags); | ||
2015 | stop_preview(dev,fh); | ||
2016 | spin_unlock_irqrestore(&dev->slock,flags); | ||
2017 | res_free(dev,fh,RESOURCE_OVERLAY); | ||
2018 | } | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2022 | /* --- capture ioctls ---------------------------------------- */ | ||
2023 | case VIDIOC_G_FMT: | ||
2024 | { | ||
2025 | struct v4l2_format *f = arg; | ||
2026 | return saa7134_g_fmt(dev,fh,f); | ||
2027 | } | ||
2028 | case VIDIOC_S_FMT: | ||
2029 | { | ||
2030 | struct v4l2_format *f = arg; | ||
2031 | return saa7134_s_fmt(dev,fh,f); | ||
2032 | } | ||
2033 | case VIDIOC_TRY_FMT: | ||
2034 | { | ||
2035 | struct v4l2_format *f = arg; | ||
2036 | return saa7134_try_fmt(dev,fh,f); | ||
2037 | } | ||
2038 | |||
2039 | case VIDIOCGMBUF: | ||
2040 | { | ||
2041 | struct video_mbuf *mbuf = arg; | ||
2042 | struct videobuf_queue *q; | ||
2043 | struct v4l2_requestbuffers req; | ||
2044 | unsigned int i; | ||
2045 | |||
2046 | q = saa7134_queue(fh); | ||
2047 | memset(&req,0,sizeof(req)); | ||
2048 | req.type = q->type; | ||
2049 | req.count = gbuffers; | ||
2050 | req.memory = V4L2_MEMORY_MMAP; | ||
2051 | err = videobuf_reqbufs(q,&req); | ||
2052 | if (err < 0) | ||
2053 | return err; | ||
2054 | memset(mbuf,0,sizeof(*mbuf)); | ||
2055 | mbuf->frames = req.count; | ||
2056 | mbuf->size = 0; | ||
2057 | for (i = 0; i < mbuf->frames; i++) { | ||
2058 | mbuf->offsets[i] = q->bufs[i]->boff; | ||
2059 | mbuf->size += q->bufs[i]->bsize; | ||
2060 | } | ||
2061 | return 0; | ||
2062 | } | ||
2063 | case VIDIOC_REQBUFS: | ||
2064 | return videobuf_reqbufs(saa7134_queue(fh),arg); | ||
2065 | |||
2066 | case VIDIOC_QUERYBUF: | ||
2067 | return videobuf_querybuf(saa7134_queue(fh),arg); | ||
2068 | |||
2069 | case VIDIOC_QBUF: | ||
2070 | return videobuf_qbuf(saa7134_queue(fh),arg); | ||
2071 | |||
2072 | case VIDIOC_DQBUF: | ||
2073 | return videobuf_dqbuf(saa7134_queue(fh),arg, | ||
2074 | file->f_flags & O_NONBLOCK); | ||
2075 | |||
2076 | case VIDIOC_STREAMON: | ||
2077 | { | ||
2078 | int res = saa7134_resource(fh); | ||
2079 | |||
2080 | if (!res_get(dev,fh,res)) | ||
2081 | return -EBUSY; | ||
2082 | return videobuf_streamon(saa7134_queue(fh)); | ||
2083 | } | ||
2084 | case VIDIOC_STREAMOFF: | ||
2085 | { | ||
2086 | int res = saa7134_resource(fh); | ||
2087 | |||
2088 | err = videobuf_streamoff(saa7134_queue(fh)); | ||
2089 | if (err < 0) | ||
2090 | return err; | ||
2091 | res_free(dev,fh,res); | ||
2092 | return 0; | ||
2093 | } | ||
2094 | |||
2095 | default: | ||
2096 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
2097 | video_do_ioctl); | ||
2098 | } | ||
2099 | return 0; | ||
2100 | } | ||
2101 | |||
2102 | static int video_ioctl(struct inode *inode, struct file *file, | ||
2103 | unsigned int cmd, unsigned long arg) | ||
2104 | { | ||
2105 | return video_usercopy(inode, file, cmd, arg, video_do_ioctl); | ||
2106 | } | ||
2107 | |||
2108 | static int radio_do_ioctl(struct inode *inode, struct file *file, | ||
2109 | unsigned int cmd, void *arg) | ||
2110 | { | ||
2111 | struct saa7134_fh *fh = file->private_data; | ||
2112 | struct saa7134_dev *dev = fh->dev; | ||
2113 | |||
2114 | if (video_debug > 1) | ||
2115 | saa7134_print_ioctl(dev->name,cmd); | ||
2116 | switch (cmd) { | ||
2117 | case VIDIOC_QUERYCAP: | ||
2118 | { | ||
2119 | struct v4l2_capability *cap = arg; | ||
2120 | |||
2121 | memset(cap,0,sizeof(*cap)); | ||
2122 | strcpy(cap->driver, "saa7134"); | ||
2123 | strlcpy(cap->card, saa7134_boards[dev->board].name, | ||
2124 | sizeof(cap->card)); | ||
2125 | sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); | ||
2126 | cap->version = SAA7134_VERSION_CODE; | ||
2127 | cap->capabilities = V4L2_CAP_TUNER; | ||
2128 | return 0; | ||
2129 | } | ||
2130 | case VIDIOC_G_TUNER: | ||
2131 | { | ||
2132 | struct v4l2_tuner *t = arg; | ||
2133 | |||
2134 | if (0 != t->index) | ||
2135 | return -EINVAL; | ||
2136 | |||
2137 | memset(t,0,sizeof(*t)); | ||
2138 | strcpy(t->name, "Radio"); | ||
2139 | t->rangelow = (int)(65*16); | ||
2140 | t->rangehigh = (int)(108*16); | ||
2141 | |||
2142 | #ifdef V4L2_I2C_CLIENTS | ||
2143 | saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t); | ||
2144 | #else | ||
2145 | { | ||
2146 | struct video_tuner vt; | ||
2147 | memset(&vt,0,sizeof(vt)); | ||
2148 | saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt); | ||
2149 | t->signal = vt.signal; | ||
2150 | } | ||
2151 | #endif | ||
2152 | return 0; | ||
2153 | } | ||
2154 | case VIDIOC_ENUMINPUT: | ||
2155 | { | ||
2156 | struct v4l2_input *i = arg; | ||
2157 | |||
2158 | if (i->index != 0) | ||
2159 | return -EINVAL; | ||
2160 | strcpy(i->name,"Radio"); | ||
2161 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
2162 | return 0; | ||
2163 | } | ||
2164 | case VIDIOC_G_INPUT: | ||
2165 | { | ||
2166 | int *i = arg; | ||
2167 | *i = 0; | ||
2168 | return 0; | ||
2169 | } | ||
2170 | case VIDIOC_G_AUDIO: | ||
2171 | { | ||
2172 | struct v4l2_audio *a = arg; | ||
2173 | |||
2174 | memset(a,0,sizeof(*a)); | ||
2175 | strcpy(a->name,"Radio"); | ||
2176 | return 0; | ||
2177 | } | ||
2178 | case VIDIOC_G_STD: | ||
2179 | { | ||
2180 | v4l2_std_id *id = arg; | ||
2181 | *id = 0; | ||
2182 | return 0; | ||
2183 | } | ||
2184 | case VIDIOC_S_AUDIO: | ||
2185 | case VIDIOC_S_TUNER: | ||
2186 | case VIDIOC_S_INPUT: | ||
2187 | case VIDIOC_S_STD: | ||
2188 | return 0; | ||
2189 | |||
2190 | case VIDIOC_QUERYCTRL: | ||
2191 | { | ||
2192 | const struct v4l2_queryctrl *ctrl; | ||
2193 | struct v4l2_queryctrl *c = arg; | ||
2194 | |||
2195 | if (c->id < V4L2_CID_BASE || | ||
2196 | c->id >= V4L2_CID_LASTP1) | ||
2197 | return -EINVAL; | ||
2198 | if (c->id == V4L2_CID_AUDIO_MUTE) { | ||
2199 | ctrl = ctrl_by_id(c->id); | ||
2200 | *c = *ctrl; | ||
2201 | } else | ||
2202 | *c = no_ctrl; | ||
2203 | return 0; | ||
2204 | } | ||
2205 | |||
2206 | case VIDIOC_G_CTRL: | ||
2207 | case VIDIOC_S_CTRL: | ||
2208 | case VIDIOC_G_FREQUENCY: | ||
2209 | case VIDIOC_S_FREQUENCY: | ||
2210 | return video_do_ioctl(inode,file,cmd,arg); | ||
2211 | |||
2212 | default: | ||
2213 | return v4l_compat_translate_ioctl(inode,file,cmd,arg, | ||
2214 | radio_do_ioctl); | ||
2215 | } | ||
2216 | return 0; | ||
2217 | } | ||
2218 | |||
2219 | static int radio_ioctl(struct inode *inode, struct file *file, | ||
2220 | unsigned int cmd, unsigned long arg) | ||
2221 | { | ||
2222 | return video_usercopy(inode, file, cmd, arg, radio_do_ioctl); | ||
2223 | } | ||
2224 | |||
2225 | static struct file_operations video_fops = | ||
2226 | { | ||
2227 | .owner = THIS_MODULE, | ||
2228 | .open = video_open, | ||
2229 | .release = video_release, | ||
2230 | .read = video_read, | ||
2231 | .poll = video_poll, | ||
2232 | .mmap = video_mmap, | ||
2233 | .ioctl = video_ioctl, | ||
2234 | .llseek = no_llseek, | ||
2235 | }; | ||
2236 | |||
2237 | static struct file_operations radio_fops = | ||
2238 | { | ||
2239 | .owner = THIS_MODULE, | ||
2240 | .open = video_open, | ||
2241 | .release = video_release, | ||
2242 | .ioctl = radio_ioctl, | ||
2243 | .llseek = no_llseek, | ||
2244 | }; | ||
2245 | |||
2246 | /* ----------------------------------------------------------- */ | ||
2247 | /* exported stuff */ | ||
2248 | |||
2249 | struct video_device saa7134_video_template = | ||
2250 | { | ||
2251 | .name = "saa7134-video", | ||
2252 | .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| | ||
2253 | VID_TYPE_CLIPPING|VID_TYPE_SCALES, | ||
2254 | .hardware = 0, | ||
2255 | .fops = &video_fops, | ||
2256 | .minor = -1, | ||
2257 | }; | ||
2258 | |||
2259 | struct video_device saa7134_vbi_template = | ||
2260 | { | ||
2261 | .name = "saa7134-vbi", | ||
2262 | .type = VID_TYPE_TUNER|VID_TYPE_TELETEXT, | ||
2263 | .hardware = 0, | ||
2264 | .fops = &video_fops, | ||
2265 | .minor = -1, | ||
2266 | }; | ||
2267 | |||
2268 | struct video_device saa7134_radio_template = | ||
2269 | { | ||
2270 | .name = "saa7134-radio", | ||
2271 | .type = VID_TYPE_TUNER, | ||
2272 | .hardware = 0, | ||
2273 | .fops = &radio_fops, | ||
2274 | .minor = -1, | ||
2275 | }; | ||
2276 | |||
2277 | int saa7134_video_init1(struct saa7134_dev *dev) | ||
2278 | { | ||
2279 | /* sanitycheck insmod options */ | ||
2280 | if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME) | ||
2281 | gbuffers = 2; | ||
2282 | if (gbufsize < 0 || gbufsize > gbufsize_max) | ||
2283 | gbufsize = gbufsize_max; | ||
2284 | gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK; | ||
2285 | |||
2286 | /* put some sensible defaults into the data structures ... */ | ||
2287 | dev->ctl_bright = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value; | ||
2288 | dev->ctl_contrast = ctrl_by_id(V4L2_CID_CONTRAST)->default_value; | ||
2289 | dev->ctl_hue = ctrl_by_id(V4L2_CID_HUE)->default_value; | ||
2290 | dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value; | ||
2291 | dev->ctl_volume = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value; | ||
2292 | dev->ctl_mute = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value; | ||
2293 | dev->ctl_invert = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value; | ||
2294 | dev->ctl_automute = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value; | ||
2295 | |||
2296 | if (dev->tda9887_conf && dev->ctl_automute) | ||
2297 | dev->tda9887_conf |= TDA9887_AUTOMUTE; | ||
2298 | dev->automute = 0; | ||
2299 | |||
2300 | INIT_LIST_HEAD(&dev->video_q.queue); | ||
2301 | init_timer(&dev->video_q.timeout); | ||
2302 | dev->video_q.timeout.function = saa7134_buffer_timeout; | ||
2303 | dev->video_q.timeout.data = (unsigned long)(&dev->video_q); | ||
2304 | dev->video_q.dev = dev; | ||
2305 | |||
2306 | if (saa7134_boards[dev->board].video_out) { | ||
2307 | /* enable video output */ | ||
2308 | int vo = saa7134_boards[dev->board].video_out; | ||
2309 | saa_writeb(SAA7134_VIDEO_PORT_CTRL0, video_out[vo][0]); | ||
2310 | saa_writeb(SAA7134_VIDEO_PORT_CTRL1, video_out[vo][1]); | ||
2311 | saa_writeb(SAA7134_VIDEO_PORT_CTRL2, video_out[vo][2]); | ||
2312 | saa_writeb(SAA7134_VIDEO_PORT_CTRL3, video_out[vo][3]); | ||
2313 | saa_writeb(SAA7134_VIDEO_PORT_CTRL4, video_out[vo][4]); | ||
2314 | saa_writeb(SAA7134_VIDEO_PORT_CTRL5, video_out[vo][5]); | ||
2315 | saa_writeb(SAA7134_VIDEO_PORT_CTRL6, video_out[vo][6]); | ||
2316 | saa_writeb(SAA7134_VIDEO_PORT_CTRL7, video_out[vo][7]); | ||
2317 | saa_writeb(SAA7134_VIDEO_PORT_CTRL8, video_out[vo][8]); | ||
2318 | } | ||
2319 | |||
2320 | return 0; | ||
2321 | } | ||
2322 | |||
2323 | int saa7134_video_init2(struct saa7134_dev *dev) | ||
2324 | { | ||
2325 | /* init video hw */ | ||
2326 | set_tvnorm(dev,&tvnorms[0]); | ||
2327 | video_mux(dev,0); | ||
2328 | saa7134_tvaudio_setmute(dev); | ||
2329 | saa7134_tvaudio_setvolume(dev,dev->ctl_volume); | ||
2330 | return 0; | ||
2331 | } | ||
2332 | |||
2333 | int saa7134_video_fini(struct saa7134_dev *dev) | ||
2334 | { | ||
2335 | /* nothing */ | ||
2336 | return 0; | ||
2337 | } | ||
2338 | |||
2339 | void saa7134_irq_video_intl(struct saa7134_dev *dev) | ||
2340 | { | ||
2341 | static const char *st[] = { | ||
2342 | "(no signal)", "NTSC", "PAL", "SECAM" }; | ||
2343 | u32 st1,st2; | ||
2344 | |||
2345 | st1 = saa_readb(SAA7134_STATUS_VIDEO1); | ||
2346 | st2 = saa_readb(SAA7134_STATUS_VIDEO2); | ||
2347 | dprintk("DCSDT: pll: %s, sync: %s, norm: %s\n", | ||
2348 | (st1 & 0x40) ? "not locked" : "locked", | ||
2349 | (st2 & 0x40) ? "no" : "yes", | ||
2350 | st[st1 & 0x03]); | ||
2351 | dev->nosignal = (st1 & 0x40) || (st2 & 0x40); | ||
2352 | |||
2353 | if (dev->nosignal) { | ||
2354 | /* no video signal -> mute audio */ | ||
2355 | if (dev->ctl_automute) | ||
2356 | dev->automute = 1; | ||
2357 | saa7134_tvaudio_setmute(dev); | ||
2358 | saa_setb(SAA7134_SYNC_CTRL, 0x20); | ||
2359 | } else { | ||
2360 | /* wake up tvaudio audio carrier scan thread */ | ||
2361 | saa7134_tvaudio_do_scan(dev); | ||
2362 | if (!noninterlaced) | ||
2363 | saa_clearb(SAA7134_SYNC_CTRL, 0x20); | ||
2364 | } | ||
2365 | if (dev->mops && dev->mops->signal_change) | ||
2366 | dev->mops->signal_change(dev); | ||
2367 | } | ||
2368 | |||
2369 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status) | ||
2370 | { | ||
2371 | enum v4l2_field field; | ||
2372 | |||
2373 | spin_lock(&dev->slock); | ||
2374 | if (dev->video_q.curr) { | ||
2375 | dev->video_fieldcount++; | ||
2376 | field = dev->video_q.curr->vb.field; | ||
2377 | if (V4L2_FIELD_HAS_BOTH(field)) { | ||
2378 | /* make sure we have seen both fields */ | ||
2379 | if ((status & 0x10) == 0x00) { | ||
2380 | dev->video_q.curr->top_seen = 1; | ||
2381 | goto done; | ||
2382 | } | ||
2383 | if (!dev->video_q.curr->top_seen) | ||
2384 | goto done; | ||
2385 | } else if (field == V4L2_FIELD_TOP) { | ||
2386 | if ((status & 0x10) != 0x10) | ||
2387 | goto done; | ||
2388 | } else if (field == V4L2_FIELD_BOTTOM) { | ||
2389 | if ((status & 0x10) != 0x00) | ||
2390 | goto done; | ||
2391 | } | ||
2392 | dev->video_q.curr->vb.field_count = dev->video_fieldcount; | ||
2393 | saa7134_buffer_finish(dev,&dev->video_q,STATE_DONE); | ||
2394 | } | ||
2395 | saa7134_buffer_next(dev,&dev->video_q); | ||
2396 | |||
2397 | done: | ||
2398 | spin_unlock(&dev->slock); | ||
2399 | } | ||
2400 | |||
2401 | /* ----------------------------------------------------------- */ | ||
2402 | /* | ||
2403 | * Local variables: | ||
2404 | * c-basic-offset: 8 | ||
2405 | * End: | ||
2406 | */ | ||
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h new file mode 100644 index 000000000000..ac90a9853236 --- /dev/null +++ b/drivers/media/video/saa7134/saa7134.h | |||
@@ -0,0 +1,618 @@ | |||
1 | /* | ||
2 | * $Id: saa7134.h,v 1.38 2005/03/07 12:01:51 kraxel Exp $ | ||
3 | * | ||
4 | * v4l2 device driver for philips saa7134 based TV cards | ||
5 | * | ||
6 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | */ | ||
22 | |||
23 | #include <linux/version.h> | ||
24 | #define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,12) | ||
25 | |||
26 | #include <linux/pci.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/videodev.h> | ||
29 | #include <linux/kdev_t.h> | ||
30 | #include <linux/input.h> | ||
31 | |||
32 | #include <asm/io.h> | ||
33 | |||
34 | #include <media/tuner.h> | ||
35 | #include <media/audiochip.h> | ||
36 | #include <media/id.h> | ||
37 | #include <media/ir-common.h> | ||
38 | #include <media/video-buf.h> | ||
39 | #include <media/video-buf-dvb.h> | ||
40 | |||
41 | #ifndef TRUE | ||
42 | # define TRUE (1==1) | ||
43 | #endif | ||
44 | #ifndef FALSE | ||
45 | # define FALSE (1==0) | ||
46 | #endif | ||
47 | #define UNSET (-1U) | ||
48 | |||
49 | /* 2.4 / 2.5 driver compatibility stuff */ | ||
50 | |||
51 | /* ----------------------------------------------------------- */ | ||
52 | /* enums */ | ||
53 | |||
54 | enum saa7134_tvaudio_mode { | ||
55 | TVAUDIO_FM_MONO = 1, | ||
56 | TVAUDIO_FM_BG_STEREO = 2, | ||
57 | TVAUDIO_FM_SAT_STEREO = 3, | ||
58 | TVAUDIO_FM_K_STEREO = 4, | ||
59 | TVAUDIO_NICAM_AM = 5, | ||
60 | TVAUDIO_NICAM_FM = 6, | ||
61 | }; | ||
62 | |||
63 | enum saa7134_audio_in { | ||
64 | TV = 1, | ||
65 | LINE1 = 2, | ||
66 | LINE2 = 3, | ||
67 | LINE2_LEFT, | ||
68 | }; | ||
69 | |||
70 | enum saa7134_video_out { | ||
71 | CCIR656 = 1, | ||
72 | }; | ||
73 | |||
74 | /* ----------------------------------------------------------- */ | ||
75 | /* static data */ | ||
76 | |||
77 | struct saa7134_tvnorm { | ||
78 | char *name; | ||
79 | v4l2_std_id id; | ||
80 | |||
81 | /* video decoder */ | ||
82 | unsigned int sync_control; | ||
83 | unsigned int luma_control; | ||
84 | unsigned int chroma_ctrl1; | ||
85 | unsigned int chroma_gain; | ||
86 | unsigned int chroma_ctrl2; | ||
87 | unsigned int vgate_misc; | ||
88 | |||
89 | /* video scaler */ | ||
90 | unsigned int h_start; | ||
91 | unsigned int h_stop; | ||
92 | unsigned int video_v_start; | ||
93 | unsigned int video_v_stop; | ||
94 | unsigned int vbi_v_start; | ||
95 | unsigned int vbi_v_stop; | ||
96 | unsigned int src_timing; | ||
97 | }; | ||
98 | |||
99 | struct saa7134_tvaudio { | ||
100 | char *name; | ||
101 | v4l2_std_id std; | ||
102 | enum saa7134_tvaudio_mode mode; | ||
103 | int carr1; | ||
104 | int carr2; | ||
105 | }; | ||
106 | |||
107 | struct saa7134_format { | ||
108 | char *name; | ||
109 | unsigned int fourcc; | ||
110 | unsigned int depth; | ||
111 | unsigned int pm; | ||
112 | unsigned int vshift; /* vertical downsampling (for planar yuv) */ | ||
113 | unsigned int hshift; /* horizontal downsampling (for planar yuv) */ | ||
114 | unsigned int bswap:1; | ||
115 | unsigned int wswap:1; | ||
116 | unsigned int yuv:1; | ||
117 | unsigned int planar:1; | ||
118 | unsigned int uvswap:1; | ||
119 | }; | ||
120 | |||
121 | /* ----------------------------------------------------------- */ | ||
122 | /* card configuration */ | ||
123 | |||
124 | #define SAA7134_BOARD_NOAUTO UNSET | ||
125 | #define SAA7134_BOARD_UNKNOWN 0 | ||
126 | #define SAA7134_BOARD_PROTEUS_PRO 1 | ||
127 | #define SAA7134_BOARD_FLYVIDEO3000 2 | ||
128 | #define SAA7134_BOARD_FLYVIDEO2000 3 | ||
129 | #define SAA7134_BOARD_EMPRESS 4 | ||
130 | #define SAA7134_BOARD_MONSTERTV 5 | ||
131 | #define SAA7134_BOARD_MD9717 6 | ||
132 | #define SAA7134_BOARD_TVSTATION_RDS 7 | ||
133 | #define SAA7134_BOARD_CINERGY400 8 | ||
134 | #define SAA7134_BOARD_MD5044 9 | ||
135 | #define SAA7134_BOARD_KWORLD 10 | ||
136 | #define SAA7134_BOARD_CINERGY600 11 | ||
137 | #define SAA7134_BOARD_MD7134 12 | ||
138 | #define SAA7134_BOARD_TYPHOON_90031 13 | ||
139 | #define SAA7134_BOARD_ELSA 14 | ||
140 | #define SAA7134_BOARD_ELSA_500TV 15 | ||
141 | #define SAA7134_BOARD_ASUSTeK_TVFM7134 16 | ||
142 | #define SAA7134_BOARD_VA1000POWER 17 | ||
143 | #define SAA7134_BOARD_BMK_MPEX_NOTUNER 18 | ||
144 | #define SAA7134_BOARD_VIDEOMATE_TV 19 | ||
145 | #define SAA7134_BOARD_CRONOS_PLUS 20 | ||
146 | #define SAA7134_BOARD_10MOONSTVMASTER 21 | ||
147 | #define SAA7134_BOARD_MD2819 22 | ||
148 | #define SAA7134_BOARD_BMK_MPEX_TUNER 23 | ||
149 | #define SAA7134_BOARD_TVSTATION_DVR 24 | ||
150 | #define SAA7134_BOARD_ASUSTEK_TVFM7133 25 | ||
151 | #define SAA7134_BOARD_PINNACLE_PCTV_STEREO 26 | ||
152 | #define SAA7134_BOARD_MANLI_MTV002 27 | ||
153 | #define SAA7134_BOARD_MANLI_MTV001 28 | ||
154 | #define SAA7134_BOARD_TG3000TV 29 | ||
155 | #define SAA7134_BOARD_ECS_TVP3XP 30 | ||
156 | #define SAA7134_BOARD_ECS_TVP3XP_4CB5 31 | ||
157 | #define SAA7134_BOARD_AVACSSMARTTV 32 | ||
158 | #define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33 | ||
159 | #define SAA7134_BOARD_NOVAC_PRIMETV7133 34 | ||
160 | #define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35 | ||
161 | #define SAA7133_BOARD_UPMOST_PURPLE_TV 36 | ||
162 | #define SAA7134_BOARD_ITEMS_MTV005 37 | ||
163 | #define SAA7134_BOARD_CINERGY200 38 | ||
164 | #define SAA7134_BOARD_FLYTVPLATINUM_MINI 39 | ||
165 | #define SAA7134_BOARD_VIDEOMATE_TV_PVR 40 | ||
166 | #define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS 41 | ||
167 | #define SAA7134_BOARD_SABRENT_SBTTVFM 42 | ||
168 | #define SAA7134_BOARD_ZOLID_XPERT_TV7134 43 | ||
169 | #define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44 | ||
170 | #define SAA7134_BOARD_AVERMEDIA_307 45 | ||
171 | #define SAA7134_BOARD_AVERMEDIA_CARDBUS 46 | ||
172 | #define SAA7134_BOARD_CINERGY400_CARDBUS 47 | ||
173 | #define SAA7134_BOARD_CINERGY600_MK3 48 | ||
174 | #define SAA7134_BOARD_VIDEOMATE_GOLD_PLUS 49 | ||
175 | #define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50 | ||
176 | #define SAA7134_BOARD_PROVIDEO_PV952 51 | ||
177 | #define SAA7134_BOARD_AVERMEDIA_305 52 | ||
178 | #define SAA7135_BOARD_ASUSTeK_TVFM7135 53 | ||
179 | #define SAA7134_BOARD_FLYTVPLATINUM_FM 54 | ||
180 | #define SAA7134_BOARD_FLYDVBTDUO 55 | ||
181 | |||
182 | #define SAA7134_MAXBOARDS 8 | ||
183 | #define SAA7134_INPUT_MAX 8 | ||
184 | |||
185 | struct saa7134_input { | ||
186 | char *name; | ||
187 | unsigned int vmux; | ||
188 | enum saa7134_audio_in amux; | ||
189 | unsigned int gpio; | ||
190 | unsigned int tv:1; | ||
191 | }; | ||
192 | |||
193 | enum saa7134_mpeg_type { | ||
194 | SAA7134_MPEG_UNUSED, | ||
195 | SAA7134_MPEG_EMPRESS, | ||
196 | SAA7134_MPEG_DVB, | ||
197 | }; | ||
198 | |||
199 | struct saa7134_board { | ||
200 | char *name; | ||
201 | unsigned int audio_clock; | ||
202 | |||
203 | /* input switching */ | ||
204 | unsigned int gpiomask; | ||
205 | struct saa7134_input inputs[SAA7134_INPUT_MAX]; | ||
206 | struct saa7134_input radio; | ||
207 | struct saa7134_input mute; | ||
208 | |||
209 | /* i2c chip info */ | ||
210 | unsigned int tuner_type; | ||
211 | unsigned int tda9887_conf; | ||
212 | |||
213 | /* peripheral I/O */ | ||
214 | enum saa7134_video_out video_out; | ||
215 | enum saa7134_mpeg_type mpeg; | ||
216 | }; | ||
217 | |||
218 | #define card_has_radio(dev) (NULL != saa7134_boards[dev->board].radio.name) | ||
219 | #define card_is_empress(dev) (SAA7134_MPEG_EMPRESS == saa7134_boards[dev->board].mpeg) | ||
220 | #define card_is_dvb(dev) (SAA7134_MPEG_DVB == saa7134_boards[dev->board].mpeg) | ||
221 | #define card_has_mpeg(dev) (SAA7134_MPEG_UNUSED != saa7134_boards[dev->board].mpeg) | ||
222 | #define card(dev) (saa7134_boards[dev->board]) | ||
223 | #define card_in(dev,n) (saa7134_boards[dev->board].inputs[n]) | ||
224 | |||
225 | /* ----------------------------------------------------------- */ | ||
226 | /* device / file handle status */ | ||
227 | |||
228 | #define RESOURCE_OVERLAY 1 | ||
229 | #define RESOURCE_VIDEO 2 | ||
230 | #define RESOURCE_VBI 4 | ||
231 | |||
232 | #define INTERLACE_AUTO 0 | ||
233 | #define INTERLACE_ON 1 | ||
234 | #define INTERLACE_OFF 2 | ||
235 | |||
236 | #define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */ | ||
237 | |||
238 | struct saa7134_dev; | ||
239 | struct saa7134_dma; | ||
240 | |||
241 | /* saa7134 page table */ | ||
242 | struct saa7134_pgtable { | ||
243 | unsigned int size; | ||
244 | u32 *cpu; | ||
245 | dma_addr_t dma; | ||
246 | }; | ||
247 | |||
248 | /* tvaudio thread status */ | ||
249 | struct saa7134_thread { | ||
250 | pid_t pid; | ||
251 | struct completion exit; | ||
252 | wait_queue_head_t wq; | ||
253 | unsigned int shutdown; | ||
254 | unsigned int scan1; | ||
255 | unsigned int scan2; | ||
256 | unsigned int mode; | ||
257 | }; | ||
258 | |||
259 | /* buffer for one video/vbi/ts frame */ | ||
260 | struct saa7134_buf { | ||
261 | /* common v4l buffer stuff -- must be first */ | ||
262 | struct videobuf_buffer vb; | ||
263 | |||
264 | /* saa7134 specific */ | ||
265 | struct saa7134_format *fmt; | ||
266 | unsigned int top_seen; | ||
267 | int (*activate)(struct saa7134_dev *dev, | ||
268 | struct saa7134_buf *buf, | ||
269 | struct saa7134_buf *next); | ||
270 | |||
271 | /* page tables */ | ||
272 | struct saa7134_pgtable *pt; | ||
273 | }; | ||
274 | |||
275 | struct saa7134_dmaqueue { | ||
276 | struct saa7134_dev *dev; | ||
277 | struct saa7134_buf *curr; | ||
278 | struct list_head queue; | ||
279 | struct timer_list timeout; | ||
280 | unsigned int need_two; | ||
281 | }; | ||
282 | |||
283 | /* video filehandle status */ | ||
284 | struct saa7134_fh { | ||
285 | struct saa7134_dev *dev; | ||
286 | unsigned int radio; | ||
287 | enum v4l2_buf_type type; | ||
288 | unsigned int resources; | ||
289 | #ifdef VIDIOC_G_PRIORITY | ||
290 | enum v4l2_priority prio; | ||
291 | #endif | ||
292 | |||
293 | /* video overlay */ | ||
294 | struct v4l2_window win; | ||
295 | struct v4l2_clip clips[8]; | ||
296 | unsigned int nclips; | ||
297 | |||
298 | /* video capture */ | ||
299 | struct saa7134_format *fmt; | ||
300 | unsigned int width,height; | ||
301 | struct videobuf_queue cap; | ||
302 | struct saa7134_pgtable pt_cap; | ||
303 | |||
304 | /* vbi capture */ | ||
305 | struct videobuf_queue vbi; | ||
306 | struct saa7134_pgtable pt_vbi; | ||
307 | }; | ||
308 | |||
309 | /* oss dsp status */ | ||
310 | struct saa7134_oss { | ||
311 | struct semaphore lock; | ||
312 | int minor_mixer; | ||
313 | int minor_dsp; | ||
314 | unsigned int users_dsp; | ||
315 | |||
316 | /* mixer */ | ||
317 | enum saa7134_audio_in input; | ||
318 | unsigned int count; | ||
319 | unsigned int line1; | ||
320 | unsigned int line2; | ||
321 | |||
322 | /* dsp */ | ||
323 | unsigned int afmt; | ||
324 | unsigned int rate; | ||
325 | unsigned int channels; | ||
326 | unsigned int recording_on; | ||
327 | unsigned int dma_running; | ||
328 | unsigned int blocks; | ||
329 | unsigned int blksize; | ||
330 | unsigned int bufsize; | ||
331 | struct saa7134_pgtable pt; | ||
332 | struct videobuf_dmabuf dma; | ||
333 | wait_queue_head_t wq; | ||
334 | unsigned int dma_blk; | ||
335 | unsigned int read_offset; | ||
336 | unsigned int read_count; | ||
337 | }; | ||
338 | |||
339 | /* IR input */ | ||
340 | struct saa7134_ir { | ||
341 | struct input_dev dev; | ||
342 | struct ir_input_state ir; | ||
343 | char name[32]; | ||
344 | char phys[32]; | ||
345 | u32 mask_keycode; | ||
346 | u32 mask_keydown; | ||
347 | u32 mask_keyup; | ||
348 | int polling; | ||
349 | u32 last_gpio; | ||
350 | struct timer_list timer; | ||
351 | }; | ||
352 | |||
353 | /* ts/mpeg status */ | ||
354 | struct saa7134_ts { | ||
355 | /* TS capture */ | ||
356 | struct saa7134_pgtable pt_ts; | ||
357 | int nr_packets; | ||
358 | int nr_bufs; | ||
359 | }; | ||
360 | |||
361 | /* ts/mpeg ops */ | ||
362 | struct saa7134_mpeg_ops { | ||
363 | enum saa7134_mpeg_type type; | ||
364 | struct list_head next; | ||
365 | int (*init)(struct saa7134_dev *dev); | ||
366 | int (*fini)(struct saa7134_dev *dev); | ||
367 | void (*signal_change)(struct saa7134_dev *dev); | ||
368 | }; | ||
369 | |||
370 | /* global device status */ | ||
371 | struct saa7134_dev { | ||
372 | struct list_head devlist; | ||
373 | struct semaphore lock; | ||
374 | spinlock_t slock; | ||
375 | #ifdef VIDIOC_G_PRIORITY | ||
376 | struct v4l2_prio_state prio; | ||
377 | #endif | ||
378 | |||
379 | /* various device info */ | ||
380 | unsigned int resources; | ||
381 | struct video_device *video_dev; | ||
382 | struct video_device *radio_dev; | ||
383 | struct video_device *vbi_dev; | ||
384 | struct saa7134_oss oss; | ||
385 | |||
386 | /* infrared remote */ | ||
387 | int has_remote; | ||
388 | struct saa7134_ir *remote; | ||
389 | |||
390 | /* pci i/o */ | ||
391 | char name[32]; | ||
392 | int nr; | ||
393 | struct pci_dev *pci; | ||
394 | unsigned char pci_rev,pci_lat; | ||
395 | __u32 __iomem *lmmio; | ||
396 | __u8 __iomem *bmmio; | ||
397 | |||
398 | /* config info */ | ||
399 | unsigned int board; | ||
400 | unsigned int tuner_type; | ||
401 | unsigned int tda9887_conf; | ||
402 | unsigned int gpio_value; | ||
403 | unsigned int irq2_mask; | ||
404 | |||
405 | /* i2c i/o */ | ||
406 | struct i2c_adapter i2c_adap; | ||
407 | struct i2c_client i2c_client; | ||
408 | unsigned char eedata[64]; | ||
409 | |||
410 | /* video overlay */ | ||
411 | struct v4l2_framebuffer ovbuf; | ||
412 | struct saa7134_format *ovfmt; | ||
413 | unsigned int ovenable; | ||
414 | enum v4l2_field ovfield; | ||
415 | |||
416 | /* video+ts+vbi capture */ | ||
417 | struct saa7134_dmaqueue video_q; | ||
418 | struct saa7134_dmaqueue vbi_q; | ||
419 | unsigned int video_fieldcount; | ||
420 | unsigned int vbi_fieldcount; | ||
421 | |||
422 | /* various v4l controls */ | ||
423 | struct saa7134_tvnorm *tvnorm; /* video */ | ||
424 | struct saa7134_tvaudio *tvaudio; | ||
425 | unsigned int ctl_input; | ||
426 | int ctl_bright; | ||
427 | int ctl_contrast; | ||
428 | int ctl_hue; | ||
429 | int ctl_saturation; | ||
430 | int ctl_freq; | ||
431 | int ctl_mute; /* audio */ | ||
432 | int ctl_volume; | ||
433 | int ctl_invert; /* private */ | ||
434 | int ctl_mirror; | ||
435 | int ctl_y_odd; | ||
436 | int ctl_y_even; | ||
437 | int ctl_automute; | ||
438 | |||
439 | /* crop */ | ||
440 | struct v4l2_rect crop_bounds; | ||
441 | struct v4l2_rect crop_defrect; | ||
442 | struct v4l2_rect crop_current; | ||
443 | |||
444 | /* other global state info */ | ||
445 | unsigned int automute; | ||
446 | struct saa7134_thread thread; | ||
447 | struct saa7134_input *input; | ||
448 | struct saa7134_input *hw_input; | ||
449 | unsigned int hw_mute; | ||
450 | int last_carrier; | ||
451 | int nosignal; | ||
452 | |||
453 | /* SAA7134_MPEG_* */ | ||
454 | struct saa7134_ts ts; | ||
455 | struct saa7134_dmaqueue ts_q; | ||
456 | struct saa7134_mpeg_ops *mops; | ||
457 | |||
458 | /* SAA7134_MPEG_EMPRESS only */ | ||
459 | struct video_device *empress_dev; | ||
460 | struct videobuf_queue empress_tsq; | ||
461 | unsigned int empress_users; | ||
462 | struct work_struct empress_workqueue; | ||
463 | int empress_started; | ||
464 | |||
465 | /* SAA7134_MPEG_DVB only */ | ||
466 | struct videobuf_dvb dvb; | ||
467 | }; | ||
468 | |||
469 | /* ----------------------------------------------------------- */ | ||
470 | |||
471 | #define saa_readl(reg) readl(dev->lmmio + (reg)) | ||
472 | #define saa_writel(reg,value) writel((value), dev->lmmio + (reg)); | ||
473 | #define saa_andorl(reg,mask,value) \ | ||
474 | writel((readl(dev->lmmio+(reg)) & ~(mask)) |\ | ||
475 | ((value) & (mask)), dev->lmmio+(reg)) | ||
476 | #define saa_setl(reg,bit) saa_andorl((reg),(bit),(bit)) | ||
477 | #define saa_clearl(reg,bit) saa_andorl((reg),(bit),0) | ||
478 | |||
479 | #define saa_readb(reg) readb(dev->bmmio + (reg)) | ||
480 | #define saa_writeb(reg,value) writeb((value), dev->bmmio + (reg)); | ||
481 | #define saa_andorb(reg,mask,value) \ | ||
482 | writeb((readb(dev->bmmio+(reg)) & ~(mask)) |\ | ||
483 | ((value) & (mask)), dev->bmmio+(reg)) | ||
484 | #define saa_setb(reg,bit) saa_andorb((reg),(bit),(bit)) | ||
485 | #define saa_clearb(reg,bit) saa_andorb((reg),(bit),0) | ||
486 | |||
487 | #define saa_wait(us) { udelay(us); } | ||
488 | |||
489 | /* ----------------------------------------------------------- */ | ||
490 | /* saa7134-core.c */ | ||
491 | |||
492 | extern struct list_head saa7134_devlist; | ||
493 | |||
494 | void saa7134_print_ioctl(char *name, unsigned int cmd); | ||
495 | void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); | ||
496 | |||
497 | #define SAA7134_PGTABLE_SIZE 4096 | ||
498 | |||
499 | int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt); | ||
500 | int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, | ||
501 | struct scatterlist *list, unsigned int length, | ||
502 | unsigned int startpage); | ||
503 | void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt); | ||
504 | |||
505 | int saa7134_buffer_count(unsigned int size, unsigned int count); | ||
506 | int saa7134_buffer_startpage(struct saa7134_buf *buf); | ||
507 | unsigned long saa7134_buffer_base(struct saa7134_buf *buf); | ||
508 | |||
509 | int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, | ||
510 | struct saa7134_buf *buf); | ||
511 | void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, | ||
512 | unsigned int state); | ||
513 | void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q); | ||
514 | void saa7134_buffer_timeout(unsigned long data); | ||
515 | void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf); | ||
516 | |||
517 | int saa7134_set_dmabits(struct saa7134_dev *dev); | ||
518 | |||
519 | /* ----------------------------------------------------------- */ | ||
520 | /* saa7134-cards.c */ | ||
521 | |||
522 | extern struct saa7134_board saa7134_boards[]; | ||
523 | extern const unsigned int saa7134_bcount; | ||
524 | extern struct pci_device_id __devinitdata saa7134_pci_tbl[]; | ||
525 | |||
526 | extern int saa7134_board_init1(struct saa7134_dev *dev); | ||
527 | extern int saa7134_board_init2(struct saa7134_dev *dev); | ||
528 | |||
529 | |||
530 | /* ----------------------------------------------------------- */ | ||
531 | /* saa7134-i2c.c */ | ||
532 | |||
533 | int saa7134_i2c_register(struct saa7134_dev *dev); | ||
534 | int saa7134_i2c_unregister(struct saa7134_dev *dev); | ||
535 | void saa7134_i2c_call_clients(struct saa7134_dev *dev, | ||
536 | unsigned int cmd, void *arg); | ||
537 | |||
538 | |||
539 | /* ----------------------------------------------------------- */ | ||
540 | /* saa7134-video.c */ | ||
541 | |||
542 | extern struct video_device saa7134_video_template; | ||
543 | extern struct video_device saa7134_radio_template; | ||
544 | |||
545 | int saa7134_common_ioctl(struct saa7134_dev *dev, | ||
546 | unsigned int cmd, void *arg); | ||
547 | |||
548 | int saa7134_video_init1(struct saa7134_dev *dev); | ||
549 | int saa7134_video_init2(struct saa7134_dev *dev); | ||
550 | int saa7134_video_fini(struct saa7134_dev *dev); | ||
551 | void saa7134_irq_video_intl(struct saa7134_dev *dev); | ||
552 | void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status); | ||
553 | |||
554 | |||
555 | /* ----------------------------------------------------------- */ | ||
556 | /* saa7134-ts.c */ | ||
557 | |||
558 | #define TS_PACKET_SIZE 188 /* TS packets 188 bytes */ | ||
559 | |||
560 | extern struct videobuf_queue_ops saa7134_ts_qops; | ||
561 | |||
562 | int saa7134_ts_init1(struct saa7134_dev *dev); | ||
563 | int saa7134_ts_fini(struct saa7134_dev *dev); | ||
564 | void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status); | ||
565 | |||
566 | int saa7134_ts_register(struct saa7134_mpeg_ops *ops); | ||
567 | void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops); | ||
568 | |||
569 | /* ----------------------------------------------------------- */ | ||
570 | /* saa7134-vbi.c */ | ||
571 | |||
572 | extern struct videobuf_queue_ops saa7134_vbi_qops; | ||
573 | extern struct video_device saa7134_vbi_template; | ||
574 | |||
575 | int saa7134_vbi_init1(struct saa7134_dev *dev); | ||
576 | int saa7134_vbi_fini(struct saa7134_dev *dev); | ||
577 | void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status); | ||
578 | |||
579 | |||
580 | /* ----------------------------------------------------------- */ | ||
581 | /* saa7134-tvaudio.c */ | ||
582 | |||
583 | int saa7134_tvaudio_rx2mode(u32 rx); | ||
584 | |||
585 | void saa7134_tvaudio_setmute(struct saa7134_dev *dev); | ||
586 | void saa7134_tvaudio_setinput(struct saa7134_dev *dev, | ||
587 | struct saa7134_input *in); | ||
588 | void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level); | ||
589 | int saa7134_tvaudio_getstereo(struct saa7134_dev *dev); | ||
590 | |||
591 | int saa7134_tvaudio_init2(struct saa7134_dev *dev); | ||
592 | int saa7134_tvaudio_fini(struct saa7134_dev *dev); | ||
593 | int saa7134_tvaudio_do_scan(struct saa7134_dev *dev); | ||
594 | |||
595 | int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value); | ||
596 | |||
597 | /* ----------------------------------------------------------- */ | ||
598 | /* saa7134-oss.c */ | ||
599 | |||
600 | extern struct file_operations saa7134_dsp_fops; | ||
601 | extern struct file_operations saa7134_mixer_fops; | ||
602 | |||
603 | int saa7134_oss_init1(struct saa7134_dev *dev); | ||
604 | int saa7134_oss_fini(struct saa7134_dev *dev); | ||
605 | void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status); | ||
606 | |||
607 | /* ----------------------------------------------------------- */ | ||
608 | /* saa7134-input.c */ | ||
609 | |||
610 | int saa7134_input_init1(struct saa7134_dev *dev); | ||
611 | void saa7134_input_fini(struct saa7134_dev *dev); | ||
612 | void saa7134_input_irq(struct saa7134_dev *dev); | ||
613 | |||
614 | /* | ||
615 | * Local variables: | ||
616 | * c-basic-offset: 8 | ||
617 | * End: | ||
618 | */ | ||