mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-13 14:04:05 +08:00
gpiolib: provide gpio_device_find()
gpiochip_find() is wrong and its kernel doc is misleading as the function doesn't return a reference to the gpio_chip but just a raw pointer. The chip itself is not guaranteed to stay alive, in fact it can be deleted at any point. Also: other than GPIO drivers themselves, nobody else has any business accessing gpio_chip structs. Provide a new gpio_device_find() function that returns a real reference to the opaque gpio_device structure that is guaranteed to stay alive for as long as there are active users of it. Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org> Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
This commit is contained in:
parent
9e4555d1e5
commit
cfe102f633
@ -1014,16 +1014,10 @@ void gpiochip_remove(struct gpio_chip *gc)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiochip_remove);
|
EXPORT_SYMBOL_GPL(gpiochip_remove);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* gpiochip_find() - iterator for locating a specific gpio_chip
|
* FIXME: This will be removed soon.
|
||||||
* @data: data to pass to match function
|
|
||||||
* @match: Callback function to check gpio_chip
|
|
||||||
*
|
*
|
||||||
* Similar to bus_find_device. It returns a reference to a gpio_chip as
|
* This function is depracated, don't use.
|
||||||
* determined by a user supplied @match callback. The callback should return
|
|
||||||
* 0 if the device doesn't match and non-zero if it does. If the callback is
|
|
||||||
* non-zero, this function will return to the caller and not iterate over any
|
|
||||||
* more gpio_chips.
|
|
||||||
*/
|
*/
|
||||||
struct gpio_chip *gpiochip_find(void *data,
|
struct gpio_chip *gpiochip_find(void *data,
|
||||||
int (*match)(struct gpio_chip *gc,
|
int (*match)(struct gpio_chip *gc,
|
||||||
@ -1031,21 +1025,62 @@ struct gpio_chip *gpiochip_find(void *data,
|
|||||||
{
|
{
|
||||||
struct gpio_device *gdev;
|
struct gpio_device *gdev;
|
||||||
struct gpio_chip *gc = NULL;
|
struct gpio_chip *gc = NULL;
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
spin_lock_irqsave(&gpio_lock, flags);
|
gdev = gpio_device_find(data, match);
|
||||||
list_for_each_entry(gdev, &gpio_devices, list)
|
if (gdev) {
|
||||||
if (gdev->chip && match(gdev->chip, data)) {
|
gc = gdev->chip;
|
||||||
gc = gdev->chip;
|
gpio_device_put(gdev);
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&gpio_lock, flags);
|
|
||||||
|
|
||||||
return gc;
|
return gc;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(gpiochip_find);
|
EXPORT_SYMBOL_GPL(gpiochip_find);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gpio_device_find() - find a specific GPIO device
|
||||||
|
* @data: data to pass to match function
|
||||||
|
* @match: Callback function to check gpio_chip
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* New reference to struct gpio_device.
|
||||||
|
*
|
||||||
|
* Similar to bus_find_device(). It returns a reference to a gpio_device as
|
||||||
|
* determined by a user supplied @match callback. The callback should return
|
||||||
|
* 0 if the device doesn't match and non-zero if it does. If the callback
|
||||||
|
* returns non-zero, this function will return to the caller and not iterate
|
||||||
|
* over any more gpio_devices.
|
||||||
|
*
|
||||||
|
* The callback takes the GPIO chip structure as argument. During the execution
|
||||||
|
* of the callback function the chip is protected from being freed. TODO: This
|
||||||
|
* actually has yet to be implemented.
|
||||||
|
*
|
||||||
|
* If the function returns non-NULL, the returned reference must be freed by
|
||||||
|
* the caller using gpio_device_put().
|
||||||
|
*/
|
||||||
|
struct gpio_device *gpio_device_find(void *data,
|
||||||
|
int (*match)(struct gpio_chip *gc,
|
||||||
|
void *data))
|
||||||
|
{
|
||||||
|
struct gpio_device *gdev;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Not yet but in the future the spinlock below will become a mutex.
|
||||||
|
* Annotate this function before anyone tries to use it in interrupt
|
||||||
|
* context like it happened with gpiochip_find().
|
||||||
|
*/
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
guard(spinlock_irqsave)(&gpio_lock);
|
||||||
|
|
||||||
|
list_for_each_entry(gdev, &gpio_devices, list) {
|
||||||
|
if (gdev->chip && match(gdev->chip, data))
|
||||||
|
return gpio_device_get(gdev);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(gpio_device_find);
|
||||||
|
|
||||||
static int gpiochip_match_name(struct gpio_chip *gc, void *data)
|
static int gpiochip_match_name(struct gpio_chip *gc, void *data)
|
||||||
{
|
{
|
||||||
const char *name = data;
|
const char *name = data;
|
||||||
|
@ -608,6 +608,9 @@ int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc,
|
|||||||
struct gpio_chip *gpiochip_find(void *data,
|
struct gpio_chip *gpiochip_find(void *data,
|
||||||
int (*match)(struct gpio_chip *gc, void *data));
|
int (*match)(struct gpio_chip *gc, void *data));
|
||||||
|
|
||||||
|
struct gpio_device *gpio_device_find(void *data,
|
||||||
|
int (*match)(struct gpio_chip *gc, void *data));
|
||||||
|
|
||||||
struct gpio_device *gpio_device_get(struct gpio_device *gdev);
|
struct gpio_device *gpio_device_get(struct gpio_device *gdev);
|
||||||
void gpio_device_put(struct gpio_device *gdev);
|
void gpio_device_put(struct gpio_device *gdev);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user