Add patches accepted for 2.6.29-rc2
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / releases / upstream / 2.6.29-rc2 / 0007-ACPI-thinkpad-acpi-add-UWB-radio-support.patch
blobc1498d56fce0c9d66c3ceb22257d5e2ff66774e7
1 From 0045c0aa7d5e787f78938e6a10927b8a516f0b83 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Sun, 11 Jan 2009 03:01:03 -0200
4 Subject: ACPI: thinkpad-acpi: add UWB radio support
6 Add rfkill support for USB UWB radio devices on very recent ThinkPad
7 laptop models.
9 The new subdriver is moslty a trimmed down copy of the wwan subdriver.
11 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
12 Cc: Ivo van Doorn <IvDoorn@gmail.com>
13 Signed-off-by: Len Brown <len.brown@intel.com>
14 ---
15 Documentation/laptops/thinkpad-acpi.txt | 18 +++
16 drivers/platform/x86/thinkpad_acpi.c | 206 ++++++++++++++++++++++++++++++-
17 2 files changed, 223 insertions(+), 1 deletions(-)
19 diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt
20 index ddc371e..91c0001 100644
21 --- a/Documentation/laptops/thinkpad-acpi.txt
22 +++ b/Documentation/laptops/thinkpad-acpi.txt
23 @@ -1413,6 +1413,24 @@ Sysfs notes:
24 rfkill controller switch "tpacpi_wwan_sw": refer to
25 Documentation/rfkill.txt for details.
27 +EXPERIMENTAL: UWB
28 +-----------------
30 +This feature is marked EXPERIMENTAL because it has not been extensively
31 +tested and validated in various ThinkPad models yet. The feature may not
32 +work as expected. USE WITH CAUTION! To use this feature, you need to supply
33 +the experimental=1 parameter when loading the module.
35 +sysfs rfkill class: switch "tpacpi_uwb_sw"
37 +This feature exports an rfkill controller for the UWB device, if one is
38 +present and enabled in the BIOS.
40 +Sysfs notes:
42 + rfkill controller switch "tpacpi_uwb_sw": refer to
43 + Documentation/rfkill.txt for details.
45 Multiple Commands, Module Parameters
46 ------------------------------------
48 diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
49 index 27d709b..c1d4041 100644
50 --- a/drivers/platform/x86/thinkpad_acpi.c
51 +++ b/drivers/platform/x86/thinkpad_acpi.c
52 @@ -169,6 +169,7 @@ enum {
53 enum {
54 TPACPI_RFK_BLUETOOTH_SW_ID = 0,
55 TPACPI_RFK_WWAN_SW_ID,
56 + TPACPI_RFK_UWB_SW_ID,
59 /* Debugging */
60 @@ -261,6 +262,7 @@ static struct {
61 u32 bright_16levels:1;
62 u32 bright_acpimode:1;
63 u32 wan:1;
64 + u32 uwb:1;
65 u32 fan_ctrl_status_undef:1;
66 u32 input_device_registered:1;
67 u32 platform_drv_registered:1;
68 @@ -317,6 +319,8 @@ static int dbg_bluetoothemul;
69 static int tpacpi_bluetooth_emulstate;
70 static int dbg_wwanemul;
71 static int tpacpi_wwan_emulstate;
72 +static int dbg_uwbemul;
73 +static int tpacpi_uwb_emulstate;
74 #endif
77 @@ -967,6 +971,7 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
78 struct rfkill **rfk,
79 const enum rfkill_type rfktype,
80 const char *name,
81 + const bool set_default,
82 int (*toggle_radio)(void *, enum rfkill_state),
83 int (*get_state)(void *, enum rfkill_state *))
85 @@ -978,7 +983,7 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
86 printk(TPACPI_ERR
87 "failed to read initial state for %s, error %d; "
88 "will turn radio off\n", name, res);
89 - } else {
90 + } else if (set_default) {
91 /* try to set the initial state as the default for the rfkill
92 * type, since we ask the firmware to preserve it across S5 in
93 * NVRAM */
94 @@ -1148,6 +1153,31 @@ static DRIVER_ATTR(wwan_emulstate, S_IWUSR | S_IRUGO,
95 tpacpi_driver_wwan_emulstate_show,
96 tpacpi_driver_wwan_emulstate_store);
98 +/* uwb_emulstate ------------------------------------------------- */
99 +static ssize_t tpacpi_driver_uwb_emulstate_show(
100 + struct device_driver *drv,
101 + char *buf)
103 + return snprintf(buf, PAGE_SIZE, "%d\n", !!tpacpi_uwb_emulstate);
106 +static ssize_t tpacpi_driver_uwb_emulstate_store(
107 + struct device_driver *drv,
108 + const char *buf, size_t count)
110 + unsigned long t;
112 + if (parse_strtoul(buf, 1, &t))
113 + return -EINVAL;
115 + tpacpi_uwb_emulstate = !!t;
117 + return count;
120 +static DRIVER_ATTR(uwb_emulstate, S_IWUSR | S_IRUGO,
121 + tpacpi_driver_uwb_emulstate_show,
122 + tpacpi_driver_uwb_emulstate_store);
123 #endif
125 /* --------------------------------------------------------------------- */
126 @@ -1175,6 +1205,8 @@ static int __init tpacpi_create_driver_attributes(struct device_driver *drv)
127 res = driver_create_file(drv, &driver_attr_bluetooth_emulstate);
128 if (!res && dbg_wwanemul)
129 res = driver_create_file(drv, &driver_attr_wwan_emulstate);
130 + if (!res && dbg_uwbemul)
131 + res = driver_create_file(drv, &driver_attr_uwb_emulstate);
132 #endif
134 return res;
135 @@ -1191,6 +1223,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv)
136 driver_remove_file(drv, &driver_attr_wlsw_emulstate);
137 driver_remove_file(drv, &driver_attr_bluetooth_emulstate);
138 driver_remove_file(drv, &driver_attr_wwan_emulstate);
139 + driver_remove_file(drv, &driver_attr_uwb_emulstate);
140 #endif
143 @@ -2125,6 +2158,7 @@ static struct attribute *hotkey_mask_attributes[] __initdata = {
145 static void bluetooth_update_rfk(void);
146 static void wan_update_rfk(void);
147 +static void uwb_update_rfk(void);
148 static void tpacpi_send_radiosw_update(void)
150 int wlsw;
151 @@ -2134,6 +2168,8 @@ static void tpacpi_send_radiosw_update(void)
152 bluetooth_update_rfk();
153 if (tp_features.wan)
154 wan_update_rfk();
155 + if (tp_features.uwb)
156 + uwb_update_rfk();
158 if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
159 mutex_lock(&tpacpi_inputdev_send_mutex);
160 @@ -3035,6 +3071,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
161 &tpacpi_bluetooth_rfkill,
162 RFKILL_TYPE_BLUETOOTH,
163 "tpacpi_bluetooth_sw",
164 + true,
165 tpacpi_bluetooth_rfk_set,
166 tpacpi_bluetooth_rfk_get);
167 if (res) {
168 @@ -3309,6 +3346,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
169 &tpacpi_wan_rfkill,
170 RFKILL_TYPE_WWAN,
171 "tpacpi_wwan_sw",
172 + true,
173 tpacpi_wan_rfk_set,
174 tpacpi_wan_rfk_get);
175 if (res) {
176 @@ -3366,6 +3404,162 @@ static struct ibm_struct wan_driver_data = {
179 /*************************************************************************
180 + * UWB subdriver
181 + */
183 +enum {
184 + /* ACPI GUWB/SUWB bits */
185 + TP_ACPI_UWB_HWPRESENT = 0x01, /* UWB hw available */
186 + TP_ACPI_UWB_RADIOSSW = 0x02, /* UWB radio enabled */
189 +static struct rfkill *tpacpi_uwb_rfkill;
191 +static int uwb_get_radiosw(void)
193 + int status;
195 + if (!tp_features.uwb)
196 + return -ENODEV;
198 + /* WLSW overrides UWB in firmware/hardware, reflect that */
199 + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status)
200 + return RFKILL_STATE_HARD_BLOCKED;
202 +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
203 + if (dbg_uwbemul)
204 + return (tpacpi_uwb_emulstate) ?
205 + RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
206 +#endif
208 + if (!acpi_evalf(hkey_handle, &status, "GUWB", "d"))
209 + return -EIO;
211 + return ((status & TP_ACPI_UWB_RADIOSSW) != 0) ?
212 + RFKILL_STATE_UNBLOCKED : RFKILL_STATE_SOFT_BLOCKED;
215 +static void uwb_update_rfk(void)
217 + int status;
219 + if (!tpacpi_uwb_rfkill)
220 + return;
222 + status = uwb_get_radiosw();
223 + if (status < 0)
224 + return;
225 + rfkill_force_state(tpacpi_uwb_rfkill, status);
228 +static int uwb_set_radiosw(int radio_on, int update_rfk)
230 + int status;
232 + if (!tp_features.uwb)
233 + return -ENODEV;
235 + /* WLSW overrides UWB in firmware/hardware, but there is no
236 + * reason to risk weird behaviour. */
237 + if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&status) && !status
238 + && radio_on)
239 + return -EPERM;
241 +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
242 + if (dbg_uwbemul) {
243 + tpacpi_uwb_emulstate = !!radio_on;
244 + if (update_rfk)
245 + uwb_update_rfk();
246 + return 0;
248 +#endif
250 + status = (radio_on) ? TP_ACPI_UWB_RADIOSSW : 0;
251 + if (!acpi_evalf(hkey_handle, NULL, "SUWB", "vd", status))
252 + return -EIO;
254 + if (update_rfk)
255 + uwb_update_rfk();
257 + return 0;
260 +/* --------------------------------------------------------------------- */
262 +static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
264 + int uwbs = uwb_get_radiosw();
266 + if (uwbs < 0)
267 + return uwbs;
269 + *state = uwbs;
270 + return 0;
273 +static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state)
275 + return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0);
278 +static void uwb_exit(void)
280 + if (tpacpi_uwb_rfkill)
281 + rfkill_unregister(tpacpi_uwb_rfkill);
284 +static int __init uwb_init(struct ibm_init_struct *iibm)
286 + int res;
287 + int status = 0;
289 + vdbg_printk(TPACPI_DBG_INIT, "initializing uwb subdriver\n");
291 + TPACPI_ACPIHANDLE_INIT(hkey);
293 + tp_features.uwb = hkey_handle &&
294 + acpi_evalf(hkey_handle, &status, "GUWB", "qd");
296 + vdbg_printk(TPACPI_DBG_INIT, "uwb is %s, status 0x%02x\n",
297 + str_supported(tp_features.uwb),
298 + status);
300 +#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
301 + if (dbg_uwbemul) {
302 + tp_features.uwb = 1;
303 + printk(TPACPI_INFO
304 + "uwb switch emulation enabled\n");
305 + } else
306 +#endif
307 + if (tp_features.uwb &&
308 + !(status & TP_ACPI_UWB_HWPRESENT)) {
309 + /* no uwb hardware present in system */
310 + tp_features.uwb = 0;
311 + dbg_printk(TPACPI_DBG_INIT,
312 + "uwb hardware not installed\n");
315 + if (!tp_features.uwb)
316 + return 1;
318 + res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID,
319 + &tpacpi_uwb_rfkill,
320 + RFKILL_TYPE_UWB,
321 + "tpacpi_uwb_sw",
322 + false,
323 + tpacpi_uwb_rfk_set,
324 + tpacpi_uwb_rfk_get);
326 + return res;
329 +static struct ibm_struct uwb_driver_data = {
330 + .name = "uwb",
331 + .exit = uwb_exit,
332 + .flags.experimental = 1,
335 +/*************************************************************************
336 * Video subdriver
339 @@ -6830,6 +7024,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
340 .init = wan_init,
341 .data = &wan_driver_data,
344 + .init = uwb_init,
345 + .data = &uwb_driver_data,
346 + },
347 #ifdef CONFIG_THINKPAD_ACPI_VIDEO
349 .init = video_init,
350 @@ -6986,6 +7184,12 @@ MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation");
351 module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0);
352 MODULE_PARM_DESC(wwan_state,
353 "Initial state of the emulated WWAN switch");
355 +module_param(dbg_uwbemul, uint, 0);
356 +MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation");
357 +module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0);
358 +MODULE_PARM_DESC(uwb_state,
359 + "Initial state of the emulated UWB switch");
360 #endif
362 static void thinkpad_acpi_module_exit(void)
364 1.5.6.5