linux-i2c.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] i2c-scmi: Quirk to work on IBM machines with broken BIOSes
@ 2009-10-20 23:11 Darrick J. Wong
  2009-10-21  2:30 ` Crane Cai
  0 siblings, 1 reply; 27+ messages in thread
From: Darrick J. Wong @ 2009-10-20 23:11 UTC (permalink / raw)
  To: crane.cai, lenb; +Cc: linux-kernel, linux-i2c, linux-acpi

On some old IBM workstations and desktop computers, the BIOS presents in the
DSDT an SMBus object that is missing the HID identifier that the i2c-scmi
driver looks for.  It also omits the leading "_" in the method names (it should
be _SBR, not SBR_).  Modify the ACPI device scan code to insert the missing HID
if it finds an IBM system with such an object, and modify the i2c-scmi driver
to handle the odd method names.

Affected machines: IntelliStation Z20/Z30.  Note that the i2c-i801 driver no
longer works on these machines because of ACPI resource conflicts.

Signed-off-by: Darrick J. Wong <djwong@us.ibm.com>
---

 drivers/acpi/scan.c           |   38 ++++++++++++++++++++++++++++++++
 drivers/i2c/busses/i2c-scmi.c |   49 ++++++++++++++++++++++++++++++++---------
 include/acpi/acpi_drivers.h   |    1 +
 3 files changed, 77 insertions(+), 11 deletions(-)


diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 14a7481..58cb324 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -8,6 +8,7 @@
 #include <linux/acpi.h>
 #include <linux/signal.h>
 #include <linux/kthread.h>
+#include <linux/dmi.h>
 
 #include <acpi/acpi_drivers.h>
 
@@ -1014,6 +1015,41 @@ static void acpi_add_id(struct acpi_device *device, const char *dev_id)
 	list_add_tail(&id->list, &device->pnp.ids);
 }
 
+/*
+ * Old IBM workstations have a DSDT bug wherein the SMBus object
+ * lacks the SMBUS01 HID and the methods do not have the necessary "_"
+ * prefix.  Work around this.
+ */
+static int probe_ibm_smbus_device(struct acpi_device *device)
+{
+	acpi_handle h_dummy;
+	struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+	int result;
+
+	if (!dmi_name_in_vendors("IBM"))
+		return -ENODEV;
+
+	/* Look for SMBS object */
+	result = acpi_get_name(device->handle, ACPI_SINGLE_NAME, &path);
+	if (result)
+		return result;
+
+	if (strcmp("SMBS", path.pointer)) {
+		result = -ENODEV;
+		goto out;
+	}
+
+	/* Does it have the necessary (but misnamed) methods? */
+	result = -ENODEV;
+	if (ACPI_SUCCESS(acpi_get_handle(device->handle, "SBI", &h_dummy)) &&
+	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBR", &h_dummy)) &&
+	    ACPI_SUCCESS(acpi_get_handle(device->handle, "SBW", &h_dummy)))
+		result = 0;
+out:
+	kfree(path.pointer);
+	return result;
+}
+
 static void acpi_device_set_id(struct acpi_device *device)
 {
 	acpi_status status;
@@ -1064,6 +1100,8 @@ static void acpi_device_set_id(struct acpi_device *device)
 			acpi_add_id(device, ACPI_BAY_HID);
 		else if (ACPI_SUCCESS(acpi_dock_match(device)))
 			acpi_add_id(device, ACPI_DOCK_HID);
+		else if (!probe_ibm_smbus_device(device))
+			acpi_add_id(device, ACPI_SMBUS_HID);
 
 		break;
 	case ACPI_BUS_TYPE_POWER:
diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c
index b4a55d4..f0ad03d 100644
--- a/drivers/i2c/busses/i2c-scmi.c
+++ b/drivers/i2c/busses/i2c-scmi.c
@@ -33,6 +33,7 @@ struct acpi_smbus_cmi {
 	u8 cap_info:1;
 	u8 cap_read:1;
 	u8 cap_write:1;
+	struct smbus_methods_t methods;
 };
 
 static const struct smbus_methods_t smbus_methods = {
@@ -41,8 +42,15 @@ static const struct smbus_methods_t smbus_methods = {
 	.mt_sbw  = "_SBW",
 };
 
+/* Some IBM BIOSes omit the leading underscore */
+static const struct smbus_methods_t ibm_smbus_methods = {
+	.mt_info = "SBI_",
+	.mt_sbr  = "SBR_",
+	.mt_sbw  = "SBW_",
+};
+
 static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
-	{"SMBUS01", 0},
+	{ACPI_SMBUS_HID, 0},
 	{"", 0}
 };
 
@@ -150,11 +158,11 @@ acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
 
 	if (read_write == I2C_SMBUS_READ) {
 		protocol |= ACPI_SMBUS_PRTCL_READ;
-		method = smbus_methods.mt_sbr;
+		method = smbus_cmi->methods.mt_sbr;
 		input.count = 3;
 	} else {
 		protocol |= ACPI_SMBUS_PRTCL_WRITE;
-		method = smbus_methods.mt_sbw;
+		method = smbus_cmi->methods.mt_sbw;
 		input.count = 5;
 	}
 
@@ -283,20 +291,21 @@ static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
 };
 
 
-static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
-				  const char *name)
+static int acpi_smbus_cmi_probe_cap(struct acpi_smbus_cmi *smbus_cmi,
+				    const char *name,
+				    const struct smbus_methods_t *methods)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *obj;
 	acpi_status status;
 
-	if (!strcmp(name, smbus_methods.mt_info)) {
+	if (!strcmp(name, methods->mt_info)) {
 		status = acpi_evaluate_object(smbus_cmi->handle,
-					smbus_methods.mt_info,
+					methods->mt_info,
 					NULL, &buffer);
 		if (ACPI_FAILURE(status)) {
 			ACPI_ERROR((AE_INFO, "Evaluating %s: %i",
-				   smbus_methods.mt_info, status));
+				   methods->mt_info, status));
 			return -EIO;
 		}
 
@@ -319,17 +328,35 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
 
 		kfree(buffer.pointer);
 		smbus_cmi->cap_info = 1;
-	} else if (!strcmp(name, smbus_methods.mt_sbr))
+		smbus_cmi->methods.mt_info = methods->mt_info;
+	} else if (!strcmp(name, methods->mt_sbr)) {
 		smbus_cmi->cap_read = 1;
-	else if (!strcmp(name, smbus_methods.mt_sbw))
+		smbus_cmi->methods.mt_sbr = methods->mt_sbr;
+	} else if (!strcmp(name, methods->mt_sbw)) {
 		smbus_cmi->cap_write = 1;
-	else
+		smbus_cmi->methods.mt_sbw = methods->mt_sbw;
+	} else {
 		ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n",
 				 name));
+		return -ENODEV;
+	}
 
 	return 0;
 }
 
+static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
+				  const char *name)
+{
+	int res;
+
+	res = acpi_smbus_cmi_probe_cap(smbus_cmi, name, &smbus_methods);
+	if (!res)
+		return 0;
+
+	res = acpi_smbus_cmi_probe_cap(smbus_cmi, name, &ibm_smbus_methods);
+	return res;
+}
+
 static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
 			void *context, void **return_value)
 {
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index f4906f6..c724a08 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -65,6 +65,7 @@
 #define ACPI_VIDEO_HID			"LNXVIDEO"
 #define ACPI_BAY_HID			"LNXIOBAY"
 #define ACPI_DOCK_HID			"LNXDOCK"
+#define ACPI_SMBUS_HID			"SMBUS01"
 
 /*
  * For fixed hardware buttons, we fabricate acpi_devices with HID

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2010-01-05 12:30 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-20 23:11 [PATCH] i2c-scmi: Quirk to work on IBM machines with broken BIOSes Darrick J. Wong
2009-10-21  2:30 ` Crane Cai
2009-10-21 14:57   ` Bjorn Helgaas
     [not found]     ` <200910210857.13978.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
2009-10-21 17:37       ` Darrick J. Wong
2009-10-22  7:17         ` Crane Cai
2009-10-22 17:43           ` Darrick J. Wong
2009-10-22 18:37             ` Jean Delvare
2009-10-23  4:44             ` Crane Cai
2009-10-23 17:03               ` [PATCH 1/2] i2c-scmi: support IBM SMBus CMI devices Darrick J. Wong
     [not found]                 ` <20091023170306.GP26149-bjhdApgbSaxhsM67afOH+sxtgHpCUUYS@public.gmane.org>
2009-10-25  9:39                   ` Jean Delvare
     [not found]                     ` <20091025103932.31ce9a6d-ig7AzVSIIG7kN2dkZ6Wm7A@public.gmane.org>
2009-10-26  2:54                       ` Crane Cai
2009-10-23 17:03               ` [PATCH 2/2] acpi: " Darrick J. Wong
2009-10-25 11:53                 ` Jean Delvare
2009-10-26 20:53                   ` Darrick J. Wong
2009-10-26 20:58                   ` [PATCH v2 1/2] " Darrick J. Wong
2009-10-27 17:03                     ` Jean Delvare
2009-10-27 17:30                       ` Darrick J. Wong
     [not found]                         ` <20091027173001.GT26149-bjhdApgbSaxhsM67afOH+sxtgHpCUUYS@public.gmane.org>
2009-10-27 17:36                           ` Jean Delvare
2009-12-04 17:06                             ` Darrick J. Wong
     [not found]                               ` <20091204170621.GA10356-bjhdApgbSaxhsM67afOH+sxtgHpCUUYS@public.gmane.org>
2009-12-04 17:36                                 ` Bjorn Helgaas
     [not found]                                   ` <200912041036.36686.bjorn.helgaas-VXdhtT5mjnY@public.gmane.org>
2009-12-04 18:07                                     ` Darrick J. Wong
2009-12-04 18:11                                     ` [RESEND PATCH v2 1/2] ACPI: Quirk to make SMBus objects work on IBM machines with broken BIOSes Darrick J. Wong
2009-12-17 14:02                                       ` Jean Delvare
2010-01-05 12:30                                         ` Jean Delvare
2009-12-04 18:13                                     ` [RESEND PATCH v2 2/2] i2c-scmi: support IBM SMBus CMI devices Darrick J. Wong
2009-10-26 21:00                   ` [PATCH " Darrick J. Wong
2009-10-27 17:24                     ` Jean Delvare

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).