Annotation of margi2/dvb_demux.c, revision 1.2
1.1 mocm 1: /*
2: * dvb_demux.c - DVB kernel demux API
3: *
4: * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
5: * & Marcus Metzler <marcus@convergence.de>
6: for convergence integrated media GmbH
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:
474: ret=dvbdmx->start_feed(dvbdmxfeed);
475: if (ret<0)
476: return ret;
477: feed->is_filtering=1;
478: dvbdmxfeed->state=DMX_STATE_GO;
479: return 0;
480: }
481:
482: static int
483: dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed)
484: {
485: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
486: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
487: int ret;
488:
489: //printk ("function : %s\n", __FUNCTION__);
490: if (dvbdmxfeed->state<DMX_STATE_GO)
491: return -EINVAL;
492: ret=dvbdmx->stop_feed(dvbdmxfeed);
493: feed->is_filtering=0;
494: dvbdmxfeed->state=DMX_STATE_ALLOCATED;
495:
496: return ret;
497: }
498:
499: static int dvbdmx_allocate_ts_feed(dmx_demux_t *demux,
500: dmx_ts_feed_t **feed,
501: dmx_ts_cb callback)
502: {
503: dvb_demux_t *dvbdmx=(dvb_demux_t *) demux;
504: dvb_demux_feed_t *dvbdmxfeed;
505:
506: if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx)))
507: return -EBUSY;
508:
509: dvbdmxfeed->type=DMX_TYPE_TS;
510: dvbdmxfeed->cb.ts=callback;
511: dvbdmxfeed->demux=dvbdmx;
512: dvbdmxfeed->pid=0xffff;
513: dvbdmxfeed->peslen=0xfffa;
514:
515: (*feed)=&dvbdmxfeed->feed.ts;
516: (*feed)->is_filtering=0;
517: (*feed)->parent=demux;
518: (*feed)->priv=0;
519: (*feed)->set=dmx_ts_feed_set;
520: (*feed)->set_type=dmx_ts_feed_set_type;
521: (*feed)->start_filtering=dmx_ts_feed_start_filtering;
522: (*feed)->stop_filtering=dmx_ts_feed_stop_filtering;
523:
524:
525: if (!(dvbdmxfeed->filter=DvbDmxFilterAlloc(dvbdmx))) {
526: dvbdmxfeed->state=DMX_STATE_FREE;
527: return -EBUSY;
528: }
529:
530: dvbdmxfeed->filter->type=DMX_TYPE_TS;
531: dvbdmxfeed->filter->feed=dvbdmxfeed;
532: dvbdmxfeed->filter->state=DMX_STATE_READY;
533:
534: return 0;
535: }
536:
537: static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed)
538: {
539: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
540:
541: if (dvbdmxfeed->state==DMX_STATE_FREE)
542: return -EINVAL;
1.2 ! mocm 543: if (dvbdmxfeed->buffer)
1.1 mocm 544: vfree(dvbdmxfeed->buffer);
545: dvbdmxfeed->buffer=0;
546: dvbdmxfeed->state=DMX_STATE_FREE;
547: dvbdmxfeed->filter->state=DMX_STATE_FREE;
548: if (dvbdmxfeed->pid!=0xffff) {
549: if (dvbdmxfeed->pid<=0x1fff)
550: dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
551: dvbdmxfeed->pid=0xffff;
552: }
553:
554: return 0;
555: }
556:
557:
558: /******************************************************************************
559: * dmx_pes_feed API calls
560: ******************************************************************************/
561: /*
562: static int
563: dmx_pes_feed_set(struct dmx_pes_feed_s* feed,
564: __u16 pid,
565: size_t circular_buffer_size,
566: int descramble,
567: struct timespec timeout)
568: {
569: return 0;
570: }
571:
572: static int
573: dmx_pes_feed_start_filtering(struct dmx_pes_feed_s* feed)
574: {
575: return 0;
576: }
577:
578: static int
579: dmx_pes_feed_stop_filtering(struct dmx_pes_feed_s* feed)
580: {
581: return 0;
582: }
583: */
584:
585: static int dvbdmx_allocate_pes_feed(dmx_demux_t *demux,
586: dmx_pes_feed_t **feed,
587: dmx_pes_cb callback)
588: {
589: return 0;
590: }
591:
592: static int dvbdmx_release_pes_feed(dmx_demux_t *demux,
593: dmx_pes_feed_t *feed)
594: {
595: return 0;
596: }
597:
598:
599: /******************************************************************************
600: * dmx_section_feed API calls
601: ******************************************************************************/
602:
603: static int
604: dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed,
605: dmx_section_filter_t** filter)
606: {
607: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
608: dvb_demux_t *dvbdemux=dvbdmxfeed->demux;
609: dvb_demux_filter_t *dvbdmxfilter;
610:
611: dvbdmxfilter=DvbDmxFilterAlloc(dvbdemux);
612: if (!dvbdmxfilter)
613: return -ENOSPC;
614:
615: *filter=&dvbdmxfilter->filter;
616: (*filter)->parent=feed;
617: (*filter)->priv=0;
618: dvbdmxfilter->feed=dvbdmxfeed;
619: dvbdmxfilter->pid=dvbdmxfeed->pid;
620: dvbdmxfilter->type=DMX_TYPE_SEC;
621: dvbdmxfilter->state=DMX_STATE_READY;
622:
623: dvbdmxfilter->next=dvbdmxfeed->filter;
624: dvbdmxfeed->filter=dvbdmxfilter;
625: return 0;
626: }
627:
628: static int
629: dmx_section_feed_set(struct dmx_section_feed_s* feed,
630: __u16 pid, size_t circular_buffer_size,
631: int descramble, int check_crc)
632: {
633: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
634: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
635:
636: //printk ("function : %s PID %04x\n", __FUNCTION__, pid);
637:
638: if (pid>0x1fff)
639: return -EINVAL;
640: if (dvbdmxfeed->pid!=0xffff) {
641: dvbdmx->pid2feed[dvbdmxfeed->pid]=0;
642: dvbdmxfeed->pid=0xffff;
643: }
644: if (dvbdmx->pid2feed[pid])
645: return -EBUSY;
646: dvbdmx->pid2feed[pid]=dvbdmxfeed;
647:
648: dvbdmxfeed->pid=pid;
649: dvbdmxfeed->buffer_size=circular_buffer_size;
650: dvbdmxfeed->descramble=descramble;
651: if (dvbdmxfeed->descramble)
652: return -ENOSYS;
653:
654: dvbdmxfeed->check_crc=check_crc;
655: dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
656: if (!dvbdmxfeed->buffer)
657: return -ENOMEM;
658: return 0;
659: }
660:
661: static int
662: dmx_section_feed_start_filtering(dmx_section_feed_t *feed)
663: {
664: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
665: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
666: int ret;
667:
668: if (feed->is_filtering)
669: return -EBUSY;
670: if (!dvbdmxfeed->filter)
671: return -EINVAL;
672:
673: dvbdmxfeed->secbufp=0;
674: dvbdmxfeed->seclen=0;
675:
676: ret=dvbdmx->start_feed(dvbdmxfeed);
677: if (ret<0)
678: return ret;
679: feed->is_filtering=1;
680: dvbdmxfeed->state=DMX_STATE_GO;
681: return 0;
682: }
683:
684: static int
685: dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed)
686: {
687: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
688: dvb_demux_t *dvbdmx=dvbdmxfeed->demux;
689: int ret=dvbdmx->stop_feed(dvbdmxfeed);
690:
691: dvbdmxfeed->state=DMX_STATE_READY;
692: feed->is_filtering=0;
693: return ret;
694: }
695:
696: static int
697: dmx_section_feed_release_filter(dmx_section_feed_t *feed,
698: dmx_section_filter_t* filter)
699: {
700: dvb_demux_filter_t *dvbdmxfilter=(dvb_demux_filter_t *) filter, *f;
701: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
702:
703: if (dvbdmxfilter->feed!=dvbdmxfeed)
704: return -EINVAL;
705: if (feed->is_filtering)
1.2 ! mocm 706: feed->stop_filtering(feed);
! 707: //return -EBUSY;
1.1 mocm 708:
709: f=dvbdmxfeed->filter;
710: if (f==dvbdmxfeed->filter)
711: dvbdmxfeed->filter=dvbdmxfilter->next;
712: else {
713: while(f->next!=dvbdmxfilter)
714: f=f->next;
715: f->next=f->next->next;
716: }
717:
718: dvbdmxfilter->state=DMX_STATE_FREE;
719: return 0;
720: }
721:
722: static int dvbdmx_allocate_section_feed(dmx_demux_t *demux,
723: dmx_section_feed_t **feed,
724: dmx_section_cb callback)
725: {
726: dvb_demux_t *dvbdmx=(dvb_demux_t *) demux;
727: dvb_demux_feed_t *dvbdmxfeed;
728:
729: if (!(dvbdmxfeed=DvbDmxFeedAlloc(dvbdmx)))
730: return -EBUSY;
731: dvbdmxfeed->type=DMX_TYPE_SEC;
732: dvbdmxfeed->cb.sec=callback;
733: dvbdmxfeed->demux=dvbdmx;
734: dvbdmxfeed->pid=0xffff;
735: dvbdmxfeed->secbufp=0;
736: dvbdmxfeed->filter=0;
737:
738: (*feed)=&dvbdmxfeed->feed.sec;
739: (*feed)->is_filtering=0;
740: (*feed)->parent=demux;
741: (*feed)->priv=0;
742: (*feed)->set=dmx_section_feed_set;
743: (*feed)->allocate_filter=dmx_section_feed_allocate_filter;
744: (*feed)->release_filter=dmx_section_feed_release_filter;
745: (*feed)->start_filtering=dmx_section_feed_start_filtering;
746: (*feed)->stop_filtering=dmx_section_feed_stop_filtering;
747: return 0;
748: }
749:
750: static int dvbdmx_release_section_feed(dmx_demux_t *demux,
751: dmx_section_feed_t *feed)
752: {
753: dvb_demux_feed_t *dvbdmxfeed=(dvb_demux_feed_t *) feed;
754:
755: if (dvbdmxfeed->state==DMX_STATE_FREE)
756: return -EINVAL;
757: if (dvbdmxfeed->buffer)
758: vfree(dvbdmxfeed->buffer);
759: dvbdmxfeed->buffer=0;
760: dvbdmxfeed->state=DMX_STATE_FREE;
761: dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
762: if (dvbdmxfeed->pid!=0xffff)
763: dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
764: return 0;
765: }
766:
767:
768: /******************************************************************************
769: * dvb_demux kernel data API calls
770: ******************************************************************************/
771:
772: static int dvbdmx_open(struct dmx_demux_s *demux)
773: {
774: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
775:
776: if (dvbdemux->users>=MAX_DVB_DEMUX_USERS)
777: return -EUSERS;
778: dvbdemux->users++;
779: return 0;
780: }
781:
782: static int dvbdmx_close(struct dmx_demux_s *demux)
783: {
784: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
785:
786: if (dvbdemux->users==0)
787: return -ENODEV;
788: dvbdemux->users--;
789: //FIXME: release any unneeded resources if users==0
790: return 0;
791: }
792:
793: static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count)
794: {
795: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
796:
797: if ((!demux->frontend) ||
798: (demux->frontend->source!=DMX_MEMORY_FE))
799: return -EINVAL;
800:
801: DvbDmxSWFilter(dvbdemux, buf, count);
802: return count;
803: }
804:
805:
806: static int dvbdmx_add_frontend(dmx_demux_t *demux,
807: dmx_frontend_t *frontend)
808: {
809: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
810: struct list_head *pos, *head=&dvbdemux->frontend_list;
811:
812: //printk ("function : %s\n", __FUNCTION__);
813:
814: if (!(frontend->id && frontend->vendor && frontend->model))
815: return -EINVAL;
816: list_for_each(pos, head)
817: {
818: if (!strcmp(DMX_FE_ENTRY(pos)->id, frontend->id))
819: return -EEXIST;
820: }
821:
822: list_add(&(frontend->connectivity_list), head);
823: return 0;
824: }
825:
826: static int
827: dvbdmx_remove_frontend(dmx_demux_t *demux,
828: dmx_frontend_t *frontend)
829: {
830: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
831: struct list_head *pos, *head=&dvbdemux->frontend_list;
832:
833: list_for_each(pos, head)
834: {
835: if (DMX_FE_ENTRY(pos)==frontend)
836: {
837: list_del(pos);
838: return 0;
839: }
840: }
841: return -ENODEV;
842: }
843:
844: static struct list_head *
845: dvbdmx_get_frontends(dmx_demux_t *demux)
846: {
847: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
848:
849: if (list_empty(&dvbdemux->frontend_list))
850: return NULL;
851: return &dvbdemux->frontend_list;
852: }
853:
854: static int dvbdmx_connect_frontend(dmx_demux_t *demux,
855: dmx_frontend_t *frontend)
856: {
857: if (demux->frontend)
858: return -EINVAL;
859:
860: demux->frontend=frontend;
861: return 0;
862: }
863:
864: static int dvbdmx_disconnect_frontend(dmx_demux_t *demux)
865: {
866: demux->frontend=NULL;
867: return 0;
868: }
869:
870: static int dvbdmx_get_pes_pids(dmx_demux_t *demux, __u16 *pids)
871: {
872: dvb_demux_t *dvbdemux=(dvb_demux_t *) demux;
873:
874: memcpy(pids, dvbdemux->pids, 5*sizeof(__u16));
875: return 0;
876: }
877:
878: int
879: DvbDmxInit(dvb_demux_t *dvbdemux, char *id, char *vendor, char *model)
880: {
881: dmx_demux_t *dmx=&dvbdemux->dmx;
882: int i;
883:
884: dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(dvb_demux_filter_t));
885: if (!dvbdemux->filter)
886: return -ENOMEM;
887:
888: dvbdemux->start_feed=0;
889: dvbdemux->stop_feed=0;
890: dvbdemux->write_to_decoder=0;
891: dvbdemux->frontend_list.next=
892: dvbdemux->frontend_list.prev=
893: &dvbdemux->frontend_list;
894: dvbdemux->users=0;
895:
896: for (i=0; i<DVB_DEMUX_FILTER_MAX; i++) {
897: dvbdemux->filter[i].state=DMX_STATE_FREE;
898: dvbdemux->filter[i].index=i;
899: }
900: for (i=0; i<DVB_DEMUX_FEED_MAX; i++)
901: dvbdemux->feed[i].state=DMX_STATE_FREE;
902: for (i=0; i<DMX_TS_PES_OTHER; i++) {
903: dvbdemux->pesfilter[i]=NULL;
904: dvbdemux->pids[i]=0xffff;
905: }
906: dvbdemux->playing=dvbdemux->recording=0;
907: memset(dvbdemux->pid2feed, 0, 0x2000*sizeof(dvb_demux_feed_t *));
908: dvbdemux->tsbufp=0;
909:
910: dmx->id=id;
911: dmx->vendor=vendor;
912: dmx->model=model;
913: dmx->frontend=0;
914: dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list;
915: dmx->priv=(void *) dvbdemux;
916: dmx->open=dvbdmx_open;
917: dmx->close=dvbdmx_close;
918: dmx->write=dvbdmx_write;
919: dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed;
920: dmx->release_ts_feed=dvbdmx_release_ts_feed;
921: dmx->allocate_pes_feed=dvbdmx_allocate_pes_feed;
922: dmx->release_pes_feed=dvbdmx_release_pes_feed;
923: dmx->allocate_section_feed=dvbdmx_allocate_section_feed;
924: dmx->release_section_feed=dvbdmx_release_section_feed;
925:
926: dmx->descramble_mac_address=NULL;
927: dmx->descramble_section_payload=NULL;
928:
929: dmx->add_frontend=dvbdmx_add_frontend;
930: dmx->remove_frontend=dvbdmx_remove_frontend;
931: dmx->get_frontends=dvbdmx_get_frontends;
932: dmx->connect_frontend=dvbdmx_connect_frontend;
933: dmx->disconnect_frontend=dvbdmx_disconnect_frontend;
934: dmx->get_pes_pids=dvbdmx_get_pes_pids;
935:
936: if (dmx_register_demux(dmx)<0)
937: return -1;
938: if (dmx->open(dmx)<0)
939: return -1;
940: return 0;
941: }
942:
943: int
944: DvbDmxRelease(dvb_demux_t *dvbdemux)
945: {
946: dmx_demux_t *dmx=&dvbdemux->dmx;
947:
948: dmx_unregister_demux(dmx);
949: if (dvbdemux->filter)
950: vfree(dvbdemux->filter);
951: return 0;
952: }
953:
954: /*
955: * Local variables:
956: * c-indent-level: 8
957: * c-brace-imaginary-offset: 0
958: * c-brace-offset: -8
959: * c-argdecl-indent: 8
960: * c-label-offset: -8
961: * c-continued-statement-offset: 8
962: * c-continued-brace-offset: 0
963: * indent-tabs-mode: nil
964: * tab-width: 8
965: * End:
966: */
LinuxTV legacy CVS <linuxtv.org/cvs>