aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/compal-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/compal-laptop.c')
-rw-r--r--drivers/platform/x86/compal-laptop.c247
1 files changed, 109 insertions, 138 deletions
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index 1a387e79f719..2740b40aad9b 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -26,17 +26,8 @@
26/* 26/*
27 * comapl-laptop.c - Compal laptop support. 27 * comapl-laptop.c - Compal laptop support.
28 * 28 *
29 * This driver exports a few files in /sys/devices/platform/compal-laptop/: 29 * The driver registers itself with the rfkill subsystem and
30 * 30 * the Linux backlight control subsystem.
31 * wlan - wlan subsystem state: contains 0 or 1 (rw)
32 *
33 * bluetooth - Bluetooth subsystem state: contains 0 or 1 (rw)
34 *
35 * raw - raw value taken from embedded controller register (ro)
36 *
37 * In addition to these platform device attributes the driver
38 * registers itself in the Linux backlight control subsystem and is
39 * available to userspace under /sys/class/backlight/compal-laptop/.
40 * 31 *
41 * This driver might work on other laptops produced by Compal. If you 32 * This driver might work on other laptops produced by Compal. If you
42 * want to try it you can pass force=1 as argument to the module which 33 * want to try it you can pass force=1 as argument to the module which
@@ -51,6 +42,7 @@
51#include <linux/dmi.h> 42#include <linux/dmi.h>
52#include <linux/backlight.h> 43#include <linux/backlight.h>
53#include <linux/platform_device.h> 44#include <linux/platform_device.h>
45#include <linux/rfkill.h>
54 46
55#define COMPAL_DRIVER_VERSION "0.2.6" 47#define COMPAL_DRIVER_VERSION "0.2.6"
56 48
@@ -63,6 +55,10 @@
63#define WLAN_MASK 0x01 55#define WLAN_MASK 0x01
64#define BT_MASK 0x02 56#define BT_MASK 0x02
65 57
58static struct rfkill *wifi_rfkill;
59static struct rfkill *bt_rfkill;
60static struct platform_device *compal_device;
61
66static int force; 62static int force;
67module_param(force, bool, 0); 63module_param(force, bool, 0);
68MODULE_PARM_DESC(force, "Force driver load, ignore DMI data"); 64MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -88,65 +84,75 @@ static int get_lcd_level(void)
88 return (int) result; 84 return (int) result;
89} 85}
90 86
91static int set_wlan_state(int state) 87static int compal_rfkill_set(void *data, bool blocked)
92{ 88{
89 unsigned long radio = (unsigned long) data;
93 u8 result, value; 90 u8 result, value;
94 91
95 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 92 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
96 93
97 if ((result & KILLSWITCH_MASK) == 0) 94 if (!blocked)
98 return -EINVAL; 95 value = (u8) (result | radio);
99 else { 96 else
100 if (state) 97 value = (u8) (result & ~radio);
101 value = (u8) (result | WLAN_MASK); 98 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
102 else
103 value = (u8) (result & ~WLAN_MASK);
104 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
105 }
106 99
107 return 0; 100 return 0;
108} 101}
109 102
110static int set_bluetooth_state(int state) 103static void compal_rfkill_poll(struct rfkill *rfkill, void *data)
111{ 104{
112 u8 result, value; 105 u8 result;
106 bool hw_blocked;
113 107
114 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 108 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
115 109
116 if ((result & KILLSWITCH_MASK) == 0) 110 hw_blocked = !(result & KILLSWITCH_MASK);
117 return -EINVAL; 111 rfkill_set_hw_state(rfkill, hw_blocked);
118 else {
119 if (state)
120 value = (u8) (result | BT_MASK);
121 else
122 value = (u8) (result & ~BT_MASK);
123 ec_write(COMPAL_EC_COMMAND_WIRELESS, value);
124 }
125
126 return 0;
127} 112}
128 113
129static int get_wireless_state(int *wlan, int *bluetooth) 114static const struct rfkill_ops compal_rfkill_ops = {
115 .poll = compal_rfkill_poll,
116 .set_block = compal_rfkill_set,
117};
118
119static int setup_rfkill(void)
130{ 120{
131 u8 result; 121 int ret;
132 122
133 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result); 123 wifi_rfkill = rfkill_alloc("compal-wifi", &compal_device->dev,
124 RFKILL_TYPE_WLAN, &compal_rfkill_ops,
125 (void *) WLAN_MASK);
126 if (!wifi_rfkill)
127 return -ENOMEM;
134 128
135 if (wlan) { 129 ret = rfkill_register(wifi_rfkill);
136 if ((result & KILLSWITCH_MASK) == 0) 130 if (ret)
137 *wlan = 0; 131 goto err_wifi;
138 else
139 *wlan = result & WLAN_MASK;
140 }
141 132
142 if (bluetooth) { 133 bt_rfkill = rfkill_alloc("compal-bluetooth", &compal_device->dev,
143 if ((result & KILLSWITCH_MASK) == 0) 134 RFKILL_TYPE_BLUETOOTH, &compal_rfkill_ops,
144 *bluetooth = 0; 135 (void *) BT_MASK);
145 else 136 if (!bt_rfkill) {
146 *bluetooth = (result & BT_MASK) >> 1; 137 ret = -ENOMEM;
138 goto err_allocate_bt;
147 } 139 }
140 ret = rfkill_register(bt_rfkill);
141 if (ret)
142 goto err_register_bt;
148 143
149 return 0; 144 return 0;
145
146err_register_bt:
147 rfkill_destroy(bt_rfkill);
148
149err_allocate_bt:
150 rfkill_unregister(wifi_rfkill);
151
152err_wifi:
153 rfkill_destroy(wifi_rfkill);
154
155 return ret;
150} 156}
151 157
152/* Backlight device stuff */ 158/* Backlight device stuff */
@@ -169,86 +175,6 @@ static struct backlight_ops compalbl_ops = {
169 175
170static struct backlight_device *compalbl_device; 176static struct backlight_device *compalbl_device;
171 177
172/* Platform device */
173
174static ssize_t show_wlan(struct device *dev,
175 struct device_attribute *attr, char *buf)
176{
177 int ret, enabled;
178
179 ret = get_wireless_state(&enabled, NULL);
180 if (ret < 0)
181 return ret;
182
183 return sprintf(buf, "%i\n", enabled);
184}
185
186static ssize_t show_raw(struct device *dev,
187 struct device_attribute *attr, char *buf)
188{
189 u8 result;
190
191 ec_read(COMPAL_EC_COMMAND_WIRELESS, &result);
192
193 return sprintf(buf, "%i\n", result);
194}
195
196static ssize_t show_bluetooth(struct device *dev,
197 struct device_attribute *attr, char *buf)
198{
199 int ret, enabled;
200
201 ret = get_wireless_state(NULL, &enabled);
202 if (ret < 0)
203 return ret;
204
205 return sprintf(buf, "%i\n", enabled);
206}
207
208static ssize_t store_wlan_state(struct device *dev,
209 struct device_attribute *attr, const char *buf, size_t count)
210{
211 int state, ret;
212
213 if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
214 return -EINVAL;
215
216 ret = set_wlan_state(state);
217 if (ret < 0)
218 return ret;
219
220 return count;
221}
222
223static ssize_t store_bluetooth_state(struct device *dev,
224 struct device_attribute *attr, const char *buf, size_t count)
225{
226 int state, ret;
227
228 if (sscanf(buf, "%i", &state) != 1 || (state < 0 || state > 1))
229 return -EINVAL;
230
231 ret = set_bluetooth_state(state);
232 if (ret < 0)
233 return ret;
234
235 return count;
236}
237
238static DEVICE_ATTR(bluetooth, 0644, show_bluetooth, store_bluetooth_state);
239static DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan_state);
240static DEVICE_ATTR(raw, 0444, show_raw, NULL);
241
242static struct attribute *compal_attributes[] = {
243 &dev_attr_bluetooth.attr,
244 &dev_attr_wlan.attr,
245 &dev_attr_raw.attr,
246 NULL
247};
248
249static struct attribute_group compal_attribute_group = {
250 .attrs = compal_attributes
251};
252 178
253static struct platform_driver compal_driver = { 179static struct platform_driver compal_driver = {
254 .driver = { 180 .driver = {
@@ -257,8 +183,6 @@ static struct platform_driver compal_driver = {
257 } 183 }
258}; 184};
259 185
260static struct platform_device *compal_device;
261
262/* Initialization */ 186/* Initialization */
263 187
264static int dmi_check_cb(const struct dmi_system_id *id) 188static int dmi_check_cb(const struct dmi_system_id *id)
@@ -310,6 +234,47 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
310 }, 234 },
311 .callback = dmi_check_cb 235 .callback = dmi_check_cb
312 }, 236 },
237 {
238 .ident = "Dell Mini 9",
239 .matches = {
240 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
241 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
242 },
243 .callback = dmi_check_cb
244 },
245 {
246 .ident = "Dell Mini 10",
247 .matches = {
248 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
249 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"),
250 },
251 .callback = dmi_check_cb
252 },
253 {
254 .ident = "Dell Mini 10v",
255 .matches = {
256 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
257 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"),
258 },
259 .callback = dmi_check_cb
260 },
261 {
262 .ident = "Dell Inspiron 11z",
263 .matches = {
264 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
265 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"),
266 },
267 .callback = dmi_check_cb
268 },
269 {
270 .ident = "Dell Mini 12",
271 .matches = {
272 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
273 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"),
274 },
275 .callback = dmi_check_cb
276 },
277
313 { } 278 { }
314}; 279};
315 280
@@ -348,23 +313,21 @@ static int __init compal_init(void)
348 313
349 ret = platform_device_add(compal_device); 314 ret = platform_device_add(compal_device);
350 if (ret) 315 if (ret)
351 goto fail_platform_device1; 316 goto fail_platform_device;
352 317
353 ret = sysfs_create_group(&compal_device->dev.kobj, 318 ret = setup_rfkill();
354 &compal_attribute_group);
355 if (ret) 319 if (ret)
356 goto fail_platform_device2; 320 goto fail_rfkill;
357 321
358 printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION 322 printk(KERN_INFO "compal-laptop: driver "COMPAL_DRIVER_VERSION
359 " successfully loaded.\n"); 323 " successfully loaded.\n");
360 324
361 return 0; 325 return 0;
362 326
363fail_platform_device2: 327fail_rfkill:
364
365 platform_device_del(compal_device); 328 platform_device_del(compal_device);
366 329
367fail_platform_device1: 330fail_platform_device:
368 331
369 platform_device_put(compal_device); 332 platform_device_put(compal_device);
370 333
@@ -382,10 +345,13 @@ fail_backlight:
382static void __exit compal_cleanup(void) 345static void __exit compal_cleanup(void)
383{ 346{
384 347
385 sysfs_remove_group(&compal_device->dev.kobj, &compal_attribute_group);
386 platform_device_unregister(compal_device); 348 platform_device_unregister(compal_device);
387 platform_driver_unregister(&compal_driver); 349 platform_driver_unregister(&compal_driver);
388 backlight_device_unregister(compalbl_device); 350 backlight_device_unregister(compalbl_device);
351 rfkill_unregister(wifi_rfkill);
352 rfkill_destroy(wifi_rfkill);
353 rfkill_unregister(bt_rfkill);
354 rfkill_destroy(bt_rfkill);
389 355
390 printk(KERN_INFO "compal-laptop: driver unloaded.\n"); 356 printk(KERN_INFO "compal-laptop: driver unloaded.\n");
391} 357}
@@ -403,3 +369,8 @@ MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
403MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*"); 369MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
404MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*"); 370MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
405MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*"); 371MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
372MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
373MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
374MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
375MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
376MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");