(210919_11:15:55.975)[ 206.398032] <1>-(1)[511:fuelgauged] bmd_ctrl_cmd_from_user+0x1bd0/0x1d5c
(210919_11:15:55.975)[ 206.398036] <1>-(1)[511:fuelgauged] nl_data_handler+0x158/0x184
(210919_11:15:55.975)[ 206.398041] <1>-(1)[511:fuelgauged] netlink_unicast+0x200/0x2f8
(210919_11:15:55.975)[ 206.398045] <1>-(1)[511:fuelgauged] netlink_sendmsg+0x2f8/0x350
(210919_11:15:55.975)[ 206.398049] <1>-(1)[511:fuelgauged] ___sys_sendmsg+0x1f4/0x2d4
(210919_11:15:55.975)[ 206.398052] <1>-(1)[511:fuelgauged] __sys_sendmsg+0x84/0xd4
(210919_11:15:55.975)[ 206.398056] <1>-(1)[511:fuelgauged] compat_SyS_sendmsg+0x10/0x18
(210919_11:15:55.975)[ 206.398059] <1>-(1)[511:fuelgauged] el0_svc_naked+0x34/0x38
battery_init
->gm.daemo_nl_sk = netlink_kernel_create(&init_net, NETLINK_FGD, &cfg);
->battery_probe
->mtk_battery_init(dev)
->fg_custom_init_from_dts(dev);
->battery_main.psy = power_supply_register(&(dev->dev), &battery_main.psd, NULL);
C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | | #define NETLINK_FGD 26 static int __init battery_init(void) { struct netlink_kernel_cfg cfg = { .input = nl_data_handler, };
int ret;
gm.daemo_nl_sk = netlink_kernel_create(&init_net, NETLINK_FGD, &cfg); //创建netlink bm_err("netlink_kernel_create protol= %d\n", NETLINK_FGD);
if (gm.daemo_nl_sk == NULL) { bm_err("netlink_kernel_create error\n"); return -1; } bm_err("netlink_kernel_create ok\n");
#ifdef CONFIG_OF /* register battery_device by DTS */ #else ret = platform_device_register(&battery_device); #endif
ret = platform_driver_register(&battery_driver_probe);
bm_err("[%s] Initialization : DONE\n", __func__);
return 0; }
static void __exit battery_exit(void) {
} module_init(battery_init); module_exit(battery_exit);
MODULE_AUTHOR("Weiching Lin"); MODULE_DESCRIPTION("Battery Device Driver"); MODULE_LICENSE("GPL"); |
内核收到应用层发过来的msg时会调用此回调函数 .input = nl_data_handler
msg的详细格式如下:
C Code /kernel-4.14/include/linux/skbuff.h
1 2 3 4 5 6 7 8 9 10 | | struct sk_buff { ... /* @len: Length of actual data */ /* @data_len: Data length */ unsigned int len, data_len; /* @head: Head of buffer */ /* @data: Data head pointer */ unsigned char *head, *data; } |
H Code \kernel-4.14\include\uapi\linux\netlink.h
1 2 3 4 5 6 7 | | struct nlmsghdr { __u32 nlmsg_len; /* Length of message including header */ __u16 nlmsg_type; /* Message content */ __u16 nlmsg_flags; /* Additional flags */ __u32 nlmsg_seq; /* Sequence number */ __u32 nlmsg_pid; /* Sending process port ID */ }; |
C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery_internal.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | | #define FGD_NL_MSG_T_HDR_LEN 28 #define FGD_NL_MAGIC 2015060303 #define FGD_NL_MSG_MAX_LEN 9200
struct fgd_nl_msg_t { unsigned int fgd_cmd; unsigned int fgd_subcmd; unsigned int fgd_subcmd_para1; unsigned int fgd_subcmd_para2; unsigned int fgd_data_len; unsigned int fgd_ret_data_len; unsigned int identity; char fgd_data[FGD_NL_MSG_MAX_LEN]; }; |
C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | | static void nl_data_handler(struct sk_buff *skb) { u32 pid; kuid_t uid; int seq; void *data; struct nlmsghdr *nlh; struct fgd_nl_msg_t *fgd_msg, *fgd_ret_msg; //fgd_msg接收上层数据,fgd_ret_msg发送数据 int size = 0; /* 取出数据 */ nlh = (struct nlmsghdr *)skb->data; pid = NETLINK_CREDS(skb)->pid; uid = NETLINK_CREDS(skb)->uid; seq = nlh->nlmsg_seq; /* 返回指向netlink消息体的payload的指针,也就是取得消息知的数据部分的首地址 */ data = NLMSG_DATA(nlh);
fgd_msg = (struct fgd_nl_msg_t *)data; //fgd_msg指向数据首地址
if (IS_ENABLED(CONFIG_POWER_EXT) || gm.disable_mtkbattery || IS_ENABLED(CONFIG_MTK_DISABLE_GAUGE)) { bm_err("GM3 disable, nl handler rev data\n"); return; }
if (fgd_msg->identity != FGD_NL_MAGIC) { bm_err("[FGERR]not correct MTKFG netlink packet!%d\n", fgd_msg->identity); return; }
if (gm.g_fgd_pid != pid && fgd_msg->fgd_cmd > FG_DAEMON_CMD_SET_DAEMON_PID) { bm_err("drop rev netlink pid:%d:%d cmd:%d:%d\n", pid, gm.g_fgd_pid, fgd_msg->fgd_cmd, FG_DAEMON_CMD_SET_DAEMON_PID); return; }
size = fgd_msg->fgd_ret_data_len + FGD_NL_MSG_T_HDR_LEN; //fgd_msg只是为了计算size
if (size > (PAGE_SIZE << 1)) fgd_ret_msg = vmalloc(size); else { if (in_interrupt()) fgd_ret_msg = kmalloc(size, GFP_ATOMIC); else fgd_ret_msg = kmalloc(size, GFP_KERNEL); }
if (fgd_ret_msg == NULL) { if (size > PAGE_SIZE) fgd_ret_msg = vmalloc(size);
if (fgd_ret_msg == NULL) return; }
memset(fgd_ret_msg, 0, size);
bmd_ctrl_cmd_from_user(data, fgd_ret_msg); nl_send_to_user(pid, seq, fgd_ret_msg);
kvfree(fgd_ret_msg); } |
根据不同的fgd_cmd填充fgd_data以及fgd_data_len
C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery_core.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | | void bmd_ctrl_cmd_from_user(void *nl_data, struct fgd_nl_msg_t *ret_msg) { struct fgd_nl_msg_t *msg; static int ptim_vbat, ptim_i;
msg = nl_data; ret_msg->fgd_cmd = msg->fgd_cmd;
switch (msg->fgd_cmd) {
case FG_DAEMON_CMD_IS_BAT_PLUGOUT: { int is_bat_plugout = 0; int bat_plugout_time = 0;
gauge_dev_get_boot_battery_plug_out_status( gm.gdev, &is_bat_plugout, &bat_plugout_time); ret_msg->fgd_data_len += sizeof(is_bat_plugout); memcpy(ret_msg->fgd_data, &is_bat_plugout, sizeof(is_bat_plugout));
bm_debug( "[fr] BATTERY_METER_CMD_GET_BOOT_BATTERY_PLUG_STATUS = %d\n", is_bat_plugout); } break; case FG_DAEMON_CMD_IS_BAT_EXIST: { int is_bat_exist = 0;
is_bat_exist = pmic_is_battery_exist();
ret_msg->fgd_data_len += sizeof(is_bat_exist); memcpy(ret_msg->fgd_data, &is_bat_exist, sizeof(is_bat_exist));
bm_debug( "[fr] FG_DAEMON_CMD_IS_BAT_EXIST = %d\n", is_bat_exist); } break; case FG_DAEMON_CMD_IS_BAT_CHARGING: case FG_DAEMON_CMD_GET_CHARGER_STATUS: case FG_DAEMON_CMD_GET_FG_HW_CAR: case FG_DAEMON_CMD_IS_CHARGER_EXIST: case FG_DAEMON_CMD_GET_INIT_FLAG: case FG_DAEMON_CMD_SET_INIT_FLAG: case FG_DAEMON_CMD_GET_TEMPERTURE: /* fix me */ case FG_DAEMON_CMD_GET_RAC: case FG_DAEMON_CMD_GET_DISABLE_NAFG: case FG_DAEMON_CMD_SET_DAEMON_PID: case FG_DAEMON_CMD_CHECK_FG_DAEMON_VERSION: case FG_DAEMON_CMD_GET_FG_SHUTDOWN_COND: case FG_DAEMON_CMD_FGADC_RESET: case FG_DAEMON_CMD_SEND_DATA: case FG_DAEMON_CMD_GET_DATA: case FG_DAEMON_CMD_COMMUNICATION_INT: case FG_DAEMON_CMD_GET_CUSTOM_SETTING: case FG_DAEMON_CMD_GET_PTIM_VBAT: case FG_DAEMON_CMD_GET_PTIM_I: case FG_DAEMON_CMD_GET_HW_OCV: case FG_DAEMON_CMD_SET_SW_OCV: case FG_DAEMON_CMD_SET_FG_BAT_INT1_GAP: case FG_DAEMON_CMD_SET_FG_BAT_INT2_HT_GAP: case FG_DAEMON_CMD_ENABLE_FG_BAT_INT2_HT: case FG_DAEMON_CMD_ENABLE_FG_BAT_INT2_LT: case FG_DAEMON_CMD_SET_FG_BAT_TMP_C_GAP: case FG_DAEMON_CMD_SET_FG_BAT_TMP_GAP: case FG_DAEMON_CMD_GET_SHUTDOWN_DURATION_TIME: case FG_DAEMON_CMD_GET_BAT_PLUG_OUT_TIME: case FG_DAEMON_CMD_GET_VBAT: case FG_DAEMON_CMD_SET_FG_RESET_RTC_STATUS: case FG_DAEMON_CMD_SET_IS_FG_INITIALIZED: case FG_DAEMON_CMD_GET_IS_FG_INITIALIZED: case FG_DAEMON_CMD_IS_HWOCV_UNRELIABLE: case FG_DAEMON_CMD_SET_FG_TIME: case FG_DAEMON_CMD_GET_FG_TIME: case FG_DAEMON_CMD_GET_ZCV: case FG_DAEMON_CMD_GET_FG_SW_CAR_NAFG_CNT: case FG_DAEMON_CMD_GET_FG_SW_CAR_NAFG_DLTV: case FG_DAEMON_CMD_GET_FG_SW_CAR_NAFG_C_DLTV: case FG_DAEMON_CMD_SET_NAG_ZCV_EN: case FG_DAEMON_CMD_SET_NAG_ZCV: case FG_DAEMON_CMD_SET_NAG_C_DLTV: case FG_DAEMON_CMD_SET_ZCV_INTR: case FG_DAEMON_CMD_SET_BAT_PLUGOUT_INTR: case FG_DAEMON_CMD_SET_IAVG_INTR: case FG_DAEMON_CMD_SET_FG_QUSE:/*useless*/ case FG_DAEMON_CMD_SET_FG_DC_RATIO: case FG_DAEMON_CMD_SET_BATTERY_CYCLE_THRESHOLD: case FG_DAEMON_CMD_SOFF_RESET: case FG_DAEMON_CMD_NCAR_RESET: case FG_DAEMON_CMD_GET_IMIX: case FG_DAEMON_CMD_IS_BATTERY_CYCLE_RESET: case FG_DAEMON_CMD_GET_AGING_FACTOR_CUST: case FG_DAEMON_CMD_GET_D0_C_SOC_CUST: case FG_DAEMON_CMD_GET_D0_V_SOC_CUST: case FG_DAEMON_CMD_GET_UISOC_CUST: case FG_DAEMON_CMD_IS_KPOC: case FG_DAEMON_CMD_GET_NAFG_VBAT: case FG_DAEMON_CMD_GET_HW_INFO: case FG_DAEMON_CMD_GET_FG_CURRENT_AVG: case FG_DAEMON_CMD_GET_FG_CURRENT_IAVG_VALID: case FG_DAEMON_CMD_SET_KERNEL_SOC: case FG_DAEMON_CMD_SET_KERNEL_UISOC: case FG_DAEMON_CMD_SET_KERNEL_INIT_VBAT: case FG_DAEMON_CMD_SET_FG_SHUTDOWN_COND: case FG_DAEMON_CMD_ENABLE_FG_VBAT_L_INT: case FG_DAEMON_CMD_ENABLE_FG_VBAT_H_INT: case FG_DAEMON_CMD_SET_FG_VBAT_L_TH: case FG_DAEMON_CMD_SET_FG_VBAT_H_TH: case FG_DAEMON_CMD_SET_CAR_TUNE_VALUE: case FG_DAEMON_CMD_PRINT_LOG: case FG_DAEMON_CMD_DUMP_LOG: case FG_DAEMON_CMD_GET_RTC_UI_SOC: case FG_DAEMON_CMD_SET_RTC_UI_SOC: case FG_DAEMON_CMD_SET_CON0_SOC: case FG_DAEMON_CMD_GET_CON0_SOC: case FG_DAEMON_CMD_SET_NVRAM_FAIL_STATUS: case FG_DAEMON_CMD_GET_NVRAM_FAIL_STATUS: case FG_DAEMON_CMD_GET_RTC_TWO_SEC_REBOOT: case FG_DAEMON_CMD_GET_RTC_INVALID: default: bm_err("bad FG_DAEMON_CTRL_CMD_FROM_USER 0x%x\n", msg->fgd_cmd); break; } /* switch() */
} |
C Code /kernel-4.14/drivers/power/supply/mediatek/battery/mtk_battery.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | | static void nl_send_to_user(u32 pid, int seq, struct fgd_nl_msg_t *reply_msg) { struct sk_buff *skb; struct nlmsghdr *nlh; /* int size=sizeof(struct fgd_nl_msg_t); */ int size = reply_msg->fgd_data_len + FGD_NL_MSG_T_HDR_LEN; int len = NLMSG_SPACE(size); void *data; int ret;
reply_msg->identity = FGD_NL_MAGIC;
if (in_interrupt()) skb = alloc_skb(len, GFP_ATOMIC); else skb = alloc_skb(len, GFP_KERNEL);
if (!skb) return;
nlh = nlmsg_put(skb, pid, seq, 0, size, 0); data = NLMSG_DATA(nlh); memcpy(data, reply_msg, size); NETLINK_CB(skb).portid = 0; /* from kernel */ NETLINK_CB(skb).dst_group = 0; /* unicast */
ret = netlink_unicast(gm.daemo_nl_sk, skb, pid, MSG_DONTWAIT); if (ret < 0) { bm_err("[Netlink] send failed %d\n", ret); return; } /*bm_debug("[Netlink] reply_user: netlink_unicast- ret=%d\n", ret); */ } |