Loading drivers/acpi/scan.c +38 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -1032,6 +1033,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 acpi_ibm_smbus_match(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; Loading Loading @@ -1082,6 +1118,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 (!acpi_ibm_smbus_match(device)) acpi_add_id(device, ACPI_SMBUS_IBM_HID); break; case ACPI_BUS_TYPE_POWER: Loading drivers/i2c/busses/i2c-scmi.c +24 −8 Original line number Diff line number Diff line Loading @@ -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 = { Loading @@ -41,10 +42,19 @@ 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}, {"SMBUS01", (kernel_ulong_t)&smbus_methods}, {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, {"", 0} }; MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); #define ACPI_SMBUS_STATUS_OK 0x00 #define ACPI_SMBUS_STATUS_FAIL 0x07 Loading Loading @@ -150,11 +160,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; } Loading Loading @@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, union acpi_object *obj; acpi_status status; if (!strcmp(name, smbus_methods.mt_info)) { if (!strcmp(name, smbus_cmi->methods->mt_info)) { status = acpi_evaluate_object(smbus_cmi->handle, smbus_methods.mt_info, smbus_cmi->methods->mt_info, NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Evaluating %s: %i", smbus_methods.mt_info, status)); smbus_cmi->methods->mt_info, status)); return -EIO; } Loading @@ -319,9 +329,9 @@ 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)) } else if (!strcmp(name, smbus_cmi->methods->mt_sbr)) smbus_cmi->cap_read = 1; else if (!strcmp(name, smbus_methods.mt_sbw)) else if (!strcmp(name, smbus_cmi->methods->mt_sbw)) smbus_cmi->cap_write = 1; else ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", Loading Loading @@ -349,6 +359,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level, static int acpi_smbus_cmi_add(struct acpi_device *device) { struct acpi_smbus_cmi *smbus_cmi; const struct acpi_device_id *id; smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); if (!smbus_cmi) Loading @@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) smbus_cmi->cap_read = 0; smbus_cmi->cap_write = 0; for (id = acpi_smbus_cmi_ids; id->id[0]; id++) if (!strcmp(id->id, acpi_device_hid(device))) smbus_cmi->methods = (struct smbus_methods_t *) id->driver_data; acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); Loading include/acpi/acpi_drivers.h +2 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,8 @@ #define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_BAY_HID "LNXIOBAY" #define ACPI_DOCK_HID "LNXDOCK" /* Quirk for broken IBM BIOSes */ #define ACPI_SMBUS_IBM_HID "SMBUSIBM" /* * For fixed hardware buttons, we fabricate acpi_devices with HID Loading Loading
drivers/acpi/scan.c +38 −0 Original line number Diff line number Diff line Loading @@ -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> Loading Loading @@ -1032,6 +1033,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 acpi_ibm_smbus_match(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; Loading Loading @@ -1082,6 +1118,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 (!acpi_ibm_smbus_match(device)) acpi_add_id(device, ACPI_SMBUS_IBM_HID); break; case ACPI_BUS_TYPE_POWER: Loading
drivers/i2c/busses/i2c-scmi.c +24 −8 Original line number Diff line number Diff line Loading @@ -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 = { Loading @@ -41,10 +42,19 @@ 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}, {"SMBUS01", (kernel_ulong_t)&smbus_methods}, {ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods}, {"", 0} }; MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids); #define ACPI_SMBUS_STATUS_OK 0x00 #define ACPI_SMBUS_STATUS_FAIL 0x07 Loading Loading @@ -150,11 +160,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; } Loading Loading @@ -290,13 +300,13 @@ static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi, union acpi_object *obj; acpi_status status; if (!strcmp(name, smbus_methods.mt_info)) { if (!strcmp(name, smbus_cmi->methods->mt_info)) { status = acpi_evaluate_object(smbus_cmi->handle, smbus_methods.mt_info, smbus_cmi->methods->mt_info, NULL, &buffer); if (ACPI_FAILURE(status)) { ACPI_ERROR((AE_INFO, "Evaluating %s: %i", smbus_methods.mt_info, status)); smbus_cmi->methods->mt_info, status)); return -EIO; } Loading @@ -319,9 +329,9 @@ 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)) } else if (!strcmp(name, smbus_cmi->methods->mt_sbr)) smbus_cmi->cap_read = 1; else if (!strcmp(name, smbus_methods.mt_sbw)) else if (!strcmp(name, smbus_cmi->methods->mt_sbw)) smbus_cmi->cap_write = 1; else ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unsupported CMI method: %s\n", Loading Loading @@ -349,6 +359,7 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level, static int acpi_smbus_cmi_add(struct acpi_device *device) { struct acpi_smbus_cmi *smbus_cmi; const struct acpi_device_id *id; smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); if (!smbus_cmi) Loading @@ -362,6 +373,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) smbus_cmi->cap_read = 0; smbus_cmi->cap_write = 0; for (id = acpi_smbus_cmi_ids; id->id[0]; id++) if (!strcmp(id->id, acpi_device_hid(device))) smbus_cmi->methods = (struct smbus_methods_t *) id->driver_data; acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); Loading
include/acpi/acpi_drivers.h +2 −0 Original line number Diff line number Diff line Loading @@ -65,6 +65,8 @@ #define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_BAY_HID "LNXIOBAY" #define ACPI_DOCK_HID "LNXDOCK" /* Quirk for broken IBM BIOSes */ #define ACPI_SMBUS_IBM_HID "SMBUSIBM" /* * For fixed hardware buttons, we fabricate acpi_devices with HID Loading