From c2392df88afbb985d9396aa75c202830b471245d Mon Sep 17 00:00:00 2001 From: Liron Kuch Date: Thu, 14 Feb 2013 16:26:38 +0200 Subject: [PATCH] tspp: improve tspp_open_stream/tspp_close_stream behavior The TSPP driver's kernel API supports opening and closing a TSPP stream using the tspp_open_stream/tspp_close_stream API functions. This commit fixes a few minor issues with the behavior and usage of this API. tspp_open_stream and tspp_close_stream were fixed to connect/disconnect the appropriate TSIF source based on the TSIF reference count. The call to tspp_close_stream from within tspp_close_channel was removed, since a kernel driver that uses the TSPP driver API is expected to call tspp_close_stream explicitly, and not rely on the TSPP driver to close the stream implicitly when the channel is closed. An ioctl was added to allow user-space application to close the stream. Change-Id: If49b440d9d83c8bba54aeabc18e8f06b3cc11b3e Signed-off-by: Liron Kuch --- .../dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c | 2 +- drivers/misc/tspp.c | 50 ++++++++++++------- include/linux/tspp.h | 2 + 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c index 49f87bad9a6..632e864ee8c 100644 --- a/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c +++ b/drivers/media/dvb/mpq/demux/mpq_dmx_plugin_tspp_v1.c @@ -1433,8 +1433,8 @@ static int mpq_tspp_dmx_remove_channel(struct dvb_demux_feed *feed) if (*channel_ref_count == 0) { /* channel is not used any more, release it */ tspp_unregister_notification(0, channel_id); - tspp_close_channel(0, channel_id); tspp_close_stream(0, channel_id); + tspp_close_channel(0, channel_id); atomic_set(data_cnt, 0); if (allocation_mode == MPQ_DMX_TSPP_CONTIGUOUS_PHYS_ALLOC) diff --git a/drivers/misc/tspp.c b/drivers/misc/tspp.c index ef238718611..9a538174fe4 100644 --- a/drivers/misc/tspp.c +++ b/drivers/misc/tspp.c @@ -1319,10 +1319,12 @@ int tspp_open_stream(u32 dev, u32 channel_id, pr_err("tspp: error starting tsif0"); return -EBUSY; } - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS, - pdev->base + TSPP_CONTROL); - wmb(); + if (pdev->tsif[0].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_TSIF1: if (tspp_config_gpios(pdev, channel->src, 1) != 0) { @@ -1334,10 +1336,12 @@ int tspp_open_stream(u32 dev, u32 channel_id, pr_err("tspp: error starting tsif1"); return -EBUSY; } - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS, - pdev->base + TSPP_CONTROL); - wmb(); + if (pdev->tsif[1].ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val & ~TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_MEM: break; @@ -1363,6 +1367,7 @@ EXPORT_SYMBOL(tspp_open_stream); int tspp_close_stream(u32 dev, u32 channel_id) { u32 val; + u32 prev_ref_count; struct tspp_device *pdev; struct tspp_channel *channel; @@ -1379,23 +1384,30 @@ int tspp_close_stream(u32 dev, u32 channel_id) switch (channel->src) { case TSPP_SOURCE_TSIF0: + prev_ref_count = pdev->tsif[0].ref_count; tspp_stop_tsif(&pdev->tsif[0]); if (tspp_config_gpios(pdev, channel->src, 0) != 0) pr_err("tspp: error disabling tsif0 GPIOs\n"); - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS, - pdev->base + TSPP_CONTROL); - wmb(); + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF0_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_TSIF1: + prev_ref_count = pdev->tsif[1].ref_count; tspp_stop_tsif(&pdev->tsif[1]); if (tspp_config_gpios(pdev, channel->src, 0) != 0) pr_err("tspp: error disabling tsif0 GPIOs\n"); - val = readl_relaxed(pdev->base + TSPP_CONTROL); - writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS, - pdev->base + TSPP_CONTROL); + if (prev_ref_count == 1) { + val = readl_relaxed(pdev->base + TSPP_CONTROL); + writel_relaxed(val | TSPP_CONTROL_TSP_TSIF1_SRC_DIS, + pdev->base + TSPP_CONTROL); + wmb(); + } break; case TSPP_SOURCE_MEM: break; @@ -1595,9 +1607,6 @@ int tspp_close_channel(u32 dev, u32 channel_id) } channel->filter_count = 0; - /* stop the stream */ - tspp_close_stream(dev, channel->id); - /* disconnect the bam */ if (sps_disconnect(channel->pipe) != 0) pr_warn("tspp: Error freeing sps endpoint (%i)", channel->id); @@ -2435,7 +2444,7 @@ static long tspp_ioctl(struct file *filp, channel = filp->private_data; dev = channel->pdev->pdev->id; - if (!param1) + if ((param0 != TSPP_IOCTL_CLOSE_STREAM) && !param1) return -EINVAL; switch (param0) { @@ -2502,6 +2511,9 @@ static long tspp_ioctl(struct file *filp, sizeof(struct tspp_buffer)) == 0) rc = tspp_set_buffer_size(channel, &b); break; + case TSPP_IOCTL_CLOSE_STREAM: + rc = tspp_close_stream(dev, channel->id); + break; default: pr_err("tspp: Unknown ioctl %i", param0); } diff --git a/include/linux/tspp.h b/include/linux/tspp.h index 551fbb090aa..c790c28dae7 100644 --- a/include/linux/tspp.h +++ b/include/linux/tspp.h @@ -88,5 +88,7 @@ struct tspp_buffer { _IOW(TSPP_IOCTL_BASE, 5, struct tspp_system_keys) #define TSPP_IOCTL_BUFFER_SIZE \ _IOW(TSPP_IOCTL_BASE, 6, struct tspp_buffer) +#define TSPP_IOCTL_CLOSE_STREAM \ + _IO(TSPP_IOCTL_BASE, 7) #endif /* _TSPP_H_ */