2010-08-18 08:36:15

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

These patches are made against 2.6.36-rc1 and also available at
git://kernel.ubuntu.com/ikepanhc/ideapad-laptop.git for-upstream

Once the rfkill of a laptop is set to block, it is no way to unblock with Linux
without driver. Thanks for David Woodhouse wrote the first driver solving this.

But the \_SB_.GECN and \_SB_.DECN are only available on Lenovo ideapad S10-3.
Using EC command to control rf/camera power is better because I believe every
ideapads which has VPC2004 device in its DSDT has this common method.

This driver is tested and work fine on Lenovo ideapad B550 and ideapad S10-3.

Ike Panhc (8):
ideapad: add ACPI helpers
ideapad: check VPC bit before sync rfkill hw status
ideapad: make sure we bind on the correct device
ideapad: use return value of _CFG to tell if device exist or not
ideapad: use EC command to control camera
ideapad: rewrite the hw rfkill notify
ideapad: rewrite the sw rfkill set
ideapad: Change the driver name to ideapad_laptop

drivers/platform/x86/Kconfig | 4 +-
drivers/platform/x86/Makefile | 2 +-
drivers/platform/x86/ideapad_acpi.c | 306 --------------------------
drivers/platform/x86/ideapad_laptop.c | 381 +++++++++++++++++++++++++++++++++
4 files changed, 384 insertions(+), 309 deletions(-)
delete mode 100644 drivers/platform/x86/ideapad_acpi.c
create mode 100644 drivers/platform/x86/ideapad_laptop.c


2010-08-18 08:37:04

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 1/8] ideapad: add ACPI helpers

There are two methods under VPC2004 which is used to access VDAT/VCMD of EC
register. Add helpers for read and write these two registers.

And add read_method_int for reading the return value from ACPI methods which
requires no parameter.

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 111 +++++++++++++++++++++++++++++++++++
1 files changed, 111 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index 7984963..af630e2 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -49,6 +49,117 @@ static struct {
{ "ideapad_killsw", RFKILL_TYPE_WLAN }
};

+/*
+ * ACPI Helpers
+ */
+#define IDEAPAD_EC_TIMEOUT (25) /* in ms */
+
+static int read_method_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ unsigned long long result;
+
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
+ if (ACPI_FAILURE(status)) {
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
+ }
+}
+
+static int method_vpcr(acpi_handle handle, int cmd, int *ret)
+{
+ acpi_status status;
+ unsigned long long result;
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = cmd;
+
+ status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
+
+ if (ACPI_FAILURE(status)) {
+ *ret = -1;
+ return -1;
+ } else {
+ *ret = result;
+ return 0;
+ }
+}
+
+static int method_vpcw(acpi_handle handle, int cmd, int data)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj[2];
+ acpi_status status;
+
+ params.count = 2;
+ params.pointer = in_obj;
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = cmd;
+ in_obj[1].type = ACPI_TYPE_INTEGER;
+ in_obj[1].integer.value = data;
+
+ status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
+ if (status != AE_OK)
+ return -1;
+ return 0;
+}
+
+static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
+{
+ int val;
+ unsigned long int start_jiffies, now_jiffies;
+
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (start_jiffies = jiffies;; ) {
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0) {
+ if (method_vpcr(handle, 0, &val))
+ return -1;
+ *data = val;
+ return 0;
+ }
+ now_jiffies = jiffies;
+ if ((now_jiffies-start_jiffies) > (HZ)/IDEAPAD_EC_TIMEOUT+1) {
+ pr_err("timeout in read_ec_cmd\n");
+ return -1;
+ }
+ }
+}
+
+static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
+{
+ int val;
+ unsigned long int start_jiffies, now_jiffies;
+
+ if (method_vpcw(handle, 0, data))
+ return -1;
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (start_jiffies = jiffies;; ) {
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0)
+ return 0;
+ now_jiffies = jiffies;
+ if ((now_jiffies-start_jiffies) > (HZ)/IDEAPAD_EC_TIMEOUT+1) {
+ pr_err("timeout in write_ec_cmd\n");
+ return -1;
+ }
+ }
+}
+/* the above is ACPI helpers */
+
static int ideapad_dev_exists(int device)
{
acpi_status status;
--
1.7.0.4

2010-08-18 08:37:32

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 2/8] ideapad: check VPC bit before sync rfkill hw status

Check VPC bit to make sure the HW rfkill is touched.

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index af630e2..6176597 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -381,7 +381,21 @@ static int ideapad_acpi_remove(struct acpi_device *adevice, int type)

static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
{
- ideapad_sync_rfk_state(adevice);
+ acpi_handle handle = adevice->handle;
+ unsigned long vpc1, vpc2, vpc_bit;
+
+ if (read_ec_data(handle, 0x10, &vpc1))
+ return;
+ if (read_ec_data(handle, 0x1A, &vpc2))
+ return;
+
+ vpc1 = (vpc2 << 8) | vpc1;
+ for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
+ if (test_bit(vpc_bit, &vpc1)) {
+ if (vpc_bit == 9)
+ ideapad_sync_rfk_state(adevice);
+ }
+ }
}

static struct acpi_driver ideapad_acpi_driver = {
--
1.7.0.4

2010-08-18 08:37:41

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 3/8] ideapad: make sure we bind on the correct device

By reading from method _STA and _CFG to make sure we bind on the correct
VPC2004 device.

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index 6176597..c1eec70 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -328,10 +328,18 @@ MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);

static int ideapad_acpi_add(struct acpi_device *adevice)
{
- int i;
+ int i, cfg;
int devs_present[5];
struct ideapad_private *priv;

+ if (read_method_int(adevice->handle, "_STA", &i))
+ return -ENODEV;
+ if (i != 0x0F)
+ return -ENODEV;
+
+ if (read_method_int(adevice->handle, "_CFG", &cfg))
+ return -ENODEV;
+
for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
devs_present[i] = ideapad_dev_exists(i);
if (devs_present[i] < 0)
--
1.7.0.4

2010-08-18 08:38:12

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 4/8] ideapad: use return value of _CFG to tell if device exist or not

There are several bits of the return value of _CFG shows if RF/Camera devices
exist or not.

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 44 ++++++++---------------------------
1 files changed, 10 insertions(+), 34 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index c1eec70..673b44d 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -40,13 +40,14 @@ struct ideapad_private {

static struct {
char *name;
+ int cfgbit;
int type;
} ideapad_rfk_data[] = {
- /* camera has no rfkill */
- { "ideapad_wlan", RFKILL_TYPE_WLAN },
- { "ideapad_bluetooth", RFKILL_TYPE_BLUETOOTH },
- { "ideapad_3g", RFKILL_TYPE_WWAN },
- { "ideapad_killsw", RFKILL_TYPE_WLAN }
+ { "ideapad_camera", 19, NUM_RFKILL_TYPES },
+ { "ideapad_wlan", 18, RFKILL_TYPE_WLAN },
+ { "ideapad_bluetooth", 16, RFKILL_TYPE_BLUETOOTH },
+ { "ideapad_3g", 17, RFKILL_TYPE_WWAN },
+ { "ideapad_killsw", 0, RFKILL_TYPE_WLAN }
};

/*
@@ -160,32 +161,6 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
}
/* the above is ACPI helpers */

-static int ideapad_dev_exists(int device)
-{
- acpi_status status;
- union acpi_object in_param;
- struct acpi_object_list input = { 1, &in_param };
- struct acpi_buffer output;
- union acpi_object out_obj;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- in_param.type = ACPI_TYPE_INTEGER;
- in_param.integer.value = device + 1;
-
- status = acpi_evaluate_object(NULL, "\\_SB_.DECN", &input, &output);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method failed %d. Is this an IdeaPAD?\n", status);
- return -ENODEV;
- }
- if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.DECN method returned unexpected type\n");
- return -ENODEV;
- }
- return out_obj.integer.value;
-}
-
static int ideapad_dev_get_state(int device)
{
acpi_status status;
@@ -341,9 +316,10 @@ static int ideapad_acpi_add(struct acpi_device *adevice)
return -ENODEV;

for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
- devs_present[i] = ideapad_dev_exists(i);
- if (devs_present[i] < 0)
- return devs_present[i];
+ if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+ devs_present[i] = 1;
+ else
+ devs_present[i] = 0;
}

/* The hardware switch is always present */
--
1.7.0.4

2010-08-18 08:38:23

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 5/8] ideapad: use EC command to control camera

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 16 +++++++++++-----
1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index 673b44d..a1fdb45 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -35,6 +35,7 @@
#define IDEAPAD_DEV_KILLSW 4

struct ideapad_private {
+ acpi_handle handle;
struct rfkill *rfk[5];
};

@@ -209,24 +210,28 @@ static ssize_t show_ideapad_cam(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int state = ideapad_dev_get_state(IDEAPAD_DEV_CAMERA);
- if (state < 0)
- return state;
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
+ unsigned long result;

- return sprintf(buf, "%d\n", state);
+ if (read_ec_data(handle, 0x1D, &result))
+ return sprintf(buf, "-1\n");
+ return sprintf(buf, "%lu\n", result);
}

static ssize_t store_ideapad_cam(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
int ret, state;

if (!count)
return 0;
if (sscanf(buf, "%i", &state) != 1)
return -EINVAL;
- ret = ideapad_dev_set_state(IDEAPAD_DEV_CAMERA, !!state);
+ ret = write_ec_cmd(handle, 0x1E, state);
if (ret < 0)
return ret;
return count;
@@ -337,6 +342,7 @@ static int ideapad_acpi_add(struct acpi_device *adevice)
}
}

+ priv->handle = adevice->handle;
dev_set_drvdata(&adevice->dev, priv);
for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
if (!devs_present[i])
--
1.7.0.4

2010-08-18 08:38:36

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 6/8] ideapad: rewrite the hw rfkill notify

1. Read hw rfkill status by ec command
2. Not to touch sw status of each rfkill when hw rfkill notify
3. Enable RF when module initial

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 45 +++++++----------------------------
1 files changed, 9 insertions(+), 36 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index a1fdb45..9d0e23f 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -162,32 +162,6 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
}
/* the above is ACPI helpers */

-static int ideapad_dev_get_state(int device)
-{
- acpi_status status;
- union acpi_object in_param;
- struct acpi_object_list input = { 1, &in_param };
- struct acpi_buffer output;
- union acpi_object out_obj;
-
- output.length = sizeof(out_obj);
- output.pointer = &out_obj;
-
- in_param.type = ACPI_TYPE_INTEGER;
- in_param.integer.value = device + 1;
-
- status = acpi_evaluate_object(NULL, "\\_SB_.GECN", &input, &output);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method failed %d\n", status);
- return -ENODEV;
- }
- if (out_obj.type != ACPI_TYPE_INTEGER) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.GECN method returned unexpected type\n");
- return -ENODEV;
- }
- return out_obj.integer.value;
-}
-
static int ideapad_dev_set_state(int device, int state)
{
acpi_status status;
@@ -255,19 +229,17 @@ static struct rfkill_ops ideapad_rfk_ops = {
static void ideapad_sync_rfk_state(struct acpi_device *adevice)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- int hw_blocked = !ideapad_dev_get_state(IDEAPAD_DEV_KILLSW);
+ acpi_handle handle = priv->handle;
+ unsigned long hw_blocked;
int i;

- rfkill_set_hw_state(priv->rfk[IDEAPAD_DEV_KILLSW], hw_blocked);
- for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
- if (priv->rfk[i])
- rfkill_set_hw_state(priv->rfk[i], hw_blocked);
- if (hw_blocked)
+ if (read_ec_data(handle, 0x23, &hw_blocked))
return;
+ hw_blocked = !hw_blocked;

- for (i = IDEAPAD_DEV_WLAN; i < IDEAPAD_DEV_KILLSW; i++)
+ for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
if (priv->rfk[i])
- rfkill_set_sw_state(priv->rfk[i], !ideapad_dev_get_state(i));
+ rfkill_set_hw_state(priv->rfk[i], hw_blocked);
}

static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
@@ -275,12 +247,13 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int ret;

- priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev-1].name, &adevice->dev,
- ideapad_rfk_data[dev-1].type, &ideapad_rfk_ops,
+ priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
+ ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
(void *)(long)dev);
if (!priv->rfk[dev])
return -ENOMEM;

+ rfkill_init_sw_state(priv->rfk[dev], 0);
ret = rfkill_register(priv->rfk[dev]);
if (ret) {
rfkill_destroy(priv->rfk[dev]);
--
1.7.0.4

2010-08-18 08:38:52

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 7/8] ideapad: rewrite the sw rfkill set

Control power of rf modules by ec commands

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/ideapad_acpi.c | 37 +++++++++++-----------------------
1 files changed, 12 insertions(+), 25 deletions(-)

diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index 9d0e23f..7c414e5 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -37,18 +37,19 @@
struct ideapad_private {
acpi_handle handle;
struct rfkill *rfk[5];
-};
+} *ideapad_priv;

static struct {
char *name;
int cfgbit;
+ int opcode;
int type;
} ideapad_rfk_data[] = {
- { "ideapad_camera", 19, NUM_RFKILL_TYPES },
- { "ideapad_wlan", 18, RFKILL_TYPE_WLAN },
- { "ideapad_bluetooth", 16, RFKILL_TYPE_BLUETOOTH },
- { "ideapad_3g", 17, RFKILL_TYPE_WWAN },
- { "ideapad_killsw", 0, RFKILL_TYPE_WLAN }
+ { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
+ { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
+ { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
+ { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
+ { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
};

/*
@@ -162,24 +163,6 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
}
/* the above is ACPI helpers */

-static int ideapad_dev_set_state(int device, int state)
-{
- acpi_status status;
- union acpi_object in_params[2];
- struct acpi_object_list input = { 2, in_params };
-
- in_params[0].type = ACPI_TYPE_INTEGER;
- in_params[0].integer.value = device + 1;
- in_params[1].type = ACPI_TYPE_INTEGER;
- in_params[1].integer.value = state;
-
- status = acpi_evaluate_object(NULL, "\\_SB_.SECN", &input, NULL);
- if (ACPI_FAILURE(status)) {
- printk(KERN_WARNING "IdeaPAD \\_SB_.SECN method failed %d\n", status);
- return -ENODEV;
- }
- return 0;
-}
static ssize_t show_ideapad_cam(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -219,7 +202,10 @@ static int ideapad_rfk_set(void *data, bool blocked)

if (device == IDEAPAD_DEV_KILLSW)
return -EINVAL;
- return ideapad_dev_set_state(device, !blocked);
+
+ return write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[device].opcode,
+ !blocked);
}

static struct rfkill_ops ideapad_rfk_ops = {
@@ -317,6 +303,7 @@ static int ideapad_acpi_add(struct acpi_device *adevice)

priv->handle = adevice->handle;
dev_set_drvdata(&adevice->dev, priv);
+ ideapad_priv = priv;
for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
if (!devs_present[i])
continue;
--
1.7.0.4

2010-08-18 08:39:06

by Ike Panhc

[permalink] [raw]
Subject: [PATCH 8/8] ideapad: Change the driver name to ideapad_laptop

Since the platform drivers doing more for laptops than just using specific
ACPI device. It will be good to change the name from *_acpi to *_laptop.

Reference: http://lkml.org/lkml/2010/8/14/154

Signed-off-by: Ike Panhc <[email protected]>
---
drivers/platform/x86/Kconfig | 4 +-
drivers/platform/x86/Makefile | 2 +-
drivers/platform/x86/ideapad_acpi.c | 381 ---------------------------------
drivers/platform/x86/ideapad_laptop.c | 381 +++++++++++++++++++++++++++++++++
4 files changed, 384 insertions(+), 384 deletions(-)
delete mode 100644 drivers/platform/x86/ideapad_acpi.c
create mode 100644 drivers/platform/x86/ideapad_laptop.c

diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 044f430..635d198 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -219,8 +219,8 @@ config SONYPI_COMPAT
---help---
Build the sonypi driver compatibility code into the sony-laptop driver.

-config IDEAPAD_ACPI
- tristate "Lenovo IdeaPad ACPI Laptop Extras"
+config IDEAPAD_LAPTOP
+ tristate "Lenovo IdeaPad Laptop Extras"
depends on ACPI
depends on RFKILL
help
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 85fb2b8..9846fa2 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -15,7 +15,7 @@ obj-$(CONFIG_ACERHDF) += acerhdf.o
obj-$(CONFIG_HP_WMI) += hp-wmi.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
-obj-$(CONFIG_IDEAPAD_ACPI) += ideapad_acpi.o
+obj-$(CONFIG_IDEAPAD_LAPTOP) += ideapad_laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
deleted file mode 100644
index 7c414e5..0000000
--- a/drivers/platform/x86/ideapad_acpi.c
+++ /dev/null
@@ -1,381 +0,0 @@
-/*
- * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
- *
- * Copyright © 2010 Intel Corporation
- * Copyright © 2010 David Woodhouse <[email protected]>
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-#include <linux/rfkill.h>
-
-#define IDEAPAD_DEV_CAMERA 0
-#define IDEAPAD_DEV_WLAN 1
-#define IDEAPAD_DEV_BLUETOOTH 2
-#define IDEAPAD_DEV_3G 3
-#define IDEAPAD_DEV_KILLSW 4
-
-struct ideapad_private {
- acpi_handle handle;
- struct rfkill *rfk[5];
-} *ideapad_priv;
-
-static struct {
- char *name;
- int cfgbit;
- int opcode;
- int type;
-} ideapad_rfk_data[] = {
- { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
- { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
- { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
- { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
- { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
-};
-
-/*
- * ACPI Helpers
- */
-#define IDEAPAD_EC_TIMEOUT (25) /* in ms */
-
-static int read_method_int(acpi_handle handle, const char *method, int *val)
-{
- acpi_status status;
- unsigned long long result;
-
- status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
- if (ACPI_FAILURE(status)) {
- *val = -1;
- return -1;
- } else {
- *val = result;
- return 0;
- }
-}
-
-static int method_vpcr(acpi_handle handle, int cmd, int *ret)
-{
- acpi_status status;
- unsigned long long result;
- struct acpi_object_list params;
- union acpi_object in_obj;
-
- params.count = 1;
- params.pointer = &in_obj;
- in_obj.type = ACPI_TYPE_INTEGER;
- in_obj.integer.value = cmd;
-
- status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
-
- if (ACPI_FAILURE(status)) {
- *ret = -1;
- return -1;
- } else {
- *ret = result;
- return 0;
- }
-}
-
-static int method_vpcw(acpi_handle handle, int cmd, int data)
-{
- struct acpi_object_list params;
- union acpi_object in_obj[2];
- acpi_status status;
-
- params.count = 2;
- params.pointer = in_obj;
- in_obj[0].type = ACPI_TYPE_INTEGER;
- in_obj[0].integer.value = cmd;
- in_obj[1].type = ACPI_TYPE_INTEGER;
- in_obj[1].integer.value = data;
-
- status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
- if (status != AE_OK)
- return -1;
- return 0;
-}
-
-static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
-{
- int val;
- unsigned long int start_jiffies, now_jiffies;
-
- if (method_vpcw(handle, 1, cmd))
- return -1;
-
- for (start_jiffies = jiffies;; ) {
- if (method_vpcr(handle, 1, &val))
- return -1;
- if (val == 0) {
- if (method_vpcr(handle, 0, &val))
- return -1;
- *data = val;
- return 0;
- }
- now_jiffies = jiffies;
- if ((now_jiffies-start_jiffies) > (HZ)/IDEAPAD_EC_TIMEOUT+1) {
- pr_err("timeout in read_ec_cmd\n");
- return -1;
- }
- }
-}
-
-static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
-{
- int val;
- unsigned long int start_jiffies, now_jiffies;
-
- if (method_vpcw(handle, 0, data))
- return -1;
- if (method_vpcw(handle, 1, cmd))
- return -1;
-
- for (start_jiffies = jiffies;; ) {
- if (method_vpcr(handle, 1, &val))
- return -1;
- if (val == 0)
- return 0;
- now_jiffies = jiffies;
- if ((now_jiffies-start_jiffies) > (HZ)/IDEAPAD_EC_TIMEOUT+1) {
- pr_err("timeout in write_ec_cmd\n");
- return -1;
- }
- }
-}
-/* the above is ACPI helpers */
-
-static ssize_t show_ideapad_cam(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct ideapad_private *priv = dev_get_drvdata(dev);
- acpi_handle handle = priv->handle;
- unsigned long result;
-
- if (read_ec_data(handle, 0x1D, &result))
- return sprintf(buf, "-1\n");
- return sprintf(buf, "%lu\n", result);
-}
-
-static ssize_t store_ideapad_cam(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct ideapad_private *priv = dev_get_drvdata(dev);
- acpi_handle handle = priv->handle;
- int ret, state;
-
- if (!count)
- return 0;
- if (sscanf(buf, "%i", &state) != 1)
- return -EINVAL;
- ret = write_ec_cmd(handle, 0x1E, state);
- if (ret < 0)
- return ret;
- return count;
-}
-
-static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
-
-static int ideapad_rfk_set(void *data, bool blocked)
-{
- int device = (unsigned long)data;
-
- if (device == IDEAPAD_DEV_KILLSW)
- return -EINVAL;
-
- return write_ec_cmd(ideapad_priv->handle,
- ideapad_rfk_data[device].opcode,
- !blocked);
-}
-
-static struct rfkill_ops ideapad_rfk_ops = {
- .set_block = ideapad_rfk_set,
-};
-
-static void ideapad_sync_rfk_state(struct acpi_device *adevice)
-{
- struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- acpi_handle handle = priv->handle;
- unsigned long hw_blocked;
- int i;
-
- if (read_ec_data(handle, 0x23, &hw_blocked))
- return;
- hw_blocked = !hw_blocked;
-
- for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
- if (priv->rfk[i])
- rfkill_set_hw_state(priv->rfk[i], hw_blocked);
-}
-
-static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
-{
- struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- int ret;
-
- priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
- ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
- (void *)(long)dev);
- if (!priv->rfk[dev])
- return -ENOMEM;
-
- rfkill_init_sw_state(priv->rfk[dev], 0);
- ret = rfkill_register(priv->rfk[dev]);
- if (ret) {
- rfkill_destroy(priv->rfk[dev]);
- return ret;
- }
- return 0;
-}
-
-static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
-{
- struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
-
- if (!priv->rfk[dev])
- return;
-
- rfkill_unregister(priv->rfk[dev]);
- rfkill_destroy(priv->rfk[dev]);
-}
-
-static const struct acpi_device_id ideapad_device_ids[] = {
- { "VPC2004", 0},
- { "", 0},
-};
-MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
-
-static int ideapad_acpi_add(struct acpi_device *adevice)
-{
- int i, cfg;
- int devs_present[5];
- struct ideapad_private *priv;
-
- if (read_method_int(adevice->handle, "_STA", &i))
- return -ENODEV;
- if (i != 0x0F)
- return -ENODEV;
-
- if (read_method_int(adevice->handle, "_CFG", &cfg))
- return -ENODEV;
-
- for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
- if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
- devs_present[i] = 1;
- else
- devs_present[i] = 0;
- }
-
- /* The hardware switch is always present */
- devs_present[IDEAPAD_DEV_KILLSW] = 1;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- if (devs_present[IDEAPAD_DEV_CAMERA]) {
- int ret = device_create_file(&adevice->dev, &dev_attr_camera_power);
- if (ret) {
- kfree(priv);
- return ret;
- }
- }
-
- priv->handle = adevice->handle;
- dev_set_drvdata(&adevice->dev, priv);
- ideapad_priv = priv;
- for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
- if (!devs_present[i])
- continue;
-
- ideapad_register_rfkill(adevice, i);
- }
- ideapad_sync_rfk_state(adevice);
- return 0;
-}
-
-static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
-{
- struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
- int i;
-
- device_remove_file(&adevice->dev, &dev_attr_camera_power);
-
- for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
- ideapad_unregister_rfkill(adevice, i);
-
- dev_set_drvdata(&adevice->dev, NULL);
- kfree(priv);
- return 0;
-}
-
-static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
-{
- acpi_handle handle = adevice->handle;
- unsigned long vpc1, vpc2, vpc_bit;
-
- if (read_ec_data(handle, 0x10, &vpc1))
- return;
- if (read_ec_data(handle, 0x1A, &vpc2))
- return;
-
- vpc1 = (vpc2 << 8) | vpc1;
- for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
- if (test_bit(vpc_bit, &vpc1)) {
- if (vpc_bit == 9)
- ideapad_sync_rfk_state(adevice);
- }
- }
-}
-
-static struct acpi_driver ideapad_acpi_driver = {
- .name = "ideapad_acpi",
- .class = "IdeaPad",
- .ids = ideapad_device_ids,
- .ops.add = ideapad_acpi_add,
- .ops.remove = ideapad_acpi_remove,
- .ops.notify = ideapad_acpi_notify,
- .owner = THIS_MODULE,
-};
-
-
-static int __init ideapad_acpi_module_init(void)
-{
- acpi_bus_register_driver(&ideapad_acpi_driver);
-
- return 0;
-}
-
-
-static void __exit ideapad_acpi_module_exit(void)
-{
- acpi_bus_unregister_driver(&ideapad_acpi_driver);
-
-}
-
-MODULE_AUTHOR("David Woodhouse <[email protected]>");
-MODULE_DESCRIPTION("IdeaPad ACPI Extras");
-MODULE_LICENSE("GPL");
-
-module_init(ideapad_acpi_module_init);
-module_exit(ideapad_acpi_module_exit);
diff --git a/drivers/platform/x86/ideapad_laptop.c b/drivers/platform/x86/ideapad_laptop.c
new file mode 100644
index 0000000..7c414e5
--- /dev/null
+++ b/drivers/platform/x86/ideapad_laptop.c
@@ -0,0 +1,381 @@
+/*
+ * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
+ *
+ * Copyright © 2010 Intel Corporation
+ * Copyright © 2010 David Woodhouse <[email protected]>
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/rfkill.h>
+
+#define IDEAPAD_DEV_CAMERA 0
+#define IDEAPAD_DEV_WLAN 1
+#define IDEAPAD_DEV_BLUETOOTH 2
+#define IDEAPAD_DEV_3G 3
+#define IDEAPAD_DEV_KILLSW 4
+
+struct ideapad_private {
+ acpi_handle handle;
+ struct rfkill *rfk[5];
+} *ideapad_priv;
+
+static struct {
+ char *name;
+ int cfgbit;
+ int opcode;
+ int type;
+} ideapad_rfk_data[] = {
+ { "ideapad_camera", 19, 0x1E, NUM_RFKILL_TYPES },
+ { "ideapad_wlan", 18, 0x15, RFKILL_TYPE_WLAN },
+ { "ideapad_bluetooth", 16, 0x17, RFKILL_TYPE_BLUETOOTH },
+ { "ideapad_3g", 17, 0x20, RFKILL_TYPE_WWAN },
+ { "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
+};
+
+/*
+ * ACPI Helpers
+ */
+#define IDEAPAD_EC_TIMEOUT (25) /* in ms */
+
+static int read_method_int(acpi_handle handle, const char *method, int *val)
+{
+ acpi_status status;
+ unsigned long long result;
+
+ status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
+ if (ACPI_FAILURE(status)) {
+ *val = -1;
+ return -1;
+ } else {
+ *val = result;
+ return 0;
+ }
+}
+
+static int method_vpcr(acpi_handle handle, int cmd, int *ret)
+{
+ acpi_status status;
+ unsigned long long result;
+ struct acpi_object_list params;
+ union acpi_object in_obj;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = cmd;
+
+ status = acpi_evaluate_integer(handle, "VPCR", &params, &result);
+
+ if (ACPI_FAILURE(status)) {
+ *ret = -1;
+ return -1;
+ } else {
+ *ret = result;
+ return 0;
+ }
+}
+
+static int method_vpcw(acpi_handle handle, int cmd, int data)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj[2];
+ acpi_status status;
+
+ params.count = 2;
+ params.pointer = in_obj;
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = cmd;
+ in_obj[1].type = ACPI_TYPE_INTEGER;
+ in_obj[1].integer.value = data;
+
+ status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
+ if (status != AE_OK)
+ return -1;
+ return 0;
+}
+
+static int read_ec_data(acpi_handle handle, int cmd, unsigned long *data)
+{
+ int val;
+ unsigned long int start_jiffies, now_jiffies;
+
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (start_jiffies = jiffies;; ) {
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0) {
+ if (method_vpcr(handle, 0, &val))
+ return -1;
+ *data = val;
+ return 0;
+ }
+ now_jiffies = jiffies;
+ if ((now_jiffies-start_jiffies) > (HZ)/IDEAPAD_EC_TIMEOUT+1) {
+ pr_err("timeout in read_ec_cmd\n");
+ return -1;
+ }
+ }
+}
+
+static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
+{
+ int val;
+ unsigned long int start_jiffies, now_jiffies;
+
+ if (method_vpcw(handle, 0, data))
+ return -1;
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (start_jiffies = jiffies;; ) {
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0)
+ return 0;
+ now_jiffies = jiffies;
+ if ((now_jiffies-start_jiffies) > (HZ)/IDEAPAD_EC_TIMEOUT+1) {
+ pr_err("timeout in write_ec_cmd\n");
+ return -1;
+ }
+ }
+}
+/* the above is ACPI helpers */
+
+static ssize_t show_ideapad_cam(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
+ unsigned long result;
+
+ if (read_ec_data(handle, 0x1D, &result))
+ return sprintf(buf, "-1\n");
+ return sprintf(buf, "%lu\n", result);
+}
+
+static ssize_t store_ideapad_cam(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ideapad_private *priv = dev_get_drvdata(dev);
+ acpi_handle handle = priv->handle;
+ int ret, state;
+
+ if (!count)
+ return 0;
+ if (sscanf(buf, "%i", &state) != 1)
+ return -EINVAL;
+ ret = write_ec_cmd(handle, 0x1E, state);
+ if (ret < 0)
+ return ret;
+ return count;
+}
+
+static DEVICE_ATTR(camera_power, 0644, show_ideapad_cam, store_ideapad_cam);
+
+static int ideapad_rfk_set(void *data, bool blocked)
+{
+ int device = (unsigned long)data;
+
+ if (device == IDEAPAD_DEV_KILLSW)
+ return -EINVAL;
+
+ return write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[device].opcode,
+ !blocked);
+}
+
+static struct rfkill_ops ideapad_rfk_ops = {
+ .set_block = ideapad_rfk_set,
+};
+
+static void ideapad_sync_rfk_state(struct acpi_device *adevice)
+{
+ struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+ acpi_handle handle = priv->handle;
+ unsigned long hw_blocked;
+ int i;
+
+ if (read_ec_data(handle, 0x23, &hw_blocked))
+ return;
+ hw_blocked = !hw_blocked;
+
+ for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
+ if (priv->rfk[i])
+ rfkill_set_hw_state(priv->rfk[i], hw_blocked);
+}
+
+static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
+{
+ struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+ int ret;
+
+ priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
+ ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
+ (void *)(long)dev);
+ if (!priv->rfk[dev])
+ return -ENOMEM;
+
+ rfkill_init_sw_state(priv->rfk[dev], 0);
+ ret = rfkill_register(priv->rfk[dev]);
+ if (ret) {
+ rfkill_destroy(priv->rfk[dev]);
+ return ret;
+ }
+ return 0;
+}
+
+static void ideapad_unregister_rfkill(struct acpi_device *adevice, int dev)
+{
+ struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+
+ if (!priv->rfk[dev])
+ return;
+
+ rfkill_unregister(priv->rfk[dev]);
+ rfkill_destroy(priv->rfk[dev]);
+}
+
+static const struct acpi_device_id ideapad_device_ids[] = {
+ { "VPC2004", 0},
+ { "", 0},
+};
+MODULE_DEVICE_TABLE(acpi, ideapad_device_ids);
+
+static int ideapad_acpi_add(struct acpi_device *adevice)
+{
+ int i, cfg;
+ int devs_present[5];
+ struct ideapad_private *priv;
+
+ if (read_method_int(adevice->handle, "_STA", &i))
+ return -ENODEV;
+ if (i != 0x0F)
+ return -ENODEV;
+
+ if (read_method_int(adevice->handle, "_CFG", &cfg))
+ return -ENODEV;
+
+ for (i = IDEAPAD_DEV_CAMERA; i < IDEAPAD_DEV_KILLSW; i++) {
+ if (test_bit(ideapad_rfk_data[i].cfgbit, (unsigned long *)&cfg))
+ devs_present[i] = 1;
+ else
+ devs_present[i] = 0;
+ }
+
+ /* The hardware switch is always present */
+ devs_present[IDEAPAD_DEV_KILLSW] = 1;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (devs_present[IDEAPAD_DEV_CAMERA]) {
+ int ret = device_create_file(&adevice->dev, &dev_attr_camera_power);
+ if (ret) {
+ kfree(priv);
+ return ret;
+ }
+ }
+
+ priv->handle = adevice->handle;
+ dev_set_drvdata(&adevice->dev, priv);
+ ideapad_priv = priv;
+ for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++) {
+ if (!devs_present[i])
+ continue;
+
+ ideapad_register_rfkill(adevice, i);
+ }
+ ideapad_sync_rfk_state(adevice);
+ return 0;
+}
+
+static int ideapad_acpi_remove(struct acpi_device *adevice, int type)
+{
+ struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
+ int i;
+
+ device_remove_file(&adevice->dev, &dev_attr_camera_power);
+
+ for (i = IDEAPAD_DEV_WLAN; i <= IDEAPAD_DEV_KILLSW; i++)
+ ideapad_unregister_rfkill(adevice, i);
+
+ dev_set_drvdata(&adevice->dev, NULL);
+ kfree(priv);
+ return 0;
+}
+
+static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
+{
+ acpi_handle handle = adevice->handle;
+ unsigned long vpc1, vpc2, vpc_bit;
+
+ if (read_ec_data(handle, 0x10, &vpc1))
+ return;
+ if (read_ec_data(handle, 0x1A, &vpc2))
+ return;
+
+ vpc1 = (vpc2 << 8) | vpc1;
+ for (vpc_bit = 0; vpc_bit < 16; vpc_bit++) {
+ if (test_bit(vpc_bit, &vpc1)) {
+ if (vpc_bit == 9)
+ ideapad_sync_rfk_state(adevice);
+ }
+ }
+}
+
+static struct acpi_driver ideapad_acpi_driver = {
+ .name = "ideapad_acpi",
+ .class = "IdeaPad",
+ .ids = ideapad_device_ids,
+ .ops.add = ideapad_acpi_add,
+ .ops.remove = ideapad_acpi_remove,
+ .ops.notify = ideapad_acpi_notify,
+ .owner = THIS_MODULE,
+};
+
+
+static int __init ideapad_acpi_module_init(void)
+{
+ acpi_bus_register_driver(&ideapad_acpi_driver);
+
+ return 0;
+}
+
+
+static void __exit ideapad_acpi_module_exit(void)
+{
+ acpi_bus_unregister_driver(&ideapad_acpi_driver);
+
+}
+
+MODULE_AUTHOR("David Woodhouse <[email protected]>");
+MODULE_DESCRIPTION("IdeaPad ACPI Extras");
+MODULE_LICENSE("GPL");
+
+module_init(ideapad_acpi_module_init);
+module_exit(ideapad_acpi_module_exit);
--
1.7.0.4

2010-08-18 08:42:48

by Oliver Neukum

[permalink] [raw]
Subject: Re: [PATCH 5/8] ideapad: use EC command to control camera

Am Mittwoch, 18. August 2010, 10:38:15 schrieb Ike Panhc:
> Signed-off-by: Ike Panhc <[email protected]>
> ---
> drivers/platform/x86/ideapad_acpi.c | 16 +++++++++++-----
> 1 files changed, 11 insertions(+), 5 deletions(-)

Hi,

wouldn't it be appropriate to integrate such switches into the generic
power framework?

Regards
Oliver

2010-08-18 08:51:29

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 5/8] ideapad: use EC command to control camera

Could you give me an example that I can follow? Just point out which C file
I shall read. no much knowledge about generic power framework.

Thanks

On 08/18/2010 04:42 PM, Oliver Neukum wrote:
> Am Mittwoch, 18. August 2010, 10:38:15 schrieb Ike Panhc:
>> Signed-off-by: Ike Panhc <[email protected]>
>> ---
>> drivers/platform/x86/ideapad_acpi.c | 16 +++++++++++-----
>> 1 files changed, 11 insertions(+), 5 deletions(-)
>
> Hi,
>
> wouldn't it be appropriate to integrate such switches into the generic
> power framework?
>
> Regards
> Oliver

2010-08-18 10:35:49

by David Woodhouse

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On Wed, 2010-08-18 at 09:36 +0100, Ike Panhc wrote:
>
> Once the rfkill of a laptop is set to block, it is no way to unblock with Linux
> without driver. Thanks for David Woodhouse wrote the first driver solving this.
>
> But the \_SB_.GECN and \_SB_.DECN are only available on Lenovo ideapad S10-3.
> Using EC command to control rf/camera power is better because I believe every
> ideapads which has VPC2004 device in its DSDT has this common method.
>
> This driver is tested and work fine on Lenovo ideapad B550 and ideapad S10-3.

Works for me too (on S10-3); thanks.

It all looks good, although should we have a delay or a schedule or at
least a cpu_relax() in the read_ec_data() and write_ec_cmd() loops?
Those loops should be using time_before() too, rather than open-coding
the comparison.

--
David Woodhouse Open Source Technology Centre
[email protected] Intel Corporation

2010-08-18 13:05:05

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On 08/18/2010 06:35 PM, David Woodhouse wrote:
> On Wed, 2010-08-18 at 09:36 +0100, Ike Panhc wrote:
>>
>> Once the rfkill of a laptop is set to block, it is no way to unblock with Linux
>> without driver. Thanks for David Woodhouse wrote the first driver solving this.
>>
>> But the \_SB_.GECN and \_SB_.DECN are only available on Lenovo ideapad S10-3.
>> Using EC command to control rf/camera power is better because I believe every
>> ideapads which has VPC2004 device in its DSDT has this common method.
>>
>> This driver is tested and work fine on Lenovo ideapad B550 and ideapad S10-3.
>
> Works for me too (on S10-3); thanks.
>
> It all looks good, although should we have a delay or a schedule or at
> least a cpu_relax() in the read_ec_data() and write_ec_cmd() loops?
> Those loops should be using time_before() too, rather than open-coding
> the comparison.
>
yeah, agree. polling from ec makes cpu busy, although its usually less then 10ms
a yield or relax will be good.

2010-08-18 13:27:40

by Matthew Garrett

[permalink] [raw]
Subject: Re: [PATCH 3/8] ideapad: make sure we bind on the correct device

On Wed, Aug 18, 2010 at 04:37:33PM +0800, Ike Panhc wrote:
> By reading from method _STA and _CFG to make sure we bind on the correct
> VPC2004 device.

I know some other drivers check _STA themselves, but it's unnecessary -
if _STA didn't evaluate appropriately, the bus driver won't create the
pnp object and there won't be anything for you to bind to in the first
place.

--
Matthew Garrett | [email protected]

2010-08-18 15:53:07

by Mario 'BitKoenig' Holbe

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On Wed, Aug 18, 2010 at 11:35:19AM +0100, David Woodhouse wrote:
> On Wed, 2010-08-18 at 09:36 +0100, Ike Panhc wrote:
> > This driver is tested and work fine on Lenovo ideapad B550 and ideapad S10-3.
> Works for me too (on S10-3); thanks.

It works for me too on S12 w/ VIA Nano - at least somehow... I have two
issues with it:

1st: the camera is not detected:

$ dmesg | grep -i cam
[ 3.062601] usb 1-4: Product: Lenovo EasyCamera
[ 7.828202] uvcvideo: Found UVC 1.00 device Lenovo EasyCamera (5986:0241)
[ 7.842987] input: Lenovo EasyCamera as /devices/pci0000:00/0000:00:10.4/usb1/1-4/1-4:1.0/input/input6
$ lsusb | grep -i cam
Bus 001 Device 002: ID 5986:0241 Acer, Inc BisonCam, NB Pro
$ rfkill list
0: ideapad_wlan: Wireless LAN
Soft blocked: no
Hard blocked: no
1: ideapad_bluetooth: Bluetooth
Soft blocked: no
Hard blocked: no
2: ideapad_killsw: Wireless LAN
Soft blocked: no
Hard blocked: no
3: hci0: Bluetooth
Soft blocked: no
Hard blocked: no
4: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no

Fn-Esc switches the Camera off and on, but there seems to be no soft
killswitch for it. I have no idea how to parse through acpidump to find
out whether there is some similar device listed or not.


2nd: both Bluetooth killswitches reproducibly disappear when I block
ideapad_bluetooth either via Gnome bluetooth-applet or via rfkill block
1 and subsequently reboot. After the reboot rfkill list shows:

0: ideapad_wlan: Wireless LAN
Soft blocked: no
Hard blocked: no
1: ideapad_killsw: Wireless LAN
Soft blocked: no
Hard blocked: no
2: phy0: Wireless LAN
Soft blocked: no
Hard blocked: no

Powering the machine off and on again restores both killswitches.
Interesting is: this does not happen when I boot into single-user mode,
rfkill block 1 there and reboot. In this case, both killswitches are
back.


regards
Mario
--
File names are infinite in length where infinity is set to 255 characters.
-- Peter Collinson, "The Unix File System"


Attachments:
(No filename) (2.08 kB)
signature.asc (482.00 B)
Digital signature
Download all attachments

2010-08-19 02:51:47

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 3/8] ideapad: make sure we bind on the correct device

On 08/18/2010 09:27 PM, Matthew Garrett wrote:
> On Wed, Aug 18, 2010 at 04:37:33PM +0800, Ike Panhc wrote:
>> By reading from method _STA and _CFG to make sure we bind on the correct
>> VPC2004 device.
>
> I know some other drivers check _STA themselves, but it's unnecessary -
> if _STA didn't evaluate appropriately, the bus driver won't create the
> pnp object and there won't be anything for you to bind to in the first
> place.
>
yes, you are right. when add, acpi_bus will check for it and tell if the
device exist or not from its bits.

2010-08-19 03:21:16

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On 08/18/2010 11:51 PM, Mario 'BitKoenig' Holbe wrote:
> On Wed, Aug 18, 2010 at 11:35:19AM +0100, David Woodhouse wrote:
>> On Wed, 2010-08-18 at 09:36 +0100, Ike Panhc wrote:
>>> This driver is tested and work fine on Lenovo ideapad B550 and ideapad S10-3.
>> Works for me too (on S10-3); thanks.
>
> It works for me too on S12 w/ VIA Nano - at least somehow... I have two
> issues with it:
>
> 1st: the camera is not detected:
>
> $ dmesg | grep -i cam
> [ 3.062601] usb 1-4: Product: Lenovo EasyCamera
> [ 7.828202] uvcvideo: Found UVC 1.00 device Lenovo EasyCamera (5986:0241)
> [ 7.842987] input: Lenovo EasyCamera as /devices/pci0000:00/0000:00:10.4/usb1/1-4/1-4:1.0/input/input6
> $ lsusb | grep -i cam
> Bus 001 Device 002: ID 5986:0241 Acer, Inc BisonCam, NB Pro
> $ rfkill list
> 0: ideapad_wlan: Wireless LAN
> Soft blocked: no
> Hard blocked: no
> 1: ideapad_bluetooth: Bluetooth
> Soft blocked: no
> Hard blocked: no
> 2: ideapad_killsw: Wireless LAN
> Soft blocked: no
> Hard blocked: no
> 3: hci0: Bluetooth
> Soft blocked: no
> Hard blocked: no
> 4: phy0: Wireless LAN
> Soft blocked: no
> Hard blocked: no
>
> Fn-Esc switches the Camera off and on, but there seems to be no soft
> killswitch for it. I have no idea how to parse through acpidump to find
> out whether there is some similar device listed or not.
rfkill for RF devices only. This driver will create an entry on sysfs to
control the camera power

You can find the entry by "find /sys/devices -name 'camera_power'"

>
>
> 2nd: both Bluetooth killswitches reproducibly disappear when I block
> ideapad_bluetooth either via Gnome bluetooth-applet or via rfkill block
> 1 and subsequently reboot. After the reboot rfkill list shows:
>
> 0: ideapad_wlan: Wireless LAN
> Soft blocked: no
> Hard blocked: no
> 1: ideapad_killsw: Wireless LAN
> Soft blocked: no
> Hard blocked: no
> 2: phy0: Wireless LAN
> Soft blocked: no
> Hard blocked: no
>
> Powering the machine off and on again restores both killswitches.
> Interesting is: this does not happen when I boot into single-user mode,
> rfkill block 1 there and reboot. In this case, both killswitches are
> back.
This is interesting. looks like the cfgbit will change on S12 if BIOS
remember it has to shutdown when booting. I will try if the same problem
happen on my ideapads.

>
>
> regards
> Mario

2010-08-19 13:28:48

by David Woodhouse

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On Thu, 2010-08-19 at 11:21 +0800, Ike Panhc wrote:
>
> > 2nd: both Bluetooth killswitches reproducibly disappear when I block
> > ideapad_bluetooth either via Gnome bluetooth-applet or via rfkill block
> > 1 and subsequently reboot. After the reboot rfkill list shows:
> >
> > 0: ideapad_wlan: Wireless LAN
> > Soft blocked: no
> > Hard blocked: no
> > 1: ideapad_killsw: Wireless LAN
> > Soft blocked: no
> > Hard blocked: no
> > 2: phy0: Wireless LAN
> > Soft blocked: no
> > Hard blocked: no
> >
> > Powering the machine off and on again restores both killswitches.
> > Interesting is: this does not happen when I boot into single-user mode,
> > rfkill block 1 there and reboot. In this case, both killswitches are
> > back.
> This is interesting. looks like the cfgbit will change on S12 if BIOS
> remember it has to shutdown when booting. I will try if the same problem
> happen on my ideapads.

If we can solve this, I'm inclined to suggest that we submit your code
to Linus to replace mine in 2.6.36. We needed *something* as a stopgap
to solve the rfkill issues, but this is better than what we have in
2-6.36-rc1.

--
dwmw2

2010-08-19 19:32:57

by Mario 'BitKoenig' Holbe

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On Thu, Aug 19, 2010 at 11:21:01AM +0800, Ike Panhc wrote:
> On 08/18/2010 11:51 PM, Mario 'BitKoenig' Holbe wrote:
> > It works for me too on S12 w/ VIA Nano - at least somehow... I have two
...
> > Fn-Esc switches the Camera off and on, but there seems to be no soft
> > killswitch for it. I have no idea how to parse through acpidump to find
> You can find the entry by "find /sys/devices -name 'camera_power'"

Thanks a lot. I found it and it works.

> > 2nd: both Bluetooth killswitches reproducibly disappear when I block
> > ideapad_bluetooth either via Gnome bluetooth-applet or via rfkill block
> > 1 and subsequently reboot.

All right, I did some more testing...

I was not able to reproduce this with Windows somewhere in the game -
neither via switching BT off in Windows and rebooting to Windows nor via
switching BT off in Linux and rebooting to Windows nor via switching BT
off in Windows and rebooting to Linux.

> This is interesting. looks like the cfgbit will change on S12 if BIOS
> remember it has to shutdown when booting. I will try if the same problem
> happen on my ideapads.

Yes, the cfgbit changes. It's normally 0xd0000 and it's 0xc0000 when the
bluetooth switch is not detected.

It's not that reproducible as it first appeared to be. Sometimes it does
not happen, i.e. sometimes after rfkill block 1 and reboot the
bluetooth killswitch is available again.

If the bluetooth killswitch is not available, a second reboot usually
makes it available again.

Once the cfgbit is 0xc0000 it's stable, i.e. modprobe -r ideapad-laptop;
modprobe ideapad-laptop doesn't change anything.

I tried to enforce the existence of the bluetooth killswitch (the
attached diff is not for inclusion but to show what I did) with some
kind of success:

[ 682.260288] ideapad_acpi_add(): cfg=0xc0000
[ 682.260293] ideapad_acpi_add(): found: ideapad_camera
[ 682.260297] ideapad_acpi_add(): found: ideapad_wlan
[ 682.260301] ideapad_acpi_add(): forced: ideapad_bluetooth
[ 682.856049] usb 4-1: new full speed USB device using uhci_hcd and address 2
[ 683.028220] usb 4-1: New USB device found, idVendor=0a5c, idProduct=2150
[ 683.028234] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 683.028244] usb 4-1: Product: BCM2046 Bluetooth Device

So, forcing the existence of the killswitch enables the bluetooth
device. I'm also able to switch if off again - the bluetooth device
disappears. Trying to switch it back on then fails - the bluetooth
device does not appear again. But this case doesn't work all that well
anyways even with cfgbit 0xd0000:

$ rfkill block 1
[ 124.648059] usb 4-1: USB disconnect, address 2
[ 124.648512] btusb_intr_complete: hci0 urb f6825700 failed to resubmit (19)
[ 124.648531] btusb_bulk_complete: hci0 urb f697ee80 failed to resubmit (19)
[ 124.649510] btusb_bulk_complete: hci0 urb f6872400 failed to resubmit (19)
[ 124.650114] btusb_send_frame: hci0 urb f67acf00 submission failed
$ rfkill unblock 1
[ 133.148059] usb 4-1: new full speed USB device using uhci_hcd and address 3
[ 148.260042] usb 4-1: device descriptor read/64, error -110
$ rfkill block 1
[ 151.092060] hub 4-0:1.0: unable to enumerate USB device on port 1
$ rfkill unblock 1
[ 155.628052] usb 4-1: new full speed USB device using uhci_hcd and address 4
[ 170.740049] usb 4-1: device descriptor read/64, error -110
[ 185.956033] usb 4-1: device descriptor read/64, error -110

Sometimes it doesn't even come back at all on unblock. Seems like the
bluetooth device doesn't really like to be powered off and on that way.
Btw.: once I messed up the bluetooth device that way not even Windows
sees it anymore when I reboot to it.

From all this I'm inclined to assume it has more to do with the
bluetooth device's USB interface than with the killswitch handling
itself. I believe the S12 BIOS just probes the device(s) on it's own and
sets the cfgbit accordingly and sometimes it just doesn't find the
bluetooth device - why ever.

This all does btw. not happen when I use the hci0 killswitch instead.
The device doesn't disappear then, has no issues with re-initialization,
etc. Looks way more stable that way.
I'm not absolutely sure about the different implications of using the
one or the other killswitch - maybe using the ACPI killswitches saves
more power than using the device-specific killswitches because it powers
the device(s) down completely, but that's just a wild guess - maybe it's
absolutely wrong, though.
However, it would probably be worth thinking about not offering the
additional RF killswitches at all but just doing the initialization
stuff to make sure the devices power up and are thus able to be handled
via their own killswitches subsequently.

Please let me know if I can provide more testing - and what kind of :)


Mario
--
We know that communication is a problem, but the company is not going to
discuss it with the employees.
-- Switching supervisor, AT&T Long Lines Division


Attachments:
(No filename) (0.00 B)
signature.asc (482.00 B)
Digital signature
Download all attachments

2010-08-20 07:01:24

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

Hi Mario,

Could you attach or upload the DSDT of S12 somewhere I can reach?
I check DSDT for S10-3 and B550, return value of _CFG is fixed.

[Ref: http://people.ubuntu.com/~ikepanhc/DSDTs]

you may use "sudo cp /sys/firmware/acpi/tables/DSDT ." and
"sudo iasl -d /sys/firmware/acpi/tables/DSDT" to decode it.

On 08/20/2010 03:31 AM, Mario 'BitKoenig' Holbe wrote:
> On Thu, Aug 19, 2010 at 11:21:01AM +0800, Ike Panhc wrote:
>> On 08/18/2010 11:51 PM, Mario 'BitKoenig' Holbe wrote:
>>> 2nd: both Bluetooth killswitches reproducibly disappear when I block
>>> ideapad_bluetooth either via Gnome bluetooth-applet or via rfkill block
>>> 1 and subsequently reboot.
>
> All right, I did some more testing...
>
> I was not able to reproduce this with Windows somewhere in the game -
> neither via switching BT off in Windows and rebooting to Windows nor via
> switching BT off in Linux and rebooting to Windows nor via switching BT
> off in Windows and rebooting to Linux.
>
>> This is interesting. looks like the cfgbit will change on S12 if BIOS
>> remember it has to shutdown when booting. I will try if the same problem
>> happen on my ideapads.
>
> Yes, the cfgbit changes. It's normally 0xd0000 and it's 0xc0000 when the
> bluetooth switch is not detected.
>
> It's not that reproducible as it first appeared to be. Sometimes it does
> not happen, i.e. sometimes after rfkill block 1 and reboot the
> bluetooth killswitch is available again.
>
> If the bluetooth killswitch is not available, a second reboot usually
> makes it available again.
>
> Once the cfgbit is 0xc0000 it's stable, i.e. modprobe -r ideapad-laptop;
> modprobe ideapad-laptop doesn't change anything.
sounds like we need an exception handle for detecting camera

>
> I tried to enforce the existence of the bluetooth killswitch (the
> attached diff is not for inclusion but to show what I did) with some
> kind of success:
>
> [ 682.260288] ideapad_acpi_add(): cfg=0xc0000
As I know the cfgbit for lower 16bit shall not be all zero.

> [ 682.260293] ideapad_acpi_add(): found: ideapad_camera
> [ 682.260297] ideapad_acpi_add(): found: ideapad_wlan
> [ 682.260301] ideapad_acpi_add(): forced: ideapad_bluetooth
> [ 682.856049] usb 4-1: new full speed USB device using uhci_hcd and address 2
> [ 683.028220] usb 4-1: New USB device found, idVendor=0a5c, idProduct=2150
> [ 683.028234] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
> [ 683.028244] usb 4-1: Product: BCM2046 Bluetooth Device
>
> So, forcing the existence of the killswitch enables the bluetooth
> device. I'm also able to switch if off again - the bluetooth device
> disappears. Trying to switch it back on then fails - the bluetooth
> device does not appear again. But this case doesn't work all that well
> anyways even with cfgbit 0xd0000:
bluetooth device shall disappear after disable from EC. But if can not be enabled
again, ahh.....

>
> $ rfkill block 1
> [ 124.648059] usb 4-1: USB disconnect, address 2
> [ 124.648512] btusb_intr_complete: hci0 urb f6825700 failed to resubmit (19)
> [ 124.648531] btusb_bulk_complete: hci0 urb f697ee80 failed to resubmit (19)
> [ 124.649510] btusb_bulk_complete: hci0 urb f6872400 failed to resubmit (19)
> [ 124.650114] btusb_send_frame: hci0 urb f67acf00 submission failed
> $ rfkill unblock 1
> [ 133.148059] usb 4-1: new full speed USB device using uhci_hcd and address 3
> [ 148.260042] usb 4-1: device descriptor read/64, error -110
> $ rfkill block 1
> [ 151.092060] hub 4-0:1.0: unable to enumerate USB device on port 1
> $ rfkill unblock 1
> [ 155.628052] usb 4-1: new full speed USB device using uhci_hcd and address 4
> [ 170.740049] usb 4-1: device descriptor read/64, error -110
> [ 185.956033] usb 4-1: device descriptor read/64, error -110
This looks like the device is power up, but usb host unable to recognize..

>
> Sometimes it doesn't even come back at all on unblock. Seems like the
> bluetooth device doesn't really like to be powered off and on that way.
> Btw.: once I messed up the bluetooth device that way not even Windows
> sees it anymore when I reboot to it.
did you see any kernel message said timeout when it does not come back at all?

>
> From all this I'm inclined to assume it has more to do with the
> bluetooth device's USB interface than with the killswitch handling
> itself. I believe the S12 BIOS just probes the device(s) on it's own and
> sets the cfgbit accordingly and sometimes it just doesn't find the
> bluetooth device - why ever.
I guess so. so I need DSDT for digging more.

>
> This all does btw. not happen when I use the hci0 killswitch instead.
> The device doesn't disappear then, has no issues with re-initialization,
> etc. Looks way more stable that way.
when you use rfkill of hci0, it only disable PHY. The driver and MAC is still
there. The rfkill of ideapad-laptop will power down all the module. I believe
its normal.

> I'm not absolutely sure about the different implications of using the
> one or the other killswitch - maybe using the ACPI killswitches saves
> more power than using the device-specific killswitches because it powers
> the device(s) down completely, but that's just a wild guess - maybe it's
> absolutely wrong, though.
I think it shall be correct.

If the rfkill for the whole bluetooth module makes trouble, I prefer not to
do it. User will feel confused if the device does not come back and the
rfkill of hci0 offers the function user need.

> However, it would probably be worth thinking about not offering the
> additional RF killswitches at all but just doing the initialization
> stuff to make sure the devices power up and are thus able to be handled
> via their own killswitches subsequently.
>
> Please let me know if I can provide more testing - and what kind of :)
>
>
> Mario

2010-08-20 09:09:10

by Mario 'BitKoenig' Holbe

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On Fri, Aug 20, 2010 at 03:01:07PM +0800, Ike Panhc wrote:
> Could you attach or upload the DSDT of S12 somewhere I can reach?

http://sandbox.fem.tu-ilmenau.de/s12/dsdt-s12-via.dsl

> I check DSDT for S10-3 and B550, return value of _CFG is fixed.
> [Ref: http://people.ubuntu.com/~ikepanhc/DSDTs]

Looks more fixed than on my S12, indeed.
I don't really speak AML, but while S10-3 ILDD (called from _CFG) seems
to read fixed values only, here on S12 PHSR (called from _CFG) seems to
do some kind of I/O operation. I'm not sure about this, but it somehow
looks like.

> On 08/20/2010 03:31 AM, Mario 'BitKoenig' Holbe wrote:
> > Once the cfgbit is 0xc0000 it's stable, i.e. modprobe -r ideapad-laptop;
> > modprobe ideapad-laptop doesn't change anything.
> sounds like we need an exception handle for detecting camera

Why? The camera is always detected - bit 19 is always set, 0xc0000 and
0xd0000 only differ in bit 16. Bit 19 btw. seems to be the only fixed
bit in S12-VIA _CFG :)

> > [ 682.260288] ideapad_acpi_add(): cfg=0xc0000
> As I know the cfgbit for lower 16bit shall not be all zero.

Mh, judging from S12-VIA _CFG they definitely are zero here.

> > So, forcing the existence of the killswitch enables the bluetooth
> > device. I'm also able to switch if off again - the bluetooth device
> > disappears. Trying to switch it back on then fails - the bluetooth
> > device does not appear again. But this case doesn't work all that well
> > anyways even with cfgbit 0xd0000:
> bluetooth device shall disappear after disable from EC. But if can not be enabled
> again, ahh.....

> > [ 155.628052] usb 4-1: new full speed USB device using uhci_hcd and address 4
> > [ 170.740049] usb 4-1: device descriptor read/64, error -110
> > [ 185.956033] usb 4-1: device descriptor read/64, error -110
> This looks like the device is power up, but usb host unable to recognize..

The bluetooth device seems not to initialize well enough to answer (110
is ETIMEDOUT).

> > Sometimes it doesn't even come back at all on unblock. Seems like the
> > bluetooth device doesn't really like to be powered off and on that way.
> did you see any kernel message said timeout when it does not come back at all?

No, when I said "does not appear again" and "it does not come back at
all" I meant I see not a single message in dmesg about anything
happening.

> If the rfkill for the whole bluetooth module makes trouble, I prefer not to
> do it. User will feel confused if the device does not come back and the
> rfkill of hci0 offers the function user need.

Hmmm, maybe provide a module parm to block rfkill devices and default it
to 1 on S12? Users would not need to care too much then but can change
it if they like...

> > Please let me know if I can provide more testing - and what kind of :)

Okay, did some more...

I played with the hardware killswitch under Linux. The bluetooth device
disappears and re-appears there and always seems to initialize
correctly. No USB read errors this way.

I also played with the soft killswitch under Windows. The bluetooth
device disappears from device manager and re-appears on unblock
(together with the Windows device plug sounds). This looks to me like
the ACPI killswitch is used for it.
No initialization-problems here, the device always comes back fully
operational. So, Windows doesn't seem to suffer from a bad
initialization.

I'm not exactly sure what this means - especially because I don't know
how the hardware killswitch works internally.
It *could* mean, the initialization problem is proably something that
could be dealt with in the USB layer long term (and would then probably
not have to be worked around anymore in ideapad_laptop). I'm not sure
about this, because this would mean the hard killswitch power-cut
somehow differs from the soft killswitch power-cut.


Mario
--
As a rule, the more bizarre a thing is, the less mysterious it proves to be.
-- Sherlock Holmes by Arthur Conan Doyle


Attachments:
(No filename) (3.89 kB)
signature.asc (478.00 B)
Digital signature
Download all attachments

2010-08-23 08:23:01

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On 08/20/2010 05:08 PM, Mario 'BitKoenig' Holbe wrote:
> On Fri, Aug 20, 2010 at 03:01:07PM +0800, Ike Panhc wrote:
>> Could you attach or upload the DSDT of S12 somewhere I can reach?
>
> http://sandbox.fem.tu-ilmenau.de/s12/dsdt-s12-via.dsl
Thanks for the DSDT and the following information.

I am not an expert on AML but after looking to the DSDT, I think I will
focus on what XCMD do.

I notice there are some interesting method/variable (Ex: BTEN/BTST..)
about bluetooth, but not have a good story about what's going on.

I think the only problem we have now is bluetooth sometimes not coming
back when rebooting after turn off bluetooth via sw rfkill. Try to find
out if there is anything need to be done before turn it on.

>
>> I check DSDT for S10-3 and B550, return value of _CFG is fixed.
>> [Ref: http://people.ubuntu.com/~ikepanhc/DSDTs]
>
> Looks more fixed than on my S12, indeed.
> I don't really speak AML, but while S10-3 ILDD (called from _CFG) seems
> to read fixed values only, here on S12 PHSR (called from _CFG) seems to
> do some kind of I/O operation. I'm not sure about this, but it somehow
> looks like.
>
>> On 08/20/2010 03:31 AM, Mario 'BitKoenig' Holbe wrote:
>>> Once the cfgbit is 0xc0000 it's stable, i.e. modprobe -r ideapad-laptop;
>>> modprobe ideapad-laptop doesn't change anything.
>> sounds like we need an exception handle for detecting camera
>
> Why? The camera is always detected - bit 19 is always set, 0xc0000 and
> 0xd0000 only differ in bit 16. Bit 19 btw. seems to be the only fixed
> bit in S12-VIA _CFG :)
>
>>> [ 682.260288] ideapad_acpi_add(): cfg=0xc0000
>> As I know the cfgbit for lower 16bit shall not be all zero.
>
> Mh, judging from S12-VIA _CFG they definitely are zero here.
>
>>> So, forcing the existence of the killswitch enables the bluetooth
>>> device. I'm also able to switch if off again - the bluetooth device
>>> disappears. Trying to switch it back on then fails - the bluetooth
>>> device does not appear again. But this case doesn't work all that well
>>> anyways even with cfgbit 0xd0000:
>> bluetooth device shall disappear after disable from EC. But if can not be enabled
>> again, ahh.....
>
>>> [ 155.628052] usb 4-1: new full speed USB device using uhci_hcd and address 4
>>> [ 170.740049] usb 4-1: device descriptor read/64, error -110
>>> [ 185.956033] usb 4-1: device descriptor read/64, error -110
>> This looks like the device is power up, but usb host unable to recognize..
>
> The bluetooth device seems not to initialize well enough to answer (110
> is ETIMEDOUT).
>
>>> Sometimes it doesn't even come back at all on unblock. Seems like the
>>> bluetooth device doesn't really like to be powered off and on that way.
>> did you see any kernel message said timeout when it does not come back at all?
>
> No, when I said "does not appear again" and "it does not come back at
> all" I meant I see not a single message in dmesg about anything
> happening.
>
>> If the rfkill for the whole bluetooth module makes trouble, I prefer not to
>> do it. User will feel confused if the device does not come back and the
>> rfkill of hci0 offers the function user need.
>
> Hmmm, maybe provide a module parm to block rfkill devices and default it
> to 1 on S12? Users would not need to care too much then but can change
> it if they like...
>
>>> Please let me know if I can provide more testing - and what kind of :)
>
> Okay, did some more...
>
> I played with the hardware killswitch under Linux. The bluetooth device
> disappears and re-appears there and always seems to initialize
> correctly. No USB read errors this way.
>
> I also played with the soft killswitch under Windows. The bluetooth
> device disappears from device manager and re-appears on unblock
> (together with the Windows device plug sounds). This looks to me like
> the ACPI killswitch is used for it.
> No initialization-problems here, the device always comes back fully
> operational. So, Windows doesn't seem to suffer from a bad
> initialization.
>
> I'm not exactly sure what this means - especially because I don't know
> how the hardware killswitch works internally.
> It *could* mean, the initialization problem is proably something that
> could be dealt with in the USB layer long term (and would then probably
> not have to be worked around anymore in ideapad_laptop). I'm not sure
> about this, because this would mean the hard killswitch power-cut
> somehow differs from the soft killswitch power-cut.
>
>
> Mario

2010-08-25 11:59:47

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

On 08/20/2010 05:08 PM, Mario 'BitKoenig' Holbe wrote:
> On Fri, Aug 20, 2010 at 03:01:07PM +0800, Ike Panhc wrote:
>> Could you attach or upload the DSDT of S12 somewhere I can reach?
>
> http://sandbox.fem.tu-ilmenau.de/s12/dsdt-s12-via.dsl
>
>> I check DSDT for S10-3 and B550, return value of _CFG is fixed.
>> [Ref: http://people.ubuntu.com/~ikepanhc/DSDTs]
>
> Looks more fixed than on my S12, indeed.
> I don't really speak AML, but while S10-3 ILDD (called from _CFG) seems
> to read fixed values only, here on S12 PHSR (called from _CFG) seems to
> do some kind of I/O operation. I'm not sure about this, but it somehow
> looks like.
>
It accesses something in system memory, but I have no idea what will happen
after writing..

>> On 08/20/2010 03:31 AM, Mario 'BitKoenig' Holbe wrote:
>>> Once the cfgbit is 0xc0000 it's stable, i.e. modprobe -r ideapad-laptop;
>>> modprobe ideapad-laptop doesn't change anything.
>> sounds like we need an exception handle for detecting camera
>
> Why? The camera is always detected - bit 19 is always set, 0xc0000 and
> 0xd0000 only differ in bit 16. Bit 19 btw. seems to be the only fixed
> bit in S12-VIA _CFG :)
>
That's my misunderstanding.

>>> [ 682.260288] ideapad_acpi_add(): cfg=0xc0000
>> As I know the cfgbit for lower 16bit shall not be all zero.
>
> Mh, judging from S12-VIA _CFG they definitely are zero here.
>
>>> So, forcing the existence of the killswitch enables the bluetooth
>>> device. I'm also able to switch if off again - the bluetooth device
>>> disappears. Trying to switch it back on then fails - the bluetooth
>>> device does not appear again. But this case doesn't work all that well
>>> anyways even with cfgbit 0xd0000:
>> bluetooth device shall disappear after disable from EC. But if can not be enabled
>> again, ahh.....
>
>>> [ 155.628052] usb 4-1: new full speed USB device using uhci_hcd and address 4
>>> [ 170.740049] usb 4-1: device descriptor read/64, error -110
>>> [ 185.956033] usb 4-1: device descriptor read/64, error -110
>> This looks like the device is power up, but usb host unable to recognize..
>
> The bluetooth device seems not to initialize well enough to answer (110
> is ETIMEDOUT).
>
There are two variables need to be written for turning on/off bluetooth. They are
BTST(in memory) and BTEN(is EC register). I will guess there are some sync failed
when enable bluetooth.

>>> Sometimes it doesn't even come back at all on unblock. Seems like the
>>> bluetooth device doesn't really like to be powered off and on that way.
>> did you see any kernel message said timeout when it does not come back at all?
>
> No, when I said "does not appear again" and "it does not come back at
> all" I meant I see not a single message in dmesg about anything
> happening.
>
>> If the rfkill for the whole bluetooth module makes trouble, I prefer not to
>> do it. User will feel confused if the device does not come back and the
>> rfkill of hci0 offers the function user need.
>
> Hmmm, maybe provide a module parm to block rfkill devices and default it
> to 1 on S12? Users would not need to care too much then but can change
> it if they like...
This could be a plan. I have several idea to go and need your help.
- Add some debug message to read BTST/BTEN when turning on/off bluetooth.
- Force to set BTST/BTEN before reading _CFG
- Provide a module parm to force enable rf devices.

Will have the drivers and please test it and let me know the result.

>
>>> Please let me know if I can provide more testing - and what kind of :)
>
> Okay, did some more...
>
> I played with the hardware killswitch under Linux. The bluetooth device
> disappears and re-appears there and always seems to initialize
> correctly. No USB read errors this way.
>
> I also played with the soft killswitch under Windows. The bluetooth
> device disappears from device manager and re-appears on unblock
> (together with the Windows device plug sounds). This looks to me like
> the ACPI killswitch is used for it.
> No initialization-problems here, the device always comes back fully
> operational. So, Windows doesn't seem to suffer from a bad
> initialization.
>
> I'm not exactly sure what this means - especially because I don't know
> how the hardware killswitch works internally.
> It *could* mean, the initialization problem is proably something that
> could be dealt with in the USB layer long term (and would then probably
> not have to be worked around anymore in ideapad_laptop). I'm not sure
> about this, because this would mean the hard killswitch power-cut
> somehow differs from the soft killswitch power-cut.
Usually the hw rf switch turning off PHY only. When turning off, device and
its driver is still there. I believe S12 is designed in this way after
reading your test result.

>
>
> Mario

2010-08-25 20:57:14

by Len Brown

[permalink] [raw]
Subject: Re: [PATCH 8/8] ideapad: Change the driver name to ideapad_laptop

> drivers/platform/x86/ideapad_acpi.c | 381 ---------------------------------
> drivers/platform/x86/ideapad_laptop.c | 381 +++++++++++++++++++++++++++++++++

Acked-by: Len Brown <[email protected]>

thanks,
Len Brown, Intel Open Source Technology Center

2010-08-26 05:43:12

by Corentin Chary

[permalink] [raw]
Subject: Re: [PATCH 8/8] ideapad: Change the driver name to ideapad_laptop

On Wed, Aug 25, 2010 at 10:56 PM, Len Brown <[email protected]> wrote:
>> ?drivers/platform/x86/ideapad_acpi.c ? | ?381 ---------------------------------
>> ?drivers/platform/x86/ideapad_laptop.c | ?381 +++++++++++++++++++++++++++++++++
>
> Acked-by: Len Brown <[email protected]>
>
> thanks,
> Len Brown, Intel Open Source Technology Center
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to [email protected]
> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>

Probably not very important .. but .. other drivers are called *-laptop.c, not
*_laptop.c ..

asus-laptop.c classmate-laptop.c compal-laptop.c dell-laptop.c eeepc-laptop.c
fujitsu-laptop.c msi-laptop.c panasonic-laptop.c sony-laptop.c topstar-laptop.c

--
Corentin Chary
http://xf.iksaif.net

2010-08-26 06:16:24

by Ike Panhc

[permalink] [raw]
Subject: Re: [PATCH 8/8] ideapad: Change the driver name to ideapad_laptop

On 08/26/2010 01:43 PM, Corentin Chary wrote:
> On Wed, Aug 25, 2010 at 10:56 PM, Len Brown <[email protected]> wrote:
>>> drivers/platform/x86/ideapad_acpi.c | 381 ---------------------------------
>>> drivers/platform/x86/ideapad_laptop.c | 381 +++++++++++++++++++++++++++++++++
>>
>> Acked-by: Len Brown <[email protected]>
>>
>> thanks,
>> Len Brown, Intel Open Source Technology Center
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
>> the body of a message to [email protected]
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
> Probably not very important .. but .. other drivers are called *-laptop.c, not
> *_laptop.c ..
>
> asus-laptop.c classmate-laptop.c compal-laptop.c dell-laptop.c eeepc-laptop.c
> fujitsu-laptop.c msi-laptop.c panasonic-laptop.c sony-laptop.c topstar-laptop.c
>
I choose _laptop.c not -laptop.c because when modprobe. We are using
"modprobe asus-laptop", but when removing, using "modprobe asus_laptop".

2010-08-26 07:43:22

by Corentin Chary

[permalink] [raw]
Subject: Re: [PATCH 8/8] ideapad: Change the driver name to ideapad_laptop

On Thu, Aug 26, 2010 at 8:16 AM, Ike Panhc <[email protected]> wrote:
> On 08/26/2010 01:43 PM, Corentin Chary wrote:
>> On Wed, Aug 25, 2010 at 10:56 PM, Len Brown <[email protected]> wrote:
>>>> ?drivers/platform/x86/ideapad_acpi.c ? | ?381 ---------------------------------
>>>> ?drivers/platform/x86/ideapad_laptop.c | ?381 +++++++++++++++++++++++++++++++++
>>>
>>> Acked-by: Len Brown <[email protected]>
>>>
>>> thanks,
>>> Len Brown, Intel Open Source Technology Center
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
>>> the body of a message to [email protected]
>>> More majordomo info at ?http://vger.kernel.org/majordomo-info.html
>>>
>>
>> Probably not very important .. but .. other drivers are called *-laptop.c, not
>> *_laptop.c ..
>>
>> asus-laptop.c classmate-laptop.c compal-laptop.c dell-laptop.c eeepc-laptop.c
>> fujitsu-laptop.c msi-laptop.c panasonic-laptop.c sony-laptop.c topstar-laptop.c
>>
> I choose _laptop.c not -laptop.c because when modprobe. We are using
> "modprobe asus-laptop", but when removing, using "modprobe asus_laptop".
>

Hum, that's a "bug" in asus-laptop, because I used KBUILD_MODNAME
(asus_laptop) instead
of "asus-laptop" as the driver name. And I don't know if I can change
that now without breaking
backward compatibility.

But other drivers should work (I tested sony-laptop).

--
Corentin Chary
http://xf.iksaif.net

2010-08-30 18:21:18

by Mario 'BitKoenig' Holbe

[permalink] [raw]
Subject: Re: [PATCH 0/8] [Resend] ideapad: using EC command to control rf/camera power

Hello Ike,

On Wed, Aug 25, 2010 at 07:59:30PM +0800, Ike Panhc wrote:
> On 08/20/2010 05:08 PM, Mario 'BitKoenig' Holbe wrote:
> > On Fri, Aug 20, 2010 at 03:01:07PM +0800, Ike Panhc wrote:
> >> Could you attach or upload the DSDT of S12 somewhere I can reach?
> >
> > http://sandbox.fem.tu-ilmenau.de/s12/dsdt-s12-via.dsl
> >
> >> I check DSDT for S10-3 and B550, return value of _CFG is fixed.
> >> [Ref: http://people.ubuntu.com/~ikepanhc/DSDTs]
> >
> > Looks more fixed than on my S12, indeed.
> > I don't really speak AML, but while S10-3 ILDD (called from _CFG) seems
> > to read fixed values only, here on S12 PHSR (called from _CFG) seems to
> > do some kind of I/O operation. I'm not sure about this, but it somehow
> > looks like.
> >
> It accesses something in system memory, but I have no idea what will happen
> after writing..

Well, the pattern looks like I/O - mmapped I/O.
Store (Arg1, \_SB.INF0)
Store (Arg0, \_SB.BCMD)
Store (Zero, \_SB.SMIC)
Store (\_SB.INF0, Local0)

Note that INF0 is written before and read after writing SMIC. Hence,
for this to be useful, something must have happened inbetween, i.e.
I/O :)

> There are two variables need to be written for turning on/off bluetooth. They are
> BTST(in memory) and BTEN(is EC register). I will guess there are some sync failed
> when enable bluetooth.

What exactly do you mean with "there are some sync failed"? I don't see
anything like that in the logs.

> This could be a plan. I have several idea to go and need your help.
> - Add some debug message to read BTST/BTEN when turning on/off bluetooth.
> - Force to set BTST/BTEN before reading _CFG
> - Provide a module parm to force enable rf devices.
>
> Will have the drivers and please test it and let me know the result.

Hmmm, I don't know if I got you right. I didn't find any new drivers to
test, so I tried to add some more debug code myself. Hope this helps.
I added some code to show_ideapad_cam() to be able to asynchronously
trigger reading of BTST, BTEN, and BTPS. As before: the patch attached
is not for inclusion but to show what I did. I'm usually not a kernel
hacker, so please take a serious look at what I did before trusting the
results :)

I attached a full protocol of actions I performed including kernel
dmesges. Typed commands are prepended by #, manual actions and comments
are enclosed in <>, kernel messages are timestamped, the rest is output
of the commands.
Basically I did the following:
0. I started with a fresh powered up system, all RF devices powered on.
1. I hw-switched RF off and back on, which went okay.
2. I sw-switched BT off and back on, which resulted in erroneous
initialization.
3. I again sw-switched BT off and back on, which resulted in BT being
completely gone.
4. I hw-switched RF off and back on, which brought BT back and
operational.

> > I played with the hardware killswitch under Linux. The bluetooth device
> > disappears and re-appears there and always seems to initialize
> > correctly. No USB read errors this way.
...
> > I'm not exactly sure what this means - especially because I don't know
> > how the hardware killswitch works internally.
> > It *could* mean, the initialization problem is proably something that
> > could be dealt with in the USB layer long term (and would then probably
> > not have to be worked around anymore in ideapad_laptop). I'm not sure
> > about this, because this would mean the hard killswitch power-cut
> > somehow differs from the soft killswitch power-cut.
> Usually the hw rf switch turning off PHY only. When turning off, device and
> its driver is still there. I believe S12 is designed in this way after
> reading your test result.

Hmmm, I don't understand your reasoning here.
I said the device disappears and re-appears when using the hw rf switch,
this doesn't look like it would turn off PHY only.


best regards
Mario
--
We know that communication is a problem, but the company is not going to
discuss it with the employees.
-- Switching supervisor, AT&T Long Lines Division


Attachments:
(No filename) (0.00 B)
signature.asc (482.00 B)
Digital signature
Download all attachments