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