]>
Commit | Line | Data |
---|---|---|
5132e7f8 GKH |
1 | From e5c812e84f0dece3400d5caf42522287e6ef139f Mon Sep 17 00:00:00 2001 |
2 | From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
3 | Date: Sun, 28 Apr 2019 18:04:11 +0200 | |
4 | Subject: ALSA: line6: use dynamic buffers | |
5 | ||
6 | From: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
7 | ||
8 | commit e5c812e84f0dece3400d5caf42522287e6ef139f upstream. | |
9 | ||
10 | The line6 driver uses a lot of USB buffers off of the stack, which is | |
11 | not allowed on many systems, causing the driver to crash on some of | |
12 | them. Fix this up by dynamically allocating the buffers with kmalloc() | |
13 | which allows for proper DMA-able memory. | |
14 | ||
15 | Reported-by: Christo Gouws <gouws.christo@gmail.com> | |
16 | Reported-by: Alan Stern <stern@rowland.harvard.edu> | |
17 | Tested-by: Christo Gouws <gouws.christo@gmail.com> | |
18 | Cc: stable <stable@vger.kernel.org> | |
19 | Signed-off-by: Takashi Iwai <tiwai@suse.de> | |
20 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
21 | ||
22 | --- | |
23 | sound/usb/line6/driver.c | 60 ++++++++++++++++++++++++++------------------- | |
24 | sound/usb/line6/toneport.c | 24 +++++++++++++----- | |
25 | 2 files changed, 53 insertions(+), 31 deletions(-) | |
26 | ||
27 | --- a/sound/usb/line6/driver.c | |
28 | +++ b/sound/usb/line6/driver.c | |
29 | @@ -307,12 +307,16 @@ int line6_read_data(struct usb_line6 *li | |
30 | { | |
31 | struct usb_device *usbdev = line6->usbdev; | |
32 | int ret; | |
33 | - unsigned char len; | |
34 | + unsigned char *len; | |
35 | unsigned count; | |
36 | ||
37 | if (address > 0xffff || datalen > 0xff) | |
38 | return -EINVAL; | |
39 | ||
40 | + len = kmalloc(sizeof(*len), GFP_KERNEL); | |
41 | + if (!len) | |
42 | + return -ENOMEM; | |
43 | + | |
44 | /* query the serial number: */ | |
45 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | |
46 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | |
47 | @@ -321,7 +325,7 @@ int line6_read_data(struct usb_line6 *li | |
48 | ||
49 | if (ret < 0) { | |
50 | dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); | |
51 | - return ret; | |
52 | + goto exit; | |
53 | } | |
54 | ||
55 | /* Wait for data length. We'll get 0xff until length arrives. */ | |
56 | @@ -331,28 +335,29 @@ int line6_read_data(struct usb_line6 *li | |
57 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | |
58 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | |
59 | USB_DIR_IN, | |
60 | - 0x0012, 0x0000, &len, 1, | |
61 | + 0x0012, 0x0000, len, 1, | |
62 | LINE6_TIMEOUT * HZ); | |
63 | if (ret < 0) { | |
64 | dev_err(line6->ifcdev, | |
65 | "receive length failed (error %d)\n", ret); | |
66 | - return ret; | |
67 | + goto exit; | |
68 | } | |
69 | ||
70 | - if (len != 0xff) | |
71 | + if (*len != 0xff) | |
72 | break; | |
73 | } | |
74 | ||
75 | - if (len == 0xff) { | |
76 | + ret = -EIO; | |
77 | + if (*len == 0xff) { | |
78 | dev_err(line6->ifcdev, "read failed after %d retries\n", | |
79 | count); | |
80 | - return -EIO; | |
81 | - } else if (len != datalen) { | |
82 | + goto exit; | |
83 | + } else if (*len != datalen) { | |
84 | /* should be equal or something went wrong */ | |
85 | dev_err(line6->ifcdev, | |
86 | "length mismatch (expected %d, got %d)\n", | |
87 | - (int)datalen, (int)len); | |
88 | - return -EIO; | |
89 | + (int)datalen, (int)*len); | |
90 | + goto exit; | |
91 | } | |
92 | ||
93 | /* receive the result: */ | |
94 | @@ -361,12 +366,12 @@ int line6_read_data(struct usb_line6 *li | |
95 | 0x0013, 0x0000, data, datalen, | |
96 | LINE6_TIMEOUT * HZ); | |
97 | ||
98 | - if (ret < 0) { | |
99 | + if (ret < 0) | |
100 | dev_err(line6->ifcdev, "read failed (error %d)\n", ret); | |
101 | - return ret; | |
102 | - } | |
103 | ||
104 | - return 0; | |
105 | +exit: | |
106 | + kfree(len); | |
107 | + return ret; | |
108 | } | |
109 | EXPORT_SYMBOL_GPL(line6_read_data); | |
110 | ||
111 | @@ -378,12 +383,16 @@ int line6_write_data(struct usb_line6 *l | |
112 | { | |
113 | struct usb_device *usbdev = line6->usbdev; | |
114 | int ret; | |
115 | - unsigned char status; | |
116 | + unsigned char *status; | |
117 | int count; | |
118 | ||
119 | if (address > 0xffff || datalen > 0xffff) | |
120 | return -EINVAL; | |
121 | ||
122 | + status = kmalloc(sizeof(*status), GFP_KERNEL); | |
123 | + if (!status) | |
124 | + return -ENOMEM; | |
125 | + | |
126 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | |
127 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | |
128 | 0x0022, address, data, datalen, | |
129 | @@ -392,7 +401,7 @@ int line6_write_data(struct usb_line6 *l | |
130 | if (ret < 0) { | |
131 | dev_err(line6->ifcdev, | |
132 | "write request failed (error %d)\n", ret); | |
133 | - return ret; | |
134 | + goto exit; | |
135 | } | |
136 | ||
137 | for (count = 0; count < LINE6_READ_WRITE_MAX_RETRIES; count++) { | |
138 | @@ -403,28 +412,29 @@ int line6_write_data(struct usb_line6 *l | |
139 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | |
140 | USB_DIR_IN, | |
141 | 0x0012, 0x0000, | |
142 | - &status, 1, LINE6_TIMEOUT * HZ); | |
143 | + status, 1, LINE6_TIMEOUT * HZ); | |
144 | ||
145 | if (ret < 0) { | |
146 | dev_err(line6->ifcdev, | |
147 | "receiving status failed (error %d)\n", ret); | |
148 | - return ret; | |
149 | + goto exit; | |
150 | } | |
151 | ||
152 | - if (status != 0xff) | |
153 | + if (*status != 0xff) | |
154 | break; | |
155 | } | |
156 | ||
157 | - if (status == 0xff) { | |
158 | + if (*status == 0xff) { | |
159 | dev_err(line6->ifcdev, "write failed after %d retries\n", | |
160 | count); | |
161 | - return -EIO; | |
162 | - } else if (status != 0) { | |
163 | + ret = -EIO; | |
164 | + } else if (*status != 0) { | |
165 | dev_err(line6->ifcdev, "write failed (error %d)\n", ret); | |
166 | - return -EIO; | |
167 | + ret = -EIO; | |
168 | } | |
169 | - | |
170 | - return 0; | |
171 | +exit: | |
172 | + kfree(status); | |
173 | + return ret; | |
174 | } | |
175 | EXPORT_SYMBOL_GPL(line6_write_data); | |
176 | ||
177 | --- a/sound/usb/line6/toneport.c | |
178 | +++ b/sound/usb/line6/toneport.c | |
179 | @@ -365,15 +365,20 @@ static bool toneport_has_source_select(s | |
180 | /* | |
181 | Setup Toneport device. | |
182 | */ | |
183 | -static void toneport_setup(struct usb_line6_toneport *toneport) | |
184 | +static int toneport_setup(struct usb_line6_toneport *toneport) | |
185 | { | |
186 | - int ticks; | |
187 | + int *ticks; | |
188 | struct usb_line6 *line6 = &toneport->line6; | |
189 | struct usb_device *usbdev = line6->usbdev; | |
190 | ||
191 | + ticks = kmalloc(sizeof(*ticks), GFP_KERNEL); | |
192 | + if (!ticks) | |
193 | + return -ENOMEM; | |
194 | + | |
195 | /* sync time on device with host: */ | |
196 | - ticks = (int)get_seconds(); | |
197 | - line6_write_data(line6, 0x80c6, &ticks, 4); | |
198 | + *ticks = (int)get_seconds(); | |
199 | + line6_write_data(line6, 0x80c6, ticks, 4); | |
200 | + kfree(ticks); | |
201 | ||
202 | /* enable device: */ | |
203 | toneport_send_cmd(usbdev, 0x0301, 0x0000); | |
204 | @@ -388,6 +393,7 @@ static void toneport_setup(struct usb_li | |
205 | toneport_update_led(toneport); | |
206 | ||
207 | mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); | |
208 | + return 0; | |
209 | } | |
210 | ||
211 | /* | |
212 | @@ -451,7 +457,9 @@ static int toneport_init(struct usb_line | |
213 | return err; | |
214 | } | |
215 | ||
216 | - toneport_setup(toneport); | |
217 | + err = toneport_setup(toneport); | |
218 | + if (err) | |
219 | + return err; | |
220 | ||
221 | /* register audio system: */ | |
222 | return snd_card_register(line6->card); | |
223 | @@ -463,7 +471,11 @@ static int toneport_init(struct usb_line | |
224 | */ | |
225 | static int toneport_reset_resume(struct usb_interface *interface) | |
226 | { | |
227 | - toneport_setup(usb_get_intfdata(interface)); | |
228 | + int err; | |
229 | + | |
230 | + err = toneport_setup(usb_get_intfdata(interface)); | |
231 | + if (err) | |
232 | + return err; | |
233 | return line6_resume(interface); | |
234 | } | |
235 | #endif |