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 const char * const 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 const char * const *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 proc_ops snd_info_entry_operations = 286 { 287 .proc_lseek = snd_info_entry_llseek, 288 .proc_read = snd_info_entry_read, 289 .proc_write = snd_info_entry_write, 290 .proc_poll = snd_info_entry_poll, 291 .proc_ioctl = snd_info_entry_ioctl, 292 .proc_mmap = snd_info_entry_mmap, 293 .proc_open = snd_info_entry_open, 294 .proc_release = snd_info_entry_release, 295 }; 296 297 /* 298 * file ops for text proc files 299 */ 300 static ssize_t snd_info_text_entry_write(struct file *file, 301 const char __user *buffer, 302 size_t count, loff_t *offset) 303 { 304 struct seq_file *m = file->private_data; 305 struct snd_info_private_data *data = m->private; 306 struct snd_info_entry *entry = data->entry; 307 struct snd_info_buffer *buf; 308 loff_t pos; 309 size_t next; 310 int err = 0; 311 312 if (!entry->c.text.write) 313 return -EIO; 314 pos = *offset; 315 if (!valid_pos(pos, count)) 316 return -EIO; 317 next = pos + count; 318 /* don't handle too large text inputs */ 319 if (next > 16 * 1024) 320 return -EIO; 321 mutex_lock(&entry->access); 322 buf = data->wbuffer; 323 if (!buf) { 324 data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL); 325 if (!buf) { 326 err = -ENOMEM; 327 goto error; 328 } 329 } 330 if (next > buf->len) { 331 char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); 332 if (!nbuf) { 333 err = -ENOMEM; 334 goto error; 335 } 336 kvfree(buf->buffer); 337 buf->buffer = nbuf; 338 buf->len = PAGE_ALIGN(next); 339 } 340 if (copy_from_user(buf->buffer + pos, buffer, count)) { 341 err = -EFAULT; 342 goto error; 343 } 344 buf->size = next; 345 error: 346 mutex_unlock(&entry->access); 347 if (err < 0) 348 return err; 349 *offset = next; 350 return count; 351 } 352 353 static int snd_info_seq_show(struct seq_file *seq, void *p) 354 { 355 struct snd_info_private_data *data = seq->private; 356 struct snd_info_entry *entry = data->entry; 357 358 if (!entry->c.text.read) { 359 return -EIO; 360 } else { 361 data->rbuffer->buffer = (char *)seq; /* XXX hack! */ 362 entry->c.text.read(entry, data->rbuffer); 363 } 364 return 0; 365 } 366 367 static int snd_info_text_entry_open(struct inode *inode, struct file *file) 368 { 369 struct snd_info_entry *entry = PDE_DATA(inode); 370 struct snd_info_private_data *data; 371 int err; 372 373 mutex_lock(&info_mutex); 374 err = alloc_info_private(entry, &data); 375 if (err < 0) 376 goto unlock; 377 378 data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL); 379 if (!data->rbuffer) { 380 err = -ENOMEM; 381 goto error; 382 } 383 if (entry->size) 384 err = single_open_size(file, snd_info_seq_show, data, 385 entry->size); 386 else 387 err = single_open(file, snd_info_seq_show, data); 388 if (err < 0) 389 goto error; 390 mutex_unlock(&info_mutex); 391 return 0; 392 393 error: 394 kfree(data->rbuffer); 395 kfree(data); 396 module_put(entry->module); 397 unlock: 398 mutex_unlock(&info_mutex); 399 return err; 400 } 401 402 static int snd_info_text_entry_release(struct inode *inode, struct file *file) 403 { 404 struct seq_file *m = file->private_data; 405 struct snd_info_private_data *data = m->private; 406 struct snd_info_entry *entry = data->entry; 407 408 if (data->wbuffer && entry->c.text.write) 409 entry->c.text.write(entry, data->wbuffer); 410 411 single_release(inode, file); 412 kfree(data->rbuffer); 413 if (data->wbuffer) { 414 kvfree(data->wbuffer->buffer); 415 kfree(data->wbuffer); 416 } 417 418 module_put(entry->module); 419 kfree(data); 420 return 0; 421 } 422 423 static const struct proc_ops snd_info_text_entry_ops = 424 { 425 .proc_open = snd_info_text_entry_open, 426 .proc_release = snd_info_text_entry_release, 427 .proc_write = snd_info_text_entry_write, 428 .proc_lseek = seq_lseek, 429 .proc_read = seq_read, 430 }; 431 432 static struct snd_info_entry *create_subdir(struct module *mod, 433 const char *name) 434 { 435 struct snd_info_entry *entry; 436 437 entry = snd_info_create_module_entry(mod, name, NULL); 438 if (!entry) 439 return NULL; 440 entry->mode = S_IFDIR | 0555; 441 if (snd_info_register(entry) < 0) { 442 snd_info_free_entry(entry); 443 return NULL; 444 } 445 return entry; 446 } 447 448 static struct snd_info_entry * 449 snd_info_create_entry(const char *name, struct snd_info_entry *parent, 450 struct module *module); 451 452 int __init snd_info_init(void) 453 { 454 snd_proc_root = snd_info_create_entry("asound", NULL, THIS_MODULE); 455 if (!snd_proc_root) 456 return -ENOMEM; 457 snd_proc_root->mode = S_IFDIR | 0555; 458 snd_proc_root->p = proc_mkdir("asound", NULL); 459 if (!snd_proc_root->p) 460 goto error; 461 #ifdef CONFIG_SND_OSSEMUL 462 snd_oss_root = create_subdir(THIS_MODULE, "oss"); 463 if (!snd_oss_root) 464 goto error; 465 #endif 466 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 467 snd_seq_root = create_subdir(THIS_MODULE, "seq"); 468 if (!snd_seq_root) 469 goto error; 470 #endif 471 if (snd_info_version_init() < 0 || 472 snd_minor_info_init() < 0 || 473 snd_minor_info_oss_init() < 0 || 474 snd_card_info_init() < 0 || 475 snd_info_minor_register() < 0) 476 goto error; 477 return 0; 478 479 error: 480 snd_info_free_entry(snd_proc_root); 481 return -ENOMEM; 482 } 483 484 int __exit snd_info_done(void) 485 { 486 snd_info_free_entry(snd_proc_root); 487 return 0; 488 } 489 490 static void snd_card_id_read(struct snd_info_entry *entry, 491 struct snd_info_buffer *buffer) 492 { 493 struct snd_card *card = entry->private_data; 494 495 snd_iprintf(buffer, "%s\n", card->id); 496 } 497 498 /* 499 * create a card proc file 500 * called from init.c 501 */ 502 int snd_info_card_create(struct snd_card *card) 503 { 504 char str[8]; 505 struct snd_info_entry *entry; 506 507 if (snd_BUG_ON(!card)) 508 return -ENXIO; 509 510 sprintf(str, "card%i", card->number); 511 entry = create_subdir(card->module, str); 512 if (!entry) 513 return -ENOMEM; 514 card->proc_root = entry; 515 516 return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); 517 } 518 519 /* 520 * register the card proc file 521 * called from init.c 522 * can be called multiple times for reinitialization 523 */ 524 int snd_info_card_register(struct snd_card *card) 525 { 526 struct proc_dir_entry *p; 527 int err; 528 529 if (snd_BUG_ON(!card)) 530 return -ENXIO; 531 532 err = snd_info_register(card->proc_root); 533 if (err < 0) 534 return err; 535 536 if (!strcmp(card->id, card->proc_root->name)) 537 return 0; 538 539 if (card->proc_root_link) 540 return 0; 541 p = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name); 542 if (!p) 543 return -ENOMEM; 544 card->proc_root_link = p; 545 return 0; 546 } 547 548 /* 549 * called on card->id change 550 */ 551 void snd_info_card_id_change(struct snd_card *card) 552 { 553 mutex_lock(&info_mutex); 554 if (card->proc_root_link) { 555 proc_remove(card->proc_root_link); 556 card->proc_root_link = NULL; 557 } 558 if (strcmp(card->id, card->proc_root->name)) 559 card->proc_root_link = proc_symlink(card->id, 560 snd_proc_root->p, 561 card->proc_root->name); 562 mutex_unlock(&info_mutex); 563 } 564 565 /* 566 * de-register the card proc file 567 * called from init.c 568 */ 569 void snd_info_card_disconnect(struct snd_card *card) 570 { 571 if (!card) 572 return; 573 mutex_lock(&info_mutex); 574 proc_remove(card->proc_root_link); 575 card->proc_root_link = NULL; 576 if (card->proc_root) 577 snd_info_disconnect(card->proc_root); 578 mutex_unlock(&info_mutex); 579 } 580 581 /* 582 * release the card proc file resources 583 * called from init.c 584 */ 585 int snd_info_card_free(struct snd_card *card) 586 { 587 if (!card) 588 return 0; 589 snd_info_free_entry(card->proc_root); 590 card->proc_root = NULL; 591 return 0; 592 } 593 594 595 /** 596 * snd_info_get_line - read one line from the procfs buffer 597 * @buffer: the procfs buffer 598 * @line: the buffer to store 599 * @len: the max. buffer size 600 * 601 * Reads one line from the buffer and stores the string. 602 * 603 * Return: Zero if successful, or 1 if error or EOF. 604 */ 605 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) 606 { 607 int c; 608 609 if (snd_BUG_ON(!buffer)) 610 return 1; 611 if (!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 proc_ops *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