[linux-dvb] [patch]dma on stack in dib0700

Oliver Neukum oliver at neukum.org
Tue Aug 26 17:05:57 CEST 2008


USB on some architectures cannot do DMA with buffers on the stack.
Therefore the dib0700 driver will fail on some architectures. The fix is
allocating buffers on the stack.

Signed-off-by: Oliver Neukum <oneukum at suse.de>

	Regards
		Oliver

---

--- linux-2.6.27-rc4/drivers/media/dvb/dvb-usb/dib0700_core.c.alt	2008-08-26 15:31:31.000000000 +0200
+++ linux-2.6.27-rc4/drivers/media/dvb/dvb-usb/dib0700_core.c	2008-08-26 15:46:32.000000000 +0200
@@ -77,8 +77,19 @@ int dib0700_ctrl_rd(struct dvb_usb_devic
 
 int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
 {
-	u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
-	return dib0700_ctrl_wr(d,buf,3);
+	u8 *buf;
+	int rv;
+
+	buf = kmalloc(3, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	buf[0] = REQUEST_SET_GPIO;
+	buf[1] = gpio;
+	buf[2] = ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6);
+
+	rv = dib0700_ctrl_wr(d,buf,3);
+	kfree(buf);
+	return rv;
 }
 
 /*
@@ -88,10 +99,15 @@ static int dib0700_i2c_xfer(struct i2c_a
 {
 	struct dvb_usb_device *d = i2c_get_adapdata(adap);
 	int i,len;
-	u8 buf[255];
+	u8 *buf;
 
-	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+	buf = kmalloc(255, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+	if (mutex_lock_interruptible(&d->i2c_mutex) < 0) {
+		kfree(buf);
 		return -EAGAIN;
+	}
 
 	for (i = 0; i < num; i++) {
 		/* fill in the address */
@@ -121,6 +137,7 @@ static int dib0700_i2c_xfer(struct i2c_a
 	}
 
 	mutex_unlock(&d->i2c_mutex);
+	kfree(buf);
 	return i;
 }
 
@@ -137,9 +154,18 @@ struct i2c_algorithm dib0700_i2c_algo =
 int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
 			struct dvb_usb_device_description **desc, int *cold)
 {
-	u8 b[16];
-	s16 ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
+	u8 *b;
+	s16 ret;
+
+	b = kmalloc(16, GFP_KERNEL);
+
+	if (b) {
+		ret = usb_control_msg(udev, usb_rcvctrlpipe(udev,0),
 		REQUEST_GET_VERSION, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, b, 16, USB_CTRL_GET_TIMEOUT);
+		kfree(b);
+	} else {
+		ret = 0;
+	}
 
 	deb_info("FW GET_VERSION length: %d\n",ret);
 
@@ -153,7 +179,12 @@ static int dib0700_set_clock(struct dvb_
 	u8 pll_src, u8 pll_range, u8 clock_gpio3, u16 pll_prediv,
 	u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
 {
-	u8 b[10];
+	u8 *b;
+	int rv;
+
+	b = kmalloc(10, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
 	b[0] = REQUEST_SET_CLOCK;
 	b[1] = (en_pll << 7) | (pll_src << 6) | (pll_range << 5) | (clock_gpio3 << 4);
 	b[2] = (pll_prediv >> 8)  & 0xff; // MSB
@@ -165,7 +196,9 @@ static int dib0700_set_clock(struct dvb_
 	b[8] = (dsuScaler >> 8)   & 0xff; // MSB
 	b[9] =  dsuScaler         & 0xff; // LSB
 
-	return dib0700_ctrl_wr(d, b, 10);
+	rv = dib0700_ctrl_wr(d, b, 10);
+	kfree(b);
+	return rv;
 }
 
 int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3)
@@ -179,30 +212,40 @@ int dib0700_ctrl_clock(struct dvb_usb_de
 
 static int dib0700_jumpram(struct usb_device *udev, u32 address)
 {
-	int ret, actlen;
-	u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
-		(address >> 24) & 0xff,
-		(address >> 16) & 0xff,
-		(address >> 8)  & 0xff,
-		 address        & 0xff };
+	int ret = 0, actlen;
+	u8 *buf;
+
+	buf = kzalloc(8, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	buf[0] = REQUEST_JUMPRAM;
+	*(u32 *)(buf + 4) = cpu_to_be32(address);
 
 	if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
 		deb_fw("jumpram to 0x%x failed\n",address);
-		return ret;
+		goto out;
 	}
 	if (actlen != 8) {
 		deb_fw("jumpram to 0x%x failed\n",address);
-		return -EIO;
+		ret = -EIO;
+		goto out;
 	}
-	return 0;
+
+out:
+	kfree(buf);
+	return ret;
 }
 
 int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
 {
 	struct hexline hx;
 	int pos = 0, ret, act_len;
+	u8 *buf;
 
-	u8 buf[260];
+	buf = kmalloc(260, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
 
 	while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
 		deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
@@ -222,6 +265,7 @@ int dib0700_download_firmware(struct usb
 			1000);
 
 		if (ret < 0) {
+			kfree(buf);
 			err("firmware download failed at %d with %d",pos,ret);
 			return ret;
 		}
@@ -236,14 +280,19 @@ int dib0700_download_firmware(struct usb
 	} else
 		ret = -EIO;
 
+	kfree(buf);
 	return ret;
 }
 
 int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
 {
 	struct dib0700_state *st = adap->dev->priv;
-	u8 b[4];
+	u8 *b;
+	int rv;
 
+	b = kmalloc(4, GFP_KERNEL);
+	if (!b)
+		return -ENOMEM;
 	b[0] = REQUEST_ENABLE_VIDEO;
 	b[1] = (onoff << 4) | 0x00; /* this bit gives a kind of command, rather than enabling something or not */
 	b[2] = (0x01 << 4); /* Master mode */
@@ -260,18 +309,29 @@ int dib0700_streaming_ctrl(struct dvb_us
 
 	deb_info("data for streaming: %x %x\n",b[1],b[2]);
 
-	return dib0700_ctrl_wr(adap->dev, b, 4);
+	rv = dib0700_ctrl_wr(adap->dev, b, 4);
+	kfree(b);
+	return rv;
 }
 
 int dib0700_rc_setup(struct dvb_usb_device *d)
 {
-	u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
-	int i = dib0700_ctrl_wr(d, rc_setup, 3);
-	if (i<0) {
-		err("ir protocol setup failed");
+	u8 *rc_setup;
+	int i;
+
+	rc_setup = kmalloc(3, GFP_KERNEL);
+	if (!rc_setup)
 		return -1;
-	}
-	return 0;
+	rc_setup[0] = REQUEST_SET_RC;
+	rc_setup[1] = dvb_usb_dib0700_ir_proto;
+	rc_setup[2] = 0;
+
+	i = dib0700_ctrl_wr(d, rc_setup, 3);
+	kfree(rc_setup);
+	if (i<0)
+		err("ir protocol setup failed");
+
+	return i >= 0 ? 0 : -1;
 }
 
 static int dib0700_probe(struct usb_interface *intf,



More information about the linux-dvb mailing list