in master/mipi-i3c-hci/ext_caps.c [256:308]
int i3c_hci_parse_ext_caps(struct i3c_hci *hci)
{
void __iomem *curr_cap = hci->EXTCAPS_regs;
void __iomem *end = curr_cap + 0x1000; /* some arbitrary limit */
u32 cap_header, cap_id, cap_length;
const struct hci_ext_caps *cap_entry;
int i, err = 0;
if (!curr_cap)
return 0;
for (; !err && curr_cap < end; curr_cap += cap_length * 4) {
cap_header = readl(curr_cap);
cap_id = FIELD_GET(CAP_HEADER_ID, cap_header);
cap_length = FIELD_GET(CAP_HEADER_LENGTH, cap_header);
DBG("id=0x%02x length=%d", cap_id, cap_length);
if (!cap_length)
break;
if (curr_cap + cap_length * 4 >= end) {
dev_err(&hci->master.dev,
"ext_cap 0x%02x has size %d (too big)\n",
cap_id, cap_length);
err = -EINVAL;
break;
}
if (cap_id >= 0xc0 && cap_id <= 0xcf) {
err = hci_extcap_vendor_specific(hci, curr_cap,
cap_id, cap_length);
continue;
}
cap_entry = NULL;
for (i = 0; i < ARRAY_SIZE(ext_capabilities); i++) {
if (ext_capabilities[i].id == cap_id) {
cap_entry = &ext_capabilities[i];
break;
}
}
if (!cap_entry) {
dev_notice(&hci->master.dev,
"unknown ext_cap 0x%02x\n", cap_id);
} else if (cap_length < cap_entry->min_length) {
dev_err(&hci->master.dev,
"ext_cap 0x%02x has size %d (expecting >= %d)\n",
cap_id, cap_length, cap_entry->min_length);
err = -EINVAL;
} else {
err = cap_entry->parser(hci, curr_cap);
}
}
return err;
}