aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/info.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/info.c')
-rw-r--r--sound/core/info.c75
1 files changed, 44 insertions, 31 deletions
diff --git a/sound/core/info.c b/sound/core/info.c
index d749a0d394a7..b70564ed8b37 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -22,6 +22,7 @@
22#include <linux/init.h> 22#include <linux/init.h>
23#include <linux/time.h> 23#include <linux/time.h>
24#include <linux/mm.h> 24#include <linux/mm.h>
25#include <linux/slab.h>
25#include <linux/smp_lock.h> 26#include <linux/smp_lock.h>
26#include <linux/string.h> 27#include <linux/string.h>
27#include <sound/core.h> 28#include <sound/core.h>
@@ -163,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
163{ 164{
164 struct snd_info_private_data *data; 165 struct snd_info_private_data *data;
165 struct snd_info_entry *entry; 166 struct snd_info_entry *entry;
166 loff_t ret; 167 loff_t ret = -EINVAL, size;
167 168
168 data = file->private_data; 169 data = file->private_data;
169 entry = data->entry; 170 entry = data->entry;
170 lock_kernel(); 171 mutex_lock(&entry->access);
171 switch (entry->content) { 172 if (entry->content == SNDRV_INFO_CONTENT_DATA &&
172 case SNDRV_INFO_CONTENT_TEXT: 173 entry->c.ops->llseek) {
173 switch (orig) { 174 offset = entry->c.ops->llseek(entry,
174 case SEEK_SET: 175 data->file_private_data,
175 file->f_pos = offset; 176 file, offset, orig);
176 ret = file->f_pos; 177 goto out;
177 goto out; 178 }
178 case SEEK_CUR: 179 if (entry->content == SNDRV_INFO_CONTENT_DATA)
179 file->f_pos += offset; 180 size = entry->size;
180 ret = file->f_pos; 181 else
181 goto out; 182 size = 0;
182 case SEEK_END: 183 switch (orig) {
183 default: 184 case SEEK_SET:
184 ret = -EINVAL;
185 goto out;
186 }
187 break; 185 break;
188 case SNDRV_INFO_CONTENT_DATA: 186 case SEEK_CUR:
189 if (entry->c.ops->llseek) { 187 offset += file->f_pos;
190 ret = entry->c.ops->llseek(entry, 188 break;
191 data->file_private_data, 189 case SEEK_END:
192 file, offset, orig); 190 if (!size)
193 goto out; 191 goto out;
194 } 192 offset += size;
195 break; 193 break;
196 } 194 default:
197 ret = -ENXIO; 195 goto out;
198out: 196 }
199 unlock_kernel(); 197 if (offset < 0)
198 goto out;
199 if (size && offset > size)
200 offset = size;
201 file->f_pos = offset;
202 ret = offset;
203 out:
204 mutex_unlock(&entry->access);
200 return ret; 205 return ret;
201} 206}
202 207
@@ -231,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
231 return -EFAULT; 236 return -EFAULT;
232 break; 237 break;
233 case SNDRV_INFO_CONTENT_DATA: 238 case SNDRV_INFO_CONTENT_DATA:
234 if (entry->c.ops->read) 239 if (pos >= entry->size)
240 return 0;
241 if (entry->c.ops->read) {
242 size = entry->size - pos;
243 size = min(count, size);
235 size = entry->c.ops->read(entry, 244 size = entry->c.ops->read(entry,
236 data->file_private_data, 245 data->file_private_data,
237 file, buffer, count, pos); 246 file, buffer, size, pos);
247 }
238 break; 248 break;
239 } 249 }
240 if ((ssize_t) size > 0) 250 if ((ssize_t) size > 0)
@@ -281,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
281 size = count; 291 size = count;
282 break; 292 break;
283 case SNDRV_INFO_CONTENT_DATA: 293 case SNDRV_INFO_CONTENT_DATA:
284 if (entry->c.ops->write) 294 if (entry->c.ops->write && count > 0) {
295 size_t maxsize = entry->size - pos;
296 count = min(count, maxsize);
285 size = entry->c.ops->write(entry, 297 size = entry->c.ops->write(entry,
286 data->file_private_data, 298 data->file_private_data,
287 file, buffer, count, pos); 299 file, buffer, count, pos);
300 }
288 break; 301 break;
289 } 302 }
290 if ((ssize_t) size > 0) 303 if ((ssize_t) size > 0)