brintos

brintos / linux-shallow public Read only

0
0
Text · 43.3 KiB · 91b6352 Raw
1803 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Configurable virtual GPIO consumer module.4 *5 * Copyright (C) 2023-2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 10#include <linux/array_size.h>11#include <linux/atomic.h>12#include <linux/bitmap.h>13#include <linux/cleanup.h>14#include <linux/completion.h>15#include <linux/configfs.h>16#include <linux/debugfs.h>17#include <linux/device.h>18#include <linux/err.h>19#include <linux/gpio/consumer.h>20#include <linux/gpio/machine.h>21#include <linux/idr.h>22#include <linux/interrupt.h>23#include <linux/irq_work.h>24#include <linux/limits.h>25#include <linux/list.h>26#include <linux/lockdep.h>27#include <linux/mod_devicetable.h>28#include <linux/module.h>29#include <linux/mutex.h>30#include <linux/notifier.h>31#include <linux/of.h>32#include <linux/overflow.h>33#include <linux/platform_device.h>34#include <linux/printk.h>35#include <linux/property.h>36#include <linux/slab.h>37#include <linux/string_helpers.h>38#include <linux/types.h>39 40#define GPIO_VIRTUSER_NAME_BUF_LEN 3241 42static DEFINE_IDA(gpio_virtuser_ida);43static struct dentry *gpio_virtuser_dbg_root;44 45struct gpio_virtuser_attr_data {46	union {47		struct gpio_desc *desc;48		struct gpio_descs *descs;49	};50	struct dentry *dbgfs_dir;51};52 53struct gpio_virtuser_line_array_data {54	struct gpio_virtuser_attr_data ad;55};56 57struct gpio_virtuser_line_data {58	struct gpio_virtuser_attr_data ad;59	char consumer[GPIO_VIRTUSER_NAME_BUF_LEN];60	struct mutex consumer_lock;61	unsigned int debounce;62	atomic_t irq;63	atomic_t irq_count;64};65 66struct gpio_virtuser_dbgfs_attr_descr {67	const char *name;68	const struct file_operations *fops;69};70 71struct gpio_virtuser_irq_work_context {72	struct irq_work work;73	struct completion work_completion;74	union {75		struct {76			struct gpio_desc *desc;77			int dir;78			int val;79			int ret;80		};81		struct {82			struct gpio_descs *descs;83			unsigned long *values;84		};85	};86};87 88static struct gpio_virtuser_irq_work_context *89to_gpio_virtuser_irq_work_context(struct irq_work *work)90{91	return container_of(work, struct gpio_virtuser_irq_work_context, work);92}93 94static void95gpio_virtuser_init_irq_work_context(struct gpio_virtuser_irq_work_context *ctx)96{97	memset(ctx, 0, sizeof(*ctx));98	init_completion(&ctx->work_completion);99}100 101static void102gpio_virtuser_irq_work_queue_sync(struct gpio_virtuser_irq_work_context *ctx)103{104	irq_work_queue(&ctx->work);105	wait_for_completion(&ctx->work_completion);106}107 108static void gpio_virtuser_dbgfs_emit_value_array(char *buf,109						 unsigned long *values,110						 size_t num_values)111{112	size_t i;113 114	for (i = 0; i < num_values; i++)115		buf[i] = test_bit(i, values) ? '1' : '0';116 117	buf[i++] = '\n';118}119 120static void gpio_virtuser_get_value_array_atomic(struct irq_work *work)121{122	struct gpio_virtuser_irq_work_context *ctx =123				to_gpio_virtuser_irq_work_context(work);124	struct gpio_descs *descs = ctx->descs;125 126	ctx->ret = gpiod_get_array_value(descs->ndescs, descs->desc,127					 descs->info, ctx->values);128	complete(&ctx->work_completion);129}130 131static int gpio_virtuser_get_array_value(struct gpio_descs *descs,132					 unsigned long *values, bool atomic)133{134	struct gpio_virtuser_irq_work_context ctx;135 136	if (!atomic)137		return gpiod_get_array_value_cansleep(descs->ndescs,138						      descs->desc,139						      descs->info, values);140 141	gpio_virtuser_init_irq_work_context(&ctx);142	ctx.work = IRQ_WORK_INIT_HARD(gpio_virtuser_get_value_array_atomic);143	ctx.descs = descs;144	ctx.values = values;145 146	gpio_virtuser_irq_work_queue_sync(&ctx);147 148	return ctx.ret;149}150 151static ssize_t gpio_virtuser_value_array_do_read(struct file *file,152						 char __user *user_buf,153						 size_t size, loff_t *ppos,154						 bool atomic)155{156	struct gpio_virtuser_line_data *data = file->private_data;157	struct gpio_descs *descs = data->ad.descs;158	size_t bufsize;159	int ret;160 161	unsigned long *values __free(bitmap) = bitmap_zalloc(descs->ndescs,162							     GFP_KERNEL);163	if (!values)164		return -ENOMEM;165 166	ret = gpio_virtuser_get_array_value(descs, values, atomic);167	if (ret)168		return ret;169 170	bufsize = descs->ndescs + 2;171 172	char *buf __free(kfree) = kzalloc(bufsize, GFP_KERNEL);173	if (!buf)174		return -ENOMEM;175 176	gpio_virtuser_dbgfs_emit_value_array(buf, values, descs->ndescs);177 178	return simple_read_from_buffer(user_buf, size, ppos, buf,179				       descs->ndescs + 1);180}181 182static int gpio_virtuser_dbgfs_parse_value_array(const char *buf,183						 size_t len,184						 unsigned long *values)185{186	size_t i;187 188	for (i = 0; i < len; i++) {189		if (buf[i] == '0')190			clear_bit(i, values);191		else if (buf[i] == '1')192			set_bit(i, values);193		else194			return -EINVAL;195	}196 197	return 0;198}199 200static void gpio_virtuser_set_value_array_atomic(struct irq_work *work)201{202	struct gpio_virtuser_irq_work_context *ctx =203				to_gpio_virtuser_irq_work_context(work);204	struct gpio_descs *descs = ctx->descs;205 206	ctx->ret = gpiod_set_array_value(descs->ndescs, descs->desc,207					 descs->info, ctx->values);208	complete(&ctx->work_completion);209}210 211static int gpio_virtuser_set_array_value(struct gpio_descs *descs,212					 unsigned long *values, bool atomic)213{214	struct gpio_virtuser_irq_work_context ctx;215 216	if (!atomic)217		return gpiod_set_array_value_cansleep(descs->ndescs,218						      descs->desc,219						      descs->info, values);220 221	gpio_virtuser_init_irq_work_context(&ctx);222	ctx.work = IRQ_WORK_INIT_HARD(gpio_virtuser_set_value_array_atomic);223	ctx.descs = descs;224	ctx.values = values;225 226	gpio_virtuser_irq_work_queue_sync(&ctx);227 228	return ctx.ret;229}230 231static ssize_t gpio_virtuser_value_array_do_write(struct file *file,232						  const char __user *user_buf,233						  size_t count, loff_t *ppos,234						  bool atomic)235{236	struct gpio_virtuser_line_data *data = file->private_data;237	struct gpio_descs *descs = data->ad.descs;238	int ret;239 240	if (count - 1 != descs->ndescs)241		return -EINVAL;242 243	char *buf __free(kfree) = kzalloc(count, GFP_KERNEL);244	if (!buf)245		return -ENOMEM;246 247	ret = simple_write_to_buffer(buf, count, ppos, user_buf, count);248	if (ret < 0)249		return ret;250 251	unsigned long *values __free(bitmap) = bitmap_zalloc(descs->ndescs,252							     GFP_KERNEL);253	if (!values)254		return -ENOMEM;255 256	ret = gpio_virtuser_dbgfs_parse_value_array(buf, count - 1, values);257	if (ret)258		return ret;259 260	ret = gpio_virtuser_set_array_value(descs, values, atomic);261	if (ret)262		return ret;263 264	return count;265}266 267static ssize_t gpio_virtuser_value_array_read(struct file *file,268					      char __user *user_buf,269					      size_t count, loff_t *ppos)270{271	return gpio_virtuser_value_array_do_read(file, user_buf, count, ppos,272						 false);273}274 275static ssize_t gpio_virtuser_value_array_write(struct file *file,276					       const char __user *user_buf,277					       size_t count, loff_t *ppos)278{279	return gpio_virtuser_value_array_do_write(file, user_buf, count, ppos,280						  false);281}282 283static const struct file_operations gpio_virtuser_value_array_fops = {284	.read = gpio_virtuser_value_array_read,285	.write = gpio_virtuser_value_array_write,286	.open = simple_open,287	.owner = THIS_MODULE,288	.llseek = default_llseek,289};290 291static ssize_t292gpio_virtuser_value_array_atomic_read(struct file *file, char __user *user_buf,293				      size_t count, loff_t *ppos)294{295	return gpio_virtuser_value_array_do_read(file, user_buf, count, ppos,296						 true);297}298 299static ssize_t300gpio_virtuser_value_array_atomic_write(struct file *file,301				       const char __user *user_buf,302				       size_t count, loff_t *ppos)303{304	return gpio_virtuser_value_array_do_write(file, user_buf, count, ppos,305						  true);306}307 308static const struct file_operations gpio_virtuser_value_array_atomic_fops = {309	.read = gpio_virtuser_value_array_atomic_read,310	.write = gpio_virtuser_value_array_atomic_write,311	.open = simple_open,312	.owner = THIS_MODULE,313	.llseek = default_llseek,314};315 316static void gpio_virtuser_do_get_direction_atomic(struct irq_work *work)317{318	struct gpio_virtuser_irq_work_context *ctx =319				to_gpio_virtuser_irq_work_context(work);320 321	ctx->ret = gpiod_get_direction(ctx->desc);322	complete(&ctx->work_completion);323}324 325static int gpio_virtuser_get_direction_atomic(struct gpio_desc *desc)326{327	struct gpio_virtuser_irq_work_context ctx;328 329	gpio_virtuser_init_irq_work_context(&ctx);330	ctx.work = IRQ_WORK_INIT_HARD(gpio_virtuser_do_get_direction_atomic);331	ctx.desc = desc;332 333	gpio_virtuser_irq_work_queue_sync(&ctx);334 335	return ctx.ret;336}337 338static ssize_t gpio_virtuser_direction_do_read(struct file *file,339					       char __user *user_buf,340					       size_t size, loff_t *ppos,341					       bool atomic)342{343	struct gpio_virtuser_line_data *data = file->private_data;344	struct gpio_desc *desc = data->ad.desc;345	char buf[32];346	int dir;347 348	if (!atomic)349		dir = gpiod_get_direction(desc);350	else351		dir = gpio_virtuser_get_direction_atomic(desc);352	if (dir < 0)353		return dir;354 355	snprintf(buf, sizeof(buf), "%s\n", dir ? "input" : "output");356 357	return simple_read_from_buffer(user_buf, size, ppos, buf, strlen(buf));358}359 360static int gpio_virtuser_set_direction(struct gpio_desc *desc, int dir, int val)361{362	if (dir)363		return gpiod_direction_input(desc);364 365	return gpiod_direction_output(desc, val);366}367 368static void gpio_virtuser_do_set_direction_atomic(struct irq_work *work)369{370	struct gpio_virtuser_irq_work_context *ctx =371				to_gpio_virtuser_irq_work_context(work);372 373	ctx->ret = gpio_virtuser_set_direction(ctx->desc, ctx->dir, ctx->val);374	complete(&ctx->work_completion);375}376 377static int gpio_virtuser_set_direction_atomic(struct gpio_desc *desc,378					      int dir, int val)379{380	struct gpio_virtuser_irq_work_context ctx;381 382	gpio_virtuser_init_irq_work_context(&ctx);383	ctx.work = IRQ_WORK_INIT_HARD(gpio_virtuser_do_set_direction_atomic);384	ctx.desc = desc;385	ctx.dir = dir;386	ctx.val = val;387 388	gpio_virtuser_irq_work_queue_sync(&ctx);389 390	return ctx.ret;391}392 393static ssize_t gpio_virtuser_direction_do_write(struct file *file,394						const char __user *user_buf,395						size_t count, loff_t *ppos,396						bool atomic)397{398	struct gpio_virtuser_line_data *data = file->private_data;399	struct gpio_desc *desc = data->ad.desc;400	char buf[32], *trimmed;401	int ret, dir, val = 0;402 403	ret = simple_write_to_buffer(buf, sizeof(buf), ppos, user_buf, count);404	if (ret < 0)405		return ret;406 407	trimmed = strim(buf);408 409	if (strcmp(trimmed, "input") == 0) {410		dir = 1;411	} else if (strcmp(trimmed, "output-high") == 0) {412		dir = 0;413		val = 1;414	} else if (strcmp(trimmed, "output-low") == 0) {415		dir = val = 0;416	} else {417		return -EINVAL;418	}419 420	if (!atomic)421		ret = gpio_virtuser_set_direction(desc, dir, val);422	else423		ret = gpio_virtuser_set_direction_atomic(desc, dir, val);424	if (ret)425		return ret;426 427	return count;428}429 430static ssize_t gpio_virtuser_direction_read(struct file *file,431					    char __user *user_buf,432					    size_t size, loff_t *ppos)433{434	return gpio_virtuser_direction_do_read(file, user_buf, size, ppos,435					       false);436}437 438static ssize_t gpio_virtuser_direction_write(struct file *file,439					     const char __user *user_buf,440					     size_t count, loff_t *ppos)441{442	return gpio_virtuser_direction_do_write(file, user_buf, count, ppos,443						false);444}445 446static const struct file_operations gpio_virtuser_direction_fops = {447	.read = gpio_virtuser_direction_read,448	.write = gpio_virtuser_direction_write,449	.open = simple_open,450	.owner = THIS_MODULE,451	.llseek = default_llseek,452};453 454static ssize_t gpio_virtuser_direction_atomic_read(struct file *file,455						   char __user *user_buf,456						   size_t size, loff_t *ppos)457{458	return gpio_virtuser_direction_do_read(file, user_buf, size, ppos,459					       true);460}461 462static ssize_t gpio_virtuser_direction_atomic_write(struct file *file,463						    const char __user *user_buf,464						    size_t count, loff_t *ppos)465{466	return gpio_virtuser_direction_do_write(file, user_buf, count, ppos,467						true);468}469 470static const struct file_operations gpio_virtuser_direction_atomic_fops = {471	.read = gpio_virtuser_direction_atomic_read,472	.write = gpio_virtuser_direction_atomic_write,473	.open = simple_open,474	.owner = THIS_MODULE,475	.llseek = default_llseek,476};477 478static int gpio_virtuser_value_get(void *data, u64 *val)479{480	struct gpio_virtuser_line_data *ld = data;481	int ret;482 483	ret = gpiod_get_value_cansleep(ld->ad.desc);484	if (ret < 0)485		return ret;486 487	*val = ret;488 489	return 0;490}491 492static int gpio_virtuser_value_set(void *data, u64 val)493{494	struct gpio_virtuser_line_data *ld = data;495 496	if (val > 1)497		return -EINVAL;498 499	gpiod_set_value_cansleep(ld->ad.desc, (int)val);500 501	return 0;502}503 504DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_value_fops,505			 gpio_virtuser_value_get,506			 gpio_virtuser_value_set,507			 "%llu\n");508 509static void gpio_virtuser_get_value_atomic(struct irq_work *work)510{511	struct gpio_virtuser_irq_work_context *ctx =512				to_gpio_virtuser_irq_work_context(work);513 514	ctx->val = gpiod_get_value(ctx->desc);515	complete(&ctx->work_completion);516}517 518static int gpio_virtuser_value_atomic_get(void *data, u64 *val)519{520	struct gpio_virtuser_line_data *ld = data;521	struct gpio_virtuser_irq_work_context ctx;522 523	gpio_virtuser_init_irq_work_context(&ctx);524	ctx.work = IRQ_WORK_INIT_HARD(gpio_virtuser_get_value_atomic);525	ctx.desc = ld->ad.desc;526 527	gpio_virtuser_irq_work_queue_sync(&ctx);528 529	if (ctx.val < 0)530		return ctx.val;531 532	*val = ctx.val;533 534	return 0;535}536 537static void gpio_virtuser_set_value_atomic(struct irq_work *work)538{539	struct gpio_virtuser_irq_work_context *ctx =540			to_gpio_virtuser_irq_work_context(work);541 542	gpiod_set_value(ctx->desc, ctx->val);543	complete(&ctx->work_completion);544}545 546static int gpio_virtuser_value_atomic_set(void *data, u64 val)547{548	struct gpio_virtuser_line_data *ld = data;549	struct gpio_virtuser_irq_work_context ctx;550 551	if (val > 1)552		return -EINVAL;553 554	gpio_virtuser_init_irq_work_context(&ctx);555	ctx.work = IRQ_WORK_INIT_HARD(gpio_virtuser_set_value_atomic);556	ctx.desc = ld->ad.desc;557	ctx.val = (int)val;558 559	gpio_virtuser_irq_work_queue_sync(&ctx);560 561	return 0;562}563 564DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_value_atomic_fops,565			 gpio_virtuser_value_atomic_get,566			 gpio_virtuser_value_atomic_set,567			 "%llu\n");568 569static int gpio_virtuser_debounce_get(void *data, u64 *val)570{571	struct gpio_virtuser_line_data *ld = data;572 573	*val = READ_ONCE(ld->debounce);574 575	return 0;576}577 578static int gpio_virtuser_debounce_set(void *data, u64 val)579{580	struct gpio_virtuser_line_data *ld = data;581	int ret;582 583	if (val > UINT_MAX)584		return -E2BIG;585 586	ret = gpiod_set_debounce(ld->ad.desc, (unsigned int)val);587	if (ret)588		/* Don't propagate errno unknown to user-space. */589		return ret == -ENOTSUPP ? -EOPNOTSUPP : ret;590 591	WRITE_ONCE(ld->debounce, (unsigned int)val);592 593	return 0;594}595 596DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_debounce_fops,597			 gpio_virtuser_debounce_get,598			 gpio_virtuser_debounce_set,599			 "%llu\n");600 601static ssize_t gpio_virtuser_consumer_read(struct file *file,602					   char __user *user_buf,603					   size_t size, loff_t *ppos)604{605	struct gpio_virtuser_line_data *data = file->private_data;606	char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 1];607	ssize_t ret;608 609	memset(buf, 0x0, sizeof(buf));610 611	scoped_guard(mutex, &data->consumer_lock)612		ret = snprintf(buf, sizeof(buf), "%s\n", data->consumer);613 614	return simple_read_from_buffer(user_buf, size, ppos, buf, ret);615}616 617static ssize_t gpio_virtuser_consumer_write(struct file *file,618					    const char __user *user_buf,619					    size_t count, loff_t *ppos)620{621	struct gpio_virtuser_line_data *data = file->private_data;622	char buf[GPIO_VIRTUSER_NAME_BUF_LEN + 2];623	int ret;624 625	ret = simple_write_to_buffer(buf, GPIO_VIRTUSER_NAME_BUF_LEN, ppos,626				     user_buf, count);627	if (ret < 0)628		return ret;629 630	buf[strlen(buf) - 1] = '\0';631 632	ret = gpiod_set_consumer_name(data->ad.desc, buf);633	if (ret)634		return ret;635 636	scoped_guard(mutex, &data->consumer_lock)637		strscpy(data->consumer, buf, sizeof(data->consumer));638 639	return count;640}641 642static const struct file_operations gpio_virtuser_consumer_fops = {643	.read = gpio_virtuser_consumer_read,644	.write = gpio_virtuser_consumer_write,645	.open = simple_open,646	.owner = THIS_MODULE,647	.llseek = default_llseek,648};649 650static int gpio_virtuser_interrupts_get(void *data, u64 *val)651{652	struct gpio_virtuser_line_data *ld = data;653 654	*val = atomic_read(&ld->irq_count);655 656	return 0;657}658 659static irqreturn_t gpio_virtuser_irq_handler(int irq, void *data)660{661	struct gpio_virtuser_line_data *ld = data;662 663	atomic_inc(&ld->irq_count);664 665	return IRQ_HANDLED;666}667 668static int gpio_virtuser_interrupts_set(void *data, u64 val)669{670	struct gpio_virtuser_line_data *ld = data;671	int irq, ret;672 673	if (val > 1)674		return -EINVAL;675 676	if (val) {677		irq = gpiod_to_irq(ld->ad.desc);678		if (irq < 0)679			return irq;680 681		ret = request_threaded_irq(irq, NULL,682					   gpio_virtuser_irq_handler,683					   IRQF_TRIGGER_RISING |684					   IRQF_TRIGGER_FALLING |685					   IRQF_ONESHOT,686					   ld->consumer, data);687		if (ret)688			return ret;689 690		atomic_set(&ld->irq, irq);691	} else {692		irq = atomic_xchg(&ld->irq, 0);693		free_irq(irq, ld);694	}695 696	return 0;697}698 699DEFINE_DEBUGFS_ATTRIBUTE(gpio_virtuser_interrupts_fops,700			 gpio_virtuser_interrupts_get,701			 gpio_virtuser_interrupts_set,702			 "%llu\n");703 704static const struct gpio_virtuser_dbgfs_attr_descr705gpio_virtuser_line_array_dbgfs_attrs[] = {706	{707		.name = "values",708		.fops = &gpio_virtuser_value_array_fops,709	},710	{711		.name = "values_atomic",712		.fops = &gpio_virtuser_value_array_atomic_fops,713	},714};715 716static const struct gpio_virtuser_dbgfs_attr_descr717gpio_virtuser_line_dbgfs_attrs[] = {718	{719		.name = "direction",720		.fops = &gpio_virtuser_direction_fops,721	},722	{723		.name = "direction_atomic",724		.fops = &gpio_virtuser_direction_atomic_fops,725	},726	{727		.name = "value",728		.fops = &gpio_virtuser_value_fops,729	},730	{731		.name = "value_atomic",732		.fops = &gpio_virtuser_value_atomic_fops,733	},734	{735		.name = "debounce",736		.fops = &gpio_virtuser_debounce_fops,737	},738	{739		.name = "consumer",740		.fops = &gpio_virtuser_consumer_fops,741	},742	{743		.name = "interrupts",744		.fops = &gpio_virtuser_interrupts_fops,745	},746};747 748static int gpio_virtuser_create_debugfs_attrs(749			const struct gpio_virtuser_dbgfs_attr_descr *attr,750			size_t num_attrs, struct dentry *parent, void *data)751{752	struct dentry *ret;753	size_t i;754 755	for (i = 0; i < num_attrs; i++, attr++) {756		ret = debugfs_create_file(attr->name, 0644, parent, data,757					  attr->fops);758		if (IS_ERR(ret))759			return PTR_ERR(ret);760	}761 762	return 0;763}764 765static int gpio_virtuser_dbgfs_init_line_array_attrs(struct device *dev,766						     struct gpio_descs *descs,767						     const char *id,768						     struct dentry *dbgfs_entry)769{770	struct gpio_virtuser_line_array_data *data;771	char *name;772 773	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);774	if (!data)775		return -ENOMEM;776 777	data->ad.descs = descs;778 779	name = devm_kasprintf(dev, GFP_KERNEL, "gpiod:%s", id);780	if (!name)781		return -ENOMEM;782 783	data->ad.dbgfs_dir = debugfs_create_dir(name, dbgfs_entry);784	if (IS_ERR(data->ad.dbgfs_dir))785		return PTR_ERR(data->ad.dbgfs_dir);786 787	return gpio_virtuser_create_debugfs_attrs(788			gpio_virtuser_line_array_dbgfs_attrs,789			ARRAY_SIZE(gpio_virtuser_line_array_dbgfs_attrs),790			data->ad.dbgfs_dir, data);791}792 793static int gpio_virtuser_dbgfs_init_line_attrs(struct device *dev,794					       struct gpio_desc *desc,795					       const char *id,796					       unsigned int index,797					       struct dentry *dbgfs_entry)798{799	struct gpio_virtuser_line_data *data;800	char *name;801	int ret;802 803	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);804	if (!data)805		return -ENOMEM;806 807	data->ad.desc = desc;808	strscpy(data->consumer, id);809	atomic_set(&data->irq, 0);810	atomic_set(&data->irq_count, 0);811 812	name = devm_kasprintf(dev, GFP_KERNEL, "gpiod:%s:%u", id, index);813	if (!name)814		return -ENOMEM;815 816	ret = devm_mutex_init(dev, &data->consumer_lock);817	if (ret)818		return ret;819 820	data->ad.dbgfs_dir = debugfs_create_dir(name, dbgfs_entry);821	if (IS_ERR(data->ad.dbgfs_dir))822		return PTR_ERR(data->ad.dbgfs_dir);823 824	return gpio_virtuser_create_debugfs_attrs(825				gpio_virtuser_line_dbgfs_attrs,826				ARRAY_SIZE(gpio_virtuser_line_dbgfs_attrs),827				data->ad.dbgfs_dir, data);828}829 830static void gpio_virtuser_debugfs_remove(void *data)831{832	struct dentry *dbgfs_entry = data;833 834	debugfs_remove_recursive(dbgfs_entry);835}836 837static int gpio_virtuser_prop_is_gpio(struct property *prop)838{839	char *dash = strrchr(prop->name, '-');840 841	return dash && strcmp(dash, "-gpios") == 0;842}843 844/*845 * If this is an OF-based system, then we iterate over properties and consider846 * all whose names end in "-gpios". For configfs we expect an additional string847 * array property - "gpio-virtuser,ids" - containing the list of all GPIO IDs848 * to request.849 */850static int gpio_virtuser_count_ids(struct device *dev)851{852	struct device_node *of_node = dev_of_node(dev);853	struct property *prop;854	int ret = 0;855 856	if (!of_node)857		return device_property_string_array_count(dev,858							  "gpio-virtuser,ids");859 860	for_each_property_of_node(of_node, prop) {861		if (gpio_virtuser_prop_is_gpio(prop))862			++ret;863	}864 865	return ret;866}867 868static int gpio_virtuser_get_ids(struct device *dev, const char **ids,869				 int num_ids)870{871	struct device_node *of_node = dev_of_node(dev);872	struct property *prop;873	size_t pos = 0, diff;874	char *dash, *tmp;875 876	if (!of_node)877		return device_property_read_string_array(dev,878							 "gpio-virtuser,ids",879							 ids, num_ids);880 881	for_each_property_of_node(of_node, prop) {882		if (!gpio_virtuser_prop_is_gpio(prop))883			continue;884 885		dash = strrchr(prop->name, '-');886		diff = dash - prop->name;887 888		tmp = devm_kmemdup(dev, prop->name, diff + 1,889				   GFP_KERNEL);890		if (!tmp)891			return -ENOMEM;892 893		tmp[diff] = '\0';894		ids[pos++] = tmp;895	}896 897	return 0;898}899 900static int gpio_virtuser_probe(struct platform_device *pdev)901{902	struct device *dev = &pdev->dev;903	struct dentry *dbgfs_entry;904	struct gpio_descs *descs;905	int ret, num_ids = 0, i;906	const char **ids;907	unsigned int j;908 909	num_ids = gpio_virtuser_count_ids(dev);910	if (num_ids < 0)911		return dev_err_probe(dev, num_ids,912				     "Failed to get the number of GPIOs to request\n");913 914	if (num_ids == 0)915		return dev_err_probe(dev, -EINVAL, "No GPIO IDs specified\n");916 917	ids = devm_kcalloc(dev, num_ids, sizeof(*ids), GFP_KERNEL);918	if (!ids)919		return -ENOMEM;920 921	ret = gpio_virtuser_get_ids(dev, ids, num_ids);922	if (ret < 0)923		return dev_err_probe(dev, ret,924				     "Failed to get the IDs of GPIOs to request\n");925 926	dbgfs_entry = debugfs_create_dir(dev_name(dev), gpio_virtuser_dbg_root);927	ret = devm_add_action_or_reset(dev, gpio_virtuser_debugfs_remove,928				       dbgfs_entry);929	if (ret)930		return ret;931 932	for (i = 0; i < num_ids; i++) {933		descs = devm_gpiod_get_array(dev, ids[i], GPIOD_ASIS);934		if (IS_ERR(descs))935			return dev_err_probe(dev, PTR_ERR(descs),936					     "Failed to request the '%s' GPIOs\n",937					     ids[i]);938 939		ret = gpio_virtuser_dbgfs_init_line_array_attrs(dev, descs,940								ids[i],941								dbgfs_entry);942		if (ret)943			return dev_err_probe(dev, ret,944					     "Failed to setup the debugfs array interface for the '%s' GPIOs\n",945					     ids[i]);946 947		for (j = 0; j < descs->ndescs; j++) {948			ret = gpio_virtuser_dbgfs_init_line_attrs(dev,949							descs->desc[j], ids[i],950							j, dbgfs_entry);951			if (ret)952				return dev_err_probe(dev, ret,953						     "Failed to setup the debugfs line interface for the '%s' GPIOs\n",954						     ids[i]);955		}956	}957 958	return 0;959}960 961static const struct of_device_id gpio_virtuser_of_match[] = {962	{ .compatible = "gpio-virtuser" },963	{ }964};965MODULE_DEVICE_TABLE(of, gpio_virtuser_of_match);966 967static struct platform_driver gpio_virtuser_driver = {968	.driver = {969		.name = "gpio-virtuser",970		.of_match_table = gpio_virtuser_of_match,971	},972	.probe = gpio_virtuser_probe,973};974 975struct gpio_virtuser_device {976	struct config_group group;977 978	struct platform_device *pdev;979	int id;980	struct mutex lock;981 982	struct notifier_block bus_notifier;983	struct completion probe_completion;984	bool driver_bound;985 986	struct gpiod_lookup_table *lookup_table;987 988	struct list_head lookup_list;989};990 991static int gpio_virtuser_bus_notifier_call(struct notifier_block *nb,992					   unsigned long action, void *data)993{994	struct gpio_virtuser_device *vdev;995	struct device *dev = data;996	char devname[32];997 998	vdev = container_of(nb, struct gpio_virtuser_device, bus_notifier);999	snprintf(devname, sizeof(devname), "gpio-virtuser.%d", vdev->id);1000 1001	if (!device_match_name(dev, devname))1002		return NOTIFY_DONE;1003 1004	switch (action) {1005	case BUS_NOTIFY_BOUND_DRIVER:1006		vdev->driver_bound = true;1007		break;1008	case BUS_NOTIFY_DRIVER_NOT_BOUND:1009		vdev->driver_bound = false;1010		break;1011	default:1012		return NOTIFY_DONE;1013	}1014 1015	complete(&vdev->probe_completion);1016	return NOTIFY_OK;1017}1018 1019static struct gpio_virtuser_device *1020to_gpio_virtuser_device(struct config_item *item)1021{1022	struct config_group *group = to_config_group(item);1023 1024	return container_of(group, struct gpio_virtuser_device, group);1025}1026 1027static bool1028gpio_virtuser_device_is_live(struct gpio_virtuser_device *dev)1029{1030	lockdep_assert_held(&dev->lock);1031 1032	return !!dev->pdev;1033}1034 1035struct gpio_virtuser_lookup {1036	struct config_group group;1037 1038	struct gpio_virtuser_device *parent;1039	struct list_head siblings;1040 1041	char *con_id;1042 1043	struct list_head entry_list;1044};1045 1046static struct gpio_virtuser_lookup *1047to_gpio_virtuser_lookup(struct config_item *item)1048{1049	struct config_group *group = to_config_group(item);1050 1051	return container_of(group, struct gpio_virtuser_lookup, group);1052}1053 1054struct gpio_virtuser_lookup_entry {1055	struct config_group group;1056 1057	struct gpio_virtuser_lookup *parent;1058	struct list_head siblings;1059 1060	char *key;1061	/* Can be negative to indicate lookup by name. */1062	int offset;1063	enum gpio_lookup_flags flags;1064};1065 1066static struct gpio_virtuser_lookup_entry *1067to_gpio_virtuser_lookup_entry(struct config_item *item)1068{1069	struct config_group *group = to_config_group(item);1070 1071	return container_of(group, struct gpio_virtuser_lookup_entry, group);1072}1073 1074static ssize_t1075gpio_virtuser_lookup_entry_config_key_show(struct config_item *item, char *page)1076{1077	struct gpio_virtuser_lookup_entry *entry =1078					to_gpio_virtuser_lookup_entry(item);1079	struct gpio_virtuser_device *dev = entry->parent->parent;1080 1081	guard(mutex)(&dev->lock);1082 1083	return sprintf(page, "%s\n", entry->key ?: "");1084}1085 1086static ssize_t1087gpio_virtuser_lookup_entry_config_key_store(struct config_item *item,1088					    const char *page, size_t count)1089{1090	struct gpio_virtuser_lookup_entry *entry =1091					to_gpio_virtuser_lookup_entry(item);1092	struct gpio_virtuser_device *dev = entry->parent->parent;1093 1094	char *key __free(kfree) = kstrndup(skip_spaces(page), count,1095					   GFP_KERNEL);1096	if (!key)1097		return -ENOMEM;1098 1099	strim(key);1100 1101	guard(mutex)(&dev->lock);1102 1103	if (gpio_virtuser_device_is_live(dev))1104		return -EBUSY;1105 1106	kfree(entry->key);1107	entry->key = no_free_ptr(key);1108 1109	return count;1110}1111 1112CONFIGFS_ATTR(gpio_virtuser_lookup_entry_config_, key);1113 1114static ssize_t1115gpio_virtuser_lookup_entry_config_offset_show(struct config_item *item,1116					      char *page)1117{1118	struct gpio_virtuser_lookup_entry *entry =1119					to_gpio_virtuser_lookup_entry(item);1120	struct gpio_virtuser_device *dev = entry->parent->parent;1121	unsigned int offset;1122 1123	scoped_guard(mutex, &dev->lock)1124		offset = entry->offset;1125 1126	return sprintf(page, "%d\n", offset);1127}1128 1129static ssize_t1130gpio_virtuser_lookup_entry_config_offset_store(struct config_item *item,1131					       const char *page, size_t count)1132{1133	struct gpio_virtuser_lookup_entry *entry =1134					to_gpio_virtuser_lookup_entry(item);1135	struct gpio_virtuser_device *dev = entry->parent->parent;1136	int offset, ret;1137 1138	ret = kstrtoint(page, 0, &offset);1139	if (ret)1140		return ret;1141 1142	/*1143	 * Negative number here means: 'key' represents a line name to lookup.1144	 * Non-negative means: 'key' represents the label of the chip with1145	 * the 'offset' value representing the line within that chip.1146	 *1147	 * GPIOLIB uses the U16_MAX value to indicate lookup by line name so1148	 * the greatest offset we can accept is (U16_MAX - 1).1149	 */1150	if (offset > (U16_MAX - 1))1151		return -EINVAL;1152 1153	guard(mutex)(&dev->lock);1154 1155	if (gpio_virtuser_device_is_live(dev))1156		return -EBUSY;1157 1158	entry->offset = offset;1159 1160	return count;1161}1162 1163CONFIGFS_ATTR(gpio_virtuser_lookup_entry_config_, offset);1164 1165static enum gpio_lookup_flags1166gpio_virtuser_lookup_get_flags(struct config_item *item)1167{1168	struct gpio_virtuser_lookup_entry *entry =1169					to_gpio_virtuser_lookup_entry(item);1170	struct gpio_virtuser_device *dev = entry->parent->parent;1171 1172	guard(mutex)(&dev->lock);1173 1174	return entry->flags;1175}1176 1177static ssize_t1178gpio_virtuser_lookup_entry_config_drive_show(struct config_item *item, char *page)1179{1180	enum gpio_lookup_flags flags = gpio_virtuser_lookup_get_flags(item);1181	const char *repr;1182 1183	if (flags & GPIO_OPEN_DRAIN)1184		repr = "open-drain";1185	else if (flags & GPIO_OPEN_SOURCE)1186		repr = "open-source";1187	else1188		repr = "push-pull";1189 1190	return sprintf(page, "%s\n", repr);1191}1192 1193static ssize_t1194gpio_virtuser_lookup_entry_config_drive_store(struct config_item *item,1195					      const char *page, size_t count)1196{1197	struct gpio_virtuser_lookup_entry *entry =1198					to_gpio_virtuser_lookup_entry(item);1199	struct gpio_virtuser_device *dev = entry->parent->parent;1200 1201	guard(mutex)(&dev->lock);1202 1203	if (gpio_virtuser_device_is_live(dev))1204		return -EBUSY;1205 1206	if (sysfs_streq(page, "push-pull")) {1207		entry->flags &= ~(GPIO_OPEN_DRAIN | GPIO_OPEN_SOURCE);1208	} else if (sysfs_streq(page, "open-drain")) {1209		entry->flags &= ~GPIO_OPEN_SOURCE;1210		entry->flags |= GPIO_OPEN_DRAIN;1211	} else if (sysfs_streq(page, "open-source")) {1212		entry->flags &= ~GPIO_OPEN_DRAIN;1213		entry->flags |= GPIO_OPEN_SOURCE;1214	} else {1215		count = -EINVAL;1216	}1217 1218	return count;1219}1220 1221CONFIGFS_ATTR(gpio_virtuser_lookup_entry_config_, drive);1222 1223static ssize_t1224gpio_virtuser_lookup_entry_config_pull_show(struct config_item *item, char *page)1225{1226	enum gpio_lookup_flags flags = gpio_virtuser_lookup_get_flags(item);1227	const char *repr;1228 1229	if (flags & GPIO_PULL_UP)1230		repr = "pull-up";1231	else if (flags & GPIO_PULL_DOWN)1232		repr = "pull-down";1233	else if (flags & GPIO_PULL_DISABLE)1234		repr = "pull-disabled";1235	else1236		repr = "as-is";1237 1238	return sprintf(page, "%s\n", repr);1239}1240 1241static ssize_t1242gpio_virtuser_lookup_entry_config_pull_store(struct config_item *item,1243					     const char *page, size_t count)1244{1245	struct gpio_virtuser_lookup_entry *entry =1246					to_gpio_virtuser_lookup_entry(item);1247	struct gpio_virtuser_device *dev = entry->parent->parent;1248 1249	guard(mutex)(&dev->lock);1250 1251	if (gpio_virtuser_device_is_live(dev))1252		return -EBUSY;1253 1254	if (sysfs_streq(page, "pull-up")) {1255		entry->flags &= ~(GPIO_PULL_DOWN | GPIO_PULL_DISABLE);1256		entry->flags |= GPIO_PULL_UP;1257	} else if (sysfs_streq(page, "pull-down")) {1258		entry->flags &= ~(GPIO_PULL_UP | GPIO_PULL_DISABLE);1259		entry->flags |= GPIO_PULL_DOWN;1260	} else if (sysfs_streq(page, "pull-disabled")) {1261		entry->flags &= ~(GPIO_PULL_UP | GPIO_PULL_DOWN);1262		entry->flags |= GPIO_PULL_DISABLE;1263	} else if (sysfs_streq(page, "as-is")) {1264		entry->flags &= ~(GPIO_PULL_UP | GPIO_PULL_DOWN |1265				  GPIO_PULL_DISABLE);1266	} else {1267		count = -EINVAL;1268	}1269 1270	return count;1271}1272 1273CONFIGFS_ATTR(gpio_virtuser_lookup_entry_config_, pull);1274 1275static ssize_t1276gpio_virtuser_lookup_entry_config_active_low_show(struct config_item *item,1277						  char *page)1278{1279	enum gpio_lookup_flags flags = gpio_virtuser_lookup_get_flags(item);1280 1281	return sprintf(page, "%c\n", flags & GPIO_ACTIVE_LOW ? '1' : '0');1282}1283 1284static ssize_t1285gpio_virtuser_lookup_entry_config_active_low_store(struct config_item *item,1286						   const char *page,1287						   size_t count)1288{1289	struct gpio_virtuser_lookup_entry *entry =1290					to_gpio_virtuser_lookup_entry(item);1291	struct gpio_virtuser_device *dev = entry->parent->parent;1292	bool active_low;1293	int ret;1294 1295	ret = kstrtobool(page, &active_low);1296	if (ret)1297		return ret;1298 1299	guard(mutex)(&dev->lock);1300 1301	if (gpio_virtuser_device_is_live(dev))1302		return -EBUSY;1303 1304	if (active_low)1305		entry->flags |= GPIO_ACTIVE_LOW;1306	else1307		entry->flags &= ~GPIO_ACTIVE_LOW;1308 1309	return count;1310}1311 1312CONFIGFS_ATTR(gpio_virtuser_lookup_entry_config_, active_low);1313 1314static ssize_t1315gpio_virtuser_lookup_entry_config_transitory_show(struct config_item *item,1316						  char *page)1317{1318	enum gpio_lookup_flags flags = gpio_virtuser_lookup_get_flags(item);1319 1320	return sprintf(page, "%c\n", flags & GPIO_TRANSITORY ? '1' : '0');1321}1322 1323static ssize_t1324gpio_virtuser_lookup_entry_config_transitory_store(struct config_item *item,1325						   const char *page,1326						   size_t count)1327{1328	struct gpio_virtuser_lookup_entry *entry =1329					to_gpio_virtuser_lookup_entry(item);1330	struct gpio_virtuser_device *dev = entry->parent->parent;1331	bool transitory;1332	int ret;1333 1334	ret = kstrtobool(page, &transitory);1335	if (ret)1336		return ret;1337 1338	guard(mutex)(&dev->lock);1339 1340	if (gpio_virtuser_device_is_live(dev))1341		return -EBUSY;1342 1343	if (transitory)1344		entry->flags |= GPIO_TRANSITORY;1345	else1346		entry->flags &= ~GPIO_TRANSITORY;1347 1348	return count;1349}1350 1351CONFIGFS_ATTR(gpio_virtuser_lookup_entry_config_, transitory);1352 1353static struct configfs_attribute *gpio_virtuser_lookup_entry_config_attrs[] = {1354	&gpio_virtuser_lookup_entry_config_attr_key,1355	&gpio_virtuser_lookup_entry_config_attr_offset,1356	&gpio_virtuser_lookup_entry_config_attr_drive,1357	&gpio_virtuser_lookup_entry_config_attr_pull,1358	&gpio_virtuser_lookup_entry_config_attr_active_low,1359	&gpio_virtuser_lookup_entry_config_attr_transitory,1360	NULL1361};1362 1363static ssize_t1364gpio_virtuser_device_config_dev_name_show(struct config_item *item,1365					  char *page)1366{1367	struct gpio_virtuser_device *dev = to_gpio_virtuser_device(item);1368	struct platform_device *pdev;1369 1370	guard(mutex)(&dev->lock);1371 1372	pdev = dev->pdev;1373	if (pdev)1374		return sprintf(page, "%s\n", dev_name(&pdev->dev));1375 1376	return sprintf(page, "gpio-sim.%d\n", dev->id);1377}1378 1379CONFIGFS_ATTR_RO(gpio_virtuser_device_config_, dev_name);1380 1381static ssize_t gpio_virtuser_device_config_live_show(struct config_item *item,1382						     char *page)1383{1384	struct gpio_virtuser_device *dev = to_gpio_virtuser_device(item);1385	bool live;1386 1387	scoped_guard(mutex, &dev->lock)1388		live = gpio_virtuser_device_is_live(dev);1389 1390	return sprintf(page, "%c\n", live ? '1' : '0');1391}1392 1393static size_t1394gpio_virtuser_get_lookup_count(struct gpio_virtuser_device *dev)1395{1396	struct gpio_virtuser_lookup *lookup;1397	size_t count = 0;1398 1399	lockdep_assert_held(&dev->lock);1400 1401	list_for_each_entry(lookup, &dev->lookup_list, siblings)1402		count += list_count_nodes(&lookup->entry_list);1403 1404	return count;1405}1406 1407static int1408gpio_virtuser_make_lookup_table(struct gpio_virtuser_device *dev)1409{1410	size_t num_entries = gpio_virtuser_get_lookup_count(dev);1411	struct gpio_virtuser_lookup_entry *entry;1412	struct gpio_virtuser_lookup *lookup;1413	unsigned int i = 0;1414 1415	lockdep_assert_held(&dev->lock);1416 1417	struct gpiod_lookup_table *table __free(kfree) =1418		kzalloc(struct_size(table, table, num_entries + 1), GFP_KERNEL);1419	if (!table)1420		return -ENOMEM;1421 1422	table->dev_id = kasprintf(GFP_KERNEL, "gpio-virtuser.%d", dev->id);1423	if (!table->dev_id)1424		return -ENOMEM;1425 1426	list_for_each_entry(lookup, &dev->lookup_list, siblings) {1427		list_for_each_entry(entry, &lookup->entry_list, siblings) {1428			table->table[i] =1429				GPIO_LOOKUP_IDX(entry->key,1430						entry->offset < 0 ? U16_MAX : entry->offset,1431						lookup->con_id, i, entry->flags);1432			i++;1433		}1434	}1435 1436	gpiod_add_lookup_table(table);1437	dev->lookup_table = no_free_ptr(table);1438 1439	return 0;1440}1441 1442static struct fwnode_handle *1443gpio_virtuser_make_device_swnode(struct gpio_virtuser_device *dev)1444{1445	struct property_entry properties[2];1446	struct gpio_virtuser_lookup *lookup;1447	unsigned int i = 0;1448	size_t num_ids;1449 1450	memset(properties, 0, sizeof(properties));1451 1452	num_ids = list_count_nodes(&dev->lookup_list);1453	char **ids __free(kfree) = kcalloc(num_ids + 1, sizeof(*ids),1454					   GFP_KERNEL);1455	if (!ids)1456		return ERR_PTR(-ENOMEM);1457 1458	list_for_each_entry(lookup, &dev->lookup_list, siblings)1459		ids[i++] = lookup->con_id;1460 1461	properties[0] = PROPERTY_ENTRY_STRING_ARRAY_LEN("gpio-virtuser,ids",1462							ids, num_ids);1463 1464	return fwnode_create_software_node(properties, NULL);1465}1466 1467static int1468gpio_virtuser_device_activate(struct gpio_virtuser_device *dev)1469{1470	struct platform_device_info pdevinfo;1471	struct fwnode_handle *swnode;1472	struct platform_device *pdev;1473	int ret;1474 1475	lockdep_assert_held(&dev->lock);1476 1477	if (list_empty(&dev->lookup_list))1478		return -ENODATA;1479 1480	swnode = gpio_virtuser_make_device_swnode(dev);1481	if (IS_ERR(swnode))1482		return PTR_ERR(swnode);1483 1484	memset(&pdevinfo, 0, sizeof(pdevinfo));1485	pdevinfo.name = "gpio-virtuser";1486	pdevinfo.id = dev->id;1487	pdevinfo.fwnode = swnode;1488 1489	ret = gpio_virtuser_make_lookup_table(dev);1490	if (ret) {1491		fwnode_remove_software_node(swnode);1492		return ret;1493	}1494 1495	reinit_completion(&dev->probe_completion);1496	dev->driver_bound = false;1497	bus_register_notifier(&platform_bus_type, &dev->bus_notifier);1498 1499	pdev = platform_device_register_full(&pdevinfo);1500	if (IS_ERR(pdev)) {1501		bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier);1502		fwnode_remove_software_node(swnode);1503		return PTR_ERR(pdev);1504	}1505 1506	wait_for_completion(&dev->probe_completion);1507	bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier);1508 1509	if (!dev->driver_bound) {1510		platform_device_unregister(pdev);1511		fwnode_remove_software_node(swnode);1512		return -ENXIO;1513	}1514 1515	dev->pdev = pdev;1516 1517	return 0;1518}1519 1520static void1521gpio_virtuser_device_deactivate(struct gpio_virtuser_device *dev)1522{1523	struct fwnode_handle *swnode;1524 1525	lockdep_assert_held(&dev->lock);1526 1527	swnode = dev_fwnode(&dev->pdev->dev);1528	platform_device_unregister(dev->pdev);1529	fwnode_remove_software_node(swnode);1530	dev->pdev = NULL;1531	gpiod_remove_lookup_table(dev->lookup_table);1532	kfree(dev->lookup_table);1533}1534 1535static ssize_t1536gpio_virtuser_device_config_live_store(struct config_item *item,1537				       const char *page, size_t count)1538{1539	struct gpio_virtuser_device *dev = to_gpio_virtuser_device(item);1540	int ret = 0;1541	bool live;1542 1543	ret = kstrtobool(page, &live);1544	if (ret)1545		return ret;1546 1547	guard(mutex)(&dev->lock);1548 1549	if (live == gpio_virtuser_device_is_live(dev))1550		return -EPERM;1551 1552	if (live)1553		ret = gpio_virtuser_device_activate(dev);1554	else1555		gpio_virtuser_device_deactivate(dev);1556 1557	return ret ?: count;1558}1559 1560CONFIGFS_ATTR(gpio_virtuser_device_config_, live);1561 1562static struct configfs_attribute *gpio_virtuser_device_config_attrs[] = {1563	&gpio_virtuser_device_config_attr_dev_name,1564	&gpio_virtuser_device_config_attr_live,1565	NULL1566};1567 1568static void1569gpio_virtuser_lookup_entry_config_group_release(struct config_item *item)1570{1571	struct gpio_virtuser_lookup_entry *entry =1572					to_gpio_virtuser_lookup_entry(item);1573	struct gpio_virtuser_device *dev = entry->parent->parent;1574 1575	guard(mutex)(&dev->lock);1576 1577	list_del(&entry->siblings);1578 1579	kfree(entry->key);1580	kfree(entry);1581}1582 1583static struct1584configfs_item_operations gpio_virtuser_lookup_entry_config_item_ops = {1585	.release	= gpio_virtuser_lookup_entry_config_group_release,1586};1587 1588static const struct1589config_item_type gpio_virtuser_lookup_entry_config_group_type = {1590	.ct_item_ops	= &gpio_virtuser_lookup_entry_config_item_ops,1591	.ct_attrs	= gpio_virtuser_lookup_entry_config_attrs,1592	.ct_owner	= THIS_MODULE,1593};1594 1595static struct config_group *1596gpio_virtuser_make_lookup_entry_group(struct config_group *group,1597				      const char *name)1598{1599	struct gpio_virtuser_lookup *lookup =1600				to_gpio_virtuser_lookup(&group->cg_item);1601	struct gpio_virtuser_device *dev = lookup->parent;1602 1603	guard(mutex)(&dev->lock);1604 1605	if (gpio_virtuser_device_is_live(dev))1606		return ERR_PTR(-EBUSY);1607 1608	struct gpio_virtuser_lookup_entry *entry __free(kfree) =1609				kzalloc(sizeof(*entry), GFP_KERNEL);1610	if (!entry)1611		return ERR_PTR(-ENOMEM);1612 1613	config_group_init_type_name(&entry->group, name,1614			&gpio_virtuser_lookup_entry_config_group_type);1615	entry->flags = GPIO_LOOKUP_FLAGS_DEFAULT;1616	entry->parent = lookup;1617	list_add_tail(&entry->siblings, &lookup->entry_list);1618 1619	return &no_free_ptr(entry)->group;1620}1621 1622static void gpio_virtuser_lookup_config_group_release(struct config_item *item)1623{1624	struct gpio_virtuser_lookup *lookup = to_gpio_virtuser_lookup(item);1625	struct gpio_virtuser_device *dev = lookup->parent;1626 1627	guard(mutex)(&dev->lock);1628 1629	list_del(&lookup->siblings);1630 1631	kfree(lookup->con_id);1632	kfree(lookup);1633}1634 1635static struct configfs_item_operations gpio_virtuser_lookup_config_item_ops = {1636	.release	= gpio_virtuser_lookup_config_group_release,1637};1638 1639static struct1640configfs_group_operations gpio_virtuser_lookup_config_group_ops = {1641	.make_group     = gpio_virtuser_make_lookup_entry_group,1642};1643 1644static const struct config_item_type gpio_virtuser_lookup_config_group_type = {1645	.ct_group_ops	= &gpio_virtuser_lookup_config_group_ops,1646	.ct_item_ops	= &gpio_virtuser_lookup_config_item_ops,1647	.ct_owner	= THIS_MODULE,1648};1649 1650static struct config_group *1651gpio_virtuser_make_lookup_group(struct config_group *group, const char *name)1652{1653	struct gpio_virtuser_device *dev =1654				to_gpio_virtuser_device(&group->cg_item);1655 1656	if (strlen(name) > (GPIO_VIRTUSER_NAME_BUF_LEN - 1))1657		return ERR_PTR(-E2BIG);1658 1659	guard(mutex)(&dev->lock);1660 1661	if (gpio_virtuser_device_is_live(dev))1662		return ERR_PTR(-EBUSY);1663 1664	struct gpio_virtuser_lookup *lookup __free(kfree) =1665				kzalloc(sizeof(*lookup), GFP_KERNEL);1666	if (!lookup)1667		return ERR_PTR(-ENOMEM);1668 1669	lookup->con_id = kstrdup(name, GFP_KERNEL);1670	if (!lookup->con_id)1671		return ERR_PTR(-ENOMEM);1672 1673	config_group_init_type_name(&lookup->group, name,1674				    &gpio_virtuser_lookup_config_group_type);1675	INIT_LIST_HEAD(&lookup->entry_list);1676	lookup->parent = dev;1677	list_add_tail(&lookup->siblings, &dev->lookup_list);1678 1679	return &no_free_ptr(lookup)->group;1680}1681 1682static void gpio_virtuser_device_config_group_release(struct config_item *item)1683{1684	struct gpio_virtuser_device *dev = to_gpio_virtuser_device(item);1685 1686	guard(mutex)(&dev->lock);1687 1688	if (gpio_virtuser_device_is_live(dev))1689		gpio_virtuser_device_deactivate(dev);1690 1691	mutex_destroy(&dev->lock);1692	ida_free(&gpio_virtuser_ida, dev->id);1693	kfree(dev);1694}1695 1696static struct configfs_item_operations gpio_virtuser_device_config_item_ops = {1697	.release	= gpio_virtuser_device_config_group_release,1698};1699 1700static struct configfs_group_operations gpio_virtuser_device_config_group_ops = {1701	.make_group	= gpio_virtuser_make_lookup_group,1702};1703 1704static const struct config_item_type gpio_virtuser_device_config_group_type = {1705	.ct_group_ops	= &gpio_virtuser_device_config_group_ops,1706	.ct_item_ops	= &gpio_virtuser_device_config_item_ops,1707	.ct_attrs	= gpio_virtuser_device_config_attrs,1708	.ct_owner	= THIS_MODULE,1709};1710 1711static struct config_group *1712gpio_virtuser_config_make_device_group(struct config_group *group,1713				       const char *name)1714{1715	struct gpio_virtuser_device *dev __free(kfree) = kzalloc(sizeof(*dev),1716								 GFP_KERNEL);1717	if (!dev)1718		return ERR_PTR(-ENOMEM);1719 1720	dev->id = ida_alloc(&gpio_virtuser_ida, GFP_KERNEL);1721	if (dev->id < 0)1722		return ERR_PTR(dev->id);1723 1724	config_group_init_type_name(&dev->group, name,1725				    &gpio_virtuser_device_config_group_type);1726	mutex_init(&dev->lock);1727	INIT_LIST_HEAD(&dev->lookup_list);1728	dev->bus_notifier.notifier_call = gpio_virtuser_bus_notifier_call;1729	init_completion(&dev->probe_completion);1730 1731	return &no_free_ptr(dev)->group;1732}1733 1734static struct configfs_group_operations gpio_virtuser_config_group_ops = {1735	.make_group	= gpio_virtuser_config_make_device_group,1736};1737 1738static const struct config_item_type gpio_virtuser_config_type = {1739	.ct_group_ops	= &gpio_virtuser_config_group_ops,1740	.ct_owner	= THIS_MODULE,1741};1742 1743static struct configfs_subsystem gpio_virtuser_config_subsys = {1744	.su_group = {1745		.cg_item = {1746			.ci_namebuf	= "gpio-virtuser",1747			.ci_type	= &gpio_virtuser_config_type,1748		},1749	},1750};1751 1752static int __init gpio_virtuser_init(void)1753{1754	int ret;1755 1756	ret = platform_driver_register(&gpio_virtuser_driver);1757	if (ret) {1758		pr_err("Failed to register the platform driver: %d\n", ret);1759		return ret;1760	}1761 1762	config_group_init(&gpio_virtuser_config_subsys.su_group);1763	mutex_init(&gpio_virtuser_config_subsys.su_mutex);1764	ret = configfs_register_subsystem(&gpio_virtuser_config_subsys);1765	if (ret) {1766		pr_err("Failed to register the '%s' configfs subsystem: %d\n",1767		       gpio_virtuser_config_subsys.su_group.cg_item.ci_namebuf,1768		       ret);1769		goto err_plat_drv_unreg;1770	}1771 1772	gpio_virtuser_dbg_root = debugfs_create_dir("gpio-virtuser", NULL);1773	if (IS_ERR(gpio_virtuser_dbg_root)) {1774		ret = PTR_ERR(gpio_virtuser_dbg_root);1775		pr_err("Failed to create the debugfs tree: %d\n", ret);1776		goto err_configfs_unreg;1777	}1778 1779	return 0;1780 1781err_configfs_unreg:1782	configfs_unregister_subsystem(&gpio_virtuser_config_subsys);1783err_plat_drv_unreg:1784	mutex_destroy(&gpio_virtuser_config_subsys.su_mutex);1785	platform_driver_unregister(&gpio_virtuser_driver);1786 1787	return ret;1788}1789module_init(gpio_virtuser_init);1790 1791static void __exit gpio_virtuser_exit(void)1792{1793	configfs_unregister_subsystem(&gpio_virtuser_config_subsys);1794	mutex_destroy(&gpio_virtuser_config_subsys.su_mutex);1795	platform_driver_unregister(&gpio_virtuser_driver);1796	debugfs_remove_recursive(gpio_virtuser_dbg_root);1797}1798module_exit(gpio_virtuser_exit);1799 1800MODULE_AUTHOR("Bartosz Golaszewski <bartosz.golaszewski@linaro.org>");1801MODULE_DESCRIPTION("Virtual GPIO consumer module");1802MODULE_LICENSE("GPL");1803