mirror of
https://github.com/torvalds/linux.git
synced 2024-12-14 23:25:54 +00:00
2874c5fd28
Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 3029 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070032.746973796@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
179 lines
4.1 KiB
C
179 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 int amilo_rfkill_remove(struct platform_device *device)
|
|
{
|
|
rfkill_unregister(amilo_rfkill_dev);
|
|
rfkill_destroy(amilo_rfkill_dev);
|
|
return 0;
|
|
}
|
|
|
|
static struct platform_driver amilo_rfkill_driver = {
|
|
.driver = {
|
|
.name = KBUILD_MODNAME,
|
|
},
|
|
.probe = amilo_rfkill_probe,
|
|
.remove = 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, -1,
|
|
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);
|