1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Regulator event over netlink 4 * 5 * Author: Naresh Solanki <Naresh.Solanki@9elements.com> 6 */ 7 8#include <regulator/regulator.h> 9#include <net/netlink.h> 10#include <net/genetlink.h> 11#include <linux/atomic.h> 12 13#include "regnl.h" 14 15static atomic_t reg_event_seqnum = ATOMIC_INIT(0); 16 17static const struct genl_multicast_group reg_event_mcgrps[] = { 18 { .name = REG_GENL_MCAST_GROUP_NAME, }, 19}; 20 21static struct genl_family reg_event_genl_family __ro_after_init = { 22 .module = THIS_MODULE, 23 .name = REG_GENL_FAMILY_NAME, 24 .version = REG_GENL_VERSION, 25 .maxattr = REG_GENL_ATTR_MAX, 26 .mcgrps = reg_event_mcgrps, 27 .n_mcgrps = ARRAY_SIZE(reg_event_mcgrps), 28}; 29 30int reg_generate_netlink_event(const char *reg_name, u64 event) 31{ 32 struct sk_buff *skb; 33 struct nlattr *attr; 34 struct reg_genl_event *edata; 35 void *msg_header; 36 int size; 37 38 /* allocate memory */ 39 size = nla_total_size(sizeof(struct reg_genl_event)) + 40 nla_total_size(0); 41 42 skb = genlmsg_new(size, GFP_ATOMIC); 43 if (!skb) 44 return -ENOMEM; 45 46 /* add the genetlink message header */ 47 msg_header = genlmsg_put(skb, 0, atomic_inc_return(®_event_seqnum), 48 ®_event_genl_family, 0, REG_GENL_CMD_EVENT); 49 if (!msg_header) { 50 nlmsg_free(skb); 51 return -ENOMEM; 52 } 53 54 /* fill the data */ 55 attr = nla_reserve(skb, REG_GENL_ATTR_EVENT, sizeof(struct reg_genl_event)); 56 if (!attr) { 57 nlmsg_free(skb); 58 return -EINVAL; 59 } 60 61 edata = nla_data(attr); 62 memset(edata, 0, sizeof(struct reg_genl_event)); 63 64 strscpy(edata->reg_name, reg_name, sizeof(edata->reg_name)); 65 edata->event = event; 66 67 /* send multicast genetlink message */ 68 genlmsg_end(skb, msg_header); 69 size = genlmsg_multicast(®_event_genl_family, skb, 0, 0, GFP_ATOMIC); 70 71 return size; 72} 73 74static int __init reg_event_genetlink_init(void) 75{ 76 return genl_register_family(®_event_genl_family); 77} 78 79static int __init reg_event_init(void) 80{ 81 int error; 82 83 /* create genetlink for acpi event */ 84 error = reg_event_genetlink_init(); 85 if (error) 86 pr_warn("Failed to create genetlink family for reg event\n"); 87 88 return 0; 89} 90 91fs_initcall(reg_event_init); 92