Path: blob/master/drivers/media/dvb/ttpci/av7110_av.c
15112 views
/*1* av7110_av.c: audio and video MPEG decoder stuff2*3* Copyright (C) 1999-2002 Ralph Metzler4* & Marcus Metzler for convergence integrated media GmbH5*6* originally based on code by:7* Copyright (C) 1998,1999 Christian Theiss <[email protected]>8*9* This program is free software; you can redistribute it and/or10* modify it under the terms of the GNU General Public License11* as published by the Free Software Foundation; either version 212* of the License, or (at your option) any later version.13*14*15* This program is distributed in the hope that it will be useful,16* but WITHOUT ANY WARRANTY; without even the implied warranty of17* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the18* GNU General Public License for more details.19*20*21* You should have received a copy of the GNU General Public License22* along with this program; if not, write to the Free Software23* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.24* Or, point your browser to http://www.gnu.org/copyleft/gpl.html25*26*27* the project's page is at http://www.linuxtv.org/28*/2930#include <linux/types.h>31#include <linux/kernel.h>32#include <linux/string.h>33#include <linux/delay.h>34#include <linux/fs.h>3536#include "av7110.h"37#include "av7110_hw.h"38#include "av7110_av.h"39#include "av7110_ipack.h"4041/* MPEG-2 (ISO 13818 / H.222.0) stream types */42#define PROG_STREAM_MAP 0xBC43#define PRIVATE_STREAM1 0xBD44#define PADDING_STREAM 0xBE45#define PRIVATE_STREAM2 0xBF46#define AUDIO_STREAM_S 0xC047#define AUDIO_STREAM_E 0xDF48#define VIDEO_STREAM_S 0xE049#define VIDEO_STREAM_E 0xEF50#define ECM_STREAM 0xF051#define EMM_STREAM 0xF152#define DSM_CC_STREAM 0xF253#define ISO13522_STREAM 0xF354#define PROG_STREAM_DIR 0xFF5556#define PTS_DTS_FLAGS 0xC05758//pts_dts flags59#define PTS_ONLY 0x8060#define PTS_DTS 0xC061#define TS_SIZE 18862#define TRANS_ERROR 0x8063#define PAY_START 0x4064#define TRANS_PRIO 0x2065#define PID_MASK_HI 0x1F66//flags67#define TRANS_SCRMBL1 0x8068#define TRANS_SCRMBL2 0x4069#define ADAPT_FIELD 0x2070#define PAYLOAD 0x1071#define COUNT_MASK 0x0F7273// adaptation flags74#define DISCON_IND 0x8075#define RAND_ACC_IND 0x4076#define ES_PRI_IND 0x2077#define PCR_FLAG 0x1078#define OPCR_FLAG 0x0879#define SPLICE_FLAG 0x0480#define TRANS_PRIV 0x0281#define ADAP_EXT_FLAG 0x018283// adaptation extension flags84#define LTW_FLAG 0x8085#define PIECE_RATE 0x4086#define SEAM_SPLICE 0x20878889static void p_to_t(u8 const *buf, long int length, u16 pid,90u8 *counter, struct dvb_demux_feed *feed);91static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);929394int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)95{96struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) p2t->priv;9798if (!(dvbdmxfeed->ts_type & TS_PACKET))99return 0;100if (buf[3] == 0xe0) // video PES do not have a length in TS101buf[4] = buf[5] = 0;102if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)103return dvbdmxfeed->cb.ts(buf, len, NULL, 0,104&dvbdmxfeed->feed.ts, DMX_OK);105else106return dvb_filter_pes2ts(p2t, buf, len, 1);107}108109static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)110{111struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;112113dvbdmxfeed->cb.ts(data, 188, NULL, 0,114&dvbdmxfeed->feed.ts, DMX_OK);115return 0;116}117118int av7110_av_start_record(struct av7110 *av7110, int av,119struct dvb_demux_feed *dvbdmxfeed)120{121int ret = 0;122struct dvb_demux *dvbdmx = dvbdmxfeed->demux;123124dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);125126if (av7110->playing || (av7110->rec_mode & av))127return -EBUSY;128av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);129dvbdmx->recording = 1;130av7110->rec_mode |= av;131132switch (av7110->rec_mode) {133case RP_AUDIO:134dvb_filter_pes2ts_init(&av7110->p2t[0],135dvbdmx->pesfilter[0]->pid,136dvb_filter_pes2ts_cb,137(void *) dvbdmx->pesfilter[0]);138ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);139break;140141case RP_VIDEO:142dvb_filter_pes2ts_init(&av7110->p2t[1],143dvbdmx->pesfilter[1]->pid,144dvb_filter_pes2ts_cb,145(void *) dvbdmx->pesfilter[1]);146ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);147break;148149case RP_AV:150dvb_filter_pes2ts_init(&av7110->p2t[0],151dvbdmx->pesfilter[0]->pid,152dvb_filter_pes2ts_cb,153(void *) dvbdmx->pesfilter[0]);154dvb_filter_pes2ts_init(&av7110->p2t[1],155dvbdmx->pesfilter[1]->pid,156dvb_filter_pes2ts_cb,157(void *) dvbdmx->pesfilter[1]);158ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);159break;160}161return ret;162}163164int av7110_av_start_play(struct av7110 *av7110, int av)165{166int ret = 0;167dprintk(2, "av7110:%p, \n", av7110);168169if (av7110->rec_mode)170return -EBUSY;171if (av7110->playing & av)172return -EBUSY;173174av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);175176if (av7110->playing == RP_NONE) {177av7110_ipack_reset(&av7110->ipack[0]);178av7110_ipack_reset(&av7110->ipack[1]);179}180181av7110->playing |= av;182switch (av7110->playing) {183case RP_AUDIO:184ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);185break;186case RP_VIDEO:187ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);188av7110->sinfo = 0;189break;190case RP_AV:191av7110->sinfo = 0;192ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);193break;194}195return ret;196}197198int av7110_av_stop(struct av7110 *av7110, int av)199{200int ret = 0;201dprintk(2, "av7110:%p, \n", av7110);202203if (!(av7110->playing & av) && !(av7110->rec_mode & av))204return 0;205av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);206if (av7110->playing) {207av7110->playing &= ~av;208switch (av7110->playing) {209case RP_AUDIO:210ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);211break;212case RP_VIDEO:213ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);214break;215case RP_NONE:216ret = av7110_set_vidmode(av7110, av7110->vidmode);217break;218}219} else {220av7110->rec_mode &= ~av;221switch (av7110->rec_mode) {222case RP_AUDIO:223ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);224break;225case RP_VIDEO:226ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);227break;228case RP_NONE:229break;230}231}232return ret;233}234235236int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)237{238int len;239u32 sync;240u16 blen;241242if (!dlen) {243wake_up(&buf->queue);244return -1;245}246while (1) {247len = dvb_ringbuffer_avail(buf);248if (len < 6) {249wake_up(&buf->queue);250return -1;251}252sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24;253sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;254sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;255sync |= DVB_RINGBUFFER_PEEK(buf, 3);256257if (((sync &~ 0x0f) == 0x000001e0) ||258((sync &~ 0x1f) == 0x000001c0) ||259(sync == 0x000001bd))260break;261printk("resync\n");262DVB_RINGBUFFER_SKIP(buf, 1);263}264blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8;265blen |= DVB_RINGBUFFER_PEEK(buf, 5);266blen += 6;267if (len < blen || blen > dlen) {268//printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);269wake_up(&buf->queue);270return -1;271}272273dvb_ringbuffer_read(buf, dest, (size_t) blen);274275dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",276(unsigned long) buf->pread, (unsigned long) buf->pwrite);277wake_up(&buf->queue);278return blen;279}280281282int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)283{284int err, vol, val, balance = 0;285286dprintk(2, "av7110:%p, \n", av7110);287288av7110->mixer.volume_left = volleft;289av7110->mixer.volume_right = volright;290291switch (av7110->adac_type) {292case DVB_ADAC_TI:293volleft = (volleft * 256) / 1036;294volright = (volright * 256) / 1036;295if (volleft > 0x3f)296volleft = 0x3f;297if (volright > 0x3f)298volright = 0x3f;299if ((err = SendDAC(av7110, 3, 0x80 + volleft)))300return err;301return SendDAC(av7110, 4, volright);302303case DVB_ADAC_CRYSTAL:304volleft = 127 - volleft / 2;305volright = 127 - volright / 2;306i2c_writereg(av7110, 0x20, 0x03, volleft);307i2c_writereg(av7110, 0x20, 0x04, volright);308return 0;309310case DVB_ADAC_MSP34x0:311vol = (volleft > volright) ? volleft : volright;312val = (vol * 0x73 / 255) << 8;313if (vol > 0)314balance = ((volright - volleft) * 127) / vol;315msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);316msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */317msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */318return 0;319320case DVB_ADAC_MSP34x5:321vol = (volleft > volright) ? volleft : volright;322val = (vol * 0x73 / 255) << 8;323if (vol > 0)324balance = ((volright - volleft) * 127) / vol;325msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);326msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */327return 0;328}329330return 0;331}332333int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)334{335int ret;336dprintk(2, "av7110:%p, \n", av7110);337338ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);339340if (!ret && !av7110->playing) {341ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],342av7110->pids[DMX_PES_AUDIO],343av7110->pids[DMX_PES_TELETEXT],3440, av7110->pids[DMX_PES_PCR]);345if (!ret)346ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);347}348return ret;349}350351352static enum av7110_video_mode sw2mode[16] = {353AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,354AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,355AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_NTSC,356AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,357AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,358AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,359AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,360AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_PAL,361};362363static int get_video_format(struct av7110 *av7110, u8 *buf, int count)364{365int i;366int hsize, vsize;367int sw;368u8 *p;369int ret = 0;370371dprintk(2, "av7110:%p, \n", av7110);372373if (av7110->sinfo)374return 0;375for (i = 7; i < count - 10; i++) {376p = buf + i;377if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)378continue;379p += 4;380hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);381vsize = ((p[1] &0x0F) << 8) | (p[2]);382sw = (p[3] & 0x0F);383ret = av7110_set_vidmode(av7110, sw2mode[sw]);384if (!ret) {385dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);386av7110->sinfo = 1;387}388break;389}390return ret;391}392393394/****************************************************************************395* I/O buffer management and control396****************************************************************************/397398static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,399const u8 *buf, unsigned long count)400{401unsigned long todo = count;402int free;403404while (todo > 0) {405if (dvb_ringbuffer_free(rbuf) < 2048) {406if (wait_event_interruptible(rbuf->queue,407(dvb_ringbuffer_free(rbuf) >= 2048)))408return count - todo;409}410free = dvb_ringbuffer_free(rbuf);411if (free > todo)412free = todo;413dvb_ringbuffer_write(rbuf, buf, free);414todo -= free;415buf += free;416}417418return count - todo;419}420421static void play_video_cb(u8 *buf, int count, void *priv)422{423struct av7110 *av7110 = (struct av7110 *) priv;424dprintk(2, "av7110:%p, \n", av7110);425426if ((buf[3] & 0xe0) == 0xe0) {427get_video_format(av7110, buf, count);428aux_ring_buffer_write(&av7110->avout, buf, count);429} else430aux_ring_buffer_write(&av7110->aout, buf, count);431}432433static void play_audio_cb(u8 *buf, int count, void *priv)434{435struct av7110 *av7110 = (struct av7110 *) priv;436dprintk(2, "av7110:%p, \n", av7110);437438aux_ring_buffer_write(&av7110->aout, buf, count);439}440441442#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)443444static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,445unsigned long count, int nonblock, int type)446{447struct dvb_ringbuffer *rb;448u8 *kb;449unsigned long todo = count;450451dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);452453rb = (type) ? &av7110->avout : &av7110->aout;454kb = av7110->kbuf[type];455456if (!kb)457return -ENOBUFS;458459if (nonblock && !FREE_COND_TS)460return -EWOULDBLOCK;461462while (todo >= TS_SIZE) {463if (!FREE_COND_TS) {464if (nonblock)465return count - todo;466if (wait_event_interruptible(rb->queue, FREE_COND_TS))467return count - todo;468}469if (copy_from_user(kb, buf, TS_SIZE))470return -EFAULT;471write_ts_to_decoder(av7110, type, kb, TS_SIZE);472todo -= TS_SIZE;473buf += TS_SIZE;474}475476return count - todo;477}478479480#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \481dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)482483static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,484unsigned long count, int nonblock, int type)485{486unsigned long todo = count, n;487dprintk(2, "av7110:%p, \n", av7110);488489if (!av7110->kbuf[type])490return -ENOBUFS;491492if (nonblock && !FREE_COND)493return -EWOULDBLOCK;494495while (todo > 0) {496if (!FREE_COND) {497if (nonblock)498return count - todo;499if (wait_event_interruptible(av7110->avout.queue,500FREE_COND))501return count - todo;502}503n = todo;504if (n > IPACKS * 2)505n = IPACKS * 2;506if (copy_from_user(av7110->kbuf[type], buf, n))507return -EFAULT;508av7110_ipack_instant_repack(av7110->kbuf[type], n,509&av7110->ipack[type]);510todo -= n;511buf += n;512}513return count - todo;514}515516static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,517unsigned long count, int nonblock, int type)518{519unsigned long todo = count, n;520dprintk(2, "av7110:%p, \n", av7110);521522if (!av7110->kbuf[type])523return -ENOBUFS;524525if (nonblock && !FREE_COND)526return -EWOULDBLOCK;527528while (todo > 0) {529if (!FREE_COND) {530if (nonblock)531return count - todo;532if (wait_event_interruptible(av7110->avout.queue,533FREE_COND))534return count - todo;535}536n = todo;537if (n > IPACKS * 2)538n = IPACKS * 2;539av7110_ipack_instant_repack(buf, n, &av7110->ipack[type]);540todo -= n;541buf += n;542}543return count - todo;544}545546static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,547unsigned long count, int nonblock, int type)548{549unsigned long todo = count, n;550dprintk(2, "av7110:%p, \n", av7110);551552if (!av7110->kbuf[type])553return -ENOBUFS;554if (nonblock && dvb_ringbuffer_free(&av7110->aout) < 20 * 1024)555return -EWOULDBLOCK;556557while (todo > 0) {558if (dvb_ringbuffer_free(&av7110->aout) < 20 * 1024) {559if (nonblock)560return count - todo;561if (wait_event_interruptible(av7110->aout.queue,562(dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)))563return count-todo;564}565n = todo;566if (n > IPACKS * 2)567n = IPACKS * 2;568if (copy_from_user(av7110->kbuf[type], buf, n))569return -EFAULT;570av7110_ipack_instant_repack(av7110->kbuf[type], n,571&av7110->ipack[type]);572todo -= n;573buf += n;574}575return count - todo;576}577578void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed)579{580memset(p->pes, 0, TS_SIZE);581p->counter = 0;582p->pos = 0;583p->frags = 0;584if (feed)585p->feed = feed;586}587588static void clear_p2t(struct av7110_p2t *p)589{590memset(p->pes, 0, TS_SIZE);591// p->counter = 0;592p->pos = 0;593p->frags = 0;594}595596597static int find_pes_header(u8 const *buf, long int length, int *frags)598{599int c = 0;600int found = 0;601602*frags = 0;603604while (c < length - 3 && !found) {605if (buf[c] == 0x00 && buf[c + 1] == 0x00 &&606buf[c + 2] == 0x01) {607switch ( buf[c + 3] ) {608case PROG_STREAM_MAP:609case PRIVATE_STREAM2:610case PROG_STREAM_DIR:611case ECM_STREAM :612case EMM_STREAM :613case PADDING_STREAM :614case DSM_CC_STREAM :615case ISO13522_STREAM:616case PRIVATE_STREAM1:617case AUDIO_STREAM_S ... AUDIO_STREAM_E:618case VIDEO_STREAM_S ... VIDEO_STREAM_E:619found = 1;620break;621622default:623c++;624break;625}626} else627c++;628}629if (c == length - 3 && !found) {630if (buf[length - 1] == 0x00)631*frags = 1;632if (buf[length - 2] == 0x00 &&633buf[length - 1] == 0x00)634*frags = 2;635if (buf[length - 3] == 0x00 &&636buf[length - 2] == 0x00 &&637buf[length - 1] == 0x01)638*frags = 3;639return -1;640}641642return c;643}644645void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p)646{647int c, c2, l, add;648int check, rest;649650c = 0;651c2 = 0;652if (p->frags){653check = 0;654switch(p->frags) {655case 1:656if (buf[c] == 0x00 && buf[c + 1] == 0x01) {657check = 1;658c += 2;659}660break;661case 2:662if (buf[c] == 0x01) {663check = 1;664c++;665}666break;667case 3:668check = 1;669}670if (check) {671switch (buf[c]) {672case PROG_STREAM_MAP:673case PRIVATE_STREAM2:674case PROG_STREAM_DIR:675case ECM_STREAM :676case EMM_STREAM :677case PADDING_STREAM :678case DSM_CC_STREAM :679case ISO13522_STREAM:680case PRIVATE_STREAM1:681case AUDIO_STREAM_S ... AUDIO_STREAM_E:682case VIDEO_STREAM_S ... VIDEO_STREAM_E:683p->pes[0] = 0x00;684p->pes[1] = 0x00;685p->pes[2] = 0x01;686p->pes[3] = buf[c];687p->pos = 4;688memcpy(p->pes + p->pos, buf + c, (TS_SIZE - 4) - p->pos);689c += (TS_SIZE - 4) - p->pos;690p_to_t(p->pes, (TS_SIZE - 4), pid, &p->counter, p->feed);691clear_p2t(p);692break;693694default:695c = 0;696break;697}698}699p->frags = 0;700}701702if (p->pos) {703c2 = find_pes_header(buf + c, length - c, &p->frags);704if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos)705l = c2+c;706else707l = (TS_SIZE - 4) - p->pos;708memcpy(p->pes + p->pos, buf, l);709c += l;710p->pos += l;711p_to_t(p->pes, p->pos, pid, &p->counter, p->feed);712clear_p2t(p);713}714715add = 0;716while (c < length) {717c2 = find_pes_header(buf + c + add, length - c - add, &p->frags);718if (c2 >= 0) {719c2 += c + add;720if (c2 > c){721p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed);722c = c2;723clear_p2t(p);724add = 0;725} else726add = 1;727} else {728l = length - c;729rest = l % (TS_SIZE - 4);730l -= rest;731p_to_t(buf + c, l, pid, &p->counter, p->feed);732memcpy(p->pes, buf + c + l, rest);733p->pos = rest;734c = length;735}736}737}738739740static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)741{742int i;743int c = 0;744int fill;745u8 tshead[4] = { 0x47, 0x00, 0x00, 0x10 };746747fill = (TS_SIZE - 4) - length;748if (pes_start)749tshead[1] = 0x40;750if (fill)751tshead[3] = 0x30;752tshead[1] |= (u8)((pid & 0x1F00) >> 8);753tshead[2] |= (u8)(pid & 0x00FF);754tshead[3] |= ((*counter)++ & 0x0F);755memcpy(buf, tshead, 4);756c += 4;757758if (fill) {759buf[4] = fill - 1;760c++;761if (fill > 1) {762buf[5] = 0x00;763c++;764}765for (i = 6; i < fill + 4; i++) {766buf[i] = 0xFF;767c++;768}769}770771return c;772}773774775static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,776struct dvb_demux_feed *feed)777{778int l, pes_start;779u8 obuf[TS_SIZE];780long c = 0;781782pes_start = 0;783if (length > 3 &&784buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)785switch (buf[3]) {786case PROG_STREAM_MAP:787case PRIVATE_STREAM2:788case PROG_STREAM_DIR:789case ECM_STREAM :790case EMM_STREAM :791case PADDING_STREAM :792case DSM_CC_STREAM :793case ISO13522_STREAM:794case PRIVATE_STREAM1:795case AUDIO_STREAM_S ... AUDIO_STREAM_E:796case VIDEO_STREAM_S ... VIDEO_STREAM_E:797pes_start = 1;798break;799800default:801break;802}803804while (c < length) {805memset(obuf, 0, TS_SIZE);806if (length - c >= (TS_SIZE - 4)){807l = write_ts_header2(pid, counter, pes_start,808obuf, (TS_SIZE - 4));809memcpy(obuf + l, buf + c, TS_SIZE - l);810c += TS_SIZE - l;811} else {812l = write_ts_header2(pid, counter, pes_start,813obuf, length - c);814memcpy(obuf + l, buf + c, TS_SIZE - l);815c = length;816}817feed->cb.ts(obuf, 188, NULL, 0, &feed->feed.ts, DMX_OK);818pes_start = 0;819}820}821822823static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)824{825struct ipack *ipack = &av7110->ipack[type];826827if (buf[1] & TRANS_ERROR) {828av7110_ipack_reset(ipack);829return -1;830}831832if (!(buf[3] & PAYLOAD))833return -1;834835if (buf[1] & PAY_START)836av7110_ipack_flush(ipack);837838if (buf[3] & ADAPT_FIELD) {839len -= buf[4] + 1;840buf += buf[4] + 1;841if (!len)842return 0;843}844845av7110_ipack_instant_repack(buf + 4, len - 4, ipack);846return 0;847}848849850int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)851{852struct dvb_demux *demux = feed->demux;853struct av7110 *av7110 = (struct av7110 *) demux->priv;854855dprintk(2, "av7110:%p, \n", av7110);856857if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)858return 0;859860switch (feed->pes_type) {861case 0:862if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)863return -EINVAL;864break;865case 1:866if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)867return -EINVAL;868break;869default:870return -1;871}872873return write_ts_to_decoder(av7110, feed->pes_type, buf, len);874}875876877878/******************************************************************************879* Video MPEG decoder events880******************************************************************************/881void dvb_video_add_event(struct av7110 *av7110, struct video_event *event)882{883struct dvb_video_events *events = &av7110->video_events;884int wp;885886spin_lock_bh(&events->lock);887888wp = (events->eventw + 1) % MAX_VIDEO_EVENT;889if (wp == events->eventr) {890events->overflow = 1;891events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;892}893894//FIXME: timestamp?895memcpy(&events->events[events->eventw], event, sizeof(struct video_event));896events->eventw = wp;897898spin_unlock_bh(&events->lock);899900wake_up_interruptible(&events->wait_queue);901}902903904static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags)905{906struct dvb_video_events *events = &av7110->video_events;907908if (events->overflow) {909events->overflow = 0;910return -EOVERFLOW;911}912if (events->eventw == events->eventr) {913int ret;914915if (flags & O_NONBLOCK)916return -EWOULDBLOCK;917918ret = wait_event_interruptible(events->wait_queue,919events->eventw != events->eventr);920if (ret < 0)921return ret;922}923924spin_lock_bh(&events->lock);925926memcpy(event, &events->events[events->eventr],927sizeof(struct video_event));928events->eventr = (events->eventr + 1) % MAX_VIDEO_EVENT;929930spin_unlock_bh(&events->lock);931932return 0;933}934935936/******************************************************************************937* DVB device file operations938******************************************************************************/939940static unsigned int dvb_video_poll(struct file *file, poll_table *wait)941{942struct dvb_device *dvbdev = file->private_data;943struct av7110 *av7110 = dvbdev->priv;944unsigned int mask = 0;945946dprintk(2, "av7110:%p, \n", av7110);947948if ((file->f_flags & O_ACCMODE) != O_RDONLY)949poll_wait(file, &av7110->avout.queue, wait);950951poll_wait(file, &av7110->video_events.wait_queue, wait);952953if (av7110->video_events.eventw != av7110->video_events.eventr)954mask = POLLPRI;955956if ((file->f_flags & O_ACCMODE) != O_RDONLY) {957if (av7110->playing) {958if (FREE_COND)959mask |= (POLLOUT | POLLWRNORM);960} else /* if not playing: may play if asked for */961mask |= (POLLOUT | POLLWRNORM);962}963964return mask;965}966967static ssize_t dvb_video_write(struct file *file, const char __user *buf,968size_t count, loff_t *ppos)969{970struct dvb_device *dvbdev = file->private_data;971struct av7110 *av7110 = dvbdev->priv;972unsigned char c;973974dprintk(2, "av7110:%p, \n", av7110);975976if ((file->f_flags & O_ACCMODE) == O_RDONLY)977return -EPERM;978979if (av7110->videostate.stream_source != VIDEO_SOURCE_MEMORY)980return -EPERM;981982if (get_user(c, buf))983return -EFAULT;984if (c == 0x47 && count % TS_SIZE == 0)985return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);986else987return dvb_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 1);988}989990static unsigned int dvb_audio_poll(struct file *file, poll_table *wait)991{992struct dvb_device *dvbdev = file->private_data;993struct av7110 *av7110 = dvbdev->priv;994unsigned int mask = 0;995996dprintk(2, "av7110:%p, \n", av7110);997998poll_wait(file, &av7110->aout.queue, wait);9991000if (av7110->playing) {1001if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)1002mask |= (POLLOUT | POLLWRNORM);1003} else /* if not playing: may play if asked for */1004mask = (POLLOUT | POLLWRNORM);10051006return mask;1007}10081009static ssize_t dvb_audio_write(struct file *file, const char __user *buf,1010size_t count, loff_t *ppos)1011{1012struct dvb_device *dvbdev = file->private_data;1013struct av7110 *av7110 = dvbdev->priv;1014unsigned char c;10151016dprintk(2, "av7110:%p, \n", av7110);10171018if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) {1019printk(KERN_ERR "not audio source memory\n");1020return -EPERM;1021}10221023if (get_user(c, buf))1024return -EFAULT;1025if (c == 0x47 && count % TS_SIZE == 0)1026return ts_play(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);1027else1028return dvb_aplay(av7110, buf, count, file->f_flags & O_NONBLOCK, 0);1029}10301031static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x00 };10321033#define MIN_IFRAME 40000010341035static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)1036{1037unsigned i, n;1038int progressive = 0;1039int match = 0;10401041dprintk(2, "av7110:%p, \n", av7110);10421043if (!(av7110->playing & RP_VIDEO)) {1044if (av7110_av_start_play(av7110, RP_VIDEO) < 0)1045return -EBUSY;1046}10471048/* search in buf for instances of 00 00 01 b5 1? */1049for (i = 0; i < len; i++) {1050unsigned char c;1051if (get_user(c, buf + i))1052return -EFAULT;1053if (match == 5) {1054progressive = c & 0x08;1055match = 0;1056}1057if (c == 0x00) {1058match = (match == 1 || match == 2) ? 2 : 1;1059continue;1060}1061switch (match++) {1062case 2: if (c == 0x01)1063continue;1064break;1065case 3: if (c == 0xb5)1066continue;1067break;1068case 4: if ((c & 0xf0) == 0x10)1069continue;1070break;1071}1072match = 0;1073}10741075/* setting n always > 1, fixes problems when playing stillframes1076consisting of I- and P-Frames */1077n = MIN_IFRAME / len + 1;10781079/* FIXME: nonblock? */1080dvb_play_kernel(av7110, iframe_header, sizeof(iframe_header), 0, 1);10811082for (i = 0; i < n; i++)1083dvb_play(av7110, buf, len, 0, 1);10841085av7110_ipack_flush(&av7110->ipack[1]);10861087if (progressive)1088return vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);1089else1090return 0;1091}109210931094static int dvb_video_ioctl(struct file *file,1095unsigned int cmd, void *parg)1096{1097struct dvb_device *dvbdev = file->private_data;1098struct av7110 *av7110 = dvbdev->priv;1099unsigned long arg = (unsigned long) parg;1100int ret = 0;11011102dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);11031104if ((file->f_flags & O_ACCMODE) == O_RDONLY) {1105if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&1106cmd != VIDEO_GET_SIZE ) {1107return -EPERM;1108}1109}11101111switch (cmd) {1112case VIDEO_STOP:1113av7110->videostate.play_state = VIDEO_STOPPED;1114if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)1115ret = av7110_av_stop(av7110, RP_VIDEO);1116else1117ret = vidcom(av7110, AV_VIDEO_CMD_STOP,1118av7110->videostate.video_blank ? 0 : 1);1119if (!ret)1120av7110->trickmode = TRICK_NONE;1121break;11221123case VIDEO_PLAY:1124av7110->trickmode = TRICK_NONE;1125if (av7110->videostate.play_state == VIDEO_FREEZED) {1126av7110->videostate.play_state = VIDEO_PLAYING;1127ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);1128if (ret)1129break;1130}1131if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {1132if (av7110->playing == RP_AV) {1133ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);1134if (ret)1135break;1136av7110->playing &= ~RP_VIDEO;1137}1138ret = av7110_av_start_play(av7110, RP_VIDEO);1139}1140if (!ret)1141ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);1142if (!ret)1143av7110->videostate.play_state = VIDEO_PLAYING;1144break;11451146case VIDEO_FREEZE:1147av7110->videostate.play_state = VIDEO_FREEZED;1148if (av7110->playing & RP_VIDEO)1149ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);1150else1151ret = vidcom(av7110, AV_VIDEO_CMD_FREEZE, 1);1152if (!ret)1153av7110->trickmode = TRICK_FREEZE;1154break;11551156case VIDEO_CONTINUE:1157if (av7110->playing & RP_VIDEO)1158ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);1159if (!ret)1160ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);1161if (!ret) {1162av7110->videostate.play_state = VIDEO_PLAYING;1163av7110->trickmode = TRICK_NONE;1164}1165break;11661167case VIDEO_SELECT_SOURCE:1168av7110->videostate.stream_source = (video_stream_source_t) arg;1169break;11701171case VIDEO_SET_BLANK:1172av7110->videostate.video_blank = (int) arg;1173break;11741175case VIDEO_GET_STATUS:1176memcpy(parg, &av7110->videostate, sizeof(struct video_status));1177break;11781179case VIDEO_GET_EVENT:1180ret = dvb_video_get_event(av7110, parg, file->f_flags);1181break;11821183case VIDEO_GET_SIZE:1184memcpy(parg, &av7110->video_size, sizeof(video_size_t));1185break;11861187case VIDEO_SET_DISPLAY_FORMAT:1188{1189video_displayformat_t format = (video_displayformat_t) arg;1190switch (format) {1191case VIDEO_PAN_SCAN:1192av7110->display_panscan = VID_PAN_SCAN_PREF;1193break;1194case VIDEO_LETTER_BOX:1195av7110->display_panscan = VID_VC_AND_PS_PREF;1196break;1197case VIDEO_CENTER_CUT_OUT:1198av7110->display_panscan = VID_CENTRE_CUT_PREF;1199break;1200default:1201ret = -EINVAL;1202}1203if (ret < 0)1204break;1205av7110->videostate.display_format = format;1206ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,12071, av7110->display_panscan);1208break;1209}12101211case VIDEO_SET_FORMAT:1212if (arg > 1) {1213ret = -EINVAL;1214break;1215}1216av7110->display_ar = arg;1217ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,12181, (u16) arg);1219break;12201221case VIDEO_STILLPICTURE:1222{1223struct video_still_picture *pic =1224(struct video_still_picture *) parg;1225av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;1226dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);1227ret = play_iframe(av7110, pic->iFrame, pic->size,1228file->f_flags & O_NONBLOCK);1229break;1230}12311232case VIDEO_FAST_FORWARD:1233//note: arg is ignored by firmware1234if (av7110->playing & RP_VIDEO)1235ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,1236__Scan_I, 2, AV_PES, 0);1237else1238ret = vidcom(av7110, AV_VIDEO_CMD_FFWD, arg);1239if (!ret) {1240av7110->trickmode = TRICK_FAST;1241av7110->videostate.play_state = VIDEO_PLAYING;1242}1243break;12441245case VIDEO_SLOWMOTION:1246if (av7110->playing&RP_VIDEO) {1247if (av7110->trickmode != TRICK_SLOW)1248ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);1249if (!ret)1250ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);1251} else {1252ret = vidcom(av7110, AV_VIDEO_CMD_PLAY, 0);1253if (!ret)1254ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 0);1255if (!ret)1256ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);1257}1258if (!ret) {1259av7110->trickmode = TRICK_SLOW;1260av7110->videostate.play_state = VIDEO_PLAYING;1261}1262break;12631264case VIDEO_GET_CAPABILITIES:1265*(int *)parg = VIDEO_CAP_MPEG1 | VIDEO_CAP_MPEG2 |1266VIDEO_CAP_SYS | VIDEO_CAP_PROG;1267break;12681269case VIDEO_CLEAR_BUFFER:1270dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);1271av7110_ipack_reset(&av7110->ipack[1]);1272if (av7110->playing == RP_AV) {1273ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,1274__Play, 2, AV_PES, 0);1275if (ret)1276break;1277if (av7110->trickmode == TRICK_FAST)1278ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,1279__Scan_I, 2, AV_PES, 0);1280if (av7110->trickmode == TRICK_SLOW) {1281ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,1282__Slow, 2, 0, 0);1283if (!ret)1284ret = vidcom(av7110, AV_VIDEO_CMD_SLOW, arg);1285}1286if (av7110->trickmode == TRICK_FREEZE)1287ret = vidcom(av7110, AV_VIDEO_CMD_STOP, 1);1288}1289break;12901291case VIDEO_SET_STREAMTYPE:1292break;12931294default:1295ret = -ENOIOCTLCMD;1296break;1297}12981299return ret;1300}13011302static int dvb_audio_ioctl(struct file *file,1303unsigned int cmd, void *parg)1304{1305struct dvb_device *dvbdev = file->private_data;1306struct av7110 *av7110 = dvbdev->priv;1307unsigned long arg = (unsigned long) parg;1308int ret = 0;13091310dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);13111312if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&1313(cmd != AUDIO_GET_STATUS))1314return -EPERM;13151316switch (cmd) {1317case AUDIO_STOP:1318if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)1319ret = av7110_av_stop(av7110, RP_AUDIO);1320else1321ret = audcom(av7110, AUDIO_CMD_MUTE);1322if (!ret)1323av7110->audiostate.play_state = AUDIO_STOPPED;1324break;13251326case AUDIO_PLAY:1327if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)1328ret = av7110_av_start_play(av7110, RP_AUDIO);1329if (!ret)1330ret = audcom(av7110, AUDIO_CMD_UNMUTE);1331if (!ret)1332av7110->audiostate.play_state = AUDIO_PLAYING;1333break;13341335case AUDIO_PAUSE:1336ret = audcom(av7110, AUDIO_CMD_MUTE);1337if (!ret)1338av7110->audiostate.play_state = AUDIO_PAUSED;1339break;13401341case AUDIO_CONTINUE:1342if (av7110->audiostate.play_state == AUDIO_PAUSED) {1343av7110->audiostate.play_state = AUDIO_PLAYING;1344ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);1345}1346break;13471348case AUDIO_SELECT_SOURCE:1349av7110->audiostate.stream_source = (audio_stream_source_t) arg;1350break;13511352case AUDIO_SET_MUTE:1353{1354ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);1355if (!ret)1356av7110->audiostate.mute_state = (int) arg;1357break;1358}13591360case AUDIO_SET_AV_SYNC:1361av7110->audiostate.AV_sync_state = (int) arg;1362ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);1363break;13641365case AUDIO_SET_BYPASS_MODE:1366if (FW_VERSION(av7110->arm_app) < 0x2621)1367ret = -EINVAL;1368av7110->audiostate.bypass_mode = (int)arg;1369break;13701371case AUDIO_CHANNEL_SELECT:1372av7110->audiostate.channel_select = (audio_channel_select_t) arg;1373switch(av7110->audiostate.channel_select) {1374case AUDIO_STEREO:1375ret = audcom(av7110, AUDIO_CMD_STEREO);1376if (!ret) {1377if (av7110->adac_type == DVB_ADAC_CRYSTAL)1378i2c_writereg(av7110, 0x20, 0x02, 0x49);1379else if (av7110->adac_type == DVB_ADAC_MSP34x5)1380msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220);1381}1382break;1383case AUDIO_MONO_LEFT:1384ret = audcom(av7110, AUDIO_CMD_MONO_L);1385if (!ret) {1386if (av7110->adac_type == DVB_ADAC_CRYSTAL)1387i2c_writereg(av7110, 0x20, 0x02, 0x4a);1388else if (av7110->adac_type == DVB_ADAC_MSP34x5)1389msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200);1390}1391break;1392case AUDIO_MONO_RIGHT:1393ret = audcom(av7110, AUDIO_CMD_MONO_R);1394if (!ret) {1395if (av7110->adac_type == DVB_ADAC_CRYSTAL)1396i2c_writereg(av7110, 0x20, 0x02, 0x45);1397else if (av7110->adac_type == DVB_ADAC_MSP34x5)1398msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210);1399}1400break;1401default:1402ret = -EINVAL;1403break;1404}1405break;14061407case AUDIO_GET_STATUS:1408memcpy(parg, &av7110->audiostate, sizeof(struct audio_status));1409break;14101411case AUDIO_GET_CAPABILITIES:1412if (FW_VERSION(av7110->arm_app) < 0x2621)1413*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_MP1 | AUDIO_CAP_MP2;1414else1415*(unsigned int *)parg = AUDIO_CAP_LPCM | AUDIO_CAP_DTS | AUDIO_CAP_AC3 |1416AUDIO_CAP_MP1 | AUDIO_CAP_MP2;1417break;14181419case AUDIO_CLEAR_BUFFER:1420dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);1421av7110_ipack_reset(&av7110->ipack[0]);1422if (av7110->playing == RP_AV)1423ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,1424__Play, 2, AV_PES, 0);1425break;14261427case AUDIO_SET_ID:1428break;14291430case AUDIO_SET_MIXER:1431{1432struct audio_mixer *amix = (struct audio_mixer *)parg;1433ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);1434break;1435}14361437case AUDIO_SET_STREAMTYPE:1438break;14391440default:1441ret = -ENOIOCTLCMD;1442}14431444return ret;1445}144614471448static int dvb_video_open(struct inode *inode, struct file *file)1449{1450struct dvb_device *dvbdev = file->private_data;1451struct av7110 *av7110 = dvbdev->priv;1452int err;14531454dprintk(2, "av7110:%p, \n", av7110);14551456if ((err = dvb_generic_open(inode, file)) < 0)1457return err;14581459if ((file->f_flags & O_ACCMODE) != O_RDONLY) {1460dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);1461dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);1462av7110->video_blank = 1;1463av7110->audiostate.AV_sync_state = 1;1464av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;14651466/* empty event queue */1467av7110->video_events.eventr = av7110->video_events.eventw = 0;1468}14691470return 0;1471}14721473static int dvb_video_release(struct inode *inode, struct file *file)1474{1475struct dvb_device *dvbdev = file->private_data;1476struct av7110 *av7110 = dvbdev->priv;14771478dprintk(2, "av7110:%p, \n", av7110);14791480if ((file->f_flags & O_ACCMODE) != O_RDONLY) {1481av7110_av_stop(av7110, RP_VIDEO);1482}14831484return dvb_generic_release(inode, file);1485}14861487static int dvb_audio_open(struct inode *inode, struct file *file)1488{1489struct dvb_device *dvbdev = file->private_data;1490struct av7110 *av7110 = dvbdev->priv;1491int err = dvb_generic_open(inode, file);14921493dprintk(2, "av7110:%p, \n", av7110);14941495if (err < 0)1496return err;1497dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);1498av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;1499return 0;1500}15011502static int dvb_audio_release(struct inode *inode, struct file *file)1503{1504struct dvb_device *dvbdev = file->private_data;1505struct av7110 *av7110 = dvbdev->priv;15061507dprintk(2, "av7110:%p, \n", av7110);15081509av7110_av_stop(av7110, RP_AUDIO);1510return dvb_generic_release(inode, file);1511}1512151315141515/******************************************************************************1516* driver registration1517******************************************************************************/15181519static const struct file_operations dvb_video_fops = {1520.owner = THIS_MODULE,1521.write = dvb_video_write,1522.unlocked_ioctl = dvb_generic_ioctl,1523.open = dvb_video_open,1524.release = dvb_video_release,1525.poll = dvb_video_poll,1526.llseek = noop_llseek,1527};15281529static struct dvb_device dvbdev_video = {1530.priv = NULL,1531.users = 6,1532.readers = 5, /* arbitrary */1533.writers = 1,1534.fops = &dvb_video_fops,1535.kernel_ioctl = dvb_video_ioctl,1536};15371538static const struct file_operations dvb_audio_fops = {1539.owner = THIS_MODULE,1540.write = dvb_audio_write,1541.unlocked_ioctl = dvb_generic_ioctl,1542.open = dvb_audio_open,1543.release = dvb_audio_release,1544.poll = dvb_audio_poll,1545.llseek = noop_llseek,1546};15471548static struct dvb_device dvbdev_audio = {1549.priv = NULL,1550.users = 1,1551.writers = 1,1552.fops = &dvb_audio_fops,1553.kernel_ioctl = dvb_audio_ioctl,1554};155515561557int av7110_av_register(struct av7110 *av7110)1558{1559av7110->audiostate.AV_sync_state = 0;1560av7110->audiostate.mute_state = 0;1561av7110->audiostate.play_state = AUDIO_STOPPED;1562av7110->audiostate.stream_source = AUDIO_SOURCE_DEMUX;1563av7110->audiostate.channel_select = AUDIO_STEREO;1564av7110->audiostate.bypass_mode = 0;15651566av7110->videostate.video_blank = 0;1567av7110->videostate.play_state = VIDEO_STOPPED;1568av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;1569av7110->videostate.video_format = VIDEO_FORMAT_4_3;1570av7110->videostate.display_format = VIDEO_LETTER_BOX;1571av7110->display_ar = VIDEO_FORMAT_4_3;1572av7110->display_panscan = VID_VC_AND_PS_PREF;15731574init_waitqueue_head(&av7110->video_events.wait_queue);1575spin_lock_init(&av7110->video_events.lock);1576av7110->video_events.eventw = av7110->video_events.eventr = 0;1577av7110->video_events.overflow = 0;1578memset(&av7110->video_size, 0, sizeof (video_size_t));15791580dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,1581&dvbdev_video, av7110, DVB_DEVICE_VIDEO);15821583dvb_register_device(&av7110->dvb_adapter, &av7110->audio_dev,1584&dvbdev_audio, av7110, DVB_DEVICE_AUDIO);15851586return 0;1587}15881589void av7110_av_unregister(struct av7110 *av7110)1590{1591dvb_unregister_device(av7110->audio_dev);1592dvb_unregister_device(av7110->video_dev);1593}15941595int av7110_av_init(struct av7110 *av7110)1596{1597void (*play[])(u8 *, int, void *) = { play_audio_cb, play_video_cb };1598int i, ret;15991600for (i = 0; i < 2; i++) {1601struct ipack *ipack = av7110->ipack + i;16021603ret = av7110_ipack_init(ipack, IPACKS, play[i]);1604if (ret < 0) {1605if (i)1606av7110_ipack_free(--ipack);1607goto out;1608}1609ipack->data = av7110;1610}16111612dvb_ringbuffer_init(&av7110->avout, av7110->iobuf, AVOUTLEN);1613dvb_ringbuffer_init(&av7110->aout, av7110->iobuf + AVOUTLEN, AOUTLEN);16141615av7110->kbuf[0] = (u8 *)(av7110->iobuf + AVOUTLEN + AOUTLEN + BMPLEN);1616av7110->kbuf[1] = av7110->kbuf[0] + 2 * IPACKS;1617out:1618return ret;1619}16201621void av7110_av_exit(struct av7110 *av7110)1622{1623av7110_ipack_free(&av7110->ipack[0]);1624av7110_ipack_free(&av7110->ipack[1]);1625}162616271628