[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#852749: linux-image-4.9.0-1-amd64: usb-audio-device not working since kernel 4.9.0.1



Control: tag -1 patch moreinfo

Please test whether the attached patches fix this.  You can find
instructions for rebuilding the kernel package at:
https://kernel-handbook.alioth.debian.org/ch-common-tasks.html#s-common-official

Ben.

-- 
Ben Hutchings
Design a system any fool can use, and only a fool will want to use it.
From: Ben Hutchings <ben@decadent.org.uk>
Date: Fri, 27 Jan 2017 00:28:33 +0000
Subject: [1/2] ALSA: line6: toneport: Add error checks to toneport_setup()
 etc.
Origin: https://git.kernel.org/linus/fc5e7a3683e1a0ce039c7ed8440ae49d60e6dfd6
Bug-Debian: https://bugs.debian.org/852749

toneport_setup() currently ignores all errors and returns void.  Make
it and toneport_update_led() report errors, and make toneport_init()
check for this.

Fixes: 705ececd1c60 ("Staging: add line6 usb driver")
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
 sound/usb/line6/toneport.c | 43 +++++++++++++++++++++++++++++--------------
 1 file changed, 29 insertions(+), 14 deletions(-)

diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index 8e22f430d700..646c27a79f68 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -294,11 +294,11 @@ static bool toneport_has_led(struct usb_line6_toneport *toneport)
 static const char * const led_colors[2] = { "red", "green" };
 static const int led_init_vals[2] = { 0x00, 0x26 };
 
-static void toneport_update_led(struct usb_line6_toneport *toneport)
+static int toneport_update_led(struct usb_line6_toneport *toneport)
 {
-	toneport_send_cmd(toneport->line6.usbdev,
-			  (toneport->leds[0].dev.brightness << 8) | 0x0002,
-			  toneport->leds[1].dev.brightness);
+	return toneport_send_cmd(toneport->line6.usbdev,
+				 (toneport->leds[0].dev.brightness << 8) | 0x0002,
+				 toneport->leds[1].dev.brightness);
 }
 
 static void toneport_led_brightness_set(struct led_classdev *led_cdev,
@@ -365,29 +365,42 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
 /*
 	Setup Toneport device.
 */
-static void toneport_setup(struct usb_line6_toneport *toneport)
+static int toneport_setup(struct usb_line6_toneport *toneport)
 {
 	int ticks;
 	struct usb_line6 *line6 = &toneport->line6;
 	struct usb_device *usbdev = line6->usbdev;
+	int err;
 
 	/* sync time on device with host: */
 	ticks = (int)get_seconds();
-	line6_write_data(line6, 0x80c6, &ticks, 4);
+	err = line6_write_data(line6, 0x80c6, &ticks, 4);
+	if (err < 0)
+		return err;
 
 	/* enable device: */
-	toneport_send_cmd(usbdev, 0x0301, 0x0000);
+	err = toneport_send_cmd(usbdev, 0x0301, 0x0000);
+	if (err < 0)
+		return err;
 
 	/* initialize source select: */
-	if (toneport_has_source_select(toneport))
-		toneport_send_cmd(usbdev,
-				  toneport_source_info[toneport->source].code,
-				  0x0000);
+	if (toneport_has_source_select(toneport)) {
+		err = toneport_send_cmd(usbdev,
+					toneport_source_info[toneport->source].code,
+					0x0000);
+		if (err < 0)
+			return err;
+	}
 
-	if (toneport_has_led(toneport))
-		toneport_update_led(toneport);
+	if (toneport_has_led(toneport)) {
+		err = toneport_update_led(toneport);
+		if (err < 0)
+			return err;
+	}
 
 	mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
+
+	return 0;
 }
 
 /*
@@ -451,7 +464,9 @@ static int toneport_init(struct usb_line6 *line6,
 			return err;
 	}
 
-	toneport_setup(toneport);
+	err = toneport_setup(toneport);
+	if (err < 0)
+		return err;
 
 	/* register audio system: */
 	return snd_card_register(line6->card);
From: Ben Hutchings <ben@decadent.org.uk>
Date: Fri, 27 Jan 2017 00:40:49 +0000
Subject: [2/2] ALSA: line6: Move USB message buffers off-stack
Origin: https://git.kernel.org/linus/13d338f1016e8898c98faa9c790d7056ef934307
Bug-Debian: https://bugs.debian.org/852749

Allocating USB buffers on the stack is not portable, and no longer
works on x86_64 (with VMAP_STACK enabled as per default).

Fixes: 705ececd1c60 ("Staging: add line6 usb driver")
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
 sound/usb/line6/driver.c   | 64 +++++++++++++++++++++++++++++-----------------
 sound/usb/line6/podhd.c    | 22 ++++++++++------
 sound/usb/line6/toneport.c | 10 +++++---
 3 files changed, 61 insertions(+), 35 deletions(-)

diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index 90009c0b3a92..b3a7f0c809da 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -337,12 +337,16 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
 {
 	struct usb_device *usbdev = line6->usbdev;
 	int ret;
-	unsigned char len;
+	unsigned char *len;
 	unsigned count;
 
 	if (address > 0xffff || datalen > 0xff)
 		return -EINVAL;
 
+	len = kmalloc(1, GFP_ATOMIC);
+	if (!len)
+		return -ENOMEM;
+
 	/* query the serial number: */
 	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
 			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
@@ -351,7 +355,7 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
 
 	if (ret < 0) {
 		dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
-		return ret;
+		goto out;
 	}
 
 	/* Wait for data length. We'll get 0xff until length arrives. */
@@ -361,28 +365,30 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
 		ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
 				      USB_TYPE_VENDOR | USB_RECIP_DEVICE |
 				      USB_DIR_IN,
-				      0x0012, 0x0000, &len, 1,
+				      0x0012, 0x0000, len, 1,
 				      LINE6_TIMEOUT * HZ);
 		if (ret < 0) {
 			dev_err(line6->ifcdev,
 				"receive length failed (error %d)\n", ret);
-			return ret;
+			goto out;
 		}
 
-		if (len != 0xff)
+		if (*len != 0xff)
 			break;
 	}
 
-	if (len == 0xff) {
+	if (*len == 0xff) {
 		dev_err(line6->ifcdev, "read failed after %d retries\n",
 			count);
-		return -EIO;
-	} else if (len != datalen) {
+		ret = -EIO;
+		goto out;
+	} else if (*len != datalen) {
 		/* should be equal or something went wrong */
 		dev_err(line6->ifcdev,
 			"length mismatch (expected %d, got %d)\n",
-			(int)datalen, (int)len);
-		return -EIO;
+			(int)datalen, (int)*len);
+		ret = -EIO;
+		goto out;
 	}
 
 	/* receive the result: */
@@ -391,12 +397,14 @@ int line6_read_data(struct usb_line6 *line6, unsigned address, void *data,
 			      0x0013, 0x0000, data, datalen,
 			      LINE6_TIMEOUT * HZ);
 
-	if (ret < 0) {
+	if (ret < 0)
 		dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
-		return ret;
-	}
+	else
+		ret = 0;
 
-	return 0;
+out:
+	kfree(len);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(line6_read_data);
 
@@ -408,12 +416,16 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
 {
 	struct usb_device *usbdev = line6->usbdev;
 	int ret;
-	unsigned char status;
+	unsigned char *status;
 	int count;
 
 	if (address > 0xffff || datalen > 0xffff)
 		return -EINVAL;
 
+	status = kmalloc(1, GFP_ATOMIC);
+	if (!status)
+		return -ENOMEM;
+
 	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
 			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
 			      0x0022, address, data, datalen,
@@ -422,7 +434,7 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
 	if (ret < 0) {
 		dev_err(line6->ifcdev,
 			"write request failed (error %d)\n", ret);
-		return ret;
+		goto out;
 	}
 
 	for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) {
@@ -433,28 +445,32 @@ int line6_write_data(struct usb_line6 *line6, unsigned address, void *data,
 				      USB_TYPE_VENDOR | USB_RECIP_DEVICE |
 				      USB_DIR_IN,
 				      0x0012, 0x0000,
-				      &status, 1, LINE6_TIMEOUT * HZ);
+				      status, 1, LINE6_TIMEOUT * HZ);
 
 		if (ret < 0) {
 			dev_err(line6->ifcdev,
 				"receiving status failed (error %d)\n", ret);
-			return ret;
+			goto out;
 		}
 
-		if (status != 0xff)
+		if (*status != 0xff)
 			break;
 	}
 
-	if (status == 0xff) {
+	if (*status == 0xff) {
 		dev_err(line6->ifcdev, "write failed after %d retries\n",
 			count);
-		return -EIO;
-	} else if (status != 0) {
+		ret = -EIO;
+	} else if (*status != 0) {
 		dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
-		return -EIO;
+		ret = -EIO;
+	} else {
+		ret = 0;
 	}
 
-	return 0;
+out:
+	kfree(status);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(line6_write_data);
 
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
index 6ab23e5aee71..b59939fa4d27 100644
--- a/sound/usb/line6/podhd.c
+++ b/sound/usb/line6/podhd.c
@@ -222,28 +222,32 @@ static void podhd_startup_start_workqueue(unsigned long data)
 static int podhd_dev_start(struct usb_line6_podhd *pod)
 {
 	int ret;
-	u8 init_bytes[8];
+	u8 *init_bytes;
 	int i;
 	struct usb_device *usbdev = pod->line6.usbdev;
 
+	init_bytes = kmalloc(8, GFP_ATOMIC);
+	if (!init_bytes)
+		return -ENOMEM;
+
 	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
 					0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
 					0x11, 0,
 					NULL, 0, LINE6_TIMEOUT * HZ);
 	if (ret < 0) {
 		dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
-		return ret;
+		goto out;
 	}
 
 	/* NOTE: looks like some kind of ping message */
 	ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
 					USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 					0x11, 0x0,
-					&init_bytes, 3, LINE6_TIMEOUT * HZ);
+					init_bytes, 3, LINE6_TIMEOUT * HZ);
 	if (ret < 0) {
 		dev_err(pod->line6.ifcdev,
 			"receive length failed (error %d)\n", ret);
-		return ret;
+		goto out;
 	}
 
 	pod->firmware_version =
@@ -252,7 +256,7 @@ static int podhd_dev_start(struct usb_line6_podhd *pod)
 	for (i = 0; i <= 16; i++) {
 		ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
 		if (ret < 0)
-			return ret;
+			goto out;
 	}
 
 	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
@@ -260,10 +264,12 @@ static int podhd_dev_start(struct usb_line6_podhd *pod)
 					USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
 					1, 0,
 					NULL, 0, LINE6_TIMEOUT * HZ);
-	if (ret < 0)
-		return ret;
+	if (ret > 0)
+		ret = 0;
 
-	return 0;
+out:
+	kfree(init_bytes);
+	return ret;
 }
 
 static void podhd_startup_workqueue(struct work_struct *work)
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index 646c27a79f68..62998af0db0b 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -367,14 +367,18 @@ static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
 */
 static int toneport_setup(struct usb_line6_toneport *toneport)
 {
-	int ticks;
+	int *ticks;
 	struct usb_line6 *line6 = &toneport->line6;
 	struct usb_device *usbdev = line6->usbdev;
 	int err;
 
 	/* sync time on device with host: */
-	ticks = (int)get_seconds();
-	err = line6_write_data(line6, 0x80c6, &ticks, 4);
+	ticks = kmalloc(sizeof(*ticks), GFP_ATOMIC);
+	if (!ticks)
+		return -ENOMEM;
+	*ticks = (int)get_seconds();
+	err = line6_write_data(line6, 0x80c6, ticks, 4);
+	kfree(ticks);
 	if (err < 0)
 		return err;
 

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: