Merge "msm: ipa: disable IPA dropping of packets on WLAN TX pipes"
diff --git a/arch/arm/boot/dts/msm8610-coresight.dtsi b/arch/arm/boot/dts/msm8610-coresight.dtsi
index 2515e62..3fbd6fc 100644
--- a/arch/arm/boot/dts/msm8610-coresight.dtsi
+++ b/arch/arm/boot/dts/msm8610-coresight.dtsi
@@ -23,6 +23,7 @@
coresight-id = <0>;
coresight-name = "coresight-tmc-etr";
coresight-nr-inports = <1>;
+ coresight-ctis = <&cti0 &cti8>;
};
tpiu: tpiu@fc320000 {
@@ -60,6 +61,7 @@
coresight-child-list = <&replicator>;
coresight-child-ports = <0>;
coresight-default-sink;
+ coresight-ctis = <&cti0 &cti8>;
};
funnel_merg: funnel@fc323000 {
@@ -203,4 +205,134 @@
qcom,blk-size = <3>;
};
+
+ cti0: cti@fc310000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc310000 0x1000>;
+ reg-names = "cti0-base";
+
+ coresight-id = <14>;
+ coresight-name = "coresight-cti0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti1: cti@fc311000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc311000 0x1000>;
+ reg-names = "cti1-base";
+
+ coresight-id = <15>;
+ coresight-name = "coresight-cti1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti2: cti@fc312000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc312000 0x1000>;
+ reg-names = "cti2-base";
+
+ coresight-id = <16>;
+ coresight-name = "coresight-cti2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti3: cti@fc313000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc313000 0x1000>;
+ reg-names = "cti3-base";
+
+ coresight-id = <17>;
+ coresight-name = "coresight-cti3";
+ coresight-nr-inports = <0>;
+ };
+
+ cti4: cti@fc314000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc314000 0x1000>;
+ reg-names = "cti4-base";
+
+ coresight-id = <18>;
+ coresight-name = "coresight-cti4";
+ coresight-nr-inports = <0>;
+ };
+
+ cti5: cti@fc315000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc315000 0x1000>;
+ reg-names = "cti5-base";
+
+ coresight-id = <19>;
+ coresight-name = "coresight-cti5";
+ coresight-nr-inports = <0>;
+ };
+
+ cti6: cti@fc316000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc316000 0x1000>;
+ reg-names = "cti6-base";
+
+ coresight-id = <20>;
+ coresight-name = "coresight-cti6";
+ coresight-nr-inports = <0>;
+ };
+
+ cti7: cti@fc317000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc317000 0x1000>;
+ reg-names = "cti7-base";
+
+ coresight-id = <21>;
+ coresight-name = "coresight-cti7";
+ coresight-nr-inports = <0>;
+ };
+
+ cti8: cti@fc318000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc318000 0x1000>;
+ reg-names = "cti8-base";
+
+ coresight-id = <22>;
+ coresight-name = "coresight-cti8";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu0: cti@fc351000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc351000 0x1000>;
+ reg-names = "cti-cpu0-base";
+
+ coresight-id = <23>;
+ coresight-name = "coresight-cti-cpu0";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu1: cti@fc352000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc352000 0x1000>;
+ reg-names = "cti-cpu1-base";
+
+ coresight-id = <24>;
+ coresight-name = "coresight-cti-cpu1";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu2: cti@fc353000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc353000 0x1000>;
+ reg-names = "cti-cpu2-base";
+
+ coresight-id = <25>;
+ coresight-name = "coresight-cti-cpu2";
+ coresight-nr-inports = <0>;
+ };
+
+ cti_cpu3: cti@fc354000 {
+ compatible = "arm,coresight-cti";
+ reg = <0xfc354000 0x1000>;
+ reg-names = "cti-cpu3-base";
+
+ coresight-id = <26>;
+ coresight-name = "coresight-cti-cpu3";
+ coresight-nr-inports = <0>;
+ };
};
diff --git a/arch/arm/configs/msm8974-perf_defconfig b/arch/arm/configs/msm8974-perf_defconfig
index 2f5f7f0..d2c97b1 100644
--- a/arch/arm/configs/msm8974-perf_defconfig
+++ b/arch/arm/configs/msm8974-perf_defconfig
@@ -226,6 +226,8 @@
CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=y
CONFIG_BT_HCISMD=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_ATH3K=y
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_NL80211_TESTMODE=y
diff --git a/arch/arm/configs/msm8974_defconfig b/arch/arm/configs/msm8974_defconfig
index 4aebfdb..c9d6112 100644
--- a/arch/arm/configs/msm8974_defconfig
+++ b/arch/arm/configs/msm8974_defconfig
@@ -230,6 +230,8 @@
CONFIG_BT_BNEP_PROTO_FILTER=y
CONFIG_BT_HIDP=y
CONFIG_BT_HCISMD=y
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_ATH3K=y
CONFIG_MSM_BT_POWER=y
CONFIG_CFG80211=y
CONFIG_NL80211_TESTMODE=y
diff --git a/arch/arm/mach-msm/gpiomux.c b/arch/arm/mach-msm/gpiomux.c
index 4714210..1f7d56a 100644
--- a/arch/arm/mach-msm/gpiomux.c
+++ b/arch/arm/mach-msm/gpiomux.c
@@ -13,7 +13,9 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
+#include <linux/io.h>
#include <mach/gpiomux.h>
+#include <mach/msm_iomap.h>
struct msm_gpiomux_rec {
struct gpiomux_setting *sets[GPIOMUX_NSETTINGS];
@@ -121,6 +123,13 @@
}
EXPORT_SYMBOL(msm_gpiomux_put);
+void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val)
+{
+ writel_relaxed(val, MSM_TLMM_BASE + misc_reg);
+ /* ensure the write completes before returning */
+ mb();
+}
+
int msm_gpiomux_init(size_t ngpio)
{
if (!ngpio)
diff --git a/arch/arm/mach-msm/include/mach/gpiomux.h b/arch/arm/mach-msm/include/mach/gpiomux.h
index 5ffcabb..9aae3fb 100644
--- a/arch/arm/mach-msm/include/mach/gpiomux.h
+++ b/arch/arm/mach-msm/include/mach/gpiomux.h
@@ -109,6 +109,14 @@
size_t ncfg;
};
+/* Provide an enum and an API to write to misc TLMM registers */
+enum msm_tlmm_misc_reg {
+ TLMM_ETM_MODE_REG = 0x2014,
+ TLMM_SDC2_HDRV_PULL_CTL = 0x2048,
+};
+
+void msm_tlmm_misc_reg_write(enum msm_tlmm_misc_reg misc_reg, int val);
+
#ifdef CONFIG_MSM_GPIOMUX
/* Before using gpiomux, initialize the subsystem by telling it how many
diff --git a/drivers/media/platform/msm/camera_v2/Kconfig b/drivers/media/platform/msm/camera_v2/Kconfig
index e4777e6..d1e9b9e 100644
--- a/drivers/media/platform/msm/camera_v2/Kconfig
+++ b/drivers/media/platform/msm/camera_v2/Kconfig
@@ -109,6 +109,15 @@
1280 * 270. It does not support auto focus. It supports
few special effects like saturation.
+config OV8825
+ bool "OmniVision OV8825 (BAYER 8MP)"
+ depends on MSMB_CAMERA
+ ---help---
+ OmniVision 8 MP Bayer Sensor with auto focus.uses
+ 2 mipi lanes, preview config = 1632*1224 30 fps,
+ snapshot config = 3264 * 2448 at 18 fps.
+ 2 lanes max fps is 18, 4 lanes max fps is 24.
+
config MSM_V4L2_VIDEO_OVERLAY_DEVICE
tristate "Qualcomm MSM V4l2 video overlay device"
---help---
@@ -119,7 +128,7 @@
config MSMB_JPEG
tristate "Qualcomm MSM Jpeg Encoder Engine support"
- depends on MSMB_CAMERA && ARCH_MSM8974
+ depends on MSMB_CAMERA && (ARCH_MSM8974 || ARCH_MSM8226)
---help---
Enable support for Jpeg Encoder/Decoder
Engine for 8974.
diff --git a/drivers/media/platform/msm/camera_v2/sensor/Makefile b/drivers/media/platform/msm/camera_v2/sensor/Makefile
index 6f941f7..62911bf 100644
--- a/drivers/media/platform/msm/camera_v2/sensor/Makefile
+++ b/drivers/media/platform/msm/camera_v2/sensor/Makefile
@@ -7,5 +7,6 @@
obj-$(CONFIG_MSM_CAMERA_SENSOR) += msm_sensor.o
obj-$(CONFIG_S5K3L1YX) += s5k3l1yx.o
obj-$(CONFIG_IMX135) += imx135.o
+obj-$(CONFIG_OV8825) += ov8825.o
obj-$(CONFIG_OV2720) += ov2720.o
obj-$(CONFIG_MT9M114) += mt9m114.o
diff --git a/drivers/media/platform/msm/camera_v2/sensor/ov8825.c b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
new file mode 100644
index 0000000..b56eb10
--- /dev/null
+++ b/drivers/media/platform/msm/camera_v2/sensor/ov8825.c
@@ -0,0 +1,167 @@
+/* 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 "msm_sensor.h"
+#define OV8825_SENSOR_NAME "ov8825"
+DEFINE_MSM_MUTEX(ov8825_mut);
+
+static struct msm_sensor_ctrl_t ov8825_s_ctrl;
+
+static struct msm_sensor_power_setting ov8825_power_setting[] = {
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VIO,
+ .config_val = 0,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VANA,
+ .config_val = 0,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VDIG,
+ .config_val = 0,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_VREG,
+ .seq_val = CAM_VAF,
+ .config_val = 0,
+ .delay = 15,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 15,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_LOW,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_STANDBY,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_GPIO,
+ .seq_val = SENSOR_GPIO_RESET,
+ .config_val = GPIO_OUT_HIGH,
+ .delay = 40,
+ },
+ {
+ .seq_type = SENSOR_CLK,
+ .seq_val = SENSOR_CAM_MCLK,
+ .config_val = 24000000,
+ .delay = 5,
+ },
+ {
+ .seq_type = SENSOR_I2C_MUX,
+ .seq_val = 0,
+ .config_val = 0,
+ .delay = 0,
+ },
+};
+
+static struct v4l2_subdev_info ov8825_subdev_info[] = {
+ {
+ .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .fmt = 1,
+ .order = 0,
+ },
+};
+
+static const struct i2c_device_id ov8825_i2c_id[] = {
+ {OV8825_SENSOR_NAME, (kernel_ulong_t)&ov8825_s_ctrl},
+ { }
+};
+
+static struct i2c_driver ov8825_i2c_driver = {
+ .id_table = ov8825_i2c_id,
+ .probe = msm_sensor_i2c_probe,
+ .driver = {
+ .name = OV8825_SENSOR_NAME,
+ },
+};
+
+static struct msm_camera_i2c_client ov8825_sensor_i2c_client = {
+ .addr_type = MSM_CAMERA_I2C_WORD_ADDR,
+};
+
+static const struct of_device_id ov8825_dt_match[] = {
+ {.compatible = "qcom,ov8825", .data = &ov8825_s_ctrl},
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, ov8825_dt_match);
+
+static struct platform_driver ov8825_platform_driver = {
+ .driver = {
+ .name = "qcom,ov8825",
+ .owner = THIS_MODULE,
+ .of_match_table = ov8825_dt_match,
+ },
+};
+
+static int32_t ov8825_platform_probe(struct platform_device *pdev)
+{
+ int32_t rc = 0;
+ const struct of_device_id *match;
+ match = of_match_device(ov8825_dt_match, &pdev->dev);
+ rc = msm_sensor_platform_probe(pdev, match->data);
+ return rc;
+}
+
+static int __init ov8825_init_module(void)
+{
+ int32_t rc = 0;
+ pr_info("%s:%d\n", __func__, __LINE__);
+ rc = platform_driver_probe(&ov8825_platform_driver,
+ ov8825_platform_probe);
+ if (!rc)
+ return rc;
+ pr_err("%s:%d rc %d\n", __func__, __LINE__, rc);
+ return i2c_add_driver(&ov8825_i2c_driver);
+}
+
+static void __exit ov8825_exit_module(void)
+{
+ pr_info("%s:%d\n", __func__, __LINE__);
+ if (ov8825_s_ctrl.pdev) {
+ msm_sensor_free_sensor_data(&ov8825_s_ctrl);
+ platform_driver_unregister(&ov8825_platform_driver);
+ } else
+ i2c_del_driver(&ov8825_i2c_driver);
+ return;
+}
+
+static struct msm_sensor_ctrl_t ov8825_s_ctrl = {
+ .sensor_i2c_client = &ov8825_sensor_i2c_client,
+ .power_setting_array.power_setting = ov8825_power_setting,
+ .power_setting_array.size = ARRAY_SIZE(ov8825_power_setting),
+ .msm_sensor_mutex = &ov8825_mut,
+ .sensor_v4l2_subdev_info = ov8825_subdev_info,
+ .sensor_v4l2_subdev_info_size = ARRAY_SIZE(ov8825_subdev_info),
+};
+
+module_init(ov8825_init_module);
+module_exit(ov8825_exit_module);
+MODULE_DESCRIPTION("ov8825");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
index 6ec1994..76ce0c0 100644
--- a/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
+++ b/drivers/media/platform/msm/dvb/adapter/mpq_stream_buffer.c
@@ -19,8 +19,6 @@
#include "mpq_stream_buffer.h"
-
-
int mpq_streambuffer_init(
struct mpq_streambuffer *sbuff,
enum mpq_streambuffer_mode mode,
@@ -29,7 +27,8 @@
void *packet_buff,
size_t packet_buff_size)
{
- if ((NULL == sbuff) || (NULL == data_buffers) || (NULL == packet_buff))
+ if ((NULL == sbuff) || (NULL == data_buffers) ||
+ (NULL == packet_buff) || (data_buff_num == 0))
return -EINVAL;
if (data_buff_num > 1) {
@@ -41,7 +40,7 @@
data_buffers,
data_buff_num *
sizeof(struct mpq_streambuffer_buffer_desc));
- } else if (data_buff_num == 1) {
+ } else {
if (mode != MPQ_STREAMBUFFER_BUFFER_MODE_RING)
return -EINVAL;
/* Single ring-buffer */
@@ -58,12 +57,38 @@
}
EXPORT_SYMBOL(mpq_streambuffer_init);
+void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff)
+{
+ spin_lock(&sbuff->packet_data.lock);
+ spin_lock(&sbuff->raw_data.lock);
+ sbuff->packet_data.error = -ENODEV;
+ sbuff->raw_data.error = -ENODEV;
+ spin_unlock(&sbuff->raw_data.lock);
+ spin_unlock(&sbuff->packet_data.lock);
+
+ wake_up_all(&sbuff->raw_data.queue);
+ wake_up_all(&sbuff->packet_data.queue);
+}
+EXPORT_SYMBOL(mpq_streambuffer_terminate);
ssize_t mpq_streambuffer_pkt_next(
struct mpq_streambuffer *sbuff,
ssize_t idx, size_t *pktlen)
{
- return dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+ ssize_t packet_idx;
+
+ spin_lock(&sbuff->packet_data.lock);
+
+ /* buffer was released, return no packet available */
+ if (sbuff->packet_data.error == -ENODEV) {
+ spin_unlock(&sbuff->packet_data.lock);
+ return -ENODEV;
+ }
+
+ packet_idx = dvb_ringbuffer_pkt_next(&sbuff->packet_data, idx, pktlen);
+ spin_unlock(&sbuff->packet_data.lock);
+
+ return packet_idx;
}
EXPORT_SYMBOL(mpq_streambuffer_pkt_next);
@@ -77,6 +102,14 @@
size_t ret;
size_t read_len;
+ spin_lock(&sbuff->packet_data.lock);
+
+ /* buffer was released, return no packet available */
+ if (sbuff->packet_data.error == -ENODEV) {
+ spin_unlock(&sbuff->packet_data.lock);
+ return -ENODEV;
+ }
+
/* read-out the packet header first */
ret = dvb_ringbuffer_pkt_read(
&sbuff->packet_data, idx, 0,
@@ -84,8 +117,10 @@
sizeof(struct mpq_streambuffer_packet_header));
/* verify length, at least packet header should exist */
- if (ret != sizeof(struct mpq_streambuffer_packet_header))
+ if (ret != sizeof(struct mpq_streambuffer_packet_header)) {
+ spin_unlock(&sbuff->packet_data.lock);
return -EINVAL;
+ }
read_len = ret;
@@ -98,12 +133,16 @@
user_data,
packet->user_data_len);
- if (ret < 0)
+ if (ret < 0) {
+ spin_unlock(&sbuff->packet_data.lock);
return ret;
+ }
read_len += ret;
}
+ spin_unlock(&sbuff->packet_data.lock);
+
return read_len;
}
EXPORT_SYMBOL(mpq_streambuffer_pkt_read);
@@ -120,12 +159,22 @@
if (NULL == sbuff)
return -EINVAL;
+ spin_lock(&sbuff->packet_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->packet_data.error == -ENODEV) {
+ spin_unlock(&sbuff->packet_data.lock);
+ return -ENODEV;
+ }
+
/* read-out the packet header first */
ret = dvb_ringbuffer_pkt_read(&sbuff->packet_data, idx,
0,
(u8 *)&packet,
sizeof(struct mpq_streambuffer_packet_header));
+ spin_unlock(&sbuff->packet_data.lock);
+
if (ret != sizeof(struct mpq_streambuffer_packet_header))
return -EINVAL;
@@ -138,6 +187,17 @@
return ret;
}
+ spin_lock(&sbuff->packet_data.lock);
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if ((sbuff->packet_data.error == -ENODEV) ||
+ (sbuff->raw_data.error == -ENODEV)) {
+ spin_unlock(&sbuff->raw_data.lock);
+ spin_unlock(&sbuff->packet_data.lock);
+ return -ENODEV;
+ }
+
/* Move read pointer to the next linear buffer for subsequent reads */
if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
(packet.raw_data_len > 0)) {
@@ -159,6 +219,9 @@
/* Now clear the packet from the packet header */
dvb_ringbuffer_pkt_dispose(&sbuff->packet_data, idx);
+ spin_unlock(&sbuff->raw_data.lock);
+ spin_unlock(&sbuff->packet_data.lock);
+
if (sbuff->cb)
sbuff->cb(sbuff, sbuff->cb_user_data);
@@ -177,12 +240,22 @@
if ((NULL == sbuff) || (NULL == packet))
return -EINVAL;
+ spin_lock(&sbuff->packet_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->packet_data.error == -ENODEV) {
+ spin_unlock(&sbuff->packet_data.lock);
+ return -ENODEV;
+ }
+
len = sizeof(struct mpq_streambuffer_packet_header) +
packet->user_data_len;
/* Make sure enough space available for packet header */
- if (dvb_ringbuffer_free(&sbuff->packet_data) < len)
+ if (dvb_ringbuffer_free(&sbuff->packet_data) < len) {
+ spin_unlock(&sbuff->packet_data.lock);
return -ENOSPC;
+ }
/* Starting writing packet header */
idx = dvb_ringbuffer_pkt_start(&sbuff->packet_data, len);
@@ -202,20 +275,22 @@
/* Move write pointer to next linear buffer for subsequent writes */
if ((MPQ_STREAMBUFFER_BUFFER_MODE_LINEAR == sbuff->mode) &&
(packet->raw_data_len > 0)) {
- if (sbuff->pending_buffers_count == sbuff->buffers_num)
+ if (sbuff->pending_buffers_count == sbuff->buffers_num) {
+ spin_unlock(&sbuff->packet_data.lock);
return -ENOSPC;
+ }
DVB_RINGBUFFER_PUSH(&sbuff->raw_data,
sizeof(struct mpq_streambuffer_buffer_desc));
sbuff->pending_buffers_count++;
}
+ spin_unlock(&sbuff->packet_data.lock);
wake_up_all(&sbuff->packet_data.queue);
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_pkt_write);
-
ssize_t mpq_streambuffer_data_write(
struct mpq_streambuffer *sbuff,
const u8 *buf, size_t len)
@@ -225,15 +300,27 @@
if ((NULL == sbuff) || (NULL == buf))
return -EINVAL;
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
- if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+ if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) {
+ spin_unlock(&sbuff->raw_data.lock);
return -ENOSPC;
+ }
/*
* Secure buffers are not permitted to be mapped into kernel
* memory, and so buffer base address may be NULL
*/
- if (NULL == sbuff->raw_data.data)
+ if (NULL == sbuff->raw_data.data) {
+ spin_unlock(&sbuff->raw_data.lock);
return -EPERM;
+ }
res = dvb_ringbuffer_write(&sbuff->raw_data, buf, len);
wake_up_all(&sbuff->raw_data.queue);
} else {
@@ -247,8 +334,10 @@
* Secure buffers are not permitted to be mapped into kernel
* memory, and so buffer base address may be NULL
*/
- if (NULL == desc->base)
+ if (NULL == desc->base) {
+ spin_unlock(&sbuff->raw_data.lock);
return -EPERM;
+ }
if ((sbuff->pending_buffers_count == sbuff->buffers_num) ||
((desc->size - desc->write_ptr) < len)) {
@@ -259,6 +348,7 @@
sbuff->buffers_num,
desc->write_ptr,
desc->size);
+ spin_unlock(&sbuff->raw_data.lock);
return -ENOSPC;
}
memcpy(desc->base + desc->write_ptr, buf, len);
@@ -266,6 +356,7 @@
res = len;
}
+ spin_unlock(&sbuff->raw_data.lock);
return res;
}
EXPORT_SYMBOL(mpq_streambuffer_data_write);
@@ -278,9 +369,19 @@
if (NULL == sbuff)
return -EINVAL;
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
- if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len))
+ if (unlikely(dvb_ringbuffer_free(&sbuff->raw_data) < len)) {
+ spin_unlock(&sbuff->raw_data.lock);
return -ENOSPC;
+ }
DVB_RINGBUFFER_PUSH(&sbuff->raw_data, len);
wake_up_all(&sbuff->raw_data.queue);
@@ -295,11 +396,13 @@
MPQ_DVB_ERR_PRINT(
"%s: No space available!\n",
__func__);
+ spin_unlock(&sbuff->raw_data.lock);
return -ENOSPC;
}
desc->write_ptr += len;
}
+ spin_unlock(&sbuff->raw_data.lock);
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_data_write_deposit);
@@ -314,13 +417,23 @@
if ((NULL == sbuff) || (NULL == buf))
return -EINVAL;
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
/*
* Secure buffers are not permitted to be mapped into kernel
* memory, and so buffer base address may be NULL
*/
- if (NULL == sbuff->raw_data.data)
+ if (NULL == sbuff->raw_data.data) {
+ spin_unlock(&sbuff->raw_data.lock);
return -EPERM;
+ }
actual_len = dvb_ringbuffer_avail(&sbuff->raw_data);
if (actual_len < len)
@@ -340,8 +453,10 @@
* Secure buffers are not permitted to be mapped into kernel
* memory, and so buffer base address may be NULL
*/
- if (NULL == desc->base)
+ if (NULL == desc->base) {
+ spin_unlock(&sbuff->raw_data.lock);
return -EPERM;
+ }
actual_len = (desc->write_ptr - desc->read_ptr);
if (actual_len < len)
@@ -350,6 +465,7 @@
desc->read_ptr += len;
}
+ spin_unlock(&sbuff->raw_data.lock);
return len;
}
EXPORT_SYMBOL(mpq_streambuffer_data_read);
@@ -364,6 +480,10 @@
if ((NULL == sbuff) || (NULL == buf))
return -EINVAL;
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV)
+ return -ENODEV;
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
/*
* Secure buffers are not permitted to be mapped into kernel
@@ -397,6 +517,7 @@
len = actual_len;
if (copy_to_user(buf, desc->base + desc->read_ptr, len))
return -EFAULT;
+
desc->read_ptr += len;
}
@@ -404,7 +525,6 @@
}
EXPORT_SYMBOL(mpq_streambuffer_data_read_user);
-
int mpq_streambuffer_data_read_dispose(
struct mpq_streambuffer *sbuff,
size_t len)
@@ -412,9 +532,19 @@
if (NULL == sbuff)
return -EINVAL;
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
- if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len))
+ if (unlikely(dvb_ringbuffer_avail(&sbuff->raw_data) < len)) {
+ spin_unlock(&sbuff->raw_data.lock);
return -EINVAL;
+ }
DVB_RINGBUFFER_SKIP(&sbuff->raw_data, len);
wake_up_all(&sbuff->raw_data.queue);
@@ -429,6 +559,8 @@
desc->read_ptr += len;
}
+ spin_unlock(&sbuff->raw_data.lock);
+
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_data_read_dispose);
@@ -444,6 +576,14 @@
if ((NULL == sbuff) || (NULL == handle))
return -EINVAL;
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
*handle = sbuff->buffers[0].handle;
} else {
@@ -455,6 +595,9 @@
&sbuff->raw_data.data[sbuff->raw_data.pwrite];
*handle = desc->handle;
}
+
+ spin_unlock(&sbuff->raw_data.lock);
+
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_get_buffer_handle);
@@ -484,15 +627,29 @@
if (NULL == sbuff)
return -EINVAL;
- if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
- return dvb_ringbuffer_free(&sbuff->raw_data);
+ spin_lock(&sbuff->raw_data.lock);
- if (sbuff->pending_buffers_count == sbuff->buffers_num)
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return dvb_ringbuffer_free(&sbuff->raw_data);
+ }
+
+ if (sbuff->pending_buffers_count == sbuff->buffers_num) {
+ spin_unlock(&sbuff->raw_data.lock);
return 0;
+ }
desc = (struct mpq_streambuffer_buffer_desc *)
&sbuff->raw_data.data[sbuff->raw_data.pwrite];
+ spin_unlock(&sbuff->raw_data.lock);
+
return desc->size - desc->write_ptr;
}
EXPORT_SYMBOL(mpq_streambuffer_data_free);
@@ -506,12 +663,25 @@
if (NULL == sbuff)
return -EINVAL;
- if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode)
- return dvb_ringbuffer_avail(&sbuff->raw_data);
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
+ if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
+ ssize_t avail = dvb_ringbuffer_avail(&sbuff->raw_data);
+ spin_unlock(&sbuff->raw_data.lock);
+ return avail;
+ }
desc = (struct mpq_streambuffer_buffer_desc *)
&sbuff->raw_data.data[sbuff->raw_data.pread];
+ spin_unlock(&sbuff->raw_data.lock);
+
return desc->write_ptr - desc->read_ptr;
}
EXPORT_SYMBOL(mpq_streambuffer_data_avail);
@@ -524,6 +694,14 @@
if (NULL == sbuff)
return -EINVAL;
+ spin_lock(&sbuff->raw_data.lock);
+
+ /* check if buffer was released */
+ if (sbuff->raw_data.error == -ENODEV) {
+ spin_unlock(&sbuff->raw_data.lock);
+ return -ENODEV;
+ }
+
if (MPQ_STREAMBUFFER_BUFFER_MODE_RING == sbuff->mode) {
if (read_offset)
*read_offset = sbuff->raw_data.pread;
@@ -544,6 +722,8 @@
}
}
+ spin_unlock(&sbuff->raw_data.lock);
+
return 0;
}
EXPORT_SYMBOL(mpq_streambuffer_get_data_rw_offset);
diff --git a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
index 9be4704..83b9bb3 100644
--- a/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
+++ b/drivers/media/platform/msm/dvb/demux/mpq_dmx_plugin_common.c
@@ -1469,7 +1469,6 @@
dec_buffs->buffers_size,
dec_buffs->is_linear);
- feed_data->buffer_desc.decoder_buffers_num = dec_buffs->buffers_num;
if (0 == dec_buffs->buffers_num)
ret = mpq_dmx_init_internal_buffers(
feed_data, dec_buffs, client);
@@ -1515,6 +1514,8 @@
mpq_adapter_unregister_stream_if(feed_data->stream_interface);
+ mpq_streambuffer_terminate(video_buffer);
+
vfree(video_buffer->packet_data.data);
buf_num = feed_data->buffer_desc.decoder_buffers_num;
diff --git a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
index 3804fb2..1707c85 100644
--- a/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
+++ b/drivers/media/platform/msm/dvb/include/mpq_stream_buffer.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
+/* 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
@@ -211,6 +211,18 @@
size_t packet_buff_size);
/**
+ * mpq_streambuffer_terminate - Terminate stream buffer
+ *
+ * @sbuff: The buffer to terminate
+ *
+ * The function sets the the buffers error flags to ENODEV
+ * and wakeup any waiting threads on the buffer queues.
+ * Threads waiting on the buffer queues should check if
+ * error was set.
+ */
+void mpq_streambuffer_terminate(struct mpq_streambuffer *sbuff);
+
+/**
* mpq_streambuffer_packet_next - Returns index of next available packet.
*
* @sbuff: The stream buffer