18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * av7110_av.c: audio and video MPEG decoder stuff
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1999-2002 Ralph  Metzler
68c2ecf20Sopenharmony_ci *                       & Marcus Metzler for convergence integrated media GmbH
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * originally based on code by:
98c2ecf20Sopenharmony_ci * Copyright (C) 1998,1999 Christian Theiss <mistert@rz.fh-augsburg.de>
108c2ecf20Sopenharmony_ci *
118c2ecf20Sopenharmony_ci * the project's page is at https://linuxtv.org
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/string.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/fs.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "av7110.h"
218c2ecf20Sopenharmony_ci#include "av7110_hw.h"
228c2ecf20Sopenharmony_ci#include "av7110_av.h"
238c2ecf20Sopenharmony_ci#include "av7110_ipack.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* MPEG-2 (ISO 13818 / H.222.0) stream types */
268c2ecf20Sopenharmony_ci#define PROG_STREAM_MAP  0xBC
278c2ecf20Sopenharmony_ci#define PRIVATE_STREAM1  0xBD
288c2ecf20Sopenharmony_ci#define PADDING_STREAM	 0xBE
298c2ecf20Sopenharmony_ci#define PRIVATE_STREAM2  0xBF
308c2ecf20Sopenharmony_ci#define AUDIO_STREAM_S	 0xC0
318c2ecf20Sopenharmony_ci#define AUDIO_STREAM_E	 0xDF
328c2ecf20Sopenharmony_ci#define VIDEO_STREAM_S	 0xE0
338c2ecf20Sopenharmony_ci#define VIDEO_STREAM_E	 0xEF
348c2ecf20Sopenharmony_ci#define ECM_STREAM	 0xF0
358c2ecf20Sopenharmony_ci#define EMM_STREAM	 0xF1
368c2ecf20Sopenharmony_ci#define DSM_CC_STREAM	 0xF2
378c2ecf20Sopenharmony_ci#define ISO13522_STREAM  0xF3
388c2ecf20Sopenharmony_ci#define PROG_STREAM_DIR  0xFF
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define PTS_DTS_FLAGS	 0xC0
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci//pts_dts flags
438c2ecf20Sopenharmony_ci#define PTS_ONLY	 0x80
448c2ecf20Sopenharmony_ci#define PTS_DTS		 0xC0
458c2ecf20Sopenharmony_ci#define TS_SIZE		 188
468c2ecf20Sopenharmony_ci#define TRANS_ERROR	 0x80
478c2ecf20Sopenharmony_ci#define PAY_START	 0x40
488c2ecf20Sopenharmony_ci#define TRANS_PRIO	 0x20
498c2ecf20Sopenharmony_ci#define PID_MASK_HI	 0x1F
508c2ecf20Sopenharmony_ci//flags
518c2ecf20Sopenharmony_ci#define TRANS_SCRMBL1	 0x80
528c2ecf20Sopenharmony_ci#define TRANS_SCRMBL2	 0x40
538c2ecf20Sopenharmony_ci#define ADAPT_FIELD	 0x20
548c2ecf20Sopenharmony_ci#define PAYLOAD		 0x10
558c2ecf20Sopenharmony_ci#define COUNT_MASK	 0x0F
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci// adaptation flags
588c2ecf20Sopenharmony_ci#define DISCON_IND	 0x80
598c2ecf20Sopenharmony_ci#define RAND_ACC_IND	 0x40
608c2ecf20Sopenharmony_ci#define ES_PRI_IND	 0x20
618c2ecf20Sopenharmony_ci#define PCR_FLAG	 0x10
628c2ecf20Sopenharmony_ci#define OPCR_FLAG	 0x08
638c2ecf20Sopenharmony_ci#define SPLICE_FLAG	 0x04
648c2ecf20Sopenharmony_ci#define TRANS_PRIV	 0x02
658c2ecf20Sopenharmony_ci#define ADAP_EXT_FLAG	 0x01
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci// adaptation extension flags
688c2ecf20Sopenharmony_ci#define LTW_FLAG	 0x80
698c2ecf20Sopenharmony_ci#define PIECE_RATE	 0x40
708c2ecf20Sopenharmony_ci#define SEAM_SPLICE	 0x20
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_cistatic void p_to_t(u8 const *buf, long int length, u16 pid,
748c2ecf20Sopenharmony_ci		   u8 *counter, struct dvb_demux_feed *feed);
758c2ecf20Sopenharmony_cistatic int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ciint av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (!(dvbdmxfeed->ts_type & TS_PACKET))
838c2ecf20Sopenharmony_ci		return 0;
848c2ecf20Sopenharmony_ci	if (buf[3] == 0xe0)	 // video PES do not have a length in TS
858c2ecf20Sopenharmony_ci		buf[4] = buf[5] = 0;
868c2ecf20Sopenharmony_ci	if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
878c2ecf20Sopenharmony_ci		return dvbdmxfeed->cb.ts(buf, len, NULL, 0,
888c2ecf20Sopenharmony_ci					 &dvbdmxfeed->feed.ts, NULL);
898c2ecf20Sopenharmony_ci	else
908c2ecf20Sopenharmony_ci		return dvb_filter_pes2ts(p2t, buf, len, 1);
918c2ecf20Sopenharmony_ci}
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	dvbdmxfeed->cb.ts(data, 188, NULL, 0,
988c2ecf20Sopenharmony_ci			  &dvbdmxfeed->feed.ts, NULL);
998c2ecf20Sopenharmony_ci	return 0;
1008c2ecf20Sopenharmony_ci}
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ciint av7110_av_start_record(struct av7110 *av7110, int av,
1038c2ecf20Sopenharmony_ci			   struct dvb_demux_feed *dvbdmxfeed)
1048c2ecf20Sopenharmony_ci{
1058c2ecf20Sopenharmony_ci	int ret = 0;
1068c2ecf20Sopenharmony_ci	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	if (av7110->playing || (av7110->rec_mode & av))
1118c2ecf20Sopenharmony_ci		return -EBUSY;
1128c2ecf20Sopenharmony_ci	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
1138c2ecf20Sopenharmony_ci	dvbdmx->recording = 1;
1148c2ecf20Sopenharmony_ci	av7110->rec_mode |= av;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	switch (av7110->rec_mode) {
1178c2ecf20Sopenharmony_ci	case RP_AUDIO:
1188c2ecf20Sopenharmony_ci		dvb_filter_pes2ts_init(&av7110->p2t[0],
1198c2ecf20Sopenharmony_ci				       dvbdmx->pesfilter[0]->pid,
1208c2ecf20Sopenharmony_ci				       dvb_filter_pes2ts_cb,
1218c2ecf20Sopenharmony_ci				       (void *) dvbdmx->pesfilter[0]);
1228c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
1238c2ecf20Sopenharmony_ci		break;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	case RP_VIDEO:
1268c2ecf20Sopenharmony_ci		dvb_filter_pes2ts_init(&av7110->p2t[1],
1278c2ecf20Sopenharmony_ci				       dvbdmx->pesfilter[1]->pid,
1288c2ecf20Sopenharmony_ci				       dvb_filter_pes2ts_cb,
1298c2ecf20Sopenharmony_ci				       (void *) dvbdmx->pesfilter[1]);
1308c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
1318c2ecf20Sopenharmony_ci		break;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	case RP_AV:
1348c2ecf20Sopenharmony_ci		dvb_filter_pes2ts_init(&av7110->p2t[0],
1358c2ecf20Sopenharmony_ci				       dvbdmx->pesfilter[0]->pid,
1368c2ecf20Sopenharmony_ci				       dvb_filter_pes2ts_cb,
1378c2ecf20Sopenharmony_ci				       (void *) dvbdmx->pesfilter[0]);
1388c2ecf20Sopenharmony_ci		dvb_filter_pes2ts_init(&av7110->p2t[1],
1398c2ecf20Sopenharmony_ci				       dvbdmx->pesfilter[1]->pid,
1408c2ecf20Sopenharmony_ci				       dvb_filter_pes2ts_cb,
1418c2ecf20Sopenharmony_ci				       (void *) dvbdmx->pesfilter[1]);
1428c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
1438c2ecf20Sopenharmony_ci		break;
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	return ret;
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ciint av7110_av_start_play(struct av7110 *av7110, int av)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	int ret = 0;
1518c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (av7110->rec_mode)
1548c2ecf20Sopenharmony_ci		return -EBUSY;
1558c2ecf20Sopenharmony_ci	if (av7110->playing & av)
1568c2ecf20Sopenharmony_ci		return -EBUSY;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (av7110->playing == RP_NONE) {
1618c2ecf20Sopenharmony_ci		av7110_ipack_reset(&av7110->ipack[0]);
1628c2ecf20Sopenharmony_ci		av7110_ipack_reset(&av7110->ipack[1]);
1638c2ecf20Sopenharmony_ci	}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	av7110->playing |= av;
1668c2ecf20Sopenharmony_ci	switch (av7110->playing) {
1678c2ecf20Sopenharmony_ci	case RP_AUDIO:
1688c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
1698c2ecf20Sopenharmony_ci		break;
1708c2ecf20Sopenharmony_ci	case RP_VIDEO:
1718c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
1728c2ecf20Sopenharmony_ci		av7110->sinfo = 0;
1738c2ecf20Sopenharmony_ci		break;
1748c2ecf20Sopenharmony_ci	case RP_AV:
1758c2ecf20Sopenharmony_ci		av7110->sinfo = 0;
1768c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
1778c2ecf20Sopenharmony_ci		break;
1788c2ecf20Sopenharmony_ci	}
1798c2ecf20Sopenharmony_ci	return ret;
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciint av7110_av_stop(struct av7110 *av7110, int av)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	int ret = 0;
1858c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	if (!(av7110->playing & av) && !(av7110->rec_mode & av))
1888c2ecf20Sopenharmony_ci		return 0;
1898c2ecf20Sopenharmony_ci	av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
1908c2ecf20Sopenharmony_ci	if (av7110->playing) {
1918c2ecf20Sopenharmony_ci		av7110->playing &= ~av;
1928c2ecf20Sopenharmony_ci		switch (av7110->playing) {
1938c2ecf20Sopenharmony_ci		case RP_AUDIO:
1948c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
1958c2ecf20Sopenharmony_ci			break;
1968c2ecf20Sopenharmony_ci		case RP_VIDEO:
1978c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
1988c2ecf20Sopenharmony_ci			break;
1998c2ecf20Sopenharmony_ci		case RP_NONE:
2008c2ecf20Sopenharmony_ci			ret = av7110_set_vidmode(av7110, av7110->vidmode);
2018c2ecf20Sopenharmony_ci			break;
2028c2ecf20Sopenharmony_ci		}
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		av7110->rec_mode &= ~av;
2058c2ecf20Sopenharmony_ci		switch (av7110->rec_mode) {
2068c2ecf20Sopenharmony_ci		case RP_AUDIO:
2078c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
2088c2ecf20Sopenharmony_ci			break;
2098c2ecf20Sopenharmony_ci		case RP_VIDEO:
2108c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
2118c2ecf20Sopenharmony_ci			break;
2128c2ecf20Sopenharmony_ci		case RP_NONE:
2138c2ecf20Sopenharmony_ci			break;
2148c2ecf20Sopenharmony_ci		}
2158c2ecf20Sopenharmony_ci	}
2168c2ecf20Sopenharmony_ci	return ret;
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciint av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	int len;
2238c2ecf20Sopenharmony_ci	u32 sync;
2248c2ecf20Sopenharmony_ci	u16 blen;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	if (!dlen) {
2278c2ecf20Sopenharmony_ci		wake_up(&buf->queue);
2288c2ecf20Sopenharmony_ci		return -1;
2298c2ecf20Sopenharmony_ci	}
2308c2ecf20Sopenharmony_ci	while (1) {
2318c2ecf20Sopenharmony_ci		len = dvb_ringbuffer_avail(buf);
2328c2ecf20Sopenharmony_ci		if (len < 6) {
2338c2ecf20Sopenharmony_ci			wake_up(&buf->queue);
2348c2ecf20Sopenharmony_ci			return -1;
2358c2ecf20Sopenharmony_ci		}
2368c2ecf20Sopenharmony_ci		sync =  DVB_RINGBUFFER_PEEK(buf, 0) << 24;
2378c2ecf20Sopenharmony_ci		sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;
2388c2ecf20Sopenharmony_ci		sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
2398c2ecf20Sopenharmony_ci		sync |= DVB_RINGBUFFER_PEEK(buf, 3);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		if (((sync &~ 0x0f) == 0x000001e0) ||
2428c2ecf20Sopenharmony_ci		    ((sync &~ 0x1f) == 0x000001c0) ||
2438c2ecf20Sopenharmony_ci		    (sync == 0x000001bd))
2448c2ecf20Sopenharmony_ci			break;
2458c2ecf20Sopenharmony_ci		printk("resync\n");
2468c2ecf20Sopenharmony_ci		DVB_RINGBUFFER_SKIP(buf, 1);
2478c2ecf20Sopenharmony_ci	}
2488c2ecf20Sopenharmony_ci	blen =  DVB_RINGBUFFER_PEEK(buf, 4) << 8;
2498c2ecf20Sopenharmony_ci	blen |= DVB_RINGBUFFER_PEEK(buf, 5);
2508c2ecf20Sopenharmony_ci	blen += 6;
2518c2ecf20Sopenharmony_ci	if (len < blen || blen > dlen) {
2528c2ecf20Sopenharmony_ci		//printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);
2538c2ecf20Sopenharmony_ci		wake_up(&buf->queue);
2548c2ecf20Sopenharmony_ci		return -1;
2558c2ecf20Sopenharmony_ci	}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ci	dvb_ringbuffer_read(buf, dest, (size_t) blen);
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
2608c2ecf20Sopenharmony_ci	       (unsigned long) buf->pread, (unsigned long) buf->pwrite);
2618c2ecf20Sopenharmony_ci	wake_up(&buf->queue);
2628c2ecf20Sopenharmony_ci	return blen;
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ciint av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
2678c2ecf20Sopenharmony_ci		      unsigned int volright)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	unsigned int vol, val, balance = 0;
2708c2ecf20Sopenharmony_ci	int err;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	av7110->mixer.volume_left = volleft;
2758c2ecf20Sopenharmony_ci	av7110->mixer.volume_right = volright;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	switch (av7110->adac_type) {
2788c2ecf20Sopenharmony_ci	case DVB_ADAC_TI:
2798c2ecf20Sopenharmony_ci		volleft = (volleft * 256) / 1036;
2808c2ecf20Sopenharmony_ci		volright = (volright * 256) / 1036;
2818c2ecf20Sopenharmony_ci		if (volleft > 0x3f)
2828c2ecf20Sopenharmony_ci			volleft = 0x3f;
2838c2ecf20Sopenharmony_ci		if (volright > 0x3f)
2848c2ecf20Sopenharmony_ci			volright = 0x3f;
2858c2ecf20Sopenharmony_ci		if ((err = SendDAC(av7110, 3, 0x80 + volleft)))
2868c2ecf20Sopenharmony_ci			return err;
2878c2ecf20Sopenharmony_ci		return SendDAC(av7110, 4, volright);
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci	case DVB_ADAC_CRYSTAL:
2908c2ecf20Sopenharmony_ci		volleft = 127 - volleft / 2;
2918c2ecf20Sopenharmony_ci		volright = 127 - volright / 2;
2928c2ecf20Sopenharmony_ci		i2c_writereg(av7110, 0x20, 0x03, volleft);
2938c2ecf20Sopenharmony_ci		i2c_writereg(av7110, 0x20, 0x04, volright);
2948c2ecf20Sopenharmony_ci		return 0;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	case DVB_ADAC_MSP34x0:
2978c2ecf20Sopenharmony_ci		vol  = (volleft > volright) ? volleft : volright;
2988c2ecf20Sopenharmony_ci		val	= (vol * 0x73 / 255) << 8;
2998c2ecf20Sopenharmony_ci		if (vol > 0)
3008c2ecf20Sopenharmony_ci		       balance = ((volright - volleft) * 127) / vol;
3018c2ecf20Sopenharmony_ci		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
3028c2ecf20Sopenharmony_ci		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
3038c2ecf20Sopenharmony_ci		msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
3048c2ecf20Sopenharmony_ci		return 0;
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	case DVB_ADAC_MSP34x5:
3078c2ecf20Sopenharmony_ci		vol = (volleft > volright) ? volleft : volright;
3088c2ecf20Sopenharmony_ci		val = (vol * 0x73 / 255) << 8;
3098c2ecf20Sopenharmony_ci		if (vol > 0)
3108c2ecf20Sopenharmony_ci			balance = ((volright - volleft) * 127) / vol;
3118c2ecf20Sopenharmony_ci		msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
3128c2ecf20Sopenharmony_ci		msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
3138c2ecf20Sopenharmony_ci		return 0;
3148c2ecf20Sopenharmony_ci	}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	return 0;
3178c2ecf20Sopenharmony_ci}
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ciint av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	int ret;
3228c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci	ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci	if (!ret && !av7110->playing) {
3278c2ecf20Sopenharmony_ci		ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
3288c2ecf20Sopenharmony_ci			   av7110->pids[DMX_PES_AUDIO],
3298c2ecf20Sopenharmony_ci			   av7110->pids[DMX_PES_TELETEXT],
3308c2ecf20Sopenharmony_ci			   0, av7110->pids[DMX_PES_PCR]);
3318c2ecf20Sopenharmony_ci		if (!ret)
3328c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci	return ret;
3358c2ecf20Sopenharmony_ci}
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_cistatic enum av7110_video_mode sw2mode[16] = {
3398c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
3408c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
3418c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,
3428c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
3438c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
3448c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
3458c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
3468c2ecf20Sopenharmony_ci	AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,
3478c2ecf20Sopenharmony_ci};
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int get_video_format(struct av7110 *av7110, u8 *buf, int count)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	int i;
3528c2ecf20Sopenharmony_ci	int hsize, vsize;
3538c2ecf20Sopenharmony_ci	int sw;
3548c2ecf20Sopenharmony_ci	u8 *p;
3558c2ecf20Sopenharmony_ci	int ret = 0;
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (av7110->sinfo)
3608c2ecf20Sopenharmony_ci		return 0;
3618c2ecf20Sopenharmony_ci	for (i = 7; i < count - 10; i++) {
3628c2ecf20Sopenharmony_ci		p = buf + i;
3638c2ecf20Sopenharmony_ci		if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
3648c2ecf20Sopenharmony_ci			continue;
3658c2ecf20Sopenharmony_ci		p += 4;
3668c2ecf20Sopenharmony_ci		hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
3678c2ecf20Sopenharmony_ci		vsize = ((p[1] &0x0F) << 8) | (p[2]);
3688c2ecf20Sopenharmony_ci		sw = (p[3] & 0x0F);
3698c2ecf20Sopenharmony_ci		ret = av7110_set_vidmode(av7110, sw2mode[sw]);
3708c2ecf20Sopenharmony_ci		if (!ret) {
3718c2ecf20Sopenharmony_ci			dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
3728c2ecf20Sopenharmony_ci			av7110->sinfo = 1;
3738c2ecf20Sopenharmony_ci		}
3748c2ecf20Sopenharmony_ci		break;
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci	return ret;
3778c2ecf20Sopenharmony_ci}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/****************************************************************************
3818c2ecf20Sopenharmony_ci * I/O buffer management and control
3828c2ecf20Sopenharmony_ci ****************************************************************************/
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_cistatic inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
3858c2ecf20Sopenharmony_ci					 const u8 *buf, unsigned long count)
3868c2ecf20Sopenharmony_ci{
3878c2ecf20Sopenharmony_ci	unsigned long todo = count;
3888c2ecf20Sopenharmony_ci	int free;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	while (todo > 0) {
3918c2ecf20Sopenharmony_ci		if (dvb_ringbuffer_free(rbuf) < 2048) {
3928c2ecf20Sopenharmony_ci			if (wait_event_interruptible(rbuf->queue,
3938c2ecf20Sopenharmony_ci						     (dvb_ringbuffer_free(rbuf) >= 2048)))
3948c2ecf20Sopenharmony_ci				return count - todo;
3958c2ecf20Sopenharmony_ci		}
3968c2ecf20Sopenharmony_ci		free = dvb_ringbuffer_free(rbuf);
3978c2ecf20Sopenharmony_ci		if (free > todo)
3988c2ecf20Sopenharmony_ci			free = todo;
3998c2ecf20Sopenharmony_ci		dvb_ringbuffer_write(rbuf, buf, free);
4008c2ecf20Sopenharmony_ci		todo -= free;
4018c2ecf20Sopenharmony_ci		buf += free;
4028c2ecf20Sopenharmony_ci	}
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	return count - todo;
4058c2ecf20Sopenharmony_ci}
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_cistatic void play_video_cb(u8 *buf, int count, void *priv)
4088c2ecf20Sopenharmony_ci{
4098c2ecf20Sopenharmony_ci	struct av7110 *av7110 = (struct av7110 *) priv;
4108c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	if ((buf[3] & 0xe0) == 0xe0) {
4138c2ecf20Sopenharmony_ci		get_video_format(av7110, buf, count);
4148c2ecf20Sopenharmony_ci		aux_ring_buffer_write(&av7110->avout, buf, count);
4158c2ecf20Sopenharmony_ci	} else
4168c2ecf20Sopenharmony_ci		aux_ring_buffer_write(&av7110->aout, buf, count);
4178c2ecf20Sopenharmony_ci}
4188c2ecf20Sopenharmony_ci
4198c2ecf20Sopenharmony_cistatic void play_audio_cb(u8 *buf, int count, void *priv)
4208c2ecf20Sopenharmony_ci{
4218c2ecf20Sopenharmony_ci	struct av7110 *av7110 = (struct av7110 *) priv;
4228c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	aux_ring_buffer_write(&av7110->aout, buf, count);
4258c2ecf20Sopenharmony_ci}
4268c2ecf20Sopenharmony_ci
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
4318c2ecf20Sopenharmony_ci		       unsigned long count, int nonblock, int type)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci	struct dvb_ringbuffer *rb;
4348c2ecf20Sopenharmony_ci	u8 *kb;
4358c2ecf20Sopenharmony_ci	unsigned long todo = count;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci	dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci	rb = (type) ? &av7110->avout : &av7110->aout;
4408c2ecf20Sopenharmony_ci	kb = av7110->kbuf[type];
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci	if (!kb)
4438c2ecf20Sopenharmony_ci		return -ENOBUFS;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	if (nonblock && !FREE_COND_TS)
4468c2ecf20Sopenharmony_ci		return -EWOULDBLOCK;
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	while (todo >= TS_SIZE) {
4498c2ecf20Sopenharmony_ci		if (!FREE_COND_TS) {
4508c2ecf20Sopenharmony_ci			if (nonblock)
4518c2ecf20Sopenharmony_ci				return count - todo;
4528c2ecf20Sopenharmony_ci			if (wait_event_interruptible(rb->queue, FREE_COND_TS))
4538c2ecf20Sopenharmony_ci				return count - todo;
4548c2ecf20Sopenharmony_ci		}
4558c2ecf20Sopenharmony_ci		if (copy_from_user(kb, buf, TS_SIZE))
4568c2ecf20Sopenharmony_ci			return -EFAULT;
4578c2ecf20Sopenharmony_ci		write_ts_to_decoder(av7110, type, kb, TS_SIZE);
4588c2ecf20Sopenharmony_ci		todo -= TS_SIZE;
4598c2ecf20Sopenharmony_ci		buf += TS_SIZE;
4608c2ecf20Sopenharmony_ci	}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	return count - todo;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
4678c2ecf20Sopenharmony_ci		   dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
4708c2ecf20Sopenharmony_ci			unsigned long count, int nonblock, int type)
4718c2ecf20Sopenharmony_ci{
4728c2ecf20Sopenharmony_ci	unsigned long todo = count, n;
4738c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	if (!av7110->kbuf[type])
4768c2ecf20Sopenharmony_ci		return -ENOBUFS;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	if (nonblock && !FREE_COND)
4798c2ecf20Sopenharmony_ci		return -EWOULDBLOCK;
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	while (todo > 0) {
4828c2ecf20Sopenharmony_ci		if (!FREE_COND) {
4838c2ecf20Sopenharmony_ci			if (nonblock)
4848c2ecf20Sopenharmony_ci				return count - todo;
4858c2ecf20Sopenharmony_ci			if (wait_event_interruptible(av7110->avout.queue,
4868c2ecf20Sopenharmony_ci						     FREE_COND))
4878c2ecf20Sopenharmony_ci				return count - todo;
4888c2ecf20Sopenharmony_ci		}
4898c2ecf20Sopenharmony_ci		n = todo;
4908c2ecf20Sopenharmony_ci		if (n > IPACKS * 2)
4918c2ecf20Sopenharmony_ci			n = IPACKS * 2;
4928c2ecf20Sopenharmony_ci		if (copy_from_user(av7110->kbuf[type], buf, n))
4938c2ecf20Sopenharmony_ci			return -EFAULT;
4948c2ecf20Sopenharmony_ci		av7110_ipack_instant_repack(av7110->kbuf[type], n,
4958c2ecf20Sopenharmony_ci					    &av7110->ipack[type]);
4968c2ecf20Sopenharmony_ci		todo -= n;
4978c2ecf20Sopenharmony_ci		buf += n;
4988c2ecf20Sopenharmony_ci	}
4998c2ecf20Sopenharmony_ci	return count - todo;
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
5038c2ecf20Sopenharmony_ci			unsigned long count, int nonblock, int type)
5048c2ecf20Sopenharmony_ci{
5058c2ecf20Sopenharmony_ci	unsigned long todo = count, n;
5068c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	if (!av7110->kbuf[type])
5098c2ecf20Sopenharmony_ci		return -ENOBUFS;
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (nonblock && !FREE_COND)
5128c2ecf20Sopenharmony_ci		return -EWOULDBLOCK;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	while (todo > 0) {
5158c2ecf20Sopenharmony_ci		if (!FREE_COND) {
5168c2ecf20Sopenharmony_ci			if (nonblock)
5178c2ecf20Sopenharmony_ci				return count - todo;
5188c2ecf20Sopenharmony_ci			if (wait_event_interruptible(av7110->avout.queue,
5198c2ecf20Sopenharmony_ci						     FREE_COND))
5208c2ecf20Sopenharmony_ci				return count - todo;
5218c2ecf20Sopenharmony_ci		}
5228c2ecf20Sopenharmony_ci		n = todo;
5238c2ecf20Sopenharmony_ci		if (n > IPACKS * 2)
5248c2ecf20Sopenharmony_ci			n = IPACKS * 2;
5258c2ecf20Sopenharmony_ci		av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]);
5268c2ecf20Sopenharmony_ci		todo -= n;
5278c2ecf20Sopenharmony_ci		buf += n;
5288c2ecf20Sopenharmony_ci	}
5298c2ecf20Sopenharmony_ci	return count - todo;
5308c2ecf20Sopenharmony_ci}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_cistatic ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
5338c2ecf20Sopenharmony_ci			 unsigned long count, int nonblock, int type)
5348c2ecf20Sopenharmony_ci{
5358c2ecf20Sopenharmony_ci	unsigned long todo = count, n;
5368c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
5378c2ecf20Sopenharmony_ci
5388c2ecf20Sopenharmony_ci	if (!av7110->kbuf[type])
5398c2ecf20Sopenharmony_ci		return -ENOBUFS;
5408c2ecf20Sopenharmony_ci	if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024)
5418c2ecf20Sopenharmony_ci		return -EWOULDBLOCK;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci	while (todo > 0) {
5448c2ecf20Sopenharmony_ci		if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) {
5458c2ecf20Sopenharmony_ci			if (nonblock)
5468c2ecf20Sopenharmony_ci				return count - todo;
5478c2ecf20Sopenharmony_ci			if (wait_event_interruptible(av7110->aout.queue,
5488c2ecf20Sopenharmony_ci					(dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)))
5498c2ecf20Sopenharmony_ci				return count-todo;
5508c2ecf20Sopenharmony_ci		}
5518c2ecf20Sopenharmony_ci		n = todo;
5528c2ecf20Sopenharmony_ci		if (n > IPACKS * 2)
5538c2ecf20Sopenharmony_ci			n = IPACKS * 2;
5548c2ecf20Sopenharmony_ci		if (copy_from_user(av7110->kbuf[type], buf, n))
5558c2ecf20Sopenharmony_ci			return -EFAULT;
5568c2ecf20Sopenharmony_ci		av7110_ipack_instant_repack(av7110->kbuf[type], n,
5578c2ecf20Sopenharmony_ci					    &av7110->ipack[type]);
5588c2ecf20Sopenharmony_ci		todo -= n;
5598c2ecf20Sopenharmony_ci		buf += n;
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci	return count - todo;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_civoid av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed)
5658c2ecf20Sopenharmony_ci{
5668c2ecf20Sopenharmony_ci	memset(p->pes, 0, TS_SIZE);
5678c2ecf20Sopenharmony_ci	p->counter = 0;
5688c2ecf20Sopenharmony_ci	p->pos = 0;
5698c2ecf20Sopenharmony_ci	p->frags = 0;
5708c2ecf20Sopenharmony_ci	if (feed)
5718c2ecf20Sopenharmony_ci		p->feed = feed;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic void clear_p2t(struct av7110_p2t *p)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	memset(p->pes, 0, TS_SIZE);
5778c2ecf20Sopenharmony_ci//	p->counter = 0;
5788c2ecf20Sopenharmony_ci	p->pos = 0;
5798c2ecf20Sopenharmony_ci	p->frags = 0;
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cistatic int find_pes_header(u8 const *buf, long int length, int *frags)
5848c2ecf20Sopenharmony_ci{
5858c2ecf20Sopenharmony_ci	int c = 0;
5868c2ecf20Sopenharmony_ci	int found = 0;
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	*frags = 0;
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	while (c < length - 3 && !found) {
5918c2ecf20Sopenharmony_ci		if (buf[c] == 0x00 && buf[c + 1] == 0x00 &&
5928c2ecf20Sopenharmony_ci		    buf[c + 2] == 0x01) {
5938c2ecf20Sopenharmony_ci			switch ( buf[c + 3] ) {
5948c2ecf20Sopenharmony_ci			case PROG_STREAM_MAP:
5958c2ecf20Sopenharmony_ci			case PRIVATE_STREAM2:
5968c2ecf20Sopenharmony_ci			case PROG_STREAM_DIR:
5978c2ecf20Sopenharmony_ci			case ECM_STREAM     :
5988c2ecf20Sopenharmony_ci			case EMM_STREAM     :
5998c2ecf20Sopenharmony_ci			case PADDING_STREAM :
6008c2ecf20Sopenharmony_ci			case DSM_CC_STREAM  :
6018c2ecf20Sopenharmony_ci			case ISO13522_STREAM:
6028c2ecf20Sopenharmony_ci			case PRIVATE_STREAM1:
6038c2ecf20Sopenharmony_ci			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
6048c2ecf20Sopenharmony_ci			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
6058c2ecf20Sopenharmony_ci				found = 1;
6068c2ecf20Sopenharmony_ci				break;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci			default:
6098c2ecf20Sopenharmony_ci				c++;
6108c2ecf20Sopenharmony_ci				break;
6118c2ecf20Sopenharmony_ci			}
6128c2ecf20Sopenharmony_ci		} else
6138c2ecf20Sopenharmony_ci			c++;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci	if (c == length - 3 && !found) {
6168c2ecf20Sopenharmony_ci		if (buf[length - 1] == 0x00)
6178c2ecf20Sopenharmony_ci			*frags = 1;
6188c2ecf20Sopenharmony_ci		if (buf[length - 2] == 0x00 &&
6198c2ecf20Sopenharmony_ci		    buf[length - 1] == 0x00)
6208c2ecf20Sopenharmony_ci			*frags = 2;
6218c2ecf20Sopenharmony_ci		if (buf[length - 3] == 0x00 &&
6228c2ecf20Sopenharmony_ci		    buf[length - 2] == 0x00 &&
6238c2ecf20Sopenharmony_ci		    buf[length - 1] == 0x01)
6248c2ecf20Sopenharmony_ci			*frags = 3;
6258c2ecf20Sopenharmony_ci		return -1;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci
6288c2ecf20Sopenharmony_ci	return c;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_civoid av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	int c, c2, l, add;
6348c2ecf20Sopenharmony_ci	int check, rest;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	c = 0;
6378c2ecf20Sopenharmony_ci	c2 = 0;
6388c2ecf20Sopenharmony_ci	if (p->frags){
6398c2ecf20Sopenharmony_ci		check = 0;
6408c2ecf20Sopenharmony_ci		switch(p->frags) {
6418c2ecf20Sopenharmony_ci		case 1:
6428c2ecf20Sopenharmony_ci			if (buf[c] == 0x00 && buf[c + 1] == 0x01) {
6438c2ecf20Sopenharmony_ci				check = 1;
6448c2ecf20Sopenharmony_ci				c += 2;
6458c2ecf20Sopenharmony_ci			}
6468c2ecf20Sopenharmony_ci			break;
6478c2ecf20Sopenharmony_ci		case 2:
6488c2ecf20Sopenharmony_ci			if (buf[c] == 0x01) {
6498c2ecf20Sopenharmony_ci				check = 1;
6508c2ecf20Sopenharmony_ci				c++;
6518c2ecf20Sopenharmony_ci			}
6528c2ecf20Sopenharmony_ci			break;
6538c2ecf20Sopenharmony_ci		case 3:
6548c2ecf20Sopenharmony_ci			check = 1;
6558c2ecf20Sopenharmony_ci		}
6568c2ecf20Sopenharmony_ci		if (check) {
6578c2ecf20Sopenharmony_ci			switch (buf[c]) {
6588c2ecf20Sopenharmony_ci			case PROG_STREAM_MAP:
6598c2ecf20Sopenharmony_ci			case PRIVATE_STREAM2:
6608c2ecf20Sopenharmony_ci			case PROG_STREAM_DIR:
6618c2ecf20Sopenharmony_ci			case ECM_STREAM     :
6628c2ecf20Sopenharmony_ci			case EMM_STREAM     :
6638c2ecf20Sopenharmony_ci			case PADDING_STREAM :
6648c2ecf20Sopenharmony_ci			case DSM_CC_STREAM  :
6658c2ecf20Sopenharmony_ci			case ISO13522_STREAM:
6668c2ecf20Sopenharmony_ci			case PRIVATE_STREAM1:
6678c2ecf20Sopenharmony_ci			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
6688c2ecf20Sopenharmony_ci			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
6698c2ecf20Sopenharmony_ci				p->pes[0] = 0x00;
6708c2ecf20Sopenharmony_ci				p->pes[1] = 0x00;
6718c2ecf20Sopenharmony_ci				p->pes[2] = 0x01;
6728c2ecf20Sopenharmony_ci				p->pes[3] = buf[c];
6738c2ecf20Sopenharmony_ci				p->pos = 4;
6748c2ecf20Sopenharmony_ci				memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos);
6758c2ecf20Sopenharmony_ci				c += (TS_SIZE - 4) - p->pos;
6768c2ecf20Sopenharmony_ci				p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed);
6778c2ecf20Sopenharmony_ci				clear_p2t(p);
6788c2ecf20Sopenharmony_ci				break;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci			default:
6818c2ecf20Sopenharmony_ci				c = 0;
6828c2ecf20Sopenharmony_ci				break;
6838c2ecf20Sopenharmony_ci			}
6848c2ecf20Sopenharmony_ci		}
6858c2ecf20Sopenharmony_ci		p->frags = 0;
6868c2ecf20Sopenharmony_ci	}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	if (p->pos) {
6898c2ecf20Sopenharmony_ci		c2 = find_pes_header(buf + c, length - c, &p->frags);
6908c2ecf20Sopenharmony_ci		if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos)
6918c2ecf20Sopenharmony_ci			l = c2+c;
6928c2ecf20Sopenharmony_ci		else
6938c2ecf20Sopenharmony_ci			l = (TS_SIZE - 4) - p->pos;
6948c2ecf20Sopenharmony_ci		memcpy(p->pes + p->pos, buf, l);
6958c2ecf20Sopenharmony_ci		c += l;
6968c2ecf20Sopenharmony_ci		p->pos += l;
6978c2ecf20Sopenharmony_ci		p_to_t(p->pes, p->pos, pid, &p->counter, p->feed);
6988c2ecf20Sopenharmony_ci		clear_p2t(p);
6998c2ecf20Sopenharmony_ci	}
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	add = 0;
7028c2ecf20Sopenharmony_ci	while (c < length) {
7038c2ecf20Sopenharmony_ci		c2 = find_pes_header(buf + c + add, length - c - add, &p->frags);
7048c2ecf20Sopenharmony_ci		if (c2 >= 0) {
7058c2ecf20Sopenharmony_ci			c2 += c + add;
7068c2ecf20Sopenharmony_ci			if (c2 > c){
7078c2ecf20Sopenharmony_ci				p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed);
7088c2ecf20Sopenharmony_ci				c = c2;
7098c2ecf20Sopenharmony_ci				clear_p2t(p);
7108c2ecf20Sopenharmony_ci				add = 0;
7118c2ecf20Sopenharmony_ci			} else
7128c2ecf20Sopenharmony_ci				add = 1;
7138c2ecf20Sopenharmony_ci		} else {
7148c2ecf20Sopenharmony_ci			l = length - c;
7158c2ecf20Sopenharmony_ci			rest = l % (TS_SIZE - 4);
7168c2ecf20Sopenharmony_ci			l -= rest;
7178c2ecf20Sopenharmony_ci			p_to_t(buf + c, l, pid, &p->counter, p->feed);
7188c2ecf20Sopenharmony_ci			memcpy(p->pes, buf + c + l, rest);
7198c2ecf20Sopenharmony_ci			p->pos = rest;
7208c2ecf20Sopenharmony_ci			c = length;
7218c2ecf20Sopenharmony_ci		}
7228c2ecf20Sopenharmony_ci	}
7238c2ecf20Sopenharmony_ci}
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)
7278c2ecf20Sopenharmony_ci{
7288c2ecf20Sopenharmony_ci	int i;
7298c2ecf20Sopenharmony_ci	int c = 0;
7308c2ecf20Sopenharmony_ci	int fill;
7318c2ecf20Sopenharmony_ci	u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 };
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	fill = (TS_SIZE - 4) - length;
7348c2ecf20Sopenharmony_ci	if (pes_start)
7358c2ecf20Sopenharmony_ci		tshead[1] = 0x40;
7368c2ecf20Sopenharmony_ci	if (fill)
7378c2ecf20Sopenharmony_ci		tshead[3] = 0x30;
7388c2ecf20Sopenharmony_ci	tshead[1] |= (u8)((pid & 0x1F00) >> 8);
7398c2ecf20Sopenharmony_ci	tshead[2] |= (u8)(pid & 0x00FF);
7408c2ecf20Sopenharmony_ci	tshead[3] |= ((*counter)++ & 0x0F);
7418c2ecf20Sopenharmony_ci	memcpy(buf, tshead, 4);
7428c2ecf20Sopenharmony_ci	c += 4;
7438c2ecf20Sopenharmony_ci
7448c2ecf20Sopenharmony_ci	if (fill) {
7458c2ecf20Sopenharmony_ci		buf[4] = fill - 1;
7468c2ecf20Sopenharmony_ci		c++;
7478c2ecf20Sopenharmony_ci		if (fill > 1) {
7488c2ecf20Sopenharmony_ci			buf[5] = 0x00;
7498c2ecf20Sopenharmony_ci			c++;
7508c2ecf20Sopenharmony_ci		}
7518c2ecf20Sopenharmony_ci		for (i = 6; i < fill + 4; i++) {
7528c2ecf20Sopenharmony_ci			buf[i] = 0xFF;
7538c2ecf20Sopenharmony_ci			c++;
7548c2ecf20Sopenharmony_ci		}
7558c2ecf20Sopenharmony_ci	}
7568c2ecf20Sopenharmony_ci
7578c2ecf20Sopenharmony_ci	return c;
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_cistatic void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
7628c2ecf20Sopenharmony_ci		   struct dvb_demux_feed *feed)
7638c2ecf20Sopenharmony_ci{
7648c2ecf20Sopenharmony_ci	int l, pes_start;
7658c2ecf20Sopenharmony_ci	u8 obuf[TS_SIZE];
7668c2ecf20Sopenharmony_ci	long c = 0;
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	pes_start = 0;
7698c2ecf20Sopenharmony_ci	if (length > 3 &&
7708c2ecf20Sopenharmony_ci	     buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)
7718c2ecf20Sopenharmony_ci		switch (buf[3]) {
7728c2ecf20Sopenharmony_ci			case PROG_STREAM_MAP:
7738c2ecf20Sopenharmony_ci			case PRIVATE_STREAM2:
7748c2ecf20Sopenharmony_ci			case PROG_STREAM_DIR:
7758c2ecf20Sopenharmony_ci			case ECM_STREAM     :
7768c2ecf20Sopenharmony_ci			case EMM_STREAM     :
7778c2ecf20Sopenharmony_ci			case PADDING_STREAM :
7788c2ecf20Sopenharmony_ci			case DSM_CC_STREAM  :
7798c2ecf20Sopenharmony_ci			case ISO13522_STREAM:
7808c2ecf20Sopenharmony_ci			case PRIVATE_STREAM1:
7818c2ecf20Sopenharmony_ci			case AUDIO_STREAM_S ... AUDIO_STREAM_E:
7828c2ecf20Sopenharmony_ci			case VIDEO_STREAM_S ... VIDEO_STREAM_E:
7838c2ecf20Sopenharmony_ci				pes_start = 1;
7848c2ecf20Sopenharmony_ci				break;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci			default:
7878c2ecf20Sopenharmony_ci				break;
7888c2ecf20Sopenharmony_ci		}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_ci	while (c < length) {
7918c2ecf20Sopenharmony_ci		memset(obuf, 0, TS_SIZE);
7928c2ecf20Sopenharmony_ci		if (length - c >= (TS_SIZE - 4)){
7938c2ecf20Sopenharmony_ci			l = write_ts_header2(pid, counter, pes_start,
7948c2ecf20Sopenharmony_ci					     obuf, (TS_SIZE - 4));
7958c2ecf20Sopenharmony_ci			memcpy(obuf + l, buf + c, TS_SIZE - l);
7968c2ecf20Sopenharmony_ci			c += TS_SIZE - l;
7978c2ecf20Sopenharmony_ci		} else {
7988c2ecf20Sopenharmony_ci			l = write_ts_header2(pid, counter, pes_start,
7998c2ecf20Sopenharmony_ci					     obuf, length - c);
8008c2ecf20Sopenharmony_ci			memcpy(obuf + l, buf + c, TS_SIZE - l);
8018c2ecf20Sopenharmony_ci			c = length;
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_ci		feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, NULL);
8048c2ecf20Sopenharmony_ci		pes_start = 0;
8058c2ecf20Sopenharmony_ci	}
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_cistatic int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
8108c2ecf20Sopenharmony_ci{
8118c2ecf20Sopenharmony_ci	struct ipack *ipack = &av7110->ipack[type];
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	if (buf[1] & TRANS_ERROR) {
8148c2ecf20Sopenharmony_ci		av7110_ipack_reset(ipack);
8158c2ecf20Sopenharmony_ci		return -1;
8168c2ecf20Sopenharmony_ci	}
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_ci	if (!(buf[3] & PAYLOAD))
8198c2ecf20Sopenharmony_ci		return -1;
8208c2ecf20Sopenharmony_ci
8218c2ecf20Sopenharmony_ci	if (buf[1] & PAY_START)
8228c2ecf20Sopenharmony_ci		av7110_ipack_flush(ipack);
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	if (buf[3] & ADAPT_FIELD) {
8258c2ecf20Sopenharmony_ci		len -= buf[4] + 1;
8268c2ecf20Sopenharmony_ci		buf += buf[4] + 1;
8278c2ecf20Sopenharmony_ci		if (!len)
8288c2ecf20Sopenharmony_ci			return 0;
8298c2ecf20Sopenharmony_ci	}
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	av7110_ipack_instant_repack(buf + 4, len - 4, ipack);
8328c2ecf20Sopenharmony_ci	return 0;
8338c2ecf20Sopenharmony_ci}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ciint av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
8378c2ecf20Sopenharmony_ci{
8388c2ecf20Sopenharmony_ci	struct dvb_demux *demux = feed->demux;
8398c2ecf20Sopenharmony_ci	struct av7110 *av7110 = (struct av7110 *) demux->priv;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
8428c2ecf20Sopenharmony_ci
8438c2ecf20Sopenharmony_ci	if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
8448c2ecf20Sopenharmony_ci		return 0;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	switch (feed->pes_type) {
8478c2ecf20Sopenharmony_ci	case 0:
8488c2ecf20Sopenharmony_ci		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
8498c2ecf20Sopenharmony_ci			return -EINVAL;
8508c2ecf20Sopenharmony_ci		break;
8518c2ecf20Sopenharmony_ci	case 1:
8528c2ecf20Sopenharmony_ci		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
8538c2ecf20Sopenharmony_ci			return -EINVAL;
8548c2ecf20Sopenharmony_ci		break;
8558c2ecf20Sopenharmony_ci	default:
8568c2ecf20Sopenharmony_ci		return -1;
8578c2ecf20Sopenharmony_ci	}
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
8608c2ecf20Sopenharmony_ci}
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci/******************************************************************************
8658c2ecf20Sopenharmony_ci * Video MPEG decoder events
8668c2ecf20Sopenharmony_ci ******************************************************************************/
8678c2ecf20Sopenharmony_civoid dvb_video_add_event(struct av7110 *av7110, struct video_event *event)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	struct dvb_video_events *events = &av7110->video_events;
8708c2ecf20Sopenharmony_ci	int wp;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	spin_lock_bh(&events->lock);
8738c2ecf20Sopenharmony_ci
8748c2ecf20Sopenharmony_ci	wp = (events->eventw + 1) % MAX_VIDEO_EVENT;
8758c2ecf20Sopenharmony_ci	if (wp == events->eventr) {
8768c2ecf20Sopenharmony_ci		events->overflow = 1;
8778c2ecf20Sopenharmony_ci		events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	//FIXME: timestamp?
8818c2ecf20Sopenharmony_ci	memcpy(&events->events[events->eventw], event, sizeof(struct video_event));
8828c2ecf20Sopenharmony_ci	events->eventw = wp;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	spin_unlock_bh(&events->lock);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	wake_up_interruptible(&events->wait_queue);
8878c2ecf20Sopenharmony_ci}
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags)
8918c2ecf20Sopenharmony_ci{
8928c2ecf20Sopenharmony_ci	struct dvb_video_events *events = &av7110->video_events;
8938c2ecf20Sopenharmony_ci
8948c2ecf20Sopenharmony_ci	if (events->overflow) {
8958c2ecf20Sopenharmony_ci		events->overflow = 0;
8968c2ecf20Sopenharmony_ci		return -EOVERFLOW;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci	if (events->eventw == events->eventr) {
8998c2ecf20Sopenharmony_ci		int ret;
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci		if (flags & O_NONBLOCK)
9028c2ecf20Sopenharmony_ci			return -EWOULDBLOCK;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci		ret = wait_event_interruptible(events->wait_queue,
9058c2ecf20Sopenharmony_ci					       events->eventw != events->eventr);
9068c2ecf20Sopenharmony_ci		if (ret < 0)
9078c2ecf20Sopenharmony_ci			return ret;
9088c2ecf20Sopenharmony_ci	}
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	spin_lock_bh(&events->lock);
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	memcpy(event, &events->events[events->eventr],
9138c2ecf20Sopenharmony_ci	       sizeof(struct video_event));
9148c2ecf20Sopenharmony_ci	events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	spin_unlock_bh(&events->lock);
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci	return 0;
9198c2ecf20Sopenharmony_ci}
9208c2ecf20Sopenharmony_ci
9218c2ecf20Sopenharmony_ci/******************************************************************************
9228c2ecf20Sopenharmony_ci * DVB device file operations
9238c2ecf20Sopenharmony_ci ******************************************************************************/
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic __poll_t dvb_video_poll(struct file *file, poll_table *wait)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
9288c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
9298c2ecf20Sopenharmony_ci	__poll_t mask = 0;
9308c2ecf20Sopenharmony_ci
9318c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	if ((file->f_flags & O_ACCMODE) != O_RDONLY)
9348c2ecf20Sopenharmony_ci		poll_wait(file, &av7110->avout.queue, wait);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	poll_wait(file, &av7110->video_events.wait_queue, wait);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	if (av7110->video_events.eventw != av7110->video_events.eventr)
9398c2ecf20Sopenharmony_ci		mask = EPOLLPRI;
9408c2ecf20Sopenharmony_ci
9418c2ecf20Sopenharmony_ci	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
9428c2ecf20Sopenharmony_ci		if (av7110->playing) {
9438c2ecf20Sopenharmony_ci			if (FREE_COND)
9448c2ecf20Sopenharmony_ci				mask |= (EPOLLOUT | EPOLLWRNORM);
9458c2ecf20Sopenharmony_ci		} else {
9468c2ecf20Sopenharmony_ci			/* if not playing: may play if asked for */
9478c2ecf20Sopenharmony_ci			mask |= (EPOLLOUT | EPOLLWRNORM);
9488c2ecf20Sopenharmony_ci		}
9498c2ecf20Sopenharmony_ci	}
9508c2ecf20Sopenharmony_ci
9518c2ecf20Sopenharmony_ci	return mask;
9528c2ecf20Sopenharmony_ci}
9538c2ecf20Sopenharmony_ci
9548c2ecf20Sopenharmony_cistatic ssize_t dvb_video_write(struct file *file, const char __user *buf,
9558c2ecf20Sopenharmony_ci			       size_t count, loff_t *ppos)
9568c2ecf20Sopenharmony_ci{
9578c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
9588c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
9598c2ecf20Sopenharmony_ci	unsigned char c;
9608c2ecf20Sopenharmony_ci
9618c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_ci	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
9648c2ecf20Sopenharmony_ci		return -EPERM;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)
9678c2ecf20Sopenharmony_ci		return -EPERM;
9688c2ecf20Sopenharmony_ci
9698c2ecf20Sopenharmony_ci	if (get_user(c, buf))
9708c2ecf20Sopenharmony_ci		return -EFAULT;
9718c2ecf20Sopenharmony_ci	if (c == 0x47 && count % TS_SIZE == 0)
9728c2ecf20Sopenharmony_ci		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
9738c2ecf20Sopenharmony_ci	else
9748c2ecf20Sopenharmony_ci		return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);
9758c2ecf20Sopenharmony_ci}
9768c2ecf20Sopenharmony_ci
9778c2ecf20Sopenharmony_cistatic __poll_t dvb_audio_poll(struct file *file, poll_table *wait)
9788c2ecf20Sopenharmony_ci{
9798c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
9808c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
9818c2ecf20Sopenharmony_ci	__poll_t mask = 0;
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	poll_wait(file, &av7110->aout.queue, wait);
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	if (av7110->playing) {
9888c2ecf20Sopenharmony_ci		if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
9898c2ecf20Sopenharmony_ci			mask |= (EPOLLOUT | EPOLLWRNORM);
9908c2ecf20Sopenharmony_ci	} else /* if not playing: may play if asked for */
9918c2ecf20Sopenharmony_ci		mask = (EPOLLOUT | EPOLLWRNORM);
9928c2ecf20Sopenharmony_ci
9938c2ecf20Sopenharmony_ci	return mask;
9948c2ecf20Sopenharmony_ci}
9958c2ecf20Sopenharmony_ci
9968c2ecf20Sopenharmony_cistatic ssize_t dvb_audio_write(struct file *file, const char __user *buf,
9978c2ecf20Sopenharmony_ci			       size_t count, loff_t *ppos)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
10008c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
10018c2ecf20Sopenharmony_ci	unsigned char c;
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) {
10068c2ecf20Sopenharmony_ci		printk(KERN_ERR "not audio source memory\n");
10078c2ecf20Sopenharmony_ci		return -EPERM;
10088c2ecf20Sopenharmony_ci	}
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	if (get_user(c, buf))
10118c2ecf20Sopenharmony_ci		return -EFAULT;
10128c2ecf20Sopenharmony_ci	if (c == 0x47 && count % TS_SIZE == 0)
10138c2ecf20Sopenharmony_ci		return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
10148c2ecf20Sopenharmony_ci	else
10158c2ecf20Sopenharmony_ci		return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci#define MIN_IFRAME 400000
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	unsigned i, n;
10258c2ecf20Sopenharmony_ci	int progressive = 0;
10268c2ecf20Sopenharmony_ci	int match = 0;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	if (len == 0)
10318c2ecf20Sopenharmony_ci		return 0;
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	if (!(av7110->playing & RP_VIDEO)) {
10348c2ecf20Sopenharmony_ci		if (av7110_av_start_play(av7110, RP_VIDEO) < 0)
10358c2ecf20Sopenharmony_ci			return -EBUSY;
10368c2ecf20Sopenharmony_ci	}
10378c2ecf20Sopenharmony_ci
10388c2ecf20Sopenharmony_ci	/* search in buf for instances of 00 00 01 b5 1? */
10398c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
10408c2ecf20Sopenharmony_ci		unsigned char c;
10418c2ecf20Sopenharmony_ci		if (get_user(c, buf + i))
10428c2ecf20Sopenharmony_ci			return -EFAULT;
10438c2ecf20Sopenharmony_ci		if (match == 5) {
10448c2ecf20Sopenharmony_ci			progressive = c & 0x08;
10458c2ecf20Sopenharmony_ci			match = 0;
10468c2ecf20Sopenharmony_ci		}
10478c2ecf20Sopenharmony_ci		if (c == 0x00) {
10488c2ecf20Sopenharmony_ci			match = (match == 1 || match == 2) ? 2 : 1;
10498c2ecf20Sopenharmony_ci			continue;
10508c2ecf20Sopenharmony_ci		}
10518c2ecf20Sopenharmony_ci		switch (match++) {
10528c2ecf20Sopenharmony_ci		case 2: if (c == 0x01)
10538c2ecf20Sopenharmony_ci				continue;
10548c2ecf20Sopenharmony_ci			break;
10558c2ecf20Sopenharmony_ci		case 3: if (c == 0xb5)
10568c2ecf20Sopenharmony_ci				continue;
10578c2ecf20Sopenharmony_ci			break;
10588c2ecf20Sopenharmony_ci		case 4: if ((c & 0xf0) == 0x10)
10598c2ecf20Sopenharmony_ci				continue;
10608c2ecf20Sopenharmony_ci			break;
10618c2ecf20Sopenharmony_ci		}
10628c2ecf20Sopenharmony_ci		match = 0;
10638c2ecf20Sopenharmony_ci	}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	/* setting n always > 1, fixes problems when playing stillframes
10668c2ecf20Sopenharmony_ci	   consisting of I- and P-Frames */
10678c2ecf20Sopenharmony_ci	n = MIN_IFRAME / len + 1;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	/* FIXME: nonblock? */
10708c2ecf20Sopenharmony_ci	dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
10738c2ecf20Sopenharmony_ci		dvb_play(av7110, buf, len, 0, 1);
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	av7110_ipack_flush(&av7110->ipack[1]);
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	if (progressive)
10788c2ecf20Sopenharmony_ci		return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
10798c2ecf20Sopenharmony_ci	else
10808c2ecf20Sopenharmony_ci		return 0;
10818c2ecf20Sopenharmony_ci}
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
10848c2ecf20Sopenharmony_cistruct compat_video_still_picture {
10858c2ecf20Sopenharmony_ci	compat_uptr_t iFrame;
10868c2ecf20Sopenharmony_ci	int32_t size;
10878c2ecf20Sopenharmony_ci};
10888c2ecf20Sopenharmony_ci#define VIDEO_STILLPICTURE32 _IOW('o', 30, struct compat_video_still_picture)
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_cistruct compat_video_event {
10918c2ecf20Sopenharmony_ci	__s32 type;
10928c2ecf20Sopenharmony_ci	/* unused, make sure to use atomic time for y2038 if it ever gets used */
10938c2ecf20Sopenharmony_ci	compat_long_t timestamp;
10948c2ecf20Sopenharmony_ci	union {
10958c2ecf20Sopenharmony_ci		video_size_t size;
10968c2ecf20Sopenharmony_ci		unsigned int frame_rate;        /* in frames per 1000sec */
10978c2ecf20Sopenharmony_ci		unsigned char vsync_field;      /* unknown/odd/even/progressive */
10988c2ecf20Sopenharmony_ci	} u;
10998c2ecf20Sopenharmony_ci};
11008c2ecf20Sopenharmony_ci#define VIDEO_GET_EVENT32 _IOR('o', 28, struct compat_video_event)
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_cistatic int dvb_compat_video_get_event(struct av7110 *av7110,
11038c2ecf20Sopenharmony_ci				      struct compat_video_event *event, int flags)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	struct video_event ev;
11068c2ecf20Sopenharmony_ci	int ret;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	ret = dvb_video_get_event(av7110, &ev, flags);
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	*event = (struct compat_video_event) {
11118c2ecf20Sopenharmony_ci		.type = ev.type,
11128c2ecf20Sopenharmony_ci		.timestamp = ev.timestamp,
11138c2ecf20Sopenharmony_ci		.u.size = ev.u.size,
11148c2ecf20Sopenharmony_ci	};
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	return ret;
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci#endif
11198c2ecf20Sopenharmony_ci
11208c2ecf20Sopenharmony_cistatic int dvb_video_ioctl(struct file *file,
11218c2ecf20Sopenharmony_ci			   unsigned int cmd, void *parg)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
11248c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
11258c2ecf20Sopenharmony_ci	unsigned long arg = (unsigned long) parg;
11268c2ecf20Sopenharmony_ci	int ret = 0;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
11318c2ecf20Sopenharmony_ci		if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
11328c2ecf20Sopenharmony_ci		     cmd != VIDEO_GET_SIZE ) {
11338c2ecf20Sopenharmony_ci			return -EPERM;
11348c2ecf20Sopenharmony_ci		}
11358c2ecf20Sopenharmony_ci	}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&av7110->ioctl_mutex))
11388c2ecf20Sopenharmony_ci		return -ERESTARTSYS;
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_ci	switch (cmd) {
11418c2ecf20Sopenharmony_ci	case VIDEO_STOP:
11428c2ecf20Sopenharmony_ci		av7110->videostate.play_state = VIDEO_STOPPED;
11438c2ecf20Sopenharmony_ci		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
11448c2ecf20Sopenharmony_ci			ret = av7110_av_stop(av7110, RP_VIDEO);
11458c2ecf20Sopenharmony_ci		else
11468c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_STOP,
11478c2ecf20Sopenharmony_ci			       av7110->videostate.video_blank ? 0 : 1);
11488c2ecf20Sopenharmony_ci		if (!ret)
11498c2ecf20Sopenharmony_ci			av7110->trickmode = TRICK_NONE;
11508c2ecf20Sopenharmony_ci		break;
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	case VIDEO_PLAY:
11538c2ecf20Sopenharmony_ci		av7110->trickmode = TRICK_NONE;
11548c2ecf20Sopenharmony_ci		if (av7110->videostate.play_state == VIDEO_FREEZED) {
11558c2ecf20Sopenharmony_ci			av7110->videostate.play_state = VIDEO_PLAYING;
11568c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
11578c2ecf20Sopenharmony_ci			if (ret)
11588c2ecf20Sopenharmony_ci				break;
11598c2ecf20Sopenharmony_ci		}
11608c2ecf20Sopenharmony_ci		if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
11618c2ecf20Sopenharmony_ci			if (av7110->playing == RP_AV) {
11628c2ecf20Sopenharmony_ci				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
11638c2ecf20Sopenharmony_ci				if (ret)
11648c2ecf20Sopenharmony_ci					break;
11658c2ecf20Sopenharmony_ci				av7110->playing &= ~RP_VIDEO;
11668c2ecf20Sopenharmony_ci			}
11678c2ecf20Sopenharmony_ci			ret = av7110_av_start_play(av7110, RP_VIDEO);
11688c2ecf20Sopenharmony_ci		}
11698c2ecf20Sopenharmony_ci		if (!ret)
11708c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
11718c2ecf20Sopenharmony_ci		if (!ret)
11728c2ecf20Sopenharmony_ci			av7110->videostate.play_state = VIDEO_PLAYING;
11738c2ecf20Sopenharmony_ci		break;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	case VIDEO_FREEZE:
11768c2ecf20Sopenharmony_ci		av7110->videostate.play_state = VIDEO_FREEZED;
11778c2ecf20Sopenharmony_ci		if (av7110->playing & RP_VIDEO)
11788c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
11798c2ecf20Sopenharmony_ci		else
11808c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);
11818c2ecf20Sopenharmony_ci		if (!ret)
11828c2ecf20Sopenharmony_ci			av7110->trickmode = TRICK_FREEZE;
11838c2ecf20Sopenharmony_ci		break;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	case VIDEO_CONTINUE:
11868c2ecf20Sopenharmony_ci		if (av7110->playing & RP_VIDEO)
11878c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
11888c2ecf20Sopenharmony_ci		if (!ret)
11898c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
11908c2ecf20Sopenharmony_ci		if (!ret) {
11918c2ecf20Sopenharmony_ci			av7110->videostate.play_state = VIDEO_PLAYING;
11928c2ecf20Sopenharmony_ci			av7110->trickmode = TRICK_NONE;
11938c2ecf20Sopenharmony_ci		}
11948c2ecf20Sopenharmony_ci		break;
11958c2ecf20Sopenharmony_ci
11968c2ecf20Sopenharmony_ci	case VIDEO_SELECT_SOURCE:
11978c2ecf20Sopenharmony_ci		av7110->videostate.stream_source = (video_stream_source_t) arg;
11988c2ecf20Sopenharmony_ci		break;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	case VIDEO_SET_BLANK:
12018c2ecf20Sopenharmony_ci		av7110->videostate.video_blank = (int) arg;
12028c2ecf20Sopenharmony_ci		break;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci	case VIDEO_GET_STATUS:
12058c2ecf20Sopenharmony_ci		memcpy(parg, &av7110->videostate, sizeof(struct video_status));
12068c2ecf20Sopenharmony_ci		break;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
12098c2ecf20Sopenharmony_ci	case VIDEO_GET_EVENT32:
12108c2ecf20Sopenharmony_ci		ret = dvb_compat_video_get_event(av7110, parg, file->f_flags);
12118c2ecf20Sopenharmony_ci		break;
12128c2ecf20Sopenharmony_ci#endif
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	case VIDEO_GET_EVENT:
12158c2ecf20Sopenharmony_ci		ret = dvb_video_get_event(av7110, parg, file->f_flags);
12168c2ecf20Sopenharmony_ci		break;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	case VIDEO_GET_SIZE:
12198c2ecf20Sopenharmony_ci		memcpy(parg, &av7110->video_size, sizeof(video_size_t));
12208c2ecf20Sopenharmony_ci		break;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	case VIDEO_SET_DISPLAY_FORMAT:
12238c2ecf20Sopenharmony_ci	{
12248c2ecf20Sopenharmony_ci		video_displayformat_t format = (video_displayformat_t) arg;
12258c2ecf20Sopenharmony_ci		switch (format) {
12268c2ecf20Sopenharmony_ci		case VIDEO_PAN_SCAN:
12278c2ecf20Sopenharmony_ci			av7110->display_panscan = VID_PAN_SCAN_PREF;
12288c2ecf20Sopenharmony_ci			break;
12298c2ecf20Sopenharmony_ci		case VIDEO_LETTER_BOX:
12308c2ecf20Sopenharmony_ci			av7110->display_panscan = VID_VC_AND_PS_PREF;
12318c2ecf20Sopenharmony_ci			break;
12328c2ecf20Sopenharmony_ci		case VIDEO_CENTER_CUT_OUT:
12338c2ecf20Sopenharmony_ci			av7110->display_panscan = VID_CENTRE_CUT_PREF;
12348c2ecf20Sopenharmony_ci			break;
12358c2ecf20Sopenharmony_ci		default:
12368c2ecf20Sopenharmony_ci			ret = -EINVAL;
12378c2ecf20Sopenharmony_ci		}
12388c2ecf20Sopenharmony_ci		if (ret < 0)
12398c2ecf20Sopenharmony_ci			break;
12408c2ecf20Sopenharmony_ci		av7110->videostate.display_format = format;
12418c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
12428c2ecf20Sopenharmony_ci				    1, av7110->display_panscan);
12438c2ecf20Sopenharmony_ci		break;
12448c2ecf20Sopenharmony_ci	}
12458c2ecf20Sopenharmony_ci
12468c2ecf20Sopenharmony_ci	case VIDEO_SET_FORMAT:
12478c2ecf20Sopenharmony_ci		if (arg > 1) {
12488c2ecf20Sopenharmony_ci			ret = -EINVAL;
12498c2ecf20Sopenharmony_ci			break;
12508c2ecf20Sopenharmony_ci		}
12518c2ecf20Sopenharmony_ci		av7110->display_ar = arg;
12528c2ecf20Sopenharmony_ci		ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
12538c2ecf20Sopenharmony_ci				    1, (u16) arg);
12548c2ecf20Sopenharmony_ci		break;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
12578c2ecf20Sopenharmony_ci	case VIDEO_STILLPICTURE32:
12588c2ecf20Sopenharmony_ci	{
12598c2ecf20Sopenharmony_ci		struct compat_video_still_picture *pic =
12608c2ecf20Sopenharmony_ci			(struct compat_video_still_picture *) parg;
12618c2ecf20Sopenharmony_ci		av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
12628c2ecf20Sopenharmony_ci		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
12638c2ecf20Sopenharmony_ci		ret = play_iframe(av7110, compat_ptr(pic->iFrame),
12648c2ecf20Sopenharmony_ci				  pic->size, file->f_flags & O_NONBLOCK);
12658c2ecf20Sopenharmony_ci		break;
12668c2ecf20Sopenharmony_ci	}
12678c2ecf20Sopenharmony_ci#endif
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci	case VIDEO_STILLPICTURE:
12708c2ecf20Sopenharmony_ci	{
12718c2ecf20Sopenharmony_ci		struct video_still_picture *pic =
12728c2ecf20Sopenharmony_ci			(struct video_still_picture *) parg;
12738c2ecf20Sopenharmony_ci		av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
12748c2ecf20Sopenharmony_ci		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
12758c2ecf20Sopenharmony_ci		ret = play_iframe(av7110, pic->iFrame, pic->size,
12768c2ecf20Sopenharmony_ci				  file->f_flags & O_NONBLOCK);
12778c2ecf20Sopenharmony_ci		break;
12788c2ecf20Sopenharmony_ci	}
12798c2ecf20Sopenharmony_ci
12808c2ecf20Sopenharmony_ci	case VIDEO_FAST_FORWARD:
12818c2ecf20Sopenharmony_ci		//note: arg is ignored by firmware
12828c2ecf20Sopenharmony_ci		if (av7110->playing & RP_VIDEO)
12838c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
12848c2ecf20Sopenharmony_ci					    __Scan_I, 2, AV_PES, 0);
12858c2ecf20Sopenharmony_ci		else
12868c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg);
12878c2ecf20Sopenharmony_ci		if (!ret) {
12888c2ecf20Sopenharmony_ci			av7110->trickmode = TRICK_FAST;
12898c2ecf20Sopenharmony_ci			av7110->videostate.play_state = VIDEO_PLAYING;
12908c2ecf20Sopenharmony_ci		}
12918c2ecf20Sopenharmony_ci		break;
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_ci	case VIDEO_SLOWMOTION:
12948c2ecf20Sopenharmony_ci		if (av7110->playing&RP_VIDEO) {
12958c2ecf20Sopenharmony_ci			if (av7110->trickmode != TRICK_SLOW)
12968c2ecf20Sopenharmony_ci				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
12978c2ecf20Sopenharmony_ci			if (!ret)
12988c2ecf20Sopenharmony_ci				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
12998c2ecf20Sopenharmony_ci		} else {
13008c2ecf20Sopenharmony_ci			ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);
13018c2ecf20Sopenharmony_ci			if (!ret)
13028c2ecf20Sopenharmony_ci				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0);
13038c2ecf20Sopenharmony_ci			if (!ret)
13048c2ecf20Sopenharmony_ci				ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
13058c2ecf20Sopenharmony_ci		}
13068c2ecf20Sopenharmony_ci		if (!ret) {
13078c2ecf20Sopenharmony_ci			av7110->trickmode = TRICK_SLOW;
13088c2ecf20Sopenharmony_ci			av7110->videostate.play_state = VIDEO_PLAYING;
13098c2ecf20Sopenharmony_ci		}
13108c2ecf20Sopenharmony_ci		break;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	case VIDEO_GET_CAPABILITIES:
13138c2ecf20Sopenharmony_ci		*(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 |
13148c2ecf20Sopenharmony_ci			VIDEO_CAP_SYS | VIDEO_CAP_PROG;
13158c2ecf20Sopenharmony_ci		break;
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci	case VIDEO_CLEAR_BUFFER:
13188c2ecf20Sopenharmony_ci		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
13198c2ecf20Sopenharmony_ci		av7110_ipack_reset(&av7110->ipack[1]);
13208c2ecf20Sopenharmony_ci		if (av7110->playing == RP_AV) {
13218c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
13228c2ecf20Sopenharmony_ci					    __Play, 2, AV_PES, 0);
13238c2ecf20Sopenharmony_ci			if (ret)
13248c2ecf20Sopenharmony_ci				break;
13258c2ecf20Sopenharmony_ci			if (av7110->trickmode == TRICK_FAST)
13268c2ecf20Sopenharmony_ci				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
13278c2ecf20Sopenharmony_ci						    __Scan_I, 2, AV_PES, 0);
13288c2ecf20Sopenharmony_ci			if (av7110->trickmode == TRICK_SLOW) {
13298c2ecf20Sopenharmony_ci				ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
13308c2ecf20Sopenharmony_ci						    __Slow, 2, 0, 0);
13318c2ecf20Sopenharmony_ci				if (!ret)
13328c2ecf20Sopenharmony_ci					ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);
13338c2ecf20Sopenharmony_ci			}
13348c2ecf20Sopenharmony_ci			if (av7110->trickmode == TRICK_FREEZE)
13358c2ecf20Sopenharmony_ci				ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1);
13368c2ecf20Sopenharmony_ci		}
13378c2ecf20Sopenharmony_ci		break;
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	case VIDEO_SET_STREAMTYPE:
13408c2ecf20Sopenharmony_ci		break;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	default:
13438c2ecf20Sopenharmony_ci		ret = -ENOIOCTLCMD;
13448c2ecf20Sopenharmony_ci		break;
13458c2ecf20Sopenharmony_ci	}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_ci	mutex_unlock(&av7110->ioctl_mutex);
13488c2ecf20Sopenharmony_ci	return ret;
13498c2ecf20Sopenharmony_ci}
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_cistatic int dvb_audio_ioctl(struct file *file,
13528c2ecf20Sopenharmony_ci			   unsigned int cmd, void *parg)
13538c2ecf20Sopenharmony_ci{
13548c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
13558c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
13568c2ecf20Sopenharmony_ci	unsigned long arg = (unsigned long) parg;
13578c2ecf20Sopenharmony_ci	int ret = 0;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
13628c2ecf20Sopenharmony_ci	    (cmd != AUDIO_GET_STATUS))
13638c2ecf20Sopenharmony_ci		return -EPERM;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	if (mutex_lock_interruptible(&av7110->ioctl_mutex))
13668c2ecf20Sopenharmony_ci		return -ERESTARTSYS;
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci	switch (cmd) {
13698c2ecf20Sopenharmony_ci	case AUDIO_STOP:
13708c2ecf20Sopenharmony_ci		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
13718c2ecf20Sopenharmony_ci			ret = av7110_av_stop(av7110, RP_AUDIO);
13728c2ecf20Sopenharmony_ci		else
13738c2ecf20Sopenharmony_ci			ret = audcom(av7110, AUDIO_CMD_MUTE);
13748c2ecf20Sopenharmony_ci		if (!ret)
13758c2ecf20Sopenharmony_ci			av7110->audiostate.play_state = AUDIO_STOPPED;
13768c2ecf20Sopenharmony_ci		break;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	case AUDIO_PLAY:
13798c2ecf20Sopenharmony_ci		if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
13808c2ecf20Sopenharmony_ci			ret = av7110_av_start_play(av7110, RP_AUDIO);
13818c2ecf20Sopenharmony_ci		if (!ret)
13828c2ecf20Sopenharmony_ci			ret = audcom(av7110, AUDIO_CMD_UNMUTE);
13838c2ecf20Sopenharmony_ci		if (!ret)
13848c2ecf20Sopenharmony_ci			av7110->audiostate.play_state = AUDIO_PLAYING;
13858c2ecf20Sopenharmony_ci		break;
13868c2ecf20Sopenharmony_ci
13878c2ecf20Sopenharmony_ci	case AUDIO_PAUSE:
13888c2ecf20Sopenharmony_ci		ret = audcom(av7110, AUDIO_CMD_MUTE);
13898c2ecf20Sopenharmony_ci		if (!ret)
13908c2ecf20Sopenharmony_ci			av7110->audiostate.play_state = AUDIO_PAUSED;
13918c2ecf20Sopenharmony_ci		break;
13928c2ecf20Sopenharmony_ci
13938c2ecf20Sopenharmony_ci	case AUDIO_CONTINUE:
13948c2ecf20Sopenharmony_ci		if (av7110->audiostate.play_state == AUDIO_PAUSED) {
13958c2ecf20Sopenharmony_ci			av7110->audiostate.play_state = AUDIO_PLAYING;
13968c2ecf20Sopenharmony_ci			ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);
13978c2ecf20Sopenharmony_ci		}
13988c2ecf20Sopenharmony_ci		break;
13998c2ecf20Sopenharmony_ci
14008c2ecf20Sopenharmony_ci	case AUDIO_SELECT_SOURCE:
14018c2ecf20Sopenharmony_ci		av7110->audiostate.stream_source = (audio_stream_source_t) arg;
14028c2ecf20Sopenharmony_ci		break;
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci	case AUDIO_SET_MUTE:
14058c2ecf20Sopenharmony_ci	{
14068c2ecf20Sopenharmony_ci		ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
14078c2ecf20Sopenharmony_ci		if (!ret)
14088c2ecf20Sopenharmony_ci			av7110->audiostate.mute_state = (int) arg;
14098c2ecf20Sopenharmony_ci		break;
14108c2ecf20Sopenharmony_ci	}
14118c2ecf20Sopenharmony_ci
14128c2ecf20Sopenharmony_ci	case AUDIO_SET_AV_SYNC:
14138c2ecf20Sopenharmony_ci		av7110->audiostate.AV_sync_state = (int) arg;
14148c2ecf20Sopenharmony_ci		ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
14158c2ecf20Sopenharmony_ci		break;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	case AUDIO_SET_BYPASS_MODE:
14188c2ecf20Sopenharmony_ci		if (FW_VERSION(av7110->arm_app) < 0x2621)
14198c2ecf20Sopenharmony_ci			ret = -EINVAL;
14208c2ecf20Sopenharmony_ci		av7110->audiostate.bypass_mode = (int)arg;
14218c2ecf20Sopenharmony_ci		break;
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci	case AUDIO_CHANNEL_SELECT:
14248c2ecf20Sopenharmony_ci		av7110->audiostate.channel_select = (audio_channel_select_t) arg;
14258c2ecf20Sopenharmony_ci		switch(av7110->audiostate.channel_select) {
14268c2ecf20Sopenharmony_ci		case AUDIO_STEREO:
14278c2ecf20Sopenharmony_ci			ret = audcom(av7110, AUDIO_CMD_STEREO);
14288c2ecf20Sopenharmony_ci			if (!ret) {
14298c2ecf20Sopenharmony_ci				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
14308c2ecf20Sopenharmony_ci					i2c_writereg(av7110, 0x20, 0x02, 0x49);
14318c2ecf20Sopenharmony_ci				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
14328c2ecf20Sopenharmony_ci					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);
14338c2ecf20Sopenharmony_ci			}
14348c2ecf20Sopenharmony_ci			break;
14358c2ecf20Sopenharmony_ci		case AUDIO_MONO_LEFT:
14368c2ecf20Sopenharmony_ci			ret = audcom(av7110, AUDIO_CMD_MONO_L);
14378c2ecf20Sopenharmony_ci			if (!ret) {
14388c2ecf20Sopenharmony_ci				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
14398c2ecf20Sopenharmony_ci					i2c_writereg(av7110, 0x20, 0x02, 0x4a);
14408c2ecf20Sopenharmony_ci				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
14418c2ecf20Sopenharmony_ci					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);
14428c2ecf20Sopenharmony_ci			}
14438c2ecf20Sopenharmony_ci			break;
14448c2ecf20Sopenharmony_ci		case AUDIO_MONO_RIGHT:
14458c2ecf20Sopenharmony_ci			ret = audcom(av7110, AUDIO_CMD_MONO_R);
14468c2ecf20Sopenharmony_ci			if (!ret) {
14478c2ecf20Sopenharmony_ci				if (av7110->adac_type == DVB_ADAC_CRYSTAL)
14488c2ecf20Sopenharmony_ci					i2c_writereg(av7110, 0x20, 0x02, 0x45);
14498c2ecf20Sopenharmony_ci				else if (av7110->adac_type == DVB_ADAC_MSP34x5)
14508c2ecf20Sopenharmony_ci					msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);
14518c2ecf20Sopenharmony_ci			}
14528c2ecf20Sopenharmony_ci			break;
14538c2ecf20Sopenharmony_ci		default:
14548c2ecf20Sopenharmony_ci			ret = -EINVAL;
14558c2ecf20Sopenharmony_ci			break;
14568c2ecf20Sopenharmony_ci		}
14578c2ecf20Sopenharmony_ci		break;
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci	case AUDIO_GET_STATUS:
14608c2ecf20Sopenharmony_ci		memcpy(parg, &av7110->audiostate, sizeof(struct audio_status));
14618c2ecf20Sopenharmony_ci		break;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	case AUDIO_GET_CAPABILITIES:
14648c2ecf20Sopenharmony_ci		if (FW_VERSION(av7110->arm_app) < 0x2621)
14658c2ecf20Sopenharmony_ci			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
14668c2ecf20Sopenharmony_ci		else
14678c2ecf20Sopenharmony_ci			*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |
14688c2ecf20Sopenharmony_ci						AUDIO_CAP_MP1 | AUDIO_CAP_MP2;
14698c2ecf20Sopenharmony_ci		break;
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	case AUDIO_CLEAR_BUFFER:
14728c2ecf20Sopenharmony_ci		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
14738c2ecf20Sopenharmony_ci		av7110_ipack_reset(&av7110->ipack[0]);
14748c2ecf20Sopenharmony_ci		if (av7110->playing == RP_AV)
14758c2ecf20Sopenharmony_ci			ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
14768c2ecf20Sopenharmony_ci					    __Play, 2, AV_PES, 0);
14778c2ecf20Sopenharmony_ci		break;
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_ci	case AUDIO_SET_ID:
14808c2ecf20Sopenharmony_ci		break;
14818c2ecf20Sopenharmony_ci
14828c2ecf20Sopenharmony_ci	case AUDIO_SET_MIXER:
14838c2ecf20Sopenharmony_ci	{
14848c2ecf20Sopenharmony_ci		struct audio_mixer *amix = (struct audio_mixer *)parg;
14858c2ecf20Sopenharmony_ci		ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
14868c2ecf20Sopenharmony_ci		break;
14878c2ecf20Sopenharmony_ci	}
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	case AUDIO_SET_STREAMTYPE:
14908c2ecf20Sopenharmony_ci		break;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	default:
14938c2ecf20Sopenharmony_ci		ret = -ENOIOCTLCMD;
14948c2ecf20Sopenharmony_ci	}
14958c2ecf20Sopenharmony_ci
14968c2ecf20Sopenharmony_ci	mutex_unlock(&av7110->ioctl_mutex);
14978c2ecf20Sopenharmony_ci	return ret;
14988c2ecf20Sopenharmony_ci}
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_cistatic int dvb_video_open(struct inode *inode, struct file *file)
15028c2ecf20Sopenharmony_ci{
15038c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
15048c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
15058c2ecf20Sopenharmony_ci	int err;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
15088c2ecf20Sopenharmony_ci
15098c2ecf20Sopenharmony_ci	if ((err = dvb_generic_open(inode, file)) < 0)
15108c2ecf20Sopenharmony_ci		return err;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
15138c2ecf20Sopenharmony_ci		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
15148c2ecf20Sopenharmony_ci		dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
15158c2ecf20Sopenharmony_ci		av7110->video_blank = 1;
15168c2ecf20Sopenharmony_ci		av7110->audiostate.AV_sync_state = 1;
15178c2ecf20Sopenharmony_ci		av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci		/*  empty event queue */
15208c2ecf20Sopenharmony_ci		av7110->video_events.eventr = av7110->video_events.eventw = 0;
15218c2ecf20Sopenharmony_ci	}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	return 0;
15248c2ecf20Sopenharmony_ci}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_cistatic int dvb_video_release(struct inode *inode, struct file *file)
15278c2ecf20Sopenharmony_ci{
15288c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
15298c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
15328c2ecf20Sopenharmony_ci
15338c2ecf20Sopenharmony_ci	if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
15348c2ecf20Sopenharmony_ci		av7110_av_stop(av7110, RP_VIDEO);
15358c2ecf20Sopenharmony_ci	}
15368c2ecf20Sopenharmony_ci
15378c2ecf20Sopenharmony_ci	return dvb_generic_release(inode, file);
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_cistatic int dvb_audio_open(struct inode *inode, struct file *file)
15418c2ecf20Sopenharmony_ci{
15428c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
15438c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
15448c2ecf20Sopenharmony_ci	int err = dvb_generic_open(inode, file);
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
15478c2ecf20Sopenharmony_ci
15488c2ecf20Sopenharmony_ci	if (err < 0)
15498c2ecf20Sopenharmony_ci		return err;
15508c2ecf20Sopenharmony_ci	dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
15518c2ecf20Sopenharmony_ci	av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;
15528c2ecf20Sopenharmony_ci	return 0;
15538c2ecf20Sopenharmony_ci}
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_cistatic int dvb_audio_release(struct inode *inode, struct file *file)
15568c2ecf20Sopenharmony_ci{
15578c2ecf20Sopenharmony_ci	struct dvb_device *dvbdev = file->private_data;
15588c2ecf20Sopenharmony_ci	struct av7110 *av7110 = dvbdev->priv;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	dprintk(2, "av7110:%p, \n", av7110);
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	av7110_av_stop(av7110, RP_AUDIO);
15638c2ecf20Sopenharmony_ci	return dvb_generic_release(inode, file);
15648c2ecf20Sopenharmony_ci}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci/******************************************************************************
15698c2ecf20Sopenharmony_ci * driver registration
15708c2ecf20Sopenharmony_ci ******************************************************************************/
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_cistatic const struct file_operations dvb_video_fops = {
15738c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
15748c2ecf20Sopenharmony_ci	.write		= dvb_video_write,
15758c2ecf20Sopenharmony_ci	.unlocked_ioctl	= dvb_generic_ioctl,
15768c2ecf20Sopenharmony_ci	.compat_ioctl	= dvb_generic_ioctl,
15778c2ecf20Sopenharmony_ci	.open		= dvb_video_open,
15788c2ecf20Sopenharmony_ci	.release	= dvb_video_release,
15798c2ecf20Sopenharmony_ci	.poll		= dvb_video_poll,
15808c2ecf20Sopenharmony_ci	.llseek		= noop_llseek,
15818c2ecf20Sopenharmony_ci};
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cistatic struct dvb_device dvbdev_video = {
15848c2ecf20Sopenharmony_ci	.priv		= NULL,
15858c2ecf20Sopenharmony_ci	.users		= 6,
15868c2ecf20Sopenharmony_ci	.readers	= 5,	/* arbitrary */
15878c2ecf20Sopenharmony_ci	.writers	= 1,
15888c2ecf20Sopenharmony_ci	.fops		= &dvb_video_fops,
15898c2ecf20Sopenharmony_ci	.kernel_ioctl	= dvb_video_ioctl,
15908c2ecf20Sopenharmony_ci};
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_cistatic const struct file_operations dvb_audio_fops = {
15938c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
15948c2ecf20Sopenharmony_ci	.write		= dvb_audio_write,
15958c2ecf20Sopenharmony_ci	.unlocked_ioctl	= dvb_generic_ioctl,
15968c2ecf20Sopenharmony_ci	.compat_ioctl	= dvb_generic_ioctl,
15978c2ecf20Sopenharmony_ci	.open		= dvb_audio_open,
15988c2ecf20Sopenharmony_ci	.release	= dvb_audio_release,
15998c2ecf20Sopenharmony_ci	.poll		= dvb_audio_poll,
16008c2ecf20Sopenharmony_ci	.llseek		= noop_llseek,
16018c2ecf20Sopenharmony_ci};
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_cistatic struct dvb_device dvbdev_audio = {
16048c2ecf20Sopenharmony_ci	.priv		= NULL,
16058c2ecf20Sopenharmony_ci	.users		= 1,
16068c2ecf20Sopenharmony_ci	.writers	= 1,
16078c2ecf20Sopenharmony_ci	.fops		= &dvb_audio_fops,
16088c2ecf20Sopenharmony_ci	.kernel_ioctl	= dvb_audio_ioctl,
16098c2ecf20Sopenharmony_ci};
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ciint av7110_av_register(struct av7110 *av7110)
16138c2ecf20Sopenharmony_ci{
16148c2ecf20Sopenharmony_ci	av7110->audiostate.AV_sync_state = 0;
16158c2ecf20Sopenharmony_ci	av7110->audiostate.mute_state = 0;
16168c2ecf20Sopenharmony_ci	av7110->audiostate.play_state = AUDIO_STOPPED;
16178c2ecf20Sopenharmony_ci	av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;
16188c2ecf20Sopenharmony_ci	av7110->audiostate.channel_select = AUDIO_STEREO;
16198c2ecf20Sopenharmony_ci	av7110->audiostate.bypass_mode = 0;
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_ci	av7110->videostate.video_blank = 0;
16228c2ecf20Sopenharmony_ci	av7110->videostate.play_state = VIDEO_STOPPED;
16238c2ecf20Sopenharmony_ci	av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
16248c2ecf20Sopenharmony_ci	av7110->videostate.video_format = VIDEO_FORMAT_4_3;
16258c2ecf20Sopenharmony_ci	av7110->videostate.display_format = VIDEO_LETTER_BOX;
16268c2ecf20Sopenharmony_ci	av7110->display_ar = VIDEO_FORMAT_4_3;
16278c2ecf20Sopenharmony_ci	av7110->display_panscan = VID_VC_AND_PS_PREF;
16288c2ecf20Sopenharmony_ci
16298c2ecf20Sopenharmony_ci	init_waitqueue_head(&av7110->video_events.wait_queue);
16308c2ecf20Sopenharmony_ci	spin_lock_init(&av7110->video_events.lock);
16318c2ecf20Sopenharmony_ci	av7110->video_events.eventw = av7110->video_events.eventr = 0;
16328c2ecf20Sopenharmony_ci	av7110->video_events.overflow = 0;
16338c2ecf20Sopenharmony_ci	memset(&av7110->video_size, 0, sizeof (video_size_t));
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,
16368c2ecf20Sopenharmony_ci			    &dvbdev_video, av7110, DVB_DEVICE_VIDEO, 0);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev,
16398c2ecf20Sopenharmony_ci			    &dvbdev_audio, av7110, DVB_DEVICE_AUDIO, 0);
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci	return 0;
16428c2ecf20Sopenharmony_ci}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_civoid av7110_av_unregister(struct av7110 *av7110)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	dvb_unregister_device(av7110->audio_dev);
16478c2ecf20Sopenharmony_ci	dvb_unregister_device(av7110->video_dev);
16488c2ecf20Sopenharmony_ci}
16498c2ecf20Sopenharmony_ci
16508c2ecf20Sopenharmony_ciint av7110_av_init(struct av7110 *av7110)
16518c2ecf20Sopenharmony_ci{
16528c2ecf20Sopenharmony_ci	void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb };
16538c2ecf20Sopenharmony_ci	int i, ret;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	for (i = 0; i < 2; i++) {
16568c2ecf20Sopenharmony_ci		struct ipack *ipack = av7110->ipack + i;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci		ret = av7110_ipack_init(ipack, IPACKS, play[i]);
16598c2ecf20Sopenharmony_ci		if (ret < 0) {
16608c2ecf20Sopenharmony_ci			if (i)
16618c2ecf20Sopenharmony_ci				av7110_ipack_free(--ipack);
16628c2ecf20Sopenharmony_ci			goto out;
16638c2ecf20Sopenharmony_ci		}
16648c2ecf20Sopenharmony_ci		ipack->data = av7110;
16658c2ecf20Sopenharmony_ci	}
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN);
16688c2ecf20Sopenharmony_ci	dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN);
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ci	av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN);
16718c2ecf20Sopenharmony_ci	av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS;
16728c2ecf20Sopenharmony_ciout:
16738c2ecf20Sopenharmony_ci	return ret;
16748c2ecf20Sopenharmony_ci}
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_civoid av7110_av_exit(struct av7110 *av7110)
16778c2ecf20Sopenharmony_ci{
16788c2ecf20Sopenharmony_ci	av7110_ipack_free(&av7110->ipack[0]);
16798c2ecf20Sopenharmony_ci	av7110_ipack_free(&av7110->ipack[1]);
16808c2ecf20Sopenharmony_ci}
1681