aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c231
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.h9
-rw-r--r--include/linux/dvb/dmx.h2
3 files changed, 184 insertions, 58 deletions
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 6d6121eb5d59..3750ff48cba1 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -430,6 +430,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
430/* stop feed but only mark the specified filter as stopped (state set) */ 430/* stop feed but only mark the specified filter as stopped (state set) */
431static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) 431static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
432{ 432{
433 struct dmxdev_feed *feed;
434
433 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); 435 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
434 436
435 switch (dmxdevfilter->type) { 437 switch (dmxdevfilter->type) {
@@ -438,7 +440,8 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
438 dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); 440 dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
439 break; 441 break;
440 case DMXDEV_TYPE_PES: 442 case DMXDEV_TYPE_PES:
441 dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts); 443 list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
444 feed->ts->stop_filtering(feed->ts);
442 break; 445 break;
443 default: 446 default:
444 return -EINVAL; 447 return -EINVAL;
@@ -449,13 +452,23 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
449/* start feed associated with the specified filter */ 452/* start feed associated with the specified filter */
450static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) 453static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
451{ 454{
455 struct dmxdev_feed *feed;
456 int ret;
457
452 dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); 458 dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
453 459
454 switch (filter->type) { 460 switch (filter->type) {
455 case DMXDEV_TYPE_SEC: 461 case DMXDEV_TYPE_SEC:
456 return filter->feed.sec->start_filtering(filter->feed.sec); 462 return filter->feed.sec->start_filtering(filter->feed.sec);
457 case DMXDEV_TYPE_PES: 463 case DMXDEV_TYPE_PES:
458 return filter->feed.ts->start_filtering(filter->feed.ts); 464 list_for_each_entry(feed, &filter->feed.ts, next) {
465 ret = feed->ts->start_filtering(feed->ts);
466 if (ret < 0) {
467 dvb_dmxdev_feed_stop(filter);
468 return ret;
469 }
470 }
471 break;
459 default: 472 default:
460 return -EINVAL; 473 return -EINVAL;
461 } 474 }
@@ -487,6 +500,9 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
487 500
488static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) 501static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
489{ 502{
503 struct dmxdev_feed *feed;
504 struct dmx_demux *demux;
505
490 if (dmxdevfilter->state < DMXDEV_STATE_GO) 506 if (dmxdevfilter->state < DMXDEV_STATE_GO)
491 return 0; 507 return 0;
492 508
@@ -503,13 +519,12 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
503 dmxdevfilter->feed.sec = NULL; 519 dmxdevfilter->feed.sec = NULL;
504 break; 520 break;
505 case DMXDEV_TYPE_PES: 521 case DMXDEV_TYPE_PES:
506 if (!dmxdevfilter->feed.ts)
507 break;
508 dvb_dmxdev_feed_stop(dmxdevfilter); 522 dvb_dmxdev_feed_stop(dmxdevfilter);
509 dmxdevfilter->dev->demux-> 523 demux = dmxdevfilter->dev->demux;
510 release_ts_feed(dmxdevfilter->dev->demux, 524 list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
511 dmxdevfilter->feed.ts); 525 demux->release_ts_feed(demux, feed->ts);
512 dmxdevfilter->feed.ts = NULL; 526 feed->ts = NULL;
527 }
513 break; 528 break;
514 default: 529 default:
515 if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) 530 if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
@@ -521,19 +536,88 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
521 return 0; 536 return 0;
522} 537}
523 538
539static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
540{
541 struct dmxdev_feed *feed, *tmp;
542
543 /* delete all PIDs */
544 list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
545 list_del(&feed->next);
546 kfree(feed);
547 }
548
549 BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
550}
551
524static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) 552static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
525{ 553{
526 if (dmxdevfilter->state < DMXDEV_STATE_SET) 554 if (dmxdevfilter->state < DMXDEV_STATE_SET)
527 return 0; 555 return 0;
528 556
557 if (dmxdevfilter->type == DMXDEV_TYPE_PES)
558 dvb_dmxdev_delete_pids(dmxdevfilter);
559
529 dmxdevfilter->type = DMXDEV_TYPE_NONE; 560 dmxdevfilter->type = DMXDEV_TYPE_NONE;
530 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); 561 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
531 return 0; 562 return 0;
532} 563}
533 564
565static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
566 struct dmxdev_filter *filter,
567 struct dmxdev_feed *feed)
568{
569 struct timespec timeout = { 0 };
570 struct dmx_pes_filter_params *para = &filter->params.pes;
571 dmx_output_t otype;
572 int ret;
573 int ts_type;
574 enum dmx_ts_pes ts_pes;
575 struct dmx_ts_feed *tsfeed;
576
577 feed->ts = NULL;
578 otype = para->output;
579
580 ts_pes = (enum dmx_ts_pes)para->pes_type;
581
582 if (ts_pes < DMX_PES_OTHER)
583 ts_type = TS_DECODER;
584 else
585 ts_type = 0;
586
587 if (otype == DMX_OUT_TS_TAP)
588 ts_type |= TS_PACKET;
589 else if (otype == DMX_OUT_TSDEMUX_TAP)
590 ts_type |= TS_PACKET | TS_DEMUX;
591 else if (otype == DMX_OUT_TAP)
592 ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
593
594 ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
595 dvb_dmxdev_ts_callback);
596 if (ret < 0)
597 return ret;
598
599 tsfeed = feed->ts;
600 tsfeed->priv = filter;
601
602 ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
603 if (ret < 0) {
604 dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
605 return ret;
606 }
607
608 ret = tsfeed->start_filtering(tsfeed);
609 if (ret < 0) {
610 dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
611 return ret;
612 }
613
614 return 0;
615}
616
534static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) 617static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
535{ 618{
536 struct dmxdev *dmxdev = filter->dev; 619 struct dmxdev *dmxdev = filter->dev;
620 struct dmxdev_feed *feed;
537 void *mem; 621 void *mem;
538 int ret, i; 622 int ret, i;
539 623
@@ -631,56 +715,14 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
631 break; 715 break;
632 } 716 }
633 case DMXDEV_TYPE_PES: 717 case DMXDEV_TYPE_PES:
634 { 718 list_for_each_entry(feed, &filter->feed.ts, next) {
635 struct timespec timeout = { 0 }; 719 ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
636 struct dmx_pes_filter_params *para = &filter->params.pes; 720 if (ret < 0) {
637 dmx_output_t otype; 721 dvb_dmxdev_filter_stop(filter);
638 int ts_type; 722 return ret;
639 enum dmx_ts_pes ts_pes; 723 }
640 struct dmx_ts_feed **tsfeed = &filter->feed.ts;
641
642 filter->feed.ts = NULL;
643 otype = para->output;
644
645 ts_pes = (enum dmx_ts_pes)para->pes_type;
646
647 if (ts_pes < DMX_PES_OTHER)
648 ts_type = TS_DECODER;
649 else
650 ts_type = 0;
651
652 if (otype == DMX_OUT_TS_TAP)
653 ts_type |= TS_PACKET;
654 else if (otype == DMX_OUT_TSDEMUX_TAP)
655 ts_type |= TS_PACKET | TS_DEMUX;
656 else if (otype == DMX_OUT_TAP)
657 ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
658
659 ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
660 tsfeed,
661 dvb_dmxdev_ts_callback);
662 if (ret < 0)
663 return ret;
664
665 (*tsfeed)->priv = filter;
666
667 ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
668 32768, timeout);
669 if (ret < 0) {
670 dmxdev->demux->release_ts_feed(dmxdev->demux,
671 *tsfeed);
672 return ret;
673 }
674
675 ret = filter->feed.ts->start_filtering(filter->feed.ts);
676 if (ret < 0) {
677 dmxdev->demux->release_ts_feed(dmxdev->demux,
678 *tsfeed);
679 return ret;
680 } 724 }
681
682 break; 725 break;
683 }
684 default: 726 default:
685 return -EINVAL; 727 return -EINVAL;
686 } 728 }
@@ -718,7 +760,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
718 dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); 760 dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
719 dmxdevfilter->type = DMXDEV_TYPE_NONE; 761 dmxdevfilter->type = DMXDEV_TYPE_NONE;
720 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); 762 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
721 dmxdevfilter->feed.ts = NULL; 763 INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
722 init_timer(&dmxdevfilter->timer); 764 init_timer(&dmxdevfilter->timer);
723 765
724 dvbdev->users++; 766 dvbdev->users++;
@@ -760,6 +802,55 @@ static inline void invert_mode(dmx_filter_t *filter)
760 filter->mode[i] ^= 0xff; 802 filter->mode[i] ^= 0xff;
761} 803}
762 804
805static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
806 struct dmxdev_filter *filter, u16 pid)
807{
808 struct dmxdev_feed *feed;
809
810 if ((filter->type != DMXDEV_TYPE_PES) ||
811 (filter->state < DMXDEV_STATE_SET))
812 return -EINVAL;
813
814 /* only TS packet filters may have multiple PIDs */
815 if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
816 (!list_empty(&filter->feed.ts)))
817 return -EINVAL;
818
819 feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
820 if (feed == NULL)
821 return -ENOMEM;
822
823 feed->pid = pid;
824 list_add(&feed->next, &filter->feed.ts);
825
826 if (filter->state >= DMXDEV_STATE_GO)
827 return dvb_dmxdev_start_feed(dmxdev, filter, feed);
828
829 return 0;
830}
831
832static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
833 struct dmxdev_filter *filter, u16 pid)
834{
835 struct dmxdev_feed *feed, *tmp;
836
837 if ((filter->type != DMXDEV_TYPE_PES) ||
838 (filter->state < DMXDEV_STATE_SET))
839 return -EINVAL;
840
841 list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
842 if ((feed->pid == pid) && (feed->ts != NULL)) {
843 feed->ts->stop_filtering(feed->ts);
844 filter->dev->demux->release_ts_feed(filter->dev->demux,
845 feed->ts);
846 list_del(&feed->next);
847 kfree(feed);
848 }
849 }
850
851 return 0;
852}
853
763static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, 854static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
764 struct dmxdev_filter *dmxdevfilter, 855 struct dmxdev_filter *dmxdevfilter,
765 struct dmx_sct_filter_params *params) 856 struct dmx_sct_filter_params *params)
@@ -784,7 +875,10 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
784 struct dmxdev_filter *dmxdevfilter, 875 struct dmxdev_filter *dmxdevfilter,
785 struct dmx_pes_filter_params *params) 876 struct dmx_pes_filter_params *params)
786{ 877{
878 int ret;
879
787 dvb_dmxdev_filter_stop(dmxdevfilter); 880 dvb_dmxdev_filter_stop(dmxdevfilter);
881 dvb_dmxdev_filter_reset(dmxdevfilter);
788 882
789 if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) 883 if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
790 return -EINVAL; 884 return -EINVAL;
@@ -795,6 +889,11 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
795 889
796 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); 890 dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
797 891
892 ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
893 dmxdevfilter->params.pes.pid);
894 if (ret < 0)
895 return ret;
896
798 if (params->flags & DMX_IMMEDIATE_START) 897 if (params->flags & DMX_IMMEDIATE_START)
799 return dvb_dmxdev_filter_start(dmxdevfilter); 898 return dvb_dmxdev_filter_start(dmxdevfilter);
800 899
@@ -958,6 +1057,24 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
958 &((struct dmx_stc *)parg)->base); 1057 &((struct dmx_stc *)parg)->base);
959 break; 1058 break;
960 1059
1060 case DMX_ADD_PID:
1061 if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
1062 ret = -ERESTARTSYS;
1063 break;
1064 }
1065 ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
1066 mutex_unlock(&dmxdevfilter->mutex);
1067 break;
1068
1069 case DMX_REMOVE_PID:
1070 if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
1071 ret = -ERESTARTSYS;
1072 break;
1073 }
1074 ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
1075 mutex_unlock(&dmxdevfilter->mutex);
1076 break;
1077
961 default: 1078 default:
962 ret = -EINVAL; 1079 ret = -EINVAL;
963 break; 1080 break;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
index 29746e70d325..c1379b56dfb4 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.h
+++ b/drivers/media/dvb/dvb-core/dmxdev.h
@@ -53,13 +53,20 @@ enum dmxdev_state {
53 DMXDEV_STATE_TIMEDOUT 53 DMXDEV_STATE_TIMEDOUT
54}; 54};
55 55
56struct dmxdev_feed {
57 u16 pid;
58 struct dmx_ts_feed *ts;
59 struct list_head next;
60};
61
56struct dmxdev_filter { 62struct dmxdev_filter {
57 union { 63 union {
58 struct dmx_section_filter *sec; 64 struct dmx_section_filter *sec;
59 } filter; 65 } filter;
60 66
61 union { 67 union {
62 struct dmx_ts_feed *ts; 68 /* list of TS and PES feeds (struct dmxdev_feed) */
69 struct list_head ts;
63 struct dmx_section_feed *sec; 70 struct dmx_section_feed *sec;
64 } feed; 71 } feed;
65 72
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index fef943738a24..f078f3ac82d4 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -151,5 +151,7 @@ struct dmx_stc {
151#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t) 151#define DMX_GET_CAPS _IOR('o', 48, dmx_caps_t)
152#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t) 152#define DMX_SET_SOURCE _IOW('o', 49, dmx_source_t)
153#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc) 153#define DMX_GET_STC _IOWR('o', 50, struct dmx_stc)
154#define DMX_ADD_PID _IOW('o', 51, __u16)
155#define DMX_REMOVE_PID _IOW('o', 52, __u16)
154 156
155#endif /*_DVBDMX_H_*/ 157#endif /*_DVBDMX_H_*/