From patchwork Thu Aug 24 21:02:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Curtis Malainey X-Patchwork-Id: 13364721 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id C0212C27C40 for ; Thu, 24 Aug 2023 21:06:38 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 2C621839; Thu, 24 Aug 2023 23:05:47 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 2C621839 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1692911197; bh=F+LE19iXdKX/DKyMZkZfMSGwIEiZBzzunQNBopthQ8E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=RZtQpAfA4NgqDTul9RWnErohL81aWdv7ZdbNpUSvdZXXCnwJHGVA7Na1SY4PRnUhk bGyVcAGujS2TRelaLSP94jepyAE5qPqIuoNr8zRGXkwwkQ1wemaNX6zRfoOvCUZWmz gEsgq36xMuCJjLpeQ8+gduf4BN49fQKFrtHwZC8U= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 1CE30F80536; Thu, 24 Aug 2023 23:05:00 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id 614A0F80553; Thu, 24 Aug 2023 23:04:59 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id D3281F8022B; Thu, 24 Aug 2023 23:04:53 +0200 (CEST) Received: from mail-oo1-xc2a.google.com (mail-oo1-xc2a.google.com [IPv6:2607:f8b0:4864:20::c2a]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 508DCF80074 for ; Thu, 24 Aug 2023 23:04:44 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 508DCF80074 Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=JCs67MlE Received: by mail-oo1-xc2a.google.com with SMTP id 006d021491bc7-5720f3ce5afso218235eaf.0 for ; Thu, 24 Aug 2023 14:04:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1692911082; x=1693515882; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=NmO/U6IMzbl2UIaHDn9OaenL1P9NwNj9czrGh7RDNVY=; b=JCs67MlEOo0AHQmjzFRqlYaagHP8f4Q7mOrtU1Ve35ghOU7ECO5AXWAtylopsemQfv TBJjq/cYXiOzQ0TuX5peefH3PVOgS/qB3v+B0ynGIXZ2SzKCdDLxG/fQLa3IGmLQb9fY jApOHulpiKrQn+Rw+FtfVjfpezNH/XO86U9Hs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692911082; x=1693515882; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NmO/U6IMzbl2UIaHDn9OaenL1P9NwNj9czrGh7RDNVY=; b=ekrxhDt6fhBR6HrLB9JbMc4QssNn/b0K1v8BO7ISxztcfGgQWnNN2wJ30/hV9B5pmk 2xiopZsDGZVakhm7I4tpuNVIEDdg80K/SUV30KWWGgnevbZ2SFu1mbX//j9+tmW0pj63 WlXzrkOaXZOvRkjJi1VhxT4x9d6iw7N/5aqjZecJ6nQg8cDGNMvNzGwKKsfLpTFeHNbA 8lAawDpmcNkubPT/XQbVfGqNdpXKrwREUAcxED69J8yEoxUMDo21lUAluXdKjRCc+NhW B3B+wgZCO4EcHZW3OixYpJJP8ZSDHJGWsRE+hxUkPqC1TGEUCOjM3KIRlUT7I9NIHMrT hhXw== X-Gm-Message-State: AOJu0YwK2ahyXvBR/8BC1SPFhJmSXsGYPudb+3qWtssFV2Su8ptLsfy/ u6FU2SOU0DUpyvhOr1/I/EuXr0EDI/x5D0PRqg== X-Google-Smtp-Source: AGHT+IG2SJXeoQodTa0fYPJBwVVasbOIheM7yyK7l+uUlYfq+BHhXTHu4mZeXrr0DtzurION6n1kDQ== X-Received: by 2002:a05:6358:5284:b0:135:4003:784c with SMTP id g4-20020a056358528400b001354003784cmr15236062rwa.17.1692911082634; Thu, 24 Aug 2023 14:04:42 -0700 (PDT) Received: from localhost ([2620:15c:9d:4:133d:5d74:91c4:bbb1]) by smtp.gmail.com with UTF8SMTPSA id z11-20020a63b04b000000b00565ec002d14sm50787pgo.33.2023.08.24.14.04.41 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 24 Aug 2023 14:04:41 -0700 (PDT) From: cujomalainey@chromium.org To: alsa-devel@alsa-project.org Cc: Curtis Malainey , Jaroslav Kysela , Takashi Iwai , Thierry Reding , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Ivan Orlov Subject: [PATCH 1/2] ALSA: core: add snd_device_init Date: Thu, 24 Aug 2023 14:02:52 -0700 Message-ID: <20230824210339.1126993-2-cujomalainey@chromium.org> X-Mailer: git-send-email 2.42.0.rc1.204.g551eb34607-goog In-Reply-To: <20230824210339.1126993-1-cujomalainey@chromium.org> References: <20230824210339.1126993-1-cujomalainey@chromium.org> MIME-Version: 1.0 Message-ID-Hash: 5577LOHUTZ2CIGI7H7JLUAO435JIBPOF X-Message-ID-Hash: 5577LOHUTZ2CIGI7H7JLUAO435JIBPOF X-MailFrom: cujomalainey@chromium.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Curtis Malainey Begin allowing refactored modules to allocate their own device but use a common initialization procedure for their devices. Signed-off-by: Curtis Malainey --- include/sound/core.h | 1 + sound/core/init.c | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/include/sound/core.h b/include/sound/core.h index dfef0c9d4b9f7..a4744e142c7e3 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -240,6 +240,7 @@ extern struct dentry *sound_debugfs_root; void snd_request_card(int card); int snd_device_alloc(struct device **dev_p, struct snd_card *card); +void snd_device_init(struct device *dev, struct snd_card *card); int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, diff --git a/sound/core/init.c b/sound/core/init.c index d61bde1225f23..37a8e4791f781 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -132,15 +132,28 @@ int snd_device_alloc(struct device **dev_p, struct snd_card *card) dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; + snd_device_init(dev, card); + *dev_p = dev; + return 0; +} +EXPORT_SYMBOL_GPL(snd_device_alloc); + +/** + * snd_device_init - Initialize struct device for sound devices + * @dev_p: pointer to store the allocated device + * @card: card to assign, optional + * + * For releasing the allocated device, call put_device(). + */ +void snd_device_init(struct device *dev, struct snd_card *card) +{ device_initialize(dev); if (card) dev->parent = &card->card_dev; dev->class = &sound_class; dev->release = default_release_alloc; - *dev_p = dev; - return 0; } -EXPORT_SYMBOL_GPL(snd_device_alloc); +EXPORT_SYMBOL_GPL(snd_device_init); static int snd_card_init(struct snd_card *card, struct device *parent, int idx, const char *xid, struct module *module, From patchwork Thu Aug 24 21:02:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Curtis Malainey X-Patchwork-Id: 13364722 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8D2F2C3DA6F for ; Thu, 24 Aug 2023 21:07:03 +0000 (UTC) Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 76EA39F6; Thu, 24 Aug 2023 23:06:11 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 76EA39F6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1692911221; bh=btY961vNOmQAoun7S7Qd/9GjC7bk3OJFgyYmbrmbBWU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=HaLnQOfjT/PT5OL6c8Lfq8YiDFGbOHM24u0xgXWY9+Eixd4PVLNyRlK4KXX0cmXK1 BbJ3Nh3Qh5OLIQq/p/SdF+6/7gwwd///aEvQy2QWVlSTL8TFnW9TjNWieFpsrTDN/0 DTDGiZTu6LS77LvmS38f+rM8vW8tx6BCQsTTRRks= Received: by alsa1.perex.cz (Postfix, from userid 50401) id 9F195F80551; Thu, 24 Aug 2023 23:06:09 +0200 (CEST) Received: from mailman-core.alsa-project.org (mailman-core.alsa-project.org [10.254.200.10]) by alsa1.perex.cz (Postfix) with ESMTP id D79C7F80158; Thu, 24 Aug 2023 23:06:08 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 5F663F80158; Thu, 24 Aug 2023 23:06:05 +0200 (CEST) Received: from mail-pl1-x62d.google.com (mail-pl1-x62d.google.com [IPv6:2607:f8b0:4864:20::62d]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E8230F800BF for ; Thu, 24 Aug 2023 23:05:51 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E8230F800BF Authentication-Results: alsa1.perex.cz; dkim=pass (1024-bit key, unprotected) header.d=chromium.org header.i=@chromium.org header.a=rsa-sha256 header.s=google header.b=d3jltpPi Received: by mail-pl1-x62d.google.com with SMTP id d9443c01a7336-1bc8a2f71eeso2985565ad.0 for ; Thu, 24 Aug 2023 14:05:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; t=1692911149; x=1693515949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=L2BwqiuA57xErKriGdnODK5pgG9NYueNyN5axyzKIFw=; b=d3jltpPiU3xuqBxHu/IS5xk85i7jL2xS1LUHS1rd2vBPLI3RXD9fUtvnolfdMYVJdN K17crkewytWVZSLmDNUCzrJydS4Ed1PFnYG4aGxGfsNJwacsFFtwAgvf53Ep2WXOmH4z SMXtm7m/gNB9NQenlQZ8ZMJU2Usgg12sim/DM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692911149; x=1693515949; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=L2BwqiuA57xErKriGdnODK5pgG9NYueNyN5axyzKIFw=; b=h46oduuDRBxNAUnN82/ZO5k6yT5WIZ6ZMu0/KUL4BKKLC9XkfdKPOLlNicroWlbf1X ymkZ24wr4qApKVFdt2fnBG9FSr4iP/qcWWs53CMXLLky8oJLSGY89Fc/R8j5JwHnsBAX vomPbiRIgk3yvbJlrd+KdC1dvp1In3q3pWc8BrULNht+3+xDYkniIkNYimCGxCu8XR7y ql8o3ek9FC2hAHPLtHnFDi2hzpy0CXd/mURDYshHkrBoyfXdtIhY1Zrcv7Bxa/1I2oup 62jtwTfi7xIXs9EAcfc2rHBGAocN8feSRiS4Azmo+kw/qHrBDO/k5navCYzd1Bfv8j4i zI8w== X-Gm-Message-State: AOJu0YyiBpBNBFYXX58o+LiEN/KC7BKmFxIi+YdZvep6P3Xot8YYPWLZ dxGHsfTRQEzFNHLsA77R6WOCNMQj/UpKBXDhdw== X-Google-Smtp-Source: AGHT+IH233BQWN3KaeofsnXgU+kzEOwD/7ymoH3BuJAsf2fo9/vTDx1JpIoeAZ5YvCwvPlzAPX3PzQ== X-Received: by 2002:a17:902:c612:b0:1b8:525a:f685 with SMTP id r18-20020a170902c61200b001b8525af685mr12610232plr.37.1692911148654; Thu, 24 Aug 2023 14:05:48 -0700 (PDT) Received: from localhost ([2620:15c:9d:4:133d:5d74:91c4:bbb1]) by smtp.gmail.com with UTF8SMTPSA id f5-20020a170902ce8500b001b89891bfc4sm94349plg.199.2023.08.24.14.05.46 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Thu, 24 Aug 2023 14:05:48 -0700 (PDT) From: cujomalainey@chromium.org To: alsa-devel@alsa-project.org Cc: Curtis Malainey , Jaroslav Kysela , Takashi Iwai , Cezary Rojewski , Pierre-Louis Bossart , Liam Girdwood , Peter Ujfalusi , Bard Liao , Ranjani Sridharan , Kai Vehmanen , Mark Brown , Dan Carpenter , "Maciej S. Szmigiero" , Clement Lecigne , Min-Hua Chen , Ivan Orlov , Greg Kroah-Hartman , Thierry Reding , Geoff Levand , =?utf-8?q?Uwe_Kleine-K=C3=B6nig?= , Kuninori Morimoto Subject: [PATCH 2/2] ALSA: core: split control primitives out of snd_card Date: Thu, 24 Aug 2023 14:02:53 -0700 Message-ID: <20230824210339.1126993-3-cujomalainey@chromium.org> X-Mailer: git-send-email 2.42.0.rc1.204.g551eb34607-goog In-Reply-To: <20230824210339.1126993-1-cujomalainey@chromium.org> References: <20230824210339.1126993-1-cujomalainey@chromium.org> MIME-Version: 1.0 Message-ID-Hash: 3XCN6WLVNC5UO5APLAUCNH554HR6QISC X-Message-ID-Hash: 3XCN6WLVNC5UO5APLAUCNH554HR6QISC X-MailFrom: cujomalainey@chromium.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-alsa-devel.alsa-project.org-0; header-match-alsa-devel.alsa-project.org-1; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.8 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Curtis Malainey Having two kobj in the same struct is broken at its core. This splits card_dev from ctl_dev so they can properly refcount and release on their own schedules without the workaround of having them being just a pointer. Signed-off-by: Curtis Malainey Acked-by: Mark Brown --- include/sound/control.h | 1 + include/sound/core.h | 33 +-- sound/core/control.c | 330 +++++++++++++---------- sound/core/control_compat.c | 8 +- sound/core/control_led.c | 18 +- sound/core/init.c | 14 +- sound/pci/hda/hda_codec.c | 3 +- sound/soc/intel/atom/sst-atom-controls.c | 8 +- sound/soc/soc-card.c | 2 +- sound/usb/media.c | 2 +- 10 files changed, 232 insertions(+), 187 deletions(-) diff --git a/include/sound/control.h b/include/sound/control.h index 9a4f4f7138da8..32920f33eb47e 100644 --- a/include/sound/control.h +++ b/include/sound/control.h @@ -128,6 +128,7 @@ typedef int (*snd_kctl_ioctl_func_t) (struct snd_card * card, struct snd_ctl_file * control, unsigned int cmd, unsigned long arg); +int snd_control_new(struct snd_card * card); void snd_ctl_notify(struct snd_card * card, unsigned int mask, struct snd_ctl_elem_id * id); void snd_ctl_notify_one(struct snd_card * card, unsigned int mask, struct snd_kcontrol * kctl, unsigned int ioff); diff --git a/include/sound/core.h b/include/sound/core.h index a4744e142c7e3..93048a7a800f4 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -95,21 +95,7 @@ struct snd_card { void (*private_free) (struct snd_card *card); /* callback for freeing of private data */ struct list_head devices; /* devices */ - - struct device *ctl_dev; /* control device */ - unsigned int last_numid; /* last used numeric ID */ - struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ - rwlock_t ctl_files_rwlock; /* ctl_files list lock */ - int controls_count; /* count of all controls */ - size_t user_ctl_alloc_size; // current memory allocation by user controls. - struct list_head controls; /* all controls for this card */ - struct list_head ctl_files; /* active control files */ -#ifdef CONFIG_SND_CTL_FAST_LOOKUP - struct xarray ctl_numids; /* hash table for numids */ - struct xarray ctl_hash; /* hash table for ctl id matching */ - bool ctl_hash_collision; /* ctl_hash collision seen? */ -#endif - + struct snd_control *ctl; /* control devices */ struct snd_info_entry *proc_root; /* root for soundcard specific files */ struct proc_dir_entry *proc_root_link; /* number link to real id */ @@ -147,6 +133,23 @@ struct snd_card { #endif }; +struct snd_control +{ + struct device dev; /* control device */ + struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ + rwlock_t files_rwlock; /* ctl_files list lock */ + int controls_count; /* count of all controls */ + size_t user_ctl_alloc_size; // current memory allocation by user controls. + struct list_head controls; /* all controls for this card */ + struct list_head files; /* active control files */ + unsigned int last_numid; /* last used numeric ID */ +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + struct xarray numids; /* hash table for numids */ + struct xarray hash; /* hash table for ctl id matching */ + bool hash_collision; /* ctl_hash collision seen? */ +#endif +}; + #define dev_to_snd_card(p) container_of(p, struct snd_card, card_dev) #ifdef CONFIG_PM diff --git a/sound/core/control.c b/sound/core/control.c index 59c8658966d4c..09066d05a8800 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -41,12 +41,49 @@ static struct snd_ctl_layer_ops *snd_ctl_layer; static int snd_ctl_remove_locked(struct snd_card *card, struct snd_kcontrol *kcontrol); +/** + * snd_control_new - Allocate and initialize snd_control + * @card: the card to be initialized + * + * This function creates and initializes snd_control + */ +int snd_control_new(struct snd_card *card) +{ + struct snd_control *ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + int err; + + if (snd_BUG_ON(!card)) + return -EINVAL; + if (!ctl) + return -ENOMEM; + + init_rwsem(&ctl->controls_rwsem); + rwlock_init(&ctl->files_rwlock); + INIT_LIST_HEAD(&ctl->controls); + INIT_LIST_HEAD(&ctl->files); +#ifdef CONFIG_SND_CTL_FAST_LOOKUP + xa_init(&ctl->numids); + xa_init(&ctl->hash); +#endif + card->ctl = ctl; + /* the control interface cannot be accessed from the user space until */ + /* snd_cards_bitmask and snd_cards are set with snd_card_register */ + err = snd_ctl_create(card); + if (err < 0) { + dev_err(card->dev, "unable to register control minors\n"); + kfree(ctl); + return err; + } + return 0; +} +EXPORT_SYMBOL(snd_control_new); static int snd_ctl_open(struct inode *inode, struct file *file) { unsigned long flags; struct snd_card *card; - struct snd_ctl_file *ctl; + struct snd_control *ctl; + struct snd_ctl_file *ctlf; int i, err; err = stream_open(inode, file); @@ -58,6 +95,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) err = -ENODEV; goto __error1; } + ctl = card->ctl; err = snd_card_file_add(card, file); if (err < 0) { err = -ENODEV; @@ -67,22 +105,22 @@ static int snd_ctl_open(struct inode *inode, struct file *file) err = -EFAULT; goto __error2; } - ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); - if (ctl == NULL) { + ctlf = kzalloc(sizeof(*ctlf), GFP_KERNEL); + if (ctlf == NULL) { err = -ENOMEM; goto __error; } - INIT_LIST_HEAD(&ctl->events); - init_waitqueue_head(&ctl->change_sleep); - spin_lock_init(&ctl->read_lock); - ctl->card = card; + INIT_LIST_HEAD(&ctlf->events); + init_waitqueue_head(&ctlf->change_sleep); + spin_lock_init(&ctlf->read_lock); + ctlf->card = card; for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++) - ctl->preferred_subdevice[i] = -1; - ctl->pid = get_pid(task_pid(current)); - file->private_data = ctl; - write_lock_irqsave(&card->ctl_files_rwlock, flags); - list_add_tail(&ctl->list, &card->ctl_files); - write_unlock_irqrestore(&card->ctl_files_rwlock, flags); + ctlf->preferred_subdevice[i] = -1; + ctlf->pid = get_pid(task_pid(current)); + file->private_data = ctlf; + write_lock_irqsave(&ctl->files_rwlock, flags); + list_add_tail(&ctlf->list, &ctl->files); + write_unlock_irqrestore(&ctl->files_rwlock, flags); snd_card_unref(card); return 0; @@ -113,27 +151,26 @@ static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl) static int snd_ctl_release(struct inode *inode, struct file *file) { unsigned long flags; - struct snd_card *card; - struct snd_ctl_file *ctl; + struct snd_ctl_file *ctlf = file->private_data; + struct snd_card *card = ctlf->card; + struct snd_control *ctl = card->ctl; struct snd_kcontrol *control; unsigned int idx; - ctl = file->private_data; file->private_data = NULL; - card = ctl->card; - write_lock_irqsave(&card->ctl_files_rwlock, flags); - list_del(&ctl->list); - write_unlock_irqrestore(&card->ctl_files_rwlock, flags); - down_write(&card->controls_rwsem); - list_for_each_entry(control, &card->controls, list) + write_lock_irqsave(&ctl->files_rwlock, flags); + list_del(&ctlf->list); + write_unlock_irqrestore(&ctl->files_rwlock, flags); + down_write(&ctl->controls_rwsem); + list_for_each_entry(control, &ctl->controls, list) for (idx = 0; idx < control->count; idx++) - if (control->vd[idx].owner == ctl) + if (control->vd[idx].owner == ctlf) control->vd[idx].owner = NULL; - up_write(&card->controls_rwsem); - snd_fasync_free(ctl->fasync); - snd_ctl_empty_read_queue(ctl); - put_pid(ctl->pid); - kfree(ctl); + up_write(&ctl->controls_rwsem); + snd_fasync_free(ctlf->fasync); + snd_ctl_empty_read_queue(ctlf); + put_pid(ctlf->pid); + kfree(ctlf); module_put(card->module); snd_card_file_remove(card, file); return 0; @@ -160,11 +197,11 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, return; if (card->shutdown) return; - read_lock_irqsave(&card->ctl_files_rwlock, flags); + read_lock_irqsave(&card->ctl->files_rwlock, flags); #if IS_ENABLED(CONFIG_SND_MIXER_OSS) card->mixer_oss_change_count++; #endif - list_for_each_entry(ctl, &card->ctl_files, list) { + list_for_each_entry(ctl, &card->ctl->files, list) { if (!ctl->subscribed) continue; spin_lock(&ctl->read_lock); @@ -187,7 +224,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask, spin_unlock(&ctl->read_lock); snd_kill_fasync(ctl->fasync, SIGIO, POLL_IN); } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + read_unlock_irqrestore(&card->ctl->files_rwlock, flags); } EXPORT_SYMBOL(snd_ctl_notify); @@ -341,13 +378,13 @@ static bool snd_ctl_remove_numid_conflict(struct snd_card *card, struct snd_kcontrol *kctl; /* Make sure that the ids assigned to the control do not wrap around */ - if (card->last_numid >= UINT_MAX - count) - card->last_numid = 0; + if (card->ctl->last_numid >= UINT_MAX - count) + card->ctl->last_numid = 0; - list_for_each_entry(kctl, &card->controls, list) { - if (kctl->id.numid < card->last_numid + 1 + count && - kctl->id.numid + kctl->count > card->last_numid + 1) { - card->last_numid = kctl->id.numid + kctl->count - 1; + list_for_each_entry(kctl, &card->ctl->controls, list) { + if (kctl->id.numid < card->ctl->last_numid + 1 + count && + kctl->id.numid + kctl->count > card->ctl->last_numid + 1) { + card->ctl->last_numid = kctl->id.numid + kctl->count - 1; return true; } } @@ -406,18 +443,19 @@ static void add_hash_entries(struct snd_card *card, struct snd_kcontrol *kcontrol) { struct snd_ctl_elem_id id = kcontrol->id; + struct snd_control *ctl = card->ctl; int i; - xa_store_range(&card->ctl_numids, kcontrol->id.numid, + xa_store_range(&ctl->numids, kcontrol->id.numid, kcontrol->id.numid + kcontrol->count - 1, kcontrol, GFP_KERNEL); for (i = 0; i < kcontrol->count; i++) { id.index = kcontrol->id.index + i; - if (xa_insert(&card->ctl_hash, get_ctl_id_hash(&id), + if (xa_insert(&ctl->hash, get_ctl_id_hash(&id), kcontrol, GFP_KERNEL)) { /* skip hash for this entry, noting we had collision */ - card->ctl_hash_collision = true; + ctl->hash_collision = true; dev_dbg(card->dev, "ctl_hash collision %d:%s:%d\n", id.iface, id.name, id.index); } @@ -429,17 +467,18 @@ static void remove_hash_entries(struct snd_card *card, struct snd_kcontrol *kcontrol) { struct snd_ctl_elem_id id = kcontrol->id; + struct snd_control *ctl = card->ctl; struct snd_kcontrol *matched; unsigned long h; int i; for (i = 0; i < kcontrol->count; i++) { - xa_erase(&card->ctl_numids, id.numid); + xa_erase(&ctl->numids, id.numid); h = get_ctl_id_hash(&id); - matched = xa_load(&card->ctl_hash, h); + matched = xa_load(&ctl->hash, h); if (matched && (matched == kcontrol || elem_id_matches(matched, &id))) - xa_erase(&card->ctl_hash, h); + xa_erase(&ctl->hash, h); id.index++; id.numid++; } @@ -469,7 +508,7 @@ static int __snd_ctl_add_replace(struct snd_card *card, struct snd_kcontrol *old; int err; - lockdep_assert_held_write(&card->controls_rwsem); + lockdep_assert_held_write(&card->ctl->controls_rwsem); id = kcontrol->id; if (id.index > UINT_MAX - kcontrol->count) @@ -496,10 +535,10 @@ static int __snd_ctl_add_replace(struct snd_card *card, if (snd_ctl_find_hole(card, kcontrol->count) < 0) return -ENOMEM; - list_add_tail(&kcontrol->list, &card->controls); - card->controls_count += kcontrol->count; - kcontrol->id.numid = card->last_numid + 1; - card->last_numid += kcontrol->count; + list_add_tail(&kcontrol->list, &card->ctl->controls); + card->ctl->controls_count += kcontrol->count; + kcontrol->id.numid = card->ctl->last_numid + 1; + card->ctl->last_numid += kcontrol->count; add_hash_entries(card, kcontrol); @@ -520,9 +559,9 @@ static int snd_ctl_add_replace(struct snd_card *card, if (snd_BUG_ON(!card || !kcontrol->info)) goto error; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); err = __snd_ctl_add_replace(card, kcontrol, mode); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); if (err < 0) goto error; return 0; @@ -580,7 +619,7 @@ static int __snd_ctl_remove(struct snd_card *card, { unsigned int idx; - lockdep_assert_held_write(&card->controls_rwsem); + lockdep_assert_held_write(&card->ctl->controls_rwsem); if (snd_BUG_ON(!card || !kcontrol)) return -EINVAL; @@ -589,7 +628,7 @@ static int __snd_ctl_remove(struct snd_card *card, if (remove_hash) remove_hash_entries(card, kcontrol); - card->controls_count -= kcontrol->count; + card->ctl->controls_count -= kcontrol->count; for (idx = 0; idx < kcontrol->count; idx++) snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); snd_ctl_free_one(kcontrol); @@ -618,9 +657,9 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol) { int ret; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); ret = snd_ctl_remove_locked(card, kcontrol); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } EXPORT_SYMBOL(snd_ctl_remove); @@ -640,14 +679,14 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) struct snd_kcontrol *kctl; int ret; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -ENOENT; } ret = snd_ctl_remove_locked(card, kctl); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } EXPORT_SYMBOL(snd_ctl_remove_id); @@ -669,7 +708,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, struct snd_kcontrol *kctl; int idx, ret; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { ret = -ENOENT; @@ -686,7 +725,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, } ret = snd_ctl_remove_locked(card, kctl); error: - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } @@ -710,7 +749,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, unsigned int index_offset; int ret; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl == NULL) { ret = -ENOENT; @@ -729,13 +768,13 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; } snd_ctl_build_ioff(id, kctl, index_offset); - downgrade_write(&card->controls_rwsem); + downgrade_write(&card->ctl->controls_rwsem); snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_INFO, kctl, index_offset); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 1; unlock: - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return ret; } EXPORT_SYMBOL_GPL(snd_ctl_activate_id); @@ -764,10 +803,10 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, struct snd_kcontrol *kctl; int saved_numid; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, src_id); if (kctl == NULL) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -ENOENT; } saved_numid = kctl->id.numid; @@ -775,7 +814,7 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id, kctl->id = *dst_id; kctl->id.numid = saved_numid; add_hash_entries(card, kctl); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return 0; } EXPORT_SYMBOL(snd_ctl_rename_id); @@ -793,7 +832,7 @@ EXPORT_SYMBOL(snd_ctl_rename_id); void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name) { - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); remove_hash_entries(card, kctl); if (strscpy(kctl->id.name, name, sizeof(kctl->id.name)) < 0) @@ -801,7 +840,7 @@ void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, name, kctl->id.name); add_hash_entries(card, kctl); - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); } EXPORT_SYMBOL(snd_ctl_rename); @@ -836,9 +875,9 @@ snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid) { if (snd_BUG_ON(!card || !numid)) return NULL; - lockdep_assert_held(&card->controls_rwsem); + lockdep_assert_held(&card->ctl->controls_rwsem); #ifdef CONFIG_SND_CTL_FAST_LOOKUP - return xa_load(&card->ctl_numids, numid); + return xa_load(&card->ctl->numids, numid); #else return snd_ctl_find_numid_slow(card, numid); #endif @@ -861,9 +900,9 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, { struct snd_kcontrol *kctl; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_numid_locked(card, numid); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return kctl; } EXPORT_SYMBOL(snd_ctl_find_numid); @@ -887,18 +926,18 @@ struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, if (snd_BUG_ON(!card || !id)) return NULL; - lockdep_assert_held(&card->controls_rwsem); + lockdep_assert_held(&card->ctl->controls_rwsem); if (id->numid != 0) return snd_ctl_find_numid_locked(card, id->numid); #ifdef CONFIG_SND_CTL_FAST_LOOKUP - kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id)); + kctl = xa_load(&card->ctl->hash, get_ctl_id_hash(id)); if (kctl && elem_id_matches(kctl, id)) return kctl; - if (!card->ctl_hash_collision) + if (!card->ctl->hash_collision) return NULL; /* we can rely on only hash table */ #endif /* no matching in hash table - try all as the last resort */ - list_for_each_entry(kctl, &card->controls, list) + list_for_each_entry(kctl, &card->ctl->controls, list) if (elem_id_matches(kctl, id)) return kctl; @@ -922,9 +961,9 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, { struct snd_kcontrol *kctl; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return kctl; } EXPORT_SYMBOL(snd_ctl_find_id); @@ -965,11 +1004,11 @@ static int snd_ctl_elem_list(struct snd_card *card, offset = list->offset; space = list->space; - down_read(&card->controls_rwsem); - list->count = card->controls_count; + down_read(&card->ctl->controls_rwsem); + list->count = card->ctl->controls_count; list->used = 0; if (space > 0) { - list_for_each_entry(kctl, &card->controls, list) { + list_for_each_entry(kctl, &card->ctl->controls, list) { if (offset >= kctl->count) { offset -= kctl->count; continue; @@ -989,7 +1028,7 @@ static int snd_ctl_elem_list(struct snd_card *card, } } out: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return err; } @@ -1240,13 +1279,13 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, struct snd_kcontrol *kctl; int result; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &info->id); if (kctl == NULL) result = -ENOENT; else result = __snd_ctl_elem_info(card, kctl, info, ctl); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return result; } @@ -1279,7 +1318,7 @@ static int snd_ctl_elem_read(struct snd_card *card, const u32 pattern = 0xdeadbeef; int ret; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &control->id); if (kctl == NULL) { ret = -ENOENT; @@ -1323,7 +1362,7 @@ static int snd_ctl_elem_read(struct snd_card *card, goto unlock; } unlock: - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return ret; } @@ -1356,10 +1395,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, unsigned int index_offset; int result; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &control->id); if (kctl == NULL) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -ENOENT; } @@ -1367,7 +1406,7 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, vd = &kctl->vd[index_offset]; if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL || (file && vd->owner && vd->owner != file)) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return -EPERM; } @@ -1388,16 +1427,16 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, result = kctl->put(kctl, control); snd_power_unref(card); if (result < 0) { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return result; } if (result > 0) { - downgrade_write(&card->controls_rwsem); + downgrade_write(&card->ctl->controls_rwsem); snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, index_offset); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); } else { - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); } return 0; @@ -1437,7 +1476,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &id); if (kctl == NULL) { result = -ENOENT; @@ -1450,7 +1489,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, result = 0; } } - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return result; } @@ -1465,7 +1504,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, &id); if (kctl == NULL) { result = -ENOENT; @@ -1480,7 +1519,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, result = 0; } } - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return result; } @@ -1497,7 +1536,7 @@ struct user_element { // check whether the addition (in bytes) of user ctl element may overflow the limit. static bool check_user_elem_overflow(struct snd_card *card, ssize_t add) { - return (ssize_t)card->user_ctl_alloc_size + add > max_user_ctl_alloc_size; + return (ssize_t)card->ctl->user_ctl_alloc_size + add > max_user_ctl_alloc_size; } static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol, @@ -1575,7 +1614,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, int i; int change; - lockdep_assert_held_write(&ue->card->controls_rwsem); + lockdep_assert_held_write(&ue->card->ctl->controls_rwsem); if (size > 1024 * 128) /* sane value */ return -EINVAL; @@ -1602,7 +1641,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; mask = SNDRV_CTL_EVENT_MASK_INFO; } else { - ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + ue->card->ctl->user_ctl_alloc_size -= ue->tlv_data_size; ue->tlv_data_size = 0; kvfree(ue->tlv_data); } @@ -1610,7 +1649,7 @@ static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf, ue->tlv_data = container; ue->tlv_data_size = size; // decremented at private_free. - ue->card->user_ctl_alloc_size += size; + ue->card->ctl->user_ctl_alloc_size += size; mask |= SNDRV_CTL_EVENT_MASK_TLV; for (i = 0; i < kctl->count; ++i) @@ -1653,7 +1692,7 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) unsigned int i; const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr; - lockdep_assert_held_write(&ue->card->controls_rwsem); + lockdep_assert_held_write(&ue->card->ctl->controls_rwsem); buf_len = ue->info.value.enumerated.names_length; if (buf_len > 64 * 1024) @@ -1680,7 +1719,7 @@ static int snd_ctl_elem_init_enum_names(struct user_element *ue) ue->priv_data = names; ue->info.value.enumerated.names_ptr = 0; // increment the allocation size; decremented again at private_free. - ue->card->user_ctl_alloc_size += ue->info.value.enumerated.names_length; + ue->card->ctl->user_ctl_alloc_size += ue->info.value.enumerated.names_length; return 0; } @@ -1695,10 +1734,10 @@ static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol) struct user_element *ue = kcontrol->private_data; // decrement the allocation size. - ue->card->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); - ue->card->user_ctl_alloc_size -= ue->tlv_data_size; + ue->card->ctl->user_ctl_alloc_size -= compute_user_elem_size(ue->elem_data_size, kcontrol->count); + ue->card->ctl->user_ctl_alloc_size -= ue->tlv_data_size; if (ue->priv_data) - ue->card->user_ctl_alloc_size -= ue->info.value.enumerated.names_length; + ue->card->ctl->user_ctl_alloc_size -= ue->info.value.enumerated.names_length; kvfree(ue->tlv_data); kvfree(ue->priv_data); @@ -1763,7 +1802,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, private_size = value_sizes[info->type] * info->count; alloc_size = compute_user_elem_size(private_size, count); - down_write(&card->controls_rwsem); + down_write(&card->ctl->controls_rwsem); if (check_user_elem_overflow(card, alloc_size)) { err = -ENOMEM; goto unlock; @@ -1789,7 +1828,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, kctl->private_free = snd_ctl_elem_user_free; // increment the allocated size; decremented again at private_free. - card->user_ctl_alloc_size += alloc_size; + card->ctl->user_ctl_alloc_size += alloc_size; /* Set private data for this userspace control. */ ue->card = card; @@ -1833,7 +1872,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, * which locks the element. */ unlock: - up_write(&card->controls_rwsem); + up_write(&card->ctl->controls_rwsem); return err; } @@ -1959,7 +1998,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, struct snd_ctl_elem_id id; struct snd_kcontrol_volatile *vd; - lockdep_assert_held(&file->card->controls_rwsem); + lockdep_assert_held(&file->card->ctl->controls_rwsem); if (copy_from_user(&header, buf, sizeof(header))) return -EFAULT; @@ -2036,19 +2075,19 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: return snd_ctl_subscribe_events(ctl, ip); case SNDRV_CTL_IOCTL_TLV_READ: - down_read(&ctl->card->controls_rwsem); + down_read(&ctl->card->ctl->controls_rwsem); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); - up_read(&ctl->card->controls_rwsem); + up_read(&ctl->card->ctl->controls_rwsem); return err; case SNDRV_CTL_IOCTL_TLV_WRITE: - down_write(&ctl->card->controls_rwsem); + down_write(&ctl->card->ctl->controls_rwsem); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); - up_write(&ctl->card->controls_rwsem); + up_write(&ctl->card->ctl->controls_rwsem); return err; case SNDRV_CTL_IOCTL_TLV_COMMAND: - down_write(&ctl->card->controls_rwsem); + down_write(&ctl->card->ctl->controls_rwsem); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); - up_write(&ctl->card->controls_rwsem); + up_write(&ctl->card->ctl->controls_rwsem); return err; case SNDRV_CTL_IOCTL_POWER: return -ENOPROTOOPT; @@ -2258,15 +2297,15 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type) int subdevice = -1; unsigned long flags; - read_lock_irqsave(&card->ctl_files_rwlock, flags); - list_for_each_entry(kctl, &card->ctl_files, list) { + read_lock_irqsave(&card->ctl->files_rwlock, flags); + list_for_each_entry(kctl, &card->ctl->files, list) { if (kctl->pid == task_pid(current)) { subdevice = kctl->preferred_subdevice[type]; if (subdevice != -1) break; } } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + read_unlock_irqrestore(&card->ctl->files_rwlock, flags); return subdevice; } EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice); @@ -2326,9 +2365,9 @@ void snd_ctl_register_layer(struct snd_ctl_layer_ops *lops) for (card_number = 0; card_number < SNDRV_CARDS; card_number++) { card = snd_card_ref(card_number); if (card) { - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); lops->lregister(card); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); snd_card_unref(card); } } @@ -2389,15 +2428,15 @@ static int snd_ctl_dev_register(struct snd_device *device) int err; err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, - &snd_ctl_f_ops, card, card->ctl_dev); + &snd_ctl_f_ops, card, &card->ctl->dev); if (err < 0) return err; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); down_read(&snd_ctl_layer_rwsem); for (lops = snd_ctl_layer; lops; lops = lops->next) lops->lregister(card); up_read(&snd_ctl_layer_rwsem); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 0; } @@ -2411,21 +2450,21 @@ static int snd_ctl_dev_disconnect(struct snd_device *device) struct snd_ctl_layer_ops *lops; unsigned long flags; - read_lock_irqsave(&card->ctl_files_rwlock, flags); - list_for_each_entry(ctl, &card->ctl_files, list) { + read_lock_irqsave(&card->ctl->files_rwlock, flags); + list_for_each_entry(ctl, &card->ctl->files, list) { wake_up(&ctl->change_sleep); snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR); } - read_unlock_irqrestore(&card->ctl_files_rwlock, flags); + read_unlock_irqrestore(&card->ctl->files_rwlock, flags); - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); down_read(&snd_ctl_layer_rwsem); for (lops = snd_ctl_layer; lops; lops = lops->next) lops->ldisconnect(card); up_read(&snd_ctl_layer_rwsem); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); - return snd_unregister_device(card->ctl_dev); + return snd_unregister_device(&card->ctl->dev); } /* @@ -2436,21 +2475,28 @@ static int snd_ctl_dev_free(struct snd_device *device) struct snd_card *card = device->device_data; struct snd_kcontrol *control; - down_write(&card->controls_rwsem); - while (!list_empty(&card->controls)) { - control = snd_kcontrol(card->controls.next); + down_write(&card->ctl->controls_rwsem); + while (!list_empty(&card->ctl->controls)) { + control = snd_kcontrol(card->ctl->controls.next); __snd_ctl_remove(card, control, false); } #ifdef CONFIG_SND_CTL_FAST_LOOKUP - xa_destroy(&card->ctl_numids); - xa_destroy(&card->ctl_hash); + xa_destroy(&card->ctl->numids); + xa_destroy(&card->ctl->hash); #endif - up_write(&card->controls_rwsem); - put_device(card->ctl_dev); + up_write(&card->ctl->controls_rwsem); + put_device(&card->ctl->dev); return 0; } +static void release_control_device(struct device *dev) +{ + struct snd_control *ctl = container_of(dev, struct snd_control, dev); + + kfree(ctl); +} + /* * create control core: * called from init.c @@ -2462,6 +2508,7 @@ int snd_ctl_create(struct snd_card *card) .dev_register = snd_ctl_dev_register, .dev_disconnect = snd_ctl_dev_disconnect, }; + struct snd_control *ctl = card->ctl; int err; if (snd_BUG_ON(!card)) @@ -2469,14 +2516,13 @@ int snd_ctl_create(struct snd_card *card) if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS)) return -ENXIO; - err = snd_device_alloc(&card->ctl_dev, card); - if (err < 0) - return err; - dev_set_name(card->ctl_dev, "controlC%d", card->number); + snd_device_init(&ctl->dev, card); + dev_set_name(&ctl->dev, "controlC%d", card->number); + ctl->dev.release = release_control_device; err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); if (err < 0) - put_device(card->ctl_dev); + put_device(&ctl->dev); return err; } diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 0e8b1bfb040e0..0e0b555f71537 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -172,15 +172,15 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, struct snd_ctl_elem_info *info; int err; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (! kctl) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return -ENOENT; } info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return -ENOMEM; } info->id = *id; @@ -188,7 +188,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, if (!err) err = kctl->info(kctl, info); snd_power_unref(card); - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); if (err >= 0) { err = info->type; *countp = info->count; diff --git a/sound/core/control_led.c b/sound/core/control_led.c index a78eb48927c7b..6b53de7660438 100644 --- a/sound/core/control_led.c +++ b/sound/core/control_led.c @@ -243,6 +243,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, unsigned int group, bool set) { struct snd_card *card; + struct snd_control *ctl; struct snd_kcontrol *kctl; struct snd_kcontrol_volatile *vd; unsigned int ioff, access, new_access; @@ -250,7 +251,8 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, card = snd_card_ref(card_number); if (card) { - down_write(&card->controls_rwsem); + ctl = card->ctl; + down_write(&ctl->controls_rwsem); kctl = snd_ctl_find_id_locked(card, id); if (kctl) { ioff = snd_ctl_get_ioff(kctl, id); @@ -271,7 +273,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id, err = -ENOENT; } unlock: - up_write(&card->controls_rwsem); + up_write(&ctl->controls_rwsem); snd_card_unref(card); } else { err = -ENXIO; @@ -357,7 +359,7 @@ static void snd_ctl_led_register(struct snd_card *card) snd_ctl_led_card_valid[card->number] = true; mutex_unlock(&snd_ctl_led_mutex); /* the register callback is already called with held card->controls_rwsem */ - list_for_each_entry(kctl, &card->controls, list) + list_for_each_entry(kctl, &card->ctl->controls, list) for (ioff = 0; ioff < kctl->count; ioff++) snd_ctl_led_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, kctl, ioff); snd_ctl_led_refresh(); @@ -617,12 +619,14 @@ static ssize_t list_show(struct device *dev, struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev); struct snd_card *card; struct snd_ctl_led_ctl *lctl; + struct snd_control *ctl; size_t l = 0; card = snd_card_ref(led_card->number); if (!card) return -ENXIO; - down_read(&card->controls_rwsem); + ctl = card->ctl; + down_read(&ctl->controls_rwsem); mutex_lock(&snd_ctl_led_mutex); if (snd_ctl_led_card_valid[led_card->number]) { list_for_each_entry(lctl, &led_card->led->controls, list) { @@ -635,7 +639,7 @@ static ssize_t list_show(struct device *dev, } } mutex_unlock(&snd_ctl_led_mutex); - up_read(&card->controls_rwsem); + up_read(&ctl->controls_rwsem); snd_card_unref(card); return l; } @@ -688,7 +692,7 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card) goto cerr; led->cards[card->number] = led_card; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - WARN(sysfs_create_link(&card->ctl_dev->kobj, &led_card->dev.kobj, link_name), + WARN(sysfs_create_link(&card->ctl->dev.kobj, &led_card->dev.kobj, link_name), "can't create symlink to controlC%i device\n", card->number); WARN(sysfs_create_link(&led_card->dev.kobj, &card->card_dev.kobj, "card"), "can't create symlink to card%i\n", card->number); @@ -714,7 +718,7 @@ static void snd_ctl_led_sysfs_remove(struct snd_card *card) if (!led_card) continue; snprintf(link_name, sizeof(link_name), "led-%s", led->name); - sysfs_remove_link(&card->ctl_dev->kobj, link_name); + sysfs_remove_link(&card->ctl->dev.kobj, link_name); sysfs_remove_link(&led_card->dev.kobj, "card"); device_unregister(&led_card->dev); led->cards[card->number] = NULL; diff --git a/sound/core/init.c b/sound/core/init.c index 37a8e4791f781..695b080603e93 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -331,14 +331,6 @@ static int snd_card_init(struct snd_card *card, struct device *parent, card->module = module; #endif INIT_LIST_HEAD(&card->devices); - init_rwsem(&card->controls_rwsem); - rwlock_init(&card->ctl_files_rwlock); - INIT_LIST_HEAD(&card->controls); - INIT_LIST_HEAD(&card->ctl_files); -#ifdef CONFIG_SND_CTL_FAST_LOOKUP - xa_init(&card->ctl_numids); - xa_init(&card->ctl_hash); -#endif spin_lock_init(&card->files_lock); INIT_LIST_HEAD(&card->files_list); mutex_init(&card->memory_mutex); @@ -363,11 +355,9 @@ static int snd_card_init(struct snd_card *card, struct device *parent, snprintf(card->irq_descr, sizeof(card->irq_descr), "%s:%s", dev_driver_string(card->dev), dev_name(&card->card_dev)); - /* the control interface cannot be accessed from the user space until */ - /* snd_cards_bitmask and snd_cards are set with snd_card_register */ - err = snd_ctl_create(card); + err = snd_control_new(card); if (err < 0) { - dev_err(parent, "unable to register control minors\n"); + dev_err(parent, "unable to create controls and register\n"); goto __error; } err = snd_info_card_create(card); diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 33af707a65ab1..7afc9a29ea9ec 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1784,13 +1784,14 @@ void snd_hda_ctls_clear(struct hda_codec *codec) int snd_hda_lock_devices(struct hda_bus *bus) { struct snd_card *card = bus->card; + struct snd_control *ctl = card->ctl; struct hda_codec *codec; spin_lock(&card->files_lock); if (card->shutdown) goto err_unlock; card->shutdown = 1; - if (!list_empty(&card->ctl_files)) + if (!list_empty(&ctl->files)) goto err_clear; list_for_each_codec(codec, bus) { diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 38116c7587174..8cd5681de9fbd 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -1434,9 +1434,9 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, struct snd_card *card = component->card->snd_card; char *idx; - down_read(&card->controls_rwsem); + down_read(&card->ctl->controls_rwsem); - list_for_each_entry(kctl, &card->controls, list) { + list_for_each_entry(kctl, &card->ctl->controls, list) { idx = strchr(kctl->id.name, ' '); if (idx == NULL) continue; @@ -1469,12 +1469,12 @@ static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w, } if (ret < 0) { - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return ret; } } - up_read(&card->controls_rwsem); + up_read(&card->ctl->controls_rwsem); return 0; } diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index 285ab4c9c7168..1129eb33f78c9 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -35,7 +35,7 @@ struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, if (unlikely(!name)) return NULL; - list_for_each_entry(kctl, &card->controls, list) + list_for_each_entry(kctl, &card->ctl->controls, list) if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) return kctl; return NULL; diff --git a/sound/usb/media.c b/sound/usb/media.c index d48db6f3ae659..5298c2f49a164 100644 --- a/sound/usb/media.c +++ b/sound/usb/media.c @@ -163,7 +163,7 @@ void snd_media_stop_pipeline(struct snd_usb_substream *subs) static int snd_media_mixer_init(struct snd_usb_audio *chip) { - struct device *ctl_dev = chip->card->ctl_dev; + struct device *ctl_dev = &chip->card->ctl->dev; struct media_intf_devnode *ctl_intf; struct usb_mixer_interface *mixer; struct media_device *mdev = chip->media_dev;