aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Oberritter <obi@linuxtv.org>2009-07-14 19:28:50 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-12 11:17:43 -0400
commit1cb662a3144992259edfd3cf9f54a6b25a913a0f (patch)
treedc3336680a9a3a143bac1056aae51315c3cec68f
parenta98f6af96ec5b22453054b36eaa325ebf20ea429 (diff)
V4L/DVB (12275): Add two new ioctls: DMX_ADD_PID and DMX_REMOVE_PID
DMX_ADD_PID allows to add multiple PIDs to a transport stream filter previously set up with DMX_SET_PES_FILTER and output=DMX_OUT_TSDEMUX_TAP. DMX_REMOVE_PID is used to drop a PID from a filter. These ioctls are to be used by readers of /dev/dvb/adapterX/demuxY. They may be called at any time, i.e. before or after the first filter on the shared file descriptor was started. They make it possible to record multiple services without the need to de- or re-multiplex TS packets. To accomplish this, dmxdev_filter->feed.ts has been converted to a list of struct dmxdev_feeds, each containing a PID value and a pointer to a struct dmx_ts_feed. Signed-off-by: Andreas Oberritter <obi@linuxtv.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-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_*/