Skip to content

Commit

Permalink
media: tuners: Don't use dynamic static allocation
Browse files Browse the repository at this point in the history
commit f1baab8 upstream.

Dynamic static allocation is evil, as Kernel stack is too low, and
compilation complains about it on some archs:
	drivers/media/tuners/e4000.c:50:1: warning: 'e4000_wr_regs' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/e4000.c:83:1: warning: 'e4000_rd_regs' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/fc2580.c:66:1: warning: 'fc2580_wr_regs.constprop.1' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/fc2580.c:98:1: warning: 'fc2580_rd_regs.constprop.0' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/tda18212.c:57:1: warning: 'tda18212_wr_regs' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/tda18212.c:90:1: warning: 'tda18212_rd_regs.constprop.0' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/tda18218.c:60:1: warning: 'tda18218_wr_regs' uses dynamic stack allocation [enabled by default]
	drivers/media/tuners/tda18218.c:92:1: warning: 'tda18218_rd_regs.constprop.0' uses dynamic stack allocation [enabled by default]
Instead, let's enforce a limit for the buffer. Considering that I2C
transfers are generally limited, and that devices used on USB has a
max data length of 64 bytes for	the control URBs.
So, it seem safe to use 64 bytes as the hard limit for all those devices.
 On most cases, the limit is a way lower than that, but	this limit
is small enough to not affect the Kernel stack, and it is a no brain
limit, as using smaller ones would require to either carefully each
driver or to take a look on each datasheet.

Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Reviewed-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Mauro Carvalho Chehab authored and Greg Kroah-Hartman committed Dec 4, 2013
1 parent e9812be commit 93d4a23
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 15 deletions.
25 changes: 21 additions & 4 deletions drivers/media/tuners/e4000.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,30 @@
#include "e4000_priv.h"
#include <linux/math64.h>

/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64

/* write multiple registers */
static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
u8 buf[1 + len];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_addr,
.flags = 0,
.len = sizeof(buf),
.len = 1 + len,
.buf = buf,
}
};

if (1 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

buf[0] = reg;
memcpy(&buf[1], val, len);

Expand All @@ -54,7 +64,7 @@ static int e4000_wr_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
u8 buf[len];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[2] = {
{
.addr = priv->cfg->i2c_addr,
Expand All @@ -64,11 +74,18 @@ static int e4000_rd_regs(struct e4000_priv *priv, u8 reg, u8 *val, int len)
}, {
.addr = priv->cfg->i2c_addr,
.flags = I2C_M_RD,
.len = sizeof(buf),
.len = len,
.buf = buf,
}
};

if (len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c rd reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, buf, len);
Expand Down
25 changes: 21 additions & 4 deletions drivers/media/tuners/fc2580.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

#include "fc2580_priv.h"

/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64

/*
* TODO:
* I2C write and read works only for one single register. Multiple registers
Expand All @@ -41,16 +44,23 @@
static int fc2580_wr_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
u8 buf[1 + len];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_addr,
.flags = 0,
.len = sizeof(buf),
.len = 1 + len,
.buf = buf,
}
};

if (1 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

buf[0] = reg;
memcpy(&buf[1], val, len);

Expand All @@ -69,7 +79,7 @@ static int fc2580_wr_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len)
static int fc2580_rd_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
u8 buf[len];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[2] = {
{
.addr = priv->cfg->i2c_addr,
Expand All @@ -79,11 +89,18 @@ static int fc2580_rd_regs(struct fc2580_priv *priv, u8 reg, u8 *val, int len)
}, {
.addr = priv->cfg->i2c_addr,
.flags = I2C_M_RD,
.len = sizeof(buf),
.len = len,
.buf = buf,
}
};

if (len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c rd reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, buf, len);
Expand Down
25 changes: 21 additions & 4 deletions drivers/media/tuners/tda18212.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@

#include "tda18212.h"

/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64

struct tda18212_priv {
struct tda18212_config *cfg;
struct i2c_adapter *i2c;
Expand All @@ -32,16 +35,23 @@ static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
int len)
{
int ret;
u8 buf[len+1];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_address,
.flags = 0,
.len = sizeof(buf),
.len = 1 + len,
.buf = buf,
}
};

if (1 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

buf[0] = reg;
memcpy(&buf[1], val, len);

Expand All @@ -61,7 +71,7 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
int len)
{
int ret;
u8 buf[len];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[2] = {
{
.addr = priv->cfg->i2c_address,
Expand All @@ -71,11 +81,18 @@ static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val,
}, {
.addr = priv->cfg->i2c_address,
.flags = I2C_M_RD,
.len = sizeof(buf),
.len = len,
.buf = buf,
}
};

if (len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c rd reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, buf, len);
Expand Down
23 changes: 20 additions & 3 deletions drivers/media/tuners/tda18218.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@

#include "tda18218_priv.h"

/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 64

/* write multiple registers */
static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
{
int ret = 0, len2, remaining;
u8 buf[1 + len];
u8 buf[MAX_XFER_SIZE];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg->i2c_address,
Expand All @@ -33,6 +36,13 @@ static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
}
};

if (1 + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

for (remaining = len; remaining > 0;
remaining -= (priv->cfg->i2c_wr_max - 1)) {
len2 = remaining;
Expand Down Expand Up @@ -63,7 +73,7 @@ static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
{
int ret;
u8 buf[reg+len]; /* we must start read always from reg 0x00 */
u8 buf[MAX_XFER_SIZE]; /* we must start read always from reg 0x00 */
struct i2c_msg msg[2] = {
{
.addr = priv->cfg->i2c_address,
Expand All @@ -73,11 +83,18 @@ static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
}, {
.addr = priv->cfg->i2c_address,
.flags = I2C_M_RD,
.len = sizeof(buf),
.len = reg + len,
.buf = buf,
}
};

if (reg + len > sizeof(buf)) {
dev_warn(&priv->i2c->dev,
"%s: i2c wr reg=%04x: len=%d is too big!\n",
KBUILD_MODNAME, reg, len);
return -EINVAL;
}

ret = i2c_transfer(priv->i2c, msg, 2);
if (ret == 2) {
memcpy(val, &buf[reg], len);
Expand Down

0 comments on commit 93d4a23

Please sign in to comment.