Browse Source

Merge branch 'acpi-scan'

* acpi-scan:
  ata: ahci_platform: Add ACPI _CLS matching
  ACPI / scan: Add support for ACPI _CLS device matching
Rafael J. Wysocki 10 years ago
parent
commit
8076ca480f

+ 30 - 2
drivers/acpi/scan.c

@@ -1019,6 +1019,29 @@ static bool acpi_of_match_device(struct acpi_device *adev,
 	return false;
 	return false;
 }
 }
 
 
+static bool __acpi_match_device_cls(const struct acpi_device_id *id,
+				    struct acpi_hardware_id *hwid)
+{
+	int i, msk, byte_shift;
+	char buf[3];
+
+	if (!id->cls)
+		return false;
+
+	/* Apply class-code bitmask, before checking each class-code byte */
+	for (i = 1; i <= 3; i++) {
+		byte_shift = 8 * (3 - i);
+		msk = (id->cls_msk >> byte_shift) & 0xFF;
+		if (!msk)
+			continue;
+
+		sprintf(buf, "%02x", (id->cls >> byte_shift) & msk);
+		if (strncmp(buf, &hwid->id[(i - 1) * 2], 2))
+			return false;
+	}
+	return true;
+}
+
 static const struct acpi_device_id *__acpi_match_device(
 static const struct acpi_device_id *__acpi_match_device(
 	struct acpi_device *device,
 	struct acpi_device *device,
 	const struct acpi_device_id *ids,
 	const struct acpi_device_id *ids,
@@ -1036,9 +1059,12 @@ static const struct acpi_device_id *__acpi_match_device(
 
 
 	list_for_each_entry(hwid, &device->pnp.ids, list) {
 	list_for_each_entry(hwid, &device->pnp.ids, list) {
 		/* First, check the ACPI/PNP IDs provided by the caller. */
 		/* First, check the ACPI/PNP IDs provided by the caller. */
-		for (id = ids; id->id[0]; id++)
-			if (!strcmp((char *) id->id, hwid->id))
+		for (id = ids; id->id[0] || id->cls; id++) {
+			if (id->id[0] && !strcmp((char *) id->id, hwid->id))
 				return id;
 				return id;
+			else if (id->cls && __acpi_match_device_cls(id, hwid))
+				return id;
+		}
 
 
 		/*
 		/*
 		 * Next, check ACPI_DT_NAMESPACE_HID and try to match the
 		 * Next, check ACPI_DT_NAMESPACE_HID and try to match the
@@ -2101,6 +2127,8 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
 		if (info->valid & ACPI_VALID_UID)
 		if (info->valid & ACPI_VALID_UID)
 			pnp->unique_id = kstrdup(info->unique_id.string,
 			pnp->unique_id = kstrdup(info->unique_id.string,
 							GFP_KERNEL);
 							GFP_KERNEL);
+		if (info->valid & ACPI_VALID_CLS)
+			acpi_add_id(pnp, info->class_code.string);
 
 
 		kfree(info);
 		kfree(info);
 
 

+ 1 - 1
drivers/ata/Kconfig

@@ -48,7 +48,7 @@ config ATA_VERBOSE_ERROR
 
 
 config ATA_ACPI
 config ATA_ACPI
 	bool "ATA ACPI Support"
 	bool "ATA ACPI Support"
-	depends on ACPI && PCI
+	depends on ACPI
 	default y
 	default y
 	help
 	help
 	  This option adds support for ATA-related ACPI objects.
 	  This option adds support for ATA-related ACPI objects.

+ 9 - 0
drivers/ata/ahci_platform.c

@@ -20,6 +20,8 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/libata.h>
 #include <linux/libata.h>
 #include <linux/ahci_platform.h>
 #include <linux/ahci_platform.h>
+#include <linux/acpi.h>
+#include <linux/pci_ids.h>
 #include "ahci.h"
 #include "ahci.h"
 
 
 #define DRV_NAME "ahci"
 #define DRV_NAME "ahci"
@@ -79,12 +81,19 @@ static const struct of_device_id ahci_of_match[] = {
 };
 };
 MODULE_DEVICE_TABLE(of, ahci_of_match);
 MODULE_DEVICE_TABLE(of, ahci_of_match);
 
 
+static const struct acpi_device_id ahci_acpi_match[] = {
+	{ ACPI_DEVICE_CLASS(PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff) },
+	{},
+};
+MODULE_DEVICE_TABLE(acpi, ahci_acpi_match);
+
 static struct platform_driver ahci_driver = {
 static struct platform_driver ahci_driver = {
 	.probe = ahci_probe,
 	.probe = ahci_probe,
 	.remove = ata_platform_remove_one,
 	.remove = ata_platform_remove_one,
 	.driver = {
 	.driver = {
 		.name = DRV_NAME,
 		.name = DRV_NAME,
 		.of_match_table = ahci_of_match,
 		.of_match_table = ahci_of_match,
+		.acpi_match_table = ahci_acpi_match,
 		.pm = &ahci_pm_ops,
 		.pm = &ahci_pm_ops,
 	},
 	},
 };
 };

+ 14 - 0
include/linux/acpi.h

@@ -58,6 +58,19 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev)
 	acpi_fwnode_handle(adev) : NULL)
 	acpi_fwnode_handle(adev) : NULL)
 #define ACPI_HANDLE(dev)		acpi_device_handle(ACPI_COMPANION(dev))
 #define ACPI_HANDLE(dev)		acpi_device_handle(ACPI_COMPANION(dev))
 
 
+/**
+ * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with
+ * the PCI-defined class-code information
+ *
+ * @_cls : the class, subclass, prog-if triple for this device
+ * @_msk : the class mask for this device
+ *
+ * This macro is used to create a struct acpi_device_id that matches a
+ * specific PCI class. The .id and .driver_data fields will be left
+ * initialized with the default value.
+ */
+#define ACPI_DEVICE_CLASS(_cls, _msk)	.cls = (_cls), .cls_msk = (_msk),
+
 static inline bool has_acpi_companion(struct device *dev)
 static inline bool has_acpi_companion(struct device *dev)
 {
 {
 	return is_acpi_node(dev->fwnode);
 	return is_acpi_node(dev->fwnode);
@@ -443,6 +456,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *);
 #define ACPI_COMPANION(dev)		(NULL)
 #define ACPI_COMPANION(dev)		(NULL)
 #define ACPI_COMPANION_SET(dev, adev)	do { } while (0)
 #define ACPI_COMPANION_SET(dev, adev)	do { } while (0)
 #define ACPI_HANDLE(dev)		(NULL)
 #define ACPI_HANDLE(dev)		(NULL)
+#define ACPI_DEVICE_CLASS(_cls, _msk)	.cls = (0), .cls_msk = (0),
 
 
 struct fwnode_handle;
 struct fwnode_handle;
 
 

+ 2 - 0
include/linux/mod_devicetable.h

@@ -189,6 +189,8 @@ struct css_device_id {
 struct acpi_device_id {
 struct acpi_device_id {
 	__u8 id[ACPI_ID_LEN];
 	__u8 id[ACPI_ID_LEN];
 	kernel_ulong_t driver_data;
 	kernel_ulong_t driver_data;
+	__u32 cls;
+	__u32 cls_msk;
 };
 };
 
 
 #define PNP_ID_LEN	8
 #define PNP_ID_LEN	8

+ 2 - 0
scripts/mod/devicetable-offsets.c

@@ -63,6 +63,8 @@ int main(void)
 
 
 	DEVID(acpi_device_id);
 	DEVID(acpi_device_id);
 	DEVID_FIELD(acpi_device_id, id);
 	DEVID_FIELD(acpi_device_id, id);
+	DEVID_FIELD(acpi_device_id, cls);
+	DEVID_FIELD(acpi_device_id, cls_msk);
 
 
 	DEVID(pnp_device_id);
 	DEVID(pnp_device_id);
 	DEVID_FIELD(pnp_device_id, id);
 	DEVID_FIELD(pnp_device_id, id);

+ 30 - 2
scripts/mod/file2alias.c

@@ -523,12 +523,40 @@ static int do_serio_entry(const char *filename,
 }
 }
 ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry);
 ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry);
 
 
-/* looks like: "acpi:ACPI0003 or acpi:PNP0C0B" or "acpi:LNXVIDEO" */
+/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or
+ *             "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if)
+ *
+ * NOTE: Each driver should use one of the following : _HID, _CIDs
+ *       or _CLS. Also, bb, ss, and pp can be substituted with ??
+ *       as don't care byte.
+ */
 static int do_acpi_entry(const char *filename,
 static int do_acpi_entry(const char *filename,
 			void *symval, char *alias)
 			void *symval, char *alias)
 {
 {
 	DEF_FIELD_ADDR(symval, acpi_device_id, id);
 	DEF_FIELD_ADDR(symval, acpi_device_id, id);
-	sprintf(alias, "acpi*:%s:*", *id);
+	DEF_FIELD_ADDR(symval, acpi_device_id, cls);
+	DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk);
+
+	if (id && strlen((const char *)*id))
+		sprintf(alias, "acpi*:%s:*", *id);
+	else if (cls) {
+		int i, byte_shift, cnt = 0;
+		unsigned int msk;
+
+		sprintf(&alias[cnt], "acpi*:");
+		cnt = 6;
+		for (i = 1; i <= 3; i++) {
+			byte_shift = 8 * (3-i);
+			msk = (*cls_msk >> byte_shift) & 0xFF;
+			if (msk)
+				sprintf(&alias[cnt], "%02x",
+					(*cls >> byte_shift) & 0xFF);
+			else
+				sprintf(&alias[cnt], "??");
+			cnt += 2;
+		}
+		sprintf(&alias[cnt], ":*");
+	}
 	return 1;
 	return 1;
 }
 }
 ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry);
 ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry);