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 468 int __init snd_info_init(void) 469 { 470 snd_proc_root = snd_info_create_entry("asound", NULL); 471 if (!snd_proc_root) 472 return -ENOMEM; 473 snd_proc_root->mode = S_IFDIR | 0555; 474 snd_proc_root->p = proc_mkdir("asound", NULL); 475 if (!snd_proc_root->p) 476 goto error; 477 #ifdef CONFIG_SND_OSSEMUL 478 snd_oss_root = create_subdir(THIS_MODULE, "oss"); 479 if (!snd_oss_root) 480 goto error; 481 #endif 482 #if IS_ENABLED(CONFIG_SND_SEQUENCER) 483 snd_seq_root = create_subdir(THIS_MODULE, "seq"); 484 if (!snd_seq_root) 485 goto error; 486 #endif 487 if (snd_info_version_init() < 0 || 488 snd_minor_info_init() < 0 || 489 snd_minor_info_oss_init() < 0 || 490 snd_card_info_init() < 0 || 491 snd_info_minor_register() < 0) 492 goto error; 493 return 0; 494 495 error: 496 snd_info_free_entry(snd_proc_root); 497 return -ENOMEM; 498 } 499 500 int __exit snd_info_done(void) 501 { 502 snd_info_free_entry(snd_proc_root); 503 return 0; 504 } 505 506 /* 507 * create a card proc file 508 * called from init.c 509 */ 510 int snd_info_card_create(struct snd_card *card) 511 { 512 char str[8]; 513 struct snd_info_entry *entry; 514 515 if (snd_BUG_ON(!card)) 516 return -ENXIO; 517 518 sprintf(str, "card%i", card->number); 519 entry = create_subdir(card->module, str); 520 if (!entry) 521 return -ENOMEM; 522 card->proc_root = entry; 523 return 0; 524 } 525 526 /* 527 * register the card proc file 528 * called from init.c 529 * can be called multiple times for reinitialization 530 */ 531 int snd_info_card_register(struct snd_card *card) 532 { 533 struct proc_dir_entry *p; 534 int err; 535 536 if (snd_BUG_ON(!card)) 537 return -ENXIO; 538 539 err = snd_info_register(card->proc_root); 540 if (err < 0) 541 return err; 542 543 if (!strcmp(card->id, card->proc_root->name)) 544 return 0; 545 546 if (card->proc_root_link) 547 return 0; 548 p = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name); 549 if (!p) 550 return -ENOMEM; 551 card->proc_root_link = p; 552 return 0; 553 } 554 555 /* 556 * called on card->id change 557 */ 558 void snd_info_card_id_change(struct snd_card *card) 559 { 560 mutex_lock(&info_mutex); 561 if (card->proc_root_link) { 562 proc_remove(card->proc_root_link); 563 card->proc_root_link = NULL; 564 } 565 if (strcmp(card->id, card->proc_root->name)) 566 card->proc_root_link = proc_symlink(card->id, 567 snd_proc_root->p, 568 card->proc_root->name); 569 mutex_unlock(&info_mutex); 570 } 571 572 /* 573 * de-register the card proc file 574 * called from init.c 575 */ 576 void snd_info_card_disconnect(struct snd_card *card) 577 { 578 if (!card) 579 return; 580 mutex_lock(&info_mutex); 581 proc_remove(card->proc_root_link); 582 card->proc_root_link = NULL; 583 if (card->proc_root) 584 snd_info_disconnect(card->proc_root); 585 mutex_unlock(&info_mutex); 586 } 587 588 /* 589 * release the card proc file resources 590 * called from init.c 591 */ 592 int snd_info_card_free(struct snd_card *card) 593 { 594 if (!card) 595 return 0; 596 snd_info_free_entry(card->proc_root); 597 card->proc_root = NULL; 598 return 0; 599 } 600 601 602 /** 603 * snd_info_get_line - read one line from the procfs buffer 604 * @buffer: the procfs buffer 605 * @line: the buffer to store 606 * @len: the max. buffer size 607 * 608 * Reads one line from the buffer and stores the string. 609 * 610 * Return: Zero if successful, or 1 if error or EOF. 611 */ 612 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) 613 { 614 int c = -1; 615 616 if (snd_BUG_ON(!buffer || !buffer->buffer)) 617 return 1; 618 if (len <= 0 || buffer->stop || buffer->error) 619 return 1; 620 while (!buffer->stop) { 621 c = buffer->buffer[buffer->curr++]; 622 if (buffer->curr >= buffer->size) 623 buffer->stop = 1; 624 if (c == '\n') 625 break; 626 if (len > 1) { 627 len--; 628 *line++ = c; 629 } 630 } 631 *line = '\0'; 632 return 0; 633 } 634 EXPORT_SYMBOL(snd_info_get_line); 635 636 /** 637 * snd_info_get_str - parse a string token 638 * @dest: the buffer to store the string token 639 * @src: the original string 640 * @len: the max. length of token - 1 641 * 642 * Parses the original string and copy a token to the given 643 * string buffer. 644 * 645 * Return: The updated pointer of the original string so that 646 * it can be used for the next call. 647 */ 648 const char *snd_info_get_str(char *dest, const char *src, int len) 649 { 650 int c; 651 652 while (*src == ' ' || *src == '\t') 653 src++; 654 if (*src == '"' || *src == '\'') { 655 c = *src++; 656 while (--len > 0 && *src && *src != c) { 657 *dest++ = *src++; 658 } 659 if (*src == c) 660 src++; 661 } else { 662 while (--len > 0 && *src && *src != ' ' && *src != '\t') { 663 *dest++ = *src++; 664 } 665 } 666 *dest = 0; 667 while (*src == ' ' || *src == '\t') 668 src++; 669 return src; 670 } 671 EXPORT_SYMBOL(snd_info_get_str); 672 673 /* 674 * snd_info_create_entry - create an info entry 675 * @name: the proc file name 676 * @parent: the parent directory 677 * 678 * Creates an info entry with the given file name and initializes as 679 * the default state. 680 * 681 * Usually called from other functions such as 682 * snd_info_create_card_entry(). 683 * 684 * Return: The pointer of the new instance, or %NULL on failure. 685 */ 686 static struct snd_info_entry * 687 snd_info_create_entry(const char *name, struct snd_info_entry *parent) 688 { 689 struct snd_info_entry *entry; 690 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 691 if (entry == NULL) 692 return NULL; 693 entry->name = kstrdup(name, GFP_KERNEL); 694 if (entry->name == NULL) { 695 kfree(entry); 696 return NULL; 697 } 698 entry->mode = S_IFREG | 0444; 699 entry->content = SNDRV_INFO_CONTENT_TEXT; 700 mutex_init(&entry->access); 701 INIT_LIST_HEAD(&entry->children); 702 INIT_LIST_HEAD(&entry->list); 703 entry->parent = parent; 704 if (parent) 705 list_add_tail(&entry->list, &parent->children); 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 struct snd_info_entry *entry; 724 725 if (!parent) 726 parent = snd_proc_root; 727 entry = snd_info_create_entry(name, parent); 728 if (entry) 729 entry->module = module; 730 return entry; 731 } 732 EXPORT_SYMBOL(snd_info_create_module_entry); 733 734 /** 735 * snd_info_create_card_entry - create an info entry for the given card 736 * @card: the card instance 737 * @name: the file name 738 * @parent: the parent directory 739 * 740 * Creates a new info entry and assigns it to the given card. 741 * 742 * Return: The pointer of the new instance, or %NULL on failure. 743 */ 744 struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, 745 const char *name, 746 struct snd_info_entry * parent) 747 { 748 struct snd_info_entry *entry; 749 750 if (!parent) 751 parent = card->proc_root; 752 entry = snd_info_create_entry(name, parent); 753 if (entry) { 754 entry->module = card->module; 755 entry->card = card; 756 } 757 return entry; 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