diff --git a/sys/compat/linuxkpi/common/include/linux/device.h b/sys/compat/linuxkpi/common/include/linux/device.h --- a/sys/compat/linuxkpi/common/include/linux/device.h +++ b/sys/compat/linuxkpi/common/include/linux/device.h @@ -680,4 +680,11 @@ #define devm_kcalloc(_dev, _sizen, _size, _gfp) \ devm_kmalloc((_dev), ((_sizen) * (_size)), (_gfp) | __GFP_ZERO) +int lkpi_devm_add_action(struct device *dev, void (*action)(void *), void *data); +#define devm_add_action(dev, action, data) \ + lkpi_devm_add_action(dev, action, data); +int lkpi_devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data); +#define devm_add_action_or_reset(dev, action, data) \ + lkpi_devm_add_action_or_reset(dev, action, data) + #endif /* _LINUXKPI_LINUX_DEVICE_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_devres.c b/sys/compat/linuxkpi/common/src/linux_devres.c --- a/sys/compat/linuxkpi/common/src/linux_devres.c +++ b/sys/compat/linuxkpi/common/src/linux_devres.c @@ -224,3 +224,46 @@ /* Nothing to do. Freed with the devres. */ } + +struct devres_action { + void *data; + void (*action)(void *); +}; + +static void +lkpi_devm_action_release(struct device *dev, void *res) +{ + struct devres_action *devres; + + devres = (struct devres_action *)res; + devres->action(devres->data); +} + +int +lkpi_devm_add_action(struct device *dev, void (*action)(void *), void *data) +{ + struct devres_action *devres; + + KASSERT(action != NULL, ("%s: action is NULL\n", __func__)); + devres = lkpi_devres_alloc(lkpi_devm_action_release, + sizeof(struct devres_action), GFP_KERNEL); + if (devres == NULL) + return (-ENOMEM); + devres->data = data; + devres->action = action; + devres_add(dev, devres); + + return (0); +} + +int +lkpi_devm_add_action_or_reset(struct device *dev, void (*action)(void *), void *data) +{ + int rv; + + rv = lkpi_devm_add_action(dev, action, data); + if (rv != 0) + action(data); + + return (rv); +}