Skip to content

Commit

Permalink
asus-wmi: try to guess the right DSTS methods
Browse files Browse the repository at this point in the history
This is tricky, new WMI aware notebooks seems to use
0x53545344 while Eee PCs are using 0x53544344. But there
is no way to know if there is an Eee PC in that wild that is
using 0x53545344 or a notebook using 0x53544344. So the
driver try to guess the available DSTS method ... But most Eee PCs
never return 0xFFFFFFFE when a method is not available, they return
0 instead (and that's useless).

So, first, try 0x53544344 then 0x53545344. We will find
a better way when we got more data.

Signed-off-by: Corentin Chary <corentincj@iksaif.net>
Signed-off-by: Matthew Garrett <mjg@redhat.com>
  • Loading branch information
Corentin Chary authored and Matthew Garrett committed Mar 28, 2011
1 parent d33da3b commit 1d070f8
Showing 1 changed file with 66 additions and 33 deletions.
99 changes: 66 additions & 33 deletions drivers/platform/x86/asus-wmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ MODULE_LICENSE("GPL");

/* WMI Methods */
#define ASUS_WMI_METHODID_DSTS 0x53544344
#define ASUS_WMI_METHODID_DSTS2 0x53545344
#define ASUS_WMI_METHODID_DEVS 0x53564544
#define ASUS_WMI_METHODID_CFVS 0x53564643

Expand Down Expand Up @@ -124,6 +125,8 @@ struct asus_rfkill {
};

struct asus_wmi {
int dsts_id;

struct input_dev *inputdev;
struct backlight_device *backlight_device;
struct platform_device *platform_device;
Expand Down Expand Up @@ -229,26 +232,26 @@ static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1,
return 0;
}

static int asus_wmi_get_devstate(u32 dev_id, u32 *retval)
static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
{
return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, dev_id,
0, retval);
return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval);
}

static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
u32 *retval)
u32 *retval)
{
return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
ctrl_param, retval);
}

/* Helper for special devices with magic return codes */
static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask)
static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
u32 dev_id, u32 mask)
{
u32 retval = 0;
int err;

err = asus_wmi_get_devstate(dev_id, &retval);
err = asus_wmi_get_devstate(asus, dev_id, &retval);

if (err < 0)
return err;
Expand All @@ -264,9 +267,10 @@ static int asus_wmi_get_devstate_bits(u32 dev_id, u32 mask)
return retval & mask;
}

static int asus_wmi_get_devstate_simple(u32 dev_id)
static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id)
{
return asus_wmi_get_devstate_bits(dev_id, ASUS_WMI_DSTS_STATUS_BIT);
return asus_wmi_get_devstate_bits(asus, dev_id,
ASUS_WMI_DSTS_STATUS_BIT);
}

/*
Expand Down Expand Up @@ -302,7 +306,7 @@ static void tpd_led_set(struct led_classdev *led_cdev,

static int read_tpd_led_state(struct asus_wmi *asus)
{
return asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_TOUCHPAD_LED);
return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED);
}

static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
Expand Down Expand Up @@ -353,7 +357,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus)
*/
static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus)
{
int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN);
int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);

if (result < 0)
return false;
Expand Down Expand Up @@ -482,7 +486,8 @@ static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node)
static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
u8 *value)
{
int result = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN);
struct asus_wmi *asus = hotplug_slot->private;
int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);

if (result < 0)
return result;
Expand Down Expand Up @@ -578,7 +583,7 @@ static void asus_rfkill_query(struct rfkill *rfkill, void *data)
struct asus_rfkill *priv = data;
int result;

result = asus_wmi_get_devstate_simple(priv->dev_id);
result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id);

if (result < 0)
return;
Expand Down Expand Up @@ -619,7 +624,7 @@ static int asus_new_rfkill(struct asus_wmi *asus,
struct asus_rfkill *arfkill,
const char *name, enum rfkill_type type, int dev_id)
{
int result = asus_wmi_get_devstate_simple(dev_id);
int result = asus_wmi_get_devstate_simple(asus, dev_id);
struct rfkill **rfkill = &arfkill->rfkill;

if (result < 0)
Expand Down Expand Up @@ -750,9 +755,9 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
/*
* Backlight
*/
static int read_backlight_power(void)
static int read_backlight_power(struct asus_wmi *asus)
{
int ret = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BACKLIGHT);
int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT);

if (ret < 0)
return ret;
Expand All @@ -762,10 +767,11 @@ static int read_backlight_power(void)

static int read_brightness(struct backlight_device *bd)
{
struct asus_wmi *asus = bl_get_data(bd);
u32 retval;
int err;

err = asus_wmi_get_devstate(ASUS_WMI_DEVID_BRIGHTNESS, &retval);
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);

if (err < 0)
return err;
Expand All @@ -775,6 +781,7 @@ static int read_brightness(struct backlight_device *bd)

static int update_bl_status(struct backlight_device *bd)
{
struct asus_wmi *asus = bl_get_data(bd);
u32 ctrl_param;
int power, err;

Expand All @@ -786,7 +793,7 @@ static int update_bl_status(struct backlight_device *bd)
if (err < 0)
return err;

power = read_backlight_power();
power = read_backlight_power(asus);
if (power != -ENODEV && bd->props.power != power) {
ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
Expand Down Expand Up @@ -825,9 +832,9 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
int max;
int power;

max = asus_wmi_get_devstate_bits(ASUS_WMI_DEVID_BRIGHTNESS,
max = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_BRIGHTNESS,
ASUS_WMI_DSTS_MAX_BRIGTH_MASK);
power = read_backlight_power();
power = read_backlight_power(asus);

if (max < 0 && power < 0) {
/* Try to keep the original error */
Expand Down Expand Up @@ -921,12 +928,13 @@ static int parse_arg(const char *buf, unsigned long count, int *val)
return count;
}

static ssize_t store_sys_wmi(int devid, const char *buf, size_t count)
static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid,
const char *buf, size_t count)
{
u32 retval;
int rv, err, value;

value = asus_wmi_get_devstate_simple(devid);
value = asus_wmi_get_devstate_simple(asus, devid);
if (value == -ENODEV) /* Check device presence */
return value;

Expand All @@ -939,9 +947,9 @@ static ssize_t store_sys_wmi(int devid, const char *buf, size_t count)
return rv;
}

static ssize_t show_sys_wmi(int devid, char *buf)
static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf)
{
int value = asus_wmi_get_devstate_simple(devid);
int value = asus_wmi_get_devstate_simple(asus, devid);

if (value < 0)
return value;
Expand All @@ -954,13 +962,17 @@ static ssize_t show_sys_wmi(int devid, char *buf)
struct device_attribute *attr, \
char *buf) \
{ \
return show_sys_wmi(_cm, buf); \
struct asus_wmi *asus = dev_get_drvdata(dev); \
\
return show_sys_wmi(asus, _cm, buf); \
} \
static ssize_t store_##_name(struct device *dev, \
struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
return store_sys_wmi(_cm, buf, count); \
struct asus_wmi *asus = dev_get_drvdata(dev); \
\
return store_sys_wmi(asus, _cm, buf, count); \
} \
static struct device_attribute dev_attr_##_name = { \
.attr = { \
Expand Down Expand Up @@ -1000,7 +1012,10 @@ static struct attribute *platform_attributes[] = {
static mode_t asus_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
{
bool supported = true;
struct device *dev = container_of(kobj, struct device, kobj);
struct platform_device *pdev = to_platform_device(dev);
struct asus_wmi *asus = platform_get_drvdata(pdev);
bool ok = true;
int devid = -1;

if (attr == &dev_attr_camera.attr)
Expand All @@ -1011,9 +1026,9 @@ static mode_t asus_sysfs_is_visible(struct kobject *kobj,
devid = ASUS_WMI_DEVID_TOUCHPAD;

if (devid != -1)
supported = asus_wmi_get_devstate_simple(devid) != -ENODEV;
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);

return supported ? attr->mode : 0;
return ok ? attr->mode : 0;
}

static struct attribute_group platform_attribute_group = {
Expand All @@ -1036,6 +1051,23 @@ static int asus_wmi_sysfs_init(struct platform_device *device)
*/
static int __init asus_wmi_platform_init(struct asus_wmi *asus)
{
/*
* Eee PC and Notebooks seems to have different method_id for DSTS,
* but it may also be related to the BIOS's SPEC.
* Note, on most Eeepc, there is no way to check if a method exist
* or note, while on notebooks, they returns 0xFFFFFFFE on failure,
* but once again, SPEC may probably be used for that kind of things.
*/
if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL))
asus->dsts_id = ASUS_WMI_METHODID_DSTS;
else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL))
asus->dsts_id = ASUS_WMI_METHODID_DSTS2;

if (!asus->dsts_id) {
pr_err("Can't find DSTS");
return -ENODEV;
}

return asus_wmi_sysfs_init(asus->platform_device);
}

Expand All @@ -1059,7 +1091,7 @@ static int show_dsts(struct seq_file *m, void *data)
int err;
u32 retval = -1;

err = asus_wmi_get_devstate(asus->debug.dev_id, &retval);
err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);

if (err < 0)
return err;
Expand Down Expand Up @@ -1262,7 +1294,7 @@ static int asus_hotk_thaw(struct device *device)
* during suspend. Normally it restores it on resume, but
* we should kick it ourselves in case hibernation is aborted.
*/
wlan = asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WLAN);
wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL);
}

Expand All @@ -1279,15 +1311,16 @@ static int asus_hotk_restore(struct device *device)
asus_rfkill_hotplug(asus);

if (asus->bluetooth.rfkill) {
bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_BLUETOOTH);
bl = !asus_wmi_get_devstate_simple(asus,
ASUS_WMI_DEVID_BLUETOOTH);
rfkill_set_sw_state(asus->bluetooth.rfkill, bl);
}
if (asus->wimax.rfkill) {
bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WIMAX);
bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX);
rfkill_set_sw_state(asus->wimax.rfkill, bl);
}
if (asus->wwan3g.rfkill) {
bl = !asus_wmi_get_devstate_simple(ASUS_WMI_DEVID_WWAN3G);
bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);
rfkill_set_sw_state(asus->wwan3g.rfkill, bl);
}

Expand Down

0 comments on commit 1d070f8

Please sign in to comment.