| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Initialization routines |
|---|
| 3 | 4 | * 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 | 5 | */ |
|---|
| 21 | 6 | |
|---|
| 22 | 7 | #include <linux/init.h> |
|---|
| .. | .. |
|---|
| 29 | 14 | #include <linux/ctype.h> |
|---|
| 30 | 15 | #include <linux/pm.h> |
|---|
| 31 | 16 | #include <linux/completion.h> |
|---|
| 17 | +#include <linux/interrupt.h> |
|---|
| 32 | 18 | |
|---|
| 33 | 19 | #include <sound/core.h> |
|---|
| 34 | 20 | #include <sound/control.h> |
|---|
| .. | .. |
|---|
| 49 | 35 | |
|---|
| 50 | 36 | /* locked for registering/using */ |
|---|
| 51 | 37 | static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS); |
|---|
| 52 | | -struct snd_card *snd_cards[SNDRV_CARDS]; |
|---|
| 53 | | -EXPORT_SYMBOL(snd_cards); |
|---|
| 38 | +static struct snd_card *snd_cards[SNDRV_CARDS]; |
|---|
| 54 | 39 | |
|---|
| 55 | 40 | static DEFINE_MUTEX(snd_card_mutex); |
|---|
| 56 | 41 | |
|---|
| .. | .. |
|---|
| 98 | 83 | #if IS_ENABLED(CONFIG_SND_MIXER_OSS) |
|---|
| 99 | 84 | int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag); |
|---|
| 100 | 85 | EXPORT_SYMBOL(snd_mixer_oss_notify_callback); |
|---|
| 101 | | -#endif |
|---|
| 102 | | - |
|---|
| 103 | | -#ifdef CONFIG_SND_PROC_FS |
|---|
| 104 | | -static void snd_card_id_read(struct snd_info_entry *entry, |
|---|
| 105 | | - struct snd_info_buffer *buffer) |
|---|
| 106 | | -{ |
|---|
| 107 | | - snd_iprintf(buffer, "%s\n", entry->card->id); |
|---|
| 108 | | -} |
|---|
| 109 | | - |
|---|
| 110 | | -static int init_info_for_card(struct snd_card *card) |
|---|
| 111 | | -{ |
|---|
| 112 | | - struct snd_info_entry *entry; |
|---|
| 113 | | - |
|---|
| 114 | | - entry = snd_info_create_card_entry(card, "id", card->proc_root); |
|---|
| 115 | | - if (!entry) { |
|---|
| 116 | | - dev_dbg(card->dev, "unable to create card entry\n"); |
|---|
| 117 | | - return -ENOMEM; |
|---|
| 118 | | - } |
|---|
| 119 | | - entry->c.text.read = snd_card_id_read; |
|---|
| 120 | | - card->proc_id = entry; |
|---|
| 121 | | - |
|---|
| 122 | | - return snd_info_card_register(card); |
|---|
| 123 | | -} |
|---|
| 124 | | -#else /* !CONFIG_SND_PROC_FS */ |
|---|
| 125 | | -#define init_info_for_card(card) |
|---|
| 126 | 86 | #endif |
|---|
| 127 | 87 | |
|---|
| 128 | 88 | static int check_empty_slot(struct module *module, int slot) |
|---|
| .. | .. |
|---|
| 244 | 204 | mutex_unlock(&snd_card_mutex); |
|---|
| 245 | 205 | card->dev = parent; |
|---|
| 246 | 206 | card->number = idx; |
|---|
| 207 | +#ifdef MODULE |
|---|
| 208 | + WARN_ON(!module); |
|---|
| 247 | 209 | card->module = module; |
|---|
| 210 | +#endif |
|---|
| 248 | 211 | INIT_LIST_HEAD(&card->devices); |
|---|
| 249 | 212 | init_rwsem(&card->controls_rwsem); |
|---|
| 250 | 213 | rwlock_init(&card->ctl_files_rwlock); |
|---|
| .. | .. |
|---|
| 252 | 215 | INIT_LIST_HEAD(&card->ctl_files); |
|---|
| 253 | 216 | spin_lock_init(&card->files_lock); |
|---|
| 254 | 217 | INIT_LIST_HEAD(&card->files_list); |
|---|
| 218 | + mutex_init(&card->memory_mutex); |
|---|
| 255 | 219 | #ifdef CONFIG_PM |
|---|
| 256 | 220 | init_waitqueue_head(&card->power_sleep); |
|---|
| 257 | 221 | #endif |
|---|
| 258 | 222 | init_waitqueue_head(&card->remove_sleep); |
|---|
| 223 | + card->sync_irq = -1; |
|---|
| 259 | 224 | |
|---|
| 260 | | - init_waitqueue_head(&card->offline_poll_wait); |
|---|
| 261 | 225 | device_initialize(&card->card_dev); |
|---|
| 262 | 226 | card->card_dev.parent = parent; |
|---|
| 263 | 227 | card->card_dev.class = sound_class; |
|---|
| .. | .. |
|---|
| 293 | 257 | return err; |
|---|
| 294 | 258 | } |
|---|
| 295 | 259 | EXPORT_SYMBOL(snd_card_new); |
|---|
| 260 | + |
|---|
| 261 | +/** |
|---|
| 262 | + * snd_card_ref - Get the card object from the index |
|---|
| 263 | + * @idx: the card index |
|---|
| 264 | + * |
|---|
| 265 | + * Returns a card object corresponding to the given index or NULL if not found. |
|---|
| 266 | + * Release the object via snd_card_unref(). |
|---|
| 267 | + */ |
|---|
| 268 | +struct snd_card *snd_card_ref(int idx) |
|---|
| 269 | +{ |
|---|
| 270 | + struct snd_card *card; |
|---|
| 271 | + |
|---|
| 272 | + mutex_lock(&snd_card_mutex); |
|---|
| 273 | + card = snd_cards[idx]; |
|---|
| 274 | + if (card) |
|---|
| 275 | + get_device(&card->card_dev); |
|---|
| 276 | + mutex_unlock(&snd_card_mutex); |
|---|
| 277 | + return card; |
|---|
| 278 | +} |
|---|
| 279 | +EXPORT_SYMBOL_GPL(snd_card_ref); |
|---|
| 296 | 280 | |
|---|
| 297 | 281 | /* return non-zero if a card is already locked */ |
|---|
| 298 | 282 | int snd_card_locked(int card) |
|---|
| .. | .. |
|---|
| 433 | 417 | /* notify all devices that we are disconnected */ |
|---|
| 434 | 418 | snd_device_disconnect_all(card); |
|---|
| 435 | 419 | |
|---|
| 420 | + if (card->sync_irq > 0) |
|---|
| 421 | + synchronize_irq(card->sync_irq); |
|---|
| 422 | + |
|---|
| 436 | 423 | snd_info_card_disconnect(card); |
|---|
| 437 | 424 | if (card->registered) { |
|---|
| 438 | 425 | device_del(&card->card_dev); |
|---|
| .. | .. |
|---|
| 490 | 477 | snd_device_free_all(card); |
|---|
| 491 | 478 | if (card->private_free) |
|---|
| 492 | 479 | card->private_free(card); |
|---|
| 493 | | - snd_info_free_entry(card->proc_id); |
|---|
| 494 | 480 | if (snd_info_card_free(card) < 0) { |
|---|
| 495 | 481 | dev_warn(card->dev, "unable to free card info\n"); |
|---|
| 496 | 482 | /* Not fatal error */ |
|---|
| .. | .. |
|---|
| 535 | 521 | */ |
|---|
| 536 | 522 | int snd_card_free(struct snd_card *card) |
|---|
| 537 | 523 | { |
|---|
| 538 | | - struct completion released; |
|---|
| 524 | + DECLARE_COMPLETION_ONSTACK(released); |
|---|
| 539 | 525 | int ret; |
|---|
| 540 | 526 | |
|---|
| 541 | | - init_completion(&released); |
|---|
| 542 | 527 | card->release_completion = &released; |
|---|
| 543 | 528 | ret = snd_card_free_when_closed(card); |
|---|
| 544 | 529 | if (ret) |
|---|
| .. | .. |
|---|
| 794 | 779 | } |
|---|
| 795 | 780 | snd_cards[card->number] = card; |
|---|
| 796 | 781 | mutex_unlock(&snd_card_mutex); |
|---|
| 797 | | - init_info_for_card(card); |
|---|
| 782 | + err = snd_info_card_register(card); |
|---|
| 783 | + if (err < 0) |
|---|
| 784 | + return err; |
|---|
| 785 | + |
|---|
| 798 | 786 | #if IS_ENABLED(CONFIG_SND_MIXER_OSS) |
|---|
| 799 | 787 | if (snd_mixer_oss_notify_callback) |
|---|
| 800 | 788 | snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_REGISTER); |
|---|
| .. | .. |
|---|
| 998 | 986 | return 0; |
|---|
| 999 | 987 | } |
|---|
| 1000 | 988 | EXPORT_SYMBOL(snd_card_file_remove); |
|---|
| 1001 | | - |
|---|
| 1002 | | -/** |
|---|
| 1003 | | - * snd_card_change_online_state - mark card's online/offline state |
|---|
| 1004 | | - * @card: Card to mark |
|---|
| 1005 | | - * @online: whether online of offline |
|---|
| 1006 | | - * |
|---|
| 1007 | | - * Mutes the DAI DAC. |
|---|
| 1008 | | - */ |
|---|
| 1009 | | -void snd_card_change_online_state(struct snd_card *card, int online) |
|---|
| 1010 | | -{ |
|---|
| 1011 | | - snd_printd("snd card %s state change %d -> %d\n", |
|---|
| 1012 | | - card->shortname, !card->offline, online); |
|---|
| 1013 | | - card->offline = !online; |
|---|
| 1014 | | - /* make sure offline is updated prior to wake up */ |
|---|
| 1015 | | - wmb(); |
|---|
| 1016 | | - xchg(&card->offline_change, 1); |
|---|
| 1017 | | - wake_up_interruptible(&card->offline_poll_wait); |
|---|
| 1018 | | -} |
|---|
| 1019 | | -EXPORT_SYMBOL_GPL(snd_card_change_online_state); |
|---|
| 1020 | 989 | |
|---|
| 1021 | 990 | #ifdef CONFIG_PM |
|---|
| 1022 | 991 | /** |
|---|