From patchwork Sat Mar 15 16:41:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Koichiro Den X-Patchwork-Id: 873948 Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D8CB4204C18 for ; Sat, 15 Mar 2025 16:41:46 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.125.188.122 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742056909; cv=none; b=GZ8hJHM3EvTsqJnsIWWVjVSltzf/R7J41+XQhwYj5e4lXpDriHBR6s1tiH63FkAlBCdh0dwA2MJNxTe8KN890sRp59OJeheCGb+15p1PwT9tBNLvcPVlQUpOAWRkR0IySvfx90zjqHmY5o8KSzuGYlUi8hJQIbJp5ik+d8powgI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1742056909; c=relaxed/simple; bh=QKzGBY006K35i0VUre3m/YXkXfWXlIbWjW5345Q28Sw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=m4j4bkofDfqtUQtdWcW6G3Ia+/41yefjichBwFPn5ofbVe2MI4+MmSGgAx1QecDSdVlBqEiDieQpwuG94U2g3jZfYwm2PCzRL/5xO9Uld/MbR72Ntxxdmvf7t+sIwgR5UlEfeaewXAEYsCXGOvr+6Eahfxjfx4A79SnS5z/IT0I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com; spf=pass smtp.mailfrom=canonical.com; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b=DNnm0WRs; arc=none smtp.client-ip=185.125.188.122 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=canonical.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=canonical.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=canonical.com header.i=@canonical.com header.b="DNnm0WRs" Received: from mail-pj1-f70.google.com (mail-pj1-f70.google.com [209.85.216.70]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 5B92E3F1EE for ; Sat, 15 Mar 2025 16:41:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1742056899; bh=gYD77nW/waFXgRcL7RZiNMF3p8f4KzCk7t7Ss3jccwc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DNnm0WRs+IOVhT5AxX8bUybsJ5rsb3p1PMGwI83oExzqX8VI78eG33UdbLOExsIxB iUuuVkEPUYQ+afmHyiJk0epxd9FyhOVfSDToTOQ7c2BYc9kH61X+0iSWeMoQhxC+ni bJnpR+7Zq7JHN6+1eL5aKcobXdzMH78Gu+RQRsspsBPKyNdjsBMt+26A5OHmFCfivB cA/NB/SyN+bh+VRrSZQBAt0LErtez9aYo4LELonT2JHKBv5ylV6PY0k/kVbzBQCk8z aihRo7hXFVE2RfoH9FLaZTA0JiMFGK3oqFg6LuAqxyAhoJKPS7Iq89bkgPpAkdzDJm kv63FqcQGB9Hw== Received: by mail-pj1-f70.google.com with SMTP id 98e67ed59e1d1-2ff8c5d185aso2281561a91.1 for ; Sat, 15 Mar 2025 09:41:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1742056898; x=1742661698; 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=gYD77nW/waFXgRcL7RZiNMF3p8f4KzCk7t7Ss3jccwc=; b=H5fLbjWW4eSUcm3hNrXk9pqLlewsSX9HGKWeXr/n0g9ho3dm5qUHBHiQy/broeF6ff 46afW5f+zroRRzrdw11aVCVe0ioTN5JChtOgZ/MGga7VvJvAHBup6zWII2YkSI556t2l /42AUgvA7KJKE2NRcwk/TkUkL1c8RcY6JtT9ii91PZNblTlViOSBhQseh4j9qvvT2Dr+ 3ilLr+vE4DUFJ4pRvz6Zg4JgO7YwnUSEjolYBzpuVXBRAiOg7c7h55ZpvcIvyQQPDRAi wO6fhkcU7RRQhKvk2C9VzqtPtqfcLmfCkfq1YGwNjeShjZ/C29HSiqlKu5L1awe0Mshc haNg== X-Gm-Message-State: AOJu0Yz+B1E9n9/GUQ/F/owK4Mt8STBTSeksuFTnnypVRYcGhYL7BzIf fWtAZ72cwycAQTLZ/JGOTyDzN9ShP+xK9uh2EbanAAAaK5TfDxjPAPj57UV14RZLSvRyv1ivWrq DZLydNlfOdkBRBJpzFt2rOjM1X6U09p9J+h7pccrtHA4x2OtojkE/wGeU9zZkLDGt4W2W9Hu4Sj 2bExJ+IMw= X-Gm-Gg: ASbGncvVMzIpiVjtMMJBu9P1DhxEla/kTPocjblwG5HjsDf5Esj+P/GTLO/qmc9W6xo 4jsBE0OkmNQFroe54HDPFOO9U2ZwphGOLAPVWMNDYISwYEzCwPyVpl+eFabeHeZW2YrdwrDHckb vKAAE8027XeQg2PeTxkc7i97qV9cqkh4GhTz6yWXPHLM2XnrvfXg6gh9Xr3SgcXjshtKxtYW7Yp iG4C66jEkLiZG1G50gXgbYeP1KqetkXTqhkS/03DBEXMyyOWSgRdtCpQJ8MBppfJniQpe9R9nDP LJx1lAjrYlJpIn+k X-Received: by 2002:a05:6a00:982:b0:736:43d6:f008 with SMTP id d2e1a72fcca58-7372235abb3mr8709252b3a.12.1742056897714; Sat, 15 Mar 2025 09:41:37 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEyWRch+DZlOrDcTTNMtsFblIYnc5TdxZVbq/yNbPFKS8wtP5jPBVMjXtbMdb8ayyf/SXsn4w== X-Received: by 2002:a05:6a00:982:b0:736:43d6:f008 with SMTP id d2e1a72fcca58-7372235abb3mr8709229b3a.12.1742056897288; Sat, 15 Mar 2025 09:41:37 -0700 (PDT) Received: from z790sl.. ([240f:74:7be:1:83e6:3590:3498:db44]) by smtp.gmail.com with ESMTPSA id d2e1a72fcca58-7371155e3a9sm4637104b3a.71.2025.03.15.09.41.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 15 Mar 2025 09:41:36 -0700 (PDT) From: Koichiro Den To: linux-gpio@vger.kernel.org Cc: brgl@bgdev.pl, geert+renesas@glider.be, linus.walleij@linaro.org, maciej.borzecki@canonical.com, linux-kernel@vger.kernel.org Subject: [PATCH v6 2/9] gpio: aggregator: reorder functions to prepare for configfs introduction Date: Sun, 16 Mar 2025 01:41:16 +0900 Message-ID: <20250315164123.1855142-3-koichiro.den@canonical.com> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20250315164123.1855142-1-koichiro.den@canonical.com> References: <20250315164123.1855142-1-koichiro.den@canonical.com> Precedence: bulk X-Mailing-List: linux-gpio@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Reorder functions in drivers/gpio/gpio-aggregator.c to prepare for the configfs-based interface additions in subsequent commits. Arrange the code so that the configfs implementations will appear above the existing sysfs-specific code, since the latter will partly depend on the configfs interface implementations when it starts to expose the settings to configfs. The order in drivers/gpio/gpio-aggregator.c will be as follows: * Basic gpio_aggregator/gpio_aggregator_line representations * Common utility functions * GPIO Forwarder implementations * Configfs interface implementations * Sysfs interface implementations * Platform device implementations * Module init/exit implementations This separate commit ensures a clean diff for the subsequent commits. No functional change. Reviewed-by: Geert Uytterhoeven Signed-off-by: Koichiro Den --- drivers/gpio/gpio-aggregator.c | 380 +++++++++++++++++---------------- 1 file changed, 192 insertions(+), 188 deletions(-) diff --git a/drivers/gpio/gpio-aggregator.c b/drivers/gpio/gpio-aggregator.c index d232ea865356..e026deb4ac64 100644 --- a/drivers/gpio/gpio-aggregator.c +++ b/drivers/gpio/gpio-aggregator.c @@ -61,194 +61,6 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key, return 0; } -static int aggr_parse(struct gpio_aggregator *aggr) -{ - char *args = skip_spaces(aggr->args); - char *name, *offsets, *p; - unsigned int i, n = 0; - int error = 0; - - unsigned long *bitmap __free(bitmap) = - bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); - if (!bitmap) - return -ENOMEM; - - args = next_arg(args, &name, &p); - while (*args) { - args = next_arg(args, &offsets, &p); - - p = get_options(offsets, 0, &error); - if (error == 0 || *p) { - /* Named GPIO line */ - error = aggr_add_gpio(aggr, name, U16_MAX, &n); - if (error) - return error; - - name = offsets; - continue; - } - - /* GPIO chip + offset(s) */ - error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS); - if (error) { - pr_err("Cannot parse %s: %d\n", offsets, error); - return error; - } - - for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { - error = aggr_add_gpio(aggr, name, i, &n); - if (error) - return error; - } - - args = next_arg(args, &name, &p); - } - - if (!n) { - pr_err("No GPIOs specified\n"); - return -EINVAL; - } - - return 0; -} - -static ssize_t new_device_store(struct device_driver *driver, const char *buf, - size_t count) -{ - struct gpio_aggregator *aggr; - struct platform_device *pdev; - int res, id; - - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - - /* kernfs guarantees string termination, so count + 1 is safe */ - aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); - if (!aggr) { - res = -ENOMEM; - goto put_module; - } - - memcpy(aggr->args, buf, count + 1); - - aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), - GFP_KERNEL); - if (!aggr->lookups) { - res = -ENOMEM; - goto free_ga; - } - - mutex_lock(&gpio_aggregator_lock); - id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); - mutex_unlock(&gpio_aggregator_lock); - - if (id < 0) { - res = id; - goto free_table; - } - - aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); - if (!aggr->lookups->dev_id) { - res = -ENOMEM; - goto remove_idr; - } - - res = aggr_parse(aggr); - if (res) - goto free_dev_id; - - gpiod_add_lookup_table(aggr->lookups); - - pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); - if (IS_ERR(pdev)) { - res = PTR_ERR(pdev); - goto remove_table; - } - - aggr->pdev = pdev; - module_put(THIS_MODULE); - return count; - -remove_table: - gpiod_remove_lookup_table(aggr->lookups); -free_dev_id: - kfree(aggr->lookups->dev_id); -remove_idr: - mutex_lock(&gpio_aggregator_lock); - idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); -free_table: - kfree(aggr->lookups); -free_ga: - kfree(aggr); -put_module: - module_put(THIS_MODULE); - return res; -} - -static DRIVER_ATTR_WO(new_device); - -static void gpio_aggregator_free(struct gpio_aggregator *aggr) -{ - platform_device_unregister(aggr->pdev); - gpiod_remove_lookup_table(aggr->lookups); - kfree(aggr->lookups->dev_id); - kfree(aggr->lookups); - kfree(aggr); -} - -static ssize_t delete_device_store(struct device_driver *driver, - const char *buf, size_t count) -{ - struct gpio_aggregator *aggr; - unsigned int id; - int error; - - if (!str_has_prefix(buf, DRV_NAME ".")) - return -EINVAL; - - error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); - if (error) - return error; - - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - - mutex_lock(&gpio_aggregator_lock); - aggr = idr_remove(&gpio_aggregator_idr, id); - mutex_unlock(&gpio_aggregator_lock); - if (!aggr) { - module_put(THIS_MODULE); - return -ENOENT; - } - - gpio_aggregator_free(aggr); - module_put(THIS_MODULE); - return count; -} -static DRIVER_ATTR_WO(delete_device); - -static struct attribute *gpio_aggregator_attrs[] = { - &driver_attr_new_device.attr, - &driver_attr_delete_device.attr, - NULL -}; -ATTRIBUTE_GROUPS(gpio_aggregator); - -static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) -{ - gpio_aggregator_free(p); - return 0; -} - -static void __exit gpio_aggregator_remove_all(void) -{ - mutex_lock(&gpio_aggregator_lock); - idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL); - idr_destroy(&gpio_aggregator_idr); - mutex_unlock(&gpio_aggregator_lock); -} - /* * GPIO Forwarder @@ -583,6 +395,184 @@ static struct gpiochip_fwd *gpiochip_fwd_create(struct device *dev, } +/* + * Sysfs interface + */ +static int aggr_parse(struct gpio_aggregator *aggr) +{ + char *args = skip_spaces(aggr->args); + char *name, *offsets, *p; + unsigned int i, n = 0; + int error = 0; + + unsigned long *bitmap __free(bitmap) = + bitmap_alloc(AGGREGATOR_MAX_GPIOS, GFP_KERNEL); + if (!bitmap) + return -ENOMEM; + + args = next_arg(args, &name, &p); + while (*args) { + args = next_arg(args, &offsets, &p); + + p = get_options(offsets, 0, &error); + if (error == 0 || *p) { + /* Named GPIO line */ + error = aggr_add_gpio(aggr, name, U16_MAX, &n); + if (error) + return error; + + name = offsets; + continue; + } + + /* GPIO chip + offset(s) */ + error = bitmap_parselist(offsets, bitmap, AGGREGATOR_MAX_GPIOS); + if (error) { + pr_err("Cannot parse %s: %d\n", offsets, error); + return error; + } + + for_each_set_bit(i, bitmap, AGGREGATOR_MAX_GPIOS) { + error = aggr_add_gpio(aggr, name, i, &n); + if (error) + return error; + } + + args = next_arg(args, &name, &p); + } + + if (!n) { + pr_err("No GPIOs specified\n"); + return -EINVAL; + } + + return 0; +} + +static ssize_t new_device_store(struct device_driver *driver, const char *buf, + size_t count) +{ + struct gpio_aggregator *aggr; + struct platform_device *pdev; + int res, id; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + /* kernfs guarantees string termination, so count + 1 is safe */ + aggr = kzalloc(sizeof(*aggr) + count + 1, GFP_KERNEL); + if (!aggr) { + res = -ENOMEM; + goto put_module; + } + + memcpy(aggr->args, buf, count + 1); + + aggr->lookups = kzalloc(struct_size(aggr->lookups, table, 1), + GFP_KERNEL); + if (!aggr->lookups) { + res = -ENOMEM; + goto free_ga; + } + + mutex_lock(&gpio_aggregator_lock); + id = idr_alloc(&gpio_aggregator_idr, aggr, 0, 0, GFP_KERNEL); + mutex_unlock(&gpio_aggregator_lock); + + if (id < 0) { + res = id; + goto free_table; + } + + aggr->lookups->dev_id = kasprintf(GFP_KERNEL, "%s.%d", DRV_NAME, id); + if (!aggr->lookups->dev_id) { + res = -ENOMEM; + goto remove_idr; + } + + res = aggr_parse(aggr); + if (res) + goto free_dev_id; + + gpiod_add_lookup_table(aggr->lookups); + + pdev = platform_device_register_simple(DRV_NAME, id, NULL, 0); + if (IS_ERR(pdev)) { + res = PTR_ERR(pdev); + goto remove_table; + } + + aggr->pdev = pdev; + module_put(THIS_MODULE); + return count; + +remove_table: + gpiod_remove_lookup_table(aggr->lookups); +free_dev_id: + kfree(aggr->lookups->dev_id); +remove_idr: + mutex_lock(&gpio_aggregator_lock); + idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); +free_table: + kfree(aggr->lookups); +free_ga: + kfree(aggr); +put_module: + module_put(THIS_MODULE); + return res; +} + +static DRIVER_ATTR_WO(new_device); + +static void gpio_aggregator_free(struct gpio_aggregator *aggr) +{ + platform_device_unregister(aggr->pdev); + gpiod_remove_lookup_table(aggr->lookups); + kfree(aggr->lookups->dev_id); + kfree(aggr->lookups); + kfree(aggr); +} + +static ssize_t delete_device_store(struct device_driver *driver, + const char *buf, size_t count) +{ + struct gpio_aggregator *aggr; + unsigned int id; + int error; + + if (!str_has_prefix(buf, DRV_NAME ".")) + return -EINVAL; + + error = kstrtouint(buf + strlen(DRV_NAME "."), 10, &id); + if (error) + return error; + + if (!try_module_get(THIS_MODULE)) + return -ENOENT; + + mutex_lock(&gpio_aggregator_lock); + aggr = idr_remove(&gpio_aggregator_idr, id); + mutex_unlock(&gpio_aggregator_lock); + if (!aggr) { + module_put(THIS_MODULE); + return -ENOENT; + } + + gpio_aggregator_free(aggr); + module_put(THIS_MODULE); + return count; +} +static DRIVER_ATTR_WO(delete_device); + +static struct attribute *gpio_aggregator_attrs[] = { + &driver_attr_new_device.attr, + &driver_attr_delete_device.attr, + NULL +}; +ATTRIBUTE_GROUPS(gpio_aggregator); + + /* * GPIO Aggregator platform device */ @@ -640,6 +630,20 @@ static struct platform_driver gpio_aggregator_driver = { }, }; +static int __exit gpio_aggregator_idr_remove(int id, void *p, void *data) +{ + gpio_aggregator_free(p); + return 0; +} + +static void __exit gpio_aggregator_remove_all(void) +{ + mutex_lock(&gpio_aggregator_lock); + idr_for_each(&gpio_aggregator_idr, gpio_aggregator_idr_remove, NULL); + idr_destroy(&gpio_aggregator_idr); + mutex_unlock(&gpio_aggregator_lock); +} + static int __init gpio_aggregator_init(void) { return platform_driver_register(&gpio_aggregator_driver);