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