Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4756707 authored by Sean Young's avatar Sean Young Committed by Mauro Carvalho Chehab
Browse files

media: dvb: i2c transfers over usb cannot be done from stack



Since commit 29d2fef8 ("usb: catch attempts to submit urbs
with a vmalloc'd transfer buffer"), the AverMedia AverTV DVB-T
USB 2.0 (a800) fails to probe.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 1efdf177
Loading
Loading
Loading
Loading
+39 −11
Original line number Original line Diff line number Diff line
@@ -55,29 +55,57 @@ struct dib3000mc_state {


static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
{
{
	u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
	u8 rb[2];
	struct i2c_msg msg[2] = {
	struct i2c_msg msg[2] = {
		{ .addr = state->i2c_addr >> 1, .flags = 0,        .buf = wb, .len = 2 },
		{ .addr = state->i2c_addr >> 1, .flags = 0,        .len = 2 },
		{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
		{ .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .len = 2 },
	};
	};
	u16 word;
	u8 *b;

	b = kmalloc(4, GFP_KERNEL);
	if (!b)
		return 0;

	b[0] = (reg >> 8) | 0x80;
	b[1] = reg;
	b[2] = 0;
	b[3] = 0;

	msg[0].buf = b;
	msg[1].buf = b + 2;


	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
	if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
		dprintk("i2c read error on %d\n",reg);
		dprintk("i2c read error on %d\n",reg);


	return (rb[0] << 8) | rb[1];
	word = (b[2] << 8) | b[3];
	kfree(b);

	return word;
}
}


static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
{
{
	u8 b[4] = {
		(reg >> 8) & 0xff, reg & 0xff,
		(val >> 8) & 0xff, val & 0xff,
	};
	struct i2c_msg msg = {
	struct i2c_msg msg = {
		.addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
		.addr = state->i2c_addr >> 1, .flags = 0, .len = 4
	};
	};
	return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
	int rc;
	u8 *b;

	b = kmalloc(4, GFP_KERNEL);
	if (!b)
		return -ENOMEM;

	b[0] = reg >> 8;
	b[1] = reg;
	b[2] = val >> 8;
	b[3] = val;

	msg.buf = b;

	rc = i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
	kfree(b);

	return rc;
}
}


static int dib3000mc_identify(struct dib3000mc_state *state)
static int dib3000mc_identify(struct dib3000mc_state *state)
+17 −5
Original line number Original line Diff line number Diff line
@@ -753,13 +753,19 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
				    struct i2c_adapter *i2c,
				    struct i2c_adapter *i2c,
				    unsigned int pll_desc_id)
				    unsigned int pll_desc_id)
{
{
	u8 b1 [] = { 0 };
	u8 *b1;
	struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD,
	struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .len = 1 };
			       .buf = b1, .len = 1 };
	struct dvb_pll_priv *priv = NULL;
	struct dvb_pll_priv *priv = NULL;
	int ret;
	int ret;
	const struct dvb_pll_desc *desc;
	const struct dvb_pll_desc *desc;


	b1 = kmalloc(1, GFP_KERNEL);
	if (!b1)
		return NULL;

	b1[0] = 0;
	msg.buf = b1;

	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
	if ((id[dvb_pll_devcount] > DVB_PLL_UNDEFINED) &&
	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
	    (id[dvb_pll_devcount] < ARRAY_SIZE(pll_list)))
		pll_desc_id = id[dvb_pll_devcount];
		pll_desc_id = id[dvb_pll_devcount];
@@ -773,15 +779,19 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
			fe->ops.i2c_gate_ctrl(fe, 1);
			fe->ops.i2c_gate_ctrl(fe, 1);


		ret = i2c_transfer (i2c, &msg, 1);
		ret = i2c_transfer (i2c, &msg, 1);
		if (ret != 1)
		if (ret != 1) {
			kfree(b1);
			return NULL;
			return NULL;
		}
		if (fe->ops.i2c_gate_ctrl)
		if (fe->ops.i2c_gate_ctrl)
			     fe->ops.i2c_gate_ctrl(fe, 0);
			     fe->ops.i2c_gate_ctrl(fe, 0);
	}
	}


	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
	priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
	if (priv == NULL)
	if (!priv) {
		kfree(b1);
		return NULL;
		return NULL;
	}


	priv->pll_i2c_address = pll_addr;
	priv->pll_i2c_address = pll_addr;
	priv->i2c = i2c;
	priv->i2c = i2c;
@@ -811,6 +821,8 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
				"insmod option" : "autodetected");
				"insmod option" : "autodetected");
	}
	}


	kfree(b1);

	return fe;
	return fe;
}
}
EXPORT_SYMBOL(dvb_pll_attach);
EXPORT_SYMBOL(dvb_pll_attach);
+47 −12
Original line number Original line Diff line number Diff line
@@ -38,41 +38,74 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
{
{
	struct i2c_msg msg[2] = {
	struct i2c_msg msg[2] = {
		{ .addr = priv->cfg->i2c_address, .flags = 0,        .buf = &reg, .len = 1 },
		{ .addr = priv->cfg->i2c_address, .flags = 0, .len = 1 },
		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val,  .len = 1 },
		{ .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .len = 1 },
	};
	};
	int rc = 0;
	u8 *b;

	b = kmalloc(2, GFP_KERNEL);
	if (!b)
		return -ENOMEM;

	b[0] = reg;
	b[1] = 0;

	msg[0].buf = b;
	msg[1].buf = b + 1;


	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
		printk(KERN_WARNING "mt2060 I2C read failed\n");
		printk(KERN_WARNING "mt2060 I2C read failed\n");
		return -EREMOTEIO;
		rc = -EREMOTEIO;
	}
	}
	return 0;
	*val = b[1];
	kfree(b);

	return rc;
}
}


// Writes a single register
// Writes a single register
static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
{
{
	u8 buf[2] = { reg, val };
	struct i2c_msg msg = {
	struct i2c_msg msg = {
		.addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
		.addr = priv->cfg->i2c_address, .flags = 0, .len = 2
	};
	};
	u8 *buf;
	int rc = 0;

	buf = kmalloc(2, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	buf[0] = reg;
	buf[1] = val;

	msg.buf = buf;


	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
		printk(KERN_WARNING "mt2060 I2C write failed\n");
		printk(KERN_WARNING "mt2060 I2C write failed\n");
		return -EREMOTEIO;
		rc = -EREMOTEIO;
	}
	}
	return 0;
	kfree(buf);
	return rc;
}
}


// Writes a set of consecutive registers
// Writes a set of consecutive registers
static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
{
{
	int rem, val_len;
	int rem, val_len;
	u8 xfer_buf[16];
	u8 *xfer_buf;
	int rc = 0;
	struct i2c_msg msg = {
	struct i2c_msg msg = {
		.addr = priv->cfg->i2c_address, .flags = 0, .buf = xfer_buf
		.addr = priv->cfg->i2c_address, .flags = 0
	};
	};


	xfer_buf = kmalloc(16, GFP_KERNEL);
	if (!xfer_buf)
		return -ENOMEM;

	msg.buf = xfer_buf;

	for (rem = len - 1; rem > 0; rem -= priv->i2c_max_regs) {
	for (rem = len - 1; rem > 0; rem -= priv->i2c_max_regs) {
		val_len = min_t(int, rem, priv->i2c_max_regs);
		val_len = min_t(int, rem, priv->i2c_max_regs);
		msg.len = 1 + val_len;
		msg.len = 1 + val_len;
@@ -81,11 +114,13 @@ static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)


		if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
		if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
			printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n", val_len);
			printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n", val_len);
			return -EREMOTEIO;
			rc = -EREMOTEIO;
			break;
		}
		}
	}
	}


	return 0;
	kfree(xfer_buf);
	return rc;
}
}


// Initialisation sequences
// Initialisation sequences