blob: 69305b6db068663d98c65157650eb2750353be33 [file] [log] [blame]
/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _MPQ_DMX_PLUGIN_COMMON_H
#define _MPQ_DMX_PLUGIN_COMMON_H
#include <linux/msm_ion.h>
#include "dvbdev.h"
#include "dmxdev.h"
#include "demux.h"
#include "dvb_demux.h"
#include "dvb_frontend.h"
#include "mpq_adapter.h"
/* Max number open() request can be done on demux device */
#define MPQ_MAX_DMX_FILES 128
/**
* TSIF alias name length
*/
#define TSIF_NAME_LENGTH 20
#define MPQ_MAX_FOUND_PATTERNS 5
/**
* struct mpq_demux - mpq demux information
* @demux: The dvb_demux instance used by mpq_demux
* @dmxdev: The dmxdev instance used by mpq_demux
* @fe_memory: Handle of front-end memory source to mpq_demux
* @source: The current source connected to the demux
* @is_initialized: Indicates whether this demux device was
* initialized or not.
* @ion_client: ION demux client used to allocate memory from ION.
* @feed_lock: Lock used to protect against private feed data
* @hw_notification_interval: Notification interval in msec,
* exposed in debugfs.
* @hw_notification_min_interval: Minimum notification internal in msec,
* exposed in debugfs.
* @hw_notification_count: Notification count, exposed in debugfs.
* @hw_notification_size: Notification size in bytes, exposed in debugfs.
* @hw_notification_min_size: Minimum notification size in bytes,
* exposed in debugfs.
* @decoder_tsp_drop_count: Counter of number of dropped TS packets
* due to decoder buffer fullness, exposed in debugfs.
* @last_notification_time: Time of last HW notification.
*/
struct mpq_demux {
struct dvb_demux demux;
struct dmxdev dmxdev;
struct dmx_frontend fe_memory;
dmx_source_t source;
int is_initialized;
struct ion_client *ion_client;
spinlock_t feed_lock;
/* debug-fs */
u32 hw_notification_interval;
u32 hw_notification_min_interval;
u32 hw_notification_count;
u32 hw_notification_size;
u32 hw_notification_min_size;
u32 decoder_tsp_drop_count;
struct timespec last_notification_time;
};
/**
* mpq_dmx_init - initialization and registration function of
* single MPQ demux device
*
* @adapter: The adapter to register mpq_demux to
* @mpq_demux: The mpq demux to initialize
*
* Every HW pluging need to provide implementation of such
* function that will be called for each demux device on the
* module initialization. The function mpq_demux_plugin_init
* should be called during the HW plugin module initialization.
*/
typedef int (*mpq_dmx_init)(
struct dvb_adapter *mpq_adapter,
struct mpq_demux *demux);
/**
* struct ts_packet_header - Transport packet header
* as defined in MPEG2 transport stream standard.
*/
struct ts_packet_header {
#if defined(__BIG_ENDIAN_BITFIELD)
unsigned sync_byte:8;
unsigned transport_error_indicator:1;
unsigned payload_unit_start_indicator:1;
unsigned transport_priority:1;
unsigned pid_msb:5;
unsigned pid_lsb:8;
unsigned transport_scrambling_control:2;
unsigned adaptation_field_control:2;
unsigned continuity_counter:4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
unsigned sync_byte:8;
unsigned pid_msb:5;
unsigned transport_priority:1;
unsigned payload_unit_start_indicator:1;
unsigned transport_error_indicator:1;
unsigned pid_lsb:8;
unsigned continuity_counter:4;
unsigned adaptation_field_control:2;
unsigned transport_scrambling_control:2;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} __packed;
/**
* struct ts_adaptation_field - Adaptation field prefix
* as defined in MPEG2 transport stream standard.
*/
struct ts_adaptation_field {
#if defined(__BIG_ENDIAN_BITFIELD)
unsigned adaptation_field_length:8;
unsigned discontinuity_indicator:1;
unsigned random_access_indicator:1;
unsigned elementary_stream_priority_indicator:1;
unsigned PCR_flag:1;
unsigned OPCR_flag:1;
unsigned splicing_point_flag:1;
unsigned transport_private_data_flag:1;
unsigned adaptation_field_extension_flag:1;
unsigned program_clock_reference_base_1:8;
unsigned program_clock_reference_base_2:8;
unsigned program_clock_reference_base_3:8;
unsigned program_clock_reference_base_4:8;
unsigned program_clock_reference_base_5:1;
unsigned reserved:6;
unsigned program_clock_reference_ext_1:1;
unsigned program_clock_reference_ext_2:8;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
unsigned adaptation_field_length:8;
unsigned adaptation_field_extension_flag:1;
unsigned transport_private_data_flag:1;
unsigned splicing_point_flag:1;
unsigned OPCR_flag:1;
unsigned PCR_flag:1;
unsigned elementary_stream_priority_indicator:1;
unsigned random_access_indicator:1;
unsigned discontinuity_indicator:1;
unsigned program_clock_reference_base_1:8;
unsigned program_clock_reference_base_2:8;
unsigned program_clock_reference_base_3:8;
unsigned program_clock_reference_base_4:8;
unsigned program_clock_reference_ext_1:1;
unsigned reserved:6;
unsigned program_clock_reference_base_5:1;
unsigned program_clock_reference_ext_2:8;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} __packed;
/*
* PES packet header containing dts and/or pts values
* as defined in MPEG2 transport stream standard.
*/
struct pes_packet_header {
#if defined(__BIG_ENDIAN_BITFIELD)
unsigned packet_start_code_prefix_1:8;
unsigned packet_start_code_prefix_2:8;
unsigned packet_start_code_prefix_3:8;
unsigned stream_id:8;
unsigned pes_packet_length_msb:8;
unsigned pes_packet_length_lsb:8;
unsigned reserved_bits0:2;
unsigned pes_scrambling_control:2;
unsigned pes_priority:1;
unsigned data_alignment_indicator:1;
unsigned copyright:1;
unsigned original_or_copy:1;
unsigned pts_dts_flag:2;
unsigned escr_flag:1;
unsigned es_rate_flag:1;
unsigned dsm_trick_mode_flag:1;
unsigned additional_copy_info_flag:1;
unsigned pes_crc_flag:1;
unsigned pes_extension_flag:1;
unsigned pes_header_data_length:8;
unsigned reserved_bits1:4;
unsigned pts_1:3;
unsigned marker_bit0:1;
unsigned pts_2:8;
unsigned pts_3:7;
unsigned marker_bit1:1;
unsigned pts_4:8;
unsigned pts_5:7;
unsigned marker_bit2:1;
unsigned reserved_bits2:4;
unsigned dts_1:3;
unsigned marker_bit3:1;
unsigned dts_2:8;
unsigned dts_3:7;
unsigned marker_bit4:1;
unsigned dts_4:8;
unsigned dts_5:7;
unsigned marker_bit5:1;
unsigned reserved_bits3:4;
#elif defined(__LITTLE_ENDIAN_BITFIELD)
unsigned packet_start_code_prefix_1:8;
unsigned packet_start_code_prefix_2:8;
unsigned packet_start_code_prefix_3:8;
unsigned stream_id:8;
unsigned pes_packet_length_lsb:8;
unsigned pes_packet_length_msb:8;
unsigned original_or_copy:1;
unsigned copyright:1;
unsigned data_alignment_indicator:1;
unsigned pes_priority:1;
unsigned pes_scrambling_control:2;
unsigned reserved_bits0:2;
unsigned pes_extension_flag:1;
unsigned pes_crc_flag:1;
unsigned additional_copy_info_flag:1;
unsigned dsm_trick_mode_flag:1;
unsigned es_rate_flag:1;
unsigned escr_flag:1;
unsigned pts_dts_flag:2;
unsigned pes_header_data_length:8;
unsigned marker_bit0:1;
unsigned pts_1:3;
unsigned reserved_bits1:4;
unsigned pts_2:8;
unsigned marker_bit1:1;
unsigned pts_3:7;
unsigned pts_4:8;
unsigned marker_bit2:1;
unsigned pts_5:7;
unsigned marker_bit3:1;
unsigned dts_1:3;
unsigned reserved_bits2:4;
unsigned dts_2:8;
unsigned marker_bit4:1;
unsigned dts_3:7;
unsigned dts_4:8;
unsigned marker_bit5:1;
unsigned dts_5:7;
unsigned reserved_bits3:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
} __packed;
/*
* mpq_framing_prefix_size_masks - possible prefix sizes.
*
* @size_mask: a bit mask (per pattern) of possible prefix sizes to use
* when searching for a pattern that started in the last buffer.
* Updated in mpq_dmx_framing_pattern_search for use in the next lookup
*/
struct mpq_framing_prefix_size_masks {
u32 size_mask[MPQ_MAX_FOUND_PATTERNS];
};
/*
* mpq_video_feed_info - private data used for video feed.
*
* @plugin_data: Underlying plugin's own private data.
* @video_buffer: Holds the streamer buffer shared with
* the decoder for feeds having the data going to the decoder.
* @pes_header: Used for feeds that output data to decoder,
* holds PES header of current processed PES.
* @pes_header_left_bytes: Used for feeds that output data to decoder,
* holds remainning PES header bytes of current processed PES.
* @pes_header_offset: Holds the offset within the current processed
* pes header.
* @fullness_wait_cancel: Flag used to signal to abort waiting for
* decoder's fullness.
* @pes_payload_address: Used for feeds that output data to decoder,
* holds current PES payload start address.
* @payload_buff_handle: ION handle for the allocated payload buffer
* @stream_interface: The ID of the video stream interface registered
* with this stream buffer.
* @patterns: pointer to the framing patterns to look for.
* @patterns_num: number of framing patterns.
* @last_framing_match_address: Used for saving the raw data address of
* the previous pattern match found in this video feed.
* @last_framing_match_type: Used for saving the type of
* the previous pattern match found in this video feed.
* @found_sequence_header_pattern: Flag used to note that an MPEG-2
* Sequence Header, H.264 SPS or VC-1 Sequence Header pattern
* (whichever is relevant according to the video standard) had already
* been found.
* @prefix_size: a bit mask representing the size(s) of possible prefixes
* to the pattern, already found in the previous buffer. If bit 0 is set,
* a prefix of size 1 was found. If bit 1 is set, a prefix of size 2 was
* found, etc. This supports a prefix size of up to 32, which is more
* than we need. The search function updates prefix_size as needed
* for the next buffer search.
* @first_pattern_offset: used to save the offset of the first pattern written
* to the stream buffer.
* @first_prefix_size: used to save the prefix size used to find the first
* pattern written to the stream buffer.
* @write_pts_dts: Flag used to decide if to write PTS/DTS information
* (if it is available in the PES header) in the meta-data passed
* to the video decoder. PTS/DTS information is written in the first
* packet after it is available.
*/
struct mpq_video_feed_info {
void *plugin_data;
struct mpq_streambuffer *video_buffer;
struct pes_packet_header pes_header;
u32 pes_header_left_bytes;
u32 pes_header_offset;
u32 pes_payload_address;
int fullness_wait_cancel;
struct ion_handle *payload_buff_handle;
enum mpq_adapter_stream_if stream_interface;
const struct mpq_framing_pattern_lookup_params *patterns;
int patterns_num;
u32 last_framing_match_address;
enum dmx_framing_pattern_type last_framing_match_type;
int found_sequence_header_pattern;
struct mpq_framing_prefix_size_masks prefix_size;
u32 first_pattern_offset;
u32 first_prefix_size;
int write_pts_dts;
};
/**
* mpq_demux_plugin_init - Initialize demux devices and register
* them to the dvb adapter.
*
* @dmx_init_func: Pointer to the function to be used
* to initialize demux of the underlying HW plugin.
*
* Return error code
*
* Should be called at the HW plugin module initialization.
*/
int mpq_dmx_plugin_init(mpq_dmx_init dmx_init_func);
/**
* mpq_demux_plugin_exit - terminate demux devices.
*
* Should be called at the HW plugin module termination.
*/
void mpq_dmx_plugin_exit(void);
/**
* mpq_dmx_set_source - implmenetation of set_source routine.
*
* @demux: The demux device to set its source.
* @src: The source to be set.
*
* Return error code
*
* Can be used by the underlying plugins to implement kernel
* demux API set_source routine.
*/
int mpq_dmx_set_source(struct dmx_demux *demux, const dmx_source_t *src);
/**
* mpq_dmx_map_buffer - map user-space buffer into kernel space.
*
* @demux: The demux device.
* @dmx_buffer: The demux buffer from user-space, assumes that
* buffer handle is ION file-handle.
* @priv_handle: Saves ION-handle of the buffer imported by this function.
* @kernel_mem: Saves kernel mapped address of the buffer.
*
* Return error code
*
* The function maps the buffer into kernel memory only if the buffer
* was not allocated with secure flag, otherwise the returned kernel
* memory address is set to NULL.
*/
int mpq_dmx_map_buffer(struct dmx_demux *demux, struct dmx_buffer *dmx_buffer,
void **priv_handle, void **kernel_mem);
/**
* mpq_dmx_unmap_buffer - unmap user-space buffer from kernel space memory.
*
* @demux: The demux device.
* @priv_handle: ION-handle of the buffer returned from mpq_dmx_map_buffer.
*
* Return error code
*
* The function unmaps the buffer from kernel memory only if the buffer
* was not allocated with secure flag.
*/
int mpq_dmx_unmap_buffer(struct dmx_demux *demux,
void *priv_handle);
/**
* mpq_dmx_init_video_feed - Initializes video feed
* used to pass data to decoder directly.
*
* @feed: The feed used for the video TS packets
*
* Return error code.
*
* If the underlying plugin wishes to perform SW PES assmebly
* for the video data and stream it to the decoder, it should
* call this function when video feed is initialized before
* using mpq_dmx_process_video_packet.
*
* The function allocates mpq_video_feed_info and saves in
* feed->priv.
*/
int mpq_dmx_init_video_feed(struct dvb_demux_feed *feed);
/**
* mpq_dmx_terminate_video_feed - Free private data of
* video feed allocated in mpq_dmx_init_video_feed
*
* @feed: The feed used for the video TS packets
*
* Return error code.
*/
int mpq_dmx_terminate_video_feed(struct dvb_demux_feed *feed);
/**
* mpq_dmx_decoder_fullness_init - Initialize waiting
* mechanism on decoder's buffer fullness.
*
* @feed: The decoder's feed
*
* Return error code.
*/
int mpq_dmx_decoder_fullness_init(struct dvb_demux_feed *feed);
/**
* mpq_dmx_decoder_fullness_wait - Checks whether decoder buffer
* have free space as required, if not, wait for it.
*
* @feed: The decoder's feed
* @required_space: the required free space to wait for
*
* Return error code.
*/
int mpq_dmx_decoder_fullness_wait(struct dvb_demux_feed *feed,
size_t required_space);
/**
* mpq_dmx_decoder_fullness_abort - Aborts waiting
* on decoder's buffer fullness if any waiting is done
* now. After calling this, to wait again the user must
* call mpq_dmx_decoder_fullness_init.
*
* @feed: The decoder's feed
*
* Return error code.
*/
int mpq_dmx_decoder_fullness_abort(struct dvb_demux_feed *feed);
/**
* mpq_dmx_decoder_buffer_status - Returns the
* status of the decoder's buffer.
*
* @feed: The decoder's feed
* @dmx_buffer_status: Status of decoder's buffer
*
* Return error code.
*/
int mpq_dmx_decoder_buffer_status(struct dvb_demux_feed *feed,
struct dmx_buffer_status *dmx_buffer_status);
/**
* mpq_dmx_process_video_packet - Assemble PES data and output it
* to the stream-buffer connected to the decoder.
*
* @feed: The feed used for the video TS packets
* @buf: The buffer holding video TS packet.
*
* Return error code.
*
* The function assumes it receives buffer with single TS packet
* of the relevant PID.
* If the output buffer is full while assembly, the function drops
* the packet and does not write them to the output buffer.
* Scrambled packets are bypassed.
*/
int mpq_dmx_process_video_packet(struct dvb_demux_feed *feed, const u8 *buf);
/**
* mpq_dmx_process_pcr_packet - Extract PCR/STC pairs from
* a 192 bytes packet.
*
* @feed: The feed used for the PCR TS packets
* @buf: The buffer holding pcr/stc packet.
*
* Return error code.
*
* The function assumes it receives buffer with single TS packet
* of the relevant PID, and that it has 4 bytes
* suffix as extra timestamp in the following format:
*
* Byte3: TSIF flags
* Byte0-2: TTS, 0..2^24-1 at 105.47 Khz (27*10^6/256).
*
* The function callbacks dmxdev after extraction of the pcr/stc
* pair.
*/
int mpq_dmx_process_pcr_packet(struct dvb_demux_feed *feed, const u8 *buf);
/**
* mpq_dmx_is_video_feed - Returns whether the PES feed
* is video one.
*
* @feed: The feed to be checked.
*
* Return 1 if feed is video feed, 0 otherwise.
*/
static inline int mpq_dmx_is_video_feed(struct dvb_demux_feed *feed)
{
if (feed->type != DMX_TYPE_TS)
return 0;
if (feed->ts_type & (~TS_DECODER))
return 0;
if ((feed->pes_type == DMX_TS_PES_VIDEO0) ||
(feed->pes_type == DMX_TS_PES_VIDEO1) ||
(feed->pes_type == DMX_TS_PES_VIDEO2) ||
(feed->pes_type == DMX_TS_PES_VIDEO3))
return 1;
return 0;
}
/**
* mpq_dmx_is_pcr_feed - Returns whether the PES feed
* is PCR one.
*
* @feed: The feed to be checked.
*
* Return 1 if feed is PCR feed, 0 otherwise.
*/
static inline int mpq_dmx_is_pcr_feed(struct dvb_demux_feed *feed)
{
if (feed->type != DMX_TYPE_TS)
return 0;
if (feed->ts_type & (~TS_DECODER))
return 0;
if ((feed->pes_type == DMX_TS_PES_PCR0) ||
(feed->pes_type == DMX_TS_PES_PCR1) ||
(feed->pes_type == DMX_TS_PES_PCR2) ||
(feed->pes_type == DMX_TS_PES_PCR3))
return 1;
return 0;
}
/**
* mpq_dmx_init_hw_statistics -
* Extend dvb-demux debugfs with HW statistics.
*
* @mpq_demux: The mpq_demux device to initialize.
*/
void mpq_dmx_init_hw_statistics(struct mpq_demux *mpq_demux);
/**
* mpq_dmx_update_hw_statistics -
* Update dvb-demux debugfs with HW notification statistics.
*
* @mpq_demux: The mpq_demux device to update.
*/
void mpq_dmx_update_hw_statistics(struct mpq_demux *mpq_demux);
#endif /* _MPQ_DMX_PLUGIN_COMMON_H */