mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-24 09:50:04 +00:00
![Uwe Kleine-König](/assets/img/avatar_default.png)
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 (mostly) ignored 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. 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/20230302144732.1903781-7-u.kleine-koenig@pengutronix.de Reviewed-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
178 lines
4.1 KiB
C
178 lines
4.1 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Support for rfkill on some Fujitsu-Siemens Amilo laptops.
|
|
* Copyright 2011 Ben Hutchings.
|
|
*
|
|
* Based in part on the fsam7440 driver, which is:
|
|
* Copyright 2005 Alejandro Vidal Mata & Javier Vidal Mata.
|
|
* and on the fsaa1655g driver, which is:
|
|
* Copyright 2006 Martin Večeřa.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/dmi.h>
|
|
#include <linux/i8042.h>
|
|
#include <linux/io.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/rfkill.h>
|
|
|
|
/*
|
|
* These values were obtained from disassembling and debugging the
|
|
* PM.exe program installed in the Fujitsu-Siemens AMILO A1655G
|
|
*/
|
|
#define A1655_WIFI_COMMAND 0x10C5
|
|
#define A1655_WIFI_ON 0x25
|
|
#define A1655_WIFI_OFF 0x45
|
|
|
|
static int amilo_a1655_rfkill_set_block(void *data, bool blocked)
|
|
{
|
|
u8 param = blocked ? A1655_WIFI_OFF : A1655_WIFI_ON;
|
|
int rc;
|
|
|
|
i8042_lock_chip();
|
|
rc = i8042_command(¶m, A1655_WIFI_COMMAND);
|
|
i8042_unlock_chip();
|
|
return rc;
|
|
}
|
|
|
|
static const struct rfkill_ops amilo_a1655_rfkill_ops = {
|
|
.set_block = amilo_a1655_rfkill_set_block
|
|
};
|
|
|
|
/*
|
|
* These values were obtained from disassembling the PM.exe program
|
|
* installed in the Fujitsu-Siemens AMILO M 7440
|
|
*/
|
|
#define M7440_PORT1 0x118f
|
|
#define M7440_PORT2 0x118e
|
|
#define M7440_RADIO_ON1 0x12
|
|
#define M7440_RADIO_ON2 0x80
|
|
#define M7440_RADIO_OFF1 0x10
|
|
#define M7440_RADIO_OFF2 0x00
|
|
|
|
static int amilo_m7440_rfkill_set_block(void *data, bool blocked)
|
|
{
|
|
u8 val1 = blocked ? M7440_RADIO_OFF1 : M7440_RADIO_ON1;
|
|
u8 val2 = blocked ? M7440_RADIO_OFF2 : M7440_RADIO_ON2;
|
|
|
|
outb(val1, M7440_PORT1);
|
|
outb(val2, M7440_PORT2);
|
|
|
|
/* Check whether the state has changed correctly */
|
|
if (inb(M7440_PORT1) != val1 || inb(M7440_PORT2) != val2)
|
|
return -EIO;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct rfkill_ops amilo_m7440_rfkill_ops = {
|
|
.set_block = amilo_m7440_rfkill_set_block
|
|
};
|
|
|
|
static const struct dmi_system_id amilo_rfkill_id_table[] = {
|
|
{
|
|
.matches = {
|
|
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
|
|
DMI_MATCH(DMI_BOARD_NAME, "AMILO A1655"),
|
|
},
|
|
.driver_data = (void *)&amilo_a1655_rfkill_ops
|
|
},
|
|
{
|
|
.matches = {
|
|
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
|
|
DMI_MATCH(DMI_BOARD_NAME, "AMILO L1310"),
|
|
},
|
|
.driver_data = (void *)&amilo_a1655_rfkill_ops
|
|
},
|
|
{
|
|
.matches = {
|
|
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
|
|
DMI_MATCH(DMI_BOARD_NAME, "AMILO M7440"),
|
|
},
|
|
.driver_data = (void *)&amilo_m7440_rfkill_ops
|
|
},
|
|
{}
|
|
};
|
|
|
|
static struct platform_device *amilo_rfkill_pdev;
|
|
static struct rfkill *amilo_rfkill_dev;
|
|
|
|
static int amilo_rfkill_probe(struct platform_device *device)
|
|
{
|
|
int rc;
|
|
const struct dmi_system_id *system_id =
|
|
dmi_first_match(amilo_rfkill_id_table);
|
|
|
|
if (!system_id)
|
|
return -ENXIO;
|
|
|
|
amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
|
|
RFKILL_TYPE_WLAN,
|
|
system_id->driver_data, NULL);
|
|
if (!amilo_rfkill_dev)
|
|
return -ENOMEM;
|
|
|
|
rc = rfkill_register(amilo_rfkill_dev);
|
|
if (rc)
|
|
goto fail;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
rfkill_destroy(amilo_rfkill_dev);
|
|
return rc;
|
|
}
|
|
|
|
static void amilo_rfkill_remove(struct platform_device *device)
|
|
{
|
|
rfkill_unregister(amilo_rfkill_dev);
|
|
rfkill_destroy(amilo_rfkill_dev);
|
|
}
|
|
|
|
static struct platform_driver amilo_rfkill_driver = {
|
|
.driver = {
|
|
.name = KBUILD_MODNAME,
|
|
},
|
|
.probe = amilo_rfkill_probe,
|
|
.remove_new = amilo_rfkill_remove,
|
|
};
|
|
|
|
static int __init amilo_rfkill_init(void)
|
|
{
|
|
int rc;
|
|
|
|
if (dmi_first_match(amilo_rfkill_id_table) == NULL)
|
|
return -ENODEV;
|
|
|
|
rc = platform_driver_register(&amilo_rfkill_driver);
|
|
if (rc)
|
|
return rc;
|
|
|
|
amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME,
|
|
PLATFORM_DEVID_NONE,
|
|
NULL, 0);
|
|
if (IS_ERR(amilo_rfkill_pdev)) {
|
|
rc = PTR_ERR(amilo_rfkill_pdev);
|
|
goto fail;
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
platform_driver_unregister(&amilo_rfkill_driver);
|
|
return rc;
|
|
}
|
|
|
|
static void __exit amilo_rfkill_exit(void)
|
|
{
|
|
platform_device_unregister(amilo_rfkill_pdev);
|
|
platform_driver_unregister(&amilo_rfkill_driver);
|
|
}
|
|
|
|
MODULE_AUTHOR("Ben Hutchings <ben@decadent.org.uk>");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table);
|
|
|
|
module_init(amilo_rfkill_init);
|
|
module_exit(amilo_rfkill_exit);
|