gpiolib: rewrite gpiodev_add_to_list
The original code of gpiodev_add_to_list is not very clear which lead to bugs or compiling warning, reference the following patches: Bugs: 1. Commitef7c755303
("gpiolib: improve overlap check of range of gpio"). 2. Commit96098df125
("gpiolib: fix chip order in gpio list") Warning: 1. Commite28ecca6ea
("gpio: fix warning about iterator"). of gpio"). There is a off-list discussion about how to improve it consequently. This commit try to follow this by rewriting the whole functions. Tested pass with my gpio mockup driver and test scripts[1]. [1] http://www.spinics.net/lists/linux-gpio/msg09598.html Suggested-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Bamvor Jian Zhang <bamvor.zhangjian@linaro.org> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
24030d9d95
commit
a961f9b472
|
@ -206,58 +206,43 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction);
|
||||||
*/
|
*/
|
||||||
static int gpiodev_add_to_list(struct gpio_device *gdev)
|
static int gpiodev_add_to_list(struct gpio_device *gdev)
|
||||||
{
|
{
|
||||||
struct gpio_device *iterator;
|
struct gpio_device *prev, *next;
|
||||||
struct gpio_device *previous = NULL;
|
|
||||||
|
|
||||||
if (!gdev->chip)
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (list_empty(&gpio_devices)) {
|
if (list_empty(&gpio_devices)) {
|
||||||
|
/* initial entry in list */
|
||||||
list_add_tail(&gdev->list, &gpio_devices);
|
list_add_tail(&gdev->list, &gpio_devices);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_for_each_entry(iterator, &gpio_devices, list) {
|
next = list_entry(gpio_devices.next, struct gpio_device, list);
|
||||||
if (iterator->base >= gdev->base + gdev->ngpio) {
|
if (gdev->base + gdev->ngpio <= next->base) {
|
||||||
/*
|
/* add before first entry */
|
||||||
* Iterator is the first GPIO chip so there is no
|
list_add(&gdev->list, &gpio_devices);
|
||||||
* previous one
|
|
||||||
*/
|
|
||||||
if (!previous) {
|
|
||||||
goto found;
|
|
||||||
} else {
|
|
||||||
/*
|
|
||||||
* We found a valid range(means
|
|
||||||
* [base, base + ngpio - 1]) between previous
|
|
||||||
* and iterator chip.
|
|
||||||
*/
|
|
||||||
if (previous->base + previous->ngpio
|
|
||||||
<= gdev->base)
|
|
||||||
goto found;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
previous = iterator;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We are beyond the last chip in the list and iterator now
|
|
||||||
* points to the head.
|
|
||||||
* Let iterator point to the last chip in the list.
|
|
||||||
*/
|
|
||||||
|
|
||||||
iterator = list_last_entry(&gpio_devices, struct gpio_device, list);
|
|
||||||
if (iterator->base + iterator->ngpio <= gdev->base) {
|
|
||||||
list_add(&gdev->list, &iterator->list);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_err(&gdev->dev,
|
prev = list_entry(gpio_devices.prev, struct gpio_device, list);
|
||||||
"GPIO integer space overlap, cannot add chip\n");
|
if (prev->base + prev->ngpio <= gdev->base) {
|
||||||
return -EBUSY;
|
/* add behind last entry */
|
||||||
|
list_add_tail(&gdev->list, &gpio_devices);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
found:
|
list_for_each_entry_safe(prev, next, &gpio_devices, list) {
|
||||||
list_add_tail(&gdev->list, &iterator->list);
|
/* at the end of the list */
|
||||||
return 0;
|
if (&next->list == &gpio_devices)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* add between prev and next */
|
||||||
|
if (prev->base + prev->ngpio <= gdev->base
|
||||||
|
&& gdev->base + gdev->ngpio <= next->base) {
|
||||||
|
list_add(&gdev->list, &prev->list);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_err(&gdev->dev, "GPIO integer space overlap, cannot add chip\n");
|
||||||
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue