/** * Configure TSPP channel to filter the PID of new feed. * * @feed: The feed to configure the channel with * * Return error status * * The function checks if the new PID can be added to an already * allocated channel, if not, a new channel is allocated and configured. */ static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed) { struct mpq_demux *mpq_demux = feed->demux->priv; struct tspp_select_source tspp_source; struct tspp_filter tspp_filter; int tsif; int ret; int channel_id; int *channel_ref_count; u32 buffer_size; tspp_source.clk_inverse = clock_inv; tspp_source.data_inverse = 0; tspp_source.sync_inverse = 0; tspp_source.enable_inverse = 0; switch (tsif_mode) { case 1: tspp_source.mode = TSPP_TSIF_MODE_1; break; case 2: tspp_source.mode = TSPP_TSIF_MODE_2; break; default: tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK; break; } /* determine the TSIF we are reading from */ if (mpq_demux->source == DMX_SOURCE_FRONT0) { tsif = 0; tspp_source.source = TSPP_SOURCE_TSIF0; } else if (mpq_demux->source == DMX_SOURCE_FRONT1) { tsif = 1; tspp_source.source = TSPP_SOURCE_TSIF1; } 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_tspp_info.tsif[tsif].mutex)) return -ERESTARTSYS; /* * It is possible that this PID was already requested before. * Can happen if we play and record same PES or PCR * piggypacked on video packet. */ ret = mpq_tspp_get_filter_slot(tsif, feed->pid); if (ret >= 0) { /* PID already configured */ mpq_dmx_tspp_info.tsif[tsif].filters[ret].ref_count++; mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); return 0; } channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref; buffer_size = TSPP_DESCRIPTOR_SIZE; /* check if required TSPP pipe is already allocated or not */ if (*channel_ref_count == 0) { if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { ret = mpq_dmx_channel_mem_alloc(tsif); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_dmx_channel_mem_alloc(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_failed; } } ret = tspp_open_channel(0, channel_id); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_open_channel(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_failed; } /* set TSPP source */ ret = tspp_open_stream(0, channel_id, &tspp_source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_select_source(%d,%d) failed (%d)\n", __func__, channel_id, tspp_source.source, ret); goto add_channel_close_ch; } /* register notification on TS packets */ tspp_register_notification(0, channel_id, mpq_tspp_callback, (void *)tsif, tspp_channel_timeout); /* register allocator and provide allocation function * that allocates from contiguous memory so that we can have * big notification size, smallest descriptor, and still provide * TZ with single big buffer based on notification size. */ if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { ret = tspp_allocate_buffers(0, channel_id, mpq_dmx_tspp_info.tsif[tsif].buffer_count, buffer_size, tspp_notification_size, tspp_mem_allocator, tspp_mem_free, NULL); } else { ret = tspp_allocate_buffers(0, channel_id, mpq_dmx_tspp_info.tsif[tsif].buffer_count, buffer_size, tspp_notification_size, NULL, NULL, NULL); } if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_allocate_buffers(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_unregister_notif; } mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux; } /* add new PID to the existing pipe */ ret = mpq_tspp_get_free_filter_slot(tsif, channel_id); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_allocate_filter_slot(%d, %d) failed\n", __func__, tsif, channel_id); goto add_channel_unregister_notif; } mpq_dmx_tspp_info.tsif[tsif].filters[ret].pid = feed->pid; mpq_dmx_tspp_info.tsif[tsif].filters[ret].ref_count++; tspp_filter.priority = ret; if (feed->pid == TSPP_PASS_THROUGH_PID) { /* pass all pids */ tspp_filter.pid = 0; tspp_filter.mask = 0; } else { tspp_filter.pid = feed->pid; tspp_filter.mask = TSPP_PID_MASK; } /* * Include TTS in RAW packets, if you change this to * TSPP_MODE_RAW_NO_SUFFIX you must also change TSPP_RAW_TTS_SIZE * accordingly. */ tspp_filter.mode = TSPP_MODE_RAW; tspp_filter.source = tspp_source.source; tspp_filter.decrypt = 0; ret = tspp_add_filter(0, channel_id, &tspp_filter); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_add_filter(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_free_filter_slot; } (*channel_ref_count)++; mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); return 0; add_channel_free_filter_slot: mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].pid = -1; mpq_dmx_tspp_info.tsif[tsif].filters[tspp_filter.priority].ref_count--; add_channel_unregister_notif: tspp_unregister_notification(0, channel_id); add_channel_close_ch: tspp_close_channel(0, channel_id); add_channel_failed: if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) mpq_dmx_channel_mem_free(tsif); mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); return ret; }
static int mpq_tspp_dmx_add_channel(struct dvb_demux_feed *feed) { struct mpq_demux *mpq_demux = feed->demux->priv; struct tspp_select_source tspp_source; struct tspp_filter tspp_filter; int tsif; int ret = 0; int slot; int channel_id; int *channel_ref_count; u32 buffer_size; int restore_user_filters = 0; int remove_accept_all_filter = 0; int remove_null_blocking_filters = 0; tspp_source.clk_inverse = clock_inv; tspp_source.data_inverse = 0; tspp_source.sync_inverse = 0; tspp_source.enable_inverse = 0; MPQ_DVB_DBG_PRINT("%s: executed, PID = %d\n", __func__, feed->pid); switch (tsif_mode) { case 1: tspp_source.mode = TSPP_TSIF_MODE_1; break; case 2: tspp_source.mode = TSPP_TSIF_MODE_2; break; default: tspp_source.mode = TSPP_TSIF_MODE_LOOPBACK; break; } if (mpq_demux->source == DMX_SOURCE_FRONT0) { tsif = 0; tspp_source.source = TSPP_SOURCE_TSIF0; } else if (mpq_demux->source == DMX_SOURCE_FRONT1) { tsif = 1; tspp_source.source = TSPP_SOURCE_TSIF1; } else { MPQ_DVB_ERR_PRINT( "%s: invalid input source (%d)\n", __func__, mpq_demux->source); return -EINVAL; } if (mutex_lock_interruptible(&mpq_dmx_tspp_info.tsif[tsif].mutex)) return -ERESTARTSYS; slot = mpq_tspp_get_filter_slot(tsif, feed->pid); if (slot >= 0) { mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); return 0; } channel_id = TSPP_CHANNEL_ID(tsif, TSPP_CHANNEL); channel_ref_count = &mpq_dmx_tspp_info.tsif[tsif].channel_ref; buffer_size = TSPP_DESCRIPTOR_SIZE; if (*channel_ref_count == 0) { if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { ret = mpq_dmx_channel_mem_alloc(tsif); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_dmx_channel_mem_alloc(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_failed; } } ret = tspp_open_channel(0, channel_id); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_open_channel(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_failed; } ret = tspp_open_stream(0, channel_id, &tspp_source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_select_source(%d,%d) failed (%d)\n", __func__, channel_id, tspp_source.source, ret); goto add_channel_close_ch; } tspp_register_notification(0, channel_id, mpq_tspp_callback, (void *)tsif, tspp_channel_timeout); if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) { ret = tspp_allocate_buffers(0, channel_id, mpq_dmx_tspp_info.tsif[tsif].buffer_count, buffer_size, tspp_notification_size, tspp_mem_allocator, tspp_mem_free, NULL); } else { ret = tspp_allocate_buffers(0, channel_id, mpq_dmx_tspp_info.tsif[tsif].buffer_count, buffer_size, tspp_notification_size, NULL, NULL, NULL); } if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_allocate_buffers(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_unregister_notif; } mpq_dmx_tspp_info.tsif[tsif].mpq_demux = mpq_demux; } slot = mpq_tspp_get_free_filter_slot(tsif); if (slot < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_tspp_get_free_filter_slot(%d) failed\n", __func__, tsif); goto add_channel_unregister_notif; } if (feed->pid == TSPP_PASS_THROUGH_PID) mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 1; else if (feed->pid == TSPP_NULL_PACKETS_PID) mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 1; mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = feed->pid; mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count++; tspp_filter.priority = -1; if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count < TSPP_MAX_HW_PID_FILTER_NUM) { tspp_filter.priority = mpq_tspp_allocate_hw_filter_index(tsif); if (tspp_filter.priority < 0) goto add_channel_free_filter_slot; if (feed->pid == TSPP_PASS_THROUGH_PID) { tspp_filter.pid = 0; tspp_filter.mask = 0; } else { tspp_filter.pid = feed->pid; tspp_filter.mask = TSPP_PID_MASK; } tspp_filter.mode = TSPP_MODE_RAW; tspp_filter.source = tspp_source.source; tspp_filter.decrypt = 0; ret = tspp_add_filter(0, channel_id, &tspp_filter); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: tspp_add_filter(%d) failed (%d)\n", __func__, channel_id, ret); goto add_channel_free_filter_slot; } mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = tspp_filter.priority; MPQ_DVB_DBG_PRINT( "%s: HW filtering mode: added TSPP HW filter, PID = %d, mask = 0x%X, index = %d\n", __func__, tspp_filter.pid, tspp_filter.mask, tspp_filter.priority); } else if (mpq_dmx_tspp_info.tsif[tsif].current_filter_count == TSPP_MAX_HW_PID_FILTER_NUM) { ret = mpq_tspp_add_accept_all_filter(channel_id, tspp_source.source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", __func__, channel_id, tspp_source.source); goto add_channel_free_filter_slot; } ret = mpq_tspp_remove_all_user_filters(channel_id, tspp_source.source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_tspp_remove_all_user_filters(%d, %d) failed\n", __func__, channel_id, tspp_source.source); restore_user_filters = 1; remove_accept_all_filter = 1; goto add_channel_free_filter_slot; } ret = mpq_tspp_add_null_blocking_filters(channel_id, tspp_source.source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_tspp_add_null_blocking_filters(%d, %d) failed\n", __func__, channel_id, tspp_source.source); restore_user_filters = 1; remove_accept_all_filter = 1; goto add_channel_free_filter_slot; } if ((mpq_dmx_tspp_info.tsif[tsif].pass_all_flag == 0) && (mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag == 0)) { ret = mpq_tspp_remove_accept_all_filter(channel_id, tspp_source.source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_tspp_remove_accept_all_filter(%d, %d) failed\n", __func__, channel_id, tspp_source.source); remove_null_blocking_filters = 1; restore_user_filters = 1; remove_accept_all_filter = 1; goto add_channel_free_filter_slot; } } } else { if (mpq_dmx_tspp_info.tsif[tsif].pass_all_flag || mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag) { ret = mpq_tspp_add_accept_all_filter(channel_id, tspp_source.source); if (ret < 0) { MPQ_DVB_ERR_PRINT( "%s: mpq_tspp_add_accept_all_filter(%d, %d) failed\n", __func__, channel_id, tspp_source.source); goto add_channel_free_filter_slot; } } } (*channel_ref_count)++; mpq_dmx_tspp_info.tsif[tsif].current_filter_count++; MPQ_DVB_DBG_PRINT("%s: success, current_filter_count = %d\n", __func__, mpq_dmx_tspp_info.tsif[tsif].current_filter_count); mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); return 0; add_channel_free_filter_slot: mpq_dmx_tspp_info.tsif[tsif].filters[slot].pid = -1; mpq_dmx_tspp_info.tsif[tsif].filters[slot].ref_count--; if (tspp_filter.priority >= 0) { mpq_dmx_tspp_info.tsif[tsif].filters[slot].hw_index = -1; mpq_tspp_release_hw_filter_index(tsif, tspp_filter.priority); } if (remove_null_blocking_filters) mpq_tspp_remove_null_blocking_filters(channel_id, tspp_source.source); if (restore_user_filters) mpq_tspp_add_all_user_filters(channel_id, tspp_source.source); if (remove_accept_all_filter) mpq_tspp_remove_accept_all_filter(channel_id, tspp_source.source); if (feed->pid == TSPP_PASS_THROUGH_PID) mpq_dmx_tspp_info.tsif[tsif].pass_all_flag = 0; else if (feed->pid == TSPP_NULL_PACKETS_PID) mpq_dmx_tspp_info.tsif[tsif].pass_nulls_flag = 0; add_channel_unregister_notif: if (*channel_ref_count == 0) { tspp_unregister_notification(0, channel_id); tspp_close_stream(0, channel_id); } add_channel_close_ch: if (*channel_ref_count == 0) tspp_close_channel(0, channel_id); add_channel_failed: if (*channel_ref_count == 0) if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) mpq_dmx_channel_mem_free(tsif); mutex_unlock(&mpq_dmx_tspp_info.tsif[tsif].mutex); return ret; }