Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/hcitools/hciattach_xr.c
Views: 3959
#include <stdio.h>1#include <stdlib.h>2#include <unistd.h>3#include <errno.h>4#include <fcntl.h>5#include <string.h>6#include <signal.h>7#include <time.h>8#include <stdint.h>9#include <sys/termios.h>10#include <sys/ioctl.h>11#include <limits.h>12#include "hciattach.h"1314/******************************************************************************15** Constants & Macros16******************************************************************************/17#define LOG_STR "XRADIO Bluetooth"18#define DBG_ON 11920#define XR_DBG(fmt, arg...) \21do { \22if (DBG_ON) \23fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \24} while(0)2526#define XR_ERR(fmt, arg...) \27do { \28fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\29perror(LOG_STR" ERROR reason"); \30} while(0)3132#define XR_DUMP(buffer, len) \33fprintf(stderr, "%s: ", LOG_STR); \34do { \35for (int i = 0; i < len; i++) { \36if (i && !(i % 16)) { \37fprintf(stderr, "\n"); \38fprintf(stderr, "%s: ", LOG_STR); \39} \40fprintf(stderr, "%02x ", buffer[i]); \41} \42fprintf(stderr, "\n"); \43} while (0)4445#define BT_FW_PATH_NAME "/system/vendor/etc/firmware/fw_xr829_bt.bin"46#define BT_FW_LOAD_ADDR 0x000047#define BT_FW_JUMP_ADDR 0x000048#define AW1722 149#define AW1732 250#define CHIP_NAME AW17225152#define SZ_1K (0x00000400U )53#define SZ_16K (0x00004000U )5455#define SWAP16(d) (((d & 0xff) << 8) | ((d & 0xff00) >> 8))56#define SWAP32(d) (((d & 0xff) << 24) | ((d & 0xff00) << 8) \57| ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24))5859#define CMD_ID(group, key) (((group) << 3) | (key))6061/*----------------------------*/62/* COMMANDS FORM PC TO MCU */63/*----------------------------*/64#define CMD_ID_MEMRW 0x0065#define CMD_ID_SEQRQ 0x0166#define CMD_ID_SYSCTL 0x0267#define CMD_ID_FLASH 0x036869#define CMD_ID_SEQRD CMD_ID(CMD_ID_SEQRQ, 0)70#define CMD_ID_SEQWR CMD_ID(CMD_ID_SEQRQ, 1)71/* uart commands */72#define CMD_ID_SETUART CMD_ID(CMD_ID_SYSCTL, 0)73#define CMD_ID_SETPC CMD_ID(CMD_ID_SYSCTL, 3)7475#define CMD_WRITEN 076#define CMD_WRITESEQ 177#define CMD_SETBAUD 278#define CMD_SETPC 379#define DATA_RAW 48081/******************************************************************************82** Type definitions83******************************************************************************/8485/* vendor serial control block */86typedef struct87{88int fd; /* fd to Bluetooth device */89struct termios *ti; /* serial terminal of BT port */90} vnd_userial_cb_t;9192#pragma pack(1)93/* command header94*95* byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 -7 byte 8-1196* ___________________________________________________________________________________________________97* | | | | | | | | |98* | 'B' | 'R' | 'O' | 'M' | Flags |Reserved | Checksum | Playload Length |99* |_________|_________|_________|_________|_________|_________|__________ ________|___________________|100*/101typedef struct {102uint8_t magic[4]; // magic "BROM"103#define CMD_BROM_MAGIC "BROM"104uint8_t flags;105#define CMD_HFLAG_ERROR (0x1U << 0)106#define CMD_HFLAG_ACK (0x1U << 1)107#define CMD_HFLAG_CHECK (0x1U << 2)108#define CMD_HFLAG_RETRY (0x1U << 3)109#define CMD_HFLAG_EXE (0x1U << 4)110uint8_t version:4;111uint8_t reserved:4;112uint16_t checksum;113uint32_t payload_len;114} __attribute__((packed)) cmd_header_t;115#define MB_CMD_HEADER_SIZE (sizeof(cmd_header_t))116117/* acknownledge structure */118typedef struct {119cmd_header_t h;120uint8_t err;121} __attribute__((packed)) cmd_ack_t;122123/* sequence read/write command structure */124typedef struct {125cmd_header_t h;126uint8_t cmdid;127uint32_t addr;128uint32_t dlen;129uint16_t dcs;130} __attribute__((packed)) cmd_seq_wr_t;131132/* io change command structure */133typedef struct {134cmd_header_t h;135uint8_t cmdid;136uint32_t val;137} __attribute__((packed)) cmd_sys_t;138139typedef struct {140cmd_header_t h;141uint8_t cmdid;142uint32_t lcr;143} __attribute__((packed)) cmd_sys_setuart_t;144145#pragma pack()146147static const uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };148static const uint8_t hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x04, 0x60, 0xE3, 0x16, 0x00};149static vnd_userial_cb_t vnd_userial;150151static int32_t cmd_sync_uart(void);152static int32_t cmd_sync_baud(uint32_t lcr);153static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data);154static int32_t cmd_set_pc(uint32_t pc);155static void userial_set_hw_fctrl(uint8_t hw_fctrl);156static uint32_t userial_read(uint8_t *p_buffer, uint32_t len, uint32_t timeout);157static uint32_t userial_write(const uint8_t *p_data, uint32_t len);158159/******************************************************************************160** Functions161******************************************************************************/162static uint16_t CheckSum16(uint8_t *data, uint32_t len)163{164uint16_t cs = 0;165uint16_t *p = (uint16_t *)data;166167while(len > 1) {168cs += *p++;169len -= 2;170}171if (len) {172cs += *(uint8_t *)p;173}174return cs;175}176177static uint64_t time_gettimeofday_us(void)178{179struct timeval tv;180gettimeofday(&tv, NULL);181return (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;182}183184static uint8_t *memsearch(uint8_t *haystack, uint32_t hlen, uint8_t *needle, uint32_t nlen)185{186while (hlen-- >= nlen) {187if (!memcmp(haystack, needle, nlen)) {188return haystack;189}190haystack++;191}192return NULL;193}194195static int32_t xr_raw_write(int type, uint8_t *data, uint32_t len)196{197uint8_t buffer[MB_CMD_HEADER_SIZE + 13] = {'B', 'R', 'O', 'M', 0, 0, 0, 0, 0, 0, 0, 0};198uint8_t *psend = data;199uint32_t lsend = len;200cmd_header_t *hdr = (cmd_header_t *)buffer;;201cmd_ack_t *ack = (cmd_ack_t *)buffer;202203if (type != DATA_RAW) {204psend = buffer;205lsend = MB_CMD_HEADER_SIZE + len;206memcpy(buffer + MB_CMD_HEADER_SIZE, data, len);207hdr->payload_len = len;208#if ENABLE_DCS209hdr->flags = CMD_HFLAG_CHECK;210#endif211hdr->checksum = ~CheckSum16(buffer, MB_CMD_HEADER_SIZE + len);212hdr->payload_len = SWAP32(hdr->payload_len);213hdr->checksum = SWAP16(hdr->checksum);214switch (type) {215case CMD_WRITESEQ:216{217cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer;218cmd->addr = SWAP32(cmd->addr);219cmd->dlen = SWAP32(cmd->dlen);220cmd->dcs = SWAP16(cmd->dcs);221}222break;223case CMD_SETBAUD:224{225cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer;226cmd->lcr = SWAP32(cmd->lcr);227}228break;229case CMD_SETPC:230{231cmd_sys_t *cmd = (cmd_sys_t*)buffer;232cmd->val = SWAP32(cmd->val);233}234break;235default:236XR_ERR("%s: Unsupport type %d", __func__, type);237return -1;238}239}240241ssize_t ret_w, ret_r;242uint64_t t0, t1, t2, t3;243244tcflush(vnd_userial.fd, TCIOFLUSH);245246t0 = time_gettimeofday_us();247ret_w = userial_write(psend, lsend);248t1 = time_gettimeofday_us();249250memset(buffer, 0, MB_CMD_HEADER_SIZE + 1);251252t2 = time_gettimeofday_us();253ret_r = userial_read(buffer, MB_CMD_HEADER_SIZE, 100000);254t3 = time_gettimeofday_us();255256XR_DBG("%s, type: %d, write len: %5d, ret: %5d, time: %6lluus, read len: %2d, ret: %2d, %6lluus",257__func__, type, lsend, ret_w, t1 - t0, MB_CMD_HEADER_SIZE, ret_r, t3 - t2);258259uint8_t *p = (uint8_t *)memsearch(buffer, MB_CMD_HEADER_SIZE, (uint8_t *)"BROM", 4);260if (p != buffer) {261if (p == NULL) {262XR_ERR("%s: invalid response", __func__);263return -1;264}265uint32_t nowread = buffer + MB_CMD_HEADER_SIZE - p;266uint32_t needread = p - buffer;267XR_DBG("%s: Index error, re-find header magic", __func__);268memcpy(buffer, p, nowread);269memset(buffer + nowread, 0x0, needread);270userial_read(buffer + nowread, needread, 100000);271}272273/* check response */274if (ack->h.flags & CMD_HFLAG_ERROR) {275userial_read(buffer + MB_CMD_HEADER_SIZE, 1, 100000);276XR_ERR("%s: resp error flag, type %d", __func__, ack->err);277return -ack->err;278}279280if (ack->h.flags & CMD_HFLAG_ACK) {281/* convert network byte order to host byte order */282ack->h.payload_len = SWAP32(ack->h.payload_len);283ack->h.checksum = SWAP16(ack->h.checksum);284if (ack->h.payload_len != 0) {285XR_ERR("%s: data payload len %d != 0", __func__, ack->h.payload_len);286return -1;287}288}289290if (ack->h.flags & CMD_HFLAG_CHECK) {291if (CheckSum16(buffer, MB_CMD_HEADER_SIZE) != 0xffff) {292XR_ERR("%s: write data response 0 checksum error", __func__);293return -1;294}295}296return 0;297}298299static int32_t cmd_sync_uart(void)300{301uint8_t sync = 0x55;302uint8_t ack[3] = {0};303ssize_t ret = -1;304uint32_t cnt = 0;305306do {307XR_DBG("uart sync count:%d.", cnt);308tcflush(vnd_userial.fd, TCIOFLUSH);309userial_write(&sync, 1);310ret = userial_read(ack, 2, 2000);311if (ret == 2 && ((ack[0] == 'O' && ack[1] == 'K') || (ack[0] == 'K' && ack[1] == 'O'))) {312XR_DBG("Receive %s, uart Sync done.", ack);313return 0;314}315} while (cnt++ < 50);316317XR_DBG("uart sync fail.");318return -1;319}320321static int32_t cmd_sync_baud(uint32_t lcr)322{323uint8_t buffer[MB_CMD_HEADER_SIZE + 5];324cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer;325326cmd->cmdid = CMD_ID_SETUART;327cmd->lcr = lcr;328329uint8_t cnt = 0;330int ret = -1;331332do {333XR_DBG("%s count:%d.", __func__, cnt);334ret = xr_raw_write(CMD_SETBAUD, buffer + MB_CMD_HEADER_SIZE, 5);335if (ret == 0) {336set_speed(vnd_userial.fd, vnd_userial.ti, lcr & 0xffffff);337return cmd_sync_uart();338}339} while (cnt++ < 3);340341XR_DBG("cmd_sync_baud fail.");342return -1;343}344345static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data)346{347int ret = -1;348uint8_t buffer[MB_CMD_HEADER_SIZE + 13];349cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer;350351cmd->cmdid = CMD_ID_SEQWR;352cmd->addr = addr;353cmd->dlen = len;354#if ENABLE_DCS355cmd->dcs = ~CheckSum16(data, len);356#endif357358ret = xr_raw_write(CMD_WRITESEQ, buffer + MB_CMD_HEADER_SIZE, 11);359if (ret == 0) {360return xr_raw_write(DATA_RAW, data, len);361}362return ret;363}364365static int32_t cmd_set_pc(uint32_t pc)366{367uint8_t buffer[MB_CMD_HEADER_SIZE + 5];368cmd_sys_t *cmd = (cmd_sys_t*)buffer;369370cmd->cmdid = CMD_ID_SETPC;371cmd->val = pc;372XR_DBG("set pc %x, val %x", pc, cmd->val);373374return xr_raw_write(CMD_SETPC, buffer + MB_CMD_HEADER_SIZE, 5);375}376377static void userial_set_hw_fctrl(uint8_t hw_fctrl)378{379if (vnd_userial.fd == -1) {380XR_ERR("vnd_userial.fd is -1");381return;382}383384if (hw_fctrl) {385XR_DBG("Set HW FlowControl On");386vnd_userial.ti->c_cflag |= CRTSCTS;387} else {388XR_DBG("Set HW FlowControl Off");389vnd_userial.ti->c_cflag &= ~CRTSCTS;390}391tcsetattr(vnd_userial.fd, TCSANOW, vnd_userial.ti);392tcflush(vnd_userial.fd, TCIOFLUSH);393}394395static uint32_t userial_read(uint8_t *buffer, uint32_t len, uint32_t timeout)396{397fd_set set;398struct timeval tv;399int rv;400401FD_ZERO(&set); /* clear the set */402FD_SET(vnd_userial.fd, &set); /* add our file descriptor to the set */403404/* there was data to read */405ssize_t r;406uint8_t *pos = (uint8_t*)buffer;407408while (len > 0) {409tv.tv_sec = 0;410tv.tv_usec = timeout;411412rv = select(vnd_userial.fd + 1, &set, NULL, NULL, &tv);413if(rv == -1) {414XR_ERR("select error"); /* an error accured */415break;416} else if(rv == 0) {417XR_ERR("read timeout"); /* a timeout occured */418break;419}420421r = read(vnd_userial.fd, pos, len);422if (r < 1)423break;424425len -= r;426pos += r;427}428429return pos - buffer;430}431432static uint32_t userial_write(const uint8_t *buffer, uint32_t len)433{434ssize_t r;435uint8_t *pos = (uint8_t*)buffer;436437while (len > 0) {438r = write(vnd_userial.fd, pos, len);439if (r < 1)440break;441442len -= r;443pos += r;444}445446return pos - buffer;447}448449static int32_t load_btfirmware(void)450{451FILE *fwfile_fd = NULL;452uint32_t len;453uint8_t *data = NULL;454uint32_t addr = BT_FW_LOAD_ADDR;455uint32_t section = SZ_16K;456457fwfile_fd = fopen(BT_FW_PATH_NAME, "rb");458XR_DBG("BT firmware: %s", BT_FW_PATH_NAME);459if(!fwfile_fd) {460XR_ERR("Unable to open BT firmware %s", BT_FW_PATH_NAME);461return -1;462}463464data = (uint8_t*)malloc(section);465if (data == NULL) {466XR_DBG("failed to alloc %d byte memory.", section);467fclose(fwfile_fd);468return -1;469}470471XR_DBG("load bt firmware starting.");472while ((len = fread(data, 1, section, fwfile_fd)) > 0) {473cmd_write_seq(addr, len, data);474addr += len;475}476477free(data);478fclose(fwfile_fd);479XR_DBG("load firmware done.");480481XR_DBG("Firmware run from address 0x%08X", BT_FW_JUMP_ADDR);482cmd_set_pc(BT_FW_JUMP_ADDR);483484if (CHIP_NAME == AW1732) {485XR_DBG("second time sync starting....");486if (cmd_sync_uart() < 0)487return -1;488cmd_set_pc(BT_FW_JUMP_ADDR);489}490return addr;491}492493static int hci_cmd_handle(const uint8_t *cmd, uint32_t cmd_len, uint32_t event_len)494{495uint8_t buffer[256];496497XR_DBG("send hci command");498userial_write(cmd, cmd_len);499XR_DUMP(cmd, cmd_len);500501if (read_hci_event(vnd_userial.fd, buffer, event_len) != event_len) {502XR_ERR("Event read error");503return -1;504}505XR_DBG("Received event");506XR_DUMP(buffer, event_len);507return 0;508}509510int xr_init(int fd, struct uart_t *u, struct termios *ti)511{512vnd_userial.fd = fd;513vnd_userial.ti = ti;514515XR_DBG("uart sync starting....");516if (cmd_sync_uart() < 0)517goto END;518XR_DBG("set bandrate to %d.", u->speed);519if (cmd_sync_baud(((u->speed) | (3<<24))) < 0)520goto END;521if (load_btfirmware() < 0)522goto END;523XR_DBG("bt firmware is running....");524525XR_DBG("set baudrate to %d", u->init_speed);526set_speed(vnd_userial.fd, vnd_userial.ti, u->init_speed);527userial_set_hw_fctrl(1);528usleep(50000);529530XR_DBG("process hci reset...");531if (hci_cmd_handle(hci_reset, sizeof(hci_reset), 7) < 0)532goto END;533534XR_DBG("process hci update baud...");535if (hci_cmd_handle(hci_update_baud_rate, sizeof(hci_update_baud_rate), 7) < 0)536goto END;537538usleep(100000);539540return 0;541542END:543XR_DBG("device fd = %d close", fd);544close(vnd_userial.fd);545vnd_userial.fd = -1;546vnd_userial.ti = NULL;547548return -1;549}550551int xr_post(int fd, struct uart_t *u, struct termios *ti)552{553XR_DBG("Done setting line discpline");554return 0;555}556557558559