2 * Support for rfkill on some Fujitsu-Siemens Amilo laptops.
3 * Copyright 2011 Ben Hutchings.
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.
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.
16 #include <linux/module.h>
17 #include <linux/dmi.h>
18 #include <linux/i8042.h>
20 #include <linux/moduleparam.h>
21 #include <linux/platform_device.h>
22 #include <linux/rfkill.h>
25 * These values were obtained from disassembling and debugging the
26 * PM.exe program installed in the Fujitsu-Siemens AMILO A1655G
28 #define A1655_WIFI_COMMAND 0x10C5
29 #define A1655_WIFI_ON 0x25
30 #define A1655_WIFI_OFF 0x45
32 static int amilo_a1655_rfkill_set_block(void *data
, bool blocked
)
34 u8 param
= blocked
? A1655_WIFI_OFF
: A1655_WIFI_ON
;
38 rc
= i8042_command(¶m
, A1655_WIFI_COMMAND
);
43 static const struct rfkill_ops amilo_a1655_rfkill_ops
= {
44 .set_block
= amilo_a1655_rfkill_set_block
48 * These values were obtained from disassembling the PM.exe program
49 * installed in the Fujitsu-Siemens AMILO M 7440
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
58 static int amilo_m7440_rfkill_set_block(void *data
, bool blocked
)
60 u8 val1
= blocked
? M7440_RADIO_OFF1
: M7440_RADIO_ON1
;
61 u8 val2
= blocked
? M7440_RADIO_OFF2
: M7440_RADIO_ON2
;
63 outb(val1
, M7440_PORT1
);
64 outb(val2
, M7440_PORT2
);
66 /* Check whether the state has changed correctly */
67 if (inb(M7440_PORT1
) != val1
|| inb(M7440_PORT2
) != val2
)
73 static const struct rfkill_ops amilo_m7440_rfkill_ops
= {
74 .set_block
= amilo_m7440_rfkill_set_block
77 static const struct dmi_system_id amilo_rfkill_id_table
[] = {
80 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
81 DMI_MATCH(DMI_BOARD_NAME
, "AMILO A1655"),
83 .driver_data
= (void *)&amilo_a1655_rfkill_ops
87 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
88 DMI_MATCH(DMI_BOARD_NAME
, "AMILO L1310"),
90 .driver_data
= (void *)&amilo_a1655_rfkill_ops
94 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
95 DMI_MATCH(DMI_BOARD_NAME
, "AMILO M7440"),
97 .driver_data
= (void *)&amilo_m7440_rfkill_ops
102 static struct platform_device
*amilo_rfkill_pdev
;
103 static struct rfkill
*amilo_rfkill_dev
;
105 static int amilo_rfkill_probe(struct platform_device
*device
)
108 const struct dmi_system_id
*system_id
=
109 dmi_first_match(amilo_rfkill_id_table
);
114 amilo_rfkill_dev
= rfkill_alloc(KBUILD_MODNAME
, &device
->dev
,
116 system_id
->driver_data
, NULL
);
117 if (!amilo_rfkill_dev
)
120 rc
= rfkill_register(amilo_rfkill_dev
);
127 rfkill_destroy(amilo_rfkill_dev
);
131 static int amilo_rfkill_remove(struct platform_device
*device
)
133 rfkill_unregister(amilo_rfkill_dev
);
134 rfkill_destroy(amilo_rfkill_dev
);
138 static struct platform_driver amilo_rfkill_driver
= {
140 .name
= KBUILD_MODNAME
,
142 .probe
= amilo_rfkill_probe
,
143 .remove
= amilo_rfkill_remove
,
146 static int __init
amilo_rfkill_init(void)
150 if (dmi_first_match(amilo_rfkill_id_table
) == NULL
)
153 rc
= platform_driver_register(&amilo_rfkill_driver
);
157 amilo_rfkill_pdev
= platform_device_register_simple(KBUILD_MODNAME
, -1,
159 if (IS_ERR(amilo_rfkill_pdev
)) {
160 rc
= PTR_ERR(amilo_rfkill_pdev
);
167 platform_driver_unregister(&amilo_rfkill_driver
);
171 static void __exit
amilo_rfkill_exit(void)
173 platform_device_unregister(amilo_rfkill_pdev
);
174 platform_driver_unregister(&amilo_rfkill_driver
);
177 MODULE_AUTHOR("Ben Hutchings <ben@decadent.org.uk>");
178 MODULE_LICENSE("GPL");
179 MODULE_DEVICE_TABLE(dmi
, amilo_rfkill_id_table
);
181 module_init(amilo_rfkill_init
);
182 module_exit(amilo_rfkill_exit
);