Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
7d8c2206
Commit
7d8c2206
authored
Dec 16, 2009
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'msi-wmi' into release
parents
f02f465b
de078e57
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
306 additions
and
0 deletions
+306
-0
drivers/platform/x86/Kconfig
drivers/platform/x86/Kconfig
+12
-0
drivers/platform/x86/Makefile
drivers/platform/x86/Makefile
+1
-0
drivers/platform/x86/msi-wmi.c
drivers/platform/x86/msi-wmi.c
+293
-0
No files found.
drivers/platform/x86/Kconfig
View file @
7d8c2206
...
...
@@ -367,6 +367,18 @@ config ACPI_WMI
It is safe to enable this driver even if your DSDT doesn't define
any ACPI-WMI devices.
config MSI_WMI
tristate "MSI WMI extras"
depends on ACPI_WMI
depends on INPUT
depends on BACKLIGHT_CLASS_DEVICE
select INPUT_SPARSEKMAP
help
Say Y here if you want to support WMI-based hotkeys on MSI laptops.
To compile this driver as a module, choose M here: the module will
be called msi-wmi.
config ACPI_ASUS
tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
depends on ACPI
...
...
drivers/platform/x86/Makefile
View file @
7d8c2206
...
...
@@ -18,6 +18,7 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_PANASONIC_LAPTOP)
+=
panasonic-laptop.o
obj-$(CONFIG_INTEL_MENLOW)
+=
intel_menlow.o
obj-$(CONFIG_ACPI_WMI)
+=
wmi.o
obj-$(CONFIG_MSI_WMI)
+=
msi-wmi.o
obj-$(CONFIG_ACPI_ASUS)
+=
asus_acpi.o
obj-$(CONFIG_TOPSTAR_LAPTOP)
+=
topstar-laptop.o
obj-$(CONFIG_ACPI_TOSHIBA)
+=
toshiba_acpi.o
drivers/platform/x86/msi-wmi.c
0 → 100644
View file @
7d8c2206
/*
* MSI WMI hotkeys
*
* Copyright (C) 2009 Novell <trenn@suse.de>
*
* Most stuff taken over from hp-wmi
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/acpi.h>
#include <linux/backlight.h>
MODULE_AUTHOR
(
"Thomas Renninger <trenn@suse.de>"
);
MODULE_DESCRIPTION
(
"MSI laptop WMI hotkeys driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_ALIAS
(
"wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
);
MODULE_ALIAS
(
"wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
);
/* Temporary workaround until the WMI sysfs interface goes in
{ "svn", DMI_SYS_VENDOR },
{ "pn", DMI_PRODUCT_NAME },
{ "pvr", DMI_PRODUCT_VERSION },
{ "rvn", DMI_BOARD_VENDOR },
{ "rn", DMI_BOARD_NAME },
*/
MODULE_ALIAS
(
"dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-6638:*"
);
#define DRV_NAME "msi-wmi"
#define DRV_PFX DRV_NAME ": "
#define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
#define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
#define dprintk(msg...) pr_debug(DRV_PFX msg)
#define KEYCODE_BASE 0xD0
#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE
#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1)
#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2)
#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3)
static
struct
key_entry
msi_wmi_keymap
[]
=
{
{
KE_KEY
,
MSI_WMI_BRIGHTNESSUP
,
{
KEY_BRIGHTNESSUP
}
},
{
KE_KEY
,
MSI_WMI_BRIGHTNESSDOWN
,
{
KEY_BRIGHTNESSDOWN
}
},
{
KE_KEY
,
MSI_WMI_VOLUMEUP
,
{
KEY_VOLUMEUP
}
},
{
KE_KEY
,
MSI_WMI_VOLUMEDOWN
,
{
KEY_VOLUMEDOWN
}
},
{
KE_END
,
0
}
};
static
ktime_t
last_pressed
[
ARRAY_SIZE
(
msi_wmi_keymap
)
-
1
];
struct
backlight_device
*
backlight
;
static
int
backlight_map
[]
=
{
0x00
,
0x33
,
0x66
,
0x99
,
0xCC
,
0xFF
};
static
struct
input_dev
*
msi_wmi_input_dev
;
static
int
msi_wmi_query_block
(
int
instance
,
int
*
ret
)
{
acpi_status
status
;
union
acpi_object
*
obj
;
struct
acpi_buffer
output
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
status
=
wmi_query_block
(
MSIWMI_BIOS_GUID
,
instance
,
&
output
);
obj
=
output
.
pointer
;
if
(
!
obj
||
obj
->
type
!=
ACPI_TYPE_INTEGER
)
{
if
(
obj
)
{
printk
(
KERN_ERR
DRV_PFX
"query block returned object "
"type: %d - buffer length:%d
\n
"
,
obj
->
type
,
obj
->
type
==
ACPI_TYPE_BUFFER
?
obj
->
buffer
.
length
:
0
);
}
kfree
(
obj
);
return
-
EINVAL
;
}
*
ret
=
obj
->
integer
.
value
;
kfree
(
obj
);
return
0
;
}
static
int
msi_wmi_set_block
(
int
instance
,
int
value
)
{
acpi_status
status
;
struct
acpi_buffer
input
=
{
sizeof
(
int
),
&
value
};
dprintk
(
"Going to set block of instance: %d - value: %d
\n
"
,
instance
,
value
);
status
=
wmi_set_block
(
MSIWMI_BIOS_GUID
,
instance
,
&
input
);
return
ACPI_SUCCESS
(
status
)
?
0
:
1
;
}
static
int
bl_get
(
struct
backlight_device
*
bd
)
{
int
level
,
err
,
ret
;
/* Instance 1 is "get backlight", cmp with DSDT */
err
=
msi_wmi_query_block
(
1
,
&
ret
);
if
(
err
)
{
printk
(
KERN_ERR
DRV_PFX
"Could not query backlight: %d
\n
"
,
err
);
return
-
EINVAL
;
}
dprintk
(
"Get: Query block returned: %d
\n
"
,
ret
);
for
(
level
=
0
;
level
<
ARRAY_SIZE
(
backlight_map
);
level
++
)
{
if
(
backlight_map
[
level
]
==
ret
)
{
dprintk
(
"Current backlight level: 0x%X - index: %d
\n
"
,
backlight_map
[
level
],
level
);
break
;
}
}
if
(
level
==
ARRAY_SIZE
(
backlight_map
))
{
printk
(
KERN_ERR
DRV_PFX
"get: Invalid brightness value: 0x%X
\n
"
,
ret
);
return
-
EINVAL
;
}
return
level
;
}
static
int
bl_set_status
(
struct
backlight_device
*
bd
)
{
int
bright
=
bd
->
props
.
brightness
;
if
(
bright
>=
ARRAY_SIZE
(
backlight_map
)
||
bright
<
0
)
return
-
EINVAL
;
/* Instance 0 is "set backlight" */
return
msi_wmi_set_block
(
0
,
backlight_map
[
bright
]);
}
static
struct
backlight_ops
msi_backlight_ops
=
{
.
get_brightness
=
bl_get
,
.
update_status
=
bl_set_status
,
};
static
void
msi_wmi_notify
(
u32
value
,
void
*
context
)
{
struct
acpi_buffer
response
=
{
ACPI_ALLOCATE_BUFFER
,
NULL
};
static
struct
key_entry
*
key
;
union
acpi_object
*
obj
;
ktime_t
cur
;
wmi_get_event_data
(
value
,
&
response
);
obj
=
(
union
acpi_object
*
)
response
.
pointer
;
if
(
obj
&&
obj
->
type
==
ACPI_TYPE_INTEGER
)
{
int
eventcode
=
obj
->
integer
.
value
;
dprintk
(
"Eventcode: 0x%x
\n
"
,
eventcode
);
key
=
sparse_keymap_entry_from_scancode
(
msi_wmi_input_dev
,
eventcode
);
if
(
key
)
{
ktime_t
diff
;
cur
=
ktime_get_real
();
diff
=
ktime_sub
(
cur
,
last_pressed
[
key
->
code
-
KEYCODE_BASE
]);
/* Ignore event if the same event happened in a 50 ms
timeframe -> Key press may result in 10-20 GPEs */
if
(
ktime_to_us
(
diff
)
<
1000
*
50
)
{
dprintk
(
"Suppressed key event 0x%X - "
"Last press was %lld us ago
\n
"
,
key
->
code
,
ktime_to_us
(
diff
));
return
;
}
last_pressed
[
key
->
code
-
KEYCODE_BASE
]
=
cur
;
if
(
key
->
type
==
KE_KEY
&&
/* Brightness is served via acpi video driver */
(
!
acpi_video_backlight_support
()
||
(
key
->
code
!=
MSI_WMI_BRIGHTNESSUP
&&
key
->
code
!=
MSI_WMI_BRIGHTNESSDOWN
)))
{
dprintk
(
"Send key: 0x%X - "
"Input layer keycode: %d
\n
"
,
key
->
code
,
key
->
keycode
);
sparse_keymap_report_entry
(
msi_wmi_input_dev
,
key
,
1
,
true
);
}
}
else
printk
(
KERN_INFO
"Unknown key pressed - %x
\n
"
,
eventcode
);
}
else
printk
(
KERN_INFO
DRV_PFX
"Unknown event received
\n
"
);
kfree
(
response
.
pointer
);
}
static
int
__init
msi_wmi_input_setup
(
void
)
{
int
err
;
msi_wmi_input_dev
=
input_allocate_device
();
if
(
!
msi_wmi_input_dev
)
return
-
ENOMEM
;
msi_wmi_input_dev
->
name
=
"MSI WMI hotkeys"
;
msi_wmi_input_dev
->
phys
=
"wmi/input0"
;
msi_wmi_input_dev
->
id
.
bustype
=
BUS_HOST
;
err
=
sparse_keymap_setup
(
msi_wmi_input_dev
,
msi_wmi_keymap
,
NULL
);
if
(
err
)
goto
err_free_dev
;
err
=
input_register_device
(
msi_wmi_input_dev
);
if
(
err
)
goto
err_free_keymap
;
memset
(
last_pressed
,
0
,
sizeof
(
last_pressed
));
return
0
;
err_free_keymap:
sparse_keymap_free
(
msi_wmi_input_dev
);
err_free_dev:
input_free_device
(
msi_wmi_input_dev
);
return
err
;
}
static
int
__init
msi_wmi_init
(
void
)
{
int
err
;
if
(
!
wmi_has_guid
(
MSIWMI_EVENT_GUID
))
{
printk
(
KERN_ERR
"This machine doesn't have MSI-hotkeys through WMI
\n
"
);
return
-
ENODEV
;
}
err
=
wmi_install_notify_handler
(
MSIWMI_EVENT_GUID
,
msi_wmi_notify
,
NULL
);
if
(
err
)
return
-
EINVAL
;
err
=
msi_wmi_input_setup
();
if
(
err
)
goto
err_uninstall_notifier
;
if
(
!
acpi_video_backlight_support
())
{
backlight
=
backlight_device_register
(
DRV_NAME
,
NULL
,
NULL
,
&
msi_backlight_ops
);
if
(
IS_ERR
(
backlight
))
goto
err_free_input
;
backlight
->
props
.
max_brightness
=
ARRAY_SIZE
(
backlight_map
)
-
1
;
err
=
bl_get
(
NULL
);
if
(
err
<
0
)
goto
err_free_backlight
;
backlight
->
props
.
brightness
=
err
;
}
dprintk
(
"Event handler installed
\n
"
);
return
0
;
err_free_backlight:
backlight_device_unregister
(
backlight
);
err_free_input:
input_unregister_device
(
msi_wmi_input_dev
);
err_uninstall_notifier:
wmi_remove_notify_handler
(
MSIWMI_EVENT_GUID
);
return
err
;
}
static
void
__exit
msi_wmi_exit
(
void
)
{
if
(
wmi_has_guid
(
MSIWMI_EVENT_GUID
))
{
wmi_remove_notify_handler
(
MSIWMI_EVENT_GUID
);
sparse_keymap_free
(
msi_wmi_input_dev
);
input_unregister_device
(
msi_wmi_input_dev
);
backlight_device_unregister
(
backlight
);
}
}
module_init
(
msi_wmi_init
);
module_exit
(
msi_wmi_exit
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment