diff options
Diffstat (limited to 'drivers/platform/x86/ideapad-laptop.c')
-rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 71 |
1 files changed, 29 insertions, 42 deletions
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index 37fe0d0448c9..114d95247cdf 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
@@ -31,32 +31,15 @@ | |||
31 | #include <linux/input.h> | 31 | #include <linux/input.h> |
32 | #include <linux/input/sparse-keymap.h> | 32 | #include <linux/input/sparse-keymap.h> |
33 | 33 | ||
34 | #define IDEAPAD_DEV_CAMERA 0 | 34 | #define IDEAPAD_RFKILL_DEV_NUM (3) |
35 | #define IDEAPAD_DEV_WLAN 1 | ||
36 | #define IDEAPAD_DEV_BLUETOOTH 2 | ||
37 | #define IDEAPAD_DEV_3G 3 | ||
38 | #define IDEAPAD_DEV_KILLSW 4 | ||
39 | 35 | ||
40 | struct ideapad_private { | 36 | struct ideapad_private { |
41 | acpi_handle handle; | 37 | struct rfkill *rfk[IDEAPAD_RFKILL_DEV_NUM]; |
42 | struct rfkill *rfk[5]; | ||
43 | struct platform_device *platform_device; | 38 | struct platform_device *platform_device; |
44 | struct input_dev *inputdev; | 39 | struct input_dev *inputdev; |
45 | } *ideapad_priv; | ||
46 | |||
47 | static struct { | ||
48 | char *name; | ||
49 | int cfgbit; | ||
50 | int opcode; | ||
51 | int type; | ||
52 | } ideapad_rfk_data[] = { | ||
53 | { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES }, | ||
54 | { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN }, | ||
55 | { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH }, | ||
56 | { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN }, | ||
57 | { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN } | ||
58 | }; | 40 | }; |
59 | 41 | ||
42 | static acpi_handle ideapad_handle; | ||
60 | static bool no_bt_rfkill; | 43 | static bool no_bt_rfkill; |
61 | module_param(no_bt_rfkill, bool, 0444); | 44 | module_param(no_bt_rfkill, bool, 0444); |
62 | MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); | 45 | MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth."); |
@@ -176,11 +159,9 @@ static ssize_t show_ideapad_cam(struct device *dev, | |||
176 | struct device_attribute *attr, | 159 | struct device_attribute *attr, |
177 | char *buf) | 160 | char *buf) |
178 | { | 161 | { |
179 | struct ideapad_private *priv = dev_get_drvdata(dev); | ||
180 | acpi_handle handle = priv->handle; | ||
181 | unsigned long result; | 162 | unsigned long result; |
182 | 163 | ||
183 | if (read_ec_data(handle, 0x1D, &result)) | 164 | if (read_ec_data(ideapad_handle, 0x1D, &result)) |
184 | return sprintf(buf, "-1\n"); | 165 | return sprintf(buf, "-1\n"); |
185 | return sprintf(buf, "%lu\n", result); | 166 | return sprintf(buf, "%lu\n", result); |
186 | } | 167 | } |
@@ -189,15 +170,13 @@ static ssize_t store_ideapad_cam(struct device *dev, | |||
189 | struct device_attribute *attr, | 170 | struct device_attribute *attr, |
190 | const char *buf, size_t count) | 171 | const char *buf, size_t count) |
191 | { | 172 | { |
192 | struct ideapad_private *priv = dev_get_drvdata(dev); | ||
193 | acpi_handle handle = priv->handle; | ||
194 | int ret, state; | 173 | int ret, state; |
195 | 174 | ||
196 | if (!count) | 175 | if (!count) |
197 | return 0; | 176 | return 0; |
198 | if (sscanf(buf, "%i", &state) != 1) | 177 | if (sscanf(buf, "%i", &state) != 1) |
199 | return -EINVAL; | 178 | return -EINVAL; |
200 | ret = write_ec_cmd(handle, 0x1E, state); | 179 | ret = write_ec_cmd(ideapad_handle, 0x1E, state); |
201 | if (ret < 0) | 180 | if (ret < 0) |
202 | return ret; | 181 | return ret; |
203 | return count; | 182 | return count; |
@@ -208,16 +187,24 @@ static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam); | |||
208 | /* | 187 | /* |
209 | * Rfkill | 188 | * Rfkill |
210 | */ | 189 | */ |
190 | struct ideapad_rfk_data { | ||
191 | char *name; | ||
192 | int cfgbit; | ||
193 | int opcode; | ||
194 | int type; | ||
195 | }; | ||
196 | |||
197 | const struct ideapad_rfk_data ideapad_rfk_data[] = { | ||
198 | { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN }, | ||
199 | { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH }, | ||
200 | { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN }, | ||
201 | }; | ||
202 | |||
211 | static int ideapad_rfk_set(void *data, bool blocked) | 203 | static int ideapad_rfk_set(void *data, bool blocked) |
212 | { | 204 | { |
213 | int device = (unsigned long)data; | 205 | unsigned long opcode = (unsigned long)data; |
214 | |||
215 | if (device == IDEAPAD_DEV_KILLSW) | ||
216 | return -EINVAL; | ||
217 | 206 | ||
218 | return write_ec_cmd(ideapad_priv->handle, | 207 | return write_ec_cmd(ideapad_handle, opcode, !blocked); |
219 | ideapad_rfk_data[device].opcode, | ||
220 | !blocked); | ||
221 | } | 208 | } |
222 | 209 | ||
223 | static struct rfkill_ops ideapad_rfk_ops = { | 210 | static struct rfkill_ops ideapad_rfk_ops = { |
@@ -227,15 +214,14 @@ static struct rfkill_ops ideapad_rfk_ops = { | |||
227 | static void ideapad_sync_rfk_state(struct acpi_device *adevice) | 214 | static void ideapad_sync_rfk_state(struct acpi_device *adevice) |
228 | { | 215 | { |
229 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); | 216 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); |
230 | acpi_handle handle = priv->handle; | ||
231 | unsigned long hw_blocked; | 217 | unsigned long hw_blocked; |
232 | int i; | 218 | int i; |
233 | 219 | ||
234 | if (read_ec_data(handle, 0x23, &hw_blocked)) | 220 | if (read_ec_data(ideapad_handle, 0x23, &hw_blocked)) |
235 | return; | 221 | return; |
236 | hw_blocked = !hw_blocked; | 222 | hw_blocked = !hw_blocked; |
237 | 223 | ||
238 | for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) | 224 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) |
239 | if (priv->rfk[i]) | 225 | if (priv->rfk[i]) |
240 | rfkill_set_hw_state(priv->rfk[i], hw_blocked); | 226 | rfkill_set_hw_state(priv->rfk[i], hw_blocked); |
241 | } | 227 | } |
@@ -250,7 +236,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, | |||
250 | if (no_bt_rfkill && | 236 | if (no_bt_rfkill && |
251 | (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) { | 237 | (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) { |
252 | /* Force to enable bluetooth when no_bt_rfkill=1 */ | 238 | /* Force to enable bluetooth when no_bt_rfkill=1 */ |
253 | write_ec_cmd(ideapad_priv->handle, | 239 | write_ec_cmd(ideapad_handle, |
254 | ideapad_rfk_data[dev].opcode, 1); | 240 | ideapad_rfk_data[dev].opcode, 1); |
255 | return 0; | 241 | return 0; |
256 | } | 242 | } |
@@ -261,7 +247,7 @@ static int __devinit ideapad_register_rfkill(struct acpi_device *adevice, | |||
261 | if (!priv->rfk[dev]) | 247 | if (!priv->rfk[dev]) |
262 | return -ENOMEM; | 248 | return -ENOMEM; |
263 | 249 | ||
264 | if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1, | 250 | if (read_ec_data(ideapad_handle, ideapad_rfk_data[dev].opcode-1, |
265 | &sw_blocked)) { | 251 | &sw_blocked)) { |
266 | rfkill_init_sw_state(priv->rfk[dev], 0); | 252 | rfkill_init_sw_state(priv->rfk[dev], 0); |
267 | } else { | 253 | } else { |
@@ -414,9 +400,8 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) | |||
414 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 400 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
415 | if (!priv) | 401 | if (!priv) |
416 | return -ENOMEM; | 402 | return -ENOMEM; |
417 | ideapad_priv = priv; | ||
418 | priv->handle = adevice->handle; | ||
419 | dev_set_drvdata(&adevice->dev, priv); | 403 | dev_set_drvdata(&adevice->dev, priv); |
404 | ideapad_handle = adevice->handle; | ||
420 | 405 | ||
421 | ret = ideapad_platform_init(priv); | 406 | ret = ideapad_platform_init(priv); |
422 | if (ret) | 407 | if (ret) |
@@ -426,9 +411,11 @@ static int __devinit ideapad_acpi_add(struct acpi_device *adevice) | |||
426 | if (ret) | 411 | if (ret) |
427 | goto input_failed; | 412 | goto input_failed; |
428 | 413 | ||
429 | for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) { | 414 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) { |
430 | if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) | 415 | if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg)) |
431 | ideapad_register_rfkill(adevice, i); | 416 | ideapad_register_rfkill(adevice, i); |
417 | else | ||
418 | priv->rfk[i] = NULL; | ||
432 | } | 419 | } |
433 | ideapad_sync_rfk_state(adevice); | 420 | ideapad_sync_rfk_state(adevice); |
434 | 421 | ||
@@ -446,7 +433,7 @@ static int __devexit ideapad_acpi_remove(struct acpi_device *adevice, int type) | |||
446 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); | 433 | struct ideapad_private *priv = dev_get_drvdata(&adevice->dev); |
447 | int i; | 434 | int i; |
448 | 435 | ||
449 | for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++) | 436 | for (i = 0; i < IDEAPAD_RFKILL_DEV_NUM; i++) |
450 | ideapad_unregister_rfkill(adevice, i); | 437 | ideapad_unregister_rfkill(adevice, i); |
451 | ideapad_input_exit(priv); | 438 | ideapad_input_exit(priv); |
452 | ideapad_platform_exit(priv); | 439 | ideapad_platform_exit(priv); |