/* * btif_woble.c * * Created on: 2020 * Author: Unisoc */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "woble.h" #include "tty.h" #include "alignment/sitm.h" #include #define CMD_TIMEOUT 5000 #define MAX_WAKE_DEVICE_MAX_NUM 36 #define CONFIG_FILE_PATH "/data/misc/bluedroid/bt_config.conf" static struct hci_cmd_t hci_cmd; uint8_t device_count_db; const woble_config_t s_woble_config_cust = {WOBLE_MOD_ENABLE, WOBLE_SLEEP_MOD_COULD_NOT_KNOW, 0, WOBLE_SLEEP_MOD_NOT_NEED_NOTITY}; mtty_bt_wake_t bt_wake_dev_db[MAX_WAKE_DEVICE_MAX_NUM]; int woble_init(void) { memset(&hci_cmd, 0, sizeof(struct hci_cmd_t)); sema_init(&hci_cmd.wait, 0); return 0; } int mtty_bt_str_hex(char *str, uint8_t count, char *hex) { uint8_t data_buf[12] = {0x00}; uint8_t i = 0; while ((*str != '\0') && (i < count * 2)) { if ((*str >= '0') && (*str <= '9')) { data_buf[i] = *str - '0' + 0x00; i++; } else if ((*str >= 'A') && (*str <= 'F')) { data_buf[i] = *str - 'A' + 0x0A; i++; } else if ((*str >= 'a') && (*str <= 'f')) { data_buf[i] = *str - 'a' + 0x0a; i++; } else { ; } str++; } if (count == 1) { *hex = data_buf[0]; } else { for (i = 0; i < count; i++) { hex[i] = (data_buf[0 + i * 2] << 4) + data_buf[1 + i * 2]; } } for (i = 0; i < count; i++) { pr_info("%s data[%d] = %02x\n", __func__, i, hex[i]); } return 0; } int mtty_bt_conf_prase(char *conf_str) { char *tok_str = conf_str; char *str1, *str2, *str3; uint8_t device_count = 0; uint8_t loop_count = 0; if (conf_str) { while (tok_str != NULL) { tok_str = strsep(&conf_str, "\r\n"); if (!tok_str) continue; if ((strpbrk(tok_str, "[") != NULL) && (strpbrk(tok_str, "]") != NULL) && (strpbrk(tok_str, ":") != NULL)) { bt_wake_dev_db[device_count].addr_str = tok_str; continue; } if (strstr(tok_str, "DevType") != NULL) { bt_wake_dev_db[device_count].dev_tp_str = tok_str; continue; } if (strstr(tok_str, "AddrType") != NULL) { bt_wake_dev_db[device_count].addr_tp_str = tok_str; device_count++; } } } else { pr_info("%s conf_str is NULL\n", __func__); } if (device_count) { for (; loop_count < device_count; loop_count++) { str1 = strchr(bt_wake_dev_db[loop_count].addr_str, '['); str2 = strstrip(bt_wake_dev_db[loop_count].dev_tp_str); str2 = strchr(str2, '='); str3 = strstrip(bt_wake_dev_db[loop_count].addr_tp_str); str3 = strchr(str3, '='); mtty_bt_str_hex(str1, 6, bt_wake_dev_db[loop_count].addr); mtty_bt_str_hex(str2, 1, &(bt_wake_dev_db[loop_count].dev_tp)); mtty_bt_str_hex(str3, 1, &(bt_wake_dev_db[loop_count].addr_tp)); } } return device_count; } int mtty_bt_read_conf(void) { char *buffer = NULL; unsigned char *p_buf = NULL; struct file *bt_conf_fp; unsigned int read_len, buffer_len; uint8_t device_count = 0; loff_t file_size = 0; loff_t file_offset = 0; memset(bt_wake_dev_db, 0, sizeof(mtty_bt_wake_t) * MAX_WAKE_DEVICE_MAX_NUM); bt_conf_fp = filp_open(CONFIG_FILE_PATH, O_RDONLY, 0); if (IS_ERR(bt_conf_fp)) { pr_info("%s open file %s error %ld \n", __func__, CONFIG_FILE_PATH, PTR_ERR(bt_conf_fp)); return device_count; } file_size = vfs_llseek(bt_conf_fp, 0, SEEK_END); buffer_len = 0; buffer = vmalloc(file_size); p_buf = buffer; if (!buffer) { fput(bt_conf_fp); pr_info("%s no memory\n", __func__); return device_count; } do { read_len = kernel_read(bt_conf_fp, p_buf, file_size, &file_offset); if (read_len > 0) { buffer_len += read_len; file_size -= read_len; p_buf += read_len; } } while ((read_len > 0) && (file_size > 0)); fput(bt_conf_fp); pr_info("%s read %s data_len:0x%x\n", __func__, CONFIG_FILE_PATH, buffer_len); device_count = mtty_bt_conf_prase(buffer); return device_count; } int woble_data_recv(const unsigned char *buf, int count) { unsigned short opcode = 0; unsigned char status = 0; const unsigned char *p = 0; const unsigned char *rxmsg = buf; int left_length = count; int pack_length = 0; int last = 0; int ret = -1; if (count < 0) { pr_err("%s count < 0!!!", __func__); } do { rxmsg = buf + (count - left_length); switch (rxmsg[PACKET_TYPE]) { case HCI_EVT: if (left_length < 3) { pr_err("%s left_length <3 !!!!!", __func__); } pack_length = rxmsg[EVT_HEADER_SIZE]; pack_length += 3; if (left_length - pack_length < 0) { pr_err("%s left_length - pack_length <0 !!!!!", __func__); } switch (rxmsg[EVT_HEADER_EVENT]) { default: case BT_HCI_EVT_CMD_COMPLETE: p = rxmsg + 4; STREAM_TO_UINT16(opcode, p); STREAM_TO_UINT8(status, p); break; case BT_HCI_EVT_CMD_STATUS: p = rxmsg + 5; STREAM_TO_UINT16(opcode, p); status = rxmsg[3]; break; } last = left_length; left_length -= pack_length; break; default: left_length = 0; break; } } while (left_length); if (hci_cmd.opcode == opcode && hci_cmd.opcode) { pr_info("%s opcode: 0x%04X, status: %d\n", __func__, opcode, status); up(&hci_cmd.wait); ret = 0; } return ret; } int hci_cmd_send_sync(unsigned short opcode, struct HC_BT_HDR *py, struct HC_BT_HDR *rsp) { unsigned char msg_req[HCI_CMD_MAX_LEN + BYTE_ALIGNMENT] = {0}, *p; int ret = 0; p = msg_req; UINT8_TO_STREAM(p, HCI_CMD); UINT16_TO_STREAM(p, opcode); if (py == NULL) { UINT8_TO_STREAM(p, 0); } else { UINT8_TO_STREAM(p, py->len); ARRAY_TO_STREAM(p, py->data, py->len); } hci_cmd.opcode = opcode; ret = marlin_sdio_write(msg_req, (p - msg_req) + (BYTE_ALIGNMENT - ((p - msg_req) % BYTE_ALIGNMENT))); if (!ret) { hci_cmd.opcode = 0; pr_err("%s marlin_sdio_write fail", __func__); return 0; } if (down_timeout(&hci_cmd.wait, msecs_to_jiffies(CMD_TIMEOUT))) { pr_err("%s CMD_TIMEOUT for CMD: 0x%04X", __func__, opcode); mdbg_assert_interface("hci cmd timeout"); } hci_cmd.opcode = 0; return 0; } void hci_set_ap_sleep_mode(int is_shutdown, int is_resume) { struct HC_BT_HDR *payload = (struct HC_BT_HDR *)vmalloc(sizeof(struct HC_BT_HDR) + 3); unsigned char *p; p = payload->data; payload->len = 6; if (is_resume && !is_shutdown) { UINT8_TO_STREAM(p, 0); } else { UINT8_TO_STREAM(p, s_woble_config_cust.woble_mod); } if (is_shutdown) { UINT8_TO_STREAM(p, WOBLE_SLEEP_MOD_COULD_KNOW); } else { UINT8_TO_STREAM(p, WOBLE_SLEEP_MOD_COULD_NOT_KNOW); } UINT16_TO_STREAM(p, s_woble_config_cust.timeout); UINT8_TO_STREAM(p, s_woble_config_cust.notify); UINT8_TO_STREAM(p, 0); hci_cmd_send_sync(BT_HCI_OP_SET_SLEEPMODE, payload, NULL); vfree(payload); return; } void hci_add_device_to_wakeup_list(mtty_bt_wake_t bt_wakeup_dev) { struct HC_BT_HDR *payload = (struct HC_BT_HDR *)vmalloc(sizeof(struct HC_BT_HDR) + 3); unsigned char *p; p = payload->data; payload->len = 10; UINT8_TO_STREAM(p, bt_wakeup_dev.addr_tp); //ARRAY_TO_STREAM(p, bt_wakeup_dev.addr,6); UINT8_TO_STREAM(p, bt_wakeup_dev.addr[5]); UINT8_TO_STREAM(p, bt_wakeup_dev.addr[4]); UINT8_TO_STREAM(p, bt_wakeup_dev.addr[3]); UINT8_TO_STREAM(p, bt_wakeup_dev.addr[2]); UINT8_TO_STREAM(p, bt_wakeup_dev.addr[1]); UINT8_TO_STREAM(p, bt_wakeup_dev.addr[0]); UINT16_TO_STREAM(p, 3); UINT8_TO_STREAM(p, 0); hci_cmd_send_sync(BT_HCI_OP_ADD_WAKEUPLIST, payload, NULL); vfree(payload); return; } void hci_set_ap_start_sleep(void) { struct HC_BT_HDR *payload = (struct HC_BT_HDR *)vmalloc(sizeof(struct HC_BT_HDR) + 3); hci_cmd_send_sync(BT_HCI_OP_SET_STARTSLEEP, NULL, NULL); vfree(payload); return; }