mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-03 00:54:09 +08:00
548eb81d7b
The .remove() callback for a platform driver returns an int which makes many driver authors wrongly assume it's possible to do error handling by returning an error code. However the value returned is ignored (apart from emitting a warning) and this typically results in resource leaks. To improve here there is a quest to make the remove callback return void. In the first step of this quest all drivers are converted to .remove_new() which already returns void. Eventually after all drivers are converted, .remove_new() will be renamed to .remove(). Trivially convert this driver from always returning zero in the remove callback to the void returning variant. Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Link: https://lore.kernel.org/r/20230919174931.1417681-49-u.kleine-koenig@pengutronix.de Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
110 lines
2.4 KiB
C
110 lines
2.4 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Industrial I/O - generic interrupt based trigger support
|
|
*
|
|
* Copyright (c) 2008-2013 Jonathan Cameron
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/interrupt.h>
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/iio/trigger.h>
|
|
|
|
|
|
struct iio_interrupt_trigger_info {
|
|
unsigned int irq;
|
|
};
|
|
|
|
static irqreturn_t iio_interrupt_trigger_poll(int irq, void *private)
|
|
{
|
|
iio_trigger_poll(private);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static int iio_interrupt_trigger_probe(struct platform_device *pdev)
|
|
{
|
|
struct iio_interrupt_trigger_info *trig_info;
|
|
struct iio_trigger *trig;
|
|
unsigned long irqflags;
|
|
struct resource *irq_res;
|
|
int irq, ret = 0;
|
|
|
|
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
|
|
if (irq_res == NULL)
|
|
return -ENODEV;
|
|
|
|
irqflags = (irq_res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED;
|
|
|
|
irq = irq_res->start;
|
|
|
|
trig = iio_trigger_alloc(NULL, "irqtrig%d", irq);
|
|
if (!trig) {
|
|
ret = -ENOMEM;
|
|
goto error_ret;
|
|
}
|
|
|
|
trig_info = kzalloc(sizeof(*trig_info), GFP_KERNEL);
|
|
if (!trig_info) {
|
|
ret = -ENOMEM;
|
|
goto error_free_trigger;
|
|
}
|
|
iio_trigger_set_drvdata(trig, trig_info);
|
|
trig_info->irq = irq;
|
|
ret = request_irq(irq, iio_interrupt_trigger_poll,
|
|
irqflags, trig->name, trig);
|
|
if (ret) {
|
|
dev_err(&pdev->dev,
|
|
"request IRQ-%d failed", irq);
|
|
goto error_free_trig_info;
|
|
}
|
|
|
|
ret = iio_trigger_register(trig);
|
|
if (ret)
|
|
goto error_release_irq;
|
|
platform_set_drvdata(pdev, trig);
|
|
|
|
return 0;
|
|
|
|
/* First clean up the partly allocated trigger */
|
|
error_release_irq:
|
|
free_irq(irq, trig);
|
|
error_free_trig_info:
|
|
kfree(trig_info);
|
|
error_free_trigger:
|
|
iio_trigger_free(trig);
|
|
error_ret:
|
|
return ret;
|
|
}
|
|
|
|
static void iio_interrupt_trigger_remove(struct platform_device *pdev)
|
|
{
|
|
struct iio_trigger *trig;
|
|
struct iio_interrupt_trigger_info *trig_info;
|
|
|
|
trig = platform_get_drvdata(pdev);
|
|
trig_info = iio_trigger_get_drvdata(trig);
|
|
iio_trigger_unregister(trig);
|
|
free_irq(trig_info->irq, trig);
|
|
kfree(trig_info);
|
|
iio_trigger_free(trig);
|
|
}
|
|
|
|
static struct platform_driver iio_interrupt_trigger_driver = {
|
|
.probe = iio_interrupt_trigger_probe,
|
|
.remove_new = iio_interrupt_trigger_remove,
|
|
.driver = {
|
|
.name = "iio_interrupt_trigger",
|
|
},
|
|
};
|
|
|
|
module_platform_driver(iio_interrupt_trigger_driver);
|
|
|
|
MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>");
|
|
MODULE_DESCRIPTION("Interrupt trigger for the iio subsystem");
|
|
MODULE_LICENSE("GPL v2");
|