diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-07-18 06:20:23 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-07-18 06:20:23 -0400 |
| commit | cd569ef5d6ff9f43e9504f1ffc7fdbe356518149 (patch) | |
| tree | 9a4ab5e600fd09e991aa1fbb69adb1c7950898a4 /drivers/misc/acer-wmi.c | |
| parent | 6879827f4e08da219c99b91e4e1d793a924103e3 (diff) | |
| parent | 5b664cb235e97afbf34db9c4d77f08ebd725335e (diff) | |
Merge branch 'linus' into x86/urgent
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 | ||
