diff options
Diffstat (limited to 'drivers/acpi/scan.c')
| -rw-r--r-- | drivers/acpi/scan.c | 51 | 
1 files changed, 45 insertions, 6 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fb7fc24fe72..0338f513a01 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -4,10 +4,12 @@  #include <linux/module.h>  #include <linux/init.h> +#include <linux/slab.h>  #include <linux/kernel.h>  #include <linux/acpi.h>  #include <linux/signal.h>  #include <linux/kthread.h> +#include <linux/dmi.h>  #include <acpi/acpi_drivers.h> @@ -1032,6 +1034,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; @@ -1044,12 +1081,6 @@ static void acpi_device_set_id(struct acpi_device *device)  		if (ACPI_IS_ROOT_DEVICE(device)) {  			acpi_add_id(device, ACPI_SYSTEM_HID);  			break; -		} else if (ACPI_IS_ROOT_DEVICE(device->parent)) { -			/* \_SB_, the only root-level namespace device */ -			acpi_add_id(device, ACPI_BUS_HID); -			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); -			strcpy(device->pnp.device_class, ACPI_BUS_CLASS); -			break;  		}  		status = acpi_get_object_info(device->handle, &info); @@ -1082,6 +1113,14 @@ 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); +		else if (!acpi_device_hid(device) && +			 ACPI_IS_ROOT_DEVICE(device->parent)) { +			acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ +			strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); +			strcpy(device->pnp.device_class, ACPI_BUS_CLASS); +		}  		break;  	case ACPI_BUS_TYPE_POWER:  |