SmartAudio/package/allwinner/tsc_demo/tsc_test/tsc/tsc_dev.c

949 lines
25 KiB
C
Executable File

//#define LOG_NDEBUG 0
#define LOG_TAG "tsc_dev"
#include <CDX_Debug.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <malloc.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <sys/prctl.h>
#include <base/dtv_base.h>
#include <demux/tsc.h>
#include "dvb_drv_sun5i.h"
#include "tsc_hal.h"
#include "tsc_dev.h"
extern int MemAdapterOpen(void);
extern void MemAdapterClose(void);
extern void* MemAdapterPalloc(int nSize);
extern void MemAdapterPfree(void* pMem);
extern void MemAdapterFlushCache(void* pMem, int nSize);
extern void* MemAdapterGetPhysicAddress(void* pVirtualAddress);
extern void* MemAdapterGetVirtualAddress(void* pPhysicAddress);
static void tsc_dev_dump_register(void *handle, int chan);
static void tsc_dev_dump(void *handle, int chan);
#define DEVICE_NAME ("/dev/ts0")
//Buffer size is asigned to tsf 54 regitster with 21 bits,
#define MAX_CHANNEL_BUF_SIZE (0x1FF000)
#define NOTIFY_PACKET_NUM /*(1024)*/(512)
#define RECORDER_BUF_SIZE (1024 * 188 * 10)
#define ENABLE_INTERRUPT (0)
#define FIRST_LIVE_CHANNEL (0)
#define LAST_LIVE_CHANNEL (TSC_CHAN_NUM-RECORD_DES_CHANNEL_NUM-1-1)
#define FIRST_RECORD_DES_CHANNEL (TSC_CHAN_NUM-RECORD_DES_CHANNEL_NUM-1)
#define LAST_RECORD_DES_CHANNEL (TSC_CHAN_NUM-2)
#define FIRST_RECORD_CHANNEL (TSC_CHAN_NUM-1)
#define LAST_RECORD_CHANNEL (TSC_CHAN_NUM-1)
static void* dvb_rx_maintask(void * arg);
static int32_t tsc_dev_open_channel(void* handle, chan_register_t* chan_register) {
if(!handle || !chan_register) {
ALOGE("invalid parameter");
return -1;
}
ALOGV("tsc_dev_open_channel, pid %d", chan_register->pid);
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
//assert pid
if (chan_register->pid > PID_ALL || chan_register->pid < 0) {
ALOGW("invalid pid, open filter fail");
return -1;
}
// 0~26:live, 27~30:record des, 31:record
uint32_t chan_num_first = FIRST_LIVE_CHANNEL;
uint32_t chan_num_last = LAST_LIVE_CHANNEL;
if(chan_register->chan_type == CHAN_TYPE_RECORDE) {
//only one chan for recoder.
chan_num_first = FIRST_RECORD_CHANNEL;
chan_num_last = LAST_RECORD_CHANNEL;
} else if (chan_register->chan_type == CHAN_TYPE_RECORD_DESCRAMBLE) {
chan_num_first = FIRST_RECORD_DES_CHANNEL + chan_register->desc_id;
chan_num_last = FIRST_RECORD_DES_CHANNEL + chan_register->desc_id;
}
pthread_mutex_lock(&dvb_rx->tsf.mutex);
uint32_t chan;
pid_chan_t *channels = dvb_rx->tsf.channels;
if (chan_register->chan_type != CHAN_TYPE_RECORD_DESCRAMBLE) {
// one pid can not be opened in two different channel, here i check.
for (chan = chan_num_first; chan <= chan_num_last; chan++) {
if (dvb_rx->tsf.channels[chan].pid == chan_register->pid) {
if (dvb_rx->tsf.channels[chan].is_opened == 1) {
ALOGW("filter %d has been opened", chan_register->pid);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
}
}
}
if (dvb_rx->tsf.pcr_channel.is_reserved_chan_opened == 1) {
if (dvb_rx->tsf.pcr_channel.pid == chan_register->pid) {
ALOGW("filter %d has been opened", chan_register->pid);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
}
for (chan = chan_num_first; chan <= chan_num_last; chan++) {
if (channels[chan].is_opened == 0)
break;
}
if (chan == chan_num_last+1) {
ALOGW("no channel to open.");
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
channels[chan].pid = chan_register->pid;
channels[chan].callback = chan_register->callback;
channels[chan].callbackparam = chan_register->callbackparam;
//open channel
uint8_t *phy_addr;
if (chan_register->chan_type == CHAN_TYPE_RECORDE) {
phy_addr = (uint8_t *)(channels[chan].buf - dvb_rx->tsf.record_buf + dvb_rx->tsf.record_phys_addr);
} else {
phy_addr = (uint8_t *)(channels[chan].buf - dvb_rx->tsf.buf + dvb_rx->tsf.phys_addr);
}
int32_t ret = tsf_open_chan(dvb_rx->tsc_ctx, channels[chan].pid, // pid.
channels[chan].buf,
phy_addr, // buffer for channel.
channels[chan].buf_size, // the buffer size in bytes.
TSF_TP_CHAN, // TS packet mode.
channels[chan].chan, // channel id.
ENABLE_INTERRUPT);
if (ret < 0) {
ALOGW("open chan err");
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
channels[chan].is_opened = 1;
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
ALOGV("open channel success, pid %d, chan %d", channels[chan].pid, channels[chan].chan);
return channels[chan].chan;
}
static int32_t tsc_dev_close_channel(void* handle, uint32_t chan) {
ALOGV("tsc_dev_close_channel, chan %d", chan);
if(chan >= TSC_CHAN_NUM)
return -1;
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
#if 0
tsf_port_e tsf_port = TSF_PORT_0;
if(chan >= TSC_CHAN_NUM) {
tsf_port = TSF_PORT_1;
chan -= TSC_CHAN_NUM;
}
#endif
pid_chan_t *channels = dvb_rx->tsf.channels;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (channels[chan].is_opened == 1) {
channels[chan].is_opened = 0;
tsf_close_chan(dvb_rx->tsc_ctx, chan);
channels[chan].pid = 0;
channels[chan].callback = NULL;
channels[chan].callbackparam = NULL;
}
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return 0;
}
static int32_t tsc_dev_open_pcr_detect(void* handle, chan_register_t* chan_register) {
ALOGV("tsc_dev_open_pcr_detect");
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
pid_chan_t *channels = dvb_rx->tsf.channels;
pcr_chan_t *pcr_channel = &dvb_rx->tsf.pcr_channel;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
uint32_t chan;
for (chan = 0; chan < PCR_CHANNEL_INDEX; chan++) {
if ((channels[chan].pid == chan_register->pid) && (channels[chan].is_opened == 1))
break;
}
if (pcr_channel->is_detect_opened == 1) {
tsf_close_pcr_detect(dvb_rx->tsc_ctx);
pcr_channel->is_detect_opened = 0;
}
if (pcr_channel->is_reserved_chan_opened == 1) {
tsf_close_chan(dvb_rx->tsc_ctx, pcr_channel->chan);
pcr_channel->is_reserved_chan_opened = 0;
}
pcr_channel->pid = chan_register->pid;
pcr_channel->callback = chan_register->callback;
pcr_channel->callbackparam = chan_register->callbackparam;
pcr_channel->attach_chan = chan;
if (chan == PCR_CHANNEL_INDEX) {
uint8_t *phy_addr = (uint8_t *)(pcr_channel->buf -
dvb_rx->tsf.buf + dvb_rx->tsf.phys_addr);
int32_t ret = tsf_open_chan(dvb_rx->tsc_ctx, pcr_channel->pid,
pcr_channel->buf, phy_addr, pcr_channel->buf_size,
TSF_TP_CHAN, pcr_channel->chan, ENABLE_INTERRUPT);
if (ret < 0) {
ALOGW("open chan fail");
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
pcr_channel->is_reserved_chan_opened = 1;
}
tsf_open_pcr_detect(dvb_rx->tsc_ctx, chan);
pcr_channel->is_detect_opened = 1;
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return 0;
}
static void tsc_dev_close_pcr_detect(void* handle) {
ALOGV("tsc_dev_close_pcr_detect");
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
pcr_chan_t *pcr_channel = &dvb_rx->tsf.pcr_channel;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (pcr_channel->is_detect_opened == 1) {
tsf_close_pcr_detect(dvb_rx->tsc_ctx);
pcr_channel->is_detect_opened = 0;
}
if (pcr_channel->is_reserved_chan_opened == 1) {
tsf_close_chan(dvb_rx->tsc_ctx, pcr_channel->chan);
pcr_channel->is_reserved_chan_opened = 0;
}
pcr_channel->pid = 0;
pcr_channel->callback = NULL;
pcr_channel->callbackparam = NULL;
pcr_channel->attach_chan = 0;
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
}
static int32_t open_chan_31(void* handle) {
int32_t ret;
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
uint8_t *phy_addr = (uint8_t *)(dvb_rx->tsf.channels[31].buf -
dvb_rx->tsf.buf + dvb_rx->tsf.phys_addr);
ret = tsf_open_chan(dvb_rx->tsc_ctx, PID_ALL, dvb_rx->tsf.channels[31].buf,
phy_addr, dvb_rx->tsf.channels[31].buf_size,
TSF_TP_CHAN, 31, ENABLE_INTERRUPT);
if (ret < 0) {
ALOGW("open chan failed");
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return 0;
}
static void close_chan_31(void* handle) {
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
tsf_close_chan(dvb_rx->tsc_ctx, 31);
}
static int32_t tsc_dev_read_channel_data(void* pdata, uint32_t pkt_num_require, uint32_t chan,
void* handle) {
uint8_t* data0;
uint8_t* data1;
uint32_t pkt_num0 = 0;
uint32_t pkt_num1 = 0;
uint8_t* buf;
ALOGV("tsc_dev_read_channel_data");
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if (chan >= TSC_CHAN_NUM)
return 0;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
tsf_request_data(dvb_rx->tsc_ctx, chan, &data0, &pkt_num0, &data1, &pkt_num1);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
if(pkt_num0) {
MemAdapterFlushCache(data0, pkt_num0);
}
if(pkt_num1) {
MemAdapterFlushCache(data1, pkt_num1);
}
pkt_num0 /= 188;
pkt_num1 /= 188;
if (pkt_num0 + pkt_num1 == 0)
return 0;
if (pkt_num_require == 0)
return 0;
buf = (uint8_t*) pdata;
int32_t packet_num = 0;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (pkt_num0 >= pkt_num_require) {
memcpy(buf, data0, pkt_num_require * 188);
tsf_flush_chan(dvb_rx->tsc_ctx, chan, pkt_num_require * 188);
packet_num = pkt_num_require;
} else if (pkt_num1 == 0) {
memcpy(buf, data0, pkt_num0 * 188);
tsf_flush_chan(dvb_rx->tsc_ctx, chan, pkt_num0 * 188);
packet_num = pkt_num0;
} else if (pkt_num0 + pkt_num1 >= pkt_num_require) {
memcpy(buf, data0, pkt_num0 * 188);
memcpy(buf + pkt_num0 * 188, data1, (pkt_num_require - pkt_num0) * 188);
tsf_flush_chan(dvb_rx->tsc_ctx, chan, pkt_num_require * 188);
packet_num = pkt_num_require;
} else {
memcpy(buf, data0, pkt_num0 * 188);
memcpy(buf + pkt_num0 * 188, data1, pkt_num1 * 188);
tsf_flush_chan(dvb_rx->tsc_ctx, chan, (pkt_num0 + pkt_num1) * 188);
packet_num = (pkt_num0 + pkt_num1);
}
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return packet_num;
}
static int32_t tsc_dev_request_channel_data(void* handle, int32_t chan,
tsf_data_t* tsf_data) {
// ALOGV("tsc_dev_request_channel_data, chan %d", chan);
// tsc_dev_dump(handle, chan);
if (chan >= TSC_CHAN_NUM) {
tsf_data->data = NULL;
tsf_data->pkt_num = 0;
tsf_data->ring_data = NULL;
tsf_data->ring_pkt_num = 0;
return -1;
}
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
int32_t err = 0;
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (dvb_rx->tsf.channels[chan].is_opened == 1) {
tsf_request_data(dvb_rx->tsc_ctx, chan, &tsf_data->data,
&tsf_data->pkt_num, &tsf_data->ring_data, &tsf_data->ring_pkt_num);
if(tsf_data->pkt_num) {
MemAdapterFlushCache(tsf_data->data, tsf_data->pkt_num);
}
if(tsf_data->ring_pkt_num) {
MemAdapterFlushCache(tsf_data->ring_data, tsf_data->ring_pkt_num);
}
tsf_data->pkt_num /= 188; //return as packet size
tsf_data->ring_pkt_num /= 188;
} else {
tsf_data->data = NULL;
tsf_data->pkt_num = 0;
tsf_data->ring_data = NULL;
tsf_data->ring_pkt_num = 0;
err = -1;
}
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return err;
}
static int32_t tsc_dev_flush_channel_data(void* handle, int32_t chan, int32_t pkt_num) {
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if (chan >= TSC_CHAN_NUM)
return -1;
#if 0
tsf_port_e tsf_port = TSF_PORT_0;
if(chan >= TSC_CHAN_NUM) {
tsf_port = TSF_PORT_1;
chan -= TSC_CHAN_NUM;
}
#endif
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (dvb_rx->tsf.channels[chan].is_opened == 1)
tsf_flush_chan(dvb_rx->tsc_ctx, chan, pkt_num * 188);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return 0;
}
static int32_t tsc_dev_get_channel_packet_num(void* handle, int32_t chan) {
int32_t result;
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
ALOGV("tsc_dev_get_channel_packet_num");
if(!dvb_rx)
return -1;
if (chan >= TSC_CHAN_NUM)
return -1;
#if 0
tsf_port_e tsf_port = TSF_PORT_0;
if(chan >= TSC_CHAN_NUM) {
tsf_port = TSF_PORT_1;
chan -= TSC_CHAN_NUM;
}
#endif
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (dvb_rx->tsf.channels[chan].is_opened == 1) {
result = tsf_check_data_size(dvb_rx->tsc_ctx, chan);
result /= 188;
} else
result = 0;
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return result;
}
static int32_t tsc_dev_get_free_channel_num(void *handle) {
ALOGV("tsc_dev_get_free_channel_num");
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!dvb_rx)
return TSC_CHAN_NUM;
int32_t i;
int32_t free_channel_num = TSC_CHAN_NUM;
pid_chan_t* channels = &dvb_rx->tsf.channels[0];
for(i = 0; i < TSC_CHAN_NUM; i ++) {
if(channels[i].is_opened) {
free_channel_num --;
}
}
return free_channel_num;
}
static void tsc_dev_reset_channel(void *handle, int chan)
{
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!dvb_rx)
return ;
if (chan >= TSC_CHAN_NUM)
return;
#if 0
tsf_port_e tsf_port = TSF_PORT_0;
if(chan >= TSC_CHAN_NUM) {
tsf_port = TSF_PORT_1;
chan -= TSC_CHAN_NUM;
}
#endif
pthread_mutex_lock(&dvb_rx->tsf.mutex);
tsf_reset_chan(dvb_rx->tsc_ctx, chan);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
}
static void tsc_dev_dump_register(void *handle, int chan)
{
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!dvb_rx)
return ;
if (chan >= TSC_CHAN_NUM)
return;
#if 0
tsf_port_e tsf_port = TSF_PORT_0;
if(chan >= TSC_CHAN_NUM) {
tsf_port = TSF_PORT_1;
chan -= TSC_CHAN_NUM;
}
#endif
pthread_mutex_lock(&dvb_rx->tsf.mutex);
tsf_dump_chan_register(dvb_rx->tsc_ctx, chan);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
}
static void tsc_dev_dump(void *handle, int chan)
{
ALOGD("chan=%d", chan);
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!dvb_rx)
return ;
if (chan >= TSC_CHAN_NUM)
return;
#if 0
tsf_port_e tsf_port = TSF_PORT_0;
if(chan >= TSC_CHAN_NUM) {
tsf_port = TSF_PORT_1;
chan -= TSC_CHAN_NUM;
}
#endif
pthread_mutex_lock(&dvb_rx->tsf.mutex);
ts_dump_registers(dvb_rx->tsc_ctx);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
}
static int32_t tsc_desc_set_pid(void *handle, int desc_id, int chan_id, int pid)
{
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!dvb_rx)
return -1;
tsf_set_cw_index(dvb_rx->tsc_ctx, chan_id, desc_id);
tsf_set_ca_enable(dvb_rx->tsc_ctx, chan_id, 1);
return 0;
}
static int32_t tsc_desc_set_key(void *handle, int desc_id, uint8_t *odd_key, uint8_t *even_key)
{
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!dvb_rx)
return -1;
if (odd_key) {
tsd_set_cw(dvb_rx->tsc_ctx, desc_id, CW_ODD_LOW_32BITS, odd_key[0] | (odd_key[1]<<8) | (odd_key[2]<<16) | (odd_key[3]<<24));
tsd_set_cw(dvb_rx->tsc_ctx, desc_id, CW_ODD_HIGH_32BITS, odd_key[4] | (odd_key[5]<<8) | (odd_key[6]<<16) | (odd_key[7]<<24));
}
if (even_key) {
tsd_set_cw(dvb_rx->tsc_ctx, desc_id, CW_EVEN_LOW_32BITS, even_key[0] | (even_key[1]<<8) | (even_key[2]<<16) | (even_key[3]<<24));
tsd_set_cw(dvb_rx->tsc_ctx, desc_id, CW_EVEN_HIGH_32_BITS, even_key[4] | (even_key[5]<<8) | (even_key[6]<<16) | (even_key[7]<<24));
}
return 0;
}
static void* dvb_rx_maintask(void * arg) {
uint32_t chan;
uint32_t pcr;
int32_t err;
uint32_t chan_status;
dvb_rx_t* dvb_rx;
prctl(PR_SET_NAME, (unsigned long)"dvb_rx");
struct intrstatus interrupt_status;
dvb_rx = (dvb_rx_t*) arg;
while (0 == dvb_rx->thread_exit) {
// ALOGV("waiting interrupt");
err = ioctl(dvb_rx->fd, TSCDEV_WAIT_INT, (unsigned long)&interrupt_status);
// print_regs(dvb_rx->tsc_ctx);
dvb_rx->chan_status |= interrupt_status.port0chan;
interrupt_status.port0pcr &= 0x00000004; //get PCR bit
interrupt_status.port0pcr >>= 2;
if (interrupt_status.port0pcr) {
if (dvb_rx->tsf.pcr_channel.is_detect_opened == 1) {
pcr = tsf_get_pcr(dvb_rx->tsc_ctx);
if (dvb_rx->tsf.pcr_channel.callback)
dvb_rx->tsf.pcr_channel.callback(&pcr, dvb_rx->tsf.pcr_channel.callbackparam);
}
}
chan_status = dvb_rx->chan_status;
dvb_rx->chan_status = 0;
//chan_status &= 0x7fffffff;
chan = 0;
while (chan_status) {
if (chan_status & 0x1) {
if (dvb_rx->tsf.channels[chan].is_opened == 1) {
if (dvb_rx->tsf.channels[chan].callback) {
dvb_rx->tsf.channels[chan].callback(NULL, (void *) dvb_rx->tsf.channels[chan].callbackparam);
}
}
}
chan_status >>= 1;
chan++;
} //while chan_status
} //while(1)
pthread_exit(NULL);
return (void *) 0;
}
static int tsc_dev_open_descramble(void* handle, int chan)
{
int index;
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!handle || chan>=TSC_CHAN_NUM)
{
ALOGE("invalid parameter");
return -1;
}
pthread_mutex_lock(&dvb_rx->tsf.mutex);
if (dvb_rx->tsf.channels[chan].is_opened == 0)
{
ALOGW("filter %d has not opened", chan);
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
return -1;
}
pthread_mutex_unlock(&dvb_rx->tsf.mutex);
pthread_mutex_lock(&dvb_rx->tsd.mutex);
for (index = 0; index < DSC_NUM; index++) {
if (dvb_rx->tsd.dsc[index].is_opened==1 && dvb_rx->tsd.dsc[index].chan==chan)
{
ALOGW("filter %d has added descramble %d", chan,index);
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return -1;
}
}
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
ALOGV("tsc_dev_open_channel, chan %d", chan);
pthread_mutex_lock(&dvb_rx->tsd.mutex);
for (index = 0; index < DSC_NUM; index++) {
if (dvb_rx->tsd.dsc[index].is_opened == 0)
break;
}
if(index > DSC_NUM)
{
ALOGW("no free descramble");
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return -1;
}
dvb_rx->tsd.dsc[index].is_opened = 1;
dvb_rx->tsd.dsc[index].chan = chan;
tsf_set_ca_enable(dvb_rx->tsc_ctx, chan, 1);
tsf_set_cw_index(dvb_rx->tsc_ctx, chan, index);
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return index;
}
static int tsc_dev_close_descramble(void* handle, int index)
{
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
int chan;
if(!handle || index>=DSC_NUM)
{
ALOGE("invalid parameter");
return -1;
}
pthread_mutex_lock(&dvb_rx->tsd.mutex);
if (dvb_rx->tsd.dsc[index].is_opened == 0)
{
ALOGW("descramble %d has not opened", index);
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return -1;
}
chan = dvb_rx->tsd.dsc[index].chan;
if(chan >= TSC_CHAN_NUM) {
ALOGE("chan num is too large");
return -1;
}
tsf_set_ca_enable(dvb_rx->tsc_ctx, chan, 0);
dvb_rx->tsd.dsc[index].is_opened = 0;
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return 0;
}
static int tsc_dev_set_descramble_cw(void* handle, int index, des_cw_type_e cw_type, uint32_t cw_value)
{
dvb_rx_t *dvb_rx = (dvb_rx_t*) handle;
if(!handle || index>=DSC_NUM)
{
ALOGE("invalid parameter");
return -1;
}
pthread_mutex_lock(&dvb_rx->tsd.mutex);
if (dvb_rx->tsd.dsc[index].is_opened == 0)
{
ALOGW("descramble %d has not opened", index);
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return -1;
}
tsd_set_cw(dvb_rx->tsc_ctx, index, cw_type, cw_value);
pthread_mutex_unlock(&dvb_rx->tsd.mutex);
return 0;
}
static const uint32_t size_mul_array[4] = { 2, 4, 8, 16 };
void* tsc_dev_open(void) {
int32_t err;
uint32_t chan;
uint32_t channel_buffer_size;
uint32_t total_buffer_size;
uint32_t size_multiply;
dvb_rx_t* dvb_rx;
ALOGV("tsc_dev_open");
ts_dev_t *ts_dev = (ts_dev_t *)malloc(sizeof(ts_dev_t));
if(ts_dev == NULL) {
ALOGE("alloc ts device failed");
return NULL;
}
// create module handle
dvb_rx = (dvb_rx_t *) malloc(sizeof(dvb_rx_t));
if (dvb_rx == NULL) {
ALOGW("malloc failed.");
free(ts_dev);
return NULL;
}
memset(dvb_rx, 0, sizeof(dvb_rx_t));
//open TSC driver
dvb_rx->fd = open(DEVICE_NAME, O_RDWR, 0);
if (dvb_rx->fd < 0) {
ALOGW("open device error, %s", strerror(errno));
free(dvb_rx);
free(ts_dev);
return NULL;
}
pthread_mutex_init(&dvb_rx->tsf.mutex, NULL);
pthread_mutex_init(&dvb_rx->tsd.mutex, NULL);
// malloc memory for all pid filter.
size_multiply = size_mul_array[TSF_INTR_THRESHOLD];
//buffer size is aligned by 1024 bytes
channel_buffer_size = (NOTIFY_PACKET_NUM * 188 * size_multiply + 0x3ff) & ~0x3ff;
DTV_ASSERT(channel_buffer_size <= MAX_CHANNEL_BUF_SIZE);
total_buffer_size = channel_buffer_size * TSC_CHAN_NUM;
total_buffer_size = (total_buffer_size + 0xfff) & ~0xfff; // PAGE_SIZE aligned
MemAdapterOpen();
printf("total_buffer_size = %d bytes\n",total_buffer_size);
dvb_rx->tsf.buf = MemAdapterPalloc(total_buffer_size);
if(dvb_rx->tsf.buf == NULL) {
ALOGE("malloc buffer for tsc failed");
goto _err_open;
}
memset(dvb_rx->tsf.buf, 0, total_buffer_size);
//MemAdapterFlushCache(dvb_rx->tsf[0].buf,total_buffer_size);
// get memory physics addresss
dvb_rx->tsf.phys_addr = (size_t)MemAdapterGetPhysicAddress(dvb_rx->tsf.buf);
dvb_rx->tsf.total_buf_size = total_buffer_size;
ALOGV("buf info, virt %p, phys 0x%x, size 0x%x", dvb_rx->tsf.buf, dvb_rx->tsf.phys_addr,
dvb_rx->tsf.total_buf_size);
uint8_t *buf = dvb_rx->tsf.buf;
for (chan = 0; chan < TSC_CHAN_NUM; chan++) {
dvb_rx->tsf.channels[chan].chan = chan;
dvb_rx->tsf.channels[chan].buf = buf;
dvb_rx->tsf.channels[chan].buf_size = NOTIFY_PACKET_NUM * size_multiply
* 188;
buf += channel_buffer_size;
}
dvb_rx->tsf.pcr_channel.chan = PCR_CHANNEL_INDEX;
dvb_rx->tsf.pcr_channel.buf = dvb_rx->tsf.channels[PCR_CHANNEL_INDEX].buf;
dvb_rx->tsf.pcr_channel.buf_size = dvb_rx->tsf.channels[PCR_CHANNEL_INDEX].buf_size;
int32_t recorder_size = RECORDER_BUF_SIZE & ~0xfff;
printf("recorder_size = %d bytes\n",recorder_size);
dvb_rx->tsf.record_buf = MemAdapterPalloc(recorder_size);
if(dvb_rx->tsf.record_buf == NULL) {
ALOGE("malloc buffer for record failed");
goto _err_open;
}
// get memory physics addresss
dvb_rx->tsf.record_phys_addr = (size_t)MemAdapterGetPhysicAddress(dvb_rx->tsf.record_buf);
dvb_rx->tsf.record_total_buf_size = recorder_size;
ALOGV("buf info, virt %p, phys 0x%x, size 0x%x", dvb_rx->tsf.record_buf, dvb_rx->tsf.record_phys_addr,
dvb_rx->tsf.record_total_buf_size);
//for recoder, use channel 31.
//dvb_rx->tsf.channels[31].chan = 0;
dvb_rx->tsf.channels[31].buf = dvb_rx->tsf.record_buf;
dvb_rx->tsf.channels[31].buf_size = recorder_size;
dvb_rx->tsf.channels[31].is_opened = 0;
// mmap registers
dvb_rx->regs = mmap(NULL, REGS_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED,
dvb_rx->fd, 0);
int ret;
ALOGD("dvb_rx->regs: %p", dvb_rx->regs);
if (dvb_rx->regs == MAP_FAILED) {
ALOGE("mmap registers failed");
goto _err_open;
}
dvb_rx->total_regs_size = REGS_SIZE;
ret = ioctl(dvb_rx->fd, TSCDEV_DISABLE_INT, 0);
if(ret < 0)
{
ALOGE("ioctl diable int failed!");
//goto _err_open;
}
#if ENABLE_INTERRUPT
// crate the main task
dvb_rx->thread_exit = 0;
err = pthread_create(&dvb_rx->thread_id, NULL, dvb_rx_maintask,
(void*) dvb_rx);
if (0 != err) {
dvb_rx->thread_exit = 1;
ALOGW("create maintask fail, tscopen fail.");
goto _err_open;
}
#endif
dvb_rx->tsc_ctx = tsc_init(dvb_rx->regs);
if (!dvb_rx->tsc_ctx) {
ALOGE("init tsc failed");
goto _err_open;
}
if (tsc_open((void*)dvb_rx->tsc_ctx) < 0) {
ALOGE("open tsc failed");
goto _err_open;
}
ts_dev->cookie = dvb_rx;
ts_dev->open_channel = tsc_dev_open_channel;
ts_dev->close_channel = tsc_dev_close_channel;
ts_dev->get_channel_packet_num = tsc_dev_get_channel_packet_num;
ts_dev->request_channel_data = tsc_dev_request_channel_data;
ts_dev->flush_channel_data = tsc_dev_flush_channel_data;
ts_dev->read_channel_data = tsc_dev_read_channel_data;
ts_dev->open_pcr_detect = tsc_dev_open_pcr_detect;
ts_dev->close_pcr_detect = tsc_dev_close_pcr_detect;
ts_dev->get_free_channel_num = tsc_dev_get_free_channel_num;
ts_dev->reset_channel = tsc_dev_reset_channel;
ts_dev->dump_register = tsc_dev_dump_register;
ts_dev->clear = NULL;
ts_dev->set_buffer_size = NULL;
ts_dev->write_data = NULL;
ts_dev->desc_set_pid = tsc_desc_set_pid;
ts_dev->desc_set_key = tsc_desc_set_key;
ts_dev->open_descramble = tsc_dev_open_descramble;
ts_dev->close_descramble = tsc_dev_close_descramble;
ts_dev->set_descramble_cw = tsc_dev_set_descramble_cw;
return (void *) ts_dev;
_err_open:
if (dvb_rx) {
if (dvb_rx->tsc_ctx) {
tsc_close(dvb_rx->tsc_ctx);
tsc_exit(dvb_rx->tsc_ctx);
}
// release memory.
if (dvb_rx->tsf.buf) {
MemAdapterPfree(dvb_rx->tsf.buf);
}
if (dvb_rx->tsf.record_buf) {
MemAdapterPfree(dvb_rx->tsf.record_buf);
}
MemAdapterClose();
if (dvb_rx->regs) {
munmap(dvb_rx->regs, dvb_rx->total_regs_size);
}
if (dvb_rx->fd) {
close(dvb_rx->fd);
}
// release mutex
pthread_mutex_destroy(&dvb_rx->tsf.mutex);
free(dvb_rx);
dvb_rx = NULL;
if(ts_dev) {
free(ts_dev);
}
}
return NULL;
}
int32_t tsc_dev_close(void* handle) {
ALOGV("tsc_dev_close");
ts_dev_t *ts_dev = (ts_dev_t *)handle;
if(ts_dev) {
dvb_rx_t *dvb_rx = (dvb_rx_t*)ts_dev->cookie;
if (dvb_rx) {
#if ENABLE_INTERRUPT
dvb_rx->thread_exit = 1;
int32_t err = ioctl(dvb_rx->fd, TSCDEV_RELEASE_SEM, NULL);
if(err < 0)
{
ALOGE("ioctl release sem failed!");
}
//kill main task thread
if (dvb_rx->thread_id > 0)
err = pthread_join(dvb_rx->thread_id, NULL);
#endif
if (dvb_rx->tsc_ctx) {
tsc_close(dvb_rx->tsc_ctx);
tsc_exit(dvb_rx->tsc_ctx);
}
if (dvb_rx->regs)
munmap(dvb_rx->regs, dvb_rx->total_regs_size);
// release memory.
if (dvb_rx->tsf.buf) {
MemAdapterPfree(dvb_rx->tsf.buf);
}
if(dvb_rx->tsf.record_buf) {
MemAdapterPfree(dvb_rx->tsf.record_buf);
}
MemAdapterClose();
if (dvb_rx->fd)
close(dvb_rx->fd);
pthread_mutex_destroy(&dvb_rx->tsf.mutex);
free(dvb_rx);
dvb_rx = NULL;
}
free(ts_dev);
}
return 0;
}