linux/sound/core/info.c
<<
>>
Prefs
   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/smp_lock.h>
  26#include <linux/string.h>
  27#include <sound/core.h>
  28#include <sound/minors.h>
  29#include <sound/info.h>
  30#include <sound/version.h>
  31#include <linux/proc_fs.h>
  32#include <linux/mutex.h>
  33#include <stdarg.h>
  34
  35/*
  36 *
  37 */
  38
  39#ifdef CONFIG_PROC_FS
  40
  41int snd_info_check_reserved_words(const char *str)
  42{
  43        static char *reserved[] =
  44        {
  45                "version",
  46                "meminfo",
  47                "memdebug",
  48                "detect",
  49                "devices",
  50                "oss",
  51                "cards",
  52                "timers",
  53                "synth",
  54                "pcm",
  55                "seq",
  56                NULL
  57        };
  58        char **xstr = reserved;
  59
  60        while (*xstr) {
  61                if (!strcmp(*xstr, str))
  62                        return 0;
  63                xstr++;
  64        }
  65        if (!strncmp(str, "card", 4))
  66                return 0;
  67        return 1;
  68}
  69
  70static DEFINE_MUTEX(info_mutex);
  71
  72struct snd_info_private_data {
  73        struct snd_info_buffer *rbuffer;
  74        struct snd_info_buffer *wbuffer;
  75        struct snd_info_entry *entry;
  76        void *file_private_data;
  77};
  78
  79static int snd_info_version_init(void);
  80static int snd_info_version_done(void);
  81static void snd_info_disconnect(struct snd_info_entry *entry);
  82
  83
  84/* resize the proc r/w buffer */
  85static int resize_info_buffer(struct snd_info_buffer *buffer,
  86                              unsigned int nsize)
  87{
  88        char *nbuf;
  89
  90        nsize = PAGE_ALIGN(nsize);
  91        nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL);
  92        if (! nbuf)
  93                return -ENOMEM;
  94
  95        buffer->buffer = nbuf;
  96        buffer->len = nsize;
  97        return 0;
  98}
  99
 100/**
 101 * snd_iprintf - printf on the procfs buffer
 102 * @buffer: the procfs buffer
 103 * @fmt: the printf format
 104 *
 105 * Outputs the string on the procfs buffer just like printf().
 106 *
 107 * Returns the size of output string.
 108 */
 109int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
 110{
 111        va_list args;
 112        int len, res;
 113        int err = 0;
 114
 115        might_sleep();
 116        if (buffer->stop || buffer->error)
 117                return 0;
 118        len = buffer->len - buffer->size;
 119        va_start(args, fmt);
 120        for (;;) {
 121                va_list ap;
 122                va_copy(ap, args);
 123                res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, ap);
 124                va_end(ap);
 125                if (res < len)
 126                        break;
 127                err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
 128                if (err < 0)
 129                        break;
 130                len = buffer->len - buffer->size;
 131        }
 132        va_end(args);
 133
 134        if (err < 0)
 135                return err;
 136        buffer->curr += res;
 137        buffer->size += res;
 138        return res;
 139}
 140
 141EXPORT_SYMBOL(snd_iprintf);
 142
 143/*
 144
 145 */
 146
 147static struct proc_dir_entry *snd_proc_root;
 148struct snd_info_entry *snd_seq_root;
 149EXPORT_SYMBOL(snd_seq_root);
 150
 151#ifdef CONFIG_SND_OSSEMUL
 152struct snd_info_entry *snd_oss_root;
 153#endif
 154
 155static void snd_remove_proc_entry(struct proc_dir_entry *parent,
 156                                  struct proc_dir_entry *de)
 157{
 158        if (de)
 159                remove_proc_entry(de->name, parent);
 160}
 161
 162static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
 163{
 164        struct snd_info_private_data *data;
 165        struct snd_info_entry *entry;
 166        loff_t ret;
 167
 168        data = file->private_data;
 169        entry = data->entry;
 170        lock_kernel();
 171        switch (entry->content) {
 172        case SNDRV_INFO_CONTENT_TEXT:
 173                switch (orig) {
 174                case SEEK_SET:
 175                        file->f_pos = offset;
 176                        ret = file->f_pos;
 177                        goto out;
 178                case SEEK_CUR:
 179                        file->f_pos += offset;
 180                        ret = file->f_pos;
 181                        goto out;
 182                case SEEK_END:
 183                default:
 184                        ret = -EINVAL;
 185                        goto out;
 186                }
 187                break;
 188        case SNDRV_INFO_CONTENT_DATA:
 189                if (entry->c.ops->llseek) {
 190                        ret = entry->c.ops->llseek(entry,
 191                                                    data->file_private_data,
 192                                                    file, offset, orig);
 193                        goto out;
 194                }
 195                break;
 196        }
 197        ret = -ENXIO;
 198out:
 199        unlock_kernel();
 200        return ret;
 201}
 202
 203static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
 204                                   size_t count, loff_t * offset)
 205{
 206        struct snd_info_private_data *data;
 207        struct snd_info_entry *entry;
 208        struct snd_info_buffer *buf;
 209        size_t size = 0;
 210        loff_t pos;
 211
 212        data = file->private_data;
 213        if (snd_BUG_ON(!data))
 214                return -ENXIO;
 215        pos = *offset;
 216        if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
 217                return -EIO;
 218        if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
 219                return -EIO;
 220        entry = data->entry;
 221        switch (entry->content) {
 222        case SNDRV_INFO_CONTENT_TEXT:
 223                buf = data->rbuffer;
 224                if (buf == NULL)
 225                        return -EIO;
 226                if (pos >= buf->size)
 227                        return 0;
 228                size = buf->size - pos;
 229                size = min(count, size);
 230                if (copy_to_user(buffer, buf->buffer + pos, size))
 231                        return -EFAULT;
 232                break;
 233        case SNDRV_INFO_CONTENT_DATA:
 234                if (entry->c.ops->read)
 235                        size = entry->c.ops->read(entry,
 236                                                  data->file_private_data,
 237                                                  file, buffer, count, pos);
 238                break;
 239        }
 240        if ((ssize_t) size > 0)
 241                *offset = pos + size;
 242        return size;
 243}
 244
 245static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
 246                                    size_t count, loff_t * offset)
 247{
 248        struct snd_info_private_data *data;
 249        struct snd_info_entry *entry;
 250        struct snd_info_buffer *buf;
 251        ssize_t size = 0;
 252        loff_t pos;
 253
 254        data = file->private_data;
 255        if (snd_BUG_ON(!data))
 256                return -ENXIO;
 257        entry = data->entry;
 258        pos = *offset;
 259        if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
 260                return -EIO;
 261        if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
 262                return -EIO;
 263        switch (entry->content) {
 264        case SNDRV_INFO_CONTENT_TEXT:
 265                buf = data->wbuffer;
 266                if (buf == NULL)
 267                        return -EIO;
 268                mutex_lock(&entry->access);
 269                if (pos + count >= buf->len) {
 270                        if (resize_info_buffer(buf, pos + count)) {
 271                                mutex_unlock(&entry->access);
 272                                return -ENOMEM;
 273                        }
 274                }
 275                if (copy_from_user(buf->buffer + pos, buffer, count)) {
 276                        mutex_unlock(&entry->access);
 277                        return -EFAULT;
 278                }
 279                buf->size = pos + count;
 280                mutex_unlock(&entry->access);
 281                size = count;
 282                break;
 283        case SNDRV_INFO_CONTENT_DATA:
 284                if (entry->c.ops->write)
 285                        size = entry->c.ops->write(entry,
 286                                                   data->file_private_data,
 287                                                   file, buffer, count, pos);
 288                break;
 289        }
 290        if ((ssize_t) size > 0)
 291                *offset = pos + size;
 292        return size;
 293}
 294
 295static int snd_info_entry_open(struct inode *inode, struct file *file)
 296{
 297        struct snd_info_entry *entry;
 298        struct snd_info_private_data *data;
 299        struct snd_info_buffer *buffer;
 300        struct proc_dir_entry *p;
 301        int mode, err;
 302
 303        mutex_lock(&info_mutex);
 304        p = PDE(inode);
 305        entry = p == NULL ? NULL : (struct snd_info_entry *)p->data;
 306        if (entry == NULL || ! entry->p) {
 307                mutex_unlock(&info_mutex);
 308                return -ENODEV;
 309        }
 310        if (!try_module_get(entry->module)) {
 311                err = -EFAULT;
 312                goto __error1;
 313        }
 314        mode = file->f_flags & O_ACCMODE;
 315        if (mode == O_RDONLY || mode == O_RDWR) {
 316                if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
 317                     entry->c.ops->read == NULL)) {
 318                        err = -ENODEV;
 319                        goto __error;
 320                }
 321        }
 322        if (mode == O_WRONLY || mode == O_RDWR) {
 323                if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
 324                     entry->c.ops->write == NULL)) {
 325                        err = -ENODEV;
 326                        goto __error;
 327                }
 328        }
 329        data = kzalloc(sizeof(*data), GFP_KERNEL);
 330        if (data == NULL) {
 331                err = -ENOMEM;
 332                goto __error;
 333        }
 334        data->entry = entry;
 335        switch (entry->content) {
 336        case SNDRV_INFO_CONTENT_TEXT:
 337                if (mode == O_RDONLY || mode == O_RDWR) {
 338                        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
 339                        if (buffer == NULL)
 340                                goto __nomem;
 341                        data->rbuffer = buffer;
 342                        buffer->len = PAGE_SIZE;
 343                        buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
 344                        if (buffer->buffer == NULL)
 345                                goto __nomem;
 346                }
 347                if (mode == O_WRONLY || mode == O_RDWR) {
 348                        buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
 349                        if (buffer == NULL)
 350                                goto __nomem;
 351                        data->wbuffer = buffer;
 352                        buffer->len = PAGE_SIZE;
 353                        buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
 354                        if (buffer->buffer == NULL)
 355                                goto __nomem;
 356                }
 357                break;
 358        case SNDRV_INFO_CONTENT_DATA:   /* data */
 359                if (entry->c.ops->open) {
 360                        if ((err = entry->c.ops->open(entry, mode,
 361                                                      &data->file_private_data)) < 0) {
 362                                kfree(data);
 363                                goto __error;
 364                        }
 365                }
 366                break;
 367        }
 368        file->private_data = data;
 369        mutex_unlock(&info_mutex);
 370        if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
 371            (mode == O_RDONLY || mode == O_RDWR)) {
 372                if (entry->c.text.read) {
 373                        mutex_lock(&entry->access);
 374                        entry->c.text.read(entry, data->rbuffer);
 375                        mutex_unlock(&entry->access);
 376                }
 377        }
 378        return 0;
 379
 380 __nomem:
 381        if (data->rbuffer) {
 382                kfree(data->rbuffer->buffer);
 383                kfree(data->rbuffer);
 384        }
 385        if (data->wbuffer) {
 386                kfree(data->wbuffer->buffer);
 387                kfree(data->wbuffer);
 388        }
 389        kfree(data);
 390        err = -ENOMEM;
 391      __error:
 392        module_put(entry->module);
 393      __error1:
 394        mutex_unlock(&info_mutex);
 395        return err;
 396}
 397
 398static int snd_info_entry_release(struct inode *inode, struct file *file)
 399{
 400        struct snd_info_entry *entry;
 401        struct snd_info_private_data *data;
 402        int mode;
 403
 404        mode = file->f_flags & O_ACCMODE;
 405        data = file->private_data;
 406        entry = data->entry;
 407        switch (entry->content) {
 408        case SNDRV_INFO_CONTENT_TEXT:
 409                if (data->rbuffer) {
 410                        kfree(data->rbuffer->buffer);
 411                        kfree(data->rbuffer);
 412                }
 413                if (data->wbuffer) {
 414                        if (entry->c.text.write) {
 415                                entry->c.text.write(entry, data->wbuffer);
 416                                if (data->wbuffer->error) {
 417                                        snd_printk(KERN_WARNING "data write error to %s (%i)\n",
 418                                                entry->name,
 419                                                data->wbuffer->error);
 420                                }
 421                        }
 422                        kfree(data->wbuffer->buffer);
 423                        kfree(data->wbuffer);
 424                }
 425                break;
 426        case SNDRV_INFO_CONTENT_DATA:
 427                if (entry->c.ops->release)
 428                        entry->c.ops->release(entry, mode,
 429                                              data->file_private_data);
 430                break;
 431        }
 432        module_put(entry->module);
 433        kfree(data);
 434        return 0;
 435}
 436
 437static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait)
 438{
 439        struct snd_info_private_data *data;
 440        struct snd_info_entry *entry;
 441        unsigned int mask;
 442
 443        data = file->private_data;
 444        if (data == NULL)
 445                return 0;
 446        entry = data->entry;
 447        mask = 0;
 448        switch (entry->content) {
 449        case SNDRV_INFO_CONTENT_DATA:
 450                if (entry->c.ops->poll)
 451                        return entry->c.ops->poll(entry,
 452                                                  data->file_private_data,
 453                                                  file, wait);
 454                if (entry->c.ops->read)
 455                        mask |= POLLIN | POLLRDNORM;
 456                if (entry->c.ops->write)
 457                        mask |= POLLOUT | POLLWRNORM;
 458                break;
 459        }
 460        return mask;
 461}
 462
 463static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
 464                                unsigned long arg)
 465{
 466        struct snd_info_private_data *data;
 467        struct snd_info_entry *entry;
 468
 469        data = file->private_data;
 470        if (data == NULL)
 471                return 0;
 472        entry = data->entry;
 473        switch (entry->content) {
 474        case SNDRV_INFO_CONTENT_DATA:
 475                if (entry->c.ops->ioctl)
 476                        return entry->c.ops->ioctl(entry,
 477                                                   data->file_private_data,
 478                                                   file, cmd, arg);
 479                break;
 480        }
 481        return -ENOTTY;
 482}
 483
 484static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
 485{
 486        struct inode *inode = file->f_path.dentry->d_inode;
 487        struct snd_info_private_data *data;
 488        struct snd_info_entry *entry;
 489
 490        data = file->private_data;
 491        if (data == NULL)
 492                return 0;
 493        entry = data->entry;
 494        switch (entry->content) {
 495        case SNDRV_INFO_CONTENT_DATA:
 496                if (entry->c.ops->mmap)
 497                        return entry->c.ops->mmap(entry,
 498                                                  data->file_private_data,
 499                                                  inode, file, vma);
 500                break;
 501        }
 502        return -ENXIO;
 503}
 504
 505static const struct file_operations snd_info_entry_operations =
 506{
 507        .owner =                THIS_MODULE,
 508        .llseek =               snd_info_entry_llseek,
 509        .read =                 snd_info_entry_read,
 510        .write =                snd_info_entry_write,
 511        .poll =                 snd_info_entry_poll,
 512        .unlocked_ioctl =       snd_info_entry_ioctl,
 513        .mmap =                 snd_info_entry_mmap,
 514        .open =                 snd_info_entry_open,
 515        .release =              snd_info_entry_release,
 516};
 517
 518int __init snd_info_init(void)
 519{
 520        struct proc_dir_entry *p;
 521
 522        p = create_proc_entry("asound", S_IFDIR | S_IRUGO | S_IXUGO, NULL);
 523        if (p == NULL)
 524                return -ENOMEM;
 525        snd_proc_root = p;
 526#ifdef CONFIG_SND_OSSEMUL
 527        {
 528                struct snd_info_entry *entry;
 529                if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
 530                        return -ENOMEM;
 531                entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
 532                if (snd_info_register(entry) < 0) {
 533                        snd_info_free_entry(entry);
 534                        return -ENOMEM;
 535                }
 536                snd_oss_root = entry;
 537        }
 538#endif
 539#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 540        {
 541                struct snd_info_entry *entry;
 542                if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL)
 543                        return -ENOMEM;
 544                entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
 545                if (snd_info_register(entry) < 0) {
 546                        snd_info_free_entry(entry);
 547                        return -ENOMEM;
 548                }
 549                snd_seq_root = entry;
 550        }
 551#endif
 552        snd_info_version_init();
 553        snd_minor_info_init();
 554        snd_minor_info_oss_init();
 555        snd_card_info_init();
 556        return 0;
 557}
 558
 559int __exit snd_info_done(void)
 560{
 561        snd_card_info_done();
 562        snd_minor_info_oss_done();
 563        snd_minor_info_done();
 564        snd_info_version_done();
 565        if (snd_proc_root) {
 566#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE)
 567                snd_info_free_entry(snd_seq_root);
 568#endif
 569#ifdef CONFIG_SND_OSSEMUL
 570                snd_info_free_entry(snd_oss_root);
 571#endif
 572                snd_remove_proc_entry(NULL, snd_proc_root);
 573        }
 574        return 0;
 575}
 576
 577/*
 578
 579 */
 580
 581
 582/*
 583 * create a card proc file
 584 * called from init.c
 585 */
 586int snd_info_card_create(struct snd_card *card)
 587{
 588        char str[8];
 589        struct snd_info_entry *entry;
 590
 591        if (snd_BUG_ON(!card))
 592                return -ENXIO;
 593
 594        sprintf(str, "card%i", card->number);
 595        if ((entry = snd_info_create_module_entry(card->module, str, NULL)) == NULL)
 596                return -ENOMEM;
 597        entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
 598        if (snd_info_register(entry) < 0) {
 599                snd_info_free_entry(entry);
 600                return -ENOMEM;
 601        }
 602        card->proc_root = entry;
 603        return 0;
 604}
 605
 606/*
 607 * register the card proc file
 608 * called from init.c
 609 */
 610int snd_info_card_register(struct snd_card *card)
 611{
 612        struct proc_dir_entry *p;
 613
 614        if (snd_BUG_ON(!card))
 615                return -ENXIO;
 616
 617        if (!strcmp(card->id, card->proc_root->name))
 618                return 0;
 619
 620        p = proc_symlink(card->id, snd_proc_root, card->proc_root->name);
 621        if (p == NULL)
 622                return -ENOMEM;
 623        card->proc_root_link = p;
 624        return 0;
 625}
 626
 627/*
 628 * called on card->id change
 629 */
 630void snd_info_card_id_change(struct snd_card *card)
 631{
 632        mutex_lock(&info_mutex);
 633        if (card->proc_root_link) {
 634                snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
 635                card->proc_root_link = NULL;
 636        }
 637        if (strcmp(card->id, card->proc_root->name))
 638                card->proc_root_link = proc_symlink(card->id,
 639                                                    snd_proc_root,
 640                                                    card->proc_root->name);
 641        mutex_unlock(&info_mutex);
 642}
 643
 644/*
 645 * de-register the card proc file
 646 * called from init.c
 647 */
 648void snd_info_card_disconnect(struct snd_card *card)
 649{
 650        if (!card)
 651                return;
 652        mutex_lock(&info_mutex);
 653        if (card->proc_root_link) {
 654                snd_remove_proc_entry(snd_proc_root, card->proc_root_link);
 655                card->proc_root_link = NULL;
 656        }
 657        if (card->proc_root)
 658                snd_info_disconnect(card->proc_root);
 659        mutex_unlock(&info_mutex);
 660}
 661
 662/*
 663 * release the card proc file resources
 664 * called from init.c
 665 */
 666int snd_info_card_free(struct snd_card *card)
 667{
 668        if (!card)
 669                return 0;
 670        snd_info_free_entry(card->proc_root);
 671        card->proc_root = NULL;
 672        return 0;
 673}
 674
 675
 676/**
 677 * snd_info_get_line - read one line from the procfs buffer
 678 * @buffer: the procfs buffer
 679 * @line: the buffer to store
 680 * @len: the max. buffer size - 1
 681 *
 682 * Reads one line from the buffer and stores the string.
 683 *
 684 * Returns zero if successful, or 1 if error or EOF.
 685 */
 686int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
 687{
 688        int c = -1;
 689
 690        if (len <= 0 || buffer->stop || buffer->error)
 691                return 1;
 692        while (--len > 0) {
 693                c = buffer->buffer[buffer->curr++];
 694                if (c == '\n') {
 695                        if (buffer->curr >= buffer->size)
 696                                buffer->stop = 1;
 697                        break;
 698                }
 699                *line++ = c;
 700                if (buffer->curr >= buffer->size) {
 701                        buffer->stop = 1;
 702                        break;
 703                }
 704        }
 705        while (c != '\n' && !buffer->stop) {
 706                c = buffer->buffer[buffer->curr++];
 707                if (buffer->curr >= buffer->size)
 708                        buffer->stop = 1;
 709        }
 710        *line = '\0';
 711        return 0;
 712}
 713
 714EXPORT_SYMBOL(snd_info_get_line);
 715
 716/**
 717 * snd_info_get_str - parse a string token
 718 * @dest: the buffer to store the string token
 719 * @src: the original string
 720 * @len: the max. length of token - 1
 721 *
 722 * Parses the original string and copy a token to the given
 723 * string buffer.
 724 *
 725 * Returns the updated pointer of the original string so that
 726 * it can be used for the next call.
 727 */
 728const char *snd_info_get_str(char *dest, const char *src, int len)
 729{
 730        int c;
 731
 732        while (*src == ' ' || *src == '\t')
 733                src++;
 734        if (*src == '"' || *src == '\'') {
 735                c = *src++;
 736                while (--len > 0 && *src && *src != c) {
 737                        *dest++ = *src++;
 738                }
 739                if (*src == c)
 740                        src++;
 741        } else {
 742                while (--len > 0 && *src && *src != ' ' && *src != '\t') {
 743                        *dest++ = *src++;
 744                }
 745        }
 746        *dest = 0;
 747        while (*src == ' ' || *src == '\t')
 748                src++;
 749        return src;
 750}
 751
 752EXPORT_SYMBOL(snd_info_get_str);
 753
 754/**
 755 * snd_info_create_entry - create an info entry
 756 * @name: the proc file name
 757 *
 758 * Creates an info entry with the given file name and initializes as
 759 * the default state.
 760 *
 761 * Usually called from other functions such as
 762 * snd_info_create_card_entry().
 763 *
 764 * Returns the pointer of the new instance, or NULL on failure.
 765 */
 766static struct snd_info_entry *snd_info_create_entry(const char *name)
 767{
 768        struct snd_info_entry *entry;
 769        entry = kzalloc(sizeof(*entry), GFP_KERNEL);
 770        if (entry == NULL)
 771                return NULL;
 772        entry->name = kstrdup(name, GFP_KERNEL);
 773        if (entry->name == NULL) {
 774                kfree(entry);
 775                return NULL;
 776        }
 777        entry->mode = S_IFREG | S_IRUGO;
 778        entry->content = SNDRV_INFO_CONTENT_TEXT;
 779        mutex_init(&entry->access);
 780        INIT_LIST_HEAD(&entry->children);
 781        INIT_LIST_HEAD(&entry->list);
 782        return entry;
 783}
 784
 785/**
 786 * snd_info_create_module_entry - create an info entry for the given module
 787 * @module: the module pointer
 788 * @name: the file name
 789 * @parent: the parent directory
 790 *
 791 * Creates a new info entry and assigns it to the given module.
 792 *
 793 * Returns the pointer of the new instance, or NULL on failure.
 794 */
 795struct snd_info_entry *snd_info_create_module_entry(struct module * module,
 796                                               const char *name,
 797                                               struct snd_info_entry *parent)
 798{
 799        struct snd_info_entry *entry = snd_info_create_entry(name);
 800        if (entry) {
 801                entry->module = module;
 802                entry->parent = parent;
 803        }
 804        return entry;
 805}
 806
 807EXPORT_SYMBOL(snd_info_create_module_entry);
 808
 809/**
 810 * snd_info_create_card_entry - create an info entry for the given card
 811 * @card: the card instance
 812 * @name: the file name
 813 * @parent: the parent directory
 814 *
 815 * Creates a new info entry and assigns it to the given card.
 816 *
 817 * Returns the pointer of the new instance, or NULL on failure.
 818 */
 819struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
 820                                             const char *name,
 821                                             struct snd_info_entry * parent)
 822{
 823        struct snd_info_entry *entry = snd_info_create_entry(name);
 824        if (entry) {
 825                entry->module = card->module;
 826                entry->card = card;
 827                entry->parent = parent;
 828        }
 829        return entry;
 830}
 831
 832EXPORT_SYMBOL(snd_info_create_card_entry);
 833
 834static void snd_info_disconnect(struct snd_info_entry *entry)
 835{
 836        struct list_head *p, *n;
 837        struct proc_dir_entry *root;
 838
 839        list_for_each_safe(p, n, &entry->children) {
 840                snd_info_disconnect(list_entry(p, struct snd_info_entry, list));
 841        }
 842
 843        if (! entry->p)
 844                return;
 845        list_del_init(&entry->list);
 846        root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
 847        snd_BUG_ON(!root);
 848        snd_remove_proc_entry(root, entry->p);
 849        entry->p = NULL;
 850}
 851
 852static int snd_info_dev_free_entry(struct snd_device *device)
 853{
 854        struct snd_info_entry *entry = device->device_data;
 855        snd_info_free_entry(entry);
 856        return 0;
 857}
 858
 859static int snd_info_dev_register_entry(struct snd_device *device)
 860{
 861        struct snd_info_entry *entry = device->device_data;
 862        return snd_info_register(entry);
 863}
 864
 865/**
 866 * snd_card_proc_new - create an info entry for the given card
 867 * @card: the card instance
 868 * @name: the file name
 869 * @entryp: the pointer to store the new info entry
 870 *
 871 * Creates a new info entry and assigns it to the given card.
 872 * Unlike snd_info_create_card_entry(), this function registers the
 873 * info entry as an ALSA device component, so that it can be
 874 * unregistered/released without explicit call.
 875 * Also, you don't have to register this entry via snd_info_register(),
 876 * since this will be registered by snd_card_register() automatically.
 877 *
 878 * The parent is assumed as card->proc_root.
 879 *
 880 * For releasing this entry, use snd_device_free() instead of
 881 * snd_info_free_entry(). 
 882 *
 883 * Returns zero if successful, or a negative error code on failure.
 884 */
 885int snd_card_proc_new(struct snd_card *card, const char *name,
 886                      struct snd_info_entry **entryp)
 887{
 888        static struct snd_device_ops ops = {
 889                .dev_free = snd_info_dev_free_entry,
 890                .dev_register = snd_info_dev_register_entry,
 891                /* disconnect is done via snd_info_card_disconnect() */
 892        };
 893        struct snd_info_entry *entry;
 894        int err;
 895
 896        entry = snd_info_create_card_entry(card, name, card->proc_root);
 897        if (! entry)
 898                return -ENOMEM;
 899        if ((err = snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)) < 0) {
 900                snd_info_free_entry(entry);
 901                return err;
 902        }
 903        if (entryp)
 904                *entryp = entry;
 905        return 0;
 906}
 907
 908EXPORT_SYMBOL(snd_card_proc_new);
 909
 910/**
 911 * snd_info_free_entry - release the info entry
 912 * @entry: the info entry
 913 *
 914 * Releases the info entry.  Don't call this after registered.
 915 */
 916void snd_info_free_entry(struct snd_info_entry * entry)
 917{
 918        if (entry == NULL)
 919                return;
 920        if (entry->p) {
 921                mutex_lock(&info_mutex);
 922                snd_info_disconnect(entry);
 923                mutex_unlock(&info_mutex);
 924        }
 925        kfree(entry->name);
 926        if (entry->private_free)
 927                entry->private_free(entry);
 928        kfree(entry);
 929}
 930
 931EXPORT_SYMBOL(snd_info_free_entry);
 932
 933/**
 934 * snd_info_register - register the info entry
 935 * @entry: the info entry
 936 *
 937 * Registers the proc info entry.
 938 *
 939 * Returns zero if successful, or a negative error code on failure.
 940 */
 941int snd_info_register(struct snd_info_entry * entry)
 942{
 943        struct proc_dir_entry *root, *p = NULL;
 944
 945        if (snd_BUG_ON(!entry))
 946                return -ENXIO;
 947        root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
 948        mutex_lock(&info_mutex);
 949        p = create_proc_entry(entry->name, entry->mode, root);
 950        if (!p) {
 951                mutex_unlock(&info_mutex);
 952                return -ENOMEM;
 953        }
 954        if (!S_ISDIR(entry->mode))
 955                p->proc_fops = &snd_info_entry_operations;
 956        p->size = entry->size;
 957        p->data = entry;
 958        entry->p = p;
 959        if (entry->parent)
 960                list_add_tail(&entry->list, &entry->parent->children);
 961        mutex_unlock(&info_mutex);
 962        return 0;
 963}
 964
 965EXPORT_SYMBOL(snd_info_register);
 966
 967/*
 968
 969 */
 970
 971static struct snd_info_entry *snd_info_version_entry;
 972
 973static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
 974{
 975        snd_iprintf(buffer,
 976                    "Advanced Linux Sound Architecture Driver Version "
 977                    CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"
 978                   );
 979}
 980
 981static int __init snd_info_version_init(void)
 982{
 983        struct snd_info_entry *entry;
 984
 985        entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
 986        if (entry == NULL)
 987                return -ENOMEM;
 988        entry->c.text.read = snd_info_version_read;
 989        if (snd_info_register(entry) < 0) {
 990                snd_info_free_entry(entry);
 991                return -ENOMEM;
 992        }
 993        snd_info_version_entry = entry;
 994        return 0;
 995}
 996
 997static int __exit snd_info_version_done(void)
 998{
 999        snd_info_free_entry(snd_info_version_entry);
1000        return 0;
1001}
1002
1003#endif /* CONFIG_PROC_FS */
1004