Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 /*
0003  * dvb_demux.c - DVB kernel demux API
0004  *
0005  * Copyright (C) 2000-2001 Ralph  Metzler <ralph@convergence.de>
0006  *             & Marcus Metzler <marcus@convergence.de>
0007  *           for convergence integrated media GmbH
0008  */
0009 
0010 #define pr_fmt(fmt) "dvb_demux: " fmt
0011 
0012 #include <linux/sched/signal.h>
0013 #include <linux/spinlock.h>
0014 #include <linux/slab.h>
0015 #include <linux/vmalloc.h>
0016 #include <linux/module.h>
0017 #include <linux/poll.h>
0018 #include <linux/string.h>
0019 #include <linux/crc32.h>
0020 #include <linux/uaccess.h>
0021 #include <asm/div64.h>
0022 
0023 #include <media/dvb_demux.h>
0024 
0025 static int dvb_demux_tscheck;
0026 module_param(dvb_demux_tscheck, int, 0644);
0027 MODULE_PARM_DESC(dvb_demux_tscheck,
0028         "enable transport stream continuity and TEI check");
0029 
0030 static int dvb_demux_speedcheck;
0031 module_param(dvb_demux_speedcheck, int, 0644);
0032 MODULE_PARM_DESC(dvb_demux_speedcheck,
0033         "enable transport stream speed check");
0034 
0035 static int dvb_demux_feed_err_pkts = 1;
0036 module_param(dvb_demux_feed_err_pkts, int, 0644);
0037 MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
0038          "when set to 0, drop packets with the TEI bit set (1 by default)");
0039 
0040 #define dprintk(fmt, arg...) \
0041     printk(KERN_DEBUG pr_fmt("%s: " fmt),  __func__, ##arg)
0042 
0043 #define dprintk_tscheck(x...) do {          \
0044     if (dvb_demux_tscheck && printk_ratelimit())    \
0045         dprintk(x);             \
0046 } while (0)
0047 
0048 #ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
0049 #  define dprintk_sect_loss(x...) dprintk(x)
0050 #else
0051 #  define dprintk_sect_loss(x...)
0052 #endif
0053 
0054 #define set_buf_flags(__feed, __flag)           \
0055     do {                        \
0056         (__feed)->buffer_flags |= (__flag); \
0057     } while (0)
0058 
0059 /******************************************************************************
0060  * static inlined helper functions
0061  ******************************************************************************/
0062 
0063 static inline u16 section_length(const u8 *buf)
0064 {
0065     return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
0066 }
0067 
0068 static inline u16 ts_pid(const u8 *buf)
0069 {
0070     return ((buf[1] & 0x1f) << 8) + buf[2];
0071 }
0072 
0073 static inline u8 payload(const u8 *tsp)
0074 {
0075     if (!(tsp[3] & 0x10))   // no payload?
0076         return 0;
0077 
0078     if (tsp[3] & 0x20) {    // adaptation field?
0079         if (tsp[4] > 183)   // corrupted data?
0080             return 0;
0081         else
0082             return 184 - 1 - tsp[4];
0083     }
0084 
0085     return 184;
0086 }
0087 
0088 static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
0089 {
0090     return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
0091 }
0092 
0093 static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
0094                 size_t len)
0095 {
0096     memcpy(d, s, len);
0097 }
0098 
0099 /******************************************************************************
0100  * Software filter functions
0101  ******************************************************************************/
0102 
0103 static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
0104                        const u8 *buf)
0105 {
0106     int count = payload(buf);
0107     int p;
0108     int ccok;
0109     u8 cc;
0110 
0111     if (count == 0)
0112         return -1;
0113 
0114     p = 188 - count;
0115 
0116     cc = buf[3] & 0x0f;
0117     ccok = ((feed->cc + 1) & 0x0f) == cc;
0118     feed->cc = cc;
0119     if (!ccok) {
0120         set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
0121         dprintk_sect_loss("missed packet: %d instead of %d!\n",
0122                   cc, (feed->cc + 1) & 0x0f);
0123     }
0124 
0125     if (buf[1] & 0x40)  // PUSI ?
0126         feed->peslen = 0xfffa;
0127 
0128     feed->peslen += count;
0129 
0130     return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts,
0131                &feed->buffer_flags);
0132 }
0133 
0134 static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
0135                       struct dvb_demux_filter *f)
0136 {
0137     u8 neq = 0;
0138     int i;
0139 
0140     for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
0141         u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
0142 
0143         if (f->maskandmode[i] & xor)
0144             return 0;
0145 
0146         neq |= f->maskandnotmode[i] & xor;
0147     }
0148 
0149     if (f->doneq && !neq)
0150         return 0;
0151 
0152     return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
0153                 NULL, 0, &f->filter, &feed->buffer_flags);
0154 }
0155 
0156 static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
0157 {
0158     struct dvb_demux *demux = feed->demux;
0159     struct dvb_demux_filter *f = feed->filter;
0160     struct dmx_section_feed *sec = &feed->feed.sec;
0161     int section_syntax_indicator;
0162 
0163     if (!sec->is_filtering)
0164         return 0;
0165 
0166     if (!f)
0167         return 0;
0168 
0169     if (sec->check_crc) {
0170         section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
0171         if (section_syntax_indicator &&
0172             demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
0173             set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD);
0174             return -1;
0175         }
0176     }
0177 
0178     do {
0179         if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
0180             return -1;
0181     } while ((f = f->next) && sec->is_filtering);
0182 
0183     sec->seclen = 0;
0184 
0185     return 0;
0186 }
0187 
0188 static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
0189 {
0190     struct dmx_section_feed *sec = &feed->feed.sec;
0191 
0192     if (sec->secbufp < sec->tsfeedp) {
0193         int n = sec->tsfeedp - sec->secbufp;
0194 
0195         /*
0196          * Section padding is done with 0xff bytes entirely.
0197          * Due to speed reasons, we won't check all of them
0198          * but just first and last.
0199          */
0200         if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
0201             set_buf_flags(feed,
0202                       DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
0203             dprintk_sect_loss("section ts padding loss: %d/%d\n",
0204                       n, sec->tsfeedp);
0205             dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
0206         }
0207     }
0208 
0209     sec->tsfeedp = sec->secbufp = sec->seclen = 0;
0210     sec->secbuf = sec->secbuf_base;
0211 }
0212 
0213 /*
0214  * Losless Section Demux 1.4.1 by Emard
0215  * Valsecchi Patrick:
0216  *  - middle of section A  (no PUSI)
0217  *  - end of section A and start of section B
0218  *    (with PUSI pointing to the start of the second section)
0219  *
0220  *  In this case, without feed->pusi_seen you'll receive a garbage section
0221  *  consisting of the end of section A. Basically because tsfeedp
0222  *  is incemented and the use=0 condition is not raised
0223  *  when the second packet arrives.
0224  *
0225  * Fix:
0226  * when demux is started, let feed->pusi_seen = false to
0227  * prevent initial feeding of garbage from the end of
0228  * previous section. When you for the first time see PUSI=1
0229  * then set feed->pusi_seen = true
0230  */
0231 static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
0232                           const u8 *buf, u8 len)
0233 {
0234     struct dvb_demux *demux = feed->demux;
0235     struct dmx_section_feed *sec = &feed->feed.sec;
0236     u16 limit, seclen, n;
0237 
0238     if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
0239         return 0;
0240 
0241     if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
0242         set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
0243         dprintk_sect_loss("section buffer full loss: %d/%d\n",
0244                   sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
0245                   DMX_MAX_SECFEED_SIZE);
0246         len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
0247     }
0248 
0249     if (len <= 0)
0250         return 0;
0251 
0252     demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
0253     sec->tsfeedp += len;
0254 
0255     /*
0256      * Dump all the sections we can find in the data (Emard)
0257      */
0258     limit = sec->tsfeedp;
0259     if (limit > DMX_MAX_SECFEED_SIZE)
0260         return -1;  /* internal error should never happen */
0261 
0262     /* to be sure always set secbuf */
0263     sec->secbuf = sec->secbuf_base + sec->secbufp;
0264 
0265     for (n = 0; sec->secbufp + 2 < limit; n++) {
0266         seclen = section_length(sec->secbuf);
0267         if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
0268             || seclen + sec->secbufp > limit)
0269             return 0;
0270         sec->seclen = seclen;
0271         sec->crc_val = ~0;
0272         /* dump [secbuf .. secbuf+seclen) */
0273         if (feed->pusi_seen) {
0274             dvb_dmx_swfilter_section_feed(feed);
0275         } else {
0276             set_buf_flags(feed,
0277                       DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
0278             dprintk_sect_loss("pusi not seen, discarding section data\n");
0279         }
0280         sec->secbufp += seclen; /* secbufp and secbuf moving together is */
0281         sec->secbuf += seclen;  /* redundant but saves pointer arithmetic */
0282     }
0283 
0284     return 0;
0285 }
0286 
0287 static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
0288                        const u8 *buf)
0289 {
0290     u8 p, count;
0291     int ccok, dc_i = 0;
0292     u8 cc;
0293 
0294     count = payload(buf);
0295 
0296     if (count == 0)     /* count == 0 if no payload or out of range */
0297         return -1;
0298 
0299     p = 188 - count;    /* payload start */
0300 
0301     cc = buf[3] & 0x0f;
0302     ccok = ((feed->cc + 1) & 0x0f) == cc;
0303     feed->cc = cc;
0304 
0305     if (buf[3] & 0x20) {
0306         /* adaption field present, check for discontinuity_indicator */
0307         if ((buf[4] > 0) && (buf[5] & 0x80))
0308             dc_i = 1;
0309     }
0310 
0311     if (!ccok || dc_i) {
0312         if (dc_i) {
0313             set_buf_flags(feed,
0314                       DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR);
0315             dprintk_sect_loss("%d frame with disconnect indicator\n",
0316                 cc);
0317         } else {
0318             set_buf_flags(feed,
0319                       DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
0320             dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n",
0321                 cc, (feed->cc + 1) & 0x0f, count + 4);
0322         }
0323         /*
0324          * those bytes under some circumstances will again be reported
0325          * in the following dvb_dmx_swfilter_section_new
0326          */
0327 
0328         /*
0329          * Discontinuity detected. Reset pusi_seen to
0330          * stop feeding of suspicious data until next PUSI=1 arrives
0331          *
0332          * FIXME: does it make sense if the MPEG-TS is the one
0333          *  reporting discontinuity?
0334          */
0335 
0336         feed->pusi_seen = false;
0337         dvb_dmx_swfilter_section_new(feed);
0338     }
0339 
0340     if (buf[1] & 0x40) {
0341         /* PUSI=1 (is set), section boundary is here */
0342         if (count > 1 && buf[p] < count) {
0343             const u8 *before = &buf[p + 1];
0344             u8 before_len = buf[p];
0345             const u8 *after = &before[before_len];
0346             u8 after_len = count - 1 - before_len;
0347 
0348             dvb_dmx_swfilter_section_copy_dump(feed, before,
0349                                before_len);
0350             /* before start of new section, set pusi_seen */
0351             feed->pusi_seen = true;
0352             dvb_dmx_swfilter_section_new(feed);
0353             dvb_dmx_swfilter_section_copy_dump(feed, after,
0354                                after_len);
0355         } else if (count > 0) {
0356             set_buf_flags(feed,
0357                       DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
0358             dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count);
0359         }
0360     } else {
0361         /* PUSI=0 (is not set), no section boundary */
0362         dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
0363     }
0364 
0365     return 0;
0366 }
0367 
0368 static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
0369                         const u8 *buf)
0370 {
0371     switch (feed->type) {
0372     case DMX_TYPE_TS:
0373         if (!feed->feed.ts.is_filtering)
0374             break;
0375         if (feed->ts_type & TS_PACKET) {
0376             if (feed->ts_type & TS_PAYLOAD_ONLY)
0377                 dvb_dmx_swfilter_payload(feed, buf);
0378             else
0379                 feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
0380                         &feed->buffer_flags);
0381         }
0382         /* Used only on full-featured devices */
0383         if (feed->ts_type & TS_DECODER)
0384             if (feed->demux->write_to_decoder)
0385                 feed->demux->write_to_decoder(feed, buf, 188);
0386         break;
0387 
0388     case DMX_TYPE_SEC:
0389         if (!feed->feed.sec.is_filtering)
0390             break;
0391         if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
0392             feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
0393         break;
0394 
0395     default:
0396         break;
0397     }
0398 }
0399 
0400 #define DVR_FEED(f)                         \
0401     (((f)->type == DMX_TYPE_TS) &&                  \
0402     ((f)->feed.ts.is_filtering) &&                  \
0403     (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
0404 
0405 static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
0406 {
0407     struct dvb_demux_feed *feed;
0408     u16 pid = ts_pid(buf);
0409     int dvr_done = 0;
0410 
0411     if (dvb_demux_speedcheck) {
0412         ktime_t cur_time;
0413         u64 speed_bytes, speed_timedelta;
0414 
0415         demux->speed_pkts_cnt++;
0416 
0417         /* show speed every SPEED_PKTS_INTERVAL packets */
0418         if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
0419             cur_time = ktime_get();
0420 
0421             if (ktime_to_ns(demux->speed_last_time) != 0) {
0422                 speed_bytes = (u64)demux->speed_pkts_cnt
0423                     * 188 * 8;
0424                 /* convert to 1024 basis */
0425                 speed_bytes = 1000 * div64_u64(speed_bytes,
0426                         1024);
0427                 speed_timedelta = ktime_ms_delta(cur_time,
0428                             demux->speed_last_time);
0429                 if (speed_timedelta)
0430                     dprintk("TS speed %llu Kbits/sec \n",
0431                         div64_u64(speed_bytes,
0432                               speed_timedelta));
0433             }
0434 
0435             demux->speed_last_time = cur_time;
0436             demux->speed_pkts_cnt = 0;
0437         }
0438     }
0439 
0440     if (buf[1] & 0x80) {
0441         list_for_each_entry(feed, &demux->feed_list, list_head) {
0442             if ((feed->pid != pid) && (feed->pid != 0x2000))
0443                 continue;
0444             set_buf_flags(feed, DMX_BUFFER_FLAG_TEI);
0445         }
0446         dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
0447                 pid, buf[1]);
0448         /* data in this packet can't be trusted - drop it unless
0449          * module option dvb_demux_feed_err_pkts is set */
0450         if (!dvb_demux_feed_err_pkts)
0451             return;
0452     } else /* if TEI bit is set, pid may be wrong- skip pkt counter */
0453         if (demux->cnt_storage && dvb_demux_tscheck) {
0454             /* check pkt counter */
0455             if (pid < MAX_PID) {
0456                 if (buf[3] & 0x10)
0457                     demux->cnt_storage[pid] =
0458                         (demux->cnt_storage[pid] + 1) & 0xf;
0459 
0460                 if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
0461                     list_for_each_entry(feed, &demux->feed_list, list_head) {
0462                         if ((feed->pid != pid) && (feed->pid != 0x2000))
0463                             continue;
0464                         set_buf_flags(feed,
0465                                   DMX_BUFFER_PKT_COUNTER_MISMATCH);
0466                     }
0467 
0468                     dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
0469                             pid, demux->cnt_storage[pid],
0470                             buf[3] & 0xf);
0471                     demux->cnt_storage[pid] = buf[3] & 0xf;
0472                 }
0473             }
0474             /* end check */
0475         }
0476 
0477     list_for_each_entry(feed, &demux->feed_list, list_head) {
0478         if ((feed->pid != pid) && (feed->pid != 0x2000))
0479             continue;
0480 
0481         /* copy each packet only once to the dvr device, even
0482          * if a PID is in multiple filters (e.g. video + PCR) */
0483         if ((DVR_FEED(feed)) && (dvr_done++))
0484             continue;
0485 
0486         if (feed->pid == pid)
0487             dvb_dmx_swfilter_packet_type(feed, buf);
0488         else if (feed->pid == 0x2000)
0489             feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
0490                     &feed->buffer_flags);
0491     }
0492 }
0493 
0494 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
0495                   size_t count)
0496 {
0497     unsigned long flags;
0498 
0499     spin_lock_irqsave(&demux->lock, flags);
0500 
0501     while (count--) {
0502         if (buf[0] == 0x47)
0503             dvb_dmx_swfilter_packet(demux, buf);
0504         buf += 188;
0505     }
0506 
0507     spin_unlock_irqrestore(&demux->lock, flags);
0508 }
0509 
0510 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
0511 
0512 static inline int find_next_packet(const u8 *buf, int pos, size_t count,
0513                    const int pktsize)
0514 {
0515     int start = pos, lost;
0516 
0517     while (pos < count) {
0518         if (buf[pos] == 0x47 ||
0519             (pktsize == 204 && buf[pos] == 0xB8))
0520             break;
0521         pos++;
0522     }
0523 
0524     lost = pos - start;
0525     if (lost) {
0526         /* This garbage is part of a valid packet? */
0527         int backtrack = pos - pktsize;
0528         if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
0529             (pktsize == 204 && buf[backtrack] == 0xB8)))
0530             return backtrack;
0531     }
0532 
0533     return pos;
0534 }
0535 
0536 /* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
0537 static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
0538         size_t count, const int pktsize)
0539 {
0540     int p = 0, i, j;
0541     const u8 *q;
0542     unsigned long flags;
0543 
0544     spin_lock_irqsave(&demux->lock, flags);
0545 
0546     if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
0547         i = demux->tsbufp;
0548         j = pktsize - i;
0549         if (count < j) {
0550             memcpy(&demux->tsbuf[i], buf, count);
0551             demux->tsbufp += count;
0552             goto bailout;
0553         }
0554         memcpy(&demux->tsbuf[i], buf, j);
0555         if (demux->tsbuf[0] == 0x47) /* double check */
0556             dvb_dmx_swfilter_packet(demux, demux->tsbuf);
0557         demux->tsbufp = 0;
0558         p += j;
0559     }
0560 
0561     while (1) {
0562         p = find_next_packet(buf, p, count, pktsize);
0563         if (p >= count)
0564             break;
0565         if (count - p < pktsize)
0566             break;
0567 
0568         q = &buf[p];
0569 
0570         if (pktsize == 204 && (*q == 0xB8)) {
0571             memcpy(demux->tsbuf, q, 188);
0572             demux->tsbuf[0] = 0x47;
0573             q = demux->tsbuf;
0574         }
0575         dvb_dmx_swfilter_packet(demux, q);
0576         p += pktsize;
0577     }
0578 
0579     i = count - p;
0580     if (i) {
0581         memcpy(demux->tsbuf, &buf[p], i);
0582         demux->tsbufp = i;
0583         if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
0584             demux->tsbuf[0] = 0x47;
0585     }
0586 
0587 bailout:
0588     spin_unlock_irqrestore(&demux->lock, flags);
0589 }
0590 
0591 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
0592 {
0593     _dvb_dmx_swfilter(demux, buf, count, 188);
0594 }
0595 EXPORT_SYMBOL(dvb_dmx_swfilter);
0596 
0597 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
0598 {
0599     _dvb_dmx_swfilter(demux, buf, count, 204);
0600 }
0601 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
0602 
0603 void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
0604 {
0605     unsigned long flags;
0606 
0607     spin_lock_irqsave(&demux->lock, flags);
0608 
0609     demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts,
0610                &demux->feed->buffer_flags);
0611 
0612     spin_unlock_irqrestore(&demux->lock, flags);
0613 }
0614 EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
0615 
0616 static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
0617 {
0618     int i;
0619 
0620     for (i = 0; i < demux->filternum; i++)
0621         if (demux->filter[i].state == DMX_STATE_FREE)
0622             break;
0623 
0624     if (i == demux->filternum)
0625         return NULL;
0626 
0627     demux->filter[i].state = DMX_STATE_ALLOCATED;
0628 
0629     return &demux->filter[i];
0630 }
0631 
0632 static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
0633 {
0634     int i;
0635 
0636     for (i = 0; i < demux->feednum; i++)
0637         if (demux->feed[i].state == DMX_STATE_FREE)
0638             break;
0639 
0640     if (i == demux->feednum)
0641         return NULL;
0642 
0643     demux->feed[i].state = DMX_STATE_ALLOCATED;
0644 
0645     return &demux->feed[i];
0646 }
0647 
0648 static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
0649 {
0650     struct dvb_demux_feed *entry;
0651 
0652     list_for_each_entry(entry, &feed->demux->feed_list, list_head)
0653         if (entry == feed)
0654             return 1;
0655 
0656     return 0;
0657 }
0658 
0659 static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
0660 {
0661     spin_lock_irq(&feed->demux->lock);
0662     if (dvb_demux_feed_find(feed)) {
0663         pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n",
0664                __func__, feed->type, feed->state, feed->pid);
0665         goto out;
0666     }
0667 
0668     list_add(&feed->list_head, &feed->demux->feed_list);
0669 out:
0670     spin_unlock_irq(&feed->demux->lock);
0671 }
0672 
0673 static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
0674 {
0675     spin_lock_irq(&feed->demux->lock);
0676     if (!(dvb_demux_feed_find(feed))) {
0677         pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n",
0678                __func__, feed->type, feed->state, feed->pid);
0679         goto out;
0680     }
0681 
0682     list_del(&feed->list_head);
0683 out:
0684     spin_unlock_irq(&feed->demux->lock);
0685 }
0686 
0687 static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
0688                enum dmx_ts_pes pes_type, ktime_t timeout)
0689 {
0690     struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
0691     struct dvb_demux *demux = feed->demux;
0692 
0693     if (pid > DMX_MAX_PID)
0694         return -EINVAL;
0695 
0696     if (mutex_lock_interruptible(&demux->mutex))
0697         return -ERESTARTSYS;
0698 
0699     if (ts_type & TS_DECODER) {
0700         if (pes_type >= DMX_PES_OTHER) {
0701             mutex_unlock(&demux->mutex);
0702             return -EINVAL;
0703         }
0704 
0705         if (demux->pesfilter[pes_type] &&
0706             demux->pesfilter[pes_type] != feed) {
0707             mutex_unlock(&demux->mutex);
0708             return -EINVAL;
0709         }
0710 
0711         demux->pesfilter[pes_type] = feed;
0712         demux->pids[pes_type] = pid;
0713     }
0714 
0715     dvb_demux_feed_add(feed);
0716 
0717     feed->pid = pid;
0718     feed->timeout = timeout;
0719     feed->ts_type = ts_type;
0720     feed->pes_type = pes_type;
0721 
0722     feed->state = DMX_STATE_READY;
0723     mutex_unlock(&demux->mutex);
0724 
0725     return 0;
0726 }
0727 
0728 static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
0729 {
0730     struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
0731     struct dvb_demux *demux = feed->demux;
0732     int ret;
0733 
0734     if (mutex_lock_interruptible(&demux->mutex))
0735         return -ERESTARTSYS;
0736 
0737     if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
0738         mutex_unlock(&demux->mutex);
0739         return -EINVAL;
0740     }
0741 
0742     if (!demux->start_feed) {
0743         mutex_unlock(&demux->mutex);
0744         return -ENODEV;
0745     }
0746 
0747     if ((ret = demux->start_feed(feed)) < 0) {
0748         mutex_unlock(&demux->mutex);
0749         return ret;
0750     }
0751 
0752     spin_lock_irq(&demux->lock);
0753     ts_feed->is_filtering = 1;
0754     feed->state = DMX_STATE_GO;
0755     spin_unlock_irq(&demux->lock);
0756     mutex_unlock(&demux->mutex);
0757 
0758     return 0;
0759 }
0760 
0761 static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
0762 {
0763     struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
0764     struct dvb_demux *demux = feed->demux;
0765     int ret;
0766 
0767     mutex_lock(&demux->mutex);
0768 
0769     if (feed->state < DMX_STATE_GO) {
0770         mutex_unlock(&demux->mutex);
0771         return -EINVAL;
0772     }
0773 
0774     if (!demux->stop_feed) {
0775         mutex_unlock(&demux->mutex);
0776         return -ENODEV;
0777     }
0778 
0779     ret = demux->stop_feed(feed);
0780 
0781     spin_lock_irq(&demux->lock);
0782     ts_feed->is_filtering = 0;
0783     feed->state = DMX_STATE_ALLOCATED;
0784     spin_unlock_irq(&demux->lock);
0785     mutex_unlock(&demux->mutex);
0786 
0787     return ret;
0788 }
0789 
0790 static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
0791                    struct dmx_ts_feed **ts_feed,
0792                    dmx_ts_cb callback)
0793 {
0794     struct dvb_demux *demux = (struct dvb_demux *)dmx;
0795     struct dvb_demux_feed *feed;
0796 
0797     if (mutex_lock_interruptible(&demux->mutex))
0798         return -ERESTARTSYS;
0799 
0800     if (!(feed = dvb_dmx_feed_alloc(demux))) {
0801         mutex_unlock(&demux->mutex);
0802         return -EBUSY;
0803     }
0804 
0805     feed->type = DMX_TYPE_TS;
0806     feed->cb.ts = callback;
0807     feed->demux = demux;
0808     feed->pid = 0xffff;
0809     feed->peslen = 0xfffa;
0810     feed->buffer_flags = 0;
0811 
0812     (*ts_feed) = &feed->feed.ts;
0813     (*ts_feed)->parent = dmx;
0814     (*ts_feed)->priv = NULL;
0815     (*ts_feed)->is_filtering = 0;
0816     (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
0817     (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
0818     (*ts_feed)->set = dmx_ts_feed_set;
0819 
0820     if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
0821         feed->state = DMX_STATE_FREE;
0822         mutex_unlock(&demux->mutex);
0823         return -EBUSY;
0824     }
0825 
0826     feed->filter->type = DMX_TYPE_TS;
0827     feed->filter->feed = feed;
0828     feed->filter->state = DMX_STATE_READY;
0829 
0830     mutex_unlock(&demux->mutex);
0831 
0832     return 0;
0833 }
0834 
0835 static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
0836                   struct dmx_ts_feed *ts_feed)
0837 {
0838     struct dvb_demux *demux = (struct dvb_demux *)dmx;
0839     struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
0840 
0841     mutex_lock(&demux->mutex);
0842 
0843     if (feed->state == DMX_STATE_FREE) {
0844         mutex_unlock(&demux->mutex);
0845         return -EINVAL;
0846     }
0847 
0848     feed->state = DMX_STATE_FREE;
0849     feed->filter->state = DMX_STATE_FREE;
0850 
0851     dvb_demux_feed_del(feed);
0852 
0853     feed->pid = 0xffff;
0854 
0855     if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_PES_OTHER)
0856         demux->pesfilter[feed->pes_type] = NULL;
0857 
0858     mutex_unlock(&demux->mutex);
0859     return 0;
0860 }
0861 
0862 /******************************************************************************
0863  * dmx_section_feed API calls
0864  ******************************************************************************/
0865 
0866 static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
0867                         struct dmx_section_filter **filter)
0868 {
0869     struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
0870     struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
0871     struct dvb_demux_filter *dvbdmxfilter;
0872 
0873     if (mutex_lock_interruptible(&dvbdemux->mutex))
0874         return -ERESTARTSYS;
0875 
0876     dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
0877     if (!dvbdmxfilter) {
0878         mutex_unlock(&dvbdemux->mutex);
0879         return -EBUSY;
0880     }
0881 
0882     spin_lock_irq(&dvbdemux->lock);
0883     *filter = &dvbdmxfilter->filter;
0884     (*filter)->parent = feed;
0885     (*filter)->priv = NULL;
0886     dvbdmxfilter->feed = dvbdmxfeed;
0887     dvbdmxfilter->type = DMX_TYPE_SEC;
0888     dvbdmxfilter->state = DMX_STATE_READY;
0889     dvbdmxfilter->next = dvbdmxfeed->filter;
0890     dvbdmxfeed->filter = dvbdmxfilter;
0891     spin_unlock_irq(&dvbdemux->lock);
0892 
0893     mutex_unlock(&dvbdemux->mutex);
0894     return 0;
0895 }
0896 
0897 static int dmx_section_feed_set(struct dmx_section_feed *feed,
0898                 u16 pid, int check_crc)
0899 {
0900     struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
0901     struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
0902 
0903     if (pid > 0x1fff)
0904         return -EINVAL;
0905 
0906     if (mutex_lock_interruptible(&dvbdmx->mutex))
0907         return -ERESTARTSYS;
0908 
0909     dvb_demux_feed_add(dvbdmxfeed);
0910 
0911     dvbdmxfeed->pid = pid;
0912     dvbdmxfeed->feed.sec.check_crc = check_crc;
0913 
0914     dvbdmxfeed->state = DMX_STATE_READY;
0915     mutex_unlock(&dvbdmx->mutex);
0916     return 0;
0917 }
0918 
0919 static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
0920 {
0921     int i;
0922     struct dvb_demux_filter *f;
0923     struct dmx_section_filter *sf;
0924     u8 mask, mode, doneq;
0925 
0926     if (!(f = dvbdmxfeed->filter))
0927         return;
0928     do {
0929         sf = &f->filter;
0930         doneq = false;
0931         for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
0932             mode = sf->filter_mode[i];
0933             mask = sf->filter_mask[i];
0934             f->maskandmode[i] = mask & mode;
0935             doneq |= f->maskandnotmode[i] = mask & ~mode;
0936         }
0937         f->doneq = doneq ? true : false;
0938     } while ((f = f->next));
0939 }
0940 
0941 static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
0942 {
0943     struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
0944     struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
0945     int ret;
0946 
0947     if (mutex_lock_interruptible(&dvbdmx->mutex))
0948         return -ERESTARTSYS;
0949 
0950     if (feed->is_filtering) {
0951         mutex_unlock(&dvbdmx->mutex);
0952         return -EBUSY;
0953     }
0954 
0955     if (!dvbdmxfeed->filter) {
0956         mutex_unlock(&dvbdmx->mutex);
0957         return -EINVAL;
0958     }
0959 
0960     dvbdmxfeed->feed.sec.tsfeedp = 0;
0961     dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
0962     dvbdmxfeed->feed.sec.secbufp = 0;
0963     dvbdmxfeed->feed.sec.seclen = 0;
0964     dvbdmxfeed->pusi_seen = false;
0965 
0966     if (!dvbdmx->start_feed) {
0967         mutex_unlock(&dvbdmx->mutex);
0968         return -ENODEV;
0969     }
0970 
0971     prepare_secfilters(dvbdmxfeed);
0972 
0973     if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
0974         mutex_unlock(&dvbdmx->mutex);
0975         return ret;
0976     }
0977 
0978     spin_lock_irq(&dvbdmx->lock);
0979     feed->is_filtering = 1;
0980     dvbdmxfeed->state = DMX_STATE_GO;
0981     spin_unlock_irq(&dvbdmx->lock);
0982 
0983     mutex_unlock(&dvbdmx->mutex);
0984     return 0;
0985 }
0986 
0987 static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
0988 {
0989     struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
0990     struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
0991     int ret;
0992 
0993     mutex_lock(&dvbdmx->mutex);
0994 
0995     if (!dvbdmx->stop_feed) {
0996         mutex_unlock(&dvbdmx->mutex);
0997         return -ENODEV;
0998     }
0999 
1000     ret = dvbdmx->stop_feed(dvbdmxfeed);
1001 
1002     spin_lock_irq(&dvbdmx->lock);
1003     dvbdmxfeed->state = DMX_STATE_READY;
1004     feed->is_filtering = 0;
1005     spin_unlock_irq(&dvbdmx->lock);
1006 
1007     mutex_unlock(&dvbdmx->mutex);
1008     return ret;
1009 }
1010 
1011 static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
1012                        struct dmx_section_filter *filter)
1013 {
1014     struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
1015     struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
1016     struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
1017 
1018     mutex_lock(&dvbdmx->mutex);
1019 
1020     if (dvbdmxfilter->feed != dvbdmxfeed) {
1021         mutex_unlock(&dvbdmx->mutex);
1022         return -EINVAL;
1023     }
1024 
1025     if (feed->is_filtering) {
1026         /* release dvbdmx->mutex as far as it is
1027            acquired by stop_filtering() itself */
1028         mutex_unlock(&dvbdmx->mutex);
1029         feed->stop_filtering(feed);
1030         mutex_lock(&dvbdmx->mutex);
1031     }
1032 
1033     spin_lock_irq(&dvbdmx->lock);
1034     f = dvbdmxfeed->filter;
1035 
1036     if (f == dvbdmxfilter) {
1037         dvbdmxfeed->filter = dvbdmxfilter->next;
1038     } else {
1039         while (f->next != dvbdmxfilter)
1040             f = f->next;
1041         f->next = f->next->next;
1042     }
1043 
1044     dvbdmxfilter->state = DMX_STATE_FREE;
1045     spin_unlock_irq(&dvbdmx->lock);
1046     mutex_unlock(&dvbdmx->mutex);
1047     return 0;
1048 }
1049 
1050 static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
1051                     struct dmx_section_feed **feed,
1052                     dmx_section_cb callback)
1053 {
1054     struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
1055     struct dvb_demux_feed *dvbdmxfeed;
1056 
1057     if (mutex_lock_interruptible(&dvbdmx->mutex))
1058         return -ERESTARTSYS;
1059 
1060     if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
1061         mutex_unlock(&dvbdmx->mutex);
1062         return -EBUSY;
1063     }
1064 
1065     dvbdmxfeed->type = DMX_TYPE_SEC;
1066     dvbdmxfeed->cb.sec = callback;
1067     dvbdmxfeed->demux = dvbdmx;
1068     dvbdmxfeed->pid = 0xffff;
1069     dvbdmxfeed->buffer_flags = 0;
1070     dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
1071     dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
1072     dvbdmxfeed->feed.sec.tsfeedp = 0;
1073     dvbdmxfeed->filter = NULL;
1074 
1075     (*feed) = &dvbdmxfeed->feed.sec;
1076     (*feed)->is_filtering = 0;
1077     (*feed)->parent = demux;
1078     (*feed)->priv = NULL;
1079 
1080     (*feed)->set = dmx_section_feed_set;
1081     (*feed)->allocate_filter = dmx_section_feed_allocate_filter;
1082     (*feed)->start_filtering = dmx_section_feed_start_filtering;
1083     (*feed)->stop_filtering = dmx_section_feed_stop_filtering;
1084     (*feed)->release_filter = dmx_section_feed_release_filter;
1085 
1086     mutex_unlock(&dvbdmx->mutex);
1087     return 0;
1088 }
1089 
1090 static int dvbdmx_release_section_feed(struct dmx_demux *demux,
1091                        struct dmx_section_feed *feed)
1092 {
1093     struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
1094     struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
1095 
1096     mutex_lock(&dvbdmx->mutex);
1097 
1098     if (dvbdmxfeed->state == DMX_STATE_FREE) {
1099         mutex_unlock(&dvbdmx->mutex);
1100         return -EINVAL;
1101     }
1102     dvbdmxfeed->state = DMX_STATE_FREE;
1103 
1104     dvb_demux_feed_del(dvbdmxfeed);
1105 
1106     dvbdmxfeed->pid = 0xffff;
1107 
1108     mutex_unlock(&dvbdmx->mutex);
1109     return 0;
1110 }
1111 
1112 /******************************************************************************
1113  * dvb_demux kernel data API calls
1114  ******************************************************************************/
1115 
1116 static int dvbdmx_open(struct dmx_demux *demux)
1117 {
1118     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1119 
1120     if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
1121         return -EUSERS;
1122 
1123     dvbdemux->users++;
1124     return 0;
1125 }
1126 
1127 static int dvbdmx_close(struct dmx_demux *demux)
1128 {
1129     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1130 
1131     if (dvbdemux->users == 0)
1132         return -ENODEV;
1133 
1134     dvbdemux->users--;
1135     //FIXME: release any unneeded resources if users==0
1136     return 0;
1137 }
1138 
1139 static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
1140 {
1141     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1142     void *p;
1143 
1144     if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
1145         return -EINVAL;
1146 
1147     p = memdup_user(buf, count);
1148     if (IS_ERR(p))
1149         return PTR_ERR(p);
1150     if (mutex_lock_interruptible(&dvbdemux->mutex)) {
1151         kfree(p);
1152         return -ERESTARTSYS;
1153     }
1154     dvb_dmx_swfilter(dvbdemux, p, count);
1155     kfree(p);
1156     mutex_unlock(&dvbdemux->mutex);
1157 
1158     if (signal_pending(current))
1159         return -EINTR;
1160     return count;
1161 }
1162 
1163 static int dvbdmx_add_frontend(struct dmx_demux *demux,
1164                    struct dmx_frontend *frontend)
1165 {
1166     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1167     struct list_head *head = &dvbdemux->frontend_list;
1168 
1169     list_add(&(frontend->connectivity_list), head);
1170 
1171     return 0;
1172 }
1173 
1174 static int dvbdmx_remove_frontend(struct dmx_demux *demux,
1175                   struct dmx_frontend *frontend)
1176 {
1177     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1178     struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
1179 
1180     list_for_each_safe(pos, n, head) {
1181         if (DMX_FE_ENTRY(pos) == frontend) {
1182             list_del(pos);
1183             return 0;
1184         }
1185     }
1186 
1187     return -ENODEV;
1188 }
1189 
1190 static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
1191 {
1192     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1193 
1194     if (list_empty(&dvbdemux->frontend_list))
1195         return NULL;
1196 
1197     return &dvbdemux->frontend_list;
1198 }
1199 
1200 static int dvbdmx_connect_frontend(struct dmx_demux *demux,
1201                    struct dmx_frontend *frontend)
1202 {
1203     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1204 
1205     if (demux->frontend)
1206         return -EINVAL;
1207 
1208     mutex_lock(&dvbdemux->mutex);
1209 
1210     demux->frontend = frontend;
1211     mutex_unlock(&dvbdemux->mutex);
1212     return 0;
1213 }
1214 
1215 static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
1216 {
1217     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1218 
1219     mutex_lock(&dvbdemux->mutex);
1220 
1221     demux->frontend = NULL;
1222     mutex_unlock(&dvbdemux->mutex);
1223     return 0;
1224 }
1225 
1226 static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
1227 {
1228     struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
1229 
1230     memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
1231     return 0;
1232 }
1233 
1234 int dvb_dmx_init(struct dvb_demux *dvbdemux)
1235 {
1236     int i;
1237     struct dmx_demux *dmx = &dvbdemux->dmx;
1238 
1239     dvbdemux->cnt_storage = NULL;
1240     dvbdemux->users = 0;
1241     dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter),
1242                           dvbdemux->filternum));
1243 
1244     if (!dvbdemux->filter)
1245         return -ENOMEM;
1246 
1247     dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed),
1248                         dvbdemux->feednum));
1249     if (!dvbdemux->feed) {
1250         vfree(dvbdemux->filter);
1251         dvbdemux->filter = NULL;
1252         return -ENOMEM;
1253     }
1254     for (i = 0; i < dvbdemux->filternum; i++) {
1255         dvbdemux->filter[i].state = DMX_STATE_FREE;
1256         dvbdemux->filter[i].index = i;
1257     }
1258     for (i = 0; i < dvbdemux->feednum; i++) {
1259         dvbdemux->feed[i].state = DMX_STATE_FREE;
1260         dvbdemux->feed[i].index = i;
1261     }
1262 
1263     dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
1264     if (!dvbdemux->cnt_storage)
1265         pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n");
1266 
1267     INIT_LIST_HEAD(&dvbdemux->frontend_list);
1268 
1269     for (i = 0; i < DMX_PES_OTHER; i++) {
1270         dvbdemux->pesfilter[i] = NULL;
1271         dvbdemux->pids[i] = 0xffff;
1272     }
1273 
1274     INIT_LIST_HEAD(&dvbdemux->feed_list);
1275 
1276     dvbdemux->playing = 0;
1277     dvbdemux->recording = 0;
1278     dvbdemux->tsbufp = 0;
1279 
1280     if (!dvbdemux->check_crc32)
1281         dvbdemux->check_crc32 = dvb_dmx_crc32;
1282 
1283     if (!dvbdemux->memcopy)
1284         dvbdemux->memcopy = dvb_dmx_memcopy;
1285 
1286     dmx->frontend = NULL;
1287     dmx->priv = dvbdemux;
1288     dmx->open = dvbdmx_open;
1289     dmx->close = dvbdmx_close;
1290     dmx->write = dvbdmx_write;
1291     dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
1292     dmx->release_ts_feed = dvbdmx_release_ts_feed;
1293     dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
1294     dmx->release_section_feed = dvbdmx_release_section_feed;
1295 
1296     dmx->add_frontend = dvbdmx_add_frontend;
1297     dmx->remove_frontend = dvbdmx_remove_frontend;
1298     dmx->get_frontends = dvbdmx_get_frontends;
1299     dmx->connect_frontend = dvbdmx_connect_frontend;
1300     dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
1301     dmx->get_pes_pids = dvbdmx_get_pes_pids;
1302 
1303     mutex_init(&dvbdemux->mutex);
1304     spin_lock_init(&dvbdemux->lock);
1305 
1306     return 0;
1307 }
1308 
1309 EXPORT_SYMBOL(dvb_dmx_init);
1310 
1311 void dvb_dmx_release(struct dvb_demux *dvbdemux)
1312 {
1313     vfree(dvbdemux->cnt_storage);
1314     vfree(dvbdemux->filter);
1315     vfree(dvbdemux->feed);
1316 }
1317 
1318 EXPORT_SYMBOL(dvb_dmx_release);