diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/platform/x86/dell-laptop.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/platform/x86/dell-laptop.c')
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 353 |
1 files changed, 289 insertions, 64 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 74909c4aaeea..661e3ac4d5b1 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -22,6 +22,9 @@ | |||
22 | #include <linux/rfkill.h> | 22 | #include <linux/rfkill.h> |
23 | #include <linux/power_supply.h> | 23 | #include <linux/power_supply.h> |
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include <linux/mm.h> | ||
26 | #include <linux/i8042.h> | ||
27 | #include <linux/slab.h> | ||
25 | #include "../../firmware/dcdbas.h" | 28 | #include "../../firmware/dcdbas.h" |
26 | 29 | ||
27 | #define BRIGHTNESS_TOKEN 0x7d | 30 | #define BRIGHTNESS_TOKEN 0x7d |
@@ -58,6 +61,14 @@ static int da_command_code; | |||
58 | static int da_num_tokens; | 61 | static int da_num_tokens; |
59 | static struct calling_interface_token *da_tokens; | 62 | static struct calling_interface_token *da_tokens; |
60 | 63 | ||
64 | static struct platform_driver platform_driver = { | ||
65 | .driver = { | ||
66 | .name = "dell-laptop", | ||
67 | .owner = THIS_MODULE, | ||
68 | } | ||
69 | }; | ||
70 | |||
71 | static struct platform_device *platform_device; | ||
61 | static struct backlight_device *dell_backlight_device; | 72 | static struct backlight_device *dell_backlight_device; |
62 | static struct rfkill *wifi_rfkill; | 73 | static struct rfkill *wifi_rfkill; |
63 | static struct rfkill *bluetooth_rfkill; | 74 | static struct rfkill *bluetooth_rfkill; |
@@ -71,10 +82,74 @@ static const struct dmi_system_id __initdata dell_device_table[] = { | |||
71 | DMI_MATCH(DMI_CHASSIS_TYPE, "8"), | 82 | DMI_MATCH(DMI_CHASSIS_TYPE, "8"), |
72 | }, | 83 | }, |
73 | }, | 84 | }, |
85 | { | ||
86 | .ident = "Dell Computer Corporation", | ||
87 | .matches = { | ||
88 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), | ||
89 | DMI_MATCH(DMI_CHASSIS_TYPE, "8"), | ||
90 | }, | ||
91 | }, | ||
74 | { } | 92 | { } |
75 | }; | 93 | }; |
76 | 94 | ||
77 | static void parse_da_table(const struct dmi_header *dm) | 95 | static struct dmi_system_id __devinitdata dell_blacklist[] = { |
96 | /* Supported by compal-laptop */ | ||
97 | { | ||
98 | .ident = "Dell Mini 9", | ||
99 | .matches = { | ||
100 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
101 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"), | ||
102 | }, | ||
103 | }, | ||
104 | { | ||
105 | .ident = "Dell Mini 10", | ||
106 | .matches = { | ||
107 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
108 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), | ||
109 | }, | ||
110 | }, | ||
111 | { | ||
112 | .ident = "Dell Mini 10v", | ||
113 | .matches = { | ||
114 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
115 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), | ||
116 | }, | ||
117 | }, | ||
118 | { | ||
119 | .ident = "Dell Inspiron 11z", | ||
120 | .matches = { | ||
121 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
122 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), | ||
123 | }, | ||
124 | }, | ||
125 | { | ||
126 | .ident = "Dell Mini 12", | ||
127 | .matches = { | ||
128 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
129 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), | ||
130 | }, | ||
131 | }, | ||
132 | {} | ||
133 | }; | ||
134 | |||
135 | static struct calling_interface_buffer *buffer; | ||
136 | static struct page *bufferpage; | ||
137 | static DEFINE_MUTEX(buffer_mutex); | ||
138 | |||
139 | static int hwswitch_state; | ||
140 | |||
141 | static void get_buffer(void) | ||
142 | { | ||
143 | mutex_lock(&buffer_mutex); | ||
144 | memset(buffer, 0, sizeof(struct calling_interface_buffer)); | ||
145 | } | ||
146 | |||
147 | static void release_buffer(void) | ||
148 | { | ||
149 | mutex_unlock(&buffer_mutex); | ||
150 | } | ||
151 | |||
152 | static void __init parse_da_table(const struct dmi_header *dm) | ||
78 | { | 153 | { |
79 | /* Final token is a terminator, so we don't want to copy it */ | 154 | /* Final token is a terminator, so we don't want to copy it */ |
80 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; | 155 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; |
@@ -103,7 +178,7 @@ static void parse_da_table(const struct dmi_header *dm) | |||
103 | da_num_tokens += tokens; | 178 | da_num_tokens += tokens; |
104 | } | 179 | } |
105 | 180 | ||
106 | static void find_tokens(const struct dmi_header *dm, void *dummy) | 181 | static void __init find_tokens(const struct dmi_header *dm, void *dummy) |
107 | { | 182 | { |
108 | switch (dm->type) { | 183 | switch (dm->type) { |
109 | case 0xd4: /* Indexed IO */ | 184 | case 0xd4: /* Indexed IO */ |
@@ -152,6 +227,8 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
152 | /* Derived from information in DellWirelessCtl.cpp: | 227 | /* Derived from information in DellWirelessCtl.cpp: |
153 | Class 17, select 11 is radio control. It returns an array of 32-bit values. | 228 | Class 17, select 11 is radio control. It returns an array of 32-bit values. |
154 | 229 | ||
230 | Input byte 0 = 0: Wireless information | ||
231 | |||
155 | result[0]: return code | 232 | result[0]: return code |
156 | result[1]: | 233 | result[1]: |
157 | Bit 0: Hardware switch supported | 234 | Bit 0: Hardware switch supported |
@@ -172,33 +249,62 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
172 | Bits 20-31: Reserved | 249 | Bits 20-31: Reserved |
173 | result[2]: NVRAM size in bytes | 250 | result[2]: NVRAM size in bytes |
174 | result[3]: NVRAM format version number | 251 | result[3]: NVRAM format version number |
252 | |||
253 | Input byte 0 = 2: Wireless switch configuration | ||
254 | result[0]: return code | ||
255 | result[1]: | ||
256 | Bit 0: Wifi controlled by switch | ||
257 | Bit 1: Bluetooth controlled by switch | ||
258 | Bit 2: WWAN controlled by switch | ||
259 | Bits 3-6: Reserved | ||
260 | Bit 7: Wireless switch config locked | ||
261 | Bit 8: Wifi locator enabled | ||
262 | Bits 9-14: Reserved | ||
263 | Bit 15: Wifi locator setting locked | ||
264 | Bits 16-31: Reserved | ||
175 | */ | 265 | */ |
176 | 266 | ||
177 | static int dell_rfkill_set(void *data, bool blocked) | 267 | static int dell_rfkill_set(void *data, bool blocked) |
178 | { | 268 | { |
179 | struct calling_interface_buffer buffer; | ||
180 | int disable = blocked ? 1 : 0; | 269 | int disable = blocked ? 1 : 0; |
181 | unsigned long radio = (unsigned long)data; | 270 | unsigned long radio = (unsigned long)data; |
271 | int hwswitch_bit = (unsigned long)data - 1; | ||
272 | int ret = 0; | ||
182 | 273 | ||
183 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 274 | get_buffer(); |
184 | buffer.input[0] = (1 | (radio<<8) | (disable << 16)); | 275 | dell_send_request(buffer, 17, 11); |
185 | dell_send_request(&buffer, 17, 11); | ||
186 | 276 | ||
187 | return 0; | 277 | /* If the hardware switch controls this radio, and the hardware |
278 | switch is disabled, don't allow changing the software state */ | ||
279 | if ((hwswitch_state & BIT(hwswitch_bit)) && | ||
280 | !(buffer->output[1] & BIT(16))) { | ||
281 | ret = -EINVAL; | ||
282 | goto out; | ||
283 | } | ||
284 | |||
285 | buffer->input[0] = (1 | (radio<<8) | (disable << 16)); | ||
286 | dell_send_request(buffer, 17, 11); | ||
287 | |||
288 | out: | ||
289 | release_buffer(); | ||
290 | return ret; | ||
188 | } | 291 | } |
189 | 292 | ||
190 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) | 293 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) |
191 | { | 294 | { |
192 | struct calling_interface_buffer buffer; | ||
193 | int status; | 295 | int status; |
194 | int bit = (unsigned long)data + 16; | 296 | int bit = (unsigned long)data + 16; |
297 | int hwswitch_bit = (unsigned long)data - 1; | ||
195 | 298 | ||
196 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 299 | get_buffer(); |
197 | dell_send_request(&buffer, 17, 11); | 300 | dell_send_request(buffer, 17, 11); |
198 | status = buffer.output[1]; | 301 | status = buffer->output[1]; |
302 | release_buffer(); | ||
199 | 303 | ||
200 | if (status & BIT(bit)) | 304 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); |
201 | rfkill_set_hw_state(rfkill, !!(status & BIT(16))); | 305 | |
306 | if (hwswitch_state & (BIT(hwswitch_bit))) | ||
307 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); | ||
202 | } | 308 | } |
203 | 309 | ||
204 | static const struct rfkill_ops dell_rfkill_ops = { | 310 | static const struct rfkill_ops dell_rfkill_ops = { |
@@ -206,18 +312,40 @@ static const struct rfkill_ops dell_rfkill_ops = { | |||
206 | .query = dell_rfkill_query, | 312 | .query = dell_rfkill_query, |
207 | }; | 313 | }; |
208 | 314 | ||
209 | static int dell_setup_rfkill(void) | 315 | static void dell_update_rfkill(struct work_struct *ignored) |
316 | { | ||
317 | if (wifi_rfkill) | ||
318 | dell_rfkill_query(wifi_rfkill, (void *)1); | ||
319 | if (bluetooth_rfkill) | ||
320 | dell_rfkill_query(bluetooth_rfkill, (void *)2); | ||
321 | if (wwan_rfkill) | ||
322 | dell_rfkill_query(wwan_rfkill, (void *)3); | ||
323 | } | ||
324 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | ||
325 | |||
326 | |||
327 | static int __init dell_setup_rfkill(void) | ||
210 | { | 328 | { |
211 | struct calling_interface_buffer buffer; | ||
212 | int status; | 329 | int status; |
213 | int ret; | 330 | int ret; |
214 | 331 | ||
215 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 332 | if (dmi_check_system(dell_blacklist)) { |
216 | dell_send_request(&buffer, 17, 11); | 333 | printk(KERN_INFO "dell-laptop: Blacklisted hardware detected - " |
217 | status = buffer.output[1]; | 334 | "not enabling rfkill\n"); |
335 | return 0; | ||
336 | } | ||
337 | |||
338 | get_buffer(); | ||
339 | dell_send_request(buffer, 17, 11); | ||
340 | status = buffer->output[1]; | ||
341 | buffer->input[0] = 0x2; | ||
342 | dell_send_request(buffer, 17, 11); | ||
343 | hwswitch_state = buffer->output[1]; | ||
344 | release_buffer(); | ||
218 | 345 | ||
219 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 346 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |
220 | wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, | 347 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, |
348 | RFKILL_TYPE_WLAN, | ||
221 | &dell_rfkill_ops, (void *) 1); | 349 | &dell_rfkill_ops, (void *) 1); |
222 | if (!wifi_rfkill) { | 350 | if (!wifi_rfkill) { |
223 | ret = -ENOMEM; | 351 | ret = -ENOMEM; |
@@ -229,7 +357,8 @@ static int dell_setup_rfkill(void) | |||
229 | } | 357 | } |
230 | 358 | ||
231 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | 359 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { |
232 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, | 360 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", |
361 | &platform_device->dev, | ||
233 | RFKILL_TYPE_BLUETOOTH, | 362 | RFKILL_TYPE_BLUETOOTH, |
234 | &dell_rfkill_ops, (void *) 2); | 363 | &dell_rfkill_ops, (void *) 2); |
235 | if (!bluetooth_rfkill) { | 364 | if (!bluetooth_rfkill) { |
@@ -242,7 +371,9 @@ static int dell_setup_rfkill(void) | |||
242 | } | 371 | } |
243 | 372 | ||
244 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | 373 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { |
245 | wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, | 374 | wwan_rfkill = rfkill_alloc("dell-wwan", |
375 | &platform_device->dev, | ||
376 | RFKILL_TYPE_WWAN, | ||
246 | &dell_rfkill_ops, (void *) 3); | 377 | &dell_rfkill_ops, (void *) 3); |
247 | if (!wwan_rfkill) { | 378 | if (!wwan_rfkill) { |
248 | ret = -ENOMEM; | 379 | ret = -ENOMEM; |
@@ -268,41 +399,67 @@ err_wifi: | |||
268 | return ret; | 399 | return ret; |
269 | } | 400 | } |
270 | 401 | ||
402 | static void dell_cleanup_rfkill(void) | ||
403 | { | ||
404 | if (wifi_rfkill) { | ||
405 | rfkill_unregister(wifi_rfkill); | ||
406 | rfkill_destroy(wifi_rfkill); | ||
407 | } | ||
408 | if (bluetooth_rfkill) { | ||
409 | rfkill_unregister(bluetooth_rfkill); | ||
410 | rfkill_destroy(bluetooth_rfkill); | ||
411 | } | ||
412 | if (wwan_rfkill) { | ||
413 | rfkill_unregister(wwan_rfkill); | ||
414 | rfkill_destroy(wwan_rfkill); | ||
415 | } | ||
416 | } | ||
417 | |||
271 | static int dell_send_intensity(struct backlight_device *bd) | 418 | static int dell_send_intensity(struct backlight_device *bd) |
272 | { | 419 | { |
273 | struct calling_interface_buffer buffer; | 420 | int ret = 0; |
274 | 421 | ||
275 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 422 | get_buffer(); |
276 | buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); | 423 | buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN); |
277 | buffer.input[1] = bd->props.brightness; | 424 | buffer->input[1] = bd->props.brightness; |
278 | 425 | ||
279 | if (buffer.input[0] == -1) | 426 | if (buffer->input[0] == -1) { |
280 | return -ENODEV; | 427 | ret = -ENODEV; |
428 | goto out; | ||
429 | } | ||
281 | 430 | ||
282 | if (power_supply_is_system_supplied() > 0) | 431 | if (power_supply_is_system_supplied() > 0) |
283 | dell_send_request(&buffer, 1, 2); | 432 | dell_send_request(buffer, 1, 2); |
284 | else | 433 | else |
285 | dell_send_request(&buffer, 1, 1); | 434 | dell_send_request(buffer, 1, 1); |
286 | 435 | ||
436 | out: | ||
437 | release_buffer(); | ||
287 | return 0; | 438 | return 0; |
288 | } | 439 | } |
289 | 440 | ||
290 | static int dell_get_intensity(struct backlight_device *bd) | 441 | static int dell_get_intensity(struct backlight_device *bd) |
291 | { | 442 | { |
292 | struct calling_interface_buffer buffer; | 443 | int ret = 0; |
293 | 444 | ||
294 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 445 | get_buffer(); |
295 | buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); | 446 | buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN); |
296 | 447 | ||
297 | if (buffer.input[0] == -1) | 448 | if (buffer->input[0] == -1) { |
298 | return -ENODEV; | 449 | ret = -ENODEV; |
450 | goto out; | ||
451 | } | ||
299 | 452 | ||
300 | if (power_supply_is_system_supplied() > 0) | 453 | if (power_supply_is_system_supplied() > 0) |
301 | dell_send_request(&buffer, 0, 2); | 454 | dell_send_request(buffer, 0, 2); |
302 | else | 455 | else |
303 | dell_send_request(&buffer, 0, 1); | 456 | dell_send_request(buffer, 0, 1); |
304 | 457 | ||
305 | return buffer.output[1]; | 458 | out: |
459 | release_buffer(); | ||
460 | if (ret) | ||
461 | return ret; | ||
462 | return buffer->output[1]; | ||
306 | } | 463 | } |
307 | 464 | ||
308 | static struct backlight_ops dell_ops = { | 465 | static struct backlight_ops dell_ops = { |
@@ -310,9 +467,32 @@ static struct backlight_ops dell_ops = { | |||
310 | .update_status = dell_send_intensity, | 467 | .update_status = dell_send_intensity, |
311 | }; | 468 | }; |
312 | 469 | ||
470 | bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, | ||
471 | struct serio *port) | ||
472 | { | ||
473 | static bool extended; | ||
474 | |||
475 | if (str & 0x20) | ||
476 | return false; | ||
477 | |||
478 | if (unlikely(data == 0xe0)) { | ||
479 | extended = true; | ||
480 | return false; | ||
481 | } else if (unlikely(extended)) { | ||
482 | switch (data) { | ||
483 | case 0x8: | ||
484 | schedule_delayed_work(&dell_rfkill_work, | ||
485 | round_jiffies_relative(HZ)); | ||
486 | break; | ||
487 | } | ||
488 | extended = false; | ||
489 | } | ||
490 | |||
491 | return false; | ||
492 | } | ||
493 | |||
313 | static int __init dell_init(void) | 494 | static int __init dell_init(void) |
314 | { | 495 | { |
315 | struct calling_interface_buffer buffer; | ||
316 | int max_intensity = 0; | 496 | int max_intensity = 0; |
317 | int ret; | 497 | int ret; |
318 | 498 | ||
@@ -326,11 +506,41 @@ static int __init dell_init(void) | |||
326 | return -ENODEV; | 506 | return -ENODEV; |
327 | } | 507 | } |
328 | 508 | ||
509 | ret = platform_driver_register(&platform_driver); | ||
510 | if (ret) | ||
511 | goto fail_platform_driver; | ||
512 | platform_device = platform_device_alloc("dell-laptop", -1); | ||
513 | if (!platform_device) { | ||
514 | ret = -ENOMEM; | ||
515 | goto fail_platform_device1; | ||
516 | } | ||
517 | ret = platform_device_add(platform_device); | ||
518 | if (ret) | ||
519 | goto fail_platform_device2; | ||
520 | |||
521 | /* | ||
522 | * Allocate buffer below 4GB for SMI data--only 32-bit physical addr | ||
523 | * is passed to SMI handler. | ||
524 | */ | ||
525 | bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32); | ||
526 | |||
527 | if (!bufferpage) | ||
528 | goto fail_buffer; | ||
529 | buffer = page_address(bufferpage); | ||
530 | mutex_init(&buffer_mutex); | ||
531 | |||
329 | ret = dell_setup_rfkill(); | 532 | ret = dell_setup_rfkill(); |
330 | 533 | ||
331 | if (ret) { | 534 | if (ret) { |
332 | printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); | 535 | printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); |
333 | goto out; | 536 | goto fail_rfkill; |
537 | } | ||
538 | |||
539 | ret = i8042_install_filter(dell_laptop_i8042_filter); | ||
540 | if (ret) { | ||
541 | printk(KERN_WARNING | ||
542 | "dell-laptop: Unable to install key filter\n"); | ||
543 | goto fail_filter; | ||
334 | } | 544 | } |
335 | 545 | ||
336 | #ifdef CONFIG_ACPI | 546 | #ifdef CONFIG_ACPI |
@@ -341,53 +551,67 @@ static int __init dell_init(void) | |||
341 | return 0; | 551 | return 0; |
342 | #endif | 552 | #endif |
343 | 553 | ||
344 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 554 | get_buffer(); |
345 | buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); | 555 | buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN); |
346 | 556 | if (buffer->input[0] != -1) { | |
347 | if (buffer.input[0] != -1) { | 557 | dell_send_request(buffer, 0, 2); |
348 | dell_send_request(&buffer, 0, 2); | 558 | max_intensity = buffer->output[3]; |
349 | max_intensity = buffer.output[3]; | ||
350 | } | 559 | } |
560 | release_buffer(); | ||
351 | 561 | ||
352 | if (max_intensity) { | 562 | if (max_intensity) { |
353 | dell_backlight_device = backlight_device_register( | 563 | struct backlight_properties props; |
354 | "dell_backlight", | 564 | memset(&props, 0, sizeof(struct backlight_properties)); |
355 | NULL, NULL, | 565 | props.max_brightness = max_intensity; |
356 | &dell_ops); | 566 | dell_backlight_device = backlight_device_register("dell_backlight", |
567 | &platform_device->dev, | ||
568 | NULL, | ||
569 | &dell_ops, | ||
570 | &props); | ||
357 | 571 | ||
358 | if (IS_ERR(dell_backlight_device)) { | 572 | if (IS_ERR(dell_backlight_device)) { |
359 | ret = PTR_ERR(dell_backlight_device); | 573 | ret = PTR_ERR(dell_backlight_device); |
360 | dell_backlight_device = NULL; | 574 | dell_backlight_device = NULL; |
361 | goto out; | 575 | goto fail_backlight; |
362 | } | 576 | } |
363 | 577 | ||
364 | dell_backlight_device->props.max_brightness = max_intensity; | ||
365 | dell_backlight_device->props.brightness = | 578 | dell_backlight_device->props.brightness = |
366 | dell_get_intensity(dell_backlight_device); | 579 | dell_get_intensity(dell_backlight_device); |
367 | backlight_update_status(dell_backlight_device); | 580 | backlight_update_status(dell_backlight_device); |
368 | } | 581 | } |
369 | 582 | ||
370 | return 0; | 583 | return 0; |
371 | out: | 584 | |
372 | if (wifi_rfkill) | 585 | fail_backlight: |
373 | rfkill_unregister(wifi_rfkill); | 586 | i8042_remove_filter(dell_laptop_i8042_filter); |
374 | if (bluetooth_rfkill) | 587 | cancel_delayed_work_sync(&dell_rfkill_work); |
375 | rfkill_unregister(bluetooth_rfkill); | 588 | fail_filter: |
376 | if (wwan_rfkill) | 589 | dell_cleanup_rfkill(); |
377 | rfkill_unregister(wwan_rfkill); | 590 | fail_rfkill: |
591 | free_page((unsigned long)bufferpage); | ||
592 | fail_buffer: | ||
593 | platform_device_del(platform_device); | ||
594 | fail_platform_device2: | ||
595 | platform_device_put(platform_device); | ||
596 | fail_platform_device1: | ||
597 | platform_driver_unregister(&platform_driver); | ||
598 | fail_platform_driver: | ||
378 | kfree(da_tokens); | 599 | kfree(da_tokens); |
379 | return ret; | 600 | return ret; |
380 | } | 601 | } |
381 | 602 | ||
382 | static void __exit dell_exit(void) | 603 | static void __exit dell_exit(void) |
383 | { | 604 | { |
605 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
606 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
384 | backlight_device_unregister(dell_backlight_device); | 607 | backlight_device_unregister(dell_backlight_device); |
385 | if (wifi_rfkill) | 608 | dell_cleanup_rfkill(); |
386 | rfkill_unregister(wifi_rfkill); | 609 | if (platform_device) { |
387 | if (bluetooth_rfkill) | 610 | platform_device_unregister(platform_device); |
388 | rfkill_unregister(bluetooth_rfkill); | 611 | platform_driver_unregister(&platform_driver); |
389 | if (wwan_rfkill) | 612 | } |
390 | rfkill_unregister(wwan_rfkill); | 613 | kfree(da_tokens); |
614 | free_page((unsigned long)buffer); | ||
391 | } | 615 | } |
392 | 616 | ||
393 | module_init(dell_init); | 617 | module_init(dell_init); |
@@ -397,3 +621,4 @@ MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | |||
397 | MODULE_DESCRIPTION("Dell laptop driver"); | 621 | MODULE_DESCRIPTION("Dell laptop driver"); |
398 | MODULE_LICENSE("GPL"); | 622 | MODULE_LICENSE("GPL"); |
399 | MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); | 623 | MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*"); |
624 | MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*"); | ||