aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-04-22 10:10:22 -0400
committerTakashi Iwai <tiwai@suse.de>2015-04-23 11:11:02 -0400
commit4adb7bcbcb69d3bee0ed72de83adaee27daccdd8 (patch)
treea2011f7aae6bbd32371242ac529b245d3b5bf834
parent412b979ccceff448dccea54bdb616c85781bc0ba (diff)
ALSA: core: Use seq_file for text proc file reads
seq_file is _the_ standard interface for simple text proc files. Though, we still need to support the binary proc files and the text file write, and also we need to manage the device disconnection gracefully. Thus this patch just replaces the text file read code with seq_file while keeping the rest intact. snd_iprintf() helper function is now a macro to expand itself to seq_printf() to be compatible with the existing code. The seq_file object is stored to the unused entry->rbuffer->buffer pointer. When the output size is expected to be large (greater than PAGE_SIZE), the driver should set entry->size field beforehand. Then the given size will be preallocated and the multiple show calls can be avoided. Acked-by: Jaroslav Kysela <perex@perex.cz> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--include/sound/info.h16
-rw-r--r--sound/core/info.c569
2 files changed, 261 insertions, 324 deletions
diff --git a/include/sound/info.h b/include/sound/info.h
index 9ca1a493d370..ff8962ebece5 100644
--- a/include/sound/info.h
+++ b/include/sound/info.h
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <linux/poll.h> 25#include <linux/poll.h>
26#include <linux/seq_file.h>
26 27
27/* buffer for information */ 28/* buffer for information */
28struct snd_info_buffer { 29struct snd_info_buffer {
@@ -110,8 +111,18 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer);
110static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {} 111static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {}
111#endif 112#endif
112 113
113__printf(2, 3) 114/**
114int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...); 115 * snd_iprintf - printf on the procfs buffer
116 * @buf: the procfs buffer
117 * @fmt: the printf format
118 *
119 * Outputs the string on the procfs buffer just like printf().
120 *
121 * Return: zero for success, or a negative error code.
122 */
123#define snd_iprintf(buf, fmt, args...) \
124 seq_printf((struct seq_file *)(buf)->buffer, fmt, ##args)
125
115int snd_info_init(void); 126int snd_info_init(void);
116int snd_info_done(void); 127int snd_info_done(void);
117 128
@@ -175,7 +186,6 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name,
175static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)), 186static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)),
176 void *private_data, 187 void *private_data,
177 void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {} 188 void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {}
178
179static inline int snd_info_check_reserved_words(const char *str) { return 1; } 189static inline int snd_info_check_reserved_words(const char *str) { return 1; }
180 190
181#endif 191#endif
diff --git a/sound/core/info.c b/sound/core/info.c
index 9f404e965ea2..8c1275f0fcbd 100644
--- a/sound/core/info.c
+++ b/sound/core/info.c
@@ -81,66 +81,6 @@ static int snd_info_version_init(void);
81static int snd_info_version_done(void); 81static int snd_info_version_done(void);
82static void snd_info_disconnect(struct snd_info_entry *entry); 82static void snd_info_disconnect(struct snd_info_entry *entry);
83 83
84
85/* resize the proc r/w buffer */
86static int resize_info_buffer(struct snd_info_buffer *buffer,
87 unsigned int nsize)
88{
89 char *nbuf;
90
91 nsize = PAGE_ALIGN(nsize);
92 nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL | __GFP_ZERO);
93 if (! nbuf)
94 return -ENOMEM;
95
96 buffer->buffer = nbuf;
97 buffer->len = nsize;
98 return 0;
99}
100
101/**
102 * snd_iprintf - printf on the procfs buffer
103 * @buffer: the procfs buffer
104 * @fmt: the printf format
105 *
106 * Outputs the string on the procfs buffer just like printf().
107 *
108 * Return: The size of output string, or a negative error code.
109 */
110int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
111{
112 va_list args;
113 int len, res;
114 int err = 0;
115
116 might_sleep();
117 if (buffer->stop || buffer->error)
118 return 0;
119 len = buffer->len - buffer->size;
120 va_start(args, fmt);
121 for (;;) {
122 va_list ap;
123 va_copy(ap, args);
124 res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, ap);
125 va_end(ap);
126 if (res < len)
127 break;
128 err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
129 if (err < 0)
130 break;
131 len = buffer->len - buffer->size;
132 }
133 va_end(args);
134
135 if (err < 0)
136 return err;
137 buffer->curr += res;
138 buffer->size += res;
139 return res;
140}
141
142EXPORT_SYMBOL(snd_iprintf);
143
144/* 84/*
145 85
146 */ 86 */
@@ -153,6 +93,37 @@ EXPORT_SYMBOL(snd_seq_root);
153struct snd_info_entry *snd_oss_root; 93struct snd_info_entry *snd_oss_root;
154#endif 94#endif
155 95
96static int alloc_info_private(struct snd_info_entry *entry,
97 struct snd_info_private_data **ret)
98{
99 struct snd_info_private_data *data;
100
101 if (!entry || !entry->p)
102 return -ENODEV;
103 if (!try_module_get(entry->module))
104 return -EFAULT;
105 data = kzalloc(sizeof(*data), GFP_KERNEL);
106 if (!data) {
107 module_put(entry->module);
108 return -ENOMEM;
109 }
110 data->entry = entry;
111 *ret = data;
112 return 0;
113}
114
115static bool valid_pos(loff_t pos, size_t count)
116{
117 if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
118 return false;
119 if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
120 return false;
121 return true;
122}
123
124/*
125 * file ops for binary proc files
126 */
156static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) 127static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
157{ 128{
158 struct snd_info_private_data *data; 129 struct snd_info_private_data *data;
@@ -162,17 +133,14 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
162 data = file->private_data; 133 data = file->private_data;
163 entry = data->entry; 134 entry = data->entry;
164 mutex_lock(&entry->access); 135 mutex_lock(&entry->access);
165 if (entry->content == SNDRV_INFO_CONTENT_DATA && 136 if (entry->c.ops->llseek) {
166 entry->c.ops->llseek) {
167 offset = entry->c.ops->llseek(entry, 137 offset = entry->c.ops->llseek(entry,
168 data->file_private_data, 138 data->file_private_data,
169 file, offset, orig); 139 file, offset, orig);
170 goto out; 140 goto out;
171 } 141 }
172 if (entry->content == SNDRV_INFO_CONTENT_DATA) 142
173 size = entry->size; 143 size = entry->size;
174 else
175 size = 0;
176 switch (orig) { 144 switch (orig) {
177 case SEEK_SET: 145 case SEEK_SET:
178 break; 146 break;
@@ -201,45 +169,20 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
201static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, 169static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
202 size_t count, loff_t * offset) 170 size_t count, loff_t * offset)
203{ 171{
204 struct snd_info_private_data *data; 172 struct snd_info_private_data *data = file->private_data;
205 struct snd_info_entry *entry; 173 struct snd_info_entry *entry = data->entry;
206 struct snd_info_buffer *buf; 174 size_t size;
207 size_t size = 0;
208 loff_t pos; 175 loff_t pos;
209 176
210 data = file->private_data;
211 if (snd_BUG_ON(!data))
212 return -ENXIO;
213 pos = *offset; 177 pos = *offset;
214 if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) 178 if (!valid_pos(pos, count))
215 return -EIO;
216 if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
217 return -EIO; 179 return -EIO;
218 entry = data->entry; 180 if (pos >= entry->size)
219 switch (entry->content) { 181 return 0;
220 case SNDRV_INFO_CONTENT_TEXT: 182 size = entry->size - pos;
221 buf = data->rbuffer; 183 size = min(count, size);
222 if (buf == NULL) 184 size = entry->c.ops->read(entry, data->file_private_data,
223 return -EIO; 185 file, buffer, size, pos);
224 if (pos >= buf->size)
225 return 0;
226 size = buf->size - pos;
227 size = min(count, size);
228 if (copy_to_user(buffer, buf->buffer + pos, size))
229 return -EFAULT;
230 break;
231 case SNDRV_INFO_CONTENT_DATA:
232 if (pos >= entry->size)
233 return 0;
234 if (entry->c.ops->read) {
235 size = entry->size - pos;
236 size = min(count, size);
237 size = entry->c.ops->read(entry,
238 data->file_private_data,
239 file, buffer, size, pos);
240 }
241 break;
242 }
243 if ((ssize_t) size > 0) 186 if ((ssize_t) size > 0)
244 *offset = pos + size; 187 *offset = pos + size;
245 return size; 188 return size;
@@ -248,280 +191,259 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
248static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer, 191static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
249 size_t count, loff_t * offset) 192 size_t count, loff_t * offset)
250{ 193{
251 struct snd_info_private_data *data; 194 struct snd_info_private_data *data = file->private_data;
252 struct snd_info_entry *entry; 195 struct snd_info_entry *entry = data->entry;
253 struct snd_info_buffer *buf;
254 ssize_t size = 0; 196 ssize_t size = 0;
255 loff_t pos; 197 loff_t pos;
256 198
257 data = file->private_data;
258 if (snd_BUG_ON(!data))
259 return -ENXIO;
260 entry = data->entry;
261 pos = *offset; 199 pos = *offset;
262 if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) 200 if (!valid_pos(pos, count))
263 return -EIO; 201 return -EIO;
264 if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) 202 if (count > 0) {
265 return -EIO; 203 size_t maxsize = entry->size - pos;
266 switch (entry->content) { 204 count = min(count, maxsize);
267 case SNDRV_INFO_CONTENT_TEXT: 205 size = entry->c.ops->write(entry, data->file_private_data,
268 buf = data->wbuffer; 206 file, buffer, count, pos);
269 if (buf == NULL)
270 return -EIO;
271 mutex_lock(&entry->access);
272 if (pos + count >= buf->len) {
273 if (resize_info_buffer(buf, pos + count)) {
274 mutex_unlock(&entry->access);
275 return -ENOMEM;
276 }
277 }
278 if (copy_from_user(buf->buffer + pos, buffer, count)) {
279 mutex_unlock(&entry->access);
280 return -EFAULT;
281 }
282 buf->size = pos + count;
283 mutex_unlock(&entry->access);
284 size = count;
285 break;
286 case SNDRV_INFO_CONTENT_DATA:
287 if (entry->c.ops->write && count > 0) {
288 size_t maxsize = entry->size - pos;
289 count = min(count, maxsize);
290 size = entry->c.ops->write(entry,
291 data->file_private_data,
292 file, buffer, count, pos);
293 }
294 break;
295 } 207 }
296 if ((ssize_t) size > 0) 208 if (size > 0)
297 *offset = pos + size; 209 *offset = pos + size;
298 return size; 210 return size;
299} 211}
300 212
301static int snd_info_entry_open(struct inode *inode, struct file *file) 213static unsigned int snd_info_entry_poll(struct file *file, poll_table *wait)
214{
215 struct snd_info_private_data *data = file->private_data;
216 struct snd_info_entry *entry = data->entry;
217 unsigned int mask = 0;
218
219 if (entry->c.ops->poll)
220 return entry->c.ops->poll(entry,
221 data->file_private_data,
222 file, wait);
223 if (entry->c.ops->read)
224 mask |= POLLIN | POLLRDNORM;
225 if (entry->c.ops->write)
226 mask |= POLLOUT | POLLWRNORM;
227 return mask;
228}
229
230static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
231 unsigned long arg)
232{
233 struct snd_info_private_data *data = file->private_data;
234 struct snd_info_entry *entry = data->entry;
235
236 if (!entry->c.ops->ioctl)
237 return -ENOTTY;
238 return entry->c.ops->ioctl(entry, data->file_private_data,
239 file, cmd, arg);
240}
241
242static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
302{ 243{
244 struct inode *inode = file_inode(file);
245 struct snd_info_private_data *data;
303 struct snd_info_entry *entry; 246 struct snd_info_entry *entry;
247
248 data = file->private_data;
249 if (data == NULL)
250 return 0;
251 entry = data->entry;
252 if (!entry->c.ops->mmap)
253 return -ENXIO;
254 return entry->c.ops->mmap(entry, data->file_private_data,
255 inode, file, vma);
256}
257
258static int snd_info_entry_open(struct inode *inode, struct file *file)
259{
260 struct snd_info_entry *entry = PDE_DATA(inode);
304 struct snd_info_private_data *data; 261 struct snd_info_private_data *data;
305 struct snd_info_buffer *buffer;
306 int mode, err; 262 int mode, err;
307 263
308 mutex_lock(&info_mutex); 264 mutex_lock(&info_mutex);
309 entry = PDE_DATA(inode); 265 err = alloc_info_private(entry, &data);
310 if (entry == NULL || ! entry->p) { 266 if (err < 0)
311 mutex_unlock(&info_mutex); 267 goto unlock;
312 return -ENODEV; 268
313 }
314 if (!try_module_get(entry->module)) {
315 err = -EFAULT;
316 goto __error1;
317 }
318 mode = file->f_flags & O_ACCMODE; 269 mode = file->f_flags & O_ACCMODE;
319 if (mode == O_RDONLY || mode == O_RDWR) { 270 if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
320 if ((entry->content == SNDRV_INFO_CONTENT_DATA && 271 ((mode == O_WRONLY || mode == O_RDWR) && !entry->c.ops->write)) {
321 entry->c.ops->read == NULL)) { 272 err = -ENODEV;
322 err = -ENODEV; 273 goto error;
323 goto __error;
324 }
325 }
326 if (mode == O_WRONLY || mode == O_RDWR) {
327 if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
328 entry->c.ops->write == NULL)) {
329 err = -ENODEV;
330 goto __error;
331 }
332 } 274 }
333 data = kzalloc(sizeof(*data), GFP_KERNEL); 275
334 if (data == NULL) { 276 if (entry->c.ops->open) {
335 err = -ENOMEM; 277 err = entry->c.ops->open(entry, mode, &data->file_private_data);
336 goto __error; 278 if (err < 0)
337 } 279 goto error;
338 data->entry = entry;
339 switch (entry->content) {
340 case SNDRV_INFO_CONTENT_TEXT:
341 if (mode == O_RDONLY || mode == O_RDWR) {
342 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
343 if (buffer == NULL)
344 goto __nomem;
345 data->rbuffer = buffer;
346 buffer->len = PAGE_SIZE;
347 buffer->buffer = kzalloc(buffer->len, GFP_KERNEL);
348 if (buffer->buffer == NULL)
349 goto __nomem;
350 }
351 if (mode == O_WRONLY || mode == O_RDWR) {
352 buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
353 if (buffer == NULL)
354 goto __nomem;
355 data->wbuffer = buffer;
356 buffer->len = PAGE_SIZE;
357 buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
358 if (buffer->buffer == NULL)
359 goto __nomem;
360 }
361 break;
362 case SNDRV_INFO_CONTENT_DATA: /* data */
363 if (entry->c.ops->open) {
364 if ((err = entry->c.ops->open(entry, mode,
365 &data->file_private_data)) < 0) {
366 kfree(data);
367 goto __error;
368 }
369 }
370 break;
371 } 280 }
281
372 file->private_data = data; 282 file->private_data = data;
373 mutex_unlock(&info_mutex); 283 mutex_unlock(&info_mutex);
374 if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
375 (mode == O_RDONLY || mode == O_RDWR)) {
376 if (entry->c.text.read) {
377 mutex_lock(&entry->access);
378 entry->c.text.read(entry, data->rbuffer);
379 mutex_unlock(&entry->access);
380 }
381 }
382 return 0; 284 return 0;
383 285
384 __nomem: 286 error:
385 if (data->rbuffer) {
386 kfree(data->rbuffer->buffer);
387 kfree(data->rbuffer);
388 }
389 if (data->wbuffer) {
390 kfree(data->wbuffer->buffer);
391 kfree(data->wbuffer);
392 }
393 kfree(data); 287 kfree(data);
394 err = -ENOMEM;
395 __error:
396 module_put(entry->module); 288 module_put(entry->module);
397 __error1: 289 unlock:
398 mutex_unlock(&info_mutex); 290 mutex_unlock(&info_mutex);
399 return err; 291 return err;
400} 292}
401 293
402static int snd_info_entry_release(struct inode *inode, struct file *file) 294static int snd_info_entry_release(struct inode *inode, struct file *file)
403{ 295{
404 struct snd_info_entry *entry; 296 struct snd_info_private_data *data = file->private_data;
405 struct snd_info_private_data *data; 297 struct snd_info_entry *entry = data->entry;
406 int mode;
407 298
408 mode = file->f_flags & O_ACCMODE; 299 if (entry->c.ops->release)
409 data = file->private_data; 300 entry->c.ops->release(entry, file->f_flags & O_ACCMODE,
410 entry = data->entry; 301 data->file_private_data);
411 switch (entry->content) {
412 case SNDRV_INFO_CONTENT_TEXT:
413 if (data->rbuffer) {
414 kfree(data->rbuffer->buffer);
415 kfree(data->rbuffer);
416 }
417 if (data->wbuffer) {
418 if (entry->c.text.write) {
419 entry->c.text.write(entry, data->wbuffer);
420 if (data->wbuffer->error) {
421 if (entry->card)
422 dev_warn(entry->card->dev, "info: data write error to %s (%i)\n",
423 entry->name,
424 data->wbuffer->error);
425 else
426 pr_warn("ALSA: info: data write error to %s (%i)\n",
427 entry->name,
428 data->wbuffer->error);
429 }
430 }
431 kfree(data->wbuffer->buffer);
432 kfree(data->wbuffer);
433 }
434 break;
435 case SNDRV_INFO_CONTENT_DATA:
436 if (entry->c.ops->release)
437 entry->c.ops->release(entry, mode,
438 data->file_private_data);
439 break;
440 }
441 module_put(entry->module); 302 module_put(entry->module);
442 kfree(data); 303 kfree(data);
443 return 0; 304 return 0;
444} 305}
445 306
446static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait) 307static const struct file_operations snd_info_entry_operations =
447{ 308{
448 struct snd_info_private_data *data; 309 .owner = THIS_MODULE,
449 struct snd_info_entry *entry; 310 .llseek = snd_info_entry_llseek,
450 unsigned int mask; 311 .read = snd_info_entry_read,
312 .write = snd_info_entry_write,
313 .poll = snd_info_entry_poll,
314 .unlocked_ioctl = snd_info_entry_ioctl,
315 .mmap = snd_info_entry_mmap,
316 .open = snd_info_entry_open,
317 .release = snd_info_entry_release,
318};
451 319
452 data = file->private_data; 320/*
453 if (data == NULL) 321 * file ops for text proc files
454 return 0; 322 */
455 entry = data->entry; 323static ssize_t snd_info_text_entry_write(struct file *file,
456 mask = 0; 324 const char __user *buffer,
457 switch (entry->content) { 325 size_t count, loff_t *offset)
458 case SNDRV_INFO_CONTENT_DATA: 326{
459 if (entry->c.ops->poll) 327 struct seq_file *m = file->private_data;
460 return entry->c.ops->poll(entry, 328 struct snd_info_private_data *data = m->private;
461 data->file_private_data, 329 struct snd_info_entry *entry = data->entry;
462 file, wait); 330 struct snd_info_buffer *buf;
463 if (entry->c.ops->read) 331 loff_t pos;
464 mask |= POLLIN | POLLRDNORM; 332 size_t next;
465 if (entry->c.ops->write) 333 int err = 0;
466 mask |= POLLOUT | POLLWRNORM; 334
467 break; 335 pos = *offset;
336 if (!valid_pos(pos, count))
337 return -EIO;
338 next = pos + count;
339 mutex_lock(&entry->access);
340 buf = data->wbuffer;
341 if (!buf) {
342 data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
343 if (!buf) {
344 err = -ENOMEM;
345 goto error;
346 }
468 } 347 }
469 return mask; 348 if (next > buf->len) {
349 char *nbuf = krealloc(buf->buffer, PAGE_ALIGN(next),
350 GFP_KERNEL | __GFP_ZERO);
351 if (!nbuf) {
352 err = -ENOMEM;
353 goto error;
354 }
355 buf->buffer = nbuf;
356 buf->len = PAGE_ALIGN(next);
357 }
358 if (copy_from_user(buf->buffer + pos, buffer, count)) {
359 err = -EFAULT;
360 goto error;
361 }
362 buf->size = next;
363 error:
364 mutex_unlock(&entry->access);
365 if (err < 0)
366 return err;
367 *offset = next;
368 return count;
470} 369}
471 370
472static long snd_info_entry_ioctl(struct file *file, unsigned int cmd, 371static int snd_info_seq_show(struct seq_file *seq, void *p)
473 unsigned long arg)
474{ 372{
475 struct snd_info_private_data *data; 373 struct snd_info_private_data *data = seq->private;
476 struct snd_info_entry *entry; 374 struct snd_info_entry *entry = data->entry;
477 375
478 data = file->private_data; 376 if (entry->c.text.read) {
479 if (data == NULL) 377 data->rbuffer->buffer = (char *)seq; /* XXX hack! */
480 return 0; 378 entry->c.text.read(entry, data->rbuffer);
481 entry = data->entry;
482 switch (entry->content) {
483 case SNDRV_INFO_CONTENT_DATA:
484 if (entry->c.ops->ioctl)
485 return entry->c.ops->ioctl(entry,
486 data->file_private_data,
487 file, cmd, arg);
488 break;
489 } 379 }
490 return -ENOTTY; 380 return 0;
491} 381}
492 382
493static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma) 383static int snd_info_text_entry_open(struct inode *inode, struct file *file)
494{ 384{
495 struct inode *inode = file_inode(file); 385 struct snd_info_entry *entry = PDE_DATA(inode);
496 struct snd_info_private_data *data; 386 struct snd_info_private_data *data;
497 struct snd_info_entry *entry; 387 int err;
498 388
499 data = file->private_data; 389 mutex_lock(&info_mutex);
500 if (data == NULL) 390 err = alloc_info_private(entry, &data);
501 return 0; 391 if (err < 0)
502 entry = data->entry; 392 goto unlock;
503 switch (entry->content) { 393
504 case SNDRV_INFO_CONTENT_DATA: 394 data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
505 if (entry->c.ops->mmap) 395 if (!data->rbuffer) {
506 return entry->c.ops->mmap(entry, 396 err = -ENOMEM;
507 data->file_private_data, 397 goto error;
508 inode, file, vma); 398 }
509 break; 399 if (entry->size)
400 err = single_open_size(file, snd_info_seq_show, data,
401 entry->size);
402 else
403 err = single_open(file, snd_info_seq_show, data);
404 if (err < 0)
405 goto error;
406 mutex_unlock(&info_mutex);
407 return 0;
408
409 error:
410 kfree(data->rbuffer);
411 kfree(data);
412 module_put(entry->module);
413 unlock:
414 mutex_unlock(&info_mutex);
415 return err;
416}
417
418static int snd_info_text_entry_release(struct inode *inode, struct file *file)
419{
420 struct seq_file *m = file->private_data;
421 struct snd_info_private_data *data = m->private;
422 struct snd_info_entry *entry = data->entry;
423
424 if (data->wbuffer && entry->c.text.write)
425 entry->c.text.write(entry, data->wbuffer);
426
427 single_release(inode, file);
428 kfree(data->rbuffer);
429 if (data->wbuffer) {
430 kfree(data->wbuffer->buffer);
431 kfree(data->wbuffer);
510 } 432 }
511 return -ENXIO; 433
434 module_put(entry->module);
435 kfree(data);
436 return 0;
512} 437}
513 438
514static const struct file_operations snd_info_entry_operations = 439static const struct file_operations snd_info_text_entry_ops =
515{ 440{
516 .owner = THIS_MODULE, 441 .owner = THIS_MODULE,
517 .llseek = snd_info_entry_llseek, 442 .open = snd_info_text_entry_open,
518 .read = snd_info_entry_read, 443 .release = snd_info_text_entry_release,
519 .write = snd_info_entry_write, 444 .write = snd_info_text_entry_write,
520 .poll = snd_info_entry_poll, 445 .llseek = seq_lseek,
521 .unlocked_ioctl = snd_info_entry_ioctl, 446 .read = seq_read,
522 .mmap = snd_info_entry_mmap,
523 .open = snd_info_entry_open,
524 .release = snd_info_entry_release,
525}; 447};
526 448
527int __init snd_info_init(void) 449int __init snd_info_init(void)
@@ -955,8 +877,13 @@ int snd_info_register(struct snd_info_entry * entry)
955 return -ENOMEM; 877 return -ENOMEM;
956 } 878 }
957 } else { 879 } else {
880 const struct file_operations *ops;
881 if (entry->content == SNDRV_INFO_CONTENT_DATA)
882 ops = &snd_info_entry_operations;
883 else
884 ops = &snd_info_text_entry_ops;
958 p = proc_create_data(entry->name, entry->mode, root, 885 p = proc_create_data(entry->name, entry->mode, root,
959 &snd_info_entry_operations, entry); 886 ops, entry);
960 if (!p) { 887 if (!p) {
961 mutex_unlock(&info_mutex); 888 mutex_unlock(&info_mutex);
962 return -ENOMEM; 889 return -ENOMEM;