mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Greg Kroah-Hartman <gregkh@suse.de>
To: linux-kernel@vger.kernel.org
Cc: "Lee, Chun-Yi" <jlee@novell.com>,
	Lennart Poettering <mzxreary@0pointer.de>,
	Greg Kroah-Hartman <gregkh@suse.de>
Subject: [PATCH 58/62] msi-laptop: Support some MSI 3G netbook that is need load SCM
Date: Tue,  2 Mar 2010 15:28:57 -0800	[thread overview]
Message-ID: <1267572541-410-58-git-send-email-gregkh@suse.de> (raw)
In-Reply-To: <20100302230933.GA32287@kroah.com>

From: Lee, Chun-Yi <jlee@novell.com>

Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
those netbook will load the SCM (windows app) to disable the original
Wlan/Bluetooth control by BIOS when user press fn key, then control
Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
cann't on/off 3G module on those 3G netbook.
On Linux, msi-laptop driver will do the same thing to disable the
original BIOS control, then might need use HAL or other userland
application to do the software control that simulate with SCM.
e.g. MSI N034 netbook

Signed-off-by: Lee, Chun-Yi <jlee@novell.com>
Cc: Lennart Poettering <mzxreary@0pointer.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
---
 drivers/platform/x86/msi-laptop.c |  238 +++++++++++++++++++++++++++++++++++++
 1 files changed, 238 insertions(+), 0 deletions(-)

diff --git a/drivers/platform/x86/msi-laptop.c b/drivers/platform/x86/msi-laptop.c
index 1784d55..ff21d1a 100644
--- a/drivers/platform/x86/msi-laptop.c
+++ b/drivers/platform/x86/msi-laptop.c
@@ -58,6 +58,7 @@
 #include <linux/dmi.h>
 #include <linux/backlight.h>
 #include <linux/platform_device.h>
+#include <linux/rfkill.h>
 
 #define MSI_DRIVER_VERSION "0.5"
 
@@ -72,6 +73,10 @@
 #define MSI_STANDARD_EC_WLAN_MASK	(1 << 3)
 #define MSI_STANDARD_EC_3G_MASK		(1 << 4)
 
+/* For set SCM load flag to disable BIOS fn key */
+#define MSI_STANDARD_EC_SCM_LOAD_ADDRESS	0x2d
+#define MSI_STANDARD_EC_SCM_LOAD_MASK		(1 << 0)
+
 static int force;
 module_param(force, bool, 0);
 MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
@@ -83,6 +88,19 @@ MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disab
 static bool old_ec_model;
 static int wlan_s, bluetooth_s, threeg_s;
 
+/* Some MSI 3G netbook only have one fn key to control Wlan/Bluetooth/3G,
+ * those netbook will load the SCM (windows app) to disable the original
+ * Wlan/Bluetooth control by BIOS when user press fn key, then control
+ * Wlan/Bluetooth/3G by SCM (software control by OS). Without SCM, user
+ * cann't on/off 3G module on those 3G netbook.
+ * On Linux, msi-laptop driver will do the same thing to disable the
+ * original BIOS control, then might need use HAL or other userland
+ * application to do the software control that simulate with SCM.
+ * e.g. MSI N034 netbook
+ */
+static bool load_scm_model;
+static struct rfkill *rfk_wlan, *rfk_bluetooth, *rfk_threeg;
+
 /* Hardware access */
 
 static int set_lcd_level(int level)
@@ -139,6 +157,35 @@ static int set_auto_brightness(int enable)
 	return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 2, NULL, 0, 1);
 }
 
+static ssize_t set_device_state(const char *buf, size_t count, u8 mask)
+{
+	int status;
+	u8 wdata = 0, rdata;
+	int result;
+
+	if (sscanf(buf, "%i", &status) != 1 || (status < 0 || status > 1))
+		return -EINVAL;
+
+	/* read current device state */
+	result = ec_read(MSI_STANDARD_EC_COMMAND_ADDRESS, &rdata);
+	if (result < 0)
+		return -EINVAL;
+
+	if (!!(rdata & mask) != status) {
+		/* reverse device bit */
+		if (rdata & mask)
+			wdata = rdata & ~mask;
+		else
+			wdata = rdata | mask;
+
+		result = ec_write(MSI_STANDARD_EC_COMMAND_ADDRESS, wdata);
+		if (result < 0)
+			return -EINVAL;
+	}
+
+	return count;
+}
+
 static int get_wireless_state(int *wlan, int *bluetooth)
 {
 	u8 wdata = 0, rdata;
@@ -215,6 +262,12 @@ static ssize_t show_wlan(struct device *dev,
 	return sprintf(buf, "%i\n", enabled);
 }
 
+static ssize_t store_wlan(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	return set_device_state(buf, count, MSI_STANDARD_EC_WLAN_MASK);
+}
+
 static ssize_t show_bluetooth(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -233,6 +286,12 @@ static ssize_t show_bluetooth(struct device *dev,
 	return sprintf(buf, "%i\n", enabled);
 }
 
+static ssize_t store_bluetooth(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	return set_device_state(buf, count, MSI_STANDARD_EC_BLUETOOTH_MASK);
+}
+
 static ssize_t show_threeg(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -250,6 +309,12 @@ static ssize_t show_threeg(struct device *dev,
 	return sprintf(buf, "%i\n", threeg_s);
 }
 
+static ssize_t store_threeg(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	return set_device_state(buf, count, MSI_STANDARD_EC_3G_MASK);
+}
+
 static ssize_t show_lcd_level(struct device *dev,
 	struct device_attribute *attr, char *buf)
 {
@@ -387,6 +452,169 @@ static struct dmi_system_id __initdata msi_dmi_table[] = {
 	{ }
 };
 
+static struct dmi_system_id __initdata msi_load_scm_models_dmi_table[] = {
+	{
+		.ident = "MSI N034",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR,
+				"MICRO-STAR INTERNATIONAL CO., LTD"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "MS-N034"),
+			DMI_MATCH(DMI_CHASSIS_VENDOR,
+			"MICRO-STAR INTERNATIONAL CO., LTD")
+		},
+		.callback = dmi_check_cb
+	},
+	{ }
+};
+
+static int rfkill_bluetooth_set(void *data, bool blocked)
+{
+	/* Do something with blocked...*/
+	/*
+	 * blocked == false is on
+	 * blocked == true is off
+	 */
+	if (blocked)
+		set_device_state("0", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+	else
+		set_device_state("1", 0, MSI_STANDARD_EC_BLUETOOTH_MASK);
+
+	return 0;
+}
+
+static int rfkill_wlan_set(void *data, bool blocked)
+{
+	if (blocked)
+		set_device_state("0", 0, MSI_STANDARD_EC_WLAN_MASK);
+	else
+		set_device_state("1", 0, MSI_STANDARD_EC_WLAN_MASK);
+
+	return 0;
+}
+
+static int rfkill_threeg_set(void *data, bool blocked)
+{
+	if (blocked)
+		set_device_state("0", 0, MSI_STANDARD_EC_3G_MASK);
+	else
+		set_device_state("1", 0, MSI_STANDARD_EC_3G_MASK);
+
+	return 0;
+}
+
+static struct rfkill_ops rfkill_bluetooth_ops = {
+	.set_block = rfkill_bluetooth_set
+};
+
+static struct rfkill_ops rfkill_wlan_ops = {
+	.set_block = rfkill_wlan_set
+};
+
+static struct rfkill_ops rfkill_threeg_ops = {
+	.set_block = rfkill_threeg_set
+};
+
+static void rfkill_cleanup(void)
+{
+	if (rfk_bluetooth) {
+		rfkill_unregister(rfk_bluetooth);
+		rfkill_destroy(rfk_bluetooth);
+	}
+
+	if (rfk_threeg) {
+		rfkill_unregister(rfk_threeg);
+		rfkill_destroy(rfk_threeg);
+	}
+
+	if (rfk_wlan) {
+		rfkill_unregister(rfk_wlan);
+		rfkill_destroy(rfk_wlan);
+	}
+}
+
+static int rfkill_init(struct platform_device *sdev)
+{
+	/* add rfkill */
+	int retval;
+
+	rfk_bluetooth = rfkill_alloc("msi-bluetooth", &sdev->dev,
+				RFKILL_TYPE_BLUETOOTH,
+				&rfkill_bluetooth_ops, NULL);
+	if (!rfk_bluetooth) {
+		retval = -ENOMEM;
+		goto err_bluetooth;
+	}
+	retval = rfkill_register(rfk_bluetooth);
+	if (retval)
+		goto err_bluetooth;
+
+	rfk_wlan = rfkill_alloc("msi-wlan", &sdev->dev, RFKILL_TYPE_WLAN,
+				&rfkill_wlan_ops, NULL);
+	if (!rfk_wlan) {
+		retval = -ENOMEM;
+		goto err_wlan;
+	}
+	retval = rfkill_register(rfk_wlan);
+	if (retval)
+		goto err_wlan;
+
+	rfk_threeg = rfkill_alloc("msi-threeg", &sdev->dev, RFKILL_TYPE_WWAN,
+				&rfkill_threeg_ops, NULL);
+	if (!rfk_threeg) {
+		retval = -ENOMEM;
+		goto err_threeg;
+	}
+	retval = rfkill_register(rfk_threeg);
+	if (retval)
+		goto err_threeg;
+
+	return 0;
+
+err_threeg:
+	rfkill_destroy(rfk_threeg);
+	if (rfk_wlan)
+		rfkill_unregister(rfk_wlan);
+err_wlan:
+	rfkill_destroy(rfk_wlan);
+	if (rfk_bluetooth)
+		rfkill_unregister(rfk_bluetooth);
+err_bluetooth:
+	rfkill_destroy(rfk_bluetooth);
+
+	return retval;
+}
+
+static int load_scm_model_init(struct platform_device *sdev)
+{
+	u8 data;
+	int result;
+
+	/* allow userland write sysfs file  */
+	dev_attr_bluetooth.store = store_bluetooth;
+	dev_attr_wlan.store = store_wlan;
+	dev_attr_threeg.store = store_threeg;
+	dev_attr_bluetooth.attr.mode |= S_IWUSR;
+	dev_attr_wlan.attr.mode |= S_IWUSR;
+	dev_attr_threeg.attr.mode |= S_IWUSR;
+
+	/* disable hardware control by fn key */
+	result = ec_read(MSI_STANDARD_EC_SCM_LOAD_ADDRESS, &data);
+	if (result < 0)
+		return result;
+
+	result = ec_write(MSI_STANDARD_EC_SCM_LOAD_ADDRESS,
+		data | MSI_STANDARD_EC_SCM_LOAD_MASK);
+	if (result < 0)
+		return result;
+
+	/* initial rfkill */
+	result = rfkill_init(sdev);
+	if (result < 0)
+		return result;
+
+	return 0;
+}
+
 static int __init msi_init(void)
 {
 	int ret;
@@ -397,6 +625,9 @@ static int __init msi_init(void)
 	if (force || dmi_check_system(msi_dmi_table))
 		old_ec_model = 1;
 
+	if (!old_ec_model && dmi_check_system(msi_load_scm_models_dmi_table))
+		load_scm_model = 1;
+
 	if (auto_brightness < 0 || auto_brightness > 2)
 		return -EINVAL;
 
@@ -429,6 +660,11 @@ static int __init msi_init(void)
 	if (ret)
 		goto fail_platform_device1;
 
+	if (load_scm_model && (load_scm_model_init(msipf_device) < 0)) {
+		ret = -EINVAL;
+		goto fail_platform_device1;
+	}
+
 	ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
 	if (ret)
 		goto fail_platform_device2;
@@ -479,6 +715,8 @@ static void __exit msi_cleanup(void)
 	platform_driver_unregister(&msipf_driver);
 	backlight_device_unregister(msibl_device);
 
+	rfkill_cleanup();
+
 	/* Enable automatic brightness control again */
 	if (auto_brightness != 2)
 		set_auto_brightness(1);
-- 
1.7.0.1


  parent reply	other threads:[~2010-03-02 23:32 UTC|newest]

Thread overview: 95+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-03-02 23:09 [GIT PATCH] driver core patches for 2.6.33-git Greg KH
2010-03-02 23:28 ` [PATCH 01/62] kobject-example: Spelling fixes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 02/62] kset-example: " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 03/62] Driver core: add platform_create_bundle() helper Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 04/62] driver core: make platform_device_id table const Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 05/62] sysdev: Pass attribute in sysdev_class attributes show/store Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 06/62] sysdev: Convert node driver class attributes to be data driven Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 07/62] sysdev: Convert cpu driver sysdev class attributes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 08/62] sysfs: Add sysfs_add/remove_files utility functions Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 09/62] sysfs: Add attribute array to sysdev classes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 10/62] sysdev: Convert node driver Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 11/62] sysdev: Use sysdev_class attribute arrays in " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 12/62] sysdev: Add sysdev_create/remove_files Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 13/62] sysdev: Fix type of sysdev class attribute in memory driver Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 14/62] sysdev: fix missing s390 conversion Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 15/62] driver-core: Add attribute argument to class_attribute show/store Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 16/62] driver core: Add class_attr_string for simple read-only string Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 17/62] driver core: Convert some drivers to CLASS_ATTR_STRING Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 18/62] Driver-Core: devtmpfs - reset inode permissions before unlinking Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 19/62] Driver-Core: devtmpfs - remove EXPERIMENTAL and enable it by default Greg Kroah-Hartman
2010-03-03  4:38   ` Eric W. Biederman
2010-03-03 16:46     ` Linus Torvalds
2010-03-03 20:03       ` Kay Sievers
2010-03-03 20:21         ` Eric W. Biederman
2010-03-03 22:01           ` Kay Sievers
2010-03-03 21:22       ` Greg KH
2010-03-03 21:48         ` Linus Torvalds
2010-03-03 22:04           ` Greg KH
2010-03-04  0:04             ` Linus Torvalds
2010-03-02 23:28 ` [PATCH 20/62] Driver-Core: disable /sbin/hotplug " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 21/62] Driver-Core: require valid action string in uevent trigger Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 22/62] sysfs: Cache the last sysfs_dirent to improve readdir scalability v2 Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 23/62] driver-core: firmware_class: remove base.h header inclusion Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 24/62] kobject: Constify struct kset_uevent_ops Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 25/62] HOWTO: Updates on subsystem trees, patchwork, -next (vs. -mm) Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 26/62] sysdev: fix up the probe/release attributes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 27/62] Driver core: Constify struct sysfs_ops in struct kobj_type Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 28/62] Driver core: make struct platform_driver.id_table const Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 29/62] platform-drivers: move probe to .devinit.text in arch/arm Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 30/62] platform-drivers: move probe to .devinit.text in drivers/scsi Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 32/62] x86: move hp-wmi's probe function to .devinit.text Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 33/62] i2c: move i2c_omap's " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 34/62] w1: move omap_hdq's " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 35/62] media: move omap24xxcam's " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 36/62] auxdisplay: move cfag12864bfb's " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 37/62] net: move am79c961's " Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 38/62] UIO: Add a driver for Hilscher netX-based fieldbus cards Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 39/62] UIO: minor Kconfig fixes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 40/62] UIO: Remove SMX Cryptengine driver Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 41/62] Driver core: Fix first line of kernel-doc for a few functions Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 42/62] sysfs: Remove sysfs_get/put_active_two Greg Kroah-Hartman
2010-03-03  1:34   ` Tejun Heo
2010-03-02 23:28 ` [PATCH 43/62] sysfs: Only take active references on attributes Greg Kroah-Hartman
2010-03-03  1:36   ` Tejun Heo
2010-03-02 23:28 ` [PATCH 44/62] sysfs: Use one lockdep class per sysfs attribute Greg Kroah-Hartman
2010-03-03  1:41   ` Tejun Heo
2010-03-02 23:28 ` [PATCH 45/62] sysfs: Use sysfs_attr_init and sysfs_bin_attr_init on dynamic attributes Greg Kroah-Hartman
2010-03-03  1:41   ` Tejun Heo
2010-03-02 23:28 ` [PATCH 46/62] sysfs: Document sysfs_attr_init and sysfs_bin_attr_init Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 47/62] sysfs: Use sysfs_attr_init and sysfs_bin_attr_init on module dynamic attributes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 48/62] sysfs: windfarm: init sysfs attributes Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 49/62] sysfs: Serialize updates to the vfs inode Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 50/62] sysfs: Pack sysfs_dirent more tightly Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 51/62] sysfs: Implement sysfs_rename_link Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 52/62] driver core: Use sysfs_rename_link in device_rename Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 53/62] sysfs: Pass super_block to sysfs_get_inode Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 54/62] sysfs: Kill unused sysfs_sb variable Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 56/62] msi-laptop: Support standard ec 66/62 command on MSI notebook and nebook Greg Kroah-Hartman
2010-03-02 23:42   ` Matthew Garrett
2010-03-02 23:58     ` Greg KH
2010-03-03 13:47       ` Matthew Garrett
2010-03-02 23:28 ` [PATCH 57/62] msi-laptop: Add threeg sysfs file for support query 3G state by standard 66/62 ec command Greg Kroah-Hartman
2010-03-02 23:36   ` Matthew Garrett
2010-03-02 23:47     ` Greg KH
2010-03-03 13:46       ` Matthew Garrett
2010-03-02 23:28 ` Greg Kroah-Hartman [this message]
2010-03-02 23:39   ` [PATCH 58/62] msi-laptop: Support some MSI 3G netbook that is need load SCM Matthew Garrett
2010-03-02 23:46     ` Greg KH
2010-03-02 23:28 ` [PATCH 59/62] msi-laptop: Add resume method for set the SCM load again Greg Kroah-Hartman
2010-03-02 23:28 ` [PATCH 60/62] msi-laptop: Detect 3G device exists by standard ec command Greg Kroah-Hartman
2010-03-02 23:29 ` [PATCH 61/62] msi-laptop: depends on RFKILL Greg Kroah-Hartman
2010-03-03  6:09   ` Dmitry Torokhov
2010-03-03 21:23     ` Greg KH
2010-03-02 23:29 ` [PATCH 62/62] sysfs: fix for thinko with sysfs_bin_attr_init() Greg Kroah-Hartman
2010-03-08 14:12 ` [GIT PATCH] driver core patches for 2.6.33-git Greg KH
2010-03-08 17:28   ` Linus Torvalds
2010-03-08 17:33     ` Greg KH
2010-03-03  4:52 [PATCH 58/62] msi-laptop: Support some MSI 3G netbook that is need load SCM Joey Lee
2010-03-03 13:45 ` Matthew Garrett
2010-03-04 17:07 Joey Lee
2010-03-04 17:09 ` Matthew Garrett
2010-03-05  6:10 Joey Lee
2010-03-09 12:42 Joey Lee
2010-03-09 21:01 ` Greg KH
2010-03-09 21:14   ` Matthew Garrett

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1267572541-410-58-git-send-email-gregkh@suse.de \
    --to=gregkh@suse.de \
    --cc=jlee@novell.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mzxreary@0pointer.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

Powered by JetHome