Skip to content

Commit c215ab9

Browse files
bwhacksMatthew Garrett
authored andcommitted
x86: Add amilo-rfkill driver for some Fujitsu-Siemens Amilo laptops
An rfkill driver based on the fsaa1655g and fsam7440 drivers for Fujitsu-Siemens Amilo A1655 and M7440 models found at: http://sourceforge.net/projects/fsaa1655g/ http://sourceforge.net/projects/fsam7440/ This adds DMI matching, replaces the procfs files with rfkill devices, and uses the proper functions to write to the i8042 safely. Signed-off-by: Ben Hutchings <ben@decadent.org.uk> Signed-off-by: Matthew Garrett <mjg@redhat.com>
1 parent fde7d90 commit c215ab9

File tree

3 files changed

+181
-0
lines changed

3 files changed

+181
-0
lines changed

drivers/platform/x86/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ config FUJITSU_LAPTOP_DEBUG
143143

144144
If you are not sure, say N here.
145145

146+
config AMILO_RFKILL
147+
tristate "Fujitsu-Siemens Amilo rfkill support"
148+
depends on RFKILL
149+
---help---
150+
This is a driver for enabling wifi on some Fujitsu-Siemens Amilo
151+
laptops.
152+
146153
config TC1100_WMI
147154
tristate "HP Compaq TC1100 Tablet WMI Extras (EXPERIMENTAL)"
148155
depends on !X86_64

drivers/platform/x86/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ obj-$(CONFIG_ACER_WMI) += acer-wmi.o
1717
obj-$(CONFIG_ACERHDF) += acerhdf.o
1818
obj-$(CONFIG_HP_ACCEL) += hp_accel.o
1919
obj-$(CONFIG_HP_WMI) += hp-wmi.o
20+
obj-$(CONFIG_AMILO_RFKILL) += amilo-rfkill.o
2021
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
2122
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
2223
obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad-laptop.o

drivers/platform/x86/amilo-rfkill.c

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* Support for rfkill on some Fujitsu-Siemens Amilo laptops.
3+
* Copyright 2011 Ben Hutchings.
4+
*
5+
* Based in part on the fsam7440 driver, which is:
6+
* Copyright 2005 Alejandro Vidal Mata & Javier Vidal Mata.
7+
* and on the fsaa1655g driver, which is:
8+
* Copyright 2006 Martin Večeřa.
9+
*
10+
* This program is free software; you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License as published by
12+
* the Free Software Foundation; either version 2 of the License, or
13+
* (at your option) any later version.
14+
*/
15+
16+
#include <linux/module.h>
17+
#include <linux/dmi.h>
18+
#include <linux/i8042.h>
19+
#include <linux/io.h>
20+
#include <linux/moduleparam.h>
21+
#include <linux/platform_device.h>
22+
#include <linux/rfkill.h>
23+
24+
/*
25+
* These values were obtained from disassembling and debugging the
26+
* PM.exe program installed in the Fujitsu-Siemens AMILO A1655G
27+
*/
28+
#define A1655_WIFI_COMMAND 0x10C5
29+
#define A1655_WIFI_ON 0x25
30+
#define A1655_WIFI_OFF 0x45
31+
32+
static int amilo_a1655_rfkill_set_block(void *data, bool blocked)
33+
{
34+
u8 param = blocked ? A1655_WIFI_OFF : A1655_WIFI_ON;
35+
int rc;
36+
37+
i8042_lock_chip();
38+
rc = i8042_command(&param, A1655_WIFI_COMMAND);
39+
i8042_unlock_chip();
40+
return rc;
41+
}
42+
43+
static const struct rfkill_ops amilo_a1655_rfkill_ops = {
44+
.set_block = amilo_a1655_rfkill_set_block
45+
};
46+
47+
/*
48+
* These values were obtained from disassembling the PM.exe program
49+
* installed in the Fujitsu-Siemens AMILO M 7440
50+
*/
51+
#define M7440_PORT1 0x118f
52+
#define M7440_PORT2 0x118e
53+
#define M7440_RADIO_ON1 0x12
54+
#define M7440_RADIO_ON2 0x80
55+
#define M7440_RADIO_OFF1 0x10
56+
#define M7440_RADIO_OFF2 0x00
57+
58+
static int amilo_m7440_rfkill_set_block(void *data, bool blocked)
59+
{
60+
u8 val1 = blocked ? M7440_RADIO_OFF1 : M7440_RADIO_ON1;
61+
u8 val2 = blocked ? M7440_RADIO_OFF2 : M7440_RADIO_ON2;
62+
63+
outb(val1, M7440_PORT1);
64+
outb(val2, M7440_PORT2);
65+
66+
/* Check whether the state has changed correctly */
67+
if (inb(M7440_PORT1) != val1 || inb(M7440_PORT2) != val2)
68+
return -EIO;
69+
70+
return 0;
71+
}
72+
73+
static const struct rfkill_ops amilo_m7440_rfkill_ops = {
74+
.set_block = amilo_m7440_rfkill_set_block
75+
};
76+
77+
static const struct dmi_system_id __devinitdata amilo_rfkill_id_table[] = {
78+
{
79+
.matches = {
80+
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
81+
DMI_MATCH(DMI_BOARD_NAME, "AMILO A1655"),
82+
},
83+
.driver_data = (void *)&amilo_a1655_rfkill_ops
84+
},
85+
{
86+
.matches = {
87+
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
88+
DMI_MATCH(DMI_BOARD_NAME, "AMILO M7440"),
89+
},
90+
.driver_data = (void *)&amilo_m7440_rfkill_ops
91+
},
92+
{}
93+
};
94+
95+
static struct platform_device *amilo_rfkill_pdev;
96+
static struct rfkill *amilo_rfkill_dev;
97+
98+
static int __devinit amilo_rfkill_probe(struct platform_device *device)
99+
{
100+
const struct dmi_system_id *system_id =
101+
dmi_first_match(amilo_rfkill_id_table);
102+
int rc;
103+
104+
amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
105+
RFKILL_TYPE_WLAN,
106+
system_id->driver_data, NULL);
107+
if (!amilo_rfkill_dev)
108+
return -ENOMEM;
109+
110+
rc = rfkill_register(amilo_rfkill_dev);
111+
if (rc)
112+
goto fail;
113+
114+
return 0;
115+
116+
fail:
117+
rfkill_destroy(amilo_rfkill_dev);
118+
return rc;
119+
}
120+
121+
static int amilo_rfkill_remove(struct platform_device *device)
122+
{
123+
rfkill_unregister(amilo_rfkill_dev);
124+
rfkill_destroy(amilo_rfkill_dev);
125+
return 0;
126+
}
127+
128+
static struct platform_driver amilo_rfkill_driver = {
129+
.driver = {
130+
.name = KBUILD_MODNAME,
131+
.owner = THIS_MODULE,
132+
},
133+
.probe = amilo_rfkill_probe,
134+
.remove = amilo_rfkill_remove,
135+
};
136+
137+
static int __init amilo_rfkill_init(void)
138+
{
139+
int rc;
140+
141+
if (dmi_first_match(amilo_rfkill_id_table) == NULL)
142+
return -ENODEV;
143+
144+
rc = platform_driver_register(&amilo_rfkill_driver);
145+
if (rc)
146+
return rc;
147+
148+
amilo_rfkill_pdev = platform_device_register_simple(KBUILD_MODNAME, -1,
149+
NULL, 0);
150+
if (IS_ERR(amilo_rfkill_pdev)) {
151+
rc = PTR_ERR(amilo_rfkill_pdev);
152+
goto fail;
153+
}
154+
155+
return 0;
156+
157+
fail:
158+
platform_driver_unregister(&amilo_rfkill_driver);
159+
return rc;
160+
}
161+
162+
static void __exit amilo_rfkill_exit(void)
163+
{
164+
platform_device_unregister(amilo_rfkill_pdev);
165+
platform_driver_unregister(&amilo_rfkill_driver);
166+
}
167+
168+
MODULE_AUTHOR("Ben Hutchings <ben@decadent.org.uk>");
169+
MODULE_LICENSE("GPL");
170+
MODULE_DEVICE_TABLE(dmi, amilo_rfkill_id_table);
171+
172+
module_init(amilo_rfkill_init);
173+
module_exit(amilo_rfkill_exit);

0 commit comments

Comments
 (0)