diff options
Diffstat (limited to 'drivers/misc/acer-wmi.c')
-rw-r--r-- | drivers/misc/acer-wmi.c | 145 |
1 files changed, 135 insertions, 10 deletions
diff --git a/drivers/misc/acer-wmi.c b/drivers/misc/acer-wmi.c index dd13a3749927..e7a3fe508dff 100644 --- a/drivers/misc/acer-wmi.c +++ b/drivers/misc/acer-wmi.c | |||
@@ -22,18 +22,18 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #define ACER_WMI_VERSION "0.1" | ||
26 | |||
27 | #include <linux/kernel.h> | 25 | #include <linux/kernel.h> |
28 | #include <linux/module.h> | 26 | #include <linux/module.h> |
29 | #include <linux/init.h> | 27 | #include <linux/init.h> |
30 | #include <linux/types.h> | 28 | #include <linux/types.h> |
31 | #include <linux/dmi.h> | 29 | #include <linux/dmi.h> |
30 | #include <linux/fb.h> | ||
32 | #include <linux/backlight.h> | 31 | #include <linux/backlight.h> |
33 | #include <linux/leds.h> | 32 | #include <linux/leds.h> |
34 | #include <linux/platform_device.h> | 33 | #include <linux/platform_device.h> |
35 | #include <linux/acpi.h> | 34 | #include <linux/acpi.h> |
36 | #include <linux/i8042.h> | 35 | #include <linux/i8042.h> |
36 | #include <linux/debugfs.h> | ||
37 | 37 | ||
38 | #include <acpi/acpi_drivers.h> | 38 | #include <acpi/acpi_drivers.h> |
39 | 39 | ||
@@ -87,6 +87,7 @@ struct acer_quirks { | |||
87 | * Acer ACPI method GUIDs | 87 | * Acer ACPI method GUIDs |
88 | */ | 88 | */ |
89 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" | 89 | #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" |
90 | #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" | ||
90 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" | 91 | #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3" |
91 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" | 92 | #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" |
92 | 93 | ||
@@ -150,6 +151,12 @@ struct acer_data { | |||
150 | int brightness; | 151 | int brightness; |
151 | }; | 152 | }; |
152 | 153 | ||
154 | struct acer_debug { | ||
155 | struct dentry *root; | ||
156 | struct dentry *devices; | ||
157 | u32 wmid_devices; | ||
158 | }; | ||
159 | |||
153 | /* Each low-level interface must define at least some of the following */ | 160 | /* Each low-level interface must define at least some of the following */ |
154 | struct wmi_interface { | 161 | struct wmi_interface { |
155 | /* The WMI device type */ | 162 | /* The WMI device type */ |
@@ -160,6 +167,9 @@ struct wmi_interface { | |||
160 | 167 | ||
161 | /* Private data for the current interface */ | 168 | /* Private data for the current interface */ |
162 | struct acer_data data; | 169 | struct acer_data data; |
170 | |||
171 | /* debugfs entries associated with this interface */ | ||
172 | struct acer_debug debug; | ||
163 | }; | 173 | }; |
164 | 174 | ||
165 | /* The static interface pointer, points to the currently detected interface */ | 175 | /* The static interface pointer, points to the currently detected interface */ |
@@ -174,7 +184,7 @@ static struct wmi_interface *interface; | |||
174 | struct quirk_entry { | 184 | struct quirk_entry { |
175 | u8 wireless; | 185 | u8 wireless; |
176 | u8 mailled; | 186 | u8 mailled; |
177 | u8 brightness; | 187 | s8 brightness; |
178 | u8 bluetooth; | 188 | u8 bluetooth; |
179 | }; | 189 | }; |
180 | 190 | ||
@@ -198,6 +208,10 @@ static int dmi_matched(const struct dmi_system_id *dmi) | |||
198 | static struct quirk_entry quirk_unknown = { | 208 | static struct quirk_entry quirk_unknown = { |
199 | }; | 209 | }; |
200 | 210 | ||
211 | static struct quirk_entry quirk_acer_aspire_1520 = { | ||
212 | .brightness = -1, | ||
213 | }; | ||
214 | |||
201 | static struct quirk_entry quirk_acer_travelmate_2490 = { | 215 | static struct quirk_entry quirk_acer_travelmate_2490 = { |
202 | .mailled = 1, | 216 | .mailled = 1, |
203 | }; | 217 | }; |
@@ -207,9 +221,31 @@ static struct quirk_entry quirk_medion_md_98300 = { | |||
207 | .wireless = 1, | 221 | .wireless = 1, |
208 | }; | 222 | }; |
209 | 223 | ||
224 | static struct quirk_entry quirk_fujitsu_amilo_li_1718 = { | ||
225 | .wireless = 2, | ||
226 | }; | ||
227 | |||
210 | static struct dmi_system_id acer_quirks[] = { | 228 | static struct dmi_system_id acer_quirks[] = { |
211 | { | 229 | { |
212 | .callback = dmi_matched, | 230 | .callback = dmi_matched, |
231 | .ident = "Acer Aspire 1360", | ||
232 | .matches = { | ||
233 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
234 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1360"), | ||
235 | }, | ||
236 | .driver_data = &quirk_acer_aspire_1520, | ||
237 | }, | ||
238 | { | ||
239 | .callback = dmi_matched, | ||
240 | .ident = "Acer Aspire 1520", | ||
241 | .matches = { | ||
242 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | ||
243 | DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 1520"), | ||
244 | }, | ||
245 | .driver_data = &quirk_acer_aspire_1520, | ||
246 | }, | ||
247 | { | ||
248 | .callback = dmi_matched, | ||
213 | .ident = "Acer Aspire 3100", | 249 | .ident = "Acer Aspire 3100", |
214 | .matches = { | 250 | .matches = { |
215 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), | 251 | DMI_MATCH(DMI_SYS_VENDOR, "Acer"), |
@@ -300,6 +336,15 @@ static struct dmi_system_id acer_quirks[] = { | |||
300 | }, | 336 | }, |
301 | { | 337 | { |
302 | .callback = dmi_matched, | 338 | .callback = dmi_matched, |
339 | .ident = "Fujitsu Siemens Amilo Li 1718", | ||
340 | .matches = { | ||
341 | DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), | ||
342 | DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Li 1718"), | ||
343 | }, | ||
344 | .driver_data = &quirk_fujitsu_amilo_li_1718, | ||
345 | }, | ||
346 | { | ||
347 | .callback = dmi_matched, | ||
303 | .ident = "Medion MD 98300", | 348 | .ident = "Medion MD 98300", |
304 | .matches = { | 349 | .matches = { |
305 | DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), | 350 | DMI_MATCH(DMI_SYS_VENDOR, "MEDION"), |
@@ -393,6 +438,12 @@ struct wmi_interface *iface) | |||
393 | return AE_ERROR; | 438 | return AE_ERROR; |
394 | *value = result & 0x1; | 439 | *value = result & 0x1; |
395 | return AE_OK; | 440 | return AE_OK; |
441 | case 2: | ||
442 | err = ec_read(0x71, &result); | ||
443 | if (err) | ||
444 | return AE_ERROR; | ||
445 | *value = result & 0x1; | ||
446 | return AE_OK; | ||
396 | default: | 447 | default: |
397 | err = ec_read(0xA, &result); | 448 | err = ec_read(0xA, &result); |
398 | if (err) | 449 | if (err) |
@@ -506,6 +557,15 @@ static acpi_status AMW0_set_capabilities(void) | |||
506 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; | 557 | struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; |
507 | union acpi_object *obj; | 558 | union acpi_object *obj; |
508 | 559 | ||
560 | /* | ||
561 | * On laptops with this strange GUID (non Acer), normal probing doesn't | ||
562 | * work. | ||
563 | */ | ||
564 | if (wmi_has_guid(AMW0_GUID2)) { | ||
565 | interface->capability |= ACER_CAP_WIRELESS; | ||
566 | return AE_OK; | ||
567 | } | ||
568 | |||
509 | args.eax = ACER_AMW0_WRITE; | 569 | args.eax = ACER_AMW0_WRITE; |
510 | args.ecx = args.edx = 0; | 570 | args.ecx = args.edx = 0; |
511 | 571 | ||
@@ -552,7 +612,8 @@ static acpi_status AMW0_set_capabilities(void) | |||
552 | * appear to use the same EC register for brightness, even if they | 612 | * appear to use the same EC register for brightness, even if they |
553 | * differ for wireless, etc | 613 | * differ for wireless, etc |
554 | */ | 614 | */ |
555 | interface->capability |= ACER_CAP_BRIGHTNESS; | 615 | if (quirks->brightness >= 0) |
616 | interface->capability |= ACER_CAP_BRIGHTNESS; | ||
556 | 617 | ||
557 | return AE_OK; | 618 | return AE_OK; |
558 | } | 619 | } |
@@ -807,7 +868,15 @@ static int read_brightness(struct backlight_device *bd) | |||
807 | 868 | ||
808 | static int update_bl_status(struct backlight_device *bd) | 869 | static int update_bl_status(struct backlight_device *bd) |
809 | { | 870 | { |
810 | set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS); | 871 | int intensity = bd->props.brightness; |
872 | |||
873 | if (bd->props.power != FB_BLANK_UNBLANK) | ||
874 | intensity = 0; | ||
875 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) | ||
876 | intensity = 0; | ||
877 | |||
878 | set_u32(intensity, ACER_CAP_BRIGHTNESS); | ||
879 | |||
811 | return 0; | 880 | return 0; |
812 | } | 881 | } |
813 | 882 | ||
@@ -829,8 +898,9 @@ static int __devinit acer_backlight_init(struct device *dev) | |||
829 | 898 | ||
830 | acer_backlight_device = bd; | 899 | acer_backlight_device = bd; |
831 | 900 | ||
901 | bd->props.power = FB_BLANK_UNBLANK; | ||
902 | bd->props.brightness = max_brightness; | ||
832 | bd->props.max_brightness = max_brightness; | 903 | bd->props.max_brightness = max_brightness; |
833 | bd->props.brightness = read_brightness(NULL); | ||
834 | backlight_update_status(bd); | 904 | backlight_update_status(bd); |
835 | return 0; | 905 | return 0; |
836 | } | 906 | } |
@@ -894,6 +964,28 @@ static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, | |||
894 | show_interface, NULL); | 964 | show_interface, NULL); |
895 | 965 | ||
896 | /* | 966 | /* |
967 | * debugfs functions | ||
968 | */ | ||
969 | static u32 get_wmid_devices(void) | ||
970 | { | ||
971 | struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
972 | union acpi_object *obj; | ||
973 | acpi_status status; | ||
974 | |||
975 | status = wmi_query_block(WMID_GUID2, 1, &out); | ||
976 | if (ACPI_FAILURE(status)) | ||
977 | return 0; | ||
978 | |||
979 | obj = (union acpi_object *) out.pointer; | ||
980 | if (obj && obj->type == ACPI_TYPE_BUFFER && | ||
981 | obj->buffer.length == sizeof(u32)) { | ||
982 | return *((u32 *) obj->buffer.pointer); | ||
983 | } else { | ||
984 | return 0; | ||
985 | } | ||
986 | } | ||
987 | |||
988 | /* | ||
897 | * Platform device | 989 | * Platform device |
898 | */ | 990 | */ |
899 | static int __devinit acer_platform_probe(struct platform_device *device) | 991 | static int __devinit acer_platform_probe(struct platform_device *device) |
@@ -1052,12 +1144,40 @@ error_sysfs: | |||
1052 | return retval; | 1144 | return retval; |
1053 | } | 1145 | } |
1054 | 1146 | ||
1147 | static void remove_debugfs(void) | ||
1148 | { | ||
1149 | debugfs_remove(interface->debug.devices); | ||
1150 | debugfs_remove(interface->debug.root); | ||
1151 | } | ||
1152 | |||
1153 | static int create_debugfs(void) | ||
1154 | { | ||
1155 | interface->debug.root = debugfs_create_dir("acer-wmi", NULL); | ||
1156 | if (!interface->debug.root) { | ||
1157 | printk(ACER_ERR "Failed to create debugfs directory"); | ||
1158 | return -ENOMEM; | ||
1159 | } | ||
1160 | |||
1161 | interface->debug.devices = debugfs_create_u32("devices", S_IRUGO, | ||
1162 | interface->debug.root, | ||
1163 | &interface->debug.wmid_devices); | ||
1164 | if (!interface->debug.devices) | ||
1165 | goto error_debugfs; | ||
1166 | |||
1167 | return 0; | ||
1168 | |||
1169 | error_debugfs: | ||
1170 | remove_debugfs(); | ||
1171 | return -ENOMEM; | ||
1172 | } | ||
1173 | |||
1055 | static int __init acer_wmi_init(void) | 1174 | static int __init acer_wmi_init(void) |
1056 | { | 1175 | { |
1057 | int err; | 1176 | int err; |
1058 | 1177 | ||
1059 | printk(ACER_INFO "Acer Laptop ACPI-WMI Extras version %s\n", | 1178 | printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); |
1060 | ACER_WMI_VERSION); | 1179 | |
1180 | find_quirks(); | ||
1061 | 1181 | ||
1062 | /* | 1182 | /* |
1063 | * Detect which ACPI-WMI interface we're using. | 1183 | * Detect which ACPI-WMI interface we're using. |
@@ -1092,8 +1212,6 @@ static int __init acer_wmi_init(void) | |||
1092 | if (wmi_has_guid(AMW0_GUID1)) | 1212 | if (wmi_has_guid(AMW0_GUID1)) |
1093 | AMW0_find_mailled(); | 1213 | AMW0_find_mailled(); |
1094 | 1214 | ||
1095 | find_quirks(); | ||
1096 | |||
1097 | if (!interface) { | 1215 | if (!interface) { |
1098 | printk(ACER_ERR "No or unsupported WMI interface, unable to " | 1216 | printk(ACER_ERR "No or unsupported WMI interface, unable to " |
1099 | "load\n"); | 1217 | "load\n"); |
@@ -1111,6 +1229,13 @@ static int __init acer_wmi_init(void) | |||
1111 | if (err) | 1229 | if (err) |
1112 | return err; | 1230 | return err; |
1113 | 1231 | ||
1232 | if (wmi_has_guid(WMID_GUID2)) { | ||
1233 | interface->debug.wmid_devices = get_wmid_devices(); | ||
1234 | err = create_debugfs(); | ||
1235 | if (err) | ||
1236 | return err; | ||
1237 | } | ||
1238 | |||
1114 | /* Override any initial settings with values from the commandline */ | 1239 | /* Override any initial settings with values from the commandline */ |
1115 | acer_commandline_init(); | 1240 | acer_commandline_init(); |
1116 | 1241 | ||