Commit c8bbc471 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman Committed by Khalid Elmously

ALSA: line6: use dynamic buffers

BugLink: https://bugs.launchpad.net/bugs/1830176

commit e5c812e8 upstream.

The line6 driver uses a lot of USB buffers off of the stack, which is
not allowed on many systems, causing the driver to crash on some of
them.  Fix this up by dynamically allocating the buffers with kmalloc()
which allows for proper DMA-able memory.
Reported-by: default avatarChristo Gouws <gouws.christo@gmail.com>
Reported-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Tested-by: default avatarChristo Gouws <gouws.christo@gmail.com>
Cc: stable <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarJuerg Haefliger <juergh@canonical.com>
Signed-off-by: default avatarKleber Sacilotto de Souza <kleber.souza@canonical.com>
parent 7a7bb33d
......@@ -307,12 +307,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(sizeof(*len), GFP_KERNEL);
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,
......@@ -321,7 +325,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 exit;
}
/* Wait for data length. We'll get 0xff until length arrives. */
......@@ -331,28 +335,29 @@ 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 exit;
}
if (len != 0xff)
if (*len != 0xff)
break;
}
if (len == 0xff) {
ret = -EIO;
if (*len == 0xff) {
dev_err(line6->ifcdev, "read failed after %d retries\n",
count);
return -EIO;
} else if (len != datalen) {
goto exit;
} 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);
goto exit;
}
/* receive the result: */
......@@ -361,12 +366,12 @@ 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;
}
return 0;
exit:
kfree(len);
return ret;
}
EXPORT_SYMBOL_GPL(line6_read_data);
......@@ -378,12 +383,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(sizeof(*status), GFP_KERNEL);
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,
......@@ -392,7 +401,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 exit;
}
for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) {
......@@ -403,28 +412,29 @@ 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 exit;
}
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;
}
return 0;
exit:
kfree(status);
return ret;
}
EXPORT_SYMBOL_GPL(line6_write_data);
......
......@@ -365,15 +365,20 @@ 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;
int *ticks;
struct usb_line6 *line6 = &toneport->line6;
struct usb_device *usbdev = line6->usbdev;
ticks = kmalloc(sizeof(*ticks), GFP_KERNEL);
if (!ticks)
return -ENOMEM;
/* sync time on device with host: */
ticks = (int)get_seconds();
line6_write_data(line6, 0x80c6, &ticks, 4);
*ticks = (int)get_seconds();
line6_write_data(line6, 0x80c6, ticks, 4);
kfree(ticks);
/* enable device: */
toneport_send_cmd(usbdev, 0x0301, 0x0000);
......@@ -388,6 +393,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
toneport_update_led(toneport);
mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
return 0;
}
/*
......@@ -451,7 +457,9 @@ static int toneport_init(struct usb_line6 *line6,
return err;
}
toneport_setup(toneport);
err = toneport_setup(toneport);
if (err)
return err;
/* register audio system: */
return snd_card_register(line6->card);
......@@ -463,7 +471,11 @@ static int toneport_init(struct usb_line6 *line6,
*/
static int toneport_reset_resume(struct usb_interface *interface)
{
toneport_setup(usb_get_intfdata(interface));
int err;
err = toneport_setup(usb_get_intfdata(interface));
if (err)
return err;
return line6_resume(interface);
}
#endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment