* [PATCH 1/9] ideapad: add ACPI helpers
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
@ 2010-10-01 7:38 ` Ike Panhc
2010-10-01 7:39 ` [PATCH 2/9] ideapad: check VPC bit before sync rfkill hw status Ike Panhc
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:38 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
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 <ike.pan@canonical.com>
---
drivers/platform/x86/ideapad_acpi.c | 109 +++++++++++++++++++++++++++++++++++
1 files changed, 109 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index 7984963..1ecf679 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -49,6 +49,115 @@ static struct {
{ "ideapad_killsw", RFKILL_TYPE_WLAN }
};
+/*
+ * ACPI Helpers
+ */
+#define IDEAPAD_EC_TIMEOUT (100) /* 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", ¶ms, &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", ¶ms, 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 end_jiffies;
+
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0) {
+ if (method_vpcr(handle, 0, &val))
+ return -1;
+ *data = val;
+ return 0;
+ }
+ }
+ 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 end_jiffies;
+
+ if (method_vpcw(handle, 0, data))
+ return -1;
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0)
+ return 0;
+ }
+ 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.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/9] ideapad: check VPC bit before sync rfkill hw status
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
2010-10-01 7:38 ` [PATCH 1/9] ideapad: add ACPI helpers Ike Panhc
@ 2010-10-01 7:39 ` Ike Panhc
2010-10-01 7:39 ` [PATCH 3/9] ideapad: make sure we bind on the correct device Ike Panhc
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:39 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
Check VPC bit to make sure the HW rfkill is touched.
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
---
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 1ecf679..15d7e7e 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -379,7 +379,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.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/9] ideapad: make sure we bind on the correct device
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
2010-10-01 7:38 ` [PATCH 1/9] ideapad: add ACPI helpers Ike Panhc
2010-10-01 7:39 ` [PATCH 2/9] ideapad: check VPC bit before sync rfkill hw status Ike Panhc
@ 2010-10-01 7:39 ` Ike Panhc
2010-10-01 7:39 ` [PATCH 4/9] ideapad: use return value of _CFG to tell if device exist or not Ike Panhc
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:39 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
By reading from method _CFG to make sure we bind on the correct VPC2004 device.
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
---
drivers/platform/x86/ideapad_acpi.c | 5 ++++-
1 files changed, 4 insertions(+), 1 deletions(-)
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index 15d7e7e..9face93 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -326,10 +326,13 @@ 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, "_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.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/9] ideapad: use return value of _CFG to tell if device exist or not
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
` (2 preceding siblings ...)
2010-10-01 7:39 ` [PATCH 3/9] ideapad: make sure we bind on the correct device Ike Panhc
@ 2010-10-01 7:39 ` Ike Panhc
2010-10-01 7:39 ` [PATCH 5/9] ideapad: use EC command to control camera Ike Panhc
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:39 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
There are several bits of the return value of _CFG shows if RF/Camera devices
exist or not.
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
---
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 9face93..43a1c89 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 }
};
/*
@@ -158,32 +159,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;
@@ -334,9 +309,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.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/9] ideapad: use EC command to control camera
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
` (3 preceding siblings ...)
2010-10-01 7:39 ` [PATCH 4/9] ideapad: use return value of _CFG to tell if device exist or not Ike Panhc
@ 2010-10-01 7:39 ` Ike Panhc
2010-10-01 7:39 ` [PATCH 6/9] ideapad: rewrite the hw rfkill notify Ike Panhc
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:39 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
---
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 43a1c89..aacf84e 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];
};
@@ -207,24 +208,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;
@@ -330,6 +335,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.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/9] ideapad: rewrite the hw rfkill notify
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
` (4 preceding siblings ...)
2010-10-01 7:39 ` [PATCH 5/9] ideapad: use EC command to control camera Ike Panhc
@ 2010-10-01 7:39 ` Ike Panhc
2010-10-01 7:39 ` [PATCH 7/9] ideapad: rewrite the sw rfkill set Ike Panhc
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:39 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
1. Read hw rfkill status by ec command
2. Not to touch sw status of each rfkill when hw rfkill notify
3. Initial rfkill status when module loaded
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
---
drivers/platform/x86/ideapad_acpi.c | 53 +++++++++++-----------------------
1 files changed, 17 insertions(+), 36 deletions(-)
diff --git a/drivers/platform/x86/ideapad_acpi.c b/drivers/platform/x86/ideapad_acpi.c
index aacf84e..3826686 100644
--- a/drivers/platform/x86/ideapad_acpi.c
+++ b/drivers/platform/x86/ideapad_acpi.c
@@ -160,32 +160,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;
@@ -253,32 +227,39 @@ 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)
{
struct ideapad_private *priv = dev_get_drvdata(&adevice->dev);
int ret;
+ unsigned long sw_blocked;
- 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;
+ if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
+ &sw_blocked)) {
+ rfkill_init_sw_state(priv->rfk[dev], 0);
+ } else {
+ sw_blocked = !sw_blocked;
+ rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
+ }
+
ret = rfkill_register(priv->rfk[dev]);
if (ret) {
rfkill_destroy(priv->rfk[dev]);
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/9] ideapad: rewrite the sw rfkill set
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
` (5 preceding siblings ...)
2010-10-01 7:39 ` [PATCH 6/9] ideapad: rewrite the hw rfkill notify Ike Panhc
@ 2010-10-01 7:39 ` Ike Panhc
2010-10-01 7:40 ` [PATCH 8/9] ideapad: Change the driver name to ideapad-laptop Ike Panhc
2010-10-01 7:40 ` [PATCH 9/9] ideapad: Add param: no_bt_rfkill Ike Panhc
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:39 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
Control power of rf modules by ec commands
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
---
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 3826686..78ac02a 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 }
};
/*
@@ -160,24 +161,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)
@@ -217,7 +200,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 = {
@@ -318,6 +304,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.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 8/9] ideapad: Change the driver name to ideapad-laptop
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
` (6 preceding siblings ...)
2010-10-01 7:39 ` [PATCH 7/9] ideapad: rewrite the sw rfkill set Ike Panhc
@ 2010-10-01 7:40 ` Ike Panhc
2010-10-01 7:40 ` [PATCH 9/9] ideapad: Add param: no_bt_rfkill Ike Panhc
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:40 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
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 <ike.pan@canonical.com>
Acked-by: Len Brown <len.brown@intel.com>
---
drivers/platform/x86/Kconfig | 4 +-
drivers/platform/x86/Makefile | 2 +-
drivers/platform/x86/ideapad-laptop.c | 382 +++++++++++++++++++++++++++++++++
drivers/platform/x86/ideapad_acpi.c | 382 ---------------------------------
4 files changed, 385 insertions(+), 385 deletions(-)
create mode 100644 drivers/platform/x86/ideapad-laptop.c
delete mode 100644 drivers/platform/x86/ideapad_acpi.c
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index cff7cc2..0881c68 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-laptop.c b/drivers/platform/x86/ideapad-laptop.c
new file mode 100644
index 0000000..78ac02a
--- /dev/null
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -0,0 +1,382 @@
+/*
+ * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
+ *
+ * Copyright © 2010 Intel Corporation
+ * Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
+ *
+ * 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 (100) /* 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", ¶ms, &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", ¶ms, 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 end_jiffies;
+
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0) {
+ if (method_vpcr(handle, 0, &val))
+ return -1;
+ *data = val;
+ return 0;
+ }
+ }
+ 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 end_jiffies;
+
+ if (method_vpcw(handle, 0, data))
+ return -1;
+ if (method_vpcw(handle, 1, cmd))
+ return -1;
+
+ for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
+ time_before(jiffies, end_jiffies);) {
+ schedule();
+ if (method_vpcr(handle, 1, &val))
+ return -1;
+ if (val == 0)
+ return 0;
+ }
+ 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;
+ unsigned long sw_blocked;
+
+ 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;
+
+ if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
+ &sw_blocked)) {
+ rfkill_init_sw_state(priv->rfk[dev], 0);
+ } else {
+ sw_blocked = !sw_blocked;
+ rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
+ }
+
+ 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, "_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 <dwmw2@infradead.org>");
+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_acpi.c b/drivers/platform/x86/ideapad_acpi.c
deleted file mode 100644
index 78ac02a..0000000
--- a/drivers/platform/x86/ideapad_acpi.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * ideapad_acpi.c - Lenovo IdeaPad ACPI Extras
- *
- * Copyright © 2010 Intel Corporation
- * Copyright © 2010 David Woodhouse <dwmw2@infradead.org>
- *
- * 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 (100) /* 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", ¶ms, &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", ¶ms, 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 end_jiffies;
-
- if (method_vpcw(handle, 1, cmd))
- return -1;
-
- for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
- time_before(jiffies, end_jiffies);) {
- schedule();
- if (method_vpcr(handle, 1, &val))
- return -1;
- if (val == 0) {
- if (method_vpcr(handle, 0, &val))
- return -1;
- *data = val;
- return 0;
- }
- }
- 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 end_jiffies;
-
- if (method_vpcw(handle, 0, data))
- return -1;
- if (method_vpcw(handle, 1, cmd))
- return -1;
-
- for (end_jiffies = jiffies+(HZ)*IDEAPAD_EC_TIMEOUT/1000+1;
- time_before(jiffies, end_jiffies);) {
- schedule();
- if (method_vpcr(handle, 1, &val))
- return -1;
- if (val == 0)
- return 0;
- }
- 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;
- unsigned long sw_blocked;
-
- 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;
-
- if (read_ec_data(ideapad_priv->handle, ideapad_rfk_data[dev].opcode-1,
- &sw_blocked)) {
- rfkill_init_sw_state(priv->rfk[dev], 0);
- } else {
- sw_blocked = !sw_blocked;
- rfkill_init_sw_state(priv->rfk[dev], sw_blocked);
- }
-
- 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, "_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 <dwmw2@infradead.org>");
-MODULE_DESCRIPTION("IdeaPad ACPI Extras");
-MODULE_LICENSE("GPL");
-
-module_init(ideapad_acpi_module_init);
-module_exit(ideapad_acpi_module_exit);
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 9/9] ideapad: Add param: no_bt_rfkill
2010-10-01 7:37 [Resend] [PATCH 0/9] ideapad: using EC command to control rf/camera power Ike Panhc
` (7 preceding siblings ...)
2010-10-01 7:40 ` [PATCH 8/9] ideapad: Change the driver name to ideapad-laptop Ike Panhc
@ 2010-10-01 7:40 ` Ike Panhc
8 siblings, 0 replies; 10+ messages in thread
From: Ike Panhc @ 2010-10-01 7:40 UTC (permalink / raw)
To: platform-driver-x86, linux-acpi, linux-kernel
Cc: Matthew Garrett, Len Brown, Corentin Chary, David Woodhouse,
Mario.Holbe
Add new module parameter that force module not to register bluetooth rfkill.
There is report that saying using this bluetooth rfkill to enable/disable
bluetooth will let bluetooth device initial failed when enable on Lenovo
ideapad S12. Fortunately there is another rfkill registered by bluetooth
driver for S12 and user can shutdown the bluetooth by either bluetooth driver
or HW RF switch.
For dual OS user, it may have some trouble that using Linux after turning off
bluetooth with another OS if we do not register bluetooth rfkill at all. So
we will force bluetooth enable when no_bt_rfkill=1.
Signed-off-by: Ike Panhc <ike.pan@canonical.com>
Tested-by: Mario 'BitKoenig' Holbe <Mario.Holbe@TU-Ilmenau.DE>
---
drivers/platform/x86/ideapad-laptop.c | 12 ++++++++++++
1 files changed, 12 insertions(+), 0 deletions(-)
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 78ac02a..6a4396e 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -52,6 +52,10 @@ static struct {
{ "ideapad_killsw", 0, 0, RFKILL_TYPE_WLAN }
};
+static bool no_bt_rfkill;
+module_param(no_bt_rfkill, bool, 0444);
+MODULE_PARM_DESC(no_bt_rfkill, "No rfkill for bluetooth.");
+
/*
* ACPI Helpers
*/
@@ -232,6 +236,14 @@ static int ideapad_register_rfkill(struct acpi_device *adevice, int dev)
int ret;
unsigned long sw_blocked;
+ if (no_bt_rfkill &&
+ (ideapad_rfk_data[dev].type == RFKILL_TYPE_BLUETOOTH)) {
+ /* Force to enable bluetooth when no_bt_rfkill=1 */
+ write_ec_cmd(ideapad_priv->handle,
+ ideapad_rfk_data[dev].opcode, 1);
+ return 0;
+ }
+
priv->rfk[dev] = rfkill_alloc(ideapad_rfk_data[dev].name, &adevice->dev,
ideapad_rfk_data[dev].type, &ideapad_rfk_ops,
(void *)(long)dev);
--
1.7.1
^ permalink raw reply related [flat|nested] 10+ messages in thread