diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/dvb/ttpci/av7110_av.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/media/dvb/ttpci/av7110_av.c')
-rw-r--r-- | drivers/media/dvb/ttpci/av7110_av.c | 1459 |
1 files changed, 1459 insertions, 0 deletions
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c new file mode 100644 index 000000000000..d77e8a00688f --- /dev/null +++ b/drivers/media/dvb/ttpci/av7110_av.c | |||
@@ -0,0 +1,1459 @@ | |||
1 | /* | ||
2 | * av7110_av.c: audio and video MPEG decoder stuff | ||
3 | * | ||
4 | * Copyright (C) 1999-2002 Ralph Metzler | ||
5 | * & Marcus Metzler for convergence integrated media GmbH | ||
6 | * | ||
7 | * originally based on code by: | ||
8 | * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or | ||
11 | * modify it under the terms of the GNU General Public License | ||
12 | * as published by the Free Software Foundation; either version 2 | ||
13 | * of the License, or (at your option) any later version. | ||
14 | * | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
25 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
26 | * | ||
27 | * | ||
28 | * the project's page is at http://www.linuxtv.org/dvb/ | ||
29 | */ | ||
30 | |||
31 | #include <linux/types.h> | ||
32 | #include <linux/kernel.h> | ||
33 | #include <linux/string.h> | ||
34 | #include <linux/sched.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/byteorder/swabb.h> | ||
37 | #include <linux/smp_lock.h> | ||
38 | #include <linux/fs.h> | ||
39 | |||
40 | #include "av7110.h" | ||
41 | #include "av7110_hw.h" | ||
42 | #include "av7110_av.h" | ||
43 | #include "av7110_ipack.h" | ||
44 | |||
45 | /* MPEG-2 (ISO 13818 / H.222.0) stream types */ | ||
46 | #define PROG_STREAM_MAP 0xBC | ||
47 | #define PRIVATE_STREAM1 0xBD | ||
48 | #define PADDING_STREAM 0xBE | ||
49 | #define PRIVATE_STREAM2 0xBF | ||
50 | #define AUDIO_STREAM_S 0xC0 | ||
51 | #define AUDIO_STREAM_E 0xDF | ||
52 | #define VIDEO_STREAM_S 0xE0 | ||
53 | #define VIDEO_STREAM_E 0xEF | ||
54 | #define ECM_STREAM 0xF0 | ||
55 | #define EMM_STREAM 0xF1 | ||
56 | #define DSM_CC_STREAM 0xF2 | ||
57 | #define ISO13522_STREAM 0xF3 | ||
58 | #define PROG_STREAM_DIR 0xFF | ||
59 | |||
60 | #define PTS_DTS_FLAGS 0xC0 | ||
61 | |||
62 | //pts_dts flags | ||
63 | #define PTS_ONLY 0x80 | ||
64 | #define PTS_DTS 0xC0 | ||
65 | #define TS_SIZE 188 | ||
66 | #define TRANS_ERROR 0x80 | ||
67 | #define PAY_START 0x40 | ||
68 | #define TRANS_PRIO 0x20 | ||
69 | #define PID_MASK_HI 0x1F | ||
70 | //flags | ||
71 | #define TRANS_SCRMBL1 0x80 | ||
72 | #define TRANS_SCRMBL2 0x40 | ||
73 | #define ADAPT_FIELD 0x20 | ||
74 | #define PAYLOAD 0x10 | ||
75 | #define COUNT_MASK 0x0F | ||
76 | |||
77 | // adaptation flags | ||
78 | #define DISCON_IND 0x80 | ||
79 | #define RAND_ACC_IND 0x40 | ||
80 | #define ES_PRI_IND 0x20 | ||
81 | #define PCR_FLAG 0x10 | ||
82 | #define OPCR_FLAG 0x08 | ||
83 | #define SPLICE_FLAG 0x04 | ||
84 | #define TRANS_PRIV 0x02 | ||
85 | #define ADAP_EXT_FLAG 0x01 | ||
86 | |||
87 | // adaptation extension flags | ||
88 | #define LTW_FLAG 0x80 | ||
89 | #define PIECE_RATE 0x40 | ||
90 | #define SEAM_SPLICE 0x20 | ||
91 | |||
92 | |||
93 | static void p_to_t(u8 const *buf, long int length, u16 pid, | ||
94 | u8 *counter, struct dvb_demux_feed *feed); | ||
95 | |||
96 | |||
97 | int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len) | ||
98 | { | ||
99 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv; | ||
100 | |||
101 | if (!(dvbdmxfeed->ts_type & TS_PACKET)) | ||
102 | return 0; | ||
103 | if (buf[3] == 0xe0) // video PES do not have a length in TS | ||
104 | buf[4] = buf[5] = 0; | ||
105 | if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) | ||
106 | return dvbdmxfeed->cb.ts(buf, len, NULL, 0, | ||
107 | &dvbdmxfeed->feed.ts, DMX_OK); | ||
108 | else | ||
109 | return dvb_filter_pes2ts(p2t, buf, len, 1); | ||
110 | } | ||
111 | |||
112 | static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data) | ||
113 | { | ||
114 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv; | ||
115 | |||
116 | dvbdmxfeed->cb.ts(data, 188, NULL, 0, | ||
117 | &dvbdmxfeed->feed.ts, DMX_OK); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | int av7110_av_start_record(struct av7110 *av7110, int av, | ||
122 | struct dvb_demux_feed *dvbdmxfeed) | ||
123 | { | ||
124 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
125 | |||
126 | dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed); | ||
127 | |||
128 | if (av7110->playing || (av7110->rec_mode & av)) | ||
129 | return -EBUSY; | ||
130 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); | ||
131 | dvbdmx->recording = 1; | ||
132 | av7110->rec_mode |= av; | ||
133 | |||
134 | switch (av7110->rec_mode) { | ||
135 | case RP_AUDIO: | ||
136 | dvb_filter_pes2ts_init(&av7110->p2t[0], | ||
137 | dvbdmx->pesfilter[0]->pid, | ||
138 | dvb_filter_pes2ts_cb, | ||
139 | (void *) dvbdmx->pesfilter[0]); | ||
140 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); | ||
141 | break; | ||
142 | |||
143 | case RP_VIDEO: | ||
144 | dvb_filter_pes2ts_init(&av7110->p2t[1], | ||
145 | dvbdmx->pesfilter[1]->pid, | ||
146 | dvb_filter_pes2ts_cb, | ||
147 | (void *) dvbdmx->pesfilter[1]); | ||
148 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); | ||
149 | break; | ||
150 | |||
151 | case RP_AV: | ||
152 | dvb_filter_pes2ts_init(&av7110->p2t[0], | ||
153 | dvbdmx->pesfilter[0]->pid, | ||
154 | dvb_filter_pes2ts_cb, | ||
155 | (void *) dvbdmx->pesfilter[0]); | ||
156 | dvb_filter_pes2ts_init(&av7110->p2t[1], | ||
157 | dvbdmx->pesfilter[1]->pid, | ||
158 | dvb_filter_pes2ts_cb, | ||
159 | (void *) dvbdmx->pesfilter[1]); | ||
160 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0); | ||
161 | break; | ||
162 | } | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | int av7110_av_start_play(struct av7110 *av7110, int av) | ||
167 | { | ||
168 | dprintk(2, "av7110:%p, \n", av7110); | ||
169 | |||
170 | if (av7110->rec_mode) | ||
171 | return -EBUSY; | ||
172 | if (av7110->playing & av) | ||
173 | return -EBUSY; | ||
174 | |||
175 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); | ||
176 | |||
177 | if (av7110->playing == RP_NONE) { | ||
178 | av7110_ipack_reset(&av7110->ipack[0]); | ||
179 | av7110_ipack_reset(&av7110->ipack[1]); | ||
180 | } | ||
181 | |||
182 | av7110->playing |= av; | ||
183 | switch (av7110->playing) { | ||
184 | case RP_AUDIO: | ||
185 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); | ||
186 | break; | ||
187 | case RP_VIDEO: | ||
188 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); | ||
189 | av7110->sinfo = 0; | ||
190 | break; | ||
191 | case RP_AV: | ||
192 | av7110->sinfo = 0; | ||
193 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0); | ||
194 | break; | ||
195 | } | ||
196 | return av7110->playing; | ||
197 | } | ||
198 | |||
199 | void av7110_av_stop(struct av7110 *av7110, int av) | ||
200 | { | ||
201 | dprintk(2, "av7110:%p, \n", av7110); | ||
202 | |||
203 | if (!(av7110->playing & av) && !(av7110->rec_mode & av)) | ||
204 | return; | ||
205 | |||
206 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); | ||
207 | if (av7110->playing) { | ||
208 | av7110->playing &= ~av; | ||
209 | switch (av7110->playing) { | ||
210 | case RP_AUDIO: | ||
211 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0); | ||
212 | break; | ||
213 | case RP_VIDEO: | ||
214 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0); | ||
215 | break; | ||
216 | case RP_NONE: | ||
217 | av7110_set_vidmode(av7110, av7110->vidmode); | ||
218 | break; | ||
219 | } | ||
220 | } else { | ||
221 | av7110->rec_mode &= ~av; | ||
222 | switch (av7110->rec_mode) { | ||
223 | case RP_AUDIO: | ||
224 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0); | ||
225 | break; | ||
226 | case RP_VIDEO: | ||
227 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0); | ||
228 | break; | ||
229 | case RP_NONE: | ||
230 | break; | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | |||
235 | |||
236 | int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen) | ||
237 | { | ||
238 | int len; | ||
239 | u32 sync; | ||
240 | u16 blen; | ||
241 | |||
242 | if (!dlen) { | ||
243 | wake_up(&buf->queue); | ||
244 | return -1; | ||
245 | } | ||
246 | while (1) { | ||
247 | if ((len = dvb_ringbuffer_avail(buf)) < 6) | ||
248 | return -1; | ||
249 | sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24; | ||
250 | sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16; | ||
251 | sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8; | ||
252 | sync |= DVB_RINGBUFFER_PEEK(buf, 3); | ||
253 | |||
254 | if (((sync &~ 0x0f) == 0x000001e0) || | ||
255 | ((sync &~ 0x1f) == 0x000001c0) || | ||
256 | (sync == 0x000001bd)) | ||
257 | break; | ||
258 | printk("resync\n"); | ||
259 | DVB_RINGBUFFER_SKIP(buf, 1); | ||
260 | } | ||
261 | blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8; | ||
262 | blen |= DVB_RINGBUFFER_PEEK(buf, 5); | ||
263 | blen += 6; | ||
264 | if (len < blen || blen > dlen) { | ||
265 | //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen); | ||
266 | wake_up(&buf->queue); | ||
267 | return -1; | ||
268 | } | ||
269 | |||
270 | dvb_ringbuffer_read(buf, dest, (size_t) blen, 0); | ||
271 | |||
272 | dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n", | ||
273 | (unsigned long) buf->pread, (unsigned long) buf->pwrite); | ||
274 | wake_up(&buf->queue); | ||
275 | return blen; | ||
276 | } | ||
277 | |||
278 | |||
279 | int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) | ||
280 | { | ||
281 | int err, vol, val, balance = 0; | ||
282 | |||
283 | dprintk(2, "av7110:%p, \n", av7110); | ||
284 | |||
285 | av7110->mixer.volume_left = volleft; | ||
286 | av7110->mixer.volume_right = volright; | ||
287 | |||
288 | switch (av7110->adac_type) { | ||
289 | case DVB_ADAC_TI: | ||
290 | volleft = (volleft * 256) / 1036; | ||
291 | volright = (volright * 256) / 1036; | ||
292 | if (volleft > 0x3f) | ||
293 | volleft = 0x3f; | ||
294 | if (volright > 0x3f) | ||
295 | volright = 0x3f; | ||
296 | if ((err = SendDAC(av7110, 3, 0x80 + volleft))) | ||
297 | return err; | ||
298 | return SendDAC(av7110, 4, volright); | ||
299 | |||
300 | case DVB_ADAC_CRYSTAL: | ||
301 | volleft = 127 - volleft / 2; | ||
302 | volright = 127 - volright / 2; | ||
303 | i2c_writereg(av7110, 0x20, 0x03, volleft); | ||
304 | i2c_writereg(av7110, 0x20, 0x04, volright); | ||
305 | return 0; | ||
306 | |||
307 | case DVB_ADAC_MSP: | ||
308 | vol = (volleft > volright) ? volleft : volright; | ||
309 | val = (vol * 0x73 / 255) << 8; | ||
310 | if (vol > 0) | ||
311 | balance = ((volright - volleft) * 127) / vol; | ||
312 | msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); | ||
313 | msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ | ||
314 | msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ | ||
315 | return 0; | ||
316 | } | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | void av7110_set_vidmode(struct av7110 *av7110, int mode) | ||
321 | { | ||
322 | dprintk(2, "av7110:%p, \n", av7110); | ||
323 | |||
324 | av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode); | ||
325 | |||
326 | if (!av7110->playing) { | ||
327 | ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO], | ||
328 | av7110->pids[DMX_PES_AUDIO], | ||
329 | av7110->pids[DMX_PES_TELETEXT], | ||
330 | 0, av7110->pids[DMX_PES_PCR]); | ||
331 | av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0); | ||
332 | } | ||
333 | } | ||
334 | |||
335 | |||
336 | static int sw2mode[16] = { | ||
337 | VIDEO_MODE_PAL, VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, | ||
338 | VIDEO_MODE_NTSC, VIDEO_MODE_NTSC, VIDEO_MODE_PAL, VIDEO_MODE_NTSC, | ||
339 | VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, | ||
340 | VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, | ||
341 | }; | ||
342 | |||
343 | static void get_video_format(struct av7110 *av7110, u8 *buf, int count) | ||
344 | { | ||
345 | int i; | ||
346 | int hsize, vsize; | ||
347 | int sw; | ||
348 | u8 *p; | ||
349 | |||
350 | dprintk(2, "av7110:%p, \n", av7110); | ||
351 | |||
352 | if (av7110->sinfo) | ||
353 | return; | ||
354 | for (i = 7; i < count - 10; i++) { | ||
355 | p = buf + i; | ||
356 | if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3) | ||
357 | continue; | ||
358 | p += 4; | ||
359 | hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4); | ||
360 | vsize = ((p[1] &0x0F) << 8) | (p[2]); | ||
361 | sw = (p[3] & 0x0F); | ||
362 | av7110_set_vidmode(av7110, sw2mode[sw]); | ||
363 | dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw); | ||
364 | av7110->sinfo = 1; | ||
365 | break; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | |||
370 | /**************************************************************************** | ||
371 | * I/O buffer management and control | ||
372 | ****************************************************************************/ | ||
373 | |||
374 | static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf, | ||
375 | const char *buf, unsigned long count) | ||
376 | { | ||
377 | unsigned long todo = count; | ||
378 | int free; | ||
379 | |||
380 | while (todo > 0) { | ||
381 | if (dvb_ringbuffer_free(rbuf) < 2048) { | ||
382 | if (wait_event_interruptible(rbuf->queue, | ||
383 | (dvb_ringbuffer_free(rbuf) >= 2048))) | ||
384 | return count - todo; | ||
385 | } | ||
386 | free = dvb_ringbuffer_free(rbuf); | ||
387 | if (free > todo) | ||
388 | free = todo; | ||
389 | dvb_ringbuffer_write(rbuf, buf, free); | ||
390 | todo -= free; | ||
391 | buf += free; | ||
392 | } | ||
393 | |||
394 | return count - todo; | ||
395 | } | ||
396 | |||
397 | static void play_video_cb(u8 *buf, int count, void *priv) | ||
398 | { | ||
399 | struct av7110 *av7110 = (struct av7110 *) priv; | ||
400 | dprintk(2, "av7110:%p, \n", av7110); | ||
401 | |||
402 | if ((buf[3] & 0xe0) == 0xe0) { | ||
403 | get_video_format(av7110, buf, count); | ||
404 | aux_ring_buffer_write(&av7110->avout, buf, count); | ||
405 | } else | ||
406 | aux_ring_buffer_write(&av7110->aout, buf, count); | ||
407 | } | ||
408 | |||
409 | static void play_audio_cb(u8 *buf, int count, void *priv) | ||
410 | { | ||
411 | struct av7110 *av7110 = (struct av7110 *) priv; | ||
412 | dprintk(2, "av7110:%p, \n", av7110); | ||
413 | |||
414 | aux_ring_buffer_write(&av7110->aout, buf, count); | ||
415 | } | ||
416 | |||
417 | #define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \ | ||
418 | dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) | ||
419 | |||
420 | static ssize_t dvb_play(struct av7110 *av7110, const u8 __user *buf, | ||
421 | unsigned long count, int nonblock, int type) | ||
422 | { | ||
423 | unsigned long todo = count, n; | ||
424 | dprintk(2, "av7110:%p, \n", av7110); | ||
425 | |||
426 | if (!av7110->kbuf[type]) | ||
427 | return -ENOBUFS; | ||
428 | |||
429 | if (nonblock && !FREE_COND) | ||
430 | return -EWOULDBLOCK; | ||
431 | |||
432 | while (todo > 0) { | ||
433 | if (!FREE_COND) { | ||
434 | if (nonblock) | ||
435 | return count - todo; | ||
436 | if (wait_event_interruptible(av7110->avout.queue, | ||
437 | FREE_COND)) | ||
438 | return count - todo; | ||
439 | } | ||
440 | n = todo; | ||
441 | if (n > IPACKS * 2) | ||
442 | n = IPACKS * 2; | ||
443 | if (copy_from_user(av7110->kbuf[type], buf, n)) | ||
444 | return -EFAULT; | ||
445 | av7110_ipack_instant_repack(av7110->kbuf[type], n, | ||
446 | &av7110->ipack[type]); | ||
447 | todo -= n; | ||
448 | buf += n; | ||
449 | } | ||
450 | return count - todo; | ||
451 | } | ||
452 | |||
453 | static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf, | ||
454 | unsigned long count, int nonblock, int type) | ||
455 | { | ||
456 | unsigned long todo = count, n; | ||
457 | dprintk(2, "av7110:%p, \n", av7110); | ||
458 | |||
459 | if (!av7110->kbuf[type]) | ||
460 | return -ENOBUFS; | ||
461 | |||
462 | if (nonblock && !FREE_COND) | ||
463 | return -EWOULDBLOCK; | ||
464 | |||
465 | while (todo > 0) { | ||
466 | if (!FREE_COND) { | ||
467 | if (nonblock) | ||
468 | return count - todo; | ||
469 | if (wait_event_interruptible(av7110->avout.queue, | ||
470 | FREE_COND)) | ||
471 | return count - todo; | ||
472 | } | ||
473 | n = todo; | ||
474 | if (n > IPACKS * 2) | ||
475 | n = IPACKS * 2; | ||
476 | av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]); | ||
477 | todo -= n; | ||
478 | buf += n; | ||
479 | } | ||
480 | return count - todo; | ||
481 | } | ||
482 | |||
483 | static ssize_t dvb_aplay(struct av7110 *av7110, const u8 __user *buf, | ||
484 | unsigned long count, int nonblock, int type) | ||
485 | { | ||
486 | unsigned long todo = count, n; | ||
487 | dprintk(2, "av7110:%p, \n", av7110); | ||
488 | |||
489 | if (!av7110->kbuf[type]) | ||
490 | return -ENOBUFS; | ||
491 | if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) | ||
492 | return -EWOULDBLOCK; | ||
493 | |||
494 | while (todo > 0) { | ||
495 | if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) { | ||
496 | if (nonblock) | ||
497 | return count - todo; | ||
498 | if (wait_event_interruptible(av7110->aout.queue, | ||
499 | (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024))) | ||
500 | return count-todo; | ||
501 | } | ||
502 | n = todo; | ||
503 | if (n > IPACKS * 2) | ||
504 | n = IPACKS * 2; | ||
505 | if (copy_from_user(av7110->kbuf[type], buf, n)) | ||
506 | return -EFAULT; | ||
507 | av7110_ipack_instant_repack(av7110->kbuf[type], n, | ||
508 | &av7110->ipack[type]); | ||
509 | todo -= n; | ||
510 | buf += n; | ||
511 | } | ||
512 | return count - todo; | ||
513 | } | ||
514 | |||
515 | void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed) | ||
516 | { | ||
517 | memset(p->pes, 0, TS_SIZE); | ||
518 | p->counter = 0; | ||
519 | p->pos = 0; | ||
520 | p->frags = 0; | ||
521 | if (feed) | ||
522 | p->feed = feed; | ||
523 | } | ||
524 | |||
525 | static void clear_p2t(struct av7110_p2t *p) | ||
526 | { | ||
527 | memset(p->pes, 0, TS_SIZE); | ||
528 | // p->counter = 0; | ||
529 | p->pos = 0; | ||
530 | p->frags = 0; | ||
531 | } | ||
532 | |||
533 | |||
534 | static int find_pes_header(u8 const *buf, long int length, int *frags) | ||
535 | { | ||
536 | int c = 0; | ||
537 | int found = 0; | ||
538 | |||
539 | *frags = 0; | ||
540 | |||
541 | while (c < length - 3 && !found) { | ||
542 | if (buf[c] == 0x00 && buf[c + 1] == 0x00 && | ||
543 | buf[c + 2] == 0x01) { | ||
544 | switch ( buf[c + 3] ) { | ||
545 | case PROG_STREAM_MAP: | ||
546 | case PRIVATE_STREAM2: | ||
547 | case PROG_STREAM_DIR: | ||
548 | case ECM_STREAM : | ||
549 | case EMM_STREAM : | ||
550 | case PADDING_STREAM : | ||
551 | case DSM_CC_STREAM : | ||
552 | case ISO13522_STREAM: | ||
553 | case PRIVATE_STREAM1: | ||
554 | case AUDIO_STREAM_S ... AUDIO_STREAM_E: | ||
555 | case VIDEO_STREAM_S ... VIDEO_STREAM_E: | ||
556 | found = 1; | ||
557 | break; | ||
558 | |||
559 | default: | ||
560 | c++; | ||
561 | break; | ||
562 | } | ||
563 | } else | ||
564 | c++; | ||
565 | } | ||
566 | if (c == length - 3 && !found) { | ||
567 | if (buf[length - 1] == 0x00) | ||
568 | *frags = 1; | ||
569 | if (buf[length - 2] == 0x00 && | ||
570 | buf[length - 1] == 0x00) | ||
571 | *frags = 2; | ||
572 | if (buf[length - 3] == 0x00 && | ||
573 | buf[length - 2] == 0x00 && | ||
574 | buf[length - 1] == 0x01) | ||
575 | *frags = 3; | ||
576 | return -1; | ||
577 | } | ||
578 | |||
579 | return c; | ||
580 | } | ||
581 | |||
582 | void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p) | ||
583 | { | ||
584 | int c, c2, l, add; | ||
585 | int check, rest; | ||
586 | |||
587 | c = 0; | ||
588 | c2 = 0; | ||
589 | if (p->frags){ | ||
590 | check = 0; | ||
591 | switch(p->frags) { | ||
592 | case 1: | ||
593 | if (buf[c] == 0x00 && buf[c + 1] == 0x01) { | ||
594 | check = 1; | ||
595 | c += 2; | ||
596 | } | ||
597 | break; | ||
598 | case 2: | ||
599 | if (buf[c] == 0x01) { | ||
600 | check = 1; | ||
601 | c++; | ||
602 | } | ||
603 | break; | ||
604 | case 3: | ||
605 | check = 1; | ||
606 | } | ||
607 | if (check) { | ||
608 | switch (buf[c]) { | ||
609 | case PROG_STREAM_MAP: | ||
610 | case PRIVATE_STREAM2: | ||
611 | case PROG_STREAM_DIR: | ||
612 | case ECM_STREAM : | ||
613 | case EMM_STREAM : | ||
614 | case PADDING_STREAM : | ||
615 | case DSM_CC_STREAM : | ||
616 | case ISO13522_STREAM: | ||
617 | case PRIVATE_STREAM1: | ||
618 | case AUDIO_STREAM_S ... AUDIO_STREAM_E: | ||
619 | case VIDEO_STREAM_S ... VIDEO_STREAM_E: | ||
620 | p->pes[0] = 0x00; | ||
621 | p->pes[1] = 0x00; | ||
622 | p->pes[2] = 0x01; | ||
623 | p->pes[3] = buf[c]; | ||
624 | p->pos = 4; | ||
625 | memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos); | ||
626 | c += (TS_SIZE - 4) - p->pos; | ||
627 | p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed); | ||
628 | clear_p2t(p); | ||
629 | break; | ||
630 | |||
631 | default: | ||
632 | c = 0; | ||
633 | break; | ||
634 | } | ||
635 | } | ||
636 | p->frags = 0; | ||
637 | } | ||
638 | |||
639 | if (p->pos) { | ||
640 | c2 = find_pes_header(buf + c, length - c, &p->frags); | ||
641 | if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos) | ||
642 | l = c2+c; | ||
643 | else | ||
644 | l = (TS_SIZE - 4) - p->pos; | ||
645 | memcpy(p->pes + p->pos, buf, l); | ||
646 | c += l; | ||
647 | p->pos += l; | ||
648 | p_to_t(p->pes, p->pos, pid, &p->counter, p->feed); | ||
649 | clear_p2t(p); | ||
650 | } | ||
651 | |||
652 | add = 0; | ||
653 | while (c < length) { | ||
654 | c2 = find_pes_header(buf + c + add, length - c - add, &p->frags); | ||
655 | if (c2 >= 0) { | ||
656 | c2 += c + add; | ||
657 | if (c2 > c){ | ||
658 | p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed); | ||
659 | c = c2; | ||
660 | clear_p2t(p); | ||
661 | add = 0; | ||
662 | } else | ||
663 | add = 1; | ||
664 | } else { | ||
665 | l = length - c; | ||
666 | rest = l % (TS_SIZE - 4); | ||
667 | l -= rest; | ||
668 | p_to_t(buf + c, l, pid, &p->counter, p->feed); | ||
669 | memcpy(p->pes, buf + c + l, rest); | ||
670 | p->pos = rest; | ||
671 | c = length; | ||
672 | } | ||
673 | } | ||
674 | } | ||
675 | |||
676 | |||
677 | static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length) | ||
678 | { | ||
679 | int i; | ||
680 | int c = 0; | ||
681 | int fill; | ||
682 | u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 }; | ||
683 | |||
684 | fill = (TS_SIZE - 4) - length; | ||
685 | if (pes_start) | ||
686 | tshead[1] = 0x40; | ||
687 | if (fill) | ||
688 | tshead[3] = 0x30; | ||
689 | tshead[1] |= (u8)((pid & 0x1F00) >> 8); | ||
690 | tshead[2] |= (u8)(pid & 0x00FF); | ||
691 | tshead[3] |= ((*counter)++ & 0x0F); | ||
692 | memcpy(buf, tshead, 4); | ||
693 | c += 4; | ||
694 | |||
695 | if (fill) { | ||
696 | buf[4] = fill - 1; | ||
697 | c++; | ||
698 | if (fill > 1) { | ||
699 | buf[5] = 0x00; | ||
700 | c++; | ||
701 | } | ||
702 | for (i = 6; i < fill + 4; i++) { | ||
703 | buf[i] = 0xFF; | ||
704 | c++; | ||
705 | } | ||
706 | } | ||
707 | |||
708 | return c; | ||
709 | } | ||
710 | |||
711 | |||
712 | static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter, | ||
713 | struct dvb_demux_feed *feed) | ||
714 | { | ||
715 | int l, pes_start; | ||
716 | u8 obuf[TS_SIZE]; | ||
717 | long c = 0; | ||
718 | |||
719 | pes_start = 0; | ||
720 | if (length > 3 && | ||
721 | buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01) | ||
722 | switch (buf[3]) { | ||
723 | case PROG_STREAM_MAP: | ||
724 | case PRIVATE_STREAM2: | ||
725 | case PROG_STREAM_DIR: | ||
726 | case ECM_STREAM : | ||
727 | case EMM_STREAM : | ||
728 | case PADDING_STREAM : | ||
729 | case DSM_CC_STREAM : | ||
730 | case ISO13522_STREAM: | ||
731 | case PRIVATE_STREAM1: | ||
732 | case AUDIO_STREAM_S ... AUDIO_STREAM_E: | ||
733 | case VIDEO_STREAM_S ... VIDEO_STREAM_E: | ||
734 | pes_start = 1; | ||
735 | break; | ||
736 | |||
737 | default: | ||
738 | break; | ||
739 | } | ||
740 | |||
741 | while (c < length) { | ||
742 | memset(obuf, 0, TS_SIZE); | ||
743 | if (length - c >= (TS_SIZE - 4)){ | ||
744 | l = write_ts_header2(pid, counter, pes_start, | ||
745 | obuf, (TS_SIZE - 4)); | ||
746 | memcpy(obuf + l, buf + c, TS_SIZE - l); | ||
747 | c += TS_SIZE - l; | ||
748 | } else { | ||
749 | l = write_ts_header2(pid, counter, pes_start, | ||
750 | obuf, length - c); | ||
751 | memcpy(obuf + l, buf + c, TS_SIZE - l); | ||
752 | c = length; | ||
753 | } | ||
754 | feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK); | ||
755 | pes_start = 0; | ||
756 | } | ||
757 | } | ||
758 | |||
759 | |||
760 | int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len) | ||
761 | { | ||
762 | struct dvb_demux *demux = feed->demux; | ||
763 | struct av7110 *av7110 = (struct av7110 *) demux->priv; | ||
764 | struct ipack *ipack = &av7110->ipack[feed->pes_type]; | ||
765 | |||
766 | dprintk(2, "av7110:%p, \n", av7110); | ||
767 | |||
768 | switch (feed->pes_type) { | ||
769 | case 0: | ||
770 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) | ||
771 | return -EINVAL; | ||
772 | break; | ||
773 | case 1: | ||
774 | if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) | ||
775 | return -EINVAL; | ||
776 | break; | ||
777 | default: | ||
778 | return -1; | ||
779 | } | ||
780 | |||
781 | if (!(buf[3] & 0x10)) /* no payload? */ | ||
782 | return -1; | ||
783 | if (buf[1] & 0x40) | ||
784 | av7110_ipack_flush(ipack); | ||
785 | |||
786 | if (buf[3] & 0x20) { /* adaptation field? */ | ||
787 | len -= buf[4] + 1; | ||
788 | buf += buf[4] + 1; | ||
789 | if (!len) | ||
790 | return 0; | ||
791 | } | ||
792 | |||
793 | av7110_ipack_instant_repack(buf + 4, len - 4, &av7110->ipack[feed->pes_type]); | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | |||
798 | |||
799 | /****************************************************************************** | ||
800 | * Video MPEG decoder events | ||
801 | ******************************************************************************/ | ||
802 | void dvb_video_add_event(struct av7110 *av7110, struct video_event *event) | ||
803 | { | ||
804 | struct dvb_video_events *events = &av7110->video_events; | ||
805 | int wp; | ||
806 | |||
807 | spin_lock_bh(&events->lock); | ||
808 | |||
809 | wp = (events->eventw + 1) % MAX_VIDEO_EVENT; | ||
810 | if (wp == events->eventr) { | ||
811 | events->overflow = 1; | ||
812 | events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; | ||
813 | } | ||
814 | |||
815 | //FIXME: timestamp? | ||
816 | memcpy(&events->events[events->eventw], event, sizeof(struct video_event)); | ||
817 | events->eventw = wp; | ||
818 | |||
819 | spin_unlock_bh(&events->lock); | ||
820 | |||
821 | wake_up_interruptible(&events->wait_queue); | ||
822 | } | ||
823 | |||
824 | |||
825 | static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags) | ||
826 | { | ||
827 | struct dvb_video_events *events = &av7110->video_events; | ||
828 | |||
829 | if (events->overflow) { | ||
830 | events->overflow = 0; | ||
831 | return -EOVERFLOW; | ||
832 | } | ||
833 | if (events->eventw == events->eventr) { | ||
834 | int ret; | ||
835 | |||
836 | if (flags & O_NONBLOCK) | ||
837 | return -EWOULDBLOCK; | ||
838 | |||
839 | ret = wait_event_interruptible(events->wait_queue, | ||
840 | events->eventw != events->eventr); | ||
841 | if (ret < 0) | ||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | spin_lock_bh(&events->lock); | ||
846 | |||
847 | memcpy(event, &events->events[events->eventr], | ||
848 | sizeof(struct video_event)); | ||
849 | events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT; | ||
850 | |||
851 | spin_unlock_bh(&events->lock); | ||
852 | |||
853 | return 0; | ||
854 | } | ||
855 | |||
856 | |||
857 | /****************************************************************************** | ||
858 | * DVB device file operations | ||
859 | ******************************************************************************/ | ||
860 | |||
861 | static unsigned int dvb_video_poll(struct file *file, poll_table *wait) | ||
862 | { | ||
863 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
864 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
865 | unsigned int mask = 0; | ||
866 | |||
867 | dprintk(2, "av7110:%p, \n", av7110); | ||
868 | |||
869 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) | ||
870 | poll_wait(file, &av7110->avout.queue, wait); | ||
871 | |||
872 | poll_wait(file, &av7110->video_events.wait_queue, wait); | ||
873 | |||
874 | if (av7110->video_events.eventw != av7110->video_events.eventr) | ||
875 | mask = POLLPRI; | ||
876 | |||
877 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
878 | if (av7110->playing) { | ||
879 | if (FREE_COND) | ||
880 | mask |= (POLLOUT | POLLWRNORM); | ||
881 | } else /* if not playing: may play if asked for */ | ||
882 | mask |= (POLLOUT | POLLWRNORM); | ||
883 | } | ||
884 | |||
885 | return mask; | ||
886 | } | ||
887 | |||
888 | static ssize_t dvb_video_write(struct file *file, const char __user *buf, | ||
889 | size_t count, loff_t *ppos) | ||
890 | { | ||
891 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
892 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
893 | |||
894 | dprintk(2, "av7110:%p, \n", av7110); | ||
895 | |||
896 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) | ||
897 | return -EPERM; | ||
898 | |||
899 | if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY) | ||
900 | return -EPERM; | ||
901 | |||
902 | return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1); | ||
903 | } | ||
904 | |||
905 | static unsigned int dvb_audio_poll(struct file *file, poll_table *wait) | ||
906 | { | ||
907 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
908 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
909 | unsigned int mask = 0; | ||
910 | |||
911 | dprintk(2, "av7110:%p, \n", av7110); | ||
912 | |||
913 | poll_wait(file, &av7110->aout.queue, wait); | ||
914 | |||
915 | if (av7110->playing) { | ||
916 | if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024) | ||
917 | mask |= (POLLOUT | POLLWRNORM); | ||
918 | } else /* if not playing: may play if asked for */ | ||
919 | mask = (POLLOUT | POLLWRNORM); | ||
920 | |||
921 | return mask; | ||
922 | } | ||
923 | |||
924 | static ssize_t dvb_audio_write(struct file *file, const char __user *buf, | ||
925 | size_t count, loff_t *ppos) | ||
926 | { | ||
927 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
928 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
929 | |||
930 | dprintk(2, "av7110:%p, \n", av7110); | ||
931 | |||
932 | if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) { | ||
933 | printk(KERN_ERR "not audio source memory\n"); | ||
934 | return -EPERM; | ||
935 | } | ||
936 | return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0); | ||
937 | } | ||
938 | |||
939 | static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 }; | ||
940 | |||
941 | #define MIN_IFRAME 400000 | ||
942 | |||
943 | static int play_iframe(struct av7110 *av7110, u8 __user *buf, unsigned int len, int nonblock) | ||
944 | { | ||
945 | int i, n; | ||
946 | |||
947 | dprintk(2, "av7110:%p, \n", av7110); | ||
948 | |||
949 | if (!(av7110->playing & RP_VIDEO)) { | ||
950 | if (av7110_av_start_play(av7110, RP_VIDEO) < 0) | ||
951 | return -EBUSY; | ||
952 | } | ||
953 | |||
954 | /* setting n always > 1, fixes problems when playing stillframes | ||
955 | consisting of I- and P-Frames */ | ||
956 | n = MIN_IFRAME / len + 1; | ||
957 | |||
958 | /* FIXME: nonblock? */ | ||
959 | dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1); | ||
960 | |||
961 | for (i = 0; i < n; i++) | ||
962 | dvb_play(av7110, buf, len, 0, 1); | ||
963 | |||
964 | av7110_ipack_flush(&av7110->ipack[1]); | ||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | |||
969 | static int dvb_video_ioctl(struct inode *inode, struct file *file, | ||
970 | unsigned int cmd, void *parg) | ||
971 | { | ||
972 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
973 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
974 | unsigned long arg = (unsigned long) parg; | ||
975 | int ret = 0; | ||
976 | |||
977 | dprintk(2, "av7110:%p, \n", av7110); | ||
978 | |||
979 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
980 | if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT && | ||
981 | cmd != VIDEO_GET_SIZE ) { | ||
982 | return -EPERM; | ||
983 | } | ||
984 | } | ||
985 | |||
986 | switch (cmd) { | ||
987 | case VIDEO_STOP: | ||
988 | av7110->videostate.play_state = VIDEO_STOPPED; | ||
989 | if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) | ||
990 | av7110_av_stop(av7110, RP_VIDEO); | ||
991 | else | ||
992 | vidcom(av7110, VIDEO_CMD_STOP, | ||
993 | av7110->videostate.video_blank ? 0 : 1); | ||
994 | av7110->trickmode = TRICK_NONE; | ||
995 | break; | ||
996 | |||
997 | case VIDEO_PLAY: | ||
998 | av7110->trickmode = TRICK_NONE; | ||
999 | if (av7110->videostate.play_state == VIDEO_FREEZED) { | ||
1000 | av7110->videostate.play_state = VIDEO_PLAYING; | ||
1001 | vidcom(av7110, VIDEO_CMD_PLAY, 0); | ||
1002 | } | ||
1003 | |||
1004 | if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) { | ||
1005 | if (av7110->playing == RP_AV) { | ||
1006 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0); | ||
1007 | av7110->playing &= ~RP_VIDEO; | ||
1008 | } | ||
1009 | av7110_av_start_play(av7110, RP_VIDEO); | ||
1010 | vidcom(av7110, VIDEO_CMD_PLAY, 0); | ||
1011 | } else { | ||
1012 | //av7110_av_stop(av7110, RP_VIDEO); | ||
1013 | vidcom(av7110, VIDEO_CMD_PLAY, 0); | ||
1014 | } | ||
1015 | av7110->videostate.play_state = VIDEO_PLAYING; | ||
1016 | break; | ||
1017 | |||
1018 | case VIDEO_FREEZE: | ||
1019 | av7110->videostate.play_state = VIDEO_FREEZED; | ||
1020 | if (av7110->playing & RP_VIDEO) | ||
1021 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0); | ||
1022 | else | ||
1023 | vidcom(av7110, VIDEO_CMD_FREEZE, 1); | ||
1024 | av7110->trickmode = TRICK_FREEZE; | ||
1025 | break; | ||
1026 | |||
1027 | case VIDEO_CONTINUE: | ||
1028 | if (av7110->playing & RP_VIDEO) | ||
1029 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0); | ||
1030 | vidcom(av7110, VIDEO_CMD_PLAY, 0); | ||
1031 | av7110->videostate.play_state = VIDEO_PLAYING; | ||
1032 | av7110->trickmode = TRICK_NONE; | ||
1033 | break; | ||
1034 | |||
1035 | case VIDEO_SELECT_SOURCE: | ||
1036 | av7110->videostate.stream_source = (video_stream_source_t) arg; | ||
1037 | break; | ||
1038 | |||
1039 | case VIDEO_SET_BLANK: | ||
1040 | av7110->videostate.video_blank = (int) arg; | ||
1041 | break; | ||
1042 | |||
1043 | case VIDEO_GET_STATUS: | ||
1044 | memcpy(parg, &av7110->videostate, sizeof(struct video_status)); | ||
1045 | break; | ||
1046 | |||
1047 | case VIDEO_GET_EVENT: | ||
1048 | ret=dvb_video_get_event(av7110, parg, file->f_flags); | ||
1049 | break; | ||
1050 | |||
1051 | case VIDEO_GET_SIZE: | ||
1052 | memcpy(parg, &av7110->video_size, sizeof(video_size_t)); | ||
1053 | break; | ||
1054 | |||
1055 | case VIDEO_SET_DISPLAY_FORMAT: | ||
1056 | { | ||
1057 | video_displayformat_t format = (video_displayformat_t) arg; | ||
1058 | u16 val = 0; | ||
1059 | |||
1060 | switch (format) { | ||
1061 | case VIDEO_PAN_SCAN: | ||
1062 | val = VID_PAN_SCAN_PREF; | ||
1063 | break; | ||
1064 | |||
1065 | case VIDEO_LETTER_BOX: | ||
1066 | val = VID_VC_AND_PS_PREF; | ||
1067 | break; | ||
1068 | |||
1069 | case VIDEO_CENTER_CUT_OUT: | ||
1070 | val = VID_CENTRE_CUT_PREF; | ||
1071 | break; | ||
1072 | |||
1073 | default: | ||
1074 | ret = -EINVAL; | ||
1075 | } | ||
1076 | if (ret < 0) | ||
1077 | break; | ||
1078 | av7110->videostate.video_format = format; | ||
1079 | ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType, | ||
1080 | 1, (u16) val); | ||
1081 | break; | ||
1082 | } | ||
1083 | |||
1084 | case VIDEO_SET_FORMAT: | ||
1085 | if (arg > 1) { | ||
1086 | ret = -EINVAL; | ||
1087 | break; | ||
1088 | } | ||
1089 | av7110->display_ar = arg; | ||
1090 | ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType, | ||
1091 | 1, (u16) arg); | ||
1092 | break; | ||
1093 | |||
1094 | case VIDEO_STILLPICTURE: | ||
1095 | { | ||
1096 | struct video_still_picture *pic = | ||
1097 | (struct video_still_picture *) parg; | ||
1098 | av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY; | ||
1099 | dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); | ||
1100 | ret = play_iframe(av7110, pic->iFrame, pic->size, | ||
1101 | file->f_flags & O_NONBLOCK); | ||
1102 | break; | ||
1103 | } | ||
1104 | |||
1105 | case VIDEO_FAST_FORWARD: | ||
1106 | //note: arg is ignored by firmware | ||
1107 | if (av7110->playing & RP_VIDEO) | ||
1108 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | ||
1109 | __Scan_I, 2, AV_PES, 0); | ||
1110 | else | ||
1111 | vidcom(av7110, VIDEO_CMD_FFWD, arg); | ||
1112 | av7110->trickmode = TRICK_FAST; | ||
1113 | av7110->videostate.play_state = VIDEO_PLAYING; | ||
1114 | break; | ||
1115 | |||
1116 | case VIDEO_SLOWMOTION: | ||
1117 | if (av7110->playing&RP_VIDEO) { | ||
1118 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0); | ||
1119 | vidcom(av7110, VIDEO_CMD_SLOW, arg); | ||
1120 | } else { | ||
1121 | vidcom(av7110, VIDEO_CMD_PLAY, 0); | ||
1122 | vidcom(av7110, VIDEO_CMD_STOP, 0); | ||
1123 | vidcom(av7110, VIDEO_CMD_SLOW, arg); | ||
1124 | } | ||
1125 | av7110->trickmode = TRICK_SLOW; | ||
1126 | av7110->videostate.play_state = VIDEO_PLAYING; | ||
1127 | break; | ||
1128 | |||
1129 | case VIDEO_GET_CAPABILITIES: | ||
1130 | *(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 | | ||
1131 | VIDEO_CAP_SYS | VIDEO_CAP_PROG; | ||
1132 | break; | ||
1133 | |||
1134 | case VIDEO_CLEAR_BUFFER: | ||
1135 | dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); | ||
1136 | av7110_ipack_reset(&av7110->ipack[1]); | ||
1137 | |||
1138 | if (av7110->playing == RP_AV) { | ||
1139 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | ||
1140 | __Play, 2, AV_PES, 0); | ||
1141 | if (av7110->trickmode == TRICK_FAST) | ||
1142 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | ||
1143 | __Scan_I, 2, AV_PES, 0); | ||
1144 | if (av7110->trickmode == TRICK_SLOW) { | ||
1145 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | ||
1146 | __Slow, 2, 0, 0); | ||
1147 | vidcom(av7110, VIDEO_CMD_SLOW, arg); | ||
1148 | } | ||
1149 | if (av7110->trickmode == TRICK_FREEZE) | ||
1150 | vidcom(av7110, VIDEO_CMD_STOP, 1); | ||
1151 | } | ||
1152 | break; | ||
1153 | |||
1154 | case VIDEO_SET_STREAMTYPE: | ||
1155 | |||
1156 | break; | ||
1157 | |||
1158 | default: | ||
1159 | ret = -ENOIOCTLCMD; | ||
1160 | break; | ||
1161 | } | ||
1162 | return ret; | ||
1163 | } | ||
1164 | |||
1165 | static int dvb_audio_ioctl(struct inode *inode, struct file *file, | ||
1166 | unsigned int cmd, void *parg) | ||
1167 | { | ||
1168 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
1169 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
1170 | unsigned long arg = (unsigned long) parg; | ||
1171 | int ret = 0; | ||
1172 | |||
1173 | dprintk(2, "av7110:%p, \n", av7110); | ||
1174 | |||
1175 | if (((file->f_flags & O_ACCMODE) == O_RDONLY) && | ||
1176 | (cmd != AUDIO_GET_STATUS)) | ||
1177 | return -EPERM; | ||
1178 | |||
1179 | switch (cmd) { | ||
1180 | case AUDIO_STOP: | ||
1181 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) | ||
1182 | av7110_av_stop(av7110, RP_AUDIO); | ||
1183 | else | ||
1184 | audcom(av7110, AUDIO_CMD_MUTE); | ||
1185 | av7110->audiostate.play_state = AUDIO_STOPPED; | ||
1186 | break; | ||
1187 | |||
1188 | case AUDIO_PLAY: | ||
1189 | if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) | ||
1190 | av7110_av_start_play(av7110, RP_AUDIO); | ||
1191 | audcom(av7110, AUDIO_CMD_UNMUTE); | ||
1192 | av7110->audiostate.play_state = AUDIO_PLAYING; | ||
1193 | break; | ||
1194 | |||
1195 | case AUDIO_PAUSE: | ||
1196 | audcom(av7110, AUDIO_CMD_MUTE); | ||
1197 | av7110->audiostate.play_state = AUDIO_PAUSED; | ||
1198 | break; | ||
1199 | |||
1200 | case AUDIO_CONTINUE: | ||
1201 | if (av7110->audiostate.play_state == AUDIO_PAUSED) { | ||
1202 | av7110->audiostate.play_state = AUDIO_PLAYING; | ||
1203 | audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16); | ||
1204 | } | ||
1205 | break; | ||
1206 | |||
1207 | case AUDIO_SELECT_SOURCE: | ||
1208 | av7110->audiostate.stream_source = (audio_stream_source_t) arg; | ||
1209 | break; | ||
1210 | |||
1211 | case AUDIO_SET_MUTE: | ||
1212 | { | ||
1213 | audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE); | ||
1214 | av7110->audiostate.mute_state = (int) arg; | ||
1215 | break; | ||
1216 | } | ||
1217 | |||
1218 | case AUDIO_SET_AV_SYNC: | ||
1219 | av7110->audiostate.AV_sync_state = (int) arg; | ||
1220 | audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF); | ||
1221 | break; | ||
1222 | |||
1223 | case AUDIO_SET_BYPASS_MODE: | ||
1224 | ret = -EINVAL; | ||
1225 | break; | ||
1226 | |||
1227 | case AUDIO_CHANNEL_SELECT: | ||
1228 | av7110->audiostate.channel_select = (audio_channel_select_t) arg; | ||
1229 | |||
1230 | switch(av7110->audiostate.channel_select) { | ||
1231 | case AUDIO_STEREO: | ||
1232 | audcom(av7110, AUDIO_CMD_STEREO); | ||
1233 | break; | ||
1234 | |||
1235 | case AUDIO_MONO_LEFT: | ||
1236 | audcom(av7110, AUDIO_CMD_MONO_L); | ||
1237 | break; | ||
1238 | |||
1239 | case AUDIO_MONO_RIGHT: | ||
1240 | audcom(av7110, AUDIO_CMD_MONO_R); | ||
1241 | break; | ||
1242 | |||
1243 | default: | ||
1244 | ret = -EINVAL; | ||
1245 | break; | ||
1246 | } | ||
1247 | break; | ||
1248 | |||
1249 | case AUDIO_GET_STATUS: | ||
1250 | memcpy(parg, &av7110->audiostate, sizeof(struct audio_status)); | ||
1251 | break; | ||
1252 | |||
1253 | case AUDIO_GET_CAPABILITIES: | ||
1254 | *(int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2; | ||
1255 | break; | ||
1256 | |||
1257 | case AUDIO_CLEAR_BUFFER: | ||
1258 | dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); | ||
1259 | av7110_ipack_reset(&av7110->ipack[0]); | ||
1260 | if (av7110->playing == RP_AV) | ||
1261 | av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, | ||
1262 | __Play, 2, AV_PES, 0); | ||
1263 | break; | ||
1264 | case AUDIO_SET_ID: | ||
1265 | |||
1266 | break; | ||
1267 | case AUDIO_SET_MIXER: | ||
1268 | { | ||
1269 | struct audio_mixer *amix = (struct audio_mixer *)parg; | ||
1270 | |||
1271 | av7110_set_volume(av7110, amix->volume_left, amix->volume_right); | ||
1272 | break; | ||
1273 | } | ||
1274 | case AUDIO_SET_STREAMTYPE: | ||
1275 | break; | ||
1276 | default: | ||
1277 | ret = -ENOIOCTLCMD; | ||
1278 | } | ||
1279 | return ret; | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | static int dvb_video_open(struct inode *inode, struct file *file) | ||
1284 | { | ||
1285 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
1286 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
1287 | int err; | ||
1288 | |||
1289 | dprintk(2, "av7110:%p, \n", av7110); | ||
1290 | |||
1291 | if ((err = dvb_generic_open(inode, file)) < 0) | ||
1292 | return err; | ||
1293 | |||
1294 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
1295 | dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); | ||
1296 | dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout); | ||
1297 | av7110->video_blank = 1; | ||
1298 | av7110->audiostate.AV_sync_state = 1; | ||
1299 | av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; | ||
1300 | |||
1301 | /* empty event queue */ | ||
1302 | av7110->video_events.eventr = av7110->video_events.eventw = 0; | ||
1303 | } | ||
1304 | |||
1305 | return 0; | ||
1306 | } | ||
1307 | |||
1308 | static int dvb_video_release(struct inode *inode, struct file *file) | ||
1309 | { | ||
1310 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
1311 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
1312 | |||
1313 | dprintk(2, "av7110:%p, \n", av7110); | ||
1314 | |||
1315 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
1316 | av7110_av_stop(av7110, RP_VIDEO); | ||
1317 | } | ||
1318 | |||
1319 | return dvb_generic_release(inode, file); | ||
1320 | } | ||
1321 | |||
1322 | static int dvb_audio_open(struct inode *inode, struct file *file) | ||
1323 | { | ||
1324 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
1325 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
1326 | int err=dvb_generic_open(inode, file); | ||
1327 | |||
1328 | dprintk(2, "av7110:%p, \n", av7110); | ||
1329 | |||
1330 | if (err < 0) | ||
1331 | return err; | ||
1332 | dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout); | ||
1333 | av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; | ||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | static int dvb_audio_release(struct inode *inode, struct file *file) | ||
1338 | { | ||
1339 | struct dvb_device *dvbdev = (struct dvb_device *) file->private_data; | ||
1340 | struct av7110 *av7110 = (struct av7110 *) dvbdev->priv; | ||
1341 | |||
1342 | dprintk(2, "av7110:%p, \n", av7110); | ||
1343 | |||
1344 | av7110_av_stop(av7110, RP_AUDIO); | ||
1345 | return dvb_generic_release(inode, file); | ||
1346 | } | ||
1347 | |||
1348 | |||
1349 | |||
1350 | /****************************************************************************** | ||
1351 | * driver registration | ||
1352 | ******************************************************************************/ | ||
1353 | |||
1354 | static struct file_operations dvb_video_fops = { | ||
1355 | .owner = THIS_MODULE, | ||
1356 | .write = dvb_video_write, | ||
1357 | .ioctl = dvb_generic_ioctl, | ||
1358 | .open = dvb_video_open, | ||
1359 | .release = dvb_video_release, | ||
1360 | .poll = dvb_video_poll, | ||
1361 | }; | ||
1362 | |||
1363 | static struct dvb_device dvbdev_video = { | ||
1364 | .priv = NULL, | ||
1365 | .users = 6, | ||
1366 | .readers = 5, /* arbitrary */ | ||
1367 | .writers = 1, | ||
1368 | .fops = &dvb_video_fops, | ||
1369 | .kernel_ioctl = dvb_video_ioctl, | ||
1370 | }; | ||
1371 | |||
1372 | static struct file_operations dvb_audio_fops = { | ||
1373 | .owner = THIS_MODULE, | ||
1374 | .write = dvb_audio_write, | ||
1375 | .ioctl = dvb_generic_ioctl, | ||
1376 | .open = dvb_audio_open, | ||
1377 | .release = dvb_audio_release, | ||
1378 | .poll = dvb_audio_poll, | ||
1379 | }; | ||
1380 | |||
1381 | static struct dvb_device dvbdev_audio = { | ||
1382 | .priv = NULL, | ||
1383 | .users = 1, | ||
1384 | .writers = 1, | ||
1385 | .fops = &dvb_audio_fops, | ||
1386 | .kernel_ioctl = dvb_audio_ioctl, | ||
1387 | }; | ||
1388 | |||
1389 | |||
1390 | int av7110_av_register(struct av7110 *av7110) | ||
1391 | { | ||
1392 | av7110->audiostate.AV_sync_state = 0; | ||
1393 | av7110->audiostate.mute_state = 0; | ||
1394 | av7110->audiostate.play_state = AUDIO_STOPPED; | ||
1395 | av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX; | ||
1396 | av7110->audiostate.channel_select = AUDIO_STEREO; | ||
1397 | av7110->audiostate.bypass_mode = 0; | ||
1398 | |||
1399 | av7110->videostate.video_blank = 0; | ||
1400 | av7110->videostate.play_state = VIDEO_STOPPED; | ||
1401 | av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX; | ||
1402 | av7110->videostate.video_format = VIDEO_FORMAT_4_3; | ||
1403 | av7110->videostate.display_format = VIDEO_CENTER_CUT_OUT; | ||
1404 | av7110->display_ar = VIDEO_FORMAT_4_3; | ||
1405 | |||
1406 | init_waitqueue_head(&av7110->video_events.wait_queue); | ||
1407 | spin_lock_init(&av7110->video_events.lock); | ||
1408 | av7110->video_events.eventw = av7110->video_events.eventr = 0; | ||
1409 | av7110->video_events.overflow = 0; | ||
1410 | memset(&av7110->video_size, 0, sizeof (video_size_t)); | ||
1411 | |||
1412 | dvb_register_device(av7110->dvb_adapter, &av7110->video_dev, | ||
1413 | &dvbdev_video, av7110, DVB_DEVICE_VIDEO); | ||
1414 | |||
1415 | dvb_register_device(av7110->dvb_adapter, &av7110->audio_dev, | ||
1416 | &dvbdev_audio, av7110, DVB_DEVICE_AUDIO); | ||
1417 | |||
1418 | return 0; | ||
1419 | } | ||
1420 | |||
1421 | void av7110_av_unregister(struct av7110 *av7110) | ||
1422 | { | ||
1423 | dvb_unregister_device(av7110->audio_dev); | ||
1424 | dvb_unregister_device(av7110->video_dev); | ||
1425 | } | ||
1426 | |||
1427 | int av7110_av_init(struct av7110 *av7110) | ||
1428 | { | ||
1429 | void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb }; | ||
1430 | int i, ret; | ||
1431 | |||
1432 | av7110->vidmode = VIDEO_MODE_PAL; | ||
1433 | |||
1434 | for (i = 0; i < 2; i++) { | ||
1435 | struct ipack *ipack = av7110->ipack + i; | ||
1436 | |||
1437 | ret = av7110_ipack_init(ipack, IPACKS, play[i]); | ||
1438 | if (ret < 0) { | ||
1439 | if (i) | ||
1440 | av7110_ipack_free(--ipack); | ||
1441 | goto out; | ||
1442 | } | ||
1443 | ipack->data = av7110; | ||
1444 | } | ||
1445 | |||
1446 | dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN); | ||
1447 | dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN); | ||
1448 | |||
1449 | av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN); | ||
1450 | av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS; | ||
1451 | out: | ||
1452 | return ret; | ||
1453 | } | ||
1454 | |||
1455 | void av7110_av_exit(struct av7110 *av7110) | ||
1456 | { | ||
1457 | av7110_ipack_free(&av7110->ipack[0]); | ||
1458 | av7110_ipack_free(&av7110->ipack[1]); | ||
1459 | } | ||