1 /* 2 * Information interface for ALSA driver 3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <linux/init.h> 23 #include <linux/time.h> 24 #include <linux/mm.h> 25 #include <linux/slab.h> 26 #include <linux/string.h> 27 #include <linux/module.h> 28 #include <sound/core.h> 29 #include <sound/minors.h> 30 #include <sound/info.h> 31 #include <linux/utsname.h> 32 #include <linux/proc_fs.h> 33 #include <linux/mutex.h> 34 #include <stdarg.h> 35 36 int snd_info_check_reserved_words(const char *str) 37 { 38 static char *reserved[] = 39 { 40 "version", 41 "meminfo", 42 "memdebug", 43 "detect", 44 "devices", 45 "oss", 46 "cards", 47 "timers", 48 "synth", 49 "pcm", 50 "seq", 51 NULL 52 }; 53 char **xstr = reserved; 54 55 while (*xstr) { 56 if (!strcmp(*xstr, str)) 57 return 0; 58 xstr++; 59 } 60 if (!strncmp(str, "card", 4)) 61 return 0; 62 return 1; 63 } 64 65 static DEFINE_MUTEX(info_mutex); 66 67 struct snd_info_private_data { 68 struct snd_info_buffer *rbuffer; 69 struct snd_info_buffer *wbuffer; 70 struct snd_info_entry *entry; 71 void *file_private_data; 72 }; 73 74 static int snd_info_version_init(void); 75 static void snd_info_disconnect(struct snd_info_entry *entry); 76 77 /* 78 79 */ 80 81 static struct snd_info_entry *snd_proc_root; 82 struct snd_info_entry *snd_seq_root; 83 EXPORT_SYMBOL(snd_seq_root); 84 85 #ifdef CONFIG_SND_OSSEMUL 86 struct snd_info_entry *snd_oss_root; 87 #endif 88 89 static int alloc_info_private(struct snd_info_entry *entry, 90 struct snd_info_private_data **ret) 91 { 92 struct snd_info_private_data *data; 93 94 if (!entry || !entry->p) 95 return -ENODEV; 96 if (!try_module_get(entry->module)) 97 return -EFAULT; 98 data = kzalloc(sizeof(*data), GFP_KERNEL); 99 if (!data) { 100 module_put(entry->module); 101 return -ENOMEM; 102 } 103 data->entry = entry; 104 *ret = data; 105 return 0; 106 } 107 108 static bool valid_pos(loff_t pos, size_t count) 109 { 110 if (pos < 0 || (long) pos != pos || (ssize_t) count < 0) 111 return false; 112 if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos) 113 return false; 114 return true; 115 } 116 117 /* 118 * file ops for binary proc files 119 */ 120 static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) 121 { 122 struct snd_info_private_data *data; 123 struct snd_info_entry *entry; 124 loff_t ret = -EINVAL, size; 125 126 data = file->private_data; 127 entry = data->entry; 128 mutex_lock(&entry->access); 129 if (entry->c.ops->llseek) { 130 offset = entry->c.ops->llseek(entry, 131 data->file_private_data, 132 file, offset, orig); 133 goto out; 134 } 135 136 size = entry->size; 137 switch (orig) { 138 case SEEK_SET: 139 break; 140 case SEEK_CUR: 141 offset += file->f_pos; 142 break; 143 case SEEK_END: 144 if (!size) 145 goto out; 146 offset += size; 147 break; 148 default: 149 goto out; 150 } 151 if (offset < 0) 152 goto out; 153 if (size && offset > size) 154 offset = size; 155 file->f_pos = offset; 156 ret = offset; 157 out: 158 mutex_unlock(&entry->access); 159 return ret; 160 } 161 162 static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, 163 size_t count, loff_t * offset) 164 { 165 struct snd_info_private_data *data = file->private_data; 166 struct snd_info_entry *entry = data->entry; 167 size_t size; 168 loff_t pos; 169 170 pos = *offset; 171 if (!valid_pos(pos, count)) 172 return -EIO; 173 if (pos >= entry->size) 174 return 0; 175 size = entry->size - pos; 176 size = min(count, size); 177 size = entry->c.ops->read(entry, data->file_private_data, 178 file, buffer, size, pos); 179 if ((ssize_t) size > 0) 180 *offset = pos + size; 181 return size; 182 } 183 184 static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer, 185 size_t count, loff_t * offset) 186 { 187 struct snd_info_private_data *data = file->private_data; 188 struct snd_info_entry *entry = data->entry; 189 ssize_t size = 0; 190 loff_t pos; 191 192 pos = *offset; 193 if (!valid_pos(pos, count)) 194 return -EIO; 195 if (count > 0) { 196 size_t maxsize = entry->size - pos; 197 count = min(count, maxsize); 198 size = entry->c.ops->write(entry, data->file_private_data, 199 file, buffer, count, pos); 200 } 201 if (size > 0) 202 *offset = pos + size; 203 return size; 204 } 205 206 static __poll_t snd_info_entry_poll(struct file *file, poll_table *wait) 207 { 208 struct snd_info_private_data *data = file->private_data; 209 struct snd_info_entry *entry = data->entry; 210 __poll_t mask = 0; 211 212 if (entry->c.ops->poll) 213 return entry->c.ops->poll(entry, 214 data->file_private_data, 215 file, wait); 216 if (entry->c.ops->read) 217 mask |= EPOLLIN | EPOLLRDNORM; 218 if (entry->c.ops->write) 219 mask |= EPOLLOUT | EPOLLWRNORM; 220 return mask; 221 } 222 223 static long snd_info_entry_ioctl(struct file *file, unsigned int cmd, 224 unsigned long arg) 225 { 226 struct snd_info_private_data *data = file->private_data; 227 struct snd_info_entry *entry = data->entry; 228 229 if (!entry->c.ops->ioctl) 230 return -ENOTTY; 231 return entry->c.ops->ioctl(entry, data->file_private_data, 232 file, cmd, arg); 233 } 234 235 static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma) 236 { 237 struct inode *inode = file_inode(file); 238 struct snd_info_private_data *data; 239 struct snd_info_entry *entry; 240 241 data = file->private_data; 242 if (data == NULL) 243 return 0; 244 entry = data->entry; 245 if (!entry->c.ops->mmap) 246 return -ENXIO; 247 return entry->c.ops->mmap(entry, data->file_private_data, 248 inode, file, vma); 249 } 250 251 static int snd_info_entry_open(struct inode *inode, struct file *file) 252 { 253 struct snd_info_entry *entry = PDE_DATA(inode); 254 struct snd_info_private_data *data; 255 int mode, err; 256 257 mutex_lock(&info_mutex); 258 err = alloc_info_private(entry, &data); 259 if (err < 0) 260 goto unlock; 261 262 mode = file->f_flags & O_ACCMODE; 263 if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) || 264 ((mode == O_WRONLY || mode == O_RDWR) && !entry->c.ops->write)) { 265 err = -ENODEV; 266 goto error; 267 } 268 269 if (entry->c.ops->open) { 270 err = entry->c.ops->open(entry, mode, &data->file_private_data); 271 if (err < 0) 272 goto error; 273 } 274 275 file->private_data = data; 276 mutex_unlock(&info_mutex); 277 return 0; 278 279 error: 280 kfree(data); 281 module_put(entry->module); 282 unlock: 283 mutex_unlock(&info_mutex); 284 return err; 285 } 286 287 static int snd_info_entry_release(struct inode *inode, struct file *file) 288 { 289 struct snd_info_private_data *data = file->private_data; 290 struct snd_info_entry *entry = data->entry; 291 292 if (entry->c.ops->release) 293 entry->c.ops->release(entry, file->f_flags & O_ACCMODE, 294 data->file_private_data); 295 module_put(entry->module); 296 kfree(data); 297 return 0; 298 } 299 300 static const struct file_operations snd_info_entry_operations = 301 { 302 .owner = THIS_MODULE, 303 .llseek = snd_info_entry_llseek, 304 .read = snd_info_entry_read, 305 .write = snd_info_entry_write, 306 .poll = snd_info_entry_poll, 307 .unlocked_ioctl = snd_info_entry_ioctl, 308 .mmap = snd_info_entry_mmap, 309 .open = snd_info_entry_open, 310 .release = snd_info_entry_release, 311 }; 312 313 /* 314 * file ops for text proc files 315 */ 316 static ssize_t snd_info_text_entry_write(struct file *file, 317 const char __user *buffer, 318 size_t count, loff_t *offset) 319 { 320 struct seq_file *m = file->private_data; 321 struct snd_info_private_data *data = m->private; 322 struct snd_info_entry *entry = data->entry; 323 struct snd_info_buffer *buf; 324 loff_t pos; 325 size_t next; 326 int err = 0; 327 328 if (!entry->c.text.write) 329 return -EIO; 330 pos = *offset; 331 if (!valid_pos(pos, count)) 332 return -EIO; 333 next = pos + count; 334 /* don't handle too large text inputs */ 335 if (next > 16 * 1024) 336 return -EIO; 337 mutex_lock(&entry->access); 338 buf = data->wbuffer; 339 if (!buf) { 340 data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL); 341 if (!buf) { 342 err = -ENOMEM; 343 goto error; 344 } 345 } 346 if (next > buf->len) { 347 char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); 348 if (!nbuf) { 349 err = -ENOMEM; 350 goto error; 351 } 352 kvfree(buf->buffer); 353 buf->buffer = nbuf; 354 buf->len = PAGE_ALIGN(next); 355 } 356 if (copy_from_user(buf->buffer + pos, buffer, count)) { 357 err = -EFAULT; 358 goto error; 359 } 360 buf->size = next; 361 error: 362 mutex_unlock(&entry->access); 363 if (err < 0) 364 return err; 365 *offset = next; 366 return count; 367 } 368 369 static int snd_info_seq_show(struct seq_file *seq, void *p) 370 { 371 struct snd_info_private_data *data = seq->private; 372 struct snd_info_entry *entry = data->entry; 373 374 if (!entry->c.text.read) { 375 return -EIO; 376 } else { 377 data->rbuffer->buffer = (char *)seq; /* XXX hack! */ 378 entry->c.text.read(entry, data->rbuffer); 379 } 380 return 0; 381 } 382 383 static int snd_info_text_entry_open(struct inode *inode, struct file *file) 384 { 385 struct snd_info_entry *entry = PDE_DATA(inode); 386 struct snd_info_private_data *data; 387 int err; 388 389 mutex_lock(&info_mutex); 390 err = alloc_info_private(entry, &data); 391 if (err < 0) 392 goto unlock; 393 394 data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL); 395 if (!data->rbuffer) { 396 err = -ENOMEM; 397 goto error; 398 } 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 418 static 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 kvfree(data->wbuffer->buffer); 431 kfree(data->wbuffer); 432 } 433 434 module_put(entry->module); 435 kfree(data); 436 return 0; 437 } 438 439 static const struct file_operations snd_info_text_entry_ops = 440 { 441 .owner = THIS_MODULE, 442 .open = snd_info_text_entry_open, 443 .release = snd_info_text_entry_release, 444 .write = snd_info_text_entry_write, 445 .llseek = seq_lseek, 446 .read = seq_read, 447 }; 448 449 static struct snd_info_entry *create_subdir(struct module *mod, 450 const char *name) 451 { 452 struct snd_info_entry *entry; 453 454 entry = snd_info_create_module_entry(mod, name, NULL); 455 if (!entry) 456 return NULL; 457 entry->mode = S_IFDIR | 0555; 458 if (snd_info_register(entry) < 0) { 459 snd_info_free_entry(entry); 460 return NULL; 461 } 462 return entry; 463 } 464 465 static struct snd_info_entry * 466 snd_info_create_entry(const char *name, struct snd_info_entry *parent, 467 struct module *module); 468 469 int __init snd_info_init(void) 470 { 471 snd_proc_root = snd_info_create_entry("asound", NULL, THIS_MODULE); 472 if (!snd_proc_root) 473 return -ENOMEM; 474 snd_proc_root->mode = S_IFDIR | 0555; 475 snd_proc_root->p = proc_mkdir("asound", NULL); 476 if (!snd_proc_root->p) 477 goto error; 478 #ifdef CONFIG_SND_OSSEMUL 479 snd_oss_root = create_subdir(THIS_MODULE, "oss"); 480 if (!snd_oss_root) 481 goto error; 482 #endif 483 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 484 snd_seq_root = create_subdir(THIS_MODULE, "seq"); 485 if (!snd_seq_root) 486 goto error; 487 #endif 488 if (snd_info_version_init() < 0 || 489 snd_minor_info_init() < 0 || 490 snd_minor_info_oss_init() < 0 || 491 snd_card_info_init() < 0 || 492 snd_info_minor_register() < 0) 493 goto error; 494 return 0; 495 496 error: 497 snd_info_free_entry(snd_proc_root); 498 return -ENOMEM; 499 } 500 501 int __exit snd_info_done(void) 502 { 503 snd_info_free_entry(snd_proc_root); 504 return 0; 505 } 506 507 static void snd_card_id_read(struct snd_info_entry *entry, 508 struct snd_info_buffer *buffer) 509 { 510 struct snd_card *card = entry->private_data; 511 512 snd_iprintf(buffer, "%s\n", card->id); 513 } 514 515 /* 516 * create a card proc file 517 * called from init.c 518 */ 519 int snd_info_card_create(struct snd_card *card) 520 { 521 char str[8]; 522 struct snd_info_entry *entry; 523 524 if (snd_BUG_ON(!card)) 525 return -ENXIO; 526 527 sprintf(str, "card%i", card->number); 528 entry = create_subdir(card->module, str); 529 if (!entry) 530 return -ENOMEM; 531 card->proc_root = entry; 532 533 return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); 534 } 535 536 /* 537 * register the card proc file 538 * called from init.c 539 * can be called multiple times for reinitialization 540 */ 541 int snd_info_card_register(struct snd_card *card) 542 { 543 struct proc_dir_entry *p; 544 int err; 545 546 if (snd_BUG_ON(!card)) 547 return -ENXIO; 548 549 err = snd_info_register(card->proc_root); 550 if (err < 0) 551 return err; 552 553 if (!strcmp(card->id, card->proc_root->name)) 554 return 0; 555 556 if (card->proc_root_link) 557 return 0; 558 p = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name); 559 if (!p) 560 return -ENOMEM; 561 card->proc_root_link = p; 562 return 0; 563 } 564 565 /* 566 * called on card->id change 567 */ 568 void snd_info_card_id_change(struct snd_card *card) 569 { 570 mutex_lock(&info_mutex); 571 if (card->proc_root_link) { 572 proc_remove(card->proc_root_link); 573 card->proc_root_link = NULL; 574 } 575 if (strcmp(card->id, card->proc_root->name)) 576 card->proc_root_link = proc_symlink(card->id, 577 snd_proc_root->p, 578 card->proc_root->name); 579 mutex_unlock(&info_mutex); 580 } 581 582 /* 583 * de-register the card proc file 584 * called from init.c 585 */ 586 void snd_info_card_disconnect(struct snd_card *card) 587 { 588 if (!card) 589 return; 590 mutex_lock(&info_mutex); 591 proc_remove(card->proc_root_link); 592 card->proc_root_link = NULL; 593 if (card->proc_root) 594 snd_info_disconnect(card->proc_root); 595 mutex_unlock(&info_mutex); 596 } 597 598 /* 599 * release the card proc file resources 600 * called from init.c 601 */ 602 int snd_info_card_free(struct snd_card *card) 603 { 604 if (!card) 605 return 0; 606 snd_info_free_entry(card->proc_root); 607 card->proc_root = NULL; 608 return 0; 609 } 610 611 612 /** 613 * snd_info_get_line - read one line from the procfs buffer 614 * @buffer: the procfs buffer 615 * @line: the buffer to store 616 * @len: the max. buffer size 617 * 618 * Reads one line from the buffer and stores the string. 619 * 620 * Return: Zero if successful, or 1 if error or EOF. 621 */ 622 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) 623 { 624 int c = -1; 625 626 if (snd_BUG_ON(!buffer || !buffer->buffer)) 627 return 1; 628 if (len <= 0 || buffer->stop || buffer->error) 629 return 1; 630 while (!buffer->stop) { 631 c = buffer->buffer[buffer->curr++]; 632 if (buffer->curr >= buffer->size) 633 buffer->stop = 1; 634 if (c == '\n') 635 break; 636 if (len > 1) { 637 len--; 638 *line++ = c; 639 } 640 } 641 *line = '\0'; 642 return 0; 643 } 644 EXPORT_SYMBOL(snd_info_get_line); 645 646 /** 647 * snd_info_get_str - parse a string token 648 * @dest: the buffer to store the string token 649 * @src: the original string 650 * @len: the max. length of token - 1 651 * 652 * Parses the original string and copy a token to the given 653 * string buffer. 654 * 655 * Return: The updated pointer of the original string so that 656 * it can be used for the next call. 657 */ 658 const char *snd_info_get_str(char *dest, const char *src, int len) 659 { 660 int c; 661 662 while (*src == ' ' || *src == '\t') 663 src++; 664 if (*src == '"' || *src == '\'') { 665 c = *src++; 666 while (--len > 0 && *src && *src != c) { 667 *dest++ = *src++; 668 } 669 if (*src == c) 670 src++; 671 } else { 672 while (--len > 0 && *src && *src != ' ' && *src != '\t') { 673 *dest++ = *src++; 674 } 675 } 676 *dest = 0; 677 while (*src == ' ' || *src == '\t') 678 src++; 679 return src; 680 } 681 EXPORT_SYMBOL(snd_info_get_str); 682 683 /* 684 * snd_info_create_entry - create an info entry 685 * @name: the proc file name 686 * @parent: the parent directory 687 * 688 * Creates an info entry with the given file name and initializes as 689 * the default state. 690 * 691 * Usually called from other functions such as 692 * snd_info_create_card_entry(). 693 * 694 * Return: The pointer of the new instance, or %NULL on failure. 695 */ 696 static struct snd_info_entry * 697 snd_info_create_entry(const char *name, struct snd_info_entry *parent, 698 struct module *module) 699 { 700 struct snd_info_entry *entry; 701 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 702 if (entry == NULL) 703 return NULL; 704 entry->name = kstrdup(name, GFP_KERNEL); 705 if (entry->name == NULL) { 706 kfree(entry); 707 return NULL; 708 } 709 entry->mode = S_IFREG | 0444; 710 entry->content = SNDRV_INFO_CONTENT_TEXT; 711 mutex_init(&entry->access); 712 INIT_LIST_HEAD(&entry->children); 713 INIT_LIST_HEAD(&entry->list); 714 entry->parent = parent; 715 entry->module = module; 716 if (parent) 717 list_add_tail(&entry->list, &parent->children); 718 return entry; 719 } 720 721 /** 722 * snd_info_create_module_entry - create an info entry for the given module 723 * @module: the module pointer 724 * @name: the file name 725 * @parent: the parent directory 726 * 727 * Creates a new info entry and assigns it to the given module. 728 * 729 * Return: The pointer of the new instance, or %NULL on failure. 730 */ 731 struct snd_info_entry *snd_info_create_module_entry(struct module * module, 732 const char *name, 733 struct snd_info_entry *parent) 734 { 735 if (!parent) 736 parent = snd_proc_root; 737 return snd_info_create_entry(name, parent, module); 738 } 739 EXPORT_SYMBOL(snd_info_create_module_entry); 740 741 /** 742 * snd_info_create_card_entry - create an info entry for the given card 743 * @card: the card instance 744 * @name: the file name 745 * @parent: the parent directory 746 * 747 * Creates a new info entry and assigns it to the given card. 748 * 749 * Return: The pointer of the new instance, or %NULL on failure. 750 */ 751 struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, 752 const char *name, 753 struct snd_info_entry * parent) 754 { 755 if (!parent) 756 parent = card->proc_root; 757 return snd_info_create_entry(name, parent, card->module); 758 } 759 EXPORT_SYMBOL(snd_info_create_card_entry); 760 761 static void snd_info_disconnect(struct snd_info_entry *entry) 762 { 763 struct snd_info_entry *p; 764 765 if (!entry->p) 766 return; 767 list_for_each_entry(p, &entry->children, list) 768 snd_info_disconnect(p); 769 proc_remove(entry->p); 770 entry->p = NULL; 771 } 772 773 /** 774 * snd_info_free_entry - release the info entry 775 * @entry: the info entry 776 * 777 * Releases the info entry. 778 */ 779 void snd_info_free_entry(struct snd_info_entry * entry) 780 { 781 struct snd_info_entry *p, *n; 782 783 if (!entry) 784 return; 785 if (entry->p) { 786 mutex_lock(&info_mutex); 787 snd_info_disconnect(entry); 788 mutex_unlock(&info_mutex); 789 } 790 791 /* free all children at first */ 792 list_for_each_entry_safe(p, n, &entry->children, list) 793 snd_info_free_entry(p); 794 795 list_del(&entry->list); 796 kfree(entry->name); 797 if (entry->private_free) 798 entry->private_free(entry); 799 kfree(entry); 800 } 801 EXPORT_SYMBOL(snd_info_free_entry); 802 803 static int __snd_info_register(struct snd_info_entry *entry) 804 { 805 struct proc_dir_entry *root, *p = NULL; 806 807 if (snd_BUG_ON(!entry)) 808 return -ENXIO; 809 root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p; 810 mutex_lock(&info_mutex); 811 if (entry->p || !root) 812 goto unlock; 813 if (S_ISDIR(entry->mode)) { 814 p = proc_mkdir_mode(entry->name, entry->mode, root); 815 if (!p) { 816 mutex_unlock(&info_mutex); 817 return -ENOMEM; 818 } 819 } else { 820 const struct file_operations *ops; 821 if (entry->content == SNDRV_INFO_CONTENT_DATA) 822 ops = &snd_info_entry_operations; 823 else 824 ops = &snd_info_text_entry_ops; 825 p = proc_create_data(entry->name, entry->mode, root, 826 ops, entry); 827 if (!p) { 828 mutex_unlock(&info_mutex); 829 return -ENOMEM; 830 } 831 proc_set_size(p, entry->size); 832 } 833 entry->p = p; 834 unlock: 835 mutex_unlock(&info_mutex); 836 return 0; 837 } 838 839 /** 840 * snd_info_register - register the info entry 841 * @entry: the info entry 842 * 843 * Registers the proc info entry. 844 * The all children entries are registered recursively. 845 * 846 * Return: Zero if successful, or a negative error code on failure. 847 */ 848 int snd_info_register(struct snd_info_entry *entry) 849 { 850 struct snd_info_entry *p; 851 int err; 852 853 if (!entry->p) { 854 err = __snd_info_register(entry); 855 if (err < 0) 856 return err; 857 } 858 859 list_for_each_entry(p, &entry->children, list) { 860 err = snd_info_register(p); 861 if (err < 0) 862 return err; 863 } 864 865 return 0; 866 } 867 EXPORT_SYMBOL(snd_info_register); 868 869 /** 870 * snd_card_rw_proc_new - Create a read/write text proc file entry for the card 871 * @card: the card instance 872 * @name: the file name 873 * @private_data: the arbitrary private data 874 * @read: the read callback 875 * @write: the write callback, NULL for read-only 876 * 877 * This proc file entry will be registered via snd_card_register() call, and 878 * it will be removed automatically at the card removal, too. 879 */ 880 int snd_card_rw_proc_new(struct snd_card *card, const char *name, 881 void *private_data, 882 void (*read)(struct snd_info_entry *, 883 struct snd_info_buffer *), 884 void (*write)(struct snd_info_entry *entry, 885 struct snd_info_buffer *buffer)) 886 { 887 struct snd_info_entry *entry; 888 889 entry = snd_info_create_card_entry(card, name, card->proc_root); 890 if (!entry) 891 return -ENOMEM; 892 snd_info_set_text_ops(entry, private_data, read); 893 if (write) { 894 entry->mode |= 0200; 895 entry->c.text.write = write; 896 } 897 return 0; 898 } 899 EXPORT_SYMBOL_GPL(snd_card_rw_proc_new); 900 901 /* 902 903 */ 904 905 static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 906 { 907 snd_iprintf(buffer, 908 "Advanced Linux Sound Architecture Driver Version k%s.\n", 909 init_utsname()->release); 910 } 911 912 static int __init snd_info_version_init(void) 913 { 914 struct snd_info_entry *entry; 915 916 entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); 917 if (entry == NULL) 918 return -ENOMEM; 919 entry->c.text.read = snd_info_version_read; 920 return snd_info_register(entry); /* freed in error path */ 921 } 922