Path: blob/next/external/cache/sources/rtk_hciattach/hciattach_h4.c
8659 views
// SPDX-License-Identifier: GPL-2.01#include <stdio.h>2#include <errno.h>3#include <unistd.h>4#include <stdlib.h>5#include <termios.h>6#include <time.h>7#include <sys/time.h>8#include <sys/types.h>9#include <sys/param.h>10#include <sys/ioctl.h>11#include <sys/socket.h>12#include <sys/uio.h>13#include <sys/stat.h>14#include <fcntl.h>15#include <signal.h>16#include <stdint.h>17#include <string.h>18#include <endian.h>19#include <byteswap.h>20#include <netinet/in.h>21#include <ctype.h>22#include <poll.h>23#include <sys/timerfd.h>24#include <sys/epoll.h>25#include "hciattach.h"26#include "hciattach_h4.h"2728extern struct rtb_struct rtb_cfg;2930static int start_xfer_wait(int fd, uint8_t *cmd, uint16_t len, uint32_t msec,31int retry, uint8_t *resp, uint16_t *resp_len)32{33uint8_t buf[64];34int result;35int state = 1;36int count = 0;37int params_len;38struct pollfd p[2];39uint16_t opcode;4041if (fd == -1 || !cmd || len < 4) {42RS_ERR("%s: invalid parameter", __func__);43return -1;44}4546opcode = ((uint16_t)cmd[2] << 8) + cmd[1];4748start_xfer:49result = write(fd, cmd, len);50if (result != len) {51RS_ERR("%s: Write cmd %04x error, %s", __func__, opcode,52strerror(errno));53return -1;54}5556start_recv:57memset(buf, 0, sizeof(buf));58memset(p, 0, sizeof(p));59state = 1;60count = 0;61p[0].fd = fd;62p[0].events = POLLERR | POLLHUP | POLLIN;63for (;;) {64p[0].revents = 0;65result = poll(p, 1, msec);66if (result < 0) {67RS_ERR("Poll call error, %s", strerror(errno));68result = -1;69break;70}7172if (result == 0) {73RS_WARN("%s: Timeout", __func__);74if (retry <= 0) {75RS_ERR("%s: Transfer exhausted", __func__);76tcflush(fd, TCIOFLUSH);77exit(EXIT_FAILURE);78}79retry--;80goto start_xfer;81}8283if (p[0].revents & (POLLERR | POLLHUP)) {84RS_ERR("POLLERR or POLLUP happens, %s",85strerror(errno));86result = -1;87break;88}8990if (state == 1) {91result = read(p[0].fd, buf, 1);92if (result == -1 || result != 1) {93RS_ERR("%s: Read pkt type error, %s", __func__,94strerror(errno));95result = -1;96break;97}98if (result == 1 && buf[0] == 0x04) {99count = 1;100state = 2;101}102} else if (state == 2) {103result = read(p[0].fd, buf + count, 2);104if (result == -1 || result != 2) {105RS_ERR("%s: Read pkt header error, %s",106__func__, strerror(errno));107break;108}109count += result;110state = 3;111params_len = buf[2];112if (params_len + 3 > sizeof(buf)) {113result = -1;114RS_ERR("%s: hci event too long", __func__);115break;116}117} else if (state == 3) {118result = read(p[0].fd, buf + count, params_len);119if (result == -1) {120RS_ERR("%s: Read pkt payload error, %s",121__func__, strerror(errno));122break;123}124count += result;125params_len -= result;126if (!params_len)127break;128}129}130131if (result >= 0) {132if (buf[1] == 0x0e) {133uint16_t tmp_opcode;134135tmp_opcode = (uint16_t)buf[4] | buf[5] << 8;136if (tmp_opcode == opcode) {137RS_INFO("Cmd complete event for cmd %04x",138opcode);139/* Status is not zero indicating command not140* succeeded */141if (buf[6])142return -1;143if (!resp)144return 0;145if (*resp_len > count)146*resp_len = count;147memcpy(resp, buf, *resp_len);148return 0;149} else {150RS_WARN("Unexpected cmd complete event, %04x",151tmp_opcode);152return -1;153}154} else {155RS_INFO("%s: Unexpected hci event packet", __func__);156util_hexdump(buf, count);157/* Continue receiving */158}159goto start_recv;160}161162return result;163}164165int h4_download_patch(int fd, int index, uint8_t *data, int len)166{167uint8_t buf[257];168uint16_t total_len;169int result;170uint8_t resp[8];171uint16_t rlen = sizeof(resp);172173RS_DBG("fd: %d, index: %d, len: %d", fd, index, len);174175if (data)176memcpy(&buf[5], data, len);177buf[0] = 0x01;178buf[1] = 0x20;179buf[2] = 0xfc;180buf[3] = len + 1;181buf[4] = (uint8_t)index;182total_len = len + 5;183184result = start_xfer_wait(fd, buf, total_len, 1000, 0, resp, &rlen);185if (result < 0) {186RS_ERR("Transfer patch failed, index %d", index);187return -1;188}189190if (rlen != 8) {191RS_ERR("%s: Unexpected length %u", __func__, rlen);192return -1;193}194195return resp[7];196}197198int h4_vendor_change_speed(int fd, uint32_t baudrate)199{200int res;201uint8_t cmd[8] = { 0 };202203cmd[0] = 1;204cmd[1] = 0x17;205cmd[2] = 0xfc;206cmd[3] = 4;207208baudrate = cpu_to_le32(baudrate);209#ifdef BAUDRATE_4BYTES210memcpy((uint16_t *) & cmd[4], &baudrate, 4);211#else212memcpy((uint16_t *) & cmd[4], &baudrate, 2);213cmd[6] = 0;214cmd[7] = 0;215#endif216217/* TODO: Wait for a while for device to up, just h4 need it */218sleep(1);219220RS_DBG("baudrate in change speed command: 0x%02x 0x%02x 0x%02x 0x%02x",221cmd[4], cmd[5], cmd[6], cmd[7]);222223res = start_xfer_wait(fd, cmd, 8, 1000, 0, NULL, 0);224if (res < 0)225RS_ERR("Change Controller baud failed");226227return res;228}229230int h4_hci_reset(int fd)231{232int result;233uint8_t cmd[4] = { 0x01, 0x03, 0x0c, 0x00};234235RS_INFO("%s: Issue hci reset cmd", __func__);236237result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0, NULL, 0);238if (result < 0) {239RS_ERR("%s: Failed to send reset cmd", __func__);240return -1;241}242243return 0;244}245246int h4_read_local_ver(int fd)247{248uint8_t cmd[4] = { 0x01, 0x01, 0x10, 0x00 };249uint8_t resp[16];250uint16_t len = sizeof(resp);251int result;252253result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0,254resp, &len);255if (result < 0) {256RS_ERR("HCI Read local version info error");257return -1;258}259260if (len != 15) {261RS_ERR("%s: Unexpected length %u", __func__, len);262return -1;263}264rtb_cfg.hci_ver = resp[7];265rtb_cfg.hci_rev = (uint32_t)resp[9] << 8 | resp[8];266rtb_cfg.lmp_subver = (uint32_t)resp[14] << 8 | resp[13];267RS_INFO("hci ver %02x, hci_rev %04x, lmp_subver %04x",268rtb_cfg.hci_ver, rtb_cfg.hci_rev, rtb_cfg.lmp_subver);269return 0;270}271272int h4_vendor_read_rom_ver(int fd)273{274uint8_t cmd[4] = { 0x01, 0x6d, 0xfc, 0x00 };275uint8_t resp[16];276uint16_t len = sizeof(resp);277int result;278279result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0,280resp, &len);281if (result < 0) {282RS_ERR("HCI Read local version info error");283return -1;284}285286if (len != 8) {287RS_ERR("%s: Unexpected length %u", __func__, len);288return -1;289}290rtb_cfg.eversion = resp[7];291RS_INFO("eversion %02x", rtb_cfg.eversion);292return 0;293}294295296297