M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,45 @@
config DVB_MPQ_DEMUX
tristate "DVB Demux Device"
depends on DVB_MPQ && ION && ION_MSM
default n
help
Support for Qualcomm based dvb demux device.
Say Y or M if you own such a device and want to use it.
config DVB_MPQ_NUM_DMX_DEVICES
int "Number of demux devices"
depends on DVB_MPQ_DEMUX
default 4
range 1 255
help
Configure number of demux devices. Depends on your use-cases for maximum concurrent stream playback.
choice
prompt "Demux Hardware Plugin"
depends on DVB_MPQ_DEMUX
default DVB_MPQ_TSIF
help
Enable support of specific demux HW plugin depending on the existing HW support.
Depending on the enabled HW, demux may take advantage of HW capbailities to perform some tasks in HW instead of SW.
config DVB_MPQ_TSPP1
bool "TSPPv1 plugin"
depends on TSPP
help
Use this option of your HW has Transport Stream Packet Processor (TSPP) version1 support
config DVB_MPQ_TSPP2
bool "TSPPv2 plugin"
depends on TSPP
help
Use this option of your HW has Transport Stream Packet Processor (TSPP) version2 support
config DVB_MPQ_TSIF
bool "TSIF plugin"
depends on TSIF
help
Use this option of your HW has only TSIF input without any Transport Stream Packet Processor (TSPP) support
endchoice

View File

@ -0,0 +1,18 @@
ccflags-y += -Idrivers/media/dvb/dvb-core/
ccflags-y += -Idrivers/media/platform/msm/dvb/include/
ccflags-y += -Idrivers/misc/
obj-$(CONFIG_DVB_MPQ_DEMUX) += mpq-dmx-hw-plugin.o
mpq-dmx-hw-plugin-y := mpq_dmx_plugin_common.o
mpq-dmx-hw-plugin-y += mpq_sdmx.o
mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP1) += mpq_dmx_plugin_tspp_v1.o
mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSPP2) += mpq_dmx_plugin_tspp_v2.o
mpq-dmx-hw-plugin-$(CONFIG_DVB_MPQ_TSIF) += mpq_dmx_plugin_tsif.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,759 @@
/* Copyright (c) 2012-2013, The Linux Foundation. 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"
#include "mpq_sdmx.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
/**
* 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_decoder_buffers_desc - decoder buffer(s) management information.
*
* @desc: Array of buffer descriptors as they are passed to mpq_streambuffer
* upon its initialization. These descriptors must remain valid as long as
* the mpq_streambuffer object is used.
* @ion_handle: Array of ION handles, one for each decoder buffer, used for
* kernel memory mapping or allocation. Handles are saved in order to release
* resources properly later on.
* @decoder_buffers_num: number of buffers that are managed, either externally
* or internally by the mpq_streambuffer object
*/
struct mpq_decoder_buffers_desc {
struct mpq_streambuffer_buffer_desc desc[DMX_MAX_DECODER_BUFFER_NUM];
struct ion_handle *ion_handle[DMX_MAX_DECODER_BUFFER_NUM];
u32 decoder_buffers_num;
};
/*
* mpq_video_feed_info - private data used for video feed.
*
* @video_buffer: Holds the streamer buffer shared with
* the decoder for feeds having the data going to the decoder.
* @video_buffer_lock: Lock protecting against video output buffer.
* The lock protects against API calls to manipulate the output buffer
* (initialize, free, re-use buffers) and dvb-sw demux parsing the video
* data through mpq_dmx_process_video_packet().
* @buffer_desc: Holds decoder buffer(s) information used for stream buffer.
* @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 remaining 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.
* @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.
* @frame_offset: Saves data buffer offset to which a new frame will be written
* @last_pattern_offset: Holds the previous pattern offset
* @pending_pattern_len: Accumulated number of data bytes that will be
* reported for this frame.
* @last_framing_match_type: Used for saving the type of
* the previous pattern match found in this video feed.
* @last_framing_match_stc: Used for saving the STC attached to TS packet
* 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_prefix_size: used to save the prefix size used to find the first
* pattern written to the stream buffer.
* @saved_pts_dts_info: used to save PTS/DTS information until it is written.
* @new_pts_dts_info: used to store PTS/DTS information from current PES header.
* @saved_info_used: indicates if saved PTS/DTS information was used.
* @new_info_exists: indicates if new PTS/DTS information exists in
* new_pts_dts_info that should be saved to saved_pts_dts_info.
* @first_pts_dts_copy: a flag used to indicate if PTS/DTS information needs
* to be copied from the currently parsed PES header to the saved_pts_dts_info.
* @tei_errs: Transport stream Transport Error Indicator (TEI) counter.
* @last_continuity: last continuity counter value found in TS packet header.
* Initialized to -1.
* @continuity_errs: Transport stream continuity error counter.
* @ts_packets_num: TS packets counter.
* @ts_dropped_bytes: counts the number of bytes dropped due to insufficient
* buffer space.
* @last_pkt_index: used to save the last streambuffer packet index reported in
* a new elementary stream data event.
* @prev_stc: STC attached to the previous video TS packet
*/
struct mpq_video_feed_info {
struct mpq_streambuffer *video_buffer;
spinlock_t video_buffer_lock;
struct mpq_decoder_buffers_desc buffer_desc;
struct pes_packet_header pes_header;
u32 pes_header_left_bytes;
u32 pes_header_offset;
int fullness_wait_cancel;
enum mpq_adapter_stream_if stream_interface;
const struct dvb_dmx_video_patterns
*patterns[DVB_DMX_MAX_SEARCH_PATTERN_NUM];
int patterns_num;
u32 frame_offset;
u32 last_pattern_offset;
u32 pending_pattern_len;
u64 last_framing_match_type;
u64 last_framing_match_stc;
int found_sequence_header_pattern;
struct dvb_dmx_video_prefix_size_masks prefix_size;
u32 first_prefix_size;
struct dmx_pts_dts_info saved_pts_dts_info;
struct dmx_pts_dts_info new_pts_dts_info;
int saved_info_used;
int new_info_exists;
int first_pts_dts_copy;
u32 tei_errs;
int last_continuity;
u32 continuity_errs;
u32 ts_packets_num;
u32 ts_dropped_bytes;
int last_pkt_index;
u64 prev_stc;
};
/**
* mpq feed object - mpq common plugin feed information
*
* @dvb_demux_feed: Back pointer to dvb demux level feed object
* @mpq_demux: Pointer to common mpq demux object
* @plugin_priv: Plugin specific private data
* @sdmx_filter_handle: Secure demux filter handle. Recording feed may share
* same filter handle
* @secondary_feed: Specifies if this feed shares filter handle with
* other feeds
* @metadata_buf: Ring buffer object for managing the metadata buffer
* @metadata_buf_handle: Allocation handle for the metadata buffer
* @sdmx_buf: Ring buffer object for intermediate output data from the sdmx
* @sdmx_buf_handle: Allocation handle for the sdmx intermediate data buffer
* @video_info: Video feed specific information
*/
struct mpq_feed {
struct dvb_demux_feed *dvb_demux_feed;
struct mpq_demux *mpq_demux;
void *plugin_priv;
/* Secure demux related */
int sdmx_filter_handle;
int secondary_feed;
enum sdmx_filter filter_type;
struct dvb_ringbuffer metadata_buf;
struct ion_handle *metadata_buf_handle;
struct dvb_ringbuffer sdmx_buf;
struct ion_handle *sdmx_buf_handle;
struct mpq_video_feed_info video_info;
};
/**
* 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.
* @mutex: Lock used to protect against private feed data
* @feeds: mpq common feed object pool
* @num_active_feeds: Number of active mpq feeds
* @num_secure_feeds: Number of secure feeds (have a sdmx filter associated)
* currently allocated.
* @filters_status: Array holding buffers status for each secure demux filter.
* Used before each call to sdmx_process() to build up to date state.
* @sdmx_session_handle: Secure demux open session handle
* @sdmx_filter_count: Number of active secure demux filters
* @sdmx_eos: End-of-stream indication flag for current sdmx session
* @plugin_priv: Underlying plugin's own private 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_drop_count: Accumulated number of bytes dropped due to decoder
* buffer fullness, exposed in debugfs.
* @decoder_out_count: Counter incremeneted for each video frame output by
* demux, exposed in debugfs.
* @decoder_out_interval_sum: Sum of intervals (msec) holding the time between
* two successive video frames output, exposed in debugfs.
* @decoder_out_interval_average: Average interval (msec) between two
* successive video frames output, exposed in debugfs.
* @decoder_out_interval_max: Max interval (msec) between two
* successive video frames output, exposed in debugfs.
* @decoder_ts_errors: Counter for number of decoder packets with TEI bit
* set, exposed in debugfs.
* @sdmx_process_count: Total number of times sdmx_process is called.
* @sdmx_process_time_sum: Total time sdmx_process takes.
* @sdmx_process_time_average: Average time sdmx_process takes.
* @sdmx_process_time_max: Max time sdmx_process takes.
* @sdmx_process_packets_sum: Total packets number sdmx_process handled.
* @sdmx_process_packets_average: Average packets number sdmx_process handled.
* @sdmx_process_packets_min: Minimum packets number sdmx_process handled.
* @decoder_out_last_time: Time of last video frame output.
* @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;
struct mutex mutex;
struct mpq_feed feeds[MPQ_MAX_DMX_FILES];
u32 num_active_feeds;
u32 num_secure_feeds;
struct sdmx_filter_status filters_status[MPQ_MAX_DMX_FILES];
int sdmx_session_handle;
int sdmx_session_ref_count;
int sdmx_filter_count;
int sdmx_eos;
void *plugin_priv;
/* 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_drop_count;
u32 decoder_out_count;
u32 decoder_out_interval_sum;
u32 decoder_out_interval_average;
u32 decoder_out_interval_max;
u32 decoder_ts_errors;
u32 sdmx_process_count;
u32 sdmx_process_time_sum;
u32 sdmx_process_time_average;
u32 sdmx_process_time_max;
u32 sdmx_process_packets_sum;
u32 sdmx_process_packets_average;
u32 sdmx_process_packets_min;
enum sdmx_log_level sdmx_log_level;
struct timespec decoder_out_last_time;
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);
/**
* 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_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_reuse_decoder_buffer - release buffer passed to decoder for reuse
* by the stream-buffer.
*
* @feed: The decoder's feed.
* @cookie: stream-buffer handle of the buffer.
*
* Return error code
*
* The function releases the buffer provided by the stream-buffer
* connected to the decoder back to the stream-buffer for reuse.
*/
int mpq_dmx_reuse_decoder_buffer(struct dvb_demux_feed *feed, int cookie);
/**
* 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_init_debugfs_entries -
* Extend dvb-demux debugfs with mpq related entries (HW statistics and secure
* demux log level).
*
* @mpq_demux: The mpq_demux device to initialize.
*/
void mpq_dmx_init_debugfs_entries(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);
/**
* mpq_dmx_set_secure_mode - Handles set secure mode command from demux device
*
* @feed: The feed to set its secure mode
* @sec_mode: Secure mode details (key ladder info)
*
* Return error code
*/
int mpq_dmx_set_secure_mode(struct dvb_demux_feed *feed,
struct dmx_secure_mode *secure_mode);
/**
* mpq_dmx_convert_tts - Convert timestamp attached by HW to each TS
* packet to 27MHz.
*
* @feed: The feed with TTS attached
* @timestamp: Buffer holding the timestamp attached by the HW
* @timestampIn27Mhz: Timestamp result in 27MHz
*
* Return error code
*/
void mpq_dmx_convert_tts(struct dvb_demux_feed *feed,
const u8 timestamp[TIMESTAMP_LEN],
u64 *timestampIn27Mhz);
/**
* mpq_sdmx_open_session - Handle the details of opening a new secure demux
* session for the specified mpq demux instance. Multiple calls to this
* is allowed, reference counting is managed to open it only when needed.
*
* @mpq_demux: mpq demux instance
*
* Return error code
*/
int mpq_sdmx_open_session(struct mpq_demux *mpq_demux);
/**
* mpq_sdmx_close_session - Closes secure demux session. The session
* is closed only if reference counter of the session reaches 0.
*
* @mpq_demux: mpq demux instance
*
* Return error code
*/
int mpq_sdmx_close_session(struct mpq_demux *mpq_demux);
/**
* mpq_dmx_init_mpq_feed - Initialize an mpq feed object
* The function allocates mpq_feed object and saves in the dvb_demux_feed
* priv field.
*
* @feed: A dvb demux level feed parent object
*
* Return error code
*/
int mpq_dmx_init_mpq_feed(struct dvb_demux_feed *feed);
/**
* mpq_dmx_terminate_feed - Destroy an mpq feed object
*
* @feed: A dvb demux level feed parent object
*
* Return error code
*/
int mpq_dmx_terminate_feed(struct dvb_demux_feed *feed);
/**
* mpq_dmx_write - demux write() function implementation.
*
* A wrapper function used for writing new data into the demux via DVR.
* It checks where new data should actually go, the secure demux or the normal
* dvb demux software demux.
*
* @demux: demux interface
* @buf: input buffer
* @count: number of data bytes in input buffer
*
* Return number of bytes processed or error code
*/
int mpq_dmx_write(struct dmx_demux *demux, const char *buf, size_t count);
/**
* mpq_sdmx_process - Perform demuxing process on the specified input buffer
* in the secure demux instance
*
* @mpq_demux: mpq demux instance
* @input: input buffer descriptor
* @fill_count: number of data bytes in input buffer that can be read
* @read_offset: offset in buffer for reading
* @tsp_size: size of single TS packet
*
* Return number of bytes read or error code
*/
int mpq_sdmx_process(struct mpq_demux *mpq_demux,
struct sdmx_buff_descr *input,
u32 fill_count,
u32 read_offset,
size_t tsp_size);
/**
* mpq_sdmx_loaded - Returns 1 if secure demux application is loaded,
* 0 otherwise. This function should be used to determine whether or not
* processing should take place in the SDMX.
*/
int mpq_sdmx_is_loaded(void);
/**
* mpq_dmx_oob_command - Handles OOB command from dvb-demux.
*
* OOB marker commands trigger callback to the dmxdev.
* Handling of EOS command may trigger current (last on stream) PES/Frame to
* be reported, in addition to callback to the dmxdev.
* In case secure demux is active for the feed, EOS command is passed to the
* secure demux for handling.
*
* @feed: dvb demux feed object
* @cmd: oob command data
*
* returns 0 on success or error
*/
int mpq_dmx_oob_command(struct dvb_demux_feed *feed,
struct dmx_oob_command *cmd);
#endif /* _MPQ_DMX_PLUGIN_COMMON_H */

View File

@ -0,0 +1,851 @@
/* Copyright (c) 2012-2013, The Linux Foundation. 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/tsif_api.h>
#include <linux/kthread.h>
#include <linux/moduleparam.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
/* TSIF HW configuration: */
#define TSIF_COUNT 2
/* Max number of section filters */
#define DMX_TSIF_MAX_SECTION_FILTER_NUM 64
/* When TSIF driver notifies demux that new packets are received */
#define DMX_TSIF_PACKETS_IN_CHUNK_DEF 512
#define DMX_TSIF_CHUNKS_IN_BUF 16
#define DMX_TSIF_TIME_LIMIT 10000
/* TSIF_DRIVER_MODE: 3 means manual control from debugfs. use 2 normally. */
#define DMX_TSIF_DRIVER_MODE_DEF 2
/* module parameters for load time configuration: */
static int threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
static int tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
static int clock_inv;
module_param(threshold, int, S_IRUGO);
module_param(tsif_mode, int, S_IRUGO | S_IWUSR);
module_param(clock_inv, int, S_IRUGO | S_IWUSR);
/*
* TSIF driver information
*/
struct tsif_driver_info {
/* handler to TSIF driver */
void *tsif_handler;
/* TSIF driver data buffer pointer */
void *data_buffer;
/* TSIF driver data buffer size, in packets */
int buffer_size;
/* TSIF driver read pointer */
int ri;
/* TSIF driver write pointer */
int wi;
/* TSIF driver state */
enum tsif_state state;
};
/*
* The following structure hold singelton information
* required for dmx implementation on top of TSIF.
*/
static struct
{
/* Information for each TSIF input processing */
struct {
/* thread processing TS packets from TSIF */
struct task_struct *thread;
wait_queue_head_t wait_queue;
/* Counter for data notifications from TSIF */
atomic_t data_cnt;
/* TSIF alias */
char name[TSIF_NAME_LENGTH];
/* TSIF driver information */
struct tsif_driver_info tsif_driver;
/* TSIF reference count (counts start/stop operations */
int ref_count;
/* Pointer to the demux connected to this TSIF */
struct mpq_demux *mpq_demux;
/* mutex protecting the data-structure */
struct mutex mutex;
} tsif[TSIF_COUNT];
} mpq_dmx_tsif_info;
/**
* Demux thread function handling data from specific TSIF.
*
* @arg: TSIF number
*/
static int mpq_dmx_tsif_thread(void *arg)
{
struct mpq_demux *mpq_demux;
struct tsif_driver_info *tsif_driver;
size_t packets = 0;
int tsif = (int)arg;
int ret;
do {
ret = wait_event_interruptible(
mpq_dmx_tsif_info.tsif[tsif].wait_queue,
(atomic_read(
&mpq_dmx_tsif_info.tsif[tsif].data_cnt) != 0) ||
kthread_should_stop());
if ((ret < 0) || kthread_should_stop()) {
MPQ_DVB_DBG_PRINT("%s: exit\n", __func__);
break;
}
if (mutex_lock_interruptible(
&mpq_dmx_tsif_info.tsif[tsif].mutex))
return -ERESTARTSYS;
tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
/* Check if driver handler is still valid */
if (tsif_driver->tsif_handler == NULL) {
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
MPQ_DVB_DBG_PRINT(
"%s: tsif was detached\n",
__func__);
continue;
}
tsif_get_state(
tsif_driver->tsif_handler, &(tsif_driver->ri),
&(tsif_driver->wi), &(tsif_driver->state));
if ((tsif_driver->wi == tsif_driver->ri) ||
(tsif_driver->state == tsif_state_stopped) ||
(tsif_driver->state == tsif_state_error)) {
mpq_demux->hw_notification_size = 0;
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
MPQ_DVB_DBG_PRINT(
"%s: TSIF invalid state %d, %d, %d\n",
__func__,
tsif_driver->state,
tsif_driver->wi,
tsif_driver->ri);
continue;
}
atomic_dec(&mpq_dmx_tsif_info.tsif[tsif].data_cnt);
if (tsif_driver->wi > tsif_driver->ri) {
packets = (tsif_driver->wi - tsif_driver->ri);
mpq_demux->hw_notification_size = packets;
dvb_dmx_swfilter_format(
&mpq_demux->demux,
(tsif_driver->data_buffer +
(tsif_driver->ri * TSIF_PKT_SIZE)),
(packets * TSIF_PKT_SIZE),
DMX_TSP_FORMAT_192_TAIL);
tsif_driver->ri =
(tsif_driver->ri + packets) %
tsif_driver->buffer_size;
tsif_reclaim_packets(
tsif_driver->tsif_handler,
tsif_driver->ri);
} else {
/*
* wi < ri, means wraparound on cyclic buffer.
* Handle in two stages.
*/
packets = (tsif_driver->buffer_size - tsif_driver->ri);
mpq_demux->hw_notification_size = packets;
dvb_dmx_swfilter_format(
&mpq_demux->demux,
(tsif_driver->data_buffer +
(tsif_driver->ri * TSIF_PKT_SIZE)),
(packets * TSIF_PKT_SIZE),
DMX_TSP_FORMAT_192_TAIL);
/* tsif_driver->ri should be 0 after this */
tsif_driver->ri =
(tsif_driver->ri + packets) %
tsif_driver->buffer_size;
packets = tsif_driver->wi;
if (packets > 0) {
mpq_demux->hw_notification_size += packets;
dvb_dmx_swfilter_format(
&mpq_demux->demux,
(tsif_driver->data_buffer +
(tsif_driver->ri * TSIF_PKT_SIZE)),
(packets * TSIF_PKT_SIZE),
DMX_TSP_FORMAT_192_TAIL);
tsif_driver->ri =
(tsif_driver->ri + packets) %
tsif_driver->buffer_size;
}
tsif_reclaim_packets(
tsif_driver->tsif_handler,
tsif_driver->ri);
}
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
} while (1);
return 0;
}
/**
* Callback function from TSIF driver when new data is ready.
*
* @user: user-data holding TSIF number
*/
static void mpq_tsif_callback(void *user)
{
int tsif = (int)user;
struct mpq_demux *mpq_demux;
MPQ_DVB_DBG_PRINT("%s executed, tsif = %d\n", __func__, tsif);
/* Save statistics on TSIF notifications */
mpq_demux = mpq_dmx_tsif_info.tsif[tsif].mpq_demux;
mpq_dmx_update_hw_statistics(mpq_demux);
atomic_inc(&mpq_dmx_tsif_info.tsif[tsif].data_cnt);
wake_up(&mpq_dmx_tsif_info.tsif[tsif].wait_queue);
}
/**
* Attach to TSIF driver and start TSIF operation.
*
* @mpq_demux: the mpq_demux we are working on.
*
* Return error code.
*/
static int mpq_tsif_dmx_start(struct mpq_demux *mpq_demux)
{
int ret = 0;
int tsif;
struct tsif_driver_info *tsif_driver;
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
"%s: invalid input source (%d)\n",
__func__,
mpq_demux->source);
return -EINVAL;
}
if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
return -ERESTARTSYS;
if (mpq_dmx_tsif_info.tsif[tsif].ref_count == 0) {
tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
/* Attach to TSIF driver */
tsif_driver->tsif_handler =
tsif_attach(tsif, mpq_tsif_callback, (void *)tsif);
if (IS_ERR_OR_NULL(tsif_driver->tsif_handler)) {
tsif_driver->tsif_handler = NULL;
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
MPQ_DVB_DBG_PRINT("%s: tsif_attach(%d) failed\n",
__func__, tsif);
return -ENODEV;
}
ret = tsif_set_clk_inverse(tsif_driver->tsif_handler,
clock_inv);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tsif_set_clk_inverse (%d) failed\n",
__func__, clock_inv);
}
/* Set TSIF driver mode */
ret = tsif_set_mode(tsif_driver->tsif_handler, tsif_mode);
if (ret < 0) {
MPQ_DVB_ERR_PRINT("%s: tsif_set_mode (%d) failed\n",
__func__, tsif_mode);
}
/* Set TSIF buffer configuration */
ret = tsif_set_buf_config(tsif_driver->tsif_handler,
threshold,
DMX_TSIF_CHUNKS_IN_BUF);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: tsif_set_buf_config (%d, %d) failed\n",
__func__, threshold,
DMX_TSIF_CHUNKS_IN_BUF);
MPQ_DVB_ERR_PRINT("Using default TSIF driver values\n");
}
/* Start TSIF driver */
ret = tsif_start(tsif_driver->tsif_handler);
if (ret < 0) {
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
MPQ_DVB_ERR_PRINT("%s: tsif_start failed\n", __func__);
return ret;
}
/*
* Get data buffer information from TSIF driver
* (must be called after tsif_start)
*/
tsif_get_info(tsif_driver->tsif_handler,
&(tsif_driver->data_buffer),
&(tsif_driver->buffer_size));
/* save pointer to the mpq_demux we are working on */
mpq_dmx_tsif_info.tsif[tsif].mpq_demux = mpq_demux;
}
mpq_dmx_tsif_info.tsif[tsif].ref_count++;
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
return ret;
}
/**
* Stop TSIF operation and detach from TSIF driver.
*
* @mpq_demux: the mpq_demux we are working on.
*
* Return error code.
*/
static int mpq_tsif_dmx_stop(struct mpq_demux *mpq_demux)
{
int tsif;
struct tsif_driver_info *tsif_driver;
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
/* determine the TSIF we are reading from */
if (mpq_demux->source == DMX_SOURCE_FRONT0) {
tsif = 0;
} else if (mpq_demux->source == DMX_SOURCE_FRONT1) {
tsif = 1;
} else {
/* invalid source */
MPQ_DVB_ERR_PRINT(
"%s: invalid input source (%d)\n",
__func__,
mpq_demux->source);
return -EINVAL;
}
if (mutex_lock_interruptible(&mpq_dmx_tsif_info.tsif[tsif].mutex))
return -ERESTARTSYS;
mpq_dmx_tsif_info.tsif[tsif].ref_count--;
if (mpq_dmx_tsif_info.tsif[tsif].ref_count == 0) {
tsif_driver = &(mpq_dmx_tsif_info.tsif[tsif].tsif_driver);
tsif_stop(tsif_driver->tsif_handler);
tsif_detach(tsif_driver->tsif_handler);
tsif_driver->tsif_handler = NULL;
tsif_driver->data_buffer = NULL;
tsif_driver->buffer_size = 0;
atomic_set(&mpq_dmx_tsif_info.tsif[tsif].data_cnt, 0);
mpq_dmx_tsif_info.tsif[tsif].mpq_demux = NULL;
}
mutex_unlock(&mpq_dmx_tsif_info.tsif[tsif].mutex);
return 0;
}
/**
* Start filtering according to feed parameter.
*
* @feed: the feed we are working on.
*
* Return error code.
*/
static int mpq_tsif_dmx_start_filtering(struct dvb_demux_feed *feed)
{
int ret = 0;
struct mpq_demux *mpq_demux = feed->demux->priv;
MPQ_DVB_DBG_PRINT(
"%s(%d) executed\n",
__func__,
feed->pid);
if (mpq_demux == NULL) {
MPQ_DVB_ERR_PRINT(
"%s: invalid mpq_demux handle\n",
__func__);
return -EINVAL;
}
if (mpq_demux->source < DMX_SOURCE_DVR0) {
/* Source from TSIF, need to configure TSIF hardware */
ret = mpq_tsif_dmx_start(mpq_demux);
if (ret < 0) {
MPQ_DVB_DBG_PRINT(
"%s: mpq_tsif_dmx_start failed(%d)\n",
__func__,
ret);
return ret;
}
}
/* Always feed sections/PES starting from a new one and
* do not partial transfer data from older one
*/
feed->pusi_seen = 0;
ret = mpq_dmx_init_mpq_feed(feed);
if (ret < 0) {
MPQ_DVB_DBG_PRINT(
"%s: mpq_dmx_init_mpq_feed failed(%d)\n",
__func__,
ret);
if (mpq_demux->source < DMX_SOURCE_DVR0)
mpq_tsif_dmx_stop(mpq_demux);
return ret;
}
return ret;
}
/**
* Stop filtering according to feed parameter.
*
* @feed: the feed we are working on.
*
* Return error code.
*/
static int mpq_tsif_dmx_stop_filtering(struct dvb_demux_feed *feed)
{
int ret = 0;
struct mpq_demux *mpq_demux = feed->demux->priv;
MPQ_DVB_DBG_PRINT(
"%s(%d) executed\n",
__func__,
feed->pid);
if (mpq_demux == NULL) {
MPQ_DVB_ERR_PRINT(
"%s: invalid mpq_demux handle\n",
__func__);
return -EINVAL;
}
mpq_dmx_terminate_feed(feed);
if (mpq_demux->source < DMX_SOURCE_DVR0) {
/* Source from TSIF, need to configure TSIF hardware */
ret = mpq_tsif_dmx_stop(mpq_demux);
}
return ret;
}
/**
* TSIF demux plugin write-to-decoder function.
*
* @feed: The feed we are working on.
* @buf: The data buffer to process.
* @len: The data buffer length.
*
* Return error code
*/
static int mpq_tsif_dmx_write_to_decoder(
struct dvb_demux_feed *feed,
const u8 *buf,
size_t len)
{
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
/*
* It is assumed that this function is called once for each
* TS packet of the relevant feed.
*/
if (len > TSIF_PKT_SIZE)
MPQ_DVB_DBG_PRINT(
"%s: warnning - len larger than one packet\n",
__func__);
if (dvb_dmx_is_video_feed(feed))
return mpq_dmx_process_video_packet(feed, buf);
if (dvb_dmx_is_pcr_feed(feed))
return mpq_dmx_process_pcr_packet(feed, buf);
return 0;
}
/**
* Returns demux capabilities of TSIF plugin
*
* @demux: demux device
* @caps: Returned capbabilities
*
* Return error code
*/
static int mpq_tsif_dmx_get_caps(struct dmx_demux *demux,
struct dmx_caps *caps)
{
struct dvb_demux *dvb_demux = demux->priv;
if ((dvb_demux == NULL) || (caps == NULL)) {
MPQ_DVB_ERR_PRINT(
"%s: invalid parameters\n",
__func__);
return -EINVAL;
}
caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_DECODER_DATA;
caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
caps->num_pid_filters = dvb_demux->feednum;
caps->num_section_filters = dvb_demux->filternum;
caps->num_section_filters_per_pid = dvb_demux->filternum;
caps->section_filter_length = DMX_FILTER_SIZE;
caps->num_demod_inputs = TSIF_COUNT;
caps->num_memory_inputs = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
caps->max_bitrate = 144;
caps->demod_input_max_bitrate = 72;
caps->memory_input_max_bitrate = 72;
/* Buffer requirements */
caps->section.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT;
caps->section.max_buffer_num = 1;
caps->section.max_size = 0xFFFFFFFF;
caps->section.size_alignment = 0;
caps->pes.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT;
caps->pes.max_buffer_num = 1;
caps->pes.max_size = 0xFFFFFFFF;
caps->pes.size_alignment = 0;
caps->recording_188_tsp.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT;
caps->recording_188_tsp.max_buffer_num = 1;
caps->recording_188_tsp.max_size = 0xFFFFFFFF;
caps->recording_188_tsp.size_alignment = 0;
caps->recording_192_tsp.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT;
caps->recording_192_tsp.max_buffer_num = 1;
caps->recording_192_tsp.max_size = 0xFFFFFFFF;
caps->recording_192_tsp.size_alignment = 0;
caps->playback_188_tsp.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT;
caps->playback_188_tsp.max_buffer_num = 1;
caps->playback_188_tsp.max_size = 0xFFFFFFFF;
caps->playback_188_tsp.size_alignment = 0;
caps->playback_192_tsp.flags =
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT;
caps->playback_192_tsp.max_buffer_num = 1;
caps->playback_192_tsp.max_size = 0xFFFFFFFF;
caps->playback_192_tsp.size_alignment = 0;
caps->decoder.flags =
DMX_BUFFER_CONTIGUOUS_MEM |
DMX_BUFFER_SECURED_IF_DECRYPTED |
DMX_BUFFER_EXTERNAL_SUPPORT |
DMX_BUFFER_INTERNAL_SUPPORT |
DMX_BUFFER_LINEAR_GROUP_SUPPORT;
caps->decoder.max_buffer_num = DMX_MAX_DECODER_BUFFER_NUM;
caps->decoder.max_size = 0xFFFFFFFF;
caps->decoder.size_alignment = SZ_4K;
return 0;
}
/**
* Reads TSIF STC from TSPP
*
* @demux: demux device
* @num: STC number. 0 for TSIF0 and 1 for TSIF1.
* @stc: STC value
* @base: divisor to get 90KHz value
*
* Return error code
*/
static int mpq_tsif_dmx_get_stc(struct dmx_demux *demux, unsigned int num,
u64 *stc, unsigned int *base)
{
struct tsif_driver_info *tsif_driver;
u32 tcr_counter;
if (!demux || !stc || !base)
return -EINVAL;
if (num == 0)
tsif_driver = &mpq_dmx_tsif_info.tsif[0].tsif_driver;
else if (num == 1)
tsif_driver = &mpq_dmx_tsif_info.tsif[1].tsif_driver;
else
return -EINVAL;
if (!tsif_driver->tsif_handler)
return -ENODEV;
tsif_get_ref_clk_counter(tsif_driver->tsif_handler, &tcr_counter);
*stc = ((u64)tcr_counter) * 256; /* conversion to 27MHz */
*base = 300; /* divisor to get 90KHz clock from stc value */
return 0;
}
/**
* Initialize a single demux device.
*
* @mpq_adapter: MPQ DVB adapter
* @mpq_demux: The demux device to initialize
*
* Return error code
*/
static int mpq_tsif_dmx_init(
struct dvb_adapter *mpq_adapter,
struct mpq_demux *mpq_demux)
{
int result;
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
/* Set the kernel-demux object capabilities */
mpq_demux->demux.dmx.capabilities =
DMX_TS_FILTERING |
DMX_PES_FILTERING |
DMX_SECTION_FILTERING |
DMX_MEMORY_BASED_FILTERING |
DMX_CRC_CHECKING |
DMX_TS_DESCRAMBLING;
/* Set dvb-demux "virtual" function pointers */
mpq_demux->demux.priv = (void *)mpq_demux;
mpq_demux->demux.filternum = DMX_TSIF_MAX_SECTION_FILTER_NUM;
mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES;
mpq_demux->demux.start_feed = mpq_tsif_dmx_start_filtering;
mpq_demux->demux.stop_feed = mpq_tsif_dmx_stop_filtering;
mpq_demux->demux.write_to_decoder = mpq_tsif_dmx_write_to_decoder;
mpq_demux->demux.decoder_fullness_init = mpq_dmx_decoder_fullness_init;
mpq_demux->demux.decoder_fullness_wait = mpq_dmx_decoder_fullness_wait;
mpq_demux->demux.decoder_fullness_abort =
mpq_dmx_decoder_fullness_abort;
mpq_demux->demux.decoder_buffer_status = mpq_dmx_decoder_buffer_status;
mpq_demux->demux.reuse_decoder_buffer = mpq_dmx_reuse_decoder_buffer;
mpq_demux->demux.set_secure_mode = NULL;
mpq_demux->demux.oob_command = mpq_dmx_oob_command;
mpq_demux->demux.convert_ts = mpq_dmx_convert_tts;
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
if (result < 0) {
MPQ_DVB_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
goto init_failed;
}
/* Now initailize the dmx-dev object */
mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
DMXDEV_CAP_INDEXING |
DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_stc = mpq_tsif_dmx_get_stc;
mpq_demux->dmxdev.demux->get_caps = mpq_tsif_dmx_get_caps;
mpq_demux->dmxdev.demux->map_buffer = mpq_dmx_map_buffer;
mpq_demux->dmxdev.demux->unmap_buffer = mpq_dmx_unmap_buffer;
result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
if (result < 0) {
MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
__func__,
result);
goto init_failed_dmx_release;
}
/* Extend dvb-demux debugfs with TSIF statistics. */
mpq_dmx_init_debugfs_entries(mpq_demux);
return 0;
init_failed_dmx_release:
dvb_dmx_release(&mpq_demux->demux);
init_failed:
return result;
}
/**
* Module initialization function.
*
* Return error code
*/
static int __init mpq_dmx_tsif_plugin_init(void)
{
int i;
int ret;
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
/* check module parameters validity */
if (threshold < 1) {
MPQ_DVB_ERR_PRINT(
"%s: invalid threshold parameter, using %d instead\n",
__func__, DMX_TSIF_PACKETS_IN_CHUNK_DEF);
threshold = DMX_TSIF_PACKETS_IN_CHUNK_DEF;
}
if ((tsif_mode < 1) || (tsif_mode > 3)) {
MPQ_DVB_ERR_PRINT(
"%s: invalid mode parameter, using %d instead\n",
__func__, DMX_TSIF_DRIVER_MODE_DEF);
tsif_mode = DMX_TSIF_DRIVER_MODE_DEF;
}
for (i = 0; i < TSIF_COUNT; i++) {
snprintf(mpq_dmx_tsif_info.tsif[i].name,
TSIF_NAME_LENGTH,
"dmx_tsif%d",
i);
atomic_set(&mpq_dmx_tsif_info.tsif[i].data_cnt, 0);
init_waitqueue_head(&mpq_dmx_tsif_info.tsif[i].wait_queue);
mpq_dmx_tsif_info.tsif[i].thread =
kthread_run(
mpq_dmx_tsif_thread, (void *)i,
mpq_dmx_tsif_info.tsif[i].name);
if (IS_ERR(mpq_dmx_tsif_info.tsif[i].thread)) {
int j;
for (j = 0; j < i; j++) {
kthread_stop(mpq_dmx_tsif_info.tsif[j].thread);
mutex_destroy(&mpq_dmx_tsif_info.tsif[j].mutex);
}
MPQ_DVB_ERR_PRINT(
"%s: kthread_run failed\n",
__func__);
return -ENOMEM;
}
mutex_init(&mpq_dmx_tsif_info.tsif[i].mutex);
mpq_dmx_tsif_info.tsif[i].tsif_driver.tsif_handler = NULL;
mpq_dmx_tsif_info.tsif[i].ref_count = 0;
}
ret = mpq_dmx_plugin_init(mpq_tsif_dmx_init);
if (ret < 0) {
MPQ_DVB_ERR_PRINT(
"%s: mpq_dmx_plugin_init failed (errno=%d)\n",
__func__,
ret);
for (i = 0; i < TSIF_COUNT; i++) {
kthread_stop(mpq_dmx_tsif_info.tsif[i].thread);
mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
}
}
return ret;
}
/**
* Module exit function.
*/
static void __exit mpq_dmx_tsif_plugin_exit(void)
{
int i;
struct tsif_driver_info *tsif_driver;
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
for (i = 0; i < TSIF_COUNT; i++) {
mutex_lock(&mpq_dmx_tsif_info.tsif[i].mutex);
tsif_driver = &(mpq_dmx_tsif_info.tsif[i].tsif_driver);
if (mpq_dmx_tsif_info.tsif[i].ref_count > 0) {
mpq_dmx_tsif_info.tsif[i].ref_count = 0;
if (tsif_driver->tsif_handler)
tsif_stop(tsif_driver->tsif_handler);
}
/* Detach from TSIF driver to avoid further notifications. */
if (tsif_driver->tsif_handler)
tsif_detach(tsif_driver->tsif_handler);
mutex_unlock(&mpq_dmx_tsif_info.tsif[i].mutex);
kthread_stop(mpq_dmx_tsif_info.tsif[i].thread);
mutex_destroy(&mpq_dmx_tsif_info.tsif[i].mutex);
}
mpq_dmx_plugin_exit();
}
module_init(mpq_dmx_tsif_plugin_init);
module_exit(mpq_dmx_tsif_plugin_exit);
MODULE_DESCRIPTION("Qualcomm demux TSIF HW Plugin");
MODULE_LICENSE("GPL v2");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,188 @@
/* Copyright (c) 2012-2013, The Linux Foundation. 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include "mpq_dvb_debug.h"
#include "mpq_dmx_plugin_common.h"
#define TSIF_COUNT 2
#define BAM_INPUT_COUNT 4
/* Max number of PID filters */
#define TSPP_MAX_PID_FILTER_NUM 128
/* Max number of section filters */
#define TSPP_MAX_SECTION_FILTER_NUM 64
static int mpq_tspp_dmx_start_filtering(struct dvb_demux_feed *feed)
{
MPQ_DVB_DBG_PRINT(
"%s(%d) executed\n",
__func__,
feed->pid);
/* Always feed sections/PES starting from a new one and
* do not partial transfer data from older one
*/
feed->pusi_seen = 0;
return 0;
}
static int mpq_tspp_dmx_stop_filtering(struct dvb_demux_feed *feed)
{
MPQ_DVB_DBG_PRINT(
"%s(%d) executed\n",
__func__,
feed->pid);
return 0;
}
/**
* Returns demux capabilities of TSPPv2 plugin
*
* @demux: demux device
* @caps: Returned capbabilities
*
* Return error code
*/
static int mpq_tspp_dmx_get_caps(struct dmx_demux *demux,
struct dmx_caps *caps)
{
struct dvb_demux *dvb_demux = demux->priv;
if ((dvb_demux == NULL) || (caps == NULL)) {
MPQ_DVB_ERR_PRINT(
"%s: invalid parameters\n",
__func__);
return -EINVAL;
}
caps->caps = DMX_CAP_PULL_MODE | DMX_CAP_VIDEO_INDEXING |
DMX_CAP_VIDEO_DECODER_DATA;
caps->num_decoders = MPQ_ADAPTER_MAX_NUM_OF_INTERFACES;
caps->num_demux_devices = CONFIG_DVB_MPQ_NUM_DMX_DEVICES;
caps->num_pid_filters = TSPP_MAX_PID_FILTER_NUM;
caps->num_section_filters = dvb_demux->filternum;
caps->num_section_filters_per_pid = dvb_demux->filternum;
caps->section_filter_length = DMX_FILTER_SIZE;
caps->num_demod_inputs = TSIF_COUNT;
caps->num_memory_inputs = BAM_INPUT_COUNT;
caps->max_bitrate = 320;
caps->demod_input_max_bitrate = 96;
caps->memory_input_max_bitrate = 80;
return 0;
}
/**
* Initialize a single demux device.
*
* @mpq_adapter: MPQ DVB adapter
* @mpq_demux: The demux device to initialize
*
* Return error code
*/
static int mpq_tspp_dmx_init(
struct dvb_adapter *mpq_adapter,
struct mpq_demux *mpq_demux)
{
int result;
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
/* Set the kernel-demux object capabilities */
mpq_demux->demux.dmx.capabilities =
DMX_TS_FILTERING |
DMX_PES_FILTERING |
DMX_SECTION_FILTERING |
DMX_MEMORY_BASED_FILTERING |
DMX_CRC_CHECKING |
DMX_TS_DESCRAMBLING;
/* Set dvb-demux "virtual" function pointers */
mpq_demux->demux.priv = (void *)mpq_demux;
mpq_demux->demux.filternum = TSPP_MAX_SECTION_FILTER_NUM;
mpq_demux->demux.feednum = MPQ_MAX_DMX_FILES;
mpq_demux->demux.start_feed = mpq_tspp_dmx_start_filtering;
mpq_demux->demux.stop_feed = mpq_tspp_dmx_stop_filtering;
mpq_demux->demux.write_to_decoder = NULL;
mpq_demux->demux.decoder_fullness_init = NULL;
mpq_demux->demux.decoder_fullness_wait = NULL;
mpq_demux->demux.decoder_fullness_abort = NULL;
mpq_demux->demux.decoder_buffer_status = NULL;
mpq_demux->demux.reuse_decoder_buffer = NULL;
mpq_demux->demux.set_secure_mode = NULL;
mpq_demux->demux.oob_command = NULL;
mpq_demux->demux.convert_ts = NULL;
/* Initialize dvb_demux object */
result = dvb_dmx_init(&mpq_demux->demux);
if (result < 0) {
MPQ_ERR_PRINT("%s: dvb_dmx_init failed\n", __func__);
goto init_failed;
}
/* Now initailize the dmx-dev object */
mpq_demux->dmxdev.filternum = MPQ_MAX_DMX_FILES;
mpq_demux->dmxdev.demux = &mpq_demux->demux.dmx;
mpq_demux->dmxdev.capabilities =
DMXDEV_CAP_DUPLEX |
DMXDEV_CAP_PULL_MODE |
DMXDEV_CAP_INDEXING |
DMXDEV_CAP_TS_INSERTION;
mpq_demux->dmxdev.demux->set_source = mpq_dmx_set_source;
mpq_demux->dmxdev.demux->get_caps = mpq_tspp_dmx_get_caps;
result = dvb_dmxdev_init(&mpq_demux->dmxdev, mpq_adapter);
if (result < 0) {
MPQ_DVB_ERR_PRINT("%s: dvb_dmxdev_init failed (errno=%d)\n",
__func__,
result);
goto init_failed_dmx_release;
}
return 0;
init_failed_dmx_release:
dvb_dmx_release(&mpq_demux->demux);
init_failed:
return result;
}
static int __init mpq_dmx_tspp_plugin_init(void)
{
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
return mpq_dmx_plugin_init(mpq_tspp_dmx_init);
}
static void __exit mpq_dmx_tspp_plugin_exit(void)
{
MPQ_DVB_DBG_PRINT("%s executed\n", __func__);
mpq_dmx_plugin_exit();
}
module_init(mpq_dmx_tspp_plugin_init);
module_exit(mpq_dmx_tspp_plugin_exit);
MODULE_DESCRIPTION("Qualcomm demux TSPP version2 HW Plugin");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,993 @@
/* Copyright (c) 2013, The Linux Foundation. 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.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kthread.h>
#include <linux/slab.h>
#include <linux/mutex.h>
#include "qseecom_kernel.h"
#include "mpq_sdmx.h"
static struct qseecom_handle *sdmx_qseecom_handles[SDMX_MAX_SESSIONS];
static struct mutex sdmx_lock[SDMX_MAX_SESSIONS];
#define QSEECOM_ALIGN_SIZE 0x40
#define QSEECOM_ALIGN_MASK (QSEECOM_ALIGN_SIZE - 1)
#define QSEECOM_ALIGN(x) \
((x + QSEECOM_ALIGN_SIZE) & (~QSEECOM_ALIGN_MASK))
enum sdmx_cmd_id {
SDMX_OPEN_SESSION_CMD,
SDMX_CLOSE_SESSION_CMD,
SDMX_SET_SESSION_CFG_CMD,
SDMX_ADD_FILTER_CMD,
SDMX_REMOVE_FILTER_CMD,
SDMX_SET_KL_IDX_CMD,
SDMX_ADD_RAW_PID_CMD,
SDMX_REMOVE_RAW_PID_CMD,
SDMX_PROCESS_CMD,
SDMX_GET_DBG_COUNTERS_CMD,
SDMX_RESET_DBG_COUNTERS_CMD,
SDMX_GET_VERSION_CMD,
SDMX_INVALIDATE_KL_CMD,
SDMX_SET_LOG_LEVEL_CMD
};
struct sdmx_proc_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u8 flags;
struct sdmx_buff_descr in_buf_descr;
u32 inp_fill_cnt;
u32 in_rd_offset;
u32 num_filters;
struct sdmx_filter_status filters_status[];
};
struct sdmx_proc_rsp {
enum sdmx_status ret;
u32 inp_fill_cnt;
u32 in_rd_offset;
u32 err_indicators;
u32 status_indicators;
};
struct sdmx_open_ses_req {
enum sdmx_cmd_id cmd_id;
};
struct sdmx_open_ses_rsp {
enum sdmx_status ret;
u32 session_handle;
};
struct sdmx_close_ses_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
};
struct sdmx_close_ses_rsp {
enum sdmx_status ret;
};
struct sdmx_ses_cfg_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
enum sdmx_proc_mode process_mode;
enum sdmx_inp_mode input_mode;
enum sdmx_pkt_format packet_len;
u8 odd_scramble_bits;
u8 even_scramble_bits;
};
struct sdmx_ses_cfg_rsp {
enum sdmx_status ret;
};
struct sdmx_set_kl_ind_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u32 pid;
u32 kl_index;
};
struct sdmx_set_kl_ind_rsp {
enum sdmx_status ret;
};
struct sdmx_add_filt_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u32 pid;
enum sdmx_filter filter_type;
struct sdmx_buff_descr meta_data_buf;
enum sdmx_buf_mode buffer_mode;
enum sdmx_raw_out_format ts_out_format;
u32 flags;
u32 num_data_bufs;
struct sdmx_data_buff_descr data_bufs[];
};
struct sdmx_add_filt_rsp {
enum sdmx_status ret;
u32 filter_handle;
};
struct sdmx_rem_filt_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u32 filter_handle;
};
struct sdmx_rem_filt_rsp {
enum sdmx_status ret;
};
struct sdmx_add_raw_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u32 filter_handle;
u32 pid;
};
struct sdmx_add_raw_rsp {
enum sdmx_status ret;
};
struct sdmx_rem_raw_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u32 filter_handle;
u32 pid;
};
struct sdmx_rem_raw_rsp {
enum sdmx_status ret;
};
struct sdmx_get_counters_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
u32 num_filters;
};
struct sdmx_get_counters_rsp {
enum sdmx_status ret;
struct sdmx_session_dbg_counters session_counters;
u32 num_filters;
struct sdmx_filter_dbg_counters filter_counters[];
};
struct sdmx_rst_counters_req {
enum sdmx_cmd_id cmd_id;
u32 session_handle;
};
struct sdmx_rst_counters_rsp {
enum sdmx_status ret;
};
struct sdmx_get_version_req {
enum sdmx_cmd_id cmd_id;
};
struct sdmx_get_version_rsp {
enum sdmx_status ret;
int32_t version;
};
struct sdmx_set_log_level_req {
enum sdmx_cmd_id cmd_id;
enum sdmx_log_level level;
u32 session_handle;
};
struct sdmx_set_log_level_rsp {
enum sdmx_status ret;
};
static void get_cmd_rsp_buffers(int handle_index,
void **cmd,
int *cmd_len,
void **rsp,
int *rsp_len)
{
*cmd = sdmx_qseecom_handles[handle_index]->sbuf;
if (*cmd_len & QSEECOM_ALIGN_MASK)
*cmd_len = QSEECOM_ALIGN(*cmd_len);
*rsp = sdmx_qseecom_handles[handle_index]->sbuf + *cmd_len;
if (*rsp_len & QSEECOM_ALIGN_MASK)
*rsp_len = QSEECOM_ALIGN(*rsp_len);
}
/*
* Returns version of secure-demux app.
*
* @session_handle: Returned instance handle. Must not be NULL.
* Return error code
*/
int sdmx_get_version(int session_handle, int32_t *version)
{
int res, cmd_len, rsp_len;
struct sdmx_get_version_req *cmd;
struct sdmx_get_version_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
(version == NULL))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_get_version_req);
rsp_len = sizeof(struct sdmx_get_version_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_GET_VERSION_CMD;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
*version = rsp->version;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_get_version);
/*
* Initializes a new secure demux instance and returns a handle of the instance.
*
* @session_handle: handle of a secure demux instance to get its version.
* Return the version if successfull or an error code.
*/
int sdmx_open_session(int *session_handle)
{
int res, cmd_len, rsp_len;
enum sdmx_status ret, version_ret;
struct sdmx_open_ses_req *cmd;
struct sdmx_open_ses_rsp *rsp;
struct qseecom_handle *qseecom_handle = NULL;
int32_t version;
/* Input validation */
if (session_handle == NULL)
return SDMX_STATUS_GENERAL_FAILURE;
/* Start the TZ app */
res = qseecom_start_app(&qseecom_handle, "securemm", 4096);
if (res < 0)
return SDMX_STATUS_GENERAL_FAILURE;
cmd_len = sizeof(struct sdmx_open_ses_req);
rsp_len = sizeof(struct sdmx_open_ses_rsp);
/* Get command and response buffers */
cmd = (struct sdmx_open_ses_req *)qseecom_handle->sbuf;
if (cmd_len & QSEECOM_ALIGN_MASK)
cmd_len = QSEECOM_ALIGN(cmd_len);
rsp = (struct sdmx_open_ses_rsp *)qseecom_handle->sbuf + cmd_len;
if (rsp_len & QSEECOM_ALIGN_MASK)
rsp_len = QSEECOM_ALIGN(rsp_len);
/* Will be later overridden by SDMX response */
*session_handle = SDMX_INVALID_SESSION_HANDLE;
/* Populate command struct */
cmd->cmd_id = SDMX_OPEN_SESSION_CMD;
/* Issue QSEECom command */
res = qseecom_send_command(qseecom_handle, (void *)cmd, cmd_len,
(void *)rsp, rsp_len);
if (res < 0) {
qseecom_shutdown_app(&qseecom_handle);
return SDMX_STATUS_GENERAL_FAILURE;
}
/* Parse response struct */
*session_handle = rsp->session_handle;
/* Initialize handle and mutex */
sdmx_qseecom_handles[*session_handle] = qseecom_handle;
mutex_init(&sdmx_lock[*session_handle]);
ret = rsp->ret;
/* Get and print the app version */
version_ret = sdmx_get_version(*session_handle, &version);
if (SDMX_SUCCESS == version_ret)
pr_info("TZ SDMX version is %x.%x\n", version >> 8,
version & 0xFF);
else
pr_err("Error reading TZ SDMX version\n");
return ret;
}
EXPORT_SYMBOL(sdmx_open_session);
/*
* Closes a secure demux instance.
*
* @session_handle: handle of a secure demux instance to close.
* Return error code
*/
int sdmx_close_session(int session_handle)
{
int res, cmd_len, rsp_len;
struct sdmx_close_ses_req *cmd;
struct sdmx_close_ses_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_close_ses_req);
rsp_len = sizeof(struct sdmx_close_ses_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_CLOSE_SESSION_CMD;
cmd->session_handle = session_handle;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
/* Shutdown the TZ app (or at least free the current handle) */
res = qseecom_shutdown_app(&sdmx_qseecom_handles[session_handle]);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
sdmx_qseecom_handles[session_handle] = NULL;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_close_session);
/*
* Configures an open secure demux instance.
*
* @session_handle: secure demux instance
* @proc_mode: Defines secure demux's behavior in case of output
* buffer overflow.
* @inp_mode: Defines the input encryption settings.
* @pkt_format: TS packet length in input buffer.
* @odd_scramble_bits: Value of the scramble bits indicating the ODD key.
* @even_scramble_bits: Value of the scramble bits indicating the EVEN key.
* Return error code
*/
int sdmx_set_session_cfg(int session_handle,
enum sdmx_proc_mode proc_mode,
enum sdmx_inp_mode inp_mode,
enum sdmx_pkt_format pkt_format,
u8 odd_scramble_bits,
u8 even_scramble_bits)
{
int res, cmd_len, rsp_len;
struct sdmx_ses_cfg_req *cmd;
struct sdmx_ses_cfg_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_ses_cfg_req);
rsp_len = sizeof(struct sdmx_ses_cfg_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_SET_SESSION_CFG_CMD;
cmd->session_handle = session_handle;
cmd->process_mode = proc_mode;
cmd->input_mode = inp_mode;
cmd->packet_len = pkt_format;
cmd->odd_scramble_bits = odd_scramble_bits;
cmd->even_scramble_bits = even_scramble_bits;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_set_session_cfg);
/*
* Creates a new secure demux filter and returns a filter handle
*
* @session_handle: secure demux instance
* @pid: pid to filter
* @filter_type: type of filtering
* @meta_data_buf: meta data buffer descriptor
* @data_buf_mode: data buffer mode (ring/linear)
* @num_data_bufs: number of data buffers (use 1 for a ring buffer)
* @data_bufs: data buffers descriptors array
* @filter_handle: returned filter handle
* @ts_out_format: output format for raw filters
* @flags: optional flags for filter
* (currently only clear section CRC verification is supported)
*
* Return error code
*/
int sdmx_add_filter(int session_handle,
u16 pid,
enum sdmx_filter filterype,
struct sdmx_buff_descr *meta_data_buf,
enum sdmx_buf_mode d_buf_mode,
u32 num_data_bufs,
struct sdmx_data_buff_descr *data_bufs,
int *filter_handle,
enum sdmx_raw_out_format ts_out_format,
u32 flags)
{
int res, cmd_len, rsp_len;
struct sdmx_add_filt_req *cmd;
struct sdmx_add_filt_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
(filter_handle == NULL))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_add_filt_req)
+ num_data_bufs * sizeof(struct sdmx_data_buff_descr);
rsp_len = sizeof(struct sdmx_add_filt_rsp);
/* Will be later overridden by SDMX response */
*filter_handle = SDMX_INVALID_FILTER_HANDLE;
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_ADD_FILTER_CMD;
cmd->session_handle = session_handle;
cmd->pid = (u32)pid;
cmd->filter_type = filterype;
cmd->ts_out_format = ts_out_format;
cmd->flags = flags;
if (meta_data_buf != NULL)
memcpy(&(cmd->meta_data_buf), meta_data_buf,
sizeof(struct sdmx_buff_descr));
else
memset(&(cmd->meta_data_buf), 0,
sizeof(struct sdmx_buff_descr));
cmd->buffer_mode = d_buf_mode;
cmd->num_data_bufs = num_data_bufs;
memcpy(cmd->data_bufs, data_bufs,
num_data_bufs * sizeof(struct sdmx_data_buff_descr));
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
/* Parse response struct */
*filter_handle = rsp->filter_handle;
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_add_filter);
/*
* Removes a secure demux filter
*
* @session_handle: secure demux instance
* @filter_handle: filter handle to remove
*
* Return error code
*/
int sdmx_remove_filter(int session_handle, int filter_handle)
{
int res, cmd_len, rsp_len;
struct sdmx_rem_filt_req *cmd;
struct sdmx_rem_filt_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_rem_filt_req);
rsp_len = sizeof(struct sdmx_rem_filt_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_REMOVE_FILTER_CMD;
cmd->session_handle = session_handle;
cmd->filter_handle = filter_handle;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_remove_filter);
/*
* Associates a key ladder index for the specified pid
*
* @session_handle: secure demux instance
* @pid: pid
* @key_ladder_index: key ladder index to associate to the pid
*
* Return error code
*
* Note: if pid already has some key ladder index associated, it will be
* overridden.
*/
int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index)
{
int res, cmd_len, rsp_len;
struct sdmx_set_kl_ind_req *cmd;
struct sdmx_set_kl_ind_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_set_kl_ind_req);
rsp_len = sizeof(struct sdmx_set_kl_ind_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_SET_KL_IDX_CMD;
cmd->session_handle = session_handle;
cmd->pid = (u32)pid;
cmd->kl_index = key_ladder_index;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_set_kl_ind);
/*
* Adds the specified pid to an existing raw (recording) filter
*
* @session_handle: secure demux instance
* @filter_handle: raw filter handle
* @pid: pid
*
* Return error code
*/
int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid)
{
int res, cmd_len, rsp_len;
struct sdmx_add_raw_req *cmd;
struct sdmx_add_raw_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_add_raw_req);
rsp_len = sizeof(struct sdmx_add_raw_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_ADD_RAW_PID_CMD;
cmd->session_handle = session_handle;
cmd->filter_handle = filter_handle;
cmd->pid = (u32)pid;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_add_raw_pid);
/*
* Removes the specified pid from a raw (recording) filter
*
* @session_handle: secure demux instance
* @filter_handle: raw filter handle
* @pid: pid
*
* Return error code
*/
int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid)
{
int res, cmd_len, rsp_len;
struct sdmx_rem_raw_req *cmd;
struct sdmx_rem_raw_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_rem_raw_req);
rsp_len = sizeof(struct sdmx_rem_raw_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_REMOVE_RAW_PID_CMD;
cmd->session_handle = session_handle;
cmd->filter_handle = filter_handle;
cmd->pid = (u32)pid;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_remove_raw_pid);
/*
* Call secure demux to perform processing on the specified input buffer
*
* @session_handle: secure demux instance
* @flags: input flags. Currently only EOS marking is supported.
* @input_buf_desc: input buffer descriptor
* @input_fill_count: number of bytes available in input buffer
* @input_read_offset: offset inside input buffer where data starts
* @error_indicators: returned general error indicators
* @status_indicators: returned general status indicators
* @num_filters: number of filters in filter status array
* @filter_status: filter status descriptor array
*
* Return error code
*/
int sdmx_process(int session_handle, u8 flags,
struct sdmx_buff_descr *input_buf_desc,
u32 *input_fill_count,
u32 *input_read_offset,
u32 *error_indicators,
u32 *status_indicators,
u32 num_filters,
struct sdmx_filter_status *filter_status)
{
int res, cmd_len, rsp_len;
struct sdmx_proc_req *cmd;
struct sdmx_proc_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
(input_buf_desc == NULL) ||
(input_fill_count == NULL) || (input_read_offset == NULL) ||
(error_indicators == NULL) || (status_indicators == NULL) ||
(filter_status == NULL))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_proc_req)
+ num_filters * sizeof(struct sdmx_filter_status);
rsp_len = sizeof(struct sdmx_proc_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_PROCESS_CMD;
cmd->session_handle = session_handle;
cmd->flags = flags;
cmd->in_buf_descr.base_addr = input_buf_desc->base_addr;
cmd->in_buf_descr.size = input_buf_desc->size;
cmd->inp_fill_cnt = *input_fill_count;
cmd->in_rd_offset = *input_read_offset;
cmd->num_filters = num_filters;
memcpy(cmd->filters_status, filter_status,
num_filters * sizeof(struct sdmx_filter_status));
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
/* Parse response struct */
*input_fill_count = rsp->inp_fill_cnt;
*input_read_offset = rsp->in_rd_offset;
*error_indicators = rsp->err_indicators;
*status_indicators = rsp->status_indicators;
memcpy(filter_status, cmd->filters_status,
num_filters * sizeof(struct sdmx_filter_status));
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_process);
/*
* Returns session-level & filter-level debug counters
*
* @session_handle: secure demux instance
* @session_counters: returned session-level debug counters
* @num_filters: returned number of filters reported in filter_counters
* @filter_counters: returned filter-level debug counters array
*
* Return error code
*/
int sdmx_get_dbg_counters(int session_handle,
struct sdmx_session_dbg_counters *session_counters,
u32 *num_filters,
struct sdmx_filter_dbg_counters *filter_counters)
{
int res, cmd_len, rsp_len;
struct sdmx_get_counters_req *cmd;
struct sdmx_get_counters_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS) ||
(session_counters == NULL) || (num_filters == NULL) ||
(filter_counters == NULL))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_get_counters_req);
rsp_len = sizeof(struct sdmx_get_counters_rsp)
+ *num_filters * sizeof(struct sdmx_filter_dbg_counters);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_GET_DBG_COUNTERS_CMD;
cmd->session_handle = session_handle;
cmd->num_filters = *num_filters;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
/* Parse response struct */
*session_counters = rsp->session_counters;
*num_filters = rsp->num_filters;
memcpy(filter_counters, rsp->filter_counters,
*num_filters * sizeof(struct sdmx_filter_dbg_counters));
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_get_dbg_counters);
/*
* Reset debug counters
*
* @session_handle: secure demux instance
*
* Return error code
*/
int sdmx_reset_dbg_counters(int session_handle)
{
int res, cmd_len, rsp_len;
struct sdmx_rst_counters_req *cmd;
struct sdmx_rst_counters_rsp *rsp;
enum sdmx_status ret;
if ((session_handle < 0) || (session_handle >= SDMX_MAX_SESSIONS))
return SDMX_STATUS_INVALID_INPUT_PARAMS;
cmd_len = sizeof(struct sdmx_rst_counters_req);
rsp_len = sizeof(struct sdmx_rst_counters_rsp);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Populate command struct */
cmd->cmd_id = SDMX_RESET_DBG_COUNTERS_CMD;
cmd->session_handle = session_handle;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}
EXPORT_SYMBOL(sdmx_reset_dbg_counters);
/*
* Set debug log verbosity level
*
* @session_handle: secure demux instance
* @level: requested log level
*
* Return error code
*/
int sdmx_set_log_level(int session_handle, enum sdmx_log_level level)
{
int res, cmd_len, rsp_len;
struct sdmx_set_log_level_req *cmd;
struct sdmx_set_log_level_rsp *rsp;
enum sdmx_status ret;
cmd_len = sizeof(struct sdmx_set_log_level_req);
rsp_len = sizeof(struct sdmx_set_log_level_rsp);
/* Get command and response buffers */
get_cmd_rsp_buffers(session_handle, (void **)&cmd, &cmd_len,
(void **)&rsp, &rsp_len);
/* Lock shared memory */
mutex_lock(&sdmx_lock[session_handle]);
/* Populate command struct */
cmd->cmd_id = SDMX_SET_LOG_LEVEL_CMD;
cmd->session_handle = session_handle;
cmd->level = level;
/* Issue QSEECom command */
res = qseecom_send_command(sdmx_qseecom_handles[session_handle],
(void *)cmd, cmd_len, (void *)rsp, rsp_len);
if (res < 0) {
mutex_unlock(&sdmx_lock[session_handle]);
return SDMX_STATUS_GENERAL_FAILURE;
}
ret = rsp->ret;
/* Unlock */
mutex_unlock(&sdmx_lock[session_handle]);
return ret;
}

View File

@ -0,0 +1,272 @@
/* Copyright (c) 2013, The Linux Foundation. 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_SDMX_H
#define _MPQ_SDMX_H
#include <linux/types.h>
/* Constant declarations */
#define SDMX_MAX_SESSIONS (4)
#define SDMX_LOOPBACK_PID (0x2000)
#define SDMX_MAX_PHYSICAL_CHUNKS (10)
/* Filter-level error indicators */
#define SDMX_FILTER_SUCCESS (0)
#define SDMX_FILTER_ERR_MD_BUF_FULL BIT(0)
#define SDMX_FILTER_ERR_D_BUF_FULL BIT(1)
#define SDMX_FILTER_ERR_D_LIN_BUFS_FULL BIT(2)
#define SDMX_FILTER_ERR_INVALID_SCRAMBLE_BITS BIT(3)
#define SDMX_FILTER_ERR_KL_IND_NOT_SET BIT(4)
#define SDMX_FILTER_ERR_CAS_DECRYPT_ERROR BIT(5)
#define SDMX_FILTER_ERR_SEC_VERIF_CRC32_FAIL BIT(6)
#define SDMX_FILTER_ERR_SEC_INTERNAL_MALLOC_FAIL BIT(7)
#define SDMX_FILTER_ERR_SEC_LEN_INVALID BIT(8)
#define SDMX_FILTER_ERR_SEC_PUSI_PTR_INVALID BIT(9)
#define SDMX_FILTER_ERR_TS_SYNC_BYTE_INVALID BIT(10)
#define SDMX_FILTER_ERR_TS_TRANSPORT_ERR BIT(11)
#define SDMX_FILTER_ERR_CONT_CNT_INVALID BIT(12)
#define SDMX_FILTER_ERR_CONT_CNT_DUPLICATE BIT(13)
#define SDMX_FILTER_ERR_INVALID_PES_HDR BIT(14)
#define SDMX_FILTER_ERR_INVALID_PES_LEN BIT(15)
#define SDMX_FILTER_ERR_INVALID_PES_ENCRYPTION BIT(16)
#define SDMX_FILTER_ERR_SECURITY_FAULT BIT(17)
#define SDMX_FILTER_ERR_IN_NS_BUFFER BIT(18)
/* Filter-level status indicators */
#define SDMX_FILTER_STATUS_EOS BIT(0)
#define SDMX_FILTER_STATUS_WR_PTR_CHANGED BIT(1)
/* Filter-level flags */
#define SDMX_FILTER_FLAG_VERIFY_SECTION_CRC BIT(0)
#define SDMX_INVALID_SESSION_HANDLE (-1)
#define SDMX_INVALID_FILTER_HANDLE (-1)
/* Input flags */
#define SDMX_INPUT_FLAG_EOS BIT(0)
#define SDMX_INPUT_FLAG_DBG_ENABLE BIT(1)
enum sdmx_buf_mode {
SDMX_RING_BUF,
SDMX_LINEAR_GROUP_BUF,
};
enum sdmx_proc_mode {
SDMX_PUSH_MODE,
SDMX_PULL_MODE,
};
enum sdmx_inp_mode {
SDMX_PKT_ENC_MODE,
SDMX_BULK_ENC_MODE,
SDMX_CLEAR_MODE,
};
enum sdmx_pkt_format {
SDMX_188_BYTE_PKT = 188,
SDMX_192_BYTE_PKT = 192,
SDMX_195_BYTE_PKT = 195,
};
enum sdmx_log_level {
SDMX_LOG_NO_PRINT,
SDMX_LOG_MSG_ERROR,
SDMX_LOG_DEBUG,
SDMX_LOG_VERBOSE
};
enum sdmx_status {
SDMX_SUCCESS = 0,
SDMX_STATUS_GENERAL_FAILURE = -1,
SDMX_STATUS_MAX_OPEN_SESSIONS_REACHED = -2,
SDMX_STATUS_INVALID_SESSION_HANDLE = -3,
SDMX_STATUS_INVALID_INPUT_PARAMS = -4,
SDMX_STATUS_UNSUPPORTED_MODE = -5,
SDMX_STATUS_INVALID_PID = -6,
SDMX_STATUS_OUT_OF_MEM = -7,
SDMX_STATUS_FILTER_EXISTS = -8,
SDMX_STATUS_INVALID_FILTER_HANDLE = -9,
SDMX_STATUS_MAX_RAW_PIDS_REACHED = -10,
SDMX_STATUS_SINGLE_PID_RAW_FILTER = -11,
SDMX_STATUS_INP_BUF_INVALID_PARAMS = -12,
SDMX_STATUS_INVALID_FILTER_CFG = -13,
SDMX_STATUS_STALLED_IN_PULL_MODE = -14,
SDMX_STATUS_SECURITY_FAULT = -15,
SDMX_STATUS_NS_BUFFER_ERROR = -16,
};
enum sdmx_filter {
SDMX_PES_FILTER, /* Other PES */
SDMX_SEPARATED_PES_FILTER, /* Separated PES (for decoder) */
SDMX_SECTION_FILTER, /* Section */
SDMX_PCR_FILTER, /* PCR */
SDMX_RAW_FILTER, /* Recording */
};
enum sdmx_raw_out_format {
SDMX_188_OUTPUT,
SDMX_192_HEAD_OUTPUT,
SDMX_192_TAIL_OUTPUT
};
struct sdmx_session_dbg_counters {
/* Total number of TS-packets input to SDMX. */
u32 ts_pkt_in;
/* Total number of TS-packets filtered out by SDMX. */
u32 ts_pkt_out;
};
struct sdmx_filter_dbg_counters {
int filter_handle;
/* Number of TS-packets filtered. */
u32 ts_pkt_count;
/* Number of TS-packets with adaptation field only (no payload). */
u32 ts_pkt_no_payload;
/* Number of TS-packets with the discontinuity indicator set. */
u32 ts_pkt_discont;
/* Number of duplicate TS-packets detected. */
u32 ts_pkt_dup;
/* Number of packets not decrypted because the key wasn't ready. */
u32 ts_pkt_key_not_ready;
};
struct sdmx_pes_counters {
/* Number of TS packets with the TEI flag set */
u32 transport_err_count;
/* Number of TS packets with continuity counter errors */
u32 continuity_err_count;
/* Number of TS packets composing this PES frame */
u32 pes_ts_count;
/* Number of TS packets dropped due to full buffer */
u32 drop_count;
};
struct sdmx_buff_descr {
/* Physical address where buffer starts */
void *base_addr;
/* Size of buffer */
u32 size;
};
struct sdmx_data_buff_descr {
/* Physical chunks of the buffer */
struct sdmx_buff_descr buff_chunks[SDMX_MAX_PHYSICAL_CHUNKS];
/* Length of buffer */
u32 length;
};
/*
* Data payload residing in the data buffers is described using this meta-data
* header. The meta data header specifies where the payload is located in the
* data buffer and how big it is.
* The meta data header optionally carries additional relevant meta data
* immediately following the meta-data header.
*/
struct sdmx_metadata_header {
/*
* Payload start offset inside data buffer. In case data is managed
* as a linear buffer group, this specifies buffer index.
*/
u32 payload_start;
/* Payload length */
u32 payload_length;
/* Number of meta data bytes immediately following this header */
u32 metadata_length;
};
struct sdmx_filter_status {
/* Secure demux filter handle */
int filter_handle;
/*
* Number of pending bytes in filter's output data buffer.
* For linear buffer mode, this is number of buffers pending.
*/
u32 data_fill_count;
/*
* Offset in data buffer for next data payload to be written.
* For linear buffer mode, this is a buffer index.
*/
u32 data_write_offset;
/* Number of pending bytes in filter's output meta data buffer */
u32 metadata_fill_count;
/* Offset in meta data buffer for next metadata header to be written */
u32 metadata_write_offset;
/* Errors (bitmap) reported by secure demux for this filter */
u32 error_indicators;
/* General status (bitmap) reported by secure demux for this filter */
u32 status_indicators;
};
int sdmx_open_session(int *session_handle);
int sdmx_close_session(int session_handle);
int sdmx_get_version(int session_handle, int32_t *version);
int sdmx_set_session_cfg(int session_handle, enum sdmx_proc_mode proc_mode,
enum sdmx_inp_mode inp_mode, enum sdmx_pkt_format pkt_format,
u8 odd_scramble_bits, u8 even_scramble_bits);
int sdmx_add_filter(int session_handle, u16 pid, enum sdmx_filter filter_type,
struct sdmx_buff_descr *meta_data_buf, enum sdmx_buf_mode data_buf_mode,
u32 num_data_bufs, struct sdmx_data_buff_descr *data_bufs,
int *filter_handle, enum sdmx_raw_out_format ts_out_format, u32 flags);
int sdmx_remove_filter(int session_handle, int filter_handle);
int sdmx_set_kl_ind(int session_handle, u16 pid, u32 key_ladder_index);
int sdmx_add_raw_pid(int session_handle, int filter_handle, u16 pid);
int sdmx_remove_raw_pid(int session_handle, int filter_handle, u16 pid);
int sdmx_process(int session_handle, u8 flags,
struct sdmx_buff_descr *input_buf_desc,
u32 *input_fill_count, u32 *input_read_offset,
u32 *error_indicators,
u32 *status_indicators,
u32 num_filters,
struct sdmx_filter_status *filter_status);
int sdmx_get_dbg_counters(int session_handle,
struct sdmx_session_dbg_counters *session_counters,
u32 *num_filters,
struct sdmx_filter_dbg_counters *filter_counters);
int sdmx_reset_dbg_counters(int session_handle);
int sdmx_set_log_level(int session_handle, enum sdmx_log_level level);
#endif /* _MPQ_SDMX_H */