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