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 || !buffer->buffer)) 610 return 1; 611 if (len <= 0 || buffer->stop || buffer->error) 612 return 1; 613 while (!buffer->stop) { 614 c = buffer->buffer[buffer->curr++]; 615 if (buffer->curr >= buffer->size) 616 buffer->stop = 1; 617 if (c == '\n') 618 break; 619 if (len > 1) { 620 len--; 621 *line++ = c; 622 } 623 } 624 *line = '\0'; 625 return 0; 626 } 627 EXPORT_SYMBOL(snd_info_get_line); 628 629 /** 630 * snd_info_get_str - parse a string token 631 * @dest: the buffer to store the string token 632 * @src: the original string 633 * @len: the max. length of token - 1 634 * 635 * Parses the original string and copy a token to the given 636 * string buffer. 637 * 638 * Return: The updated pointer of the original string so that 639 * it can be used for the next call. 640 */ 641 const char *snd_info_get_str(char *dest, const char *src, int len) 642 { 643 int c; 644 645 while (*src == ' ' || *src == '\t') 646 src++; 647 if (*src == '"' || *src == '\'') { 648 c = *src++; 649 while (--len > 0 && *src && *src != c) { 650 *dest++ = *src++; 651 } 652 if (*src == c) 653 src++; 654 } else { 655 while (--len > 0 && *src && *src != ' ' && *src != '\t') { 656 *dest++ = *src++; 657 } 658 } 659 *dest = 0; 660 while (*src == ' ' || *src == '\t') 661 src++; 662 return src; 663 } 664 EXPORT_SYMBOL(snd_info_get_str); 665 666 /* 667 * snd_info_create_entry - create an info entry 668 * @name: the proc file name 669 * @parent: the parent directory 670 * 671 * Creates an info entry with the given file name and initializes as 672 * the default state. 673 * 674 * Usually called from other functions such as 675 * snd_info_create_card_entry(). 676 * 677 * Return: The pointer of the new instance, or %NULL on failure. 678 */ 679 static struct snd_info_entry * 680 snd_info_create_entry(const char *name, struct snd_info_entry *parent, 681 struct module *module) 682 { 683 struct snd_info_entry *entry; 684 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 685 if (entry == NULL) 686 return NULL; 687 entry->name = kstrdup(name, GFP_KERNEL); 688 if (entry->name == NULL) { 689 kfree(entry); 690 return NULL; 691 } 692 entry->mode = S_IFREG | 0444; 693 entry->content = SNDRV_INFO_CONTENT_TEXT; 694 mutex_init(&entry->access); 695 INIT_LIST_HEAD(&entry->children); 696 INIT_LIST_HEAD(&entry->list); 697 entry->parent = parent; 698 entry->module = module; 699 if (parent) { 700 mutex_lock(&parent->access); 701 list_add_tail(&entry->list, &parent->children); 702 mutex_unlock(&parent->access); 703 } 704 return entry; 705 } 706 707 /** 708 * snd_info_create_module_entry - create an info entry for the given module 709 * @module: the module pointer 710 * @name: the file name 711 * @parent: the parent directory 712 * 713 * Creates a new info entry and assigns it to the given module. 714 * 715 * Return: The pointer of the new instance, or %NULL on failure. 716 */ 717 struct snd_info_entry *snd_info_create_module_entry(struct module * module, 718 const char *name, 719 struct snd_info_entry *parent) 720 { 721 if (!parent) 722 parent = snd_proc_root; 723 return snd_info_create_entry(name, parent, module); 724 } 725 EXPORT_SYMBOL(snd_info_create_module_entry); 726 727 /** 728 * snd_info_create_card_entry - create an info entry for the given card 729 * @card: the card instance 730 * @name: the file name 731 * @parent: the parent directory 732 * 733 * Creates a new info entry and assigns it to the given card. 734 * 735 * Return: The pointer of the new instance, or %NULL on failure. 736 */ 737 struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, 738 const char *name, 739 struct snd_info_entry * parent) 740 { 741 if (!parent) 742 parent = card->proc_root; 743 return snd_info_create_entry(name, parent, card->module); 744 } 745 EXPORT_SYMBOL(snd_info_create_card_entry); 746 747 static void snd_info_disconnect(struct snd_info_entry *entry) 748 { 749 struct snd_info_entry *p; 750 751 if (!entry->p) 752 return; 753 list_for_each_entry(p, &entry->children, list) 754 snd_info_disconnect(p); 755 proc_remove(entry->p); 756 entry->p = NULL; 757 } 758 759 /** 760 * snd_info_free_entry - release the info entry 761 * @entry: the info entry 762 * 763 * Releases the info entry. 764 */ 765 void snd_info_free_entry(struct snd_info_entry * entry) 766 { 767 struct snd_info_entry *p, *n; 768 769 if (!entry) 770 return; 771 if (entry->p) { 772 mutex_lock(&info_mutex); 773 snd_info_disconnect(entry); 774 mutex_unlock(&info_mutex); 775 } 776 777 /* free all children at first */ 778 list_for_each_entry_safe(p, n, &entry->children, list) 779 snd_info_free_entry(p); 780 781 p = entry->parent; 782 if (p) { 783 mutex_lock(&p->access); 784 list_del(&entry->list); 785 mutex_unlock(&p->access); 786 } 787 kfree(entry->name); 788 if (entry->private_free) 789 entry->private_free(entry); 790 kfree(entry); 791 } 792 EXPORT_SYMBOL(snd_info_free_entry); 793 794 static int __snd_info_register(struct snd_info_entry *entry) 795 { 796 struct proc_dir_entry *root, *p = NULL; 797 798 if (snd_BUG_ON(!entry)) 799 return -ENXIO; 800 root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p; 801 mutex_lock(&info_mutex); 802 if (entry->p || !root) 803 goto unlock; 804 if (S_ISDIR(entry->mode)) { 805 p = proc_mkdir_mode(entry->name, entry->mode, root); 806 if (!p) { 807 mutex_unlock(&info_mutex); 808 return -ENOMEM; 809 } 810 } else { 811 const struct proc_ops *ops; 812 if (entry->content == SNDRV_INFO_CONTENT_DATA) 813 ops = &snd_info_entry_operations; 814 else 815 ops = &snd_info_text_entry_ops; 816 p = proc_create_data(entry->name, entry->mode, root, 817 ops, entry); 818 if (!p) { 819 mutex_unlock(&info_mutex); 820 return -ENOMEM; 821 } 822 proc_set_size(p, entry->size); 823 } 824 entry->p = p; 825 unlock: 826 mutex_unlock(&info_mutex); 827 return 0; 828 } 829 830 /** 831 * snd_info_register - register the info entry 832 * @entry: the info entry 833 * 834 * Registers the proc info entry. 835 * The all children entries are registered recursively. 836 * 837 * Return: Zero if successful, or a negative error code on failure. 838 */ 839 int snd_info_register(struct snd_info_entry *entry) 840 { 841 struct snd_info_entry *p; 842 int err; 843 844 if (!entry->p) { 845 err = __snd_info_register(entry); 846 if (err < 0) 847 return err; 848 } 849 850 list_for_each_entry(p, &entry->children, list) { 851 err = snd_info_register(p); 852 if (err < 0) 853 return err; 854 } 855 856 return 0; 857 } 858 EXPORT_SYMBOL(snd_info_register); 859 860 /** 861 * snd_card_rw_proc_new - Create a read/write text proc file entry for the card 862 * @card: the card instance 863 * @name: the file name 864 * @private_data: the arbitrary private data 865 * @read: the read callback 866 * @write: the write callback, NULL for read-only 867 * 868 * This proc file entry will be registered via snd_card_register() call, and 869 * it will be removed automatically at the card removal, too. 870 */ 871 int snd_card_rw_proc_new(struct snd_card *card, const char *name, 872 void *private_data, 873 void (*read)(struct snd_info_entry *, 874 struct snd_info_buffer *), 875 void (*write)(struct snd_info_entry *entry, 876 struct snd_info_buffer *buffer)) 877 { 878 struct snd_info_entry *entry; 879 880 entry = snd_info_create_card_entry(card, name, card->proc_root); 881 if (!entry) 882 return -ENOMEM; 883 snd_info_set_text_ops(entry, private_data, read); 884 if (write) { 885 entry->mode |= 0200; 886 entry->c.text.write = write; 887 } 888 return 0; 889 } 890 EXPORT_SYMBOL_GPL(snd_card_rw_proc_new); 891 892 /* 893 894 */ 895 896 static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 897 { 898 snd_iprintf(buffer, 899 "Advanced Linux Sound Architecture Driver Version k%s.\n", 900 init_utsname()->release); 901 } 902 903 static int __init snd_info_version_init(void) 904 { 905 struct snd_info_entry *entry; 906 907 entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL); 908 if (entry == NULL) 909 return -ENOMEM; 910 entry->c.text.read = snd_info_version_read; 911 return snd_info_register(entry); /* freed in error path */ 912 } 913