diff options
Diffstat (limited to 'drivers/gpio/gpio-sim.c')
| -rw-r--r-- | drivers/gpio/gpio-sim.c | 448 |
1 files changed, 281 insertions, 167 deletions
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index 271db3639a78..a83f5238427c 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -7,11 +7,13 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/array_size.h> #include <linux/bitmap.h> #include <linux/cleanup.h> -#include <linux/completion.h> #include <linux/configfs.h> #include <linux/device.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> #include <linux/gpio/driver.h> #include <linux/gpio/machine.h> #include <linux/idr.h> @@ -19,27 +21,33 @@ #include <linux/irq.h> #include <linux/irq_sim.h> #include <linux/list.h> +#include <linux/lockdep.h> +#include <linux/minmax.h> #include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/notifier.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/string_helpers.h> #include <linux/sysfs.h> +#include <linux/types.h> -#include "gpiolib.h" +#include "dev-sync-probe.h" #define GPIO_SIM_NGPIO_MAX 1024 -#define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ +#define GPIO_SIM_PROP_MAX 5 /* Max 4 properties + sentinel. */ #define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ static DEFINE_IDA(gpio_sim_ida); struct gpio_sim_chip { struct gpio_chip gc; + struct device *dev; + unsigned long *request_map; unsigned long *direction_map; unsigned long *value_map; unsigned long *pull_map; @@ -63,16 +71,11 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, unsigned int offset, int value) { int irq, irq_type, ret; - struct gpio_desc *desc; - struct gpio_chip *gc; - - gc = &chip->gc; - desc = &gc->gpiodev->descs[offset]; guard(mutex)(&chip->lock); - if (test_bit(FLAG_REQUESTED, &desc->flags) && - !test_bit(FLAG_IS_OUT, &desc->flags)) { + if (test_bit(offset, chip->request_map) && + test_bit(offset, chip->direction_map)) { if (value == !!test_bit(offset, chip->value_map)) goto set_pull; @@ -99,8 +102,8 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip, set_value: /* Change the value unless we're actively driving the line. */ - if (!test_bit(FLAG_REQUESTED, &desc->flags) || - !test_bit(FLAG_IS_OUT, &desc->flags)) + if (!test_bit(offset, chip->request_map) || + test_bit(offset, chip->direction_map)) __assign_bit(offset, chip->value_map, value); set_pull: @@ -117,12 +120,14 @@ static int gpio_sim_get(struct gpio_chip *gc, unsigned int offset) return !!test_bit(offset, chip->value_map); } -static void gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) +static int gpio_sim_set(struct gpio_chip *gc, unsigned int offset, int value) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); scoped_guard(mutex, &chip->lock) __assign_bit(offset, chip->value_map, value); + + return 0; } static int gpio_sim_get_multiple(struct gpio_chip *gc, @@ -136,14 +141,16 @@ static int gpio_sim_get_multiple(struct gpio_chip *gc, return 0; } -static void gpio_sim_set_multiple(struct gpio_chip *gc, - unsigned long *mask, unsigned long *bits) +static int gpio_sim_set_multiple(struct gpio_chip *gc, + unsigned long *mask, unsigned long *bits) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); scoped_guard(mutex, &chip->lock) bitmap_replace(chip->value_map, chip->value_map, bits, mask, gc->ngpio); + + return 0; } static int gpio_sim_direction_output(struct gpio_chip *gc, @@ -180,8 +187,8 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset) return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT; } -static int gpio_sim_set_config(struct gpio_chip *gc, - unsigned int offset, unsigned long config) +static int gpio_sim_set_config(struct gpio_chip *gc, unsigned int offset, + unsigned long config) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); @@ -204,13 +211,64 @@ static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset) return irq_create_mapping(chip->irq_sim, offset); } -static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) +static int gpio_sim_request(struct gpio_chip *gc, unsigned int offset) { struct gpio_sim_chip *chip = gpiochip_get_data(gc); scoped_guard(mutex, &chip->lock) + __set_bit(offset, chip->request_map); + + return 0; +} + +static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + + scoped_guard(mutex, &chip->lock) { __assign_bit(offset, chip->value_map, !!test_bit(offset, chip->pull_map)); + __clear_bit(offset, chip->request_map); + } +} + +static int gpio_sim_irq_requested(struct irq_domain *domain, + irq_hw_number_t hwirq, void *data) +{ + struct gpio_sim_chip *chip = data; + + return gpiochip_lock_as_irq(&chip->gc, hwirq); +} + +static void gpio_sim_irq_released(struct irq_domain *domain, + irq_hw_number_t hwirq, void *data) +{ + struct gpio_sim_chip *chip = data; + + gpiochip_unlock_as_irq(&chip->gc, hwirq); +} + +static const struct irq_sim_ops gpio_sim_irq_sim_ops = { + .irq_sim_irq_requested = gpio_sim_irq_requested, + .irq_sim_irq_released = gpio_sim_irq_released, +}; + +static void gpio_sim_dbg_show(struct seq_file *seq, struct gpio_chip *gc) +{ + struct gpio_sim_chip *chip = gpiochip_get_data(gc); + const char *label; + int i; + + guard(mutex)(&chip->lock); + + for_each_hwgpio(gc, i, label) + seq_printf(seq, " gpio-%-3d (%s) %s,%s\n", i, + label ?: "<unused>", + test_bit(i, chip->direction_map) ? "input" : + test_bit(i, chip->value_map) ? "output-high" : + "output-low", + test_bit(i, chip->pull_map) ? "pull-up" : + "pull-down"); } static ssize_t gpio_sim_sysfs_val_show(struct device *dev, @@ -275,11 +333,11 @@ static ssize_t gpio_sim_sysfs_pull_store(struct device *dev, return len; } -static void gpio_sim_mutex_destroy(void *data) +static void gpio_sim_put_device(void *data) { - struct mutex *lock = data; + struct device *dev = data; - mutex_destroy(lock); + put_device(dev); } static void gpio_sim_dispose_mappings(void *data) @@ -295,7 +353,7 @@ static void gpio_sim_sysfs_remove(void *data) { struct gpio_sim_chip *chip = data; - sysfs_remove_groups(&chip->gc.gpiodev->dev.kobj, chip->attr_groups); + sysfs_remove_groups(&chip->dev->kobj, chip->attr_groups); } static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) @@ -352,8 +410,7 @@ static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip) chip->attr_groups[i] = attr_group; } - ret = sysfs_create_groups(&chip->gc.gpiodev->dev.kobj, - chip->attr_groups); + ret = sysfs_create_groups(&chip->dev->kobj, chip->attr_groups); if (ret) return ret; @@ -377,7 +434,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) ret = fwnode_property_read_string(swnode, "gpio-sim,label", &label); if (ret) { - label = devm_kasprintf(dev, GFP_KERNEL, "%s-%pfwP", + label = devm_kasprintf(dev, GFP_KERNEL, "%s:%pfwP", dev_name(dev), swnode); if (!label) return -ENOMEM; @@ -387,6 +444,10 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) if (!chip) return -ENOMEM; + chip->request_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL); + if (!chip->request_map) + return -ENOMEM; + chip->direction_map = devm_bitmap_alloc(dev, num_lines, GFP_KERNEL); if (!chip->direction_map) return -ENOMEM; @@ -402,7 +463,9 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) if (!chip->pull_map) return -ENOMEM; - chip->irq_sim = devm_irq_domain_create_sim(dev, swnode, num_lines); + chip->irq_sim = devm_irq_domain_create_sim_full(dev, swnode, num_lines, + &gpio_sim_irq_sim_ops, + chip); if (IS_ERR(chip->irq_sim)) return PTR_ERR(chip->irq_sim); @@ -410,9 +473,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) if (ret) return ret; - mutex_init(&chip->lock); - ret = devm_add_action_or_reset(dev, gpio_sim_mutex_destroy, - &chip->lock); + ret = devm_mutex_init(dev, &chip->lock); if (ret) return ret; @@ -432,15 +493,25 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) gc->get_direction = gpio_sim_get_direction; gc->set_config = gpio_sim_set_config; gc->to_irq = gpio_sim_to_irq; + gc->request = gpio_sim_request; gc->free = gpio_sim_free; + gc->dbg_show = PTR_IF(IS_ENABLED(CONFIG_DEBUG_FS), gpio_sim_dbg_show); gc->can_sleep = true; ret = devm_gpiochip_add_data(dev, gc, chip); if (ret) return ret; - /* Used by sysfs and configfs callbacks. */ - dev_set_drvdata(&gc->gpiodev->dev, chip); + chip->dev = device_find_child(dev, swnode, device_match_fwnode); + if (!chip->dev) + return -ENODEV; + + ret = devm_add_action_or_reset(dev, gpio_sim_put_device, chip->dev); + if (ret) + return ret; + + /* Used by sysfs callbacks. */ + dev_set_drvdata(chip->dev, chip); return gpio_sim_setup_sysfs(chip); } @@ -448,15 +519,12 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev) static int gpio_sim_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct fwnode_handle *swnode; int ret; - device_for_each_child_node(dev, swnode) { + device_for_each_child_node_scoped(dev, swnode) { ret = gpio_sim_add_bank(swnode, dev); - if (ret) { - fwnode_handle_put(swnode); + if (ret) return ret; - } } return 0; @@ -477,14 +545,9 @@ static struct platform_driver gpio_sim_driver = { }; struct gpio_sim_device { + struct dev_sync_probe_data probe_data; struct config_group group; - /* - * If pdev is NULL, the device is 'pending' (waiting for configuration). - * Once the pointer is assigned, the device has been created and the - * item is 'live'. - */ - struct platform_device *pdev; int id; /* @@ -498,46 +561,11 @@ struct gpio_sim_device { */ struct mutex lock; - /* - * This is used to synchronously wait for the driver's probe to complete - * and notify the user-space about any errors. - */ - struct notifier_block bus_notifier; - struct completion probe_completion; - bool driver_bound; - struct gpiod_hog *hogs; struct list_head bank_list; }; -/* This is called with dev->lock already taken. */ -static int gpio_sim_bus_notifier_call(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct gpio_sim_device *simdev = container_of(nb, - struct gpio_sim_device, - bus_notifier); - struct device *dev = data; - char devname[32]; - - snprintf(devname, sizeof(devname), "gpio-sim.%u", simdev->id); - - if (strcmp(dev_name(dev), devname) == 0) { - if (action == BUS_NOTIFY_BOUND_DRIVER) - simdev->driver_bound = true; - else if (action == BUS_NOTIFY_DRIVER_NOT_BOUND) - simdev->driver_bound = false; - else - return NOTIFY_DONE; - - complete(&simdev->probe_completion); - return NOTIFY_OK; - } - - return NOTIFY_DONE; -} - static struct gpio_sim_device *to_gpio_sim_device(struct config_item *item) { struct config_group *group = to_config_group(item); @@ -600,6 +628,7 @@ struct gpio_sim_line { unsigned int offset; char *name; + bool valid; /* There can only be one hog per line. */ struct gpio_sim_hog *hog; @@ -640,9 +669,11 @@ static struct gpio_sim_device *gpio_sim_hog_get_device(struct gpio_sim_hog *hog) return gpio_sim_line_get_device(line); } -static bool gpio_sim_device_is_live_unlocked(struct gpio_sim_device *dev) +static bool gpio_sim_device_is_live(struct gpio_sim_device *dev) { - return !!dev->pdev; + lockdep_assert_held(&dev->lock); + + return !!dev->probe_data.pdev; } static char *gpio_sim_strdup_trimmed(const char *str, size_t count) @@ -664,7 +695,7 @@ static ssize_t gpio_sim_device_config_dev_name_show(struct config_item *item, guard(mutex)(&dev->lock); - pdev = dev->pdev; + pdev = dev->probe_data.pdev; if (pdev) return sprintf(page, "%s\n", dev_name(&pdev->dev)); @@ -680,57 +711,67 @@ gpio_sim_device_config_live_show(struct config_item *item, char *page) bool live; scoped_guard(mutex, &dev->lock) - live = gpio_sim_device_is_live_unlocked(dev); + live = gpio_sim_device_is_live(dev); return sprintf(page, "%c\n", live ? '1' : '0'); } -static char **gpio_sim_make_line_names(struct gpio_sim_bank *bank, - unsigned int *line_names_size) +static unsigned int gpio_sim_get_line_names_size(struct gpio_sim_bank *bank) { - unsigned int max_offset = 0; - bool has_line_names = false; struct gpio_sim_line *line; - char **line_names; + unsigned int size = 0; list_for_each_entry(line, &bank->line_list, siblings) { - if (line->offset >= bank->num_lines) + if (!line->name || (line->offset >= bank->num_lines)) continue; - if (line->name) { - if (line->offset > max_offset) - max_offset = line->offset; - - /* - * max_offset can stay at 0 so it's not an indicator - * of whether line names were configured at all. - */ - has_line_names = true; - } + size = max(size, line->offset + 1); } - if (!has_line_names) - /* - * This is not an error - NULL means, there are no line - * names configured. - */ - return NULL; + return size; +} - *line_names_size = max_offset + 1; +static void +gpio_sim_set_line_names(struct gpio_sim_bank *bank, char **line_names) +{ + struct gpio_sim_line *line; - line_names = kcalloc(*line_names_size, sizeof(*line_names), GFP_KERNEL); - if (!line_names) - return ERR_PTR(-ENOMEM); + list_for_each_entry(line, &bank->line_list, siblings) { + if (!line->name || (line->offset >= bank->num_lines)) + continue; + + line_names[line->offset] = line->name; + } +} + +static unsigned int gpio_sim_get_reserved_ranges_size(struct gpio_sim_bank *bank) +{ + struct gpio_sim_line *line; + unsigned int size = 0; list_for_each_entry(line, &bank->line_list, siblings) { - if (line->offset >= bank->num_lines) + if (line->valid) continue; - if (line->name && (line->offset <= max_offset)) - line_names[line->offset] = line->name; + size += 2; } - return line_names; + return size; +} + +static void gpio_sim_set_reserved_ranges(struct gpio_sim_bank *bank, + u32 *ranges) +{ + struct gpio_sim_line *line; + int i = 0; + + list_for_each_entry(line, &bank->line_list, siblings) { + if (line->valid) + continue; + + ranges[i++] = line->offset; + ranges[i++] = 1; + } } static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) @@ -796,7 +837,7 @@ static int gpio_sim_add_hogs(struct gpio_sim_device *dev) GFP_KERNEL); else hog->chip_label = kasprintf(GFP_KERNEL, - "gpio-sim.%u-%pfwP", + "gpio-sim.%u:%pfwP", dev->id, bank->swnode); if (!hog->chip_label) { @@ -833,9 +874,10 @@ static struct fwnode_handle * gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, struct fwnode_handle *parent) { + unsigned int prop_idx = 0, line_names_size, ranges_size; struct property_entry properties[GPIO_SIM_PROP_MAX]; - unsigned int prop_idx = 0, line_names_size = 0; char **line_names __free(kfree) = NULL; + u32 *ranges __free(kfree) = NULL; memset(properties, 0, sizeof(properties)); @@ -845,14 +887,32 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, properties[prop_idx++] = PROPERTY_ENTRY_STRING("gpio-sim,label", bank->label); - line_names = gpio_sim_make_line_names(bank, &line_names_size); - if (IS_ERR(line_names)) - return ERR_CAST(line_names); + line_names_size = gpio_sim_get_line_names_size(bank); + if (line_names_size) { + line_names = kcalloc(line_names_size, sizeof(*line_names), + GFP_KERNEL); + if (!line_names) + return ERR_PTR(-ENOMEM); + + gpio_sim_set_line_names(bank, line_names); - if (line_names) properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( "gpio-line-names", line_names, line_names_size); + } + + ranges_size = gpio_sim_get_reserved_ranges_size(bank); + if (ranges_size) { + ranges = kcalloc(ranges_size, sizeof(u32), GFP_KERNEL); + if (!ranges) + return ERR_PTR(-ENOMEM); + + gpio_sim_set_reserved_ranges(bank, ranges); + + properties[prop_idx++] = PROPERTY_ENTRY_U32_ARRAY_LEN( + "gpio-reserved-ranges", + ranges, ranges_size); + } return fwnode_create_software_node(properties, parent); } @@ -884,14 +944,15 @@ static bool gpio_sim_bank_labels_non_unique(struct gpio_sim_device *dev) return false; } -static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev) +static int gpio_sim_device_activate(struct gpio_sim_device *dev) { struct platform_device_info pdevinfo; struct fwnode_handle *swnode; - struct platform_device *pdev; struct gpio_sim_bank *bank; int ret; + lockdep_assert_held(&dev->lock); + if (list_empty(&dev->bank_list)) return -ENODATA; @@ -928,43 +989,53 @@ static int gpio_sim_device_activate_unlocked(struct gpio_sim_device *dev) pdevinfo.fwnode = swnode; pdevinfo.id = dev->id; - reinit_completion(&dev->probe_completion); - dev->driver_bound = false; - bus_register_notifier(&platform_bus_type, &dev->bus_notifier); - - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - gpio_sim_remove_hogs(dev); - gpio_sim_remove_swnode_recursive(swnode); - return PTR_ERR(pdev); - } - - wait_for_completion(&dev->probe_completion); - bus_unregister_notifier(&platform_bus_type, &dev->bus_notifier); - - if (!dev->driver_bound) { - /* Probe failed, check kernel log. */ - platform_device_unregister(pdev); + ret = dev_sync_probe_register(&dev->probe_data, &pdevinfo); + if (ret) { gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); - return -ENXIO; + return ret; } - dev->pdev = pdev; - return 0; } -static void gpio_sim_device_deactivate_unlocked(struct gpio_sim_device *dev) +static void gpio_sim_device_deactivate(struct gpio_sim_device *dev) { struct fwnode_handle *swnode; - swnode = dev_fwnode(&dev->pdev->dev); - platform_device_unregister(dev->pdev); + lockdep_assert_held(&dev->lock); + + swnode = dev_fwnode(&dev->probe_data.pdev->dev); + dev_sync_probe_unregister(&dev->probe_data); gpio_sim_remove_hogs(dev); gpio_sim_remove_swnode_recursive(swnode); - dev->pdev = NULL; +} + +static void +gpio_sim_device_lockup_configfs(struct gpio_sim_device *dev, bool lock) +{ + struct configfs_subsystem *subsys = dev->group.cg_subsys; + struct gpio_sim_bank *bank; + struct gpio_sim_line *line; + struct config_item *item; + + /* + * The device only needs to depend on leaf entries. This is + * sufficient to lock up all the configfs entries that the + * instantiated, alive device depends on. + */ + list_for_each_entry(bank, &dev->bank_list, siblings) { + list_for_each_entry(line, &bank->line_list, siblings) { + item = line->hog ? &line->hog->item + : &line->group.cg_item; + + if (lock) + WARN_ON(configfs_depend_item_unlocked(subsys, + item)); + else + configfs_undepend_item_unlocked(item); + } + } } static ssize_t @@ -979,14 +1050,24 @@ gpio_sim_device_config_live_store(struct config_item *item, if (ret) return ret; - guard(mutex)(&dev->lock); + if (live) + gpio_sim_device_lockup_configfs(dev, true); - if (live == gpio_sim_device_is_live_unlocked(dev)) - ret = -EPERM; - else if (live) - ret = gpio_sim_device_activate_unlocked(dev); - else - gpio_sim_device_deactivate_unlocked(dev); + scoped_guard(mutex, &dev->lock) { + if (live == gpio_sim_device_is_live(dev)) + ret = -EPERM; + else if (live) + ret = gpio_sim_device_activate(dev); + else + gpio_sim_device_deactivate(dev); + } + + /* + * Undepend is required only if device disablement (live == 0) + * succeeds or if device enablement (live == 1) fails. + */ + if (live == !!ret) + gpio_sim_device_lockup_configfs(dev, false); return ret ?: count; } @@ -1027,8 +1108,8 @@ static ssize_t gpio_sim_bank_config_chip_name_show(struct config_item *item, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) - return device_for_each_child(&dev->pdev->dev, &ctx, + if (gpio_sim_device_is_live(dev)) + return device_for_each_child(&dev->probe_data.pdev->dev, &ctx, gpio_sim_emit_chip_name); return sprintf(page, "none\n"); @@ -1056,7 +1137,7 @@ static ssize_t gpio_sim_bank_config_label_store(struct config_item *item, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return -EBUSY; trimmed = gpio_sim_strdup_trimmed(page, count); @@ -1100,7 +1181,7 @@ gpio_sim_bank_config_num_lines_store(struct config_item *item, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return -EBUSY; bank->num_lines = num_lines; @@ -1137,7 +1218,7 @@ static ssize_t gpio_sim_line_config_name_store(struct config_item *item, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return -EBUSY; trimmed = gpio_sim_strdup_trimmed(page, count); @@ -1152,8 +1233,41 @@ static ssize_t gpio_sim_line_config_name_store(struct config_item *item, CONFIGFS_ATTR(gpio_sim_line_config_, name); +static ssize_t +gpio_sim_line_config_valid_show(struct config_item *item, char *page) +{ + struct gpio_sim_line *line = to_gpio_sim_line(item); + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); + + guard(mutex)(&dev->lock); + + return sprintf(page, "%c\n", line->valid ? '1' : '0'); +} + +static ssize_t gpio_sim_line_config_valid_store(struct config_item *item, + const char *page, size_t count) +{ + struct gpio_sim_line *line = to_gpio_sim_line(item); + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); + bool valid; + int ret; + + ret = kstrtobool(page, &valid); + if (ret) + return ret; + + guard(mutex)(&dev->lock); + + line->valid = valid; + + return count; +} + +CONFIGFS_ATTR(gpio_sim_line_config_, valid); + static struct configfs_attribute *gpio_sim_line_config_attrs[] = { &gpio_sim_line_config_attr_name, + &gpio_sim_line_config_attr_valid, NULL }; @@ -1177,7 +1291,7 @@ static ssize_t gpio_sim_hog_config_name_store(struct config_item *item, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return -EBUSY; trimmed = gpio_sim_strdup_trimmed(page, count); @@ -1232,7 +1346,7 @@ gpio_sim_hog_config_direction_store(struct config_item *item, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return -EBUSY; if (sysfs_streq(page, "input")) @@ -1350,7 +1464,7 @@ gpio_sim_bank_config_make_line_group(struct config_group *group, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return ERR_PTR(-EBUSY); line = kzalloc(sizeof(*line), GFP_KERNEL); @@ -1362,6 +1476,7 @@ gpio_sim_bank_config_make_line_group(struct config_group *group, line->parent = bank; line->offset = offset; + line->valid = true; list_add_tail(&line->siblings, &bank->line_list); return &line->group; @@ -1403,7 +1518,7 @@ gpio_sim_device_config_make_bank_group(struct config_group *group, guard(mutex)(&dev->lock); - if (gpio_sim_device_is_live_unlocked(dev)) + if (gpio_sim_device_is_live(dev)) return ERR_PTR(-EBUSY); bank = kzalloc(sizeof(*bank), GFP_KERNEL); @@ -1425,8 +1540,8 @@ static void gpio_sim_device_config_group_release(struct config_item *item) struct gpio_sim_device *dev = to_gpio_sim_device(item); scoped_guard(mutex, &dev->lock) { - if (gpio_sim_device_is_live_unlocked(dev)) - gpio_sim_device_deactivate_unlocked(dev); + if (gpio_sim_device_is_live(dev)) + gpio_sim_device_deactivate(dev); } mutex_destroy(&dev->lock); @@ -1452,10 +1567,10 @@ static const struct config_item_type gpio_sim_device_config_group_type = { static struct config_group * gpio_sim_config_make_device_group(struct config_group *group, const char *name) { - struct gpio_sim_device *dev __free(kfree) = NULL; int id; - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + struct gpio_sim_device *dev __free(kfree) = kzalloc(sizeof(*dev), + GFP_KERNEL); if (!dev) return ERR_PTR(-ENOMEM); @@ -1469,8 +1584,7 @@ gpio_sim_config_make_device_group(struct config_group *group, const char *name) mutex_init(&dev->lock); INIT_LIST_HEAD(&dev->bank_list); - dev->bus_notifier.notifier_call = gpio_sim_bus_notifier_call; - init_completion(&dev->probe_completion); + dev_sync_probe_init(&dev->probe_data); return &no_free_ptr(dev)->group; } @@ -1526,6 +1640,6 @@ static void __exit gpio_sim_exit(void) } module_exit(gpio_sim_exit); -MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl"); +MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>"); MODULE_DESCRIPTION("GPIO Simulator Module"); MODULE_LICENSE("GPL"); |
