in wdat_wdt.c [114:202]
static int wdat_wdt_run_action(struct wdat_wdt *wdat, unsigned int action,
u32 param, u32 *retval)
{
struct wdat_instruction *instr;
if (action >= ARRAY_SIZE(wdat->instructions))
return -EINVAL;
if (!wdat->instructions[action])
return -EOPNOTSUPP;
dev_dbg(&wdat->pdev->dev, "Running action %#x\n", action);
/* Run each instruction sequentially */
list_for_each_entry(instr, wdat->instructions[action], node) {
const struct acpi_wdat_entry *entry = &instr->entry;
const struct acpi_generic_address *gas;
u32 flags, value, mask, x, y;
bool preserve;
int ret;
gas = &entry->register_region;
preserve = entry->instruction & ACPI_WDAT_PRESERVE_REGISTER;
flags = entry->instruction & ~ACPI_WDAT_PRESERVE_REGISTER;
value = entry->value;
mask = entry->mask;
switch (flags) {
case ACPI_WDAT_READ_VALUE:
ret = wdat_wdt_read(wdat, instr, &x);
if (ret)
return ret;
x >>= gas->bit_offset;
x &= mask;
if (retval)
*retval = x == value;
break;
case ACPI_WDAT_READ_COUNTDOWN:
ret = wdat_wdt_read(wdat, instr, &x);
if (ret)
return ret;
x >>= gas->bit_offset;
x &= mask;
if (retval)
*retval = x;
break;
case ACPI_WDAT_WRITE_VALUE:
x = value & mask;
x <<= gas->bit_offset;
if (preserve) {
ret = wdat_wdt_read(wdat, instr, &y);
if (ret)
return ret;
y = y & ~(mask << gas->bit_offset);
x |= y;
}
ret = wdat_wdt_write(wdat, instr, x);
if (ret)
return ret;
break;
case ACPI_WDAT_WRITE_COUNTDOWN:
x = param;
x &= mask;
x <<= gas->bit_offset;
if (preserve) {
ret = wdat_wdt_read(wdat, instr, &y);
if (ret)
return ret;
y = y & ~(mask << gas->bit_offset);
x |= y;
}
ret = wdat_wdt_write(wdat, instr, x);
if (ret)
return ret;
break;
default:
dev_err(&wdat->pdev->dev, "Unknown instruction: %u\n",
flags);
return -EINVAL;
}
}
return 0;
}