Annotation of margi2/dvb_demux.c, revision 1.3
1.1 mocm 1: /*
2: * dvb_demux.c - DVB kernel demux API
3: *
1.3 ! mocm 4: * Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
! 5: * & Marcus Metzler <marcus@convergence.de>
! 6: * for convergence integrated media GmbH
1.1 mocm 7: *
8: * This program is free software; you can redistribute it and/or
9: * modify it under the terms of the GNU Lesser General Public License
10: * as published by the Free Software Foundation; either version 2.1
11: * of the License, or (at your option) any later version.
12: *
13: * This program is distributed in the hope that it will be useful,
14: * but WITHOUT ANY WARRANTY; without even the implied warranty of
15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: * GNU General Public License for more details.
17: *
18: * You should have received a copy of the GNU Lesser General Public License
19: * along with this program; if not, write to the Free Software
20: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21: *
22: */
23:
24: #include <linux/vmalloc.h>
25: #include <linux/module.h>
26: #include <linux/poll.h>
27: #include <asm/uaccess.h>
28:
29: #include "dvb_demux.h"
30:
31: LIST_HEAD(dmx_muxs);
32:
33: int dmx_register_demux(dmx_demux_t *demux)
34: {
35: struct list_head *pos, *head=&dmx_muxs;
36:
37: if (!(demux->id && demux->vendor && demux->model))
38: return -EINVAL;
39: list_for_each(pos, head)
40: {
41: if (!strcmp(DMX_DIR_ENTRY(pos)->id, demux->id))
42: return -EEXIST;
43: }
44:
45: demux->users=0;
46: list_add(&(demux->reg_list), head);
47: MOD_INC_USE_COUNT;
48: return 0;
49: }
50:
51: int dmx_unregister_demux(dmx_demux_t* demux)
52: {
53: struct list_head *pos, *head=&dmx_muxs;
54:
55: list_for_each(pos, head)
56: {
57: if (DMX_DIR_ENTRY(pos)==demux)
58: {
59: if (demux->users!=0)
60: return -EINVAL;
61: list_del(pos);
62: MOD_DEC_USE_COUNT;
63: return 0;
64: }
65: }
66: return -ENODEV;
67: }
68:
69:
70: struct list_head *dmx_get_demuxes(void)
71: {
72: if (list_empty(&dmx_muxs))
73: return NULL;
74:
75: return &dmx_muxs;
76: }
77:
78: /******************************************************************************
79: * static inlined helper functions
80: ******************************************************************************/
81:
82: static inline u16
83: section_length(const u8 *buf)
84: {
1.2 mocm 85: return 3+((buf[1]&0x0f)<<8)+buf[2];
1.1 mocm 86: }
87:
88: static inline u16
89: ts_pid(const u8 *buf)
90: {
1.2 mocm 91: return ((buf[1]&0x1f)<<8)+buf[2];
1.1 mocm 92: }
93:
94: static inline int
1.2 mocm 95: payload(const u8 *tsp)
1.1 mocm 96: {
97: if (!(tsp[3]&0x10)) // no payload?
98: return 0;
1.2 mocm 99: if (tsp[3]&0x20) // adaptation field?
100: return 184-1-tsp[4];
101: return 184;
1.1 mocm 102: }
103:
104: /******************************************************************************
105: * Software filter functions
106: ******************************************************************************/
107:
108: static inline int
109: DvbDmxSWFilterPayload(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf)
110: {
1.2 mocm 111: int p, count, ccok;
1.1 mocm 112:
1.2 mocm 113: if (!(count=payload(buf)))
1.1 mocm 114: return -1;
1.2 mocm 115: p=188-count;
1.1 mocm 116: ccok=((dvbdmxfeed->cc+1)&0x0f)==(buf[3]&0x0f) ? 1 : 0;
117: dvbdmxfeed->cc=buf[3]&0x0f;
1.2 mocm 118: /*
1.1 mocm 119: if (!ccok)
120: printk("missed packet!\n");
121: */
1.2 mocm 122: if (buf[1]&0x40) // PUSI ?
1.1 mocm 123: dvbdmxfeed->peslen=0xfffa;
124: dvbdmxfeed->peslen+=count;
125:
126: return dvbdmxfeed->cb.ts((u8 *)&buf[p], count, 0, 0,
127: &dvbdmxfeed->feed.ts, DMX_OK);
128: }
129:
130:
131: static int
132: DvbDmxSWFilterSectionFilter(dvb_demux_feed_t *dvbdmxfeed,
133: dvb_demux_filter_t *dvbdmxfilter)
134: {
135: dmx_section_filter_t *filter=&dvbdmxfilter->filter;
136: #if 0
137: int i;
138:
139: for (i=0; i<DVB_DEMUX_MASK_MAX; i++)
140: if (filter->filter_mask[i]&
141: (filter->filter_value[i]^dvbdmxfeed->secbuf[i]))
142: return 0;
143: #else
144: u32 res;
145: u32 *val=(u32 *)(filter->filter_value);
146: u32 *mask=(u32 *)(filter->filter_mask);
147: u32 *data=(u32 *)(dvbdmxfeed->secbuf);
148:
149: res=mask[0]&(val[0]^data[0]);
150: if (res) return 0;
151:
152: res=mask[1]&(val[1]^data[1]);
153: if (res) return 0;
154:
155: res=mask[2]&(val[2]^data[2]);
156: if (res) return 0;
157:
158: res=mask[3]&(val[3]^data[3]);
159: if (res) return 0;
160:
161: res=*(u16 *)(4+mask) & (*(u16 *)(4+val) ^ *(u16 *)(4+data));
162: if (res) return 0;
163: #endif
164:
165: return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen,
166: 0, 0, filter, DMX_OK);
167: }
168:
169: static inline int
170: DvbDmxSWFilterSectionFeed(dvb_demux_feed_t *dvbdmxfeed)
171: {
172: u8 *buf=dvbdmxfeed->secbuf;
173: dvb_demux_filter_t *f;
174:
175: if (dvbdmxfeed->secbufp!=dvbdmxfeed->seclen)
176: return -1;
177: if (!dvbdmxfeed->feed.sec.is_filtering)
178: return 0;
179: if (!(f=dvbdmxfeed->filter))
180: return 0;
181: do
182: if (DvbDmxSWFilterSectionFilter(dvbdmxfeed, f)<0)
183: return -1;
184: while ((f=f->next) && dvbdmxfeed->feed.sec.is_filtering);
185:
186: dvbdmxfeed->secbufp=dvbdmxfeed->seclen=0;
187: memset(buf, 0, DVB_DEMUX_MASK_MAX);
188: return 0;
189: }
190:
191: static inline int
192: DvbDmxSWFilterSectionPacket(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf)
193: {
1.2 mocm 194: int p, count;
195: int ccok, rest;
1.1 mocm 196:
1.2 mocm 197: if (!(count=payload(buf)))
1.1 mocm 198: return -1;
1.2 mocm 199: p=188-count;
1.1 mocm 200:
1.2 mocm 201: ccok=((dvbdmxfeed->cc+1)&0x0f)==(buf[3]&0x0f) ? 1 : 0;
202: dvbdmxfeed->cc=buf[3]&0x0f;
1.1 mocm 203:
1.2 mocm 204: if (buf[1]&0x40) { // PUSI set -- a section begins in this packet
205: // offset to start of first section is in buf[p]
1.1 mocm 206:
1.2 mocm 207: if (buf[p] && ccok) { // rest of previous section?
1.1 mocm 208:
1.2 mocm 209: // did we have enough data in last packet to calc length?
210: if (dvbdmxfeed->secbufp && dvbdmxfeed->secbufp<3) {
211: memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp,
212: buf+p+1,
213: 3-dvbdmxfeed->secbufp);
214: dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf);
215: }
1.1 mocm 216: rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp;
217: if (rest==buf[p] && dvbdmxfeed->seclen) {
218: memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp,
219: buf+p+1, buf[p]);
220: dvbdmxfeed->secbufp+=buf[p];
221: DvbDmxSWFilterSectionFeed(dvbdmxfeed);
222: }
223: }
1.2 mocm 224: p+=buf[p]+1; // skip rest of last section
225: count=188-p;
1.1 mocm 226: while (count>0) {
1.2 mocm 227: if ((count>2) && // enough data to determine sec length?
1.1 mocm 228: ((dvbdmxfeed->seclen=section_length(buf+p))<=count)) {
229: memcpy(dvbdmxfeed->secbuf, buf+p,
230: dvbdmxfeed->seclen);
231: dvbdmxfeed->secbufp=dvbdmxfeed->seclen;
232: p+=dvbdmxfeed->seclen;
1.2 mocm 233: count=188-p;
1.1 mocm 234: DvbDmxSWFilterSectionFeed(dvbdmxfeed);
1.2 mocm 235:
236: // filling bytes until packet end?
237: if (buf[p]==0xff)
238: count=0;
239: } else { // section continues to following ts block
1.1 mocm 240: memcpy(dvbdmxfeed->secbuf, buf+p, count);
1.2 mocm 241: dvbdmxfeed->secbufp+=count;
1.1 mocm 242: count=0;
243: }
244: }
1.2 mocm 245: } else { // section continued below
1.1 mocm 246: if (!ccok)
247: return -1;
1.2 mocm 248: if (!dvbdmxfeed->secbufp) // any data in last ts packet?
249: return -1;
250: // did we have enough data in last packet to calc section length?
1.1 mocm 251: if (dvbdmxfeed->secbufp<3) {
1.2 mocm 252: memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p,
253: 3-dvbdmxfeed->secbufp);
1.1 mocm 254: dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf);
255: }
256: rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp;
1.2 mocm 257: if (rest<0)
1.1 mocm 258: return -1;
1.2 mocm 259: if (rest<=count) { // section completed in this ts block
260: memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, rest);
261: dvbdmxfeed->secbufp+=rest;
262: DvbDmxSWFilterSectionFeed(dvbdmxfeed);
263: } else { // section continues in following ts block
264: memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, count);
265: dvbdmxfeed->secbufp+=count;
266: }
267:
1.1 mocm 268: }
269: return 0;
270: }
271:
272: static void
273: DvbDmxSWFilterPacketType(dvb_demux_feed_t *dvbdmxfeed, const u8 *buf)
274: {
275: switch(dvbdmxfeed->type) {
276: case DMX_TYPE_TS:
277: if (!dvbdmxfeed->feed.ts.is_filtering)
278: break;
279: if (dvbdmxfeed->ts_type & TS_PACKET) {
280: if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
281: DvbDmxSWFilterPayload(dvbdmxfeed, buf);
282: else
283: dvbdmxfeed->cb.ts((u8 *)buf, 188, 0, 0,
284: &dvbdmxfeed->feed.ts, DMX_OK);
285: }
286: if (dvbdmxfeed->ts_type & TS_DECODER)
287: if (dvbdmxfeed->demux->write_to_decoder)
288: dvbdmxfeed->demux->
289: write_to_decoder(dvbdmxfeed, (u8 *)buf, 188);
290: break;
291:
292: case DMX_TYPE_SEC:
293: if (!dvbdmxfeed->feed.sec.is_filtering)
294: break;
295: if (DvbDmxSWFilterSectionPacket(dvbdmxfeed, buf)<0)
296: dvbdmxfeed->seclen=dvbdmxfeed->secbufp=0;
297: break;
298:
299: default:
300: break;
301: }
302: }
303:
304: void inline
305: DvbDmxSWFilterPacket(dvb_demux_t *dvbdmx, const u8 *buf)
306: {
307: dvb_demux_feed_t *dvbdmxfeed;
308:
309: if (!(dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)]))
310: return;
311: DvbDmxSWFilterPacketType(dvbdmxfeed, buf);
312: }
313:
314: void
315: DvbDmxSWFilterPackets(dvb_demux_t *dvbdmx, const u8 *buf, int count)
316: {
317: dvb_demux_feed_t *dvbdmxfeed;
318:
319: for (; count>0; count--, buf+=188)
320: if ((dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)]))
321: DvbDmxSWFilterPacketType(dvbdmxfeed, buf);
322: }
323:
324: static inline void
325: DvbDmxSWFilter(dvb_demux_t *dvbdmx, const u8 *buf, size_t count)
326: {
327: int p=0,i, j;
328:
329: if ((i=dvbdmx->tsbufp)) {
330: if (count<(j=188-i)) {
331: memcpy(&dvbdmx->tsbuf[i], buf, count);
332: dvbdmx->tsbufp+=count;
333: return;
334: }
335: memcpy(&dvbdmx->tsbuf[i], buf, j);
336: DvbDmxSWFilterPacket(dvbdmx, dvbdmx->tsbuf);
337: dvbdmx->tsbufp=0;
338: p+=j;
339: }
340:
341: while (p<count) {
342: if (buf[p]==0x47) {
343: if (count-p>=188) {
344: DvbDmxSWFilterPacket(dvbdmx, buf+p);
345: p+=188;
346: } else {
347: i=count-p;
348: memcpy(dvbdmx->tsbuf, buf+p, i);
349: dvbdmx->tsbufp=i;
350: return;
351: }
352: } else
353: p++;
354: }
355: }
356:
357:
358: /******************************************************************************
359: ******************************************************************************
360: * DVB DEMUX API LEVEL FUNCTIONS
361: ******************************************************************************
362: ******************************************************************************/
363:
364: static dvb_demux_filter_t *
365: DvbDmxFilterAlloc(dvb_demux_t *dvbdmx)
366: {
367: int i;
368:
369: for (i=0; i<DVB_DEMUX_FILTER_MAX; i++)
370: if (dvbdmx->filter[i].state==DMX_STATE_FREE)
371: break;
372: if (i==DVB_DEMUX_FILTER_MAX)
373: return 0;
374: dvbdmx->filter[i].state=DMX_STATE_ALLOCATED;
375: return &dvbdmx->filter[i];
376: }
377:
378: static dvb_demux_feed_t *
379: DvbDmxFeedAlloc(dvb_demux_t *dvbdmx)
380: {
381: int i;
382:
383: for (i=0; i<DVB_DEMUX_FEED_MAX; i++)
384: if (dvbdmx->feed[i].state==DMX_STATE_FREE)
385: break;
386: if (i==DVB_DEMUX_FEED_MAX)
387: return 0;
388: dvbdmx->feed[i].state=DMX_STATE_ALLOCATED;
389: return &dvbdmx->feed[i];
390: }
391:
392:
393: /******************************************************************************
394: * dmx_ts_feed API calls
395: ******************************************************************************/
396:
397: static int
398: dmx_ts_feed_set_type(dmx_ts_feed_t *feed, int type, dmx_ts_pes_t pes_type)
399: {
400: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
401: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
402:
403: dvbdmxfeed->ts_type=type;
404: dvbdmxfeed->pes_type=pes_type;
405:
406: if (dvbdmxfeed->ts_type & TS_DECODER) {
407: if (pes_type >= DMX_TS_PES_OTHER)
408: return -EINVAL;
409: if (dvbdmx->pesfilter[pes_type] &&
410: (dvbdmx->pesfilter[pes_type]!=dvbdmxfeed))
411: return -EINVAL;
412: dvbdmx->pesfilter[pes_type]=dvbdmxfeed;
413: //printk("pids[%d]=%04x\n", pes_type, dvbdmxfeed->pid);
414: dvbdmx->pids[pes_type]=dvbdmxfeed->pid;
415: }
416: return 0;
417: }
418:
419: static int
420: dmx_ts_feed_set(struct dmx_ts_feed_s* feed,
421: __u16 pid,
422: size_t callback_length,
423: size_t circular_buffer_size,
424: int descramble,
425: struct timespec timeout
426: )
427: {
428: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
429: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
430:
431: if (pid>0x1fff)
432: return -EINVAL;
433: if (dvbdmxfeed->pid!=0xffff) {
434: if (dvbdmxfeed->pid<=0x1fff)
435: dvbdmx->pid2feed[dvbdmxfeed->pid]=0;
436: dvbdmxfeed->pid=0xffff;
437: }
438: if (dvbdmx->pid2feed[pid])
439: return -EBUSY;
440:
441: dvbdmx->pid2feed[pid]=dvbdmxfeed;
442: dvbdmxfeed->pid=pid;
443:
444: dvbdmxfeed->buffer_size=circular_buffer_size;
445: dvbdmxfeed->descramble=descramble;
446: dvbdmxfeed->timeout=timeout;
447: dvbdmxfeed->cb_length=callback_length;
448: dvbdmxfeed->ts_type=TS_PACKET;
449:
450: if (dvbdmxfeed->descramble)
451: return -ENOSYS;
452:
453: if (dvbdmxfeed->buffer_size) {
454: dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
455: if (!dvbdmxfeed->buffer)
456: return -ENOMEM;
457: }
458: dvbdmxfeed->state=DMX_STATE_READY;
459: return 0;
460: }
461:
462: static int
463: dmx_ts_feed_start_filtering(struct dmx_ts_feed_s* feed)
464: {
465: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
466: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
467: int ret;
468:
469: if (dvbdmxfeed->state!=DMX_STATE_READY)
470: return -EINVAL;
471: if (dvbdmxfeed->type!=DMX_TYPE_TS)
472: return -EINVAL;
473:
1.3 ! mocm 474: if (!dvbdmx->start_feed)
! 475: return -1;
1.1 mocm 476: ret=dvbdmx->start_feed(dvbdmxfeed);
477: if (ret<0)
478: return ret;
479: feed->is_filtering=1;
480: dvbdmxfeed->state=DMX_STATE_GO;
481: return 0;
482: }
483:
484: static int
485: dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed)
486: {
487: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
488: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
489: int ret;
490:
491: //printk ("function : %s\n", __FUNCTION__);
492: if (dvbdmxfeed->state<DMX_STATE_GO)
493: return -EINVAL;
1.3 ! mocm 494: if (!dvbdmx->stop_feed)
! 495: return -1;
1.1 mocm 496: ret=dvbdmx->stop_feed(dvbdmxfeed);
497: feed->is_filtering=0;
498: dvbdmxfeed->state=DMX_STATE_ALLOCATED;
499:
500: return ret;
501: }
502:
503: static int dvbdmx_allocate_ts_feed(dmx_demux_t *demux,
504: dmx_ts_feed_t **feed,
505: dmx_ts_cb callback)
506: {
507: dvb_demux_t *dvbdmx=(dvb_demux_t *) demux;
508: dvb_demux_feed_t *dvbdmxfeed;
509:
510: if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx)))
511: return -EBUSY;
512:
513: dvbdmxfeed->type=DMX_TYPE_TS;
514: dvbdmxfeed->cb.ts=callback;
515: dvbdmxfeed->demux=dvbdmx;
516: dvbdmxfeed->pid=0xffff;
517: dvbdmxfeed->peslen=0xfffa;
518:
519: (*feed)=&dvbdmxfeed->feed.ts;
520: (*feed)->is_filtering=0;
521: (*feed)->parent=demux;
522: (*feed)->priv=0;
523: (*feed)->set=dmx_ts_feed_set;
524: (*feed)->set_type=dmx_ts_feed_set_type;
525: (*feed)->start_filtering=dmx_ts_feed_start_filtering;
526: (*feed)->stop_filtering=dmx_ts_feed_stop_filtering;
527:
528:
529: if (!(dvbdmxfeed->filter=DvbDmxFilterAlloc(dvbdmx))) {
530: dvbdmxfeed->state=DMX_STATE_FREE;
531: return -EBUSY;
532: }
533:
534: dvbdmxfeed->filter->type=DMX_TYPE_TS;
535: dvbdmxfeed->filter->feed=dvbdmxfeed;
536: dvbdmxfeed->filter->state=DMX_STATE_READY;
537:
538: return 0;
539: }
540:
541: static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed)
542: {
543: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
544:
545: if (dvbdmxfeed->state==DMX_STATE_FREE)
546: return -EINVAL;
1.3 ! mocm 547: if (dvbdmxfeed->buffer) {
1.1 mocm 548: vfree(dvbdmxfeed->buffer);
1.3 ! mocm 549: dvbdmxfeed->buffer=0;
! 550: }
1.1 mocm 551: dvbdmxfeed->state=DMX_STATE_FREE;
552: dvbdmxfeed->filter->state=DMX_STATE_FREE;
553: if (dvbdmxfeed->pid!=0xffff) {
554: if (dvbdmxfeed->pid<=0x1fff)
555: dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
556: dvbdmxfeed->pid=0xffff;
557: }
558:
559: return 0;
560: }
561:
562:
563: /******************************************************************************
564: * dmx_pes_feed API calls
565: ******************************************************************************/
566: /*
567: static int
568: dmx_pes_feed_set(struct dmx_pes_feed_s* feed,
569: __u16 pid,
570: size_t circular_buffer_size,
571: int descramble,
572: struct timespec timeout)
573: {
574: return 0;
575: }
576:
577: static int
578: dmx_pes_feed_start_filtering(struct dmx_pes_feed_s* feed)
579: {
580: return 0;
581: }
582:
583: static int
584: dmx_pes_feed_stop_filtering(struct dmx_pes_feed_s* feed)
585: {
586: return 0;
587: }
588: */
589:
590: static int dvbdmx_allocate_pes_feed(dmx_demux_t *demux,
591: dmx_pes_feed_t **feed,
592: dmx_pes_cb callback)
593: {
594: return 0;
595: }
596:
597: static int dvbdmx_release_pes_feed(dmx_demux_t *demux,
598: dmx_pes_feed_t *feed)
599: {
600: return 0;
601: }
602:
603:
604: /******************************************************************************
605: * dmx_section_feed API calls
606: ******************************************************************************/
607:
608: static int
609: dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed,
610: dmx_section_filter_t** filter)
611: {
612: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
613: dvb_demux_t *dvbdemux=dvbdmxfeed->demux;
614: dvb_demux_filter_t *dvbdmxfilter;
615:
616: dvbdmxfilter=DvbDmxFilterAlloc(dvbdemux);
617: if (!dvbdmxfilter)
618: return -ENOSPC;
619:
620: *filter=&dvbdmxfilter->filter;
621: (*filter)->parent=feed;
622: (*filter)->priv=0;
623: dvbdmxfilter->feed=dvbdmxfeed;
624: dvbdmxfilter->pid=dvbdmxfeed->pid;
625: dvbdmxfilter->type=DMX_TYPE_SEC;
626: dvbdmxfilter->state=DMX_STATE_READY;
627:
628: dvbdmxfilter->next=dvbdmxfeed->filter;
629: dvbdmxfeed->filter=dvbdmxfilter;
630: return 0;
631: }
632:
633: static int
634: dmx_section_feed_set(struct dmx_section_feed_s* feed,
635: __u16 pid, size_t circular_buffer_size,
636: int descramble, int check_crc)
637: {
638: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
639: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
640:
641: //printk ("function : %s PID %04x\n", __FUNCTION__, pid);
642:
643: if (pid>0x1fff)
644: return -EINVAL;
645: if (dvbdmxfeed->pid!=0xffff) {
646: dvbdmx->pid2feed[dvbdmxfeed->pid]=0;
647: dvbdmxfeed->pid=0xffff;
648: }
649: if (dvbdmx->pid2feed[pid])
650: return -EBUSY;
651: dvbdmx->pid2feed[pid]=dvbdmxfeed;
652:
653: dvbdmxfeed->pid=pid;
654: dvbdmxfeed->buffer_size=circular_buffer_size;
655: dvbdmxfeed->descramble=descramble;
656: if (dvbdmxfeed->descramble)
657: return -ENOSYS;
658:
659: dvbdmxfeed->check_crc=check_crc;
660: dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
661: if (!dvbdmxfeed->buffer)
662: return -ENOMEM;
1.3 ! mocm 663: dvbdmxfeed->state=DMX_STATE_READY;
1.1 mocm 664: return 0;
665: }
666:
667: static int
668: dmx_section_feed_start_filtering(dmx_section_feed_t *feed)
669: {
670: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
671: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
672: int ret;
673:
674: if (feed->is_filtering)
675: return -EBUSY;
676: if (!dvbdmxfeed->filter)
677: return -EINVAL;
678:
679: dvbdmxfeed->secbufp=0;
680: dvbdmxfeed->seclen=0;
681:
1.3 ! mocm 682: if (!dvbdmx->start_feed)
! 683: return -1;
1.1 mocm 684: ret=dvbdmx->start_feed(dvbdmxfeed);
685: if (ret<0)
686: return ret;
687: feed->is_filtering=1;
688: dvbdmxfeed->state=DMX_STATE_GO;
689: return 0;
690: }
691:
692: static int
693: dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed)
694: {
695: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
696: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
1.3 ! mocm 697: int ret;
! 698:
! 699: if (!dvbdmx->stop_feed)
! 700: return -1;
! 701: ret=dvbdmx->stop_feed(dvbdmxfeed);
1.1 mocm 702:
703: dvbdmxfeed->state=DMX_STATE_READY;
704: feed->is_filtering=0;
705: return ret;
706: }
707:
708: static int
709: dmx_section_feed_release_filter(dmx_section_feed_t *feed,
710: dmx_section_filter_t* filter)
711: {
712: dvb_demux_filter_t *dvbdmxfilter=(dvb_demux_filter_t *) filter, *f;
713: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
714:
715: if (dvbdmxfilter->feed!=dvbdmxfeed)
716: return -EINVAL;
717: if (feed->is_filtering)
1.2 mocm 718: feed->stop_filtering(feed);
719: //return -EBUSY;
1.1 mocm 720:
721: f=dvbdmxfeed->filter;
1.3 ! mocm 722: if (f==dvbdmxfilter)
1.1 mocm 723: dvbdmxfeed->filter=dvbdmxfilter->next;
724: else {
725: while(f->next!=dvbdmxfilter)
726: f=f->next;
727: f->next=f->next->next;
728: }
729:
730: dvbdmxfilter->state=DMX_STATE_FREE;
731: return 0;
732: }
733:
734: static int dvbdmx_allocate_section_feed(dmx_demux_t *demux,
735: dmx_section_feed_t **feed,
736: dmx_section_cb callback)
737: {
738: dvb_demux_t *dvbdmx=(dvb_demux_t *) demux;
739: dvb_demux_feed_t *dvbdmxfeed;
740:
741: if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx)))
742: return -EBUSY;
743: dvbdmxfeed->type=DMX_TYPE_SEC;
744: dvbdmxfeed->cb.sec=callback;
745: dvbdmxfeed->demux=dvbdmx;
746: dvbdmxfeed->pid=0xffff;
747: dvbdmxfeed->secbufp=0;
748: dvbdmxfeed->filter=0;
749:
750: (*feed)=&dvbdmxfeed->feed.sec;
751: (*feed)->is_filtering=0;
752: (*feed)->parent=demux;
753: (*feed)->priv=0;
754: (*feed)->set=dmx_section_feed_set;
755: (*feed)->allocate_filter=dmx_section_feed_allocate_filter;
756: (*feed)->release_filter=dmx_section_feed_release_filter;
757: (*feed)->start_filtering=dmx_section_feed_start_filtering;
758: (*feed)->stop_filtering=dmx_section_feed_stop_filtering;
759: return 0;
760: }
761:
762: static int dvbdmx_release_section_feed(dmx_demux_t *demux,
763: dmx_section_feed_t *feed)
764: {
765: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
766:
767: if (dvbdmxfeed->state==DMX_STATE_FREE)
768: return -EINVAL;
1.3 ! mocm 769: if (dvbdmxfeed->buffer) {
1.1 mocm 770: vfree(dvbdmxfeed->buffer);
1.3 ! mocm 771: dvbdmxfeed->buffer=0;
! 772: }
1.1 mocm 773: dvbdmxfeed->state=DMX_STATE_FREE;
774: dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
775: if (dvbdmxfeed->pid!=0xffff)
776: dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
777: return 0;
778: }
779:
780:
781: /******************************************************************************
782: * dvb_demux kernel data API calls
783: ******************************************************************************/
784:
1.3 ! mocm 785: static int dvbdmx_open(dmx_demux_t *demux)
1.1 mocm 786: {
787: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
788:
789: if (dvbdemux->users>=MAX_DVB_DEMUX_USERS)
790: return -EUSERS;
791: dvbdemux->users++;
792: return 0;
793: }
794:
795: static int dvbdmx_close(struct dmx_demux_s *demux)
796: {
797: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
798:
799: if (dvbdemux->users==0)
800: return -ENODEV;
801: dvbdemux->users--;
802: //FIXME: release any unneeded resources if users==0
803: return 0;
804: }
805:
806: static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count)
807: {
808: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
809:
810: if ((!demux->frontend) ||
811: (demux->frontend->source!=DMX_MEMORY_FE))
812: return -EINVAL;
813:
814: DvbDmxSWFilter(dvbdemux, buf, count);
815: return count;
816: }
817:
818:
819: static int dvbdmx_add_frontend(dmx_demux_t *demux,
820: dmx_frontend_t *frontend)
821: {
822: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
823: struct list_head *pos, *head=&dvbdemux->frontend_list;
824:
825: //printk ("function : %s\n", __FUNCTION__);
826:
827: if (!(frontend->id && frontend->vendor && frontend->model))
828: return -EINVAL;
829: list_for_each(pos, head)
830: {
831: if (!strcmp(DMX_FE_ENTRY(pos)->id, frontend->id))
832: return -EEXIST;
833: }
834:
835: list_add(&(frontend->connectivity_list), head);
836: return 0;
837: }
838:
839: static int
840: dvbdmx_remove_frontend(dmx_demux_t *demux,
841: dmx_frontend_t *frontend)
842: {
843: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
844: struct list_head *pos, *head=&dvbdemux->frontend_list;
845:
846: list_for_each(pos, head)
847: {
848: if (DMX_FE_ENTRY(pos)==frontend)
849: {
850: list_del(pos);
851: return 0;
852: }
853: }
854: return -ENODEV;
855: }
856:
857: static struct list_head *
858: dvbdmx_get_frontends(dmx_demux_t *demux)
859: {
860: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
861:
862: if (list_empty(&dvbdemux->frontend_list))
863: return NULL;
864: return &dvbdemux->frontend_list;
865: }
866:
867: static int dvbdmx_connect_frontend(dmx_demux_t *demux,
868: dmx_frontend_t *frontend)
869: {
870: if (demux->frontend)
871: return -EINVAL;
872:
873: demux->frontend=frontend;
874: return 0;
875: }
876:
877: static int dvbdmx_disconnect_frontend(dmx_demux_t *demux)
878: {
879: demux->frontend=NULL;
880: return 0;
881: }
882:
883: static int dvbdmx_get_pes_pids(dmx_demux_t *demux, __u16 *pids)
884: {
885: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
886:
887: memcpy(pids, dvbdemux->pids, 5*sizeof(__u16));
888: return 0;
889: }
890:
891: int
1.3 ! mocm 892: DvbDmxInit(dvb_demux_t *dvbdemux)
1.1 mocm 893: {
1.3 ! mocm 894: int i;
1.1 mocm 895: dmx_demux_t *dmx=&dvbdemux->dmx;
896:
1.3 ! mocm 897: dvbdemux->users=0;
1.1 mocm 898: dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(dvb_demux_filter_t));
899: if (!dvbdemux->filter)
900: return -ENOMEM;
901: for (i=0; i<DVB_DEMUX_FILTER_MAX; i++) {
902: dvbdemux->filter[i].state=DMX_STATE_FREE;
903: dvbdemux->filter[i].index=i;
904: }
905: for (i=0; i<DVB_DEMUX_FEED_MAX; i++)
906: dvbdemux->feed[i].state=DMX_STATE_FREE;
1.3 ! mocm 907: dvbdemux->frontend_list.next=
! 908: dvbdemux->frontend_list.prev=
! 909: &dvbdemux->frontend_list;
1.1 mocm 910: for (i=0; i<DMX_TS_PES_OTHER; i++) {
911: dvbdemux->pesfilter[i]=NULL;
912: dvbdemux->pids[i]=0xffff;
913: }
914: dvbdemux->playing=dvbdemux->recording=0;
915: memset(dvbdemux->pid2feed, 0, 0x2000*sizeof(dvb_demux_feed_t *));
916: dvbdemux->tsbufp=0;
917:
918: dmx->frontend=0;
919: dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list;
920: dmx->priv=(void *) dvbdemux;
1.3 ! mocm 921: //dmx->users=0; // reset in dmx_register_demux()
1.1 mocm 922: dmx->open=dvbdmx_open;
923: dmx->close=dvbdmx_close;
924: dmx->write=dvbdmx_write;
925: dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed;
926: dmx->release_ts_feed=dvbdmx_release_ts_feed;
927: dmx->allocate_pes_feed=dvbdmx_allocate_pes_feed;
928: dmx->release_pes_feed=dvbdmx_release_pes_feed;
929: dmx->allocate_section_feed=dvbdmx_allocate_section_feed;
930: dmx->release_section_feed=dvbdmx_release_section_feed;
931:
932: dmx->descramble_mac_address=NULL;
933: dmx->descramble_section_payload=NULL;
934:
935: dmx->add_frontend=dvbdmx_add_frontend;
936: dmx->remove_frontend=dvbdmx_remove_frontend;
937: dmx->get_frontends=dvbdmx_get_frontends;
938: dmx->connect_frontend=dvbdmx_connect_frontend;
939: dmx->disconnect_frontend=dvbdmx_disconnect_frontend;
940: dmx->get_pes_pids=dvbdmx_get_pes_pids;
941:
942: if (dmx_register_demux(dmx)<0)
943: return -1;
1.3 ! mocm 944: //if (dmx->open(dmx)<0)
! 945: // return -1;
1.1 mocm 946: return 0;
947: }
948:
949: int
950: DvbDmxRelease(dvb_demux_t *dvbdemux)
951: {
952: dmx_demux_t *dmx=&dvbdemux->dmx;
953:
954: dmx_unregister_demux(dmx);
955: if (dvbdemux->filter)
956: vfree(dvbdemux->filter);
957: return 0;
958: }
959:
960: /*
961: * Local variables:
962: * c-indent-level: 8
963: * c-brace-imaginary-offset: 0
964: * c-brace-offset: -8
965: * c-argdecl-indent: 8
966: * c-label-offset: -8
967: * c-continued-statement-offset: 8
968: * c-continued-brace-offset: 0
969: * indent-tabs-mode: nil
970: * tab-width: 8
971: * End:
972: */
LinuxTV legacy CVS <linuxtv.org/cvs>