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.c149
1 files changed, 79 insertions, 70 deletions
diff --git a/sound/core/info.c b/sound/core/info.c
index 9c288539e99d..86366839c4bb 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -21,7 +21,6 @@
21 21
22#include <sound/driver.h> 22#include <sound/driver.h>
23#include <linux/init.h> 23#include <linux/init.h>
24#include <linux/vmalloc.h>
25#include <linux/time.h> 24#include <linux/time.h>
26#include <linux/smp_lock.h> 25#include <linux/smp_lock.h>
27#include <linux/string.h> 26#include <linux/string.h>
@@ -82,6 +81,24 @@ static int snd_info_version_init(void);
82static int snd_info_version_done(void); 81static int snd_info_version_done(void);
83 82
84 83
84/* resize the proc r/w buffer */
85static int resize_info_buffer(struct snd_info_buffer *buffer,
86 unsigned int nsize)
87{
88 char *nbuf;
89
90 nsize = PAGE_ALIGN(nsize);
91 nbuf = kmalloc(nsize, GFP_KERNEL);
92 if (! nbuf)
93 return -ENOMEM;
94
95 memcpy(nbuf, buffer->buffer, buffer->len);
96 kfree(buffer->buffer);
97 buffer->buffer = nbuf;
98 buffer->len = nsize;
99 return 0;
100}
101
85/** 102/**
86 * snd_iprintf - printf on the procfs buffer 103 * snd_iprintf - printf on the procfs buffer
87 * @buffer: the procfs buffer 104 * @buffer: the procfs buffer
@@ -95,17 +112,25 @@ int snd_iprintf(struct snd_info_buffer *buffer, char *fmt,...)
95{ 112{
96 va_list args; 113 va_list args;
97 int len, res; 114 int len, res;
115 int err = 0;
98 116
99 if (buffer->stop || buffer->error) 117 if (buffer->stop || buffer->error)
100 return 0; 118 return 0;
101 len = buffer->len - buffer->size; 119 len = buffer->len - buffer->size;
102 va_start(args, fmt); 120 va_start(args, fmt);
103 res = vsnprintf(buffer->curr, len, fmt, args); 121 for (;;) {
104 va_end(args); 122 res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, args);
105 if (res >= len) { 123 if (res < len)
106 buffer->stop = 1; 124 break;
107 return 0; 125 err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
126 if (err < 0)
127 break;
128 len = buffer->len - buffer->size;
108 } 129 }
130 va_end(args);
131
132 if (err < 0)
133 return err;
109 buffer->curr += res; 134 buffer->curr += res;
110 buffer->size += res; 135 buffer->size += res;
111 return res; 136 return res;
@@ -225,7 +250,7 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
225 struct snd_info_private_data *data; 250 struct snd_info_private_data *data;
226 struct snd_info_entry *entry; 251 struct snd_info_entry *entry;
227 struct snd_info_buffer *buf; 252 struct snd_info_buffer *buf;
228 size_t size = 0; 253 ssize_t size = 0;
229 loff_t pos; 254 loff_t pos;
230 255
231 data = file->private_data; 256 data = file->private_data;
@@ -241,14 +266,20 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer
241 buf = data->wbuffer; 266 buf = data->wbuffer;
242 if (buf == NULL) 267 if (buf == NULL)
243 return -EIO; 268 return -EIO;
244 if (pos >= buf->len) 269 mutex_unlock(&entry->access);
245 return -ENOMEM; 270 if (pos + count >= buf->len) {
246 size = buf->len - pos; 271 if (resize_info_buffer(buf, pos + count)) {
247 size = min(count, size); 272 mutex_unlock(&entry->access);
248 if (copy_from_user(buf->buffer + pos, buffer, size)) 273 return -ENOMEM;
274 }
275 }
276 if (copy_from_user(buf->buffer + pos, buffer, count)) {
277 mutex_unlock(&entry->access);
249 return -EFAULT; 278 return -EFAULT;
250 if ((long)buf->size < pos + size) 279 }
251 buf->size = pos + size; 280 buf->size = pos + count;
281 mutex_unlock(&entry->access);
282 size = count;
252 break; 283 break;
253 case SNDRV_INFO_CONTENT_DATA: 284 case SNDRV_INFO_CONTENT_DATA:
254 if (entry->c.ops->write) 285 if (entry->c.ops->write)
@@ -283,18 +314,14 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
283 } 314 }
284 mode = file->f_flags & O_ACCMODE; 315 mode = file->f_flags & O_ACCMODE;
285 if (mode == O_RDONLY || mode == O_RDWR) { 316 if (mode == O_RDONLY || mode == O_RDWR) {
286 if ((entry->content == SNDRV_INFO_CONTENT_TEXT && 317 if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
287 !entry->c.text.read_size) ||
288 (entry->content == SNDRV_INFO_CONTENT_DATA &&
289 entry->c.ops->read == NULL)) { 318 entry->c.ops->read == NULL)) {
290 err = -ENODEV; 319 err = -ENODEV;
291 goto __error; 320 goto __error;
292 } 321 }
293 } 322 }
294 if (mode == O_WRONLY || mode == O_RDWR) { 323 if (mode == O_WRONLY || mode == O_RDWR) {
295 if ((entry->content == SNDRV_INFO_CONTENT_TEXT && 324 if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
296 !entry->c.text.write_size) ||
297 (entry->content == SNDRV_INFO_CONTENT_DATA &&
298 entry->c.ops->write == NULL)) { 325 entry->c.ops->write == NULL)) {
299 err = -ENODEV; 326 err = -ENODEV;
300 goto __error; 327 goto __error;
@@ -310,49 +337,23 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
310 case SNDRV_INFO_CONTENT_TEXT: 337 case SNDRV_INFO_CONTENT_TEXT:
311 if (mode == O_RDONLY || mode == O_RDWR) { 338 if (mode == O_RDONLY || mode == O_RDWR) {
312 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 339 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
313 if (buffer == NULL) { 340 if (buffer == NULL)
314 kfree(data); 341 goto __nomem;
315 err = -ENOMEM;
316 goto __error;
317 }
318 buffer->len = (entry->c.text.read_size +
319 (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
320 buffer->buffer = vmalloc(buffer->len);
321 if (buffer->buffer == NULL) {
322 kfree(buffer);
323 kfree(data);
324 err = -ENOMEM;
325 goto __error;
326 }
327 buffer->curr = buffer->buffer;
328 data->rbuffer = buffer; 342 data->rbuffer = buffer;
343 buffer->len = PAGE_SIZE;
344 buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
345 if (buffer->buffer == NULL)
346 goto __nomem;
329 } 347 }
330 if (mode == O_WRONLY || mode == O_RDWR) { 348 if (mode == O_WRONLY || mode == O_RDWR) {
331 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL); 349 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
332 if (buffer == NULL) { 350 if (buffer == NULL)
333 if (mode == O_RDWR) { 351 goto __nomem;
334 vfree(data->rbuffer->buffer);
335 kfree(data->rbuffer);
336 }
337 kfree(data);
338 err = -ENOMEM;
339 goto __error;
340 }
341 buffer->len = (entry->c.text.write_size +
342 (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
343 buffer->buffer = vmalloc(buffer->len);
344 if (buffer->buffer == NULL) {
345 if (mode == O_RDWR) {
346 vfree(data->rbuffer->buffer);
347 kfree(data->rbuffer);
348 }
349 kfree(buffer);
350 kfree(data);
351 err = -ENOMEM;
352 goto __error;
353 }
354 buffer->curr = buffer->buffer;
355 data->wbuffer = buffer; 352 data->wbuffer = buffer;
353 buffer->len = PAGE_SIZE;
354 buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
355 if (buffer->buffer == NULL)
356 goto __nomem;
356 } 357 }
357 break; 358 break;
358 case SNDRV_INFO_CONTENT_DATA: /* data */ 359 case SNDRV_INFO_CONTENT_DATA: /* data */
@@ -377,6 +378,17 @@ static int snd_info_entry_open(struct inode *inode, struct file *file)
377 } 378 }
378 return 0; 379 return 0;
379 380
381 __nomem:
382 if (data->rbuffer) {
383 kfree(data->rbuffer->buffer);
384 kfree(data->rbuffer);
385 }
386 if (data->wbuffer) {
387 kfree(data->wbuffer->buffer);
388 kfree(data->wbuffer);
389 }
390 kfree(data);
391 err = -ENOMEM;
380 __error: 392 __error:
381 module_put(entry->module); 393 module_put(entry->module);
382 __error1: 394 __error1:
@@ -395,11 +407,11 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
395 entry = data->entry; 407 entry = data->entry;
396 switch (entry->content) { 408 switch (entry->content) {
397 case SNDRV_INFO_CONTENT_TEXT: 409 case SNDRV_INFO_CONTENT_TEXT:
398 if (mode == O_RDONLY || mode == O_RDWR) { 410 if (data->rbuffer) {
399 vfree(data->rbuffer->buffer); 411 kfree(data->rbuffer->buffer);
400 kfree(data->rbuffer); 412 kfree(data->rbuffer);
401 } 413 }
402 if (mode == O_WRONLY || mode == O_RDWR) { 414 if (data->wbuffer) {
403 if (entry->c.text.write) { 415 if (entry->c.text.write) {
404 entry->c.text.write(entry, data->wbuffer); 416 entry->c.text.write(entry, data->wbuffer);
405 if (data->wbuffer->error) { 417 if (data->wbuffer->error) {
@@ -408,7 +420,7 @@ static int snd_info_entry_release(struct inode *inode, struct file *file)
408 data->wbuffer->error); 420 data->wbuffer->error);
409 } 421 }
410 } 422 }
411 vfree(data->wbuffer->buffer); 423 kfree(data->wbuffer->buffer);
412 kfree(data->wbuffer); 424 kfree(data->wbuffer);
413 } 425 }
414 break; 426 break;
@@ -668,24 +680,22 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
668 if (len <= 0 || buffer->stop || buffer->error) 680 if (len <= 0 || buffer->stop || buffer->error)
669 return 1; 681 return 1;
670 while (--len > 0) { 682 while (--len > 0) {
671 c = *buffer->curr++; 683 c = buffer->buffer[buffer->curr++];
672 if (c == '\n') { 684 if (c == '\n') {
673 if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { 685 if (buffer->curr >= buffer->size)
674 buffer->stop = 1; 686 buffer->stop = 1;
675 }
676 break; 687 break;
677 } 688 }
678 *line++ = c; 689 *line++ = c;
679 if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { 690 if (buffer->curr >= buffer->size) {
680 buffer->stop = 1; 691 buffer->stop = 1;
681 break; 692 break;
682 } 693 }
683 } 694 }
684 while (c != '\n' && !buffer->stop) { 695 while (c != '\n' && !buffer->stop) {
685 c = *buffer->curr++; 696 c = buffer->buffer[buffer->curr++];
686 if ((buffer->curr - buffer->buffer) >= (long)buffer->size) { 697 if (buffer->curr >= buffer->size)
687 buffer->stop = 1; 698 buffer->stop = 1;
688 }
689 } 699 }
690 *line = '\0'; 700 *line = '\0';
691 return 0; 701 return 0;
@@ -978,7 +988,6 @@ static int __init snd_info_version_init(void)
978 entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); 988 entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
979 if (entry == NULL) 989 if (entry == NULL)
980 return -ENOMEM; 990 return -ENOMEM;
981 entry->c.text.read_size = 256;
982 entry->c.text.read = snd_info_version_read; 991 entry->c.text.read = snd_info_version_read;
983 if (snd_info_register(entry) < 0) { 992 if (snd_info_register(entry) < 0) {
984 snd_info_free_entry(entry); 993 snd_info_free_entry(entry);