return div_u64(byte * wf_send_coef.num, wf_send_coef.denom);
}
+/* l2cap_recv_acldata */
+static DEFINE_RATIONAL(l2cap_recv_acldata_coef);
+
+static u64 l2cap_recv_acldata_system(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PE_L2CAP_RECV_SYSTEM, &byte, sizeof(byte));
+
+ return div_u64(byte * l2cap_recv_acldata_coef.num,
+ l2cap_recv_acldata_coef.denom);
+}
+
+static u64 l2cap_recv_acldata_apps(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PE_L2CAP_RECV_APPS, &byte, sizeof(byte));
+
+ return div_u64(byte * l2cap_recv_acldata_coef.num,
+ l2cap_recv_acldata_coef.denom);
+}
+
+/* sco_recv_scodata */
+static DEFINE_RATIONAL(sco_recv_scodata_coef);
+
+static u64 sco_recv_scodata_system(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PE_SCO_RECV_SYSTEM, &byte, sizeof(byte));
+
+ return div_u64(byte * sco_recv_scodata_coef.num,
+ sco_recv_scodata_coef.denom);
+}
+
+static u64 sco_recv_scodata_apps(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PE_SCO_RECV_APPS, &byte, sizeof(byte));
+
+ return div_u64(byte * sco_recv_scodata_coef.num,
+ sco_recv_scodata_coef.denom);
+}
+
+/* hci_send_acl */
+static DEFINE_RATIONAL(hci_send_acl_coef);
+
+static u64 hci_send_acl_system(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PT_SEND_ACL_SYSTEM, &byte, sizeof(byte));
+
+ return div_u64(byte * hci_send_acl_coef.num, hci_send_acl_coef.denom);
+}
+
+static u64 hci_send_acl_apps(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PT_SEND_ACL_APPS, &byte, sizeof(byte));
+
+ return div_u64(byte * hci_send_acl_coef.num, hci_send_acl_coef.denom);
+}
+
+/* hci_send_sco */
+static DEFINE_RATIONAL(hci_send_sco_coef);
+
+static u64 hci_send_sco_system(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PT_SEND_SCO_SYSTEM, &byte, sizeof(byte));
+
+ return div_u64(byte * hci_send_sco_coef.num, hci_send_sco_coef.denom);
+}
+
+static u64 hci_send_sco_apps(void)
+{
+ u64 byte = 0;
+
+ get_parameter_energy(PT_SEND_SCO_APPS, &byte, sizeof(byte));
+
+ return div_u64(byte * hci_send_sco_coef.num, hci_send_sco_coef.denom);
+}
+
+
+
+
+
/* ============================================================================
* === PARAMETERS ===
* ============================================================================
.coef = &wf_send_coef,
.system = wf_send_system,
.apps = wf_send_apps
+ },
+ {
+ .name = "sco_recv_scodata",
+ .coef = &sco_recv_scodata_coef,
+ .system = sco_recv_scodata_system,
+ .apps = sco_recv_scodata_apps
+ },
+ {
+ .name = "l2cap_recv_acldata",
+ .coef = &l2cap_recv_acldata_coef,
+ .system = l2cap_recv_acldata_system,
+ .apps = l2cap_recv_acldata_apps
+ },
+ {
+ .name = "hci_send_acl",
+ .coef = &hci_send_acl_coef,
+ .system = hci_send_acl_system,
+ .apps = hci_send_acl_apps
+ },
+ {
+ .name = "hci_send_sco",
+ .coef = &hci_send_sco_coef,
+ .system = hci_send_sco_system,
+ .apps = hci_send_sco_apps
}
};
/* for sock_send */
atomic64_t bytes_send;
+
+ /* for l2cap_recv */
+ atomic64_t bytes_l2cap_recv_acldata;
+
+ /* for sco_recv_scodata */
+ atomic64_t bytes_sco_recv_scodata;
+
+ /* for hci_send_acl */
+ atomic64_t bytes_hci_send_acl;
+
+ /* for hci_send_sco */
+ atomic64_t bytes_hci_send_sco;
};
static sspt_feature_id_t feature_id = SSPT_FEATURE_ID_BAD;
atomic64_set(&ed->bytes_written, 0);
atomic64_set(&ed->bytes_recv, 0);
atomic64_set(&ed->bytes_send, 0);
+ atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
+ atomic64_set(&ed->bytes_sco_recv_scodata, 0);
+ atomic64_set(&ed->bytes_hci_send_acl, 0);
+ atomic64_set(&ed->bytes_hci_send_sco, 0);
}
static void uninit_ed(struct energy_data *ed)
atomic64_set(&ed->bytes_written, 0);
atomic64_set(&ed->bytes_recv, 0);
atomic64_set(&ed->bytes_send, 0);
+ atomic64_set(&ed->bytes_l2cap_recv_acldata, 0);
+ atomic64_set(&ed->bytes_sco_recv_scodata, 0);
+ atomic64_set(&ed->bytes_hci_send_acl, 0);
+ atomic64_set(&ed->bytes_hci_send_sco, 0);
}
static void *create_ed(void)
+/* ============================================================================
+ * = bluetooth =
+ * ============================================================================
+ */
+#define RET_HANDLER_BT_NAME(name) ret_handler_bt_##name
+#define DEFINE_RET_HANDLER_BT(name) \
+ int RET_HANDLER_BT_NAME(name)(struct kretprobe_instance *ri, \
+ struct pt_regs *regs) \
+ { \
+ unsigned int len = *(unsigned int *)ri->data; \
+ if (len) { \
+ struct energy_data *ed = get_energy_data(current); \
+ if (ed) \
+ atomic64_add(len, &ed->bytes_##name); \
+ atomic64_add(len, &ed_system.bytes_##name); \
+ } \
+ return 0; \
+}
+
+static DEFINE_RET_HANDLER_BT(l2cap_recv_acldata)
+static DEFINE_RET_HANDLER_BT(sco_recv_scodata)
+static DEFINE_RET_HANDLER_BT(hci_send_acl)
+static DEFINE_RET_HANDLER_BT(hci_send_sco)
+
+static int entry_handler_generic_bt(struct kretprobe_instance *ri,
+ struct pt_regs *regs)
+{
+ struct sk_buff *skb = (struct sk_buff *)swap_get_sarg(regs, 1);
+ unsigned int *len = (unsigned int *)ri->data;
+
+ *len = skb ? skb->len : 0;
+
+ return 0;
+}
+
+static struct kretprobe l2cap_recv_acldata_krp = {
+ .entry_handler = entry_handler_generic_bt,
+ .handler = RET_HANDLER_BT_NAME(l2cap_recv_acldata),
+ .data_size = sizeof(unsigned int)
+};
+
+static struct kretprobe sco_recv_scodata_krp = {
+ .entry_handler = entry_handler_generic_bt,
+ .handler = RET_HANDLER_BT_NAME(sco_recv_scodata),
+ .data_size = sizeof(unsigned int)
+};
+
+static struct kretprobe hci_send_acl_krp = {
+ .entry_handler = entry_handler_generic_bt,
+ .handler = RET_HANDLER_BT_NAME(hci_send_acl),
+ .data_size = sizeof(unsigned int)
+};
+
+static struct kretprobe hci_send_sco_krp = {
+ .entry_handler = entry_handler_generic_bt,
+ .handler = RET_HANDLER_BT_NAME(hci_send_sco),
+ .data_size = sizeof(unsigned int)
+};
+
+
+static int energy_bt_once(void)
+{
+ const char *sym;
+
+ sym = "l2cap_recv_acldata";
+ l2cap_recv_acldata_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
+ if (l2cap_recv_acldata_krp.kp.addr == NULL)
+ goto not_found;
+
+ sym = "sco_recv_scodata";
+ sco_recv_scodata_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
+ if (sco_recv_scodata_krp.kp.addr == NULL)
+ goto not_found;
+
+ sym = "hci_send_acl";
+ hci_send_acl_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
+ if (hci_send_acl_krp.kp.addr == NULL)
+ goto not_found;
+
+ sym = "hci_send_sco";
+ hci_send_sco_krp.kp.addr = (kprobe_opcode_t *)swap_ksyms(sym);
+ if (hci_send_sco_krp.kp.addr == NULL)
+ goto not_found;
+
+ return 0;
+
+not_found:
+ printk(KERN_INFO "ERROR: symbol '%s' not found\n", sym);
+ return -ESRCH;
+}
+
+static int energy_bt_flag = 0;
+
+static int energy_bt_set(void)
+{
+ int ret;
+
+ ret = swap_register_kretprobe(&l2cap_recv_acldata_krp);
+ if (ret) {
+ pr_err("register fail 'l2cap_recv_acldata_krp' ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = swap_register_kretprobe(&sco_recv_scodata_krp);
+ if (ret) {
+ printk("register fail 'sco_recv_scodata_krp' ret=%d\n" ,ret);
+ goto unreg_l2cap_recv_acldata;
+ }
+
+ ret = swap_register_kretprobe(&hci_send_acl_krp);
+ if (ret) {
+ printk("register fail 'hci_send_acl_krp' ret=%d\n", ret);
+ goto unreg_sco_recv_scodata;
+ }
+
+ ret = swap_register_kretprobe(&hci_send_sco_krp);
+ if (ret) {
+ printk("register fail 'hci_send_sco_krp' ret=%d\n", ret);
+ goto unreg_hci_send_acl;
+ }
+
+ energy_bt_flag = 1;
+
+ return 0;
+
+unreg_hci_send_acl:
+ swap_unregister_kretprobe(&hci_send_acl_krp);
+
+unreg_sco_recv_scodata:
+ swap_unregister_kretprobe(&sco_recv_scodata_krp);
+
+unreg_l2cap_recv_acldata:
+ swap_unregister_kretprobe(&l2cap_recv_acldata_krp);
+
+ return ret;
+}
+
+static void energy_bt_unset(void)
+{
+ if (energy_bt_flag == 0)
+ return;
+
+ swap_unregister_kretprobe(&hci_send_sco_krp);
+ swap_unregister_kretprobe(&hci_send_acl_krp);
+ swap_unregister_kretprobe(&sco_recv_scodata_krp);
+ swap_unregister_kretprobe(&l2cap_recv_acldata_krp);
+
+ energy_bt_flag = 0;
+}
+
+
+
+
+
enum parameter_type {
PT_CPU,
PT_READ,
PT_WRITE,
PT_WF_RECV,
- PT_WF_SEND
+ PT_WF_SEND,
+ PT_L2CAP_RECV,
+ PT_SCO_RECV,
+ PT_SEND_ACL,
+ PT_SEND_SCO
};
struct cmd_pt {
case PT_WF_SEND:
*val += atomic64_read(&ed->bytes_send);
break;
+ case PT_L2CAP_RECV:
+ *val += atomic64_read(&ed->bytes_l2cap_recv_acldata);
+ break;
+ case PT_SCO_RECV:
+ *val += atomic64_read(&ed->bytes_sco_recv_scodata);
+ break;
+ case PT_SEND_ACL:
+ *val += atomic64_read(&ed->bytes_hci_send_acl);
+ break;
+ case PT_SEND_SCO:
+ *val += atomic64_read(&ed->bytes_hci_send_sco);
+ break;
default:
break;
}
case PE_WF_SEND_SYSTEM:
*val = atomic64_read(&ed_system.bytes_send);
break;
+ case PE_L2CAP_RECV_SYSTEM:
+ *val = atomic64_read(&ed_system.bytes_l2cap_recv_acldata);
+ break;
+ case PE_SCO_RECV_SYSTEM:
+ *val = atomic64_read(&ed_system.bytes_sco_recv_scodata);
+ break;
+ case PT_SEND_ACL_SYSTEM:
+ *val = atomic64_read(&ed_system.bytes_hci_send_acl);
+ break;
+ case PT_SEND_SCO_SYSTEM:
+ *val = atomic64_read(&ed_system.bytes_hci_send_sco);
+ break;
case PE_READ_APPS:
current_parameter_apps(PT_READ, buf, sz);
break;
case PE_WF_SEND_APPS:
current_parameter_apps(PT_WF_SEND, buf, sz);
break;
+ case PE_L2CAP_RECV_APPS:
+ current_parameter_apps(PT_L2CAP_RECV, buf, sz);
+ break;
+ case PE_SCO_RECV_APPS:
+ current_parameter_apps(PT_SCO_RECV, buf, sz);
+ break;
+ case PT_SEND_ACL_APPS:
+ current_parameter_apps(PT_SEND_ACL, buf, sz);
+ break;
+ case PT_SEND_SCO_APPS:
+ current_parameter_apps(PT_SEND_SCO, buf, sz);
+ break;
default:
ret = -EINVAL;
break;
goto unregister_sys_write;
}
+ energy_bt_set();
energy_wifi_set();
/* TODO: check return value */
{
lcd_unset_energy();
energy_wifi_unset();
+ energy_bt_unset();
swap_unregister_kretprobe(&switch_to_krp);
swap_unregister_kretprobe(&sys_write_krp);
if (sys_write_krp.kp.addr == NULL)
goto not_found;
+ energy_bt_once();
energy_wifi_once();
return 0;