From d0abf313caa5b78fc668d41ebe08b97bc29f001e Mon Sep 17 00:00:00 2001 From: Hamad Kadmany Date: Mon, 13 May 2013 18:56:06 +0300 Subject: [PATCH] media: dvb: Add support for monitoring scrambling bits Query of scrambling bits and notification when these change are required by some applications. Change-Id: If39dccb712c6bb14f2e277c8919eb34798f84146 Signed-off-by: Hamad Kadmany --- drivers/media/dvb/dvb-core/demux.h | 6 ++- drivers/media/dvb/dvb-core/dmxdev.c | 69 +++++++++++++++++++++++- drivers/media/dvb/dvb-core/dvb_demux.c | 73 ++++++++++++++++++++++++++ drivers/media/dvb/dvb-core/dvb_demux.h | 2 + include/linux/dvb/dmx.h | 45 ++++++++++++++-- 5 files changed, 187 insertions(+), 8 deletions(-) diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h index fcade49b2c5..2c2b33953be 100644 --- a/drivers/media/dvb/dvb-core/demux.h +++ b/drivers/media/dvb/dvb-core/demux.h @@ -75,7 +75,8 @@ enum dmx_success { DMX_FIFO_ERROR, /* Receiver FIFO overrun */ DMX_MISSED_ERROR, /* Receiver missed packet */ DMX_OK_DECODER_BUF, /* Received OK, new ES data in decoder buffer */ - DMX_OK_IDX /* Received OK, new index event */ + DMX_OK_IDX, /* Received OK, new index event */ + DMX_OK_SCRAMBLING_STATUS, /* Received OK, new scrambling status */ } ; @@ -135,6 +136,7 @@ struct dmx_data_ready { } marker; struct dmx_index_event_info idx_event; + struct dmx_scrambling_status_event_info scrambling_bits; }; }; @@ -250,6 +252,7 @@ struct dmx_ts_feed { int (*ts_insertion_terminate)(struct dmx_ts_feed *feed); int (*ts_insertion_insert_buffer)(struct dmx_ts_feed *feed, char *data, size_t size); + int (*get_scrambling_bits)(struct dmx_ts_feed *feed, u8 *value); }; /*--------------------------------------------------------------------------*/ @@ -300,6 +303,7 @@ struct dmx_section_feed { struct dmx_secure_mode *sec_mode); int (*oob_command) (struct dmx_section_feed *feed, struct dmx_oob_command *cmd); + int (*get_scrambling_bits)(struct dmx_section_feed *feed, u8 *value); }; /*--------------------------------------------------------------------------*/ diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 2a750a6cc12..6734da82a87 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -1796,6 +1796,35 @@ static int dvb_dmxdev_set_indexing_params(struct dmxdev_filter *dmxdevfilter, return 0; } +static int dvb_dmxdev_get_scrambling_bits(struct dmxdev_filter *filter, + struct dmx_scrambling_bits *scrambling_bits) +{ + struct dmxdev_feed *feed; + + if (!scrambling_bits || + (filter->state != DMXDEV_STATE_GO)) + return -EINVAL; + + if (filter->type == DMXDEV_TYPE_SEC) { + if (filter->feed.sec.feed->get_scrambling_bits) + return filter->feed.sec.feed->get_scrambling_bits( + filter->feed.sec.feed, + &scrambling_bits->value); + return -EINVAL; + } + + list_for_each_entry(feed, &filter->feed.ts, next) { + if (feed->pid == scrambling_bits->pid) { + if (feed->ts->get_scrambling_bits) + return feed->ts->get_scrambling_bits(feed->ts, + &scrambling_bits->value); + return -EINVAL; + } + } + + return -EINVAL; +} + static void dvb_dmxdev_ts_insertion_work(struct work_struct *worker) { struct ts_insertion_buffer *ts_buffer = @@ -2519,6 +2548,13 @@ static int dvb_dmxdev_section_event_cb(struct dmx_section_filter *filter, dvb_dmxdev_add_event(&dmxdevfilter->events, &event); spin_unlock(&dmxdevfilter->dev->lock); wake_up_all(&dmxdevfilter->buffer.queue); + } else if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) { + event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE; + event.params.scrambling_status = + dmx_data_ready->scrambling_bits; + dvb_dmxdev_add_event(&dmxdevfilter->events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&dmxdevfilter->buffer.queue); } else { spin_unlock(&dmxdevfilter->dev->lock); } @@ -2635,6 +2671,16 @@ static int dvb_dmxdev_ts_event_cb(struct dmx_ts_feed *feed, return 0; } + if (dmx_data_ready->status == DMX_OK_SCRAMBLING_STATUS) { + event.type = DMX_EVENT_SCRAMBLING_STATUS_CHANGE; + event.params.scrambling_status = + dmx_data_ready->scrambling_bits; + dvb_dmxdev_add_event(events, &event); + spin_unlock(&dmxdevfilter->dev->lock); + wake_up_all(&buffer->queue); + return 0; + } + if (dmx_data_ready->status == DMX_OK_DECODER_BUF) { event.type = DMX_EVENT_NEW_ES_DATA; event.params.es_data.buf_handle = dmx_data_ready->buf.handle; @@ -3938,6 +3984,15 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; + case DMX_GET_SCRAMBLING_BITS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_dmxdev_get_scrambling_bits(dmxdevfilter, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + default: ret = -EINVAL; break; @@ -4193,6 +4248,7 @@ static int dvb_dmxdev_dbgfs_print(struct seq_file *s, void *p) struct dmxdev_filter *filter; int active_count = 0; struct dmx_buffer_status buffer_status; + struct dmx_scrambling_bits scrambling_bits; const char *pes_feeds[] = {"DEC", "PES", "DVR", "REC"}; if (!dmxdev) @@ -4209,23 +4265,32 @@ static int dvb_dmxdev_dbgfs_print(struct seq_file *s, void *p) seq_printf(s, "type: SEC, "); seq_printf(s, "PID %04d ", filter->params.sec.pid); + scrambling_bits.pid = filter->params.sec.pid; } else { seq_printf(s, "type: %s, ", pes_feeds[filter->params.pes.output]); seq_printf(s, "PID: %04d ", filter->params.pes.pid); + scrambling_bits.pid = filter->params.pes.pid; } + dvb_dmxdev_get_scrambling_bits(filter, + &scrambling_bits); + if (0 == dvb_dmxdev_get_buffer_status( filter, &buffer_status)) { seq_printf(s, "size: %08d, ", buffer_status.size); seq_printf(s, "fullness: %08d, ", buffer_status.fullness); - seq_printf(s, "error: %d\n", + seq_printf(s, "error: %d, ", buffer_status.error); + seq_printf(s, "scramble: %d\n", + scrambling_bits.value); + } else { - seq_printf(s, "\n"); + seq_printf(s, "scramble: %d\n", + scrambling_bits.value); } } } diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 939d591ae46..62d2bfd2de4 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -164,6 +164,11 @@ static inline u16 ts_pid(const u8 *buf) return ((buf[1] & 0x1f) << 8) + buf[2]; } +static inline u16 ts_scrambling_ctrl(const u8 *buf) +{ + return (buf[3] >> 6) & 0x3; +} + static inline u8 payload(const u8 *tsp) { if (!(tsp[3] & 0x10)) // no payload? @@ -1284,6 +1289,32 @@ static inline int dvb_dmx_swfilter_buffer_check( static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, const u8 *buf, const u8 timestamp[TIMESTAMP_LEN]) { + u16 pid = ts_pid(buf); + u8 scrambling_bits = ts_scrambling_ctrl(buf); + struct dmx_data_ready dmx_data_ready; + + /* + * Notify on scrambling status change only when we move + * from clear (0) to non-clear and vise-versa + */ + if ((scrambling_bits && !feed->scrambling_bits) || + (!scrambling_bits && feed->scrambling_bits)) { + dmx_data_ready.status = DMX_OK_SCRAMBLING_STATUS; + dmx_data_ready.data_length = 0; + dmx_data_ready.scrambling_bits.pid = pid; + dmx_data_ready.scrambling_bits.old_value = + feed->scrambling_bits; + dmx_data_ready.scrambling_bits.new_value = scrambling_bits; + + if (feed->type == DMX_TYPE_SEC) + feed->data_ready_cb.sec(&feed->filter->filter, + &dmx_data_ready); + else + feed->data_ready_cb.ts(&feed->feed.ts, &dmx_data_ready); + } + + feed->scrambling_bits = scrambling_bits; + switch (feed->type) { case DMX_TYPE_TS: if (!feed->feed.ts.is_filtering) @@ -2044,6 +2075,7 @@ static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) } feed->first_cc = 1; + feed->scrambling_bits = 0; if ((feed->ts_type & TS_PACKET) && !(feed->ts_type & TS_PAYLOAD_ONLY)) { @@ -2331,6 +2363,25 @@ static int dvbdmx_ts_feed_oob_cmd(struct dmx_ts_feed *ts_feed, return ret; } +static int dvbdmx_ts_get_scrambling_bits(struct dmx_ts_feed *ts_feed, + u8 *value) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; + struct dvb_demux *demux = feed->demux; + + spin_lock(&demux->lock); + + if (!ts_feed->is_filtering) { + spin_unlock(&demux->lock); + return -EINVAL; + } + + *value = feed->scrambling_bits; + spin_unlock(&demux->lock); + + return 0; +} + static int dvbdmx_ts_insertion_insert_buffer(struct dmx_ts_feed *ts_feed, char *data, size_t size) { @@ -2420,6 +2471,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, (*ts_feed)->notify_data_read = NULL; (*ts_feed)->set_secure_mode = dmx_ts_set_secure_mode; (*ts_feed)->oob_command = dvbdmx_ts_feed_oob_cmd; + (*ts_feed)->get_scrambling_bits = dvbdmx_ts_get_scrambling_bits; (*ts_feed)->ts_insertion_init = NULL; (*ts_feed)->ts_insertion_terminate = NULL; (*ts_feed)->ts_insertion_insert_buffer = @@ -2586,6 +2638,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) dvbdmxfeed->feed.sec.secbufp = 0; dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->first_cc = 1; + dvbdmxfeed->scrambling_bits = 0; if (!dvbdmx->start_feed) { mutex_unlock(&dvbdmx->mutex); @@ -2752,6 +2805,25 @@ static int dvbdmx_section_feed_oob_cmd(struct dmx_section_feed *section_feed, return ret; } +static int dvbdmx_section_get_scrambling_bits( + struct dmx_section_feed *section_feed, u8 *value) +{ + struct dvb_demux_feed *feed = (struct dvb_demux_feed *)section_feed; + struct dvb_demux *demux = feed->demux; + + spin_lock(&demux->lock); + + if (!section_feed->is_filtering) { + spin_unlock(&demux->lock); + return -EINVAL; + } + + *value = feed->scrambling_bits; + spin_unlock(&demux->lock); + + return 0; +} + static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, struct dmx_section_feed **feed, dmx_section_cb callback) @@ -2792,6 +2864,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, (*feed)->notify_data_read = NULL; (*feed)->set_secure_mode = dmx_section_set_secure_mode; (*feed)->oob_command = dvbdmx_section_feed_oob_cmd; + (*feed)->get_scrambling_bits = dvbdmx_section_get_scrambling_bits; mutex_unlock(&dvbdmx->mutex); return 0; diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h index 879aad28f44..9fb1a121119 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/drivers/media/dvb/dvb-core/dvb_demux.h @@ -187,6 +187,8 @@ struct dvb_demux_feed { int first_cc; int pusi_seen; /* prevents feeding of garbage from previous section */ + u8 scrambling_bits; + struct dvb_demux_rec_info *rec_info; u64 prev_tsp_num; u64 prev_stc; diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h index aa1eba57693..ce9e5b9c33b 100644 --- a/include/linux/dvb/dmx.h +++ b/include/linux/dvb/dmx.h @@ -195,7 +195,7 @@ struct dmx_buffer_status { /* write pointer offset in bytes */ unsigned int write_offset; - /* non-zero if data error occured */ + /* non-zero if data error occurred */ int error; }; @@ -237,7 +237,10 @@ enum dmx_event { * (dmx_sct_filter_params) and no sections were * received for the given time. */ - DMX_EVENT_SECTION_TIMEOUT = 0x00000400 + DMX_EVENT_SECTION_TIMEOUT = 0x00000400, + + /* Scrambling bits change between clear and scrambled */ + DMX_EVENT_SCRAMBLING_STATUS_CHANGE = 0x00000800 }; enum dmx_oob_cmd { @@ -256,7 +259,7 @@ enum dmx_oob_cmd { /* Discontinuity indicator was set */ #define DMX_FILTER_DISCONTINUITY_INDICATOR 0x02 -/* PES legnth in PES header is not correct */ +/* PES length in PES header is not correct */ #define DMX_FILTER_PES_LENGTH_ERROR 0x04 @@ -412,7 +415,7 @@ struct dmx_index_event_info { /* * The PID the index entry belongs to. * In case of recording filter, multiple PIDs may exist in the same - * filter through DMX_ADD_PID ioctl and each can be indexed seperatly. + * filter through DMX_ADD_PID ioctl and each can be indexed separately. */ __u16 pid; @@ -423,7 +426,7 @@ struct dmx_index_event_info { __u64 match_tsp_num; /* - * The TS packet number in the recorded data preceeding + * The TS packet number in the recorded data preceding * match_tsp_num and has PUSI set. */ __u64 last_pusi_tsp_num; @@ -432,6 +435,23 @@ struct dmx_index_event_info { __u64 stc; }; +/* Scrambling information associated with DMX_EVENT_SCRAMBLING_STATUS_CHANGE */ +struct dmx_scrambling_status_event_info { + /* + * The PID which its scrambling bit status changed. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have + * different scrambling bits status. + */ + __u16 pid; + + /* old value of scrambling bits */ + __u8 old_value; + + /* new value of scrambling bits */ + __u8 new_value; +}; + /* * Filter's event returned through DMX_GET_EVENT. * poll with POLLPRI would block until events are available. @@ -447,6 +467,7 @@ struct dmx_filter_event { struct dmx_es_data_event_info es_data; struct dmx_marker_event_info marker; struct dmx_index_event_info index; + struct dmx_scrambling_status_event_info scrambling_status; } params; }; @@ -754,6 +775,19 @@ struct dmx_abort_ts_insertion { __u32 identifier; }; +struct dmx_scrambling_bits { + /* + * The PID to return its scrambling bit value. + * In case of recording filter, multiple PIDs may exist in the same + * filter through DMX_ADD_PID ioctl, each may have different + * scrambling bits status. + */ + __u16 pid; + + /* Current value of scrambling bits: 0, 1, 2 or 3 */ + __u8 value; +}; + #define DMX_START _IO('o', 41) #define DMX_STOP _IO('o', 42) #define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params) @@ -784,5 +818,6 @@ struct dmx_abort_ts_insertion { #define DMX_SET_INDEXING_PARAMS _IOW('o', 69, struct dmx_indexing_params) #define DMX_SET_TS_INSERTION _IOW('o', 70, struct dmx_set_ts_insertion) #define DMX_ABORT_TS_INSERTION _IOW('o', 71, struct dmx_abort_ts_insertion) +#define DMX_GET_SCRAMBLING_BITS _IOWR('o', 72, struct dmx_scrambling_bits) #endif /*_DVBDMX_H_*/