/* * dvb_demux.c - DVB kernel demux API * * Copyright (C) 2000-2001 Ralph Metzler * & Marcus Metzler * for convergence integrated media GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #include #include #include #include #include "dvb_demux.h" LIST_HEAD(dmx_muxs); int dmx_register_demux(dmx_demux_t *demux) { struct list_head *pos, *head=&dmx_muxs; if (!(demux->id && demux->vendor && demux->model)) return -EINVAL; list_for_each(pos, head) { if (!strcmp(DMX_DIR_ENTRY(pos)->id, demux->id)) return -EEXIST; } demux->users=0; list_add(&(demux->reg_list), head); MOD_INC_USE_COUNT; return 0; } int dmx_unregister_demux(dmx_demux_t* demux) { struct list_head *pos, *head=&dmx_muxs; list_for_each(pos, head) { if (DMX_DIR_ENTRY(pos)==demux) { if (demux->users!=0) return -EINVAL; list_del(pos); MOD_DEC_USE_COUNT; return 0; } } return -ENODEV; } struct list_head *dmx_get_demuxes(void) { if (list_empty(&dmx_muxs)) return NULL; return &dmx_muxs; } /****************************************************************************** * static inlined helper functions ******************************************************************************/ static inline u16 section_length(const u8 *buf) { return 3+((buf[1]&0x0f)<<8)+buf[2]; } static inline u16 ts_pid(const u8 *buf) { return ((buf[1]&0x1f)<<8)+buf[2]; } static inline int payload(const u8 *tsp) { if (!(tsp[3]&0x10)) // no payload? return 0; if (tsp[3]&0x20) // adaptation field? return 184-1-tsp[4]; return 184; } /****************************************************************************** * Software filter functions ******************************************************************************/ static inline int DvbDmxSWFilterPayload(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) { int p, count, ccok; if (!(count=payload(buf))) return -1; p=188-count; ccok=((dvbdmxfeed->cc+1)&0x0f)==(buf[3]&0x0f) ? 1 : 0; dvbdmxfeed->cc=buf[3]&0x0f; /* if (!ccok) printk("missed packet!\n"); */ if (buf[1]&0x40) // PUSI ? dvbdmxfeed->peslen=0xfffa; dvbdmxfeed->peslen+=count; return dvbdmxfeed->cb.ts((u8 *)&buf[p], count, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); } static int DvbDmxSWFilterSectionFilter(dvb_demux_feed_t *dvbdmxfeed, dvb_demux_filter_t *dvbdmxfilter) { dmx_section_filter_t *filter=&dvbdmxfilter->filter; #if 0 int i; for (i=0; ifilter_mask[i]& (filter->filter_value[i]^dvbdmxfeed->secbuf[i])) return 0; #else u32 res; u32 *val=(u32 *)(filter->filter_value); u32 *mask=(u32 *)(filter->filter_mask); u32 *data=(u32 *)(dvbdmxfeed->secbuf); res=mask[0]&(val[0]^data[0]); if (res) return 0; res=mask[1]&(val[1]^data[1]); if (res) return 0; res=mask[2]&(val[2]^data[2]); if (res) return 0; res=mask[3]&(val[3]^data[3]); if (res) return 0; res=*(u16 *)(4+mask) & (*(u16 *)(4+val) ^ *(u16 *)(4+data)); if (res) return 0; #endif return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen, 0, 0, filter, DMX_OK); } static inline int DvbDmxSWFilterSectionFeed(dvb_demux_feed_t *dvbdmxfeed) { u8 *buf=dvbdmxfeed->secbuf; dvb_demux_filter_t *f; if (dvbdmxfeed->secbufp!=dvbdmxfeed->seclen) return -1; if (!dvbdmxfeed->feed.sec.is_filtering) return 0; if (!(f=dvbdmxfeed->filter)) return 0; do if (DvbDmxSWFilterSectionFilter(dvbdmxfeed, f)<0) return -1; while ((f=f->next) && dvbdmxfeed->feed.sec.is_filtering); dvbdmxfeed->secbufp=dvbdmxfeed->seclen=0; memset(buf, 0, DVB_DEMUX_MASK_MAX); return 0; } static inline int DvbDmxSWFilterSectionPacket(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) { int p, count; int ccok, rest; if (!(count=payload(buf))) return -1; p=188-count; ccok=((dvbdmxfeed->cc+1)&0x0f)==(buf[3]&0x0f) ? 1 : 0; dvbdmxfeed->cc=buf[3]&0x0f; if (buf[1]&0x40) { // PUSI set -- a section begins in this packet // offset to start of first section is in buf[p] if (buf[p] && ccok) { // rest of previous section? // did we have enough data in last packet to calc length? if (dvbdmxfeed->secbufp && dvbdmxfeed->secbufp<3) { memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p+1, 3-dvbdmxfeed->secbufp); dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf); } rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp; if (rest==buf[p] && dvbdmxfeed->seclen) { memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p+1, buf[p]); dvbdmxfeed->secbufp+=buf[p]; DvbDmxSWFilterSectionFeed(dvbdmxfeed); } } p+=buf[p]+1; // skip rest of last section count=188-p; while (count>0) { if ((count>2) && // enough data to determine sec length? ((dvbdmxfeed->seclen=section_length(buf+p))<=count)) { memcpy(dvbdmxfeed->secbuf, buf+p, dvbdmxfeed->seclen); dvbdmxfeed->secbufp=dvbdmxfeed->seclen; p+=dvbdmxfeed->seclen; count=188-p; DvbDmxSWFilterSectionFeed(dvbdmxfeed); // filling bytes until packet end? if (buf[p]==0xff) count=0; } else { // section continues to following ts block memcpy(dvbdmxfeed->secbuf, buf+p, count); dvbdmxfeed->secbufp+=count; count=0; } } } else { // section continued below if (!ccok) return -1; if (!dvbdmxfeed->secbufp) // any data in last ts packet? return -1; // did we have enough data in last packet to calc section length? if (dvbdmxfeed->secbufp<3) { memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, 3-dvbdmxfeed->secbufp); dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf); } rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp; if (rest<0) return -1; if (rest<=count) { // section completed in this ts block memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, rest); dvbdmxfeed->secbufp+=rest; DvbDmxSWFilterSectionFeed(dvbdmxfeed); } else { // section continues in following ts block memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, count); dvbdmxfeed->secbufp+=count; } } return 0; } static void DvbDmxSWFilterPacketType(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf) { switch(dvbdmxfeed->type) { case DMX_TYPE_TS: if (!dvbdmxfeed->feed.ts.is_filtering) break; if (dvbdmxfeed->ts_type & TS_PACKET) { if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) DvbDmxSWFilterPayload(dvbdmxfeed, buf); else dvbdmxfeed->cb.ts((u8 *)buf, 188, 0, 0, &dvbdmxfeed->feed.ts, DMX_OK); } if (dvbdmxfeed->ts_type & TS_DECODER) if (dvbdmxfeed->demux->write_to_decoder) dvbdmxfeed->demux-> write_to_decoder(dvbdmxfeed, (u8 *)buf, 188); break; case DMX_TYPE_SEC: if (!dvbdmxfeed->feed.sec.is_filtering) break; if (DvbDmxSWFilterSectionPacket(dvbdmxfeed, buf)<0) dvbdmxfeed->seclen=dvbdmxfeed->secbufp=0; break; default: break; } } void inline DvbDmxSWFilterPacket(dvb_demux_t *dvbdmx, const u8 *buf) { dvb_demux_feed_t *dvbdmxfeed; if (!(dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)])) return; DvbDmxSWFilterPacketType(dvbdmxfeed, buf); } void DvbDmxSWFilterPackets(dvb_demux_t *dvbdmx, const u8 *buf, int count) { dvb_demux_feed_t *dvbdmxfeed; for (; count>0; count--, buf+=188) if ((dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)])) DvbDmxSWFilterPacketType(dvbdmxfeed, buf); } static inline void DvbDmxSWFilter(dvb_demux_t *dvbdmx, const u8 *buf, size_t count) { int p=0,i, j; if ((i=dvbdmx->tsbufp)) { if (count<(j=188-i)) { memcpy(&dvbdmx->tsbuf[i], buf, count); dvbdmx->tsbufp+=count; return; } memcpy(&dvbdmx->tsbuf[i], buf, j); DvbDmxSWFilterPacket(dvbdmx, dvbdmx->tsbuf); dvbdmx->tsbufp=0; p+=j; } while (p=188) { DvbDmxSWFilterPacket(dvbdmx, buf+p); p+=188; } else { i=count-p; memcpy(dvbdmx->tsbuf, buf+p, i); dvbdmx->tsbufp=i; return; } } else p++; } } /****************************************************************************** ****************************************************************************** * DVB DEMUX API LEVEL FUNCTIONS ****************************************************************************** ******************************************************************************/ static dvb_demux_filter_t * DvbDmxFilterAlloc(dvb_demux_t *dvbdmx) { int i; for (i=0; ifilter[i].state==DMX_STATE_FREE) break; if (i==DVB_DEMUX_FILTER_MAX) return 0; dvbdmx->filter[i].state=DMX_STATE_ALLOCATED; return &dvbdmx->filter[i]; } static dvb_demux_feed_t * DvbDmxFeedAlloc(dvb_demux_t *dvbdmx) { int i; for (i=0; ifeed[i].state==DMX_STATE_FREE) break; if (i==DVB_DEMUX_FEED_MAX) return 0; dvbdmx->feed[i].state=DMX_STATE_ALLOCATED; return &dvbdmx->feed[i]; } /****************************************************************************** * dmx_ts_feed API calls ******************************************************************************/ static int dmx_ts_feed_set_type(dmx_ts_feed_t *feed, int type, dmx_ts_pes_t pes_type) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; dvbdmxfeed->ts_type=type; dvbdmxfeed->pes_type=pes_type; if (dvbdmxfeed->ts_type & TS_DECODER) { if (pes_type >= DMX_TS_PES_OTHER) return -EINVAL; if (dvbdmx->pesfilter[pes_type] && (dvbdmx->pesfilter[pes_type]!=dvbdmxfeed)) return -EINVAL; dvbdmx->pesfilter[pes_type]=dvbdmxfeed; //printk("pids[%d]=%04x\n", pes_type, dvbdmxfeed->pid); dvbdmx->pids[pes_type]=dvbdmxfeed->pid; } return 0; } static int dmx_ts_feed_set(struct dmx_ts_feed_s* feed, __u16 pid, size_t callback_length, size_t circular_buffer_size, int descramble, struct timespec timeout ) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; if (pid>0x1fff) return -EINVAL; if (dvbdmxfeed->pid!=0xffff) { if (dvbdmxfeed->pid<=0x1fff) dvbdmx->pid2feed[dvbdmxfeed->pid]=0; dvbdmxfeed->pid=0xffff; } if (dvbdmx->pid2feed[pid]) return -EBUSY; dvbdmx->pid2feed[pid]=dvbdmxfeed; dvbdmxfeed->pid=pid; dvbdmxfeed->buffer_size=circular_buffer_size; dvbdmxfeed->descramble=descramble; dvbdmxfeed->timeout=timeout; dvbdmxfeed->cb_length=callback_length; dvbdmxfeed->ts_type=TS_PACKET; if (dvbdmxfeed->descramble) return -ENOSYS; if (dvbdmxfeed->buffer_size) { dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); if (!dvbdmxfeed->buffer) return -ENOMEM; } dvbdmxfeed->state=DMX_STATE_READY; return 0; } static int dmx_ts_feed_start_filtering(struct dmx_ts_feed_s* feed) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; int ret; if (dvbdmxfeed->state!=DMX_STATE_READY) return -EINVAL; if (dvbdmxfeed->type!=DMX_TYPE_TS) return -EINVAL; if (!dvbdmx->start_feed) return -1; ret=dvbdmx->start_feed(dvbdmxfeed); if (ret<0) return ret; feed->is_filtering=1; dvbdmxfeed->state=DMX_STATE_GO; return 0; } static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; int ret; //printk ("function : %s\n", __FUNCTION__); if (dvbdmxfeed->statestop_feed) return -1; ret=dvbdmx->stop_feed(dvbdmxfeed); feed->is_filtering=0; dvbdmxfeed->state=DMX_STATE_ALLOCATED; return ret; } static int dvbdmx_allocate_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t **feed, dmx_ts_cb callback) { dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; dvb_demux_feed_t *dvbdmxfeed; if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx))) return -EBUSY; dvbdmxfeed->type=DMX_TYPE_TS; dvbdmxfeed->cb.ts=callback; dvbdmxfeed->demux=dvbdmx; dvbdmxfeed->pid=0xffff; dvbdmxfeed->peslen=0xfffa; (*feed)=&dvbdmxfeed->feed.ts; (*feed)->is_filtering=0; (*feed)->parent=demux; (*feed)->priv=0; (*feed)->set=dmx_ts_feed_set; (*feed)->set_type=dmx_ts_feed_set_type; (*feed)->start_filtering=dmx_ts_feed_start_filtering; (*feed)->stop_filtering=dmx_ts_feed_stop_filtering; if (!(dvbdmxfeed->filter=DvbDmxFilterAlloc(dvbdmx))) { dvbdmxfeed->state=DMX_STATE_FREE; return -EBUSY; } dvbdmxfeed->filter->type=DMX_TYPE_TS; dvbdmxfeed->filter->feed=dvbdmxfeed; dvbdmxfeed->filter->state=DMX_STATE_READY; return 0; } static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; if (dvbdmxfeed->state==DMX_STATE_FREE) return -EINVAL; if (dvbdmxfeed->buffer) { vfree(dvbdmxfeed->buffer); dvbdmxfeed->buffer=0; } dvbdmxfeed->state=DMX_STATE_FREE; dvbdmxfeed->filter->state=DMX_STATE_FREE; if (dvbdmxfeed->pid!=0xffff) { if (dvbdmxfeed->pid<=0x1fff) dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; dvbdmxfeed->pid=0xffff; } return 0; } /****************************************************************************** * dmx_pes_feed API calls ******************************************************************************/ /* static int dmx_pes_feed_set(struct dmx_pes_feed_s* feed, __u16 pid, size_t circular_buffer_size, int descramble, struct timespec timeout) { return 0; } static int dmx_pes_feed_start_filtering(struct dmx_pes_feed_s* feed) { return 0; } static int dmx_pes_feed_stop_filtering(struct dmx_pes_feed_s* feed) { return 0; } */ static int dvbdmx_allocate_pes_feed(dmx_demux_t *demux, dmx_pes_feed_t **feed, dmx_pes_cb callback) { return 0; } static int dvbdmx_release_pes_feed(dmx_demux_t *demux, dmx_pes_feed_t *feed) { return 0; } /****************************************************************************** * dmx_section_feed API calls ******************************************************************************/ static int dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed, dmx_section_filter_t** filter) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdemux=dvbdmxfeed->demux; dvb_demux_filter_t *dvbdmxfilter; dvbdmxfilter=DvbDmxFilterAlloc(dvbdemux); if (!dvbdmxfilter) return -ENOSPC; *filter=&dvbdmxfilter->filter; (*filter)->parent=feed; (*filter)->priv=0; dvbdmxfilter->feed=dvbdmxfeed; dvbdmxfilter->pid=dvbdmxfeed->pid; dvbdmxfilter->type=DMX_TYPE_SEC; dvbdmxfilter->state=DMX_STATE_READY; dvbdmxfilter->next=dvbdmxfeed->filter; dvbdmxfeed->filter=dvbdmxfilter; return 0; } static int dmx_section_feed_set(struct dmx_section_feed_s* feed, __u16 pid, size_t circular_buffer_size, int descramble, int check_crc) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; //printk ("function : %s PID %04x\n", __FUNCTION__, pid); if (pid>0x1fff) return -EINVAL; if (dvbdmxfeed->pid!=0xffff) { dvbdmx->pid2feed[dvbdmxfeed->pid]=0; dvbdmxfeed->pid=0xffff; } if (dvbdmx->pid2feed[pid]) return -EBUSY; dvbdmx->pid2feed[pid]=dvbdmxfeed; dvbdmxfeed->pid=pid; dvbdmxfeed->buffer_size=circular_buffer_size; dvbdmxfeed->descramble=descramble; if (dvbdmxfeed->descramble) return -ENOSYS; dvbdmxfeed->check_crc=check_crc; dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); if (!dvbdmxfeed->buffer) return -ENOMEM; dvbdmxfeed->state=DMX_STATE_READY; return 0; } static int dmx_section_feed_start_filtering(dmx_section_feed_t *feed) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; int ret; if (feed->is_filtering) return -EBUSY; if (!dvbdmxfeed->filter) return -EINVAL; dvbdmxfeed->secbufp=0; dvbdmxfeed->seclen=0; if (!dvbdmx->start_feed) return -1; ret=dvbdmx->start_feed(dvbdmxfeed); if (ret<0) return ret; feed->is_filtering=1; dvbdmxfeed->state=DMX_STATE_GO; return 0; } static int dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; dvb_demux_t *dvbdmx=dvbdmxfeed->demux; int ret; if (!dvbdmx->stop_feed) return -1; ret=dvbdmx->stop_feed(dvbdmxfeed); dvbdmxfeed->state=DMX_STATE_READY; feed->is_filtering=0; return ret; } static int dmx_section_feed_release_filter(dmx_section_feed_t *feed, dmx_section_filter_t* filter) { dvb_demux_filter_t *dvbdmxfilter=(dvb_demux_filter_t *) filter, *f; dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; if (dvbdmxfilter->feed!=dvbdmxfeed) return -EINVAL; if (feed->is_filtering) feed->stop_filtering(feed); //return -EBUSY; f=dvbdmxfeed->filter; if (f==dvbdmxfilter) dvbdmxfeed->filter=dvbdmxfilter->next; else { while(f->next!=dvbdmxfilter) f=f->next; f->next=f->next->next; } dvbdmxfilter->state=DMX_STATE_FREE; return 0; } static int dvbdmx_allocate_section_feed(dmx_demux_t *demux, dmx_section_feed_t **feed, dmx_section_cb callback) { dvb_demux_t *dvbdmx=(dvb_demux_t *) demux; dvb_demux_feed_t *dvbdmxfeed; if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx))) return -EBUSY; dvbdmxfeed->type=DMX_TYPE_SEC; dvbdmxfeed->cb.sec=callback; dvbdmxfeed->demux=dvbdmx; dvbdmxfeed->pid=0xffff; dvbdmxfeed->secbufp=0; dvbdmxfeed->filter=0; (*feed)=&dvbdmxfeed->feed.sec; (*feed)->is_filtering=0; (*feed)->parent=demux; (*feed)->priv=0; (*feed)->set=dmx_section_feed_set; (*feed)->allocate_filter=dmx_section_feed_allocate_filter; (*feed)->release_filter=dmx_section_feed_release_filter; (*feed)->start_filtering=dmx_section_feed_start_filtering; (*feed)->stop_filtering=dmx_section_feed_stop_filtering; return 0; } static int dvbdmx_release_section_feed(dmx_demux_t *demux, dmx_section_feed_t *feed) { dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed; if (dvbdmxfeed->state==DMX_STATE_FREE) return -EINVAL; if (dvbdmxfeed->buffer) { vfree(dvbdmxfeed->buffer); dvbdmxfeed->buffer=0; } dvbdmxfeed->state=DMX_STATE_FREE; dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; if (dvbdmxfeed->pid!=0xffff) dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; return 0; } /****************************************************************************** * dvb_demux kernel data API calls ******************************************************************************/ static int dvbdmx_open(dmx_demux_t *demux) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; if (dvbdemux->users>=MAX_DVB_DEMUX_USERS) return -EUSERS; dvbdemux->users++; return 0; } static int dvbdmx_close(struct dmx_demux_s *demux) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; if (dvbdemux->users==0) return -ENODEV; dvbdemux->users--; //FIXME: release any unneeded resources if users==0 return 0; } static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; if ((!demux->frontend) || (demux->frontend->source!=DMX_MEMORY_FE)) return -EINVAL; DvbDmxSWFilter(dvbdemux, buf, count); return count; } static int dvbdmx_add_frontend(dmx_demux_t *demux, dmx_frontend_t *frontend) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; struct list_head *pos, *head=&dvbdemux->frontend_list; //printk ("function : %s\n", __FUNCTION__); if (!(frontend->id && frontend->vendor && frontend->model)) return -EINVAL; list_for_each(pos, head) { if (!strcmp(DMX_FE_ENTRY(pos)->id, frontend->id)) return -EEXIST; } list_add(&(frontend->connectivity_list), head); return 0; } static int dvbdmx_remove_frontend(dmx_demux_t *demux, dmx_frontend_t *frontend) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; struct list_head *pos, *head=&dvbdemux->frontend_list; list_for_each(pos, head) { if (DMX_FE_ENTRY(pos)==frontend) { list_del(pos); return 0; } } return -ENODEV; } static struct list_head * dvbdmx_get_frontends(dmx_demux_t *demux) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; if (list_empty(&dvbdemux->frontend_list)) return NULL; return &dvbdemux->frontend_list; } static int dvbdmx_connect_frontend(dmx_demux_t *demux, dmx_frontend_t *frontend) { if (demux->frontend) return -EINVAL; demux->frontend=frontend; return 0; } static int dvbdmx_disconnect_frontend(dmx_demux_t *demux) { demux->frontend=NULL; return 0; } static int dvbdmx_get_pes_pids(dmx_demux_t *demux, __u16 *pids) { dvb_demux_t *dvbdemux=(dvb_demux_t *) demux; memcpy(pids, dvbdemux->pids, 5*sizeof(__u16)); return 0; } int DvbDmxInit(dvb_demux_t *dvbdemux) { int i; dmx_demux_t *dmx=&dvbdemux->dmx; dvbdemux->users=0; dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(dvb_demux_filter_t)); if (!dvbdemux->filter) return -ENOMEM; for (i=0; ifilter[i].state=DMX_STATE_FREE; dvbdemux->filter[i].index=i; } for (i=0; ifeed[i].state=DMX_STATE_FREE; dvbdemux->frontend_list.next= dvbdemux->frontend_list.prev= &dvbdemux->frontend_list; for (i=0; ipesfilter[i]=NULL; dvbdemux->pids[i]=0xffff; } dvbdemux->playing=dvbdemux->recording=0; memset(dvbdemux->pid2feed, 0, 0x2000*sizeof(dvb_demux_feed_t *)); dvbdemux->tsbufp=0; dmx->frontend=0; dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list; dmx->priv=(void *) dvbdemux; //dmx->users=0; // reset in dmx_register_demux() dmx->open=dvbdmx_open; dmx->close=dvbdmx_close; dmx->write=dvbdmx_write; dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed; dmx->release_ts_feed=dvbdmx_release_ts_feed; dmx->allocate_pes_feed=dvbdmx_allocate_pes_feed; dmx->release_pes_feed=dvbdmx_release_pes_feed; dmx->allocate_section_feed=dvbdmx_allocate_section_feed; dmx->release_section_feed=dvbdmx_release_section_feed; dmx->descramble_mac_address=NULL; dmx->descramble_section_payload=NULL; dmx->add_frontend=dvbdmx_add_frontend; dmx->remove_frontend=dvbdmx_remove_frontend; dmx->get_frontends=dvbdmx_get_frontends; dmx->connect_frontend=dvbdmx_connect_frontend; dmx->disconnect_frontend=dvbdmx_disconnect_frontend; dmx->get_pes_pids=dvbdmx_get_pes_pids; if (dmx_register_demux(dmx)<0) return -1; //if (dmx->open(dmx)<0) // return -1; return 0; } int DvbDmxRelease(dvb_demux_t *dvbdemux) { dmx_demux_t *dmx=&dvbdemux->dmx; dmx_unregister_demux(dmx); if (dvbdemux->filter) vfree(dvbdemux->filter); return 0; } /* * Local variables: * c-indent-level: 8 * c-brace-imaginary-offset: 0 * c-brace-offset: -8 * c-argdecl-indent: 8 * c-label-offset: -8 * c-continued-statement-offset: 8 * c-continued-brace-offset: 0 * indent-tabs-mode: nil * tab-width: 8 * End: */