acpi_device_id 其实是有四个变量组成的,定义如下:
struct acpi_device_id {
__u8 id[ACPI_ID_LEN];
kernel_ulong_t driver_data;
__u32 cls;
__u32 cls_msk;
};
但是我们一般定义的时候
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ }
};
一般只要acpi_device_id 中的id 匹配即可,但是如果有两份driver 对应同一个id的话,则可以比较cls的的方式解决,例如上例子中的
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
直接上code
static const struct acpi_device_id *__acpi_match_device(
struct acpi_device *device,
const struct acpi_device_id *ids,
const struct of_device_id *of_ids)
{
const struct acpi_device_id *id;
struct acpi_hardware_id *hwid;
/*
* If the device is not present, it is unnecessary to load device
* driver for it.
*/
if (!device || !device->status.present)
return NULL;
list_for_each_entry(hwid, &device->pnp.ids, list) {
/* First, check the ACPI/PNP IDs provided by the caller. */
for (id = ids; id->id[0] || id->cls; id++) {
//本例子中的if条件中的strcmp 匹配失败。走else的case 匹配成功
if (id->id[0] && !strcmp((char *) id->id, hwid->id))
return id;
else if (id->cls && __acpi_match_device_cls(id, hwid))
return id;
}
}
return NULL;
}
从__acpi_match_device_cls 中看如果要用cls匹配的话,需要一定的规则。
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);
本例中id->cls_msk =4
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;
}
本例子中匹配的调价i=1/2/3.则hwid->id[(i - 1) * 2]
当i=1 :msk=4>>16 & 0xff =0
当i=2 :msk=4>>8 & 0xff =0
当i=3 :msk=4>>0 & 0xff =4 id[(i - 1) * 2]=id[4],则比较的是01
struct acpi_device_id {
__u8 id[ACPI_ID_LEN];
kernel_ulong_t driver_data;
__u32 cls;
__u32 cls_msk;
};
但是我们一般定义的时候
static const struct acpi_device_id dw_i2c_acpi_match[] = {
{ "INT33C2", 0 },
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
{ }
};
一般只要acpi_device_id 中的id 匹配即可,但是如果有两份driver 对应同一个id的话,则可以比较cls的的方式解决,例如上例子中的
{ "AMD0010", ACCESS_INTR_MASK },
{ "AMDI0010", ACCESS_INTR_MASK },
直接上code
static const struct acpi_device_id *__acpi_match_device(
struct acpi_device *device,
const struct acpi_device_id *ids,
const struct of_device_id *of_ids)
{
const struct acpi_device_id *id;
struct acpi_hardware_id *hwid;
/*
* If the device is not present, it is unnecessary to load device
* driver for it.
*/
if (!device || !device->status.present)
return NULL;
list_for_each_entry(hwid, &device->pnp.ids, list) {
/* First, check the ACPI/PNP IDs provided by the caller. */
for (id = ids; id->id[0] || id->cls; id++) {
//本例子中的if条件中的strcmp 匹配失败。走else的case 匹配成功
if (id->id[0] && !strcmp((char *) id->id, hwid->id))
return id;
else if (id->cls && __acpi_match_device_cls(id, hwid))
return id;
}
}
return NULL;
}
从__acpi_match_device_cls 中看如果要用cls匹配的话,需要一定的规则。
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);
本例中id->cls_msk =4
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;
}
本例子中匹配的调价i=1/2/3.则hwid->id[(i - 1) * 2]
当i=1 :msk=4>>16 & 0xff =0
当i=2 :msk=4>>8 & 0xff =0
当i=3 :msk=4>>0 & 0xff =4 id[(i - 1) * 2]=id[4],则比较的是01
则为匹配kernel中的AMDI0010,bios传递的id应该从4开始为01即可,例如AMDXI0100
所以这里的cls就是规定从id中那个那个字符开始比较,最多比较2个字符。