1547 lines
41 KiB
Diff
Executable File
1547 lines
41 KiB
Diff
Executable File
Index: bluez-5.38/Makefile.in
|
|
===================================================================
|
|
--- bluez-5.38/Makefile.in
|
|
+++ bluez-5.38/Makefile.in
|
|
@@ -1235,7 +1235,8 @@ am__tools_hciattach_SOURCES_DIST = tools
|
|
tools/hciattach_st.c tools/hciattach_ti.c \
|
|
tools/hciattach_tialt.c tools/hciattach_ath3k.c \
|
|
tools/hciattach_qualcomm.c tools/hciattach_intel.c \
|
|
- tools/hciattach_bcm43xx.c
|
|
+ tools/hciattach_bcm43xx.c \
|
|
+ tools/hciattach_xradio.c
|
|
@TOOLS_TRUE@am_tools_hciattach_OBJECTS = tools/hciattach.$(OBJEXT) \
|
|
@TOOLS_TRUE@ tools/hciattach_st.$(OBJEXT) \
|
|
@TOOLS_TRUE@ tools/hciattach_ti.$(OBJEXT) \
|
|
@@ -1243,7 +1244,8 @@ am__tools_hciattach_SOURCES_DIST = tools
|
|
@TOOLS_TRUE@ tools/hciattach_ath3k.$(OBJEXT) \
|
|
@TOOLS_TRUE@ tools/hciattach_qualcomm.$(OBJEXT) \
|
|
@TOOLS_TRUE@ tools/hciattach_intel.$(OBJEXT) \
|
|
-@TOOLS_TRUE@ tools/hciattach_bcm43xx.$(OBJEXT)
|
|
+@TOOLS_TRUE@ tools/hciattach_bcm43xx.$(OBJEXT) \
|
|
+@TOOLS_TRUE@ tools/hciattach_xradio.$(OBJEXT)
|
|
tools_hciattach_OBJECTS = $(am_tools_hciattach_OBJECTS)
|
|
@TOOLS_TRUE@tools_hciattach_DEPENDENCIES = \
|
|
@TOOLS_TRUE@ lib/libbluetooth-internal.la
|
|
@@ -2581,7 +2583,8 @@ unit_tests = $(am__append_35) unit/test-
|
|
@TOOLS_TRUE@ tools/hciattach_ath3k.c \
|
|
@TOOLS_TRUE@ tools/hciattach_qualcomm.c \
|
|
@TOOLS_TRUE@ tools/hciattach_intel.c \
|
|
-@TOOLS_TRUE@ tools/hciattach_bcm43xx.c
|
|
+@TOOLS_TRUE@ tools/hciattach_bcm43xx.c \
|
|
+@TOOLS_TRUE@ tools/hciattach_xradio.c
|
|
|
|
@TOOLS_TRUE@tools_hciattach_LDADD = lib/libbluetooth-internal.la
|
|
@TOOLS_TRUE@tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
|
|
@@ -4702,6 +4705,8 @@ tools/hciattach_intel.$(OBJEXT): tools/$
|
|
tools/$(DEPDIR)/$(am__dirstamp)
|
|
tools/hciattach_bcm43xx.$(OBJEXT): tools/$(am__dirstamp) \
|
|
tools/$(DEPDIR)/$(am__dirstamp)
|
|
+tools/hciattach_xradio.$(OBJEXT): tools/$(am__dirstamp) \
|
|
+ tools/$(DEPDIR)/$(am__dirstamp)
|
|
|
|
tools/hciattach$(EXEEXT): $(tools_hciattach_OBJECTS) $(tools_hciattach_DEPENDENCIES) $(EXTRA_tools_hciattach_DEPENDENCIES) tools/$(am__dirstamp)
|
|
@rm -f tools/hciattach$(EXEEXT)
|
|
@@ -5569,6 +5574,7 @@ distclean-compile:
|
|
@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach.Po@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ath3k.Po@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_bcm43xx.Po@am__quote@
|
|
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_xradio.Po@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_intel.Po@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_qualcomm.Po@am__quote@
|
|
@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_st.Po@am__quote@
|
|
Index: bluez-5.38/Makefile.tools
|
|
===================================================================
|
|
--- bluez-5.38/Makefile.tools
|
|
+++ bluez-5.38/Makefile.tools
|
|
@@ -163,7 +163,8 @@ tools_hciattach_SOURCES = tools/hciattac
|
|
tools/hciattach_ath3k.c \
|
|
tools/hciattach_qualcomm.c \
|
|
tools/hciattach_intel.c \
|
|
- tools/hciattach_bcm43xx.c
|
|
+ tools/hciattach_bcm43xx.c \
|
|
+ tools/hciattach_xradio.c
|
|
tools_hciattach_LDADD = lib/libbluetooth-internal.la
|
|
|
|
tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
|
|
Index: bluez-5.38/tools/hciattach.c
|
|
===================================================================
|
|
--- bluez-5.38/tools/hciattach.c
|
|
+++ bluez-5.38/tools/hciattach.c
|
|
@@ -349,6 +349,11 @@ static int bcm43xx(int fd, struct uart_t
|
|
return bcm43xx_init(fd, u->init_speed, u->speed, ti, u->bdaddr);
|
|
}
|
|
|
|
+static int xradio(int fd, struct uart_t *u, struct termios *ti)
|
|
+{
|
|
+ return xradio_init(fd, u->init_speed, u->speed, ti, u->bdaddr);
|
|
+}
|
|
+
|
|
static int read_check(int fd, void *buf, int count)
|
|
{
|
|
int res;
|
|
@@ -1164,6 +1169,10 @@ struct uart_t uart[] = {
|
|
{ "bcm43xx-3wire", 0x0000, 0x0000, HCI_UART_3WIRE, 115200, 3000000,
|
|
0, DISABLE_PM, NULL, bcm43xx, NULL },
|
|
|
|
+ /* Xradio XR829 */
|
|
+ { "xradio", 0x0000, 0x0000, HCI_UART_H4, 115200, 1500000,
|
|
+ 0, DISABLE_PM, NULL, xradio, NULL },
|
|
+
|
|
{ "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200,
|
|
FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm },
|
|
|
|
@@ -1234,7 +1243,11 @@ static int init_uart(char *dev, struct u
|
|
|
|
cfmakeraw(&ti);
|
|
|
|
- ti.c_cflag |= CLOCAL;
|
|
+ /* ti.c_cflag |= CLOCAL; */
|
|
+ ti.c_cflag |= CS8;
|
|
+ ti.c_cflag &= ~(PARENB | PARODD);
|
|
+ ti.c_cflag &= ~(CSTOPB);
|
|
+
|
|
if (u->flags & FLOW_CTL)
|
|
ti.c_cflag |= CRTSCTS;
|
|
else
|
|
@@ -1245,6 +1258,14 @@ static int init_uart(char *dev, struct u
|
|
goto fail;
|
|
}
|
|
|
|
+ tcflush(fd, TCIOFLUSH);
|
|
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
|
|
+ perror("Can't set port settings");
|
|
+ goto fail;
|
|
+ }
|
|
+ tcflush(fd, TCIOFLUSH);
|
|
+ tcflush(fd, TCIOFLUSH);
|
|
+
|
|
/* Set initial baudrate */
|
|
if (set_speed(fd, &ti, u->init_speed) < 0) {
|
|
perror("Can't set initial baud rate");
|
|
@@ -1252,15 +1273,16 @@ static int init_uart(char *dev, struct u
|
|
}
|
|
|
|
tcflush(fd, TCIOFLUSH);
|
|
-
|
|
+#if 0
|
|
if (send_break) {
|
|
tcsendbreak(fd, 0);
|
|
usleep(500000);
|
|
}
|
|
+#endif
|
|
|
|
if (u->init && u->init(fd, u, &ti) < 0)
|
|
goto fail;
|
|
-
|
|
+#if 0
|
|
tcflush(fd, TCIOFLUSH);
|
|
|
|
/* Set actual baudrate */
|
|
@@ -1288,7 +1310,7 @@ static int init_uart(char *dev, struct u
|
|
|
|
if (u->post && u->post(fd, u, &ti) < 0)
|
|
goto fail;
|
|
-
|
|
+#endif
|
|
return fd;
|
|
|
|
fail:
|
|
Index: bluez-5.38/tools/hciattach.h
|
|
===================================================================
|
|
--- bluez-5.38/tools/hciattach.h
|
|
+++ bluez-5.38/tools/hciattach.h
|
|
@@ -66,3 +66,5 @@ int qualcomm_init(int fd, int speed, str
|
|
int intel_init(int fd, int init_speed, int *speed, struct termios *ti);
|
|
int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti,
|
|
const char *bdaddr);
|
|
+int xradio_init(int fd, int def_speed, int speed, struct termios *ti,
|
|
+ const char *bdaddr);
|
|
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ bluez-5.38.orig/tools/hciattach_xradio.c
|
|
@@ -0,0 +1,1383 @@
|
|
+/*
|
|
+ *
|
|
+ * BlueZ - Bluetooth protocol stack for Linux
|
|
+ *
|
|
+ * Copyright (C) 2018 Xradio Technology Co., Ltd.. All rights reserved.
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ *
|
|
+ */
|
|
+
|
|
+#ifdef HAVE_CONFIG_H
|
|
+#include <config.h>
|
|
+#endif
|
|
+
|
|
+#include <stdio.h>
|
|
+#include <stdlib.h>
|
|
+#include <unistd.h>
|
|
+#include <termios.h>
|
|
+#include <fcntl.h>
|
|
+#include <unistd.h>
|
|
+#include <errno.h>
|
|
+#include <dirent.h>
|
|
+#include <time.h>
|
|
+#include <limits.h>
|
|
+#include <sys/ioctl.h>
|
|
+#include <signal.h>
|
|
+
|
|
+#include "lib/bluetooth.h"
|
|
+#include "lib/hci.h"
|
|
+#include "lib/hci_lib.h"
|
|
+
|
|
+#include "hciattach.h"
|
|
+
|
|
+#ifndef BT_FW_PATH_NAME
|
|
+#define BT_FW_PATH_NAME "/lib/firmware/fw_xr829_bt.bin"
|
|
+#endif
|
|
+
|
|
+#define UNUSED(x) (void)(x)
|
|
+
|
|
+#define SHOW_LOG 0
|
|
+#define SAVE_TXRX_DATA 0
|
|
+
|
|
+#define SWAP16(d) (((d & 0xff) << 8) | ((d & 0xff00) >> 8))
|
|
+#define SWAP32(d) (((d & 0xff) << 24) | ((d & 0xff00) << 8) \
|
|
+ | ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24))
|
|
+
|
|
+#define FILL_HEADER_MAGIC(h) do { \
|
|
+ (h)->magic[0] = 'B'; \
|
|
+ (h)->magic[1] = 'R'; \
|
|
+ (h)->magic[2] = 'O'; \
|
|
+ (h)->magic[3] = 'M'; \
|
|
+} while(0)
|
|
+
|
|
+#define HEADER_MAGIC_VALID(h) ( \
|
|
+ (h)->magic[0] == 'B' && \
|
|
+ (h)->magic[1] == 'R' && \
|
|
+ (h)->magic[2] == 'O' && \
|
|
+ (h)->magic[3] == 'M' )
|
|
+
|
|
+#define FILL_HEADER_CHECKSUM(h, cs) do { \
|
|
+ (h)->checksum = cs; \
|
|
+ } while(0)
|
|
+
|
|
+#define UART_BUF_RXCLEAR (1<<0)
|
|
+#define UART_BUF_TXCLEAR (1<<1)
|
|
+
|
|
+#define SZ_512 (0x00000200U )
|
|
+#define SZ_1K (0x00000400U )
|
|
+#define SZ_2K (0x00000800U )
|
|
+#define SZ_4K (0x00001000U )
|
|
+#define SZ_8K (0x00002000U )
|
|
+#define SZ_16K (0x00004000U )
|
|
+#define SZ_32K (0x00008000U )
|
|
+#define SZ_64K (0x00010000U )
|
|
+#define SZ_128K (0x00020000U )
|
|
+#define SZ_256K (0x00040000U )
|
|
+#define SZ_512K (0x00080000U )
|
|
+#define SZ_1M (0x00100000U )
|
|
+#define SZ_2M (0x00200000U )
|
|
+#define SZ_4M (0x00400000U )
|
|
+#define SZ_8M (0x00800000U )
|
|
+#define SZ_16M (0x01000000U )
|
|
+#define SZ_32M (0x02000000U )
|
|
+#define SZ_64M (0x04000000U )
|
|
+#define SZ_128M (0x08000000U )
|
|
+#define SZ_256M (0x10000000U )
|
|
+#define SZ_512M (0x20000000U )
|
|
+#define SZ_1G (0x40000000U )
|
|
+#define SZ_2G (0x80000000U )
|
|
+#define SZ_4G (0x0100000000ULL)
|
|
+#define SZ_8G (0x0200000000ULL)
|
|
+#define SZ_16G (0x0400000000ULL)
|
|
+#define SZ_32G (0x0800000000ULL)
|
|
+#define SZ_64G (0x1000000000ULL)
|
|
+
|
|
+#define CMD_REVESION 0x0000 /* 0.0.0.0 */
|
|
+#define CMD_SYNC_WORD 0x55
|
|
+#define CMD_ID(group, key) (((group) << 3) | (key))
|
|
+
|
|
+/*----------------------------*/
|
|
+/* COMMANDS FORM PC TO MCU */
|
|
+/*----------------------------*/
|
|
+#define CMD_ID_MEMRW 0x00
|
|
+#define CMD_ID_SEQRQ 0x01
|
|
+#define CMD_ID_SYSCTL 0x02
|
|
+#define CMD_ID_FLASH 0x03
|
|
+/* memory access commands */
|
|
+#define CMD_ID_READ1 CMD_ID(CMD_ID_MEMRW, 0)
|
|
+#define CMD_ID_WRITE1 CMD_ID(CMD_ID_MEMRW, 1)
|
|
+#define CMD_ID_READ2 CMD_ID(CMD_ID_MEMRW, 2)
|
|
+#define CMD_ID_WRITE2 CMD_ID(CMD_ID_MEMRW, 3)
|
|
+#define CMD_ID_READ4 CMD_ID(CMD_ID_MEMRW, 4)
|
|
+#define CMD_ID_WRITE4 CMD_ID(CMD_ID_MEMRW, 5)
|
|
+#define CMD_ID_READ8 CMD_ID(CMD_ID_MEMRW, 6)
|
|
+#define CMD_ID_WRITE8 CMD_ID(CMD_ID_MEMRW, 7)
|
|
+
|
|
+#define CMD_ID_SEQRD CMD_ID(CMD_ID_SEQRQ, 0)
|
|
+#define CMD_ID_SEQWR CMD_ID(CMD_ID_SEQRQ, 1)
|
|
+/* uart commands */
|
|
+#define CMD_ID_SETUART CMD_ID(CMD_ID_SYSCTL, 0)
|
|
+#define CMD_ID_SETJTAG CMD_ID(CMD_ID_SYSCTL, 1)
|
|
+#define CMD_ID_REBOOT CMD_ID(CMD_ID_SYSCTL, 2)
|
|
+#define CMD_ID_SETPC CMD_ID(CMD_ID_SYSCTL, 3)
|
|
+#define CMD_ID_SETCKCS CMD_ID(CMD_ID_SYSCTL, 4)
|
|
+/* flash operation commands */
|
|
+#define CMD_ID_FLASH_GETINFO CMD_ID(CMD_ID_FLASH, 0)
|
|
+#define CMD_ID_FLASH_ERASE CMD_ID(CMD_ID_FLASH, 1)
|
|
+#define CMD_ID_FLASH_READ CMD_ID(CMD_ID_FLASH, 2)
|
|
+#define CMD_ID_FLASH_WRITE CMD_ID(CMD_ID_FLASH, 3)
|
|
+
|
|
+/*----------------------------*/
|
|
+/* COMMANDS FORM MCU TO PC */
|
|
+/*----------------------------*/
|
|
+/* message output */
|
|
+#define CMD_ID_SENDMSG CMD_ID(0, 0)
|
|
+
|
|
+#pragma pack(1)
|
|
+/* command header
|
|
+ *
|
|
+ * byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 byte 6 -7 byte 8-11
|
|
+ * ___________________________________________________________________________________________________
|
|
+ * | | | | | | | | |
|
|
+ * | 'B' | 'R' | 'O' | 'M' | Flags |Reserved | Checksum | Playload Length |
|
|
+ * |_________|_________|_________|_________|_________|_________|__________ ________|___________________|
|
|
+ */
|
|
+typedef struct {
|
|
+ unsigned char magic[4]; /* magic "BROM" */
|
|
+ #define CMD_BROM_MAGIC "BROM"
|
|
+ unsigned char flags;
|
|
+ #define CMD_HFLAG_ERROR (0x1U << 0)
|
|
+ #define CMD_HFLAG_ACK (0x1U << 1)
|
|
+ #define CMD_HFLAG_CHECK (0x1U << 2)
|
|
+ #define CMD_HFLAG_RETRY (0x1U << 3)
|
|
+ #define CMD_HFLAG_EXE (0x1U << 4)
|
|
+ unsigned char version:4;
|
|
+ unsigned char reserved:4;
|
|
+ unsigned short checksum;
|
|
+ unsigned int payload_len;
|
|
+} __attribute__((packed)) cmd_header_t;
|
|
+#define MB_CMD_HEADER_SIZE (sizeof(cmd_header_t))
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+} __attribute__((packed)) cmd_header_id_t;
|
|
+#define MB_HEADER_TO_ID(h) (((cmd_header_id_t*)(h))->cmdid)
|
|
+
|
|
+/* acknownledge structure */
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char err;
|
|
+} __attribute__((packed)) cmd_ack_t;
|
|
+
|
|
+/* memory read/write command structure */
|
|
+#define CMD_RW_DATA_POS (MB_CMD_HEADER_SIZE + 5)
|
|
+#define CMD_RW_DATA_LEN(id) (1 << ((id >> 1) & 0x3))
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int addr;
|
|
+} __attribute__((packed)) cmd_rw_t;
|
|
+
|
|
+/* sequence read/write command structure */
|
|
+#define CMD_SEQRW_DATA_POS (MB_CMD_HEADER_SIZE + 5)
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int addr;
|
|
+ unsigned int dlen;
|
|
+ unsigned short dcs;
|
|
+} __attribute__((packed)) cmd_seq_wr_t;
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int addr;
|
|
+ unsigned int dlen;
|
|
+} __attribute__((packed)) cmd_seq_rd_t;
|
|
+
|
|
+/* io change command structure */
|
|
+#define CMD_SYS_DATA_POS (MB_CMD_HEADER_SIZE + 1)
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int val;
|
|
+} __attribute__((packed)) cmd_sys_t;
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int lcr;
|
|
+} __attribute__((packed)) cmd_sys_setuart_t;
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned char mode;
|
|
+} __attribute__((packed)) cmd_sys_setjtag_t;
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned char mode;
|
|
+} __attribute__((packed)) cmd_sys_setcs_t;
|
|
+
|
|
+/* flash command structure */
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned char erase_cmd;
|
|
+ unsigned int addr;
|
|
+} __attribute__((packed)) cmd_flash_er_t;
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int sector;
|
|
+ unsigned int num;
|
|
+ unsigned short dcs;
|
|
+} __attribute__((packed)) cmd_flash_wr_t;
|
|
+
|
|
+typedef struct {
|
|
+ cmd_header_t h;
|
|
+ unsigned char cmdid;
|
|
+ unsigned int sector;
|
|
+ unsigned int num;
|
|
+} __attribute__((packed)) cmd_flash_rd_t;
|
|
+
|
|
+#pragma pack()
|
|
+
|
|
+/* response error type */
|
|
+#define MB_ERR_UNKNOWNCMD (1)
|
|
+#define MB_ERR_TIMEOUT (2)
|
|
+#define MB_ERR_CHECKSUM (3)
|
|
+#define MB_ERR_INVALID (4)
|
|
+#define MB_ERR_NOMEM (5)
|
|
+
|
|
+#define UPIO_BT_POWER_OFF 0
|
|
+#define UPIO_BT_POWER_ON 1
|
|
+
|
|
+/* UPIO signals */
|
|
+enum {
|
|
+ UPIO_BT_WAKE = 0,
|
|
+ UPIO_HOST_WAKE,
|
|
+ UPIO_LPM_MODE,
|
|
+ UPIO_MAX_COUNT
|
|
+};
|
|
+
|
|
+/* UPIO assertion/deassertion */
|
|
+enum {
|
|
+ UPIO_UNKNOWN = 0,
|
|
+ UPIO_DEASSERT,
|
|
+ UPIO_ASSERT
|
|
+};
|
|
+
|
|
+#define BT_WAKE_VIA_PROC 1
|
|
+
|
|
+/* proc fs node for enable/disable lpm mode */
|
|
+#ifndef VENDOR_LPM_PROC_NODE
|
|
+#define VENDOR_LPM_PROC_NODE "/proc/bluetooth/sleep/lpm"
|
|
+#endif
|
|
+
|
|
+/* proc fs node for sleep bt device */
|
|
+#ifndef VENDOR_BTWAKE_PROC_NODE
|
|
+#define VENDOR_BTWAKE_PROC_NODE "/proc/bluetooth/sleep/btwrite"
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * Maximum btwrite assertion holding time without consecutive btwrite kicking.
|
|
+ * This value is correlative(shorter) to the in-activity timeout period set in
|
|
+ * the bluesleep LPM code. The current value used in bluesleep is 10sec.
|
|
+ */
|
|
+#ifndef PROC_BTWAKE_TIMER_TIMEOUT_MS
|
|
+#define PROC_BTWAKE_TIMER_TIMEOUT_MS 10000
|
|
+#endif
|
|
+
|
|
+/* lpm proc control block */
|
|
+typedef struct
|
|
+{
|
|
+ uint8_t btwrite_active;
|
|
+ uint8_t timer_created;
|
|
+ timer_t timer_id;
|
|
+ uint32_t timeout_ms;
|
|
+} vnd_lpm_proc_cb_t;
|
|
+
|
|
+static unsigned char upio_state[UPIO_MAX_COUNT];
|
|
+static int rfkill_id = -1;
|
|
+static char *rfkill_state_path = NULL;
|
|
+static vnd_lpm_proc_cb_t lpm_proc_cb;
|
|
+
|
|
+/* for friendly debugging outpout string */
|
|
+static char *lpm_mode[] = {
|
|
+ "UNKNOWN",
|
|
+ "disabled",
|
|
+ "enabled"
|
|
+};
|
|
+
|
|
+static char *lpm_state[] = {
|
|
+ "UNKNOWN",
|
|
+ "de-asserted",
|
|
+ "asserted"
|
|
+};
|
|
+
|
|
+static unsigned int g_chip_name = 1; /* 1:AW1722 2:AW1732 */
|
|
+static unsigned int g_load_addr = 0x0000;
|
|
+static unsigned int g_jump_addr = 0x0000;
|
|
+static unsigned int g_port_num = 1;
|
|
+static unsigned int g_dump_debug = 1;
|
|
+static unsigned int g_hciup_flag = 1;
|
|
+static unsigned int g_startup_reset_flag =1;
|
|
+static unsigned int g_update_hcirate_flag = 1;
|
|
+static unsigned int g_bdaddr_flag = 0;
|
|
+
|
|
+static unsigned char g_trans_buf[1024];
|
|
+
|
|
+static unsigned char hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
|
|
+static unsigned char hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x04, 0x60, 0xE3, 0x16, 0x00};
|
|
+static unsigned char hci_write_bd_addr[] = { 0x01, 0x32, 0xfc, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
|
+
|
|
+static void proc_btwrite_timeout(union sigval arg)
|
|
+{
|
|
+ UNUSED(arg);
|
|
+ printf("%s.\n", __FUNCTION__);
|
|
+ lpm_proc_cb.btwrite_active = 0;
|
|
+}
|
|
+
|
|
+static void ms_delay (uint32_t timeout)
|
|
+{
|
|
+ struct timespec delay;
|
|
+ int err;
|
|
+
|
|
+ if (timeout == 0)
|
|
+ return;
|
|
+
|
|
+ delay.tv_sec = timeout / 1000;
|
|
+ delay.tv_nsec = 1000 * 1000 * (timeout%1000);
|
|
+
|
|
+ /* [u]sleep can't be used because it uses SIGALRM */
|
|
+ do {
|
|
+ err = nanosleep(&delay, &delay);
|
|
+ } while (err < 0 && errno == EINTR);
|
|
+}
|
|
+
|
|
+static unsigned short check_sum16(unsigned char *data, unsigned int len)
|
|
+{
|
|
+ unsigned short cs = 0;
|
|
+ unsigned short *p = (unsigned short*)data;
|
|
+
|
|
+ while(len > 1) {
|
|
+ cs += *p++;
|
|
+ len -= 2;
|
|
+ }
|
|
+ if (len) {
|
|
+ cs += *(unsigned char*)p;
|
|
+ }
|
|
+
|
|
+ return cs;
|
|
+}
|
|
+
|
|
+static void debug_dump(unsigned char *out, int len)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < len; i++)
|
|
+ {
|
|
+ if (i && !(i % 16))
|
|
+ {
|
|
+ fprintf(stderr, "\n");
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "%02x ", out[i]);
|
|
+ }
|
|
+
|
|
+ fprintf(stderr, "\n");
|
|
+}
|
|
+
|
|
+static void debug_dump_data(unsigned char *prompt, unsigned char *buf, unsigned int len)
|
|
+{
|
|
+#if SHOW_LOG
|
|
+ unsigned int i, j;
|
|
+ unsigned int head = 0;
|
|
+
|
|
+ printf("Dump(%s): len %d\n", prompt, len);
|
|
+ for (i = 0; i < len;) {
|
|
+ printf("0x%02x, ", buf[i]&0xff);
|
|
+ if (i % 8 == 7 || i==len-1) {
|
|
+ printf("\n");
|
|
+ }
|
|
+
|
|
+ i++;
|
|
+ }
|
|
+ printf("\n");
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void debug_write_txdata(unsigned char *buf, unsigned int len)
|
|
+{
|
|
+#if SAVE_TXRX_DATA
|
|
+ unsigned int i;
|
|
+ static unsigned int txidx = 0;
|
|
+ static unsigned int txlen = 0;
|
|
+ cmd_rw_t *cmd = (cmd_rw_t *)buf;
|
|
+ char name[16] = "txdata.hex";
|
|
+ FILE *fd;
|
|
+
|
|
+ txidx ++;
|
|
+ txlen = 0;
|
|
+
|
|
+ txlen += len;
|
|
+ sprintf(&name[strlen("txdata.hex")], "%d", txidx);
|
|
+ fd = fopen(name, "wb+");
|
|
+
|
|
+ fprintf(fd, "%02x\n", txlen & 0xff);
|
|
+ fprintf(fd, "%02x\n", (txlen>>8) & 0xff);
|
|
+ fprintf(fd, "%02x\n", (txlen>>16) & 0xff);
|
|
+ fprintf(fd, "%02x\n", (txlen>>24) & 0xff);
|
|
+
|
|
+ for (i=0; i<len; i++)
|
|
+ fprintf(fd, "%02x\n", buf[i]);
|
|
+ fclose(fd);
|
|
+#endif
|
|
+}
|
|
+
|
|
+static void debug_write_rxdata(unsigned char *buf, unsigned int len)
|
|
+{
|
|
+#if SAVE_TXRX_DATA
|
|
+ unsigned int i;
|
|
+ static unsigned int rxidx = 0;
|
|
+ static unsigned int rxlen = 0;
|
|
+ cmd_rw_t *cmd = (cmd_rw_t *)buf;
|
|
+ char name[16] = "rxdata.hex";
|
|
+ FILE *fd;
|
|
+
|
|
+ if (HEADER_MAGIC_VALID(&cmd->h)) {
|
|
+ rxidx ++;
|
|
+ rxlen = 0;
|
|
+ }
|
|
+ rxlen += len;
|
|
+ sprintf(&name[strlen("rxdata.hex")], "%d", rxidx);
|
|
+ if (HEADER_MAGIC_VALID(&cmd->h)) {
|
|
+ fd = fopen(name, "wb+");
|
|
+ fprintf(fd, "%02x\n", rxlen & 0xff);
|
|
+ fprintf(fd, "%02x\n", (rxlen>>8) & 0xff);
|
|
+ fprintf(fd, "%02x\n", (rxlen>>16) & 0xff);
|
|
+ fprintf(fd, "%02x\n", (rxlen>>24) & 0xff);
|
|
+ } else {
|
|
+ fd = fopen(name, "ab+");
|
|
+ }
|
|
+ for (i=0; i<len; i++)
|
|
+ fprintf(fd, "%02x\n", buf[i]);
|
|
+ if (!HEADER_MAGIC_VALID(&cmd->h)) {
|
|
+ fclose(fd);
|
|
+ fd = fopen(name, "rb+");
|
|
+ fseek(fd, 0, SEEK_SET);
|
|
+ fprintf(fd, "%02x\n", rxlen & 0xff);
|
|
+ fprintf(fd, "%02x\n", (rxlen>>8) & 0xff);
|
|
+ fprintf(fd, "%02x\n", (rxlen>>16) & 0xff);
|
|
+ fprintf(fd, "%02x\n", (rxlen>>24) & 0xff);
|
|
+ }
|
|
+
|
|
+ fclose(fd);
|
|
+#endif
|
|
+}
|
|
+
|
|
+static int userial_sync(int fd)
|
|
+{
|
|
+ unsigned char syncbuf[] = {0x55};
|
|
+ unsigned char ackbuf[3] = {0};
|
|
+ int ret = -1;
|
|
+ int flags;
|
|
+ int cnt = 0;
|
|
+
|
|
+ flags = fcntl(fd, F_GETFL);
|
|
+ flags |= O_NONBLOCK;
|
|
+ if (fcntl(fd, F_SETFL, flags) == -1) {
|
|
+ printf("[%s] fcntl NONBLOCK fail.\n", __FUNCTION__);
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+
|
|
+ /*
|
|
+ * sync success or stop by alarm.
|
|
+ */
|
|
+ do {
|
|
+ printf("[%s] uart sync count: %d.\n", __FUNCTION__, ++cnt);
|
|
+ write(fd, syncbuf, 1);
|
|
+ usleep(20000);
|
|
+ ret = read(fd, ackbuf, 2);
|
|
+ printf("[%s] read buf: %02x %02x.\n", __FUNCTION__, ackbuf[0], ackbuf[1]);
|
|
+ if (ret < 0) {
|
|
+ if (errno == EAGAIN)
|
|
+ continue;
|
|
+ }
|
|
+ if (ret == 2 && ((ackbuf[0] == 'O' && ackbuf[1] == 'K')
|
|
+ || (ackbuf[0] == 'K' && ackbuf[1] == 'O'))) {
|
|
+ printf("[%s] Receive %s, uart sync done.\n", __FUNCTION__, ackbuf);
|
|
+ break;
|
|
+ }
|
|
+ } while (1);
|
|
+
|
|
+ flags &= ~(O_NONBLOCK);
|
|
+ if (fcntl(fd, F_SETFL, flags) == -1) {
|
|
+ printf("[%s] fcntl BLOCK fail.\n", __FUNCTION__);
|
|
+ exit(-1);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void userial_vendor_set_hw_fctrl(int fd, uint8_t hw_fctrl)
|
|
+{
|
|
+ struct termios ti;
|
|
+
|
|
+ if (fd == -1)
|
|
+ {
|
|
+ printf("fd is -1\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (tcgetattr(fd, &ti) < 0) {
|
|
+ perror("Can't get port settings");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if(hw_fctrl)
|
|
+ {
|
|
+ printf("Set HW FlowControl On\n");
|
|
+ if(ti.c_cflag & CRTSCTS)
|
|
+ {
|
|
+ printf("userial_vendor_set_hw_fctrl already hw flowcontrol on\n");
|
|
+ return;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ ti.c_cflag |= CRTSCTS;
|
|
+ tcsetattr(fd, TCSANOW, &ti);
|
|
+ printf("userial_vendor_set_hw_fctrl set hw flowcontrol on\n");
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ printf("Set HW FlowControl Off\n");
|
|
+ if(ti.c_cflag & CRTSCTS)
|
|
+ {
|
|
+ ti.c_cflag &= ~CRTSCTS;
|
|
+ tcsetattr(fd, TCSANOW, &ti);
|
|
+ return;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ printf("userial_vendor_set_hw_fctrl set hw flowcontrol off\n");
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ tcflush(fd, TCIOFLUSH);
|
|
+}
|
|
+
|
|
+static void userial_clearbuf(int fd, uint8_t flag)
|
|
+{
|
|
+ if (flag == UART_BUF_RXCLEAR)
|
|
+ tcflush(fd, TCIFLUSH);
|
|
+ else if (flag == UART_BUF_TXCLEAR)
|
|
+ tcflush(fd, TCOFLUSH);
|
|
+ else
|
|
+ tcflush(fd, TCIOFLUSH);
|
|
+}
|
|
+
|
|
+static uint16_t userial_read(int fd, uint8_t *p_buffer, uint16_t len)
|
|
+{
|
|
+ int ret = -1;
|
|
+ uint16_t total_len = 0;
|
|
+
|
|
+ do {
|
|
+ ret = read(fd, p_buffer + total_len, len);
|
|
+ if(ret == -1)
|
|
+ {
|
|
+ printf("%s error writing to serial port: %s.\n", __func__, strerror(errno));
|
|
+ return total_len;
|
|
+ }
|
|
+ total_len += ret;
|
|
+ len -= ret;
|
|
+ } while(len);
|
|
+
|
|
+ return total_len;
|
|
+}
|
|
+
|
|
+static uint16_t userial_write(int fd, const uint8_t *p_data, uint16_t len)
|
|
+{
|
|
+ uint16_t total = 0;
|
|
+ int ret;
|
|
+
|
|
+ while (len) {
|
|
+ ret = write(fd, p_data + total, len);
|
|
+ switch (ret) {
|
|
+ case -1:
|
|
+ printf("%s error writing to serial port: %s.\n", __func__, strerror(errno));
|
|
+ return total;
|
|
+ case 0:
|
|
+ return total;
|
|
+ default:
|
|
+ total += ret;
|
|
+ len -= ret;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ return total;
|
|
+}
|
|
+
|
|
+static int userial_vendor_set_baud(int fd, int def_speed)
|
|
+{
|
|
+ struct termios ti;
|
|
+
|
|
+ if (tcgetattr(fd, &ti) < 0) {
|
|
+ perror("Can't get port settings");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ if (set_speed(fd, &ti, def_speed) < 0) {
|
|
+ perror("Can't set initial baud rate");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void read_event(int fd, unsigned char *buffer)
|
|
+{
|
|
+ int i = 0;
|
|
+ int len = 3;
|
|
+ int count;
|
|
+
|
|
+ while ((count = read(fd, &buffer[i], len)) < len)
|
|
+ {
|
|
+ i += count;
|
|
+ len -= count;
|
|
+ }
|
|
+
|
|
+ i += count;
|
|
+ len = buffer[2];
|
|
+
|
|
+ while ((count = read(fd, &buffer[i], len)) < len)
|
|
+ {
|
|
+ i += count;
|
|
+ len -= count;
|
|
+ }
|
|
+
|
|
+ if (g_dump_debug)
|
|
+ {
|
|
+ count += i;
|
|
+
|
|
+ fprintf(stderr, "received %d\n", count);
|
|
+ debug_dump(buffer, count);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void xradio_hci_send_cmd(int fd, unsigned char *buf, int len)
|
|
+{
|
|
+ if (g_dump_debug)
|
|
+ {
|
|
+ fprintf(stderr, "writing\n");
|
|
+ debug_dump(buf, len);
|
|
+ }
|
|
+
|
|
+ write(fd, buf, len);
|
|
+}
|
|
+
|
|
+static void proc_reset(int fd)
|
|
+{
|
|
+ /* signal(SIGALRM, expired); */
|
|
+
|
|
+ xradio_hci_send_cmd(fd, hci_reset, sizeof(hci_reset));
|
|
+ /* alarm(4); */
|
|
+ read_event(fd, g_trans_buf);
|
|
+ /* alarm(0); */
|
|
+}
|
|
+
|
|
+static void proc_baudrate(int fd, int speed)
|
|
+{
|
|
+ xradio_hci_send_cmd(fd, hci_update_baud_rate, sizeof(hci_update_baud_rate));
|
|
+
|
|
+ read_event(fd, g_trans_buf);
|
|
+
|
|
+ userial_vendor_set_baud(fd, speed);
|
|
+ ms_delay(100);
|
|
+
|
|
+ if (g_dump_debug)
|
|
+ {
|
|
+ fprintf(stderr, "Done setting baudrate\n");
|
|
+ }
|
|
+}
|
|
+
|
|
+static void proc_bdaddr(int fd)
|
|
+{
|
|
+ xradio_hci_send_cmd(fd, hci_write_bd_addr, sizeof(hci_write_bd_addr));
|
|
+
|
|
+ read_event(fd, g_trans_buf);
|
|
+}
|
|
+
|
|
+static void proc_enable_hci(int fd)
|
|
+{
|
|
+ int i = N_HCI;
|
|
+ int proto = HCI_UART_H4;
|
|
+ if (ioctl(fd, TIOCSETD, &i) < 0) {
|
|
+ fprintf(stderr, "Can't set line discipline\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
|
|
+ fprintf(stderr, "Can't set hci protocol\n");
|
|
+ return;
|
|
+ }
|
|
+ fprintf(stderr, "Done setting line discpline\n");
|
|
+ return;
|
|
+}
|
|
+
|
|
+static int init_rfkill(void)
|
|
+{
|
|
+ char path[64];
|
|
+ char buf[16];
|
|
+ int fd, sz, id;
|
|
+
|
|
+ for (id = 0; ; id++)
|
|
+ {
|
|
+ snprintf(path, sizeof(path), "/sys/class/rfkill/rfkill%d/type", id);
|
|
+ fd = open(path, O_RDONLY);
|
|
+ if (fd < 0)
|
|
+ {
|
|
+ printf("init_rfkill : open(%s) failed: %s (%d).\n", \
|
|
+ path, strerror(errno), errno);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ sz = read(fd, &buf, sizeof(buf));
|
|
+ close(fd);
|
|
+
|
|
+ if (sz >= 9 && memcmp(buf, "bluetooth", 9) == 0)
|
|
+ {
|
|
+ rfkill_id = id;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ asprintf(&rfkill_state_path, "/sys/class/rfkill/rfkill%d/state", rfkill_id);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int upio_set_bluetooth_power(int on)
|
|
+{
|
|
+ int sz;
|
|
+ int fd = -1;
|
|
+ int ret = -1;
|
|
+ char buffer = '0';
|
|
+
|
|
+ switch(on) {
|
|
+ case UPIO_BT_POWER_OFF:
|
|
+ buffer = '0';
|
|
+ break;
|
|
+ case UPIO_BT_POWER_ON:
|
|
+ buffer = '1';
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ fd = open(rfkill_state_path, O_WRONLY);
|
|
+
|
|
+ if (fd < 0)
|
|
+ {
|
|
+ printf("set_bluetooth_power : open(%s) for write failed: %s (%d).\n",
|
|
+ rfkill_state_path, strerror(errno), errno);
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ sz = write(fd, &buffer, 1);
|
|
+
|
|
+ if (sz < 0)
|
|
+ {
|
|
+ printf("set_bluetooth_power : write(%s) failed: %s (%d).\n",
|
|
+ rfkill_state_path, strerror(errno),errno);
|
|
+ }
|
|
+ else
|
|
+ ret = 0;
|
|
+
|
|
+ if (fd >= 0)
|
|
+ close(fd);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static void upio_init(void)
|
|
+{
|
|
+ memset(upio_state, UPIO_UNKNOWN, UPIO_MAX_COUNT);
|
|
+ memset(&lpm_proc_cb, 0, sizeof(vnd_lpm_proc_cb_t));
|
|
+}
|
|
+
|
|
+static void upio_cleanup(void)
|
|
+{
|
|
+ if (lpm_proc_cb.timer_created == 1)
|
|
+ //timer_delete(lpm_proc_cb.timer_id);
|
|
+ ;
|
|
+ lpm_proc_cb.timer_created = 0;
|
|
+}
|
|
+
|
|
+static void upio_set(uint8_t pio, uint8_t action, uint8_t polarity)
|
|
+{
|
|
+ UNUSED(polarity);
|
|
+ int rc;
|
|
+#if (BT_WAKE_VIA_PROC == 1)
|
|
+ int fd = -1;
|
|
+ char buffer;
|
|
+#endif
|
|
+
|
|
+ switch (pio)
|
|
+ {
|
|
+ case UPIO_LPM_MODE:
|
|
+ printf("set LPM mode:%s", lpm_mode[action]);
|
|
+ if (upio_state[UPIO_LPM_MODE] == action)
|
|
+ {
|
|
+ printf("LPM is %s already", lpm_mode[action]);
|
|
+ return;
|
|
+ }
|
|
+ upio_state[UPIO_LPM_MODE] = action;
|
|
+
|
|
+#if (BT_WAKE_VIA_PROC == 1)
|
|
+ fd = open(VENDOR_LPM_PROC_NODE, O_WRONLY);
|
|
+ if (fd < 0)
|
|
+ {
|
|
+ printf("upio_set : open(%s) for write failed: %s (%d)",
|
|
+ VENDOR_LPM_PROC_NODE, strerror(errno), errno);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (action == UPIO_ASSERT)
|
|
+ {
|
|
+ buffer = '1';
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ buffer = '0';
|
|
+ if (lpm_proc_cb.timer_created == 1)
|
|
+ {
|
|
+ //timer_delete(lpm_proc_cb.timer_id);
|
|
+ lpm_proc_cb.timer_created = 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (write(fd, &buffer, 1) < 0)
|
|
+ {
|
|
+ printf("upio_set : write(%s) failed: %s (%d)",
|
|
+ VENDOR_LPM_PROC_NODE, strerror(errno),errno);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ if (action == UPIO_ASSERT)
|
|
+ {
|
|
+ // create btwrite assertion holding timer
|
|
+ if (lpm_proc_cb.timer_created == 0)
|
|
+ {
|
|
+#if 0
|
|
+ int status;
|
|
+ struct sigevent se;
|
|
+ se.sigev_notify = SIGEV_THREAD;
|
|
+ se.sigev_value.sival_ptr = &lpm_proc_cb.timer_id;
|
|
+ se.sigev_notify_function = proc_btwrite_timeout;
|
|
+ se.sigev_notify_attributes = NULL;
|
|
+ status = timer_create(CLOCK_MONOTONIC, &se,&lpm_proc_cb.timer_id);
|
|
+ if (status == 0)
|
|
+ lpm_proc_cb.timer_created = 1;
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (fd >= 0)
|
|
+ close(fd);
|
|
+#endif
|
|
+ break;
|
|
+ case UPIO_BT_WAKE:
|
|
+ printf("upio_set: UPIO_BT_WAKE");
|
|
+
|
|
+ if (upio_state[UPIO_BT_WAKE] == action)
|
|
+ {
|
|
+ printf("BT_WAKE is %s already", lpm_state[action]);
|
|
+
|
|
+#if (BT_WAKE_VIA_PROC == 1)
|
|
+ if (lpm_proc_cb.btwrite_active == 1)
|
|
+ /*
|
|
+ * The proc btwrite node could have not been updated for
|
|
+ * certain time already due to heavy downstream path flow.
|
|
+ * In this case, we want to explicity touch proc btwrite
|
|
+ * node to keep the bt_wake assertion in the LPM kernel
|
|
+ * driver. The current kernel bluesleep LPM code starts
|
|
+ * a 10sec internal in-activity timeout timer before it
|
|
+ * attempts to deassert BT_WAKE line.
|
|
+ */
|
|
+#endif
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ upio_state[UPIO_BT_WAKE] = action;
|
|
+
|
|
+#if (BT_WAKE_VIA_PROC == 1)
|
|
+
|
|
+ // Kick proc btwrite node only at UPIO_ASSERT
|
|
+ if (action == UPIO_DEASSERT)
|
|
+ {
|
|
+ buffer = '0';
|
|
+ return;
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ buffer = '1';
|
|
+ }
|
|
+
|
|
+ fd = open(VENDOR_BTWAKE_PROC_NODE, O_WRONLY);
|
|
+
|
|
+ if (fd < 0)
|
|
+ {
|
|
+ printf("upio_set : open(%s) for write failed: %s (%d)",
|
|
+ VENDOR_BTWAKE_PROC_NODE, strerror(errno), errno);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (write(fd, &buffer, 1) < 0)
|
|
+ {
|
|
+ printf("upio_set : write(%s) failed: %s (%d)",
|
|
+ VENDOR_BTWAKE_PROC_NODE, strerror(errno),errno);
|
|
+ }
|
|
+ else
|
|
+ {
|
|
+ lpm_proc_cb.btwrite_active = 1;
|
|
+
|
|
+ if (lpm_proc_cb.timer_created == 1)
|
|
+ {
|
|
+#if 0
|
|
+ struct itimerspec ts;
|
|
+
|
|
+ ts.it_value.tv_sec = PROC_BTWAKE_TIMER_TIMEOUT_MS/1000;
|
|
+ ts.it_value.tv_nsec = 1000*(PROC_BTWAKE_TIMER_TIMEOUT_MS%1000);
|
|
+ ts.it_interval.tv_sec = 0;
|
|
+ ts.it_interval.tv_nsec = 0;
|
|
+
|
|
+ timer_settime(lpm_proc_cb.timer_id, 0, &ts, 0);
|
|
+#endif
|
|
+ }
|
|
+ }
|
|
+
|
|
+ printf("proc btwake assertion");
|
|
+
|
|
+ if (fd >= 0)
|
|
+ close(fd);
|
|
+#endif
|
|
+
|
|
+ break;
|
|
+ case UPIO_HOST_WAKE:
|
|
+ printf("upio_set: UPIO_HOST_WAKE");
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int com_sync_baudrate(int fd, int def_speed, unsigned int lcr);
|
|
+static int com_stream_write(int fd, unsigned int addr, unsigned int len, unsigned char* data);
|
|
+static int com_write_byte(int fd, unsigned int addr, unsigned int len, unsigned char* data);
|
|
+static int com_set_pc(int fd, unsigned int pc);
|
|
+
|
|
+static int com_sync_baudrate(int fd, int speed, unsigned int lcr)
|
|
+{
|
|
+ unsigned int payload_len = 5; /* cmdid(1) + lcr(1) + baud(3) */
|
|
+ unsigned char cmdbuff[MB_CMD_HEADER_SIZE + 5] = {0};
|
|
+ cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)cmdbuff;
|
|
+ cmd_ack_t *ack = (cmd_ack_t *)cmdbuff;
|
|
+
|
|
+ /* fill header */
|
|
+ FILL_HEADER_MAGIC(&cmd->h);
|
|
+ cmd->h.flags = CMD_HFLAG_CHECK;
|
|
+ cmd->h.version = 0;
|
|
+ cmd->h.checksum = 0;
|
|
+ cmd->h.payload_len = payload_len;
|
|
+ /* fill command id */
|
|
+ cmd->cmdid = CMD_ID_SETUART;
|
|
+ cmd->lcr = lcr;
|
|
+ cmd->h.checksum = ~check_sum16(cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+
|
|
+ /* convert host byte order to network byte order */
|
|
+ cmd->h.payload_len = SWAP32(cmd->h.payload_len);
|
|
+ cmd->h.checksum = SWAP16(cmd->h.checksum);
|
|
+ cmd->lcr = SWAP32(cmd->lcr);
|
|
+
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ /* send command */
|
|
+ userial_write(fd, cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+ memset(cmdbuff, 0, MB_CMD_HEADER_SIZE + 5);
|
|
+ userial_read(fd, cmdbuff, MB_CMD_HEADER_SIZE);
|
|
+ /* check header */
|
|
+ if (!HEADER_MAGIC_VALID(&ack->h)) {
|
|
+ printf("invalid response\n");
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR);
|
|
+ return -1;
|
|
+ } else if (ack->h.flags & CMD_HFLAG_ERROR) {
|
|
+ userial_read(fd, cmdbuff + MB_CMD_HEADER_SIZE, 1);
|
|
+ printf("resp error flag, type %d\n", ack->err);
|
|
+ return -ack->err;
|
|
+ } else {
|
|
+ if (ack->h.flags & CMD_HFLAG_ACK) {
|
|
+ /* convert network byte order to host byte order */
|
|
+ ack->h.payload_len = SWAP32(ack->h.payload_len);
|
|
+ ack->h.checksum = SWAP16(ack->h.checksum);
|
|
+ if (ack->h.payload_len != 0) {
|
|
+ printf("data payload len %d != 0\n", ack->h.payload_len);
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR);
|
|
+ return -1;
|
|
+ }
|
|
+ if ((ack->h.flags & CMD_HFLAG_CHECK) &&
|
|
+ (check_sum16(cmdbuff, MB_CMD_HEADER_SIZE)) != 0xffff) {
|
|
+ printf("Set uart mode response checksum error\n");
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ printf("Set uart mode done\n");
|
|
+ userial_vendor_set_baud(fd, speed); // low 24 bits
|
|
+ return userial_sync(fd);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int com_stream_write(int fd, unsigned int addr, unsigned int len, unsigned char *data)
|
|
+{
|
|
+ unsigned int payload_len = 11; /* cmdid(1) + addr(4) + dlen(4) + dcs(2) */
|
|
+ unsigned char cmdbuff[MB_CMD_HEADER_SIZE + 11] = {0};
|
|
+ cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)cmdbuff;
|
|
+ cmd_ack_t *ack = (cmd_ack_t *)cmdbuff;
|
|
+
|
|
+ /* fill header */
|
|
+ FILL_HEADER_MAGIC(&cmd->h);
|
|
+ cmd->h.flags = CMD_HFLAG_CHECK;
|
|
+ cmd->h.version = 0;
|
|
+ cmd->h.checksum = 0;
|
|
+ cmd->h.payload_len = payload_len;
|
|
+ /* fill command id */
|
|
+ cmd->cmdid = CMD_ID_SEQWR;
|
|
+ /* fill command address, data length,
|
|
+ data checksum and command checksum */
|
|
+ cmd->addr = addr;
|
|
+ cmd->dlen = len;
|
|
+ cmd->dcs = ~check_sum16(data, len);
|
|
+ cmd->h.checksum = ~check_sum16(cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+
|
|
+ /* convert host byte order to network byte order */
|
|
+ cmd->h.payload_len = SWAP32(cmd->h.payload_len);
|
|
+ cmd->addr = SWAP32(cmd->addr);
|
|
+ cmd->dlen = SWAP32(cmd->dlen);
|
|
+ cmd->dcs = SWAP16(cmd->dcs);
|
|
+ cmd->h.checksum = SWAP16(cmd->h.checksum);
|
|
+
|
|
+ /* clear rx buffer */
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ /* send cmd */
|
|
+ userial_write(fd, cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+ userial_read(fd, cmdbuff, MB_CMD_HEADER_SIZE);
|
|
+ /* check data */
|
|
+ if (!HEADER_MAGIC_VALID(&ack->h)) {
|
|
+ printf("invalid response\n");
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ } else if (ack->h.flags & CMD_HFLAG_ERROR) {
|
|
+ userial_read(fd, cmdbuff + MB_CMD_HEADER_SIZE, 1);
|
|
+ printf("resp error flag, type %d\n", ack->err);
|
|
+ } else {
|
|
+ if (ack->h.flags & CMD_HFLAG_ACK) {
|
|
+ /* convert network byte order to host byte order */
|
|
+ ack->h.payload_len = SWAP32(ack->h.payload_len);
|
|
+ ack->h.checksum = SWAP16(ack->h.checksum);
|
|
+ if (ack->h.payload_len != 0) {
|
|
+ printf("data payload len %d != 0\n", ack->h.payload_len);
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ }
|
|
+ /* check response */
|
|
+ if ((ack->h.flags & CMD_HFLAG_CHECK) &&
|
|
+ (check_sum16(cmdbuff, MB_CMD_HEADER_SIZE) != 0xffff)) {
|
|
+ printf("write data response 0 checksum error\n");
|
|
+ return -1;
|
|
+ }
|
|
+ /* send data */
|
|
+ userial_write(fd, data, len);
|
|
+ userial_read(fd, cmdbuff, MB_CMD_HEADER_SIZE);
|
|
+ /* check data */
|
|
+ if (ack->h.flags & CMD_HFLAG_ERROR) {
|
|
+ userial_read(fd, cmdbuff + MB_CMD_HEADER_SIZE, 1);
|
|
+ printf("resp error flag, type %d\n", ack->err);
|
|
+ return -ack->err;
|
|
+ } else {
|
|
+ if (ack->h.flags & CMD_HFLAG_ACK) {
|
|
+ /* convert network byte order to host byte order */
|
|
+ ack->h.payload_len = SWAP32(ack->h.payload_len);
|
|
+ ack->h.checksum = SWAP16(ack->h.checksum);
|
|
+ if (ack->h.payload_len != 0) {
|
|
+ printf("data payload len %d != 0\n", ack->h.payload_len);
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ }
|
|
+ /* check response */
|
|
+ if ((ack->h.flags & CMD_HFLAG_CHECK) &&
|
|
+ (check_sum16(cmdbuff, MB_CMD_HEADER_SIZE) != 0xffff)) {
|
|
+ printf("write data response 1 checksum error\n");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int com_write_byte(int fd, unsigned int addr, unsigned int len, unsigned char *data)
|
|
+{
|
|
+ unsigned int payload_len = 5 + len;
|
|
+ unsigned char cmdbuff[MB_CMD_HEADER_SIZE + 13] = {0}; /* max 8 bytes data */
|
|
+ cmd_rw_t *cmd = (cmd_rw_t *)cmdbuff;
|
|
+ cmd_ack_t *ack = (cmd_ack_t *)cmdbuff;
|
|
+
|
|
+ /* fill header */
|
|
+ FILL_HEADER_MAGIC(&cmd->h);
|
|
+ cmd->h.flags = CMD_HFLAG_CHECK;
|
|
+ cmd->h.version = 0;
|
|
+ cmd->h.checksum = 0;
|
|
+ cmd->h.payload_len = payload_len; // cmdid(1) + addr(4) + data(len)
|
|
+ /* fill command id */
|
|
+ cmd->cmdid = len == 1 ? CMD_ID_WRITE1 :
|
|
+ len == 2 ? CMD_ID_WRITE2 :
|
|
+ len == 4 ? CMD_ID_WRITE4 :
|
|
+ len == 8 ? CMD_ID_WRITE8 : CMD_ID_WRITE4;
|
|
+ /* fill command address, data and checksum */
|
|
+ cmd->addr = addr;
|
|
+ memcpy(cmdbuff + sizeof(cmd_rw_t), data, len);
|
|
+ cmd->h.checksum = ~check_sum16(cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+
|
|
+ /* convert host byte order to network byte order */
|
|
+ cmd->h.payload_len = SWAP32(cmd->h.payload_len);
|
|
+ cmd->addr = SWAP32(cmd->addr);
|
|
+ cmd->h.checksum = SWAP16(cmd->h.checksum);
|
|
+
|
|
+ /* clear rx buffer */
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ /* send cmd */
|
|
+ userial_write(fd, cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+ userial_read(fd, cmdbuff, MB_CMD_HEADER_SIZE);
|
|
+
|
|
+ /* check data */
|
|
+ if (!HEADER_MAGIC_VALID(&ack->h)) {
|
|
+ printf("invalid response\n");
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ } else if (ack->h.flags & CMD_HFLAG_ERROR) {
|
|
+ userial_read(fd, cmdbuff + MB_CMD_HEADER_SIZE, 1);
|
|
+ printf("resp error flag, type %d\n", ack->err);
|
|
+ return -ack->err;
|
|
+ } else {
|
|
+ if (ack->h.flags & CMD_HFLAG_ACK) {
|
|
+ /* convert network byte order to host byte order */
|
|
+ ack->h.payload_len = SWAP32(ack->h.payload_len);
|
|
+ ack->h.checksum = SWAP16(ack->h.checksum);
|
|
+ if (ack->h.payload_len != 0) {
|
|
+ printf("data payload len %d != 0\n", ack->h.payload_len);
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ }
|
|
+ /* check response */
|
|
+ if ((ack->h.flags & CMD_HFLAG_CHECK) &&
|
|
+ (check_sum16(cmdbuff, MB_CMD_HEADER_SIZE) != 0xffff)) {
|
|
+ printf("write data response checksum error\n");
|
|
+ return -1;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int com_set_pc(int fd, unsigned int pc)
|
|
+{
|
|
+ unsigned int payload_len = 5; /* cmdid(1) + PC addr(4) */
|
|
+ unsigned char cmdbuff[MB_CMD_HEADER_SIZE + 5] = {0};
|
|
+ cmd_sys_t *cmd = (cmd_sys_t*)cmdbuff;
|
|
+ cmd_ack_t *ack = (cmd_ack_t *)cmdbuff;
|
|
+
|
|
+ /* fill header */
|
|
+ FILL_HEADER_MAGIC(&cmd->h);
|
|
+ cmd->h.flags = CMD_HFLAG_CHECK;
|
|
+ cmd->h.version = 0;
|
|
+ cmd->h.checksum = 0;
|
|
+ cmd->h.payload_len = payload_len;
|
|
+ /* fill command id */
|
|
+ cmd->cmdid = CMD_ID_SETPC;
|
|
+ cmd->val = pc;
|
|
+ cmd->h.checksum = ~check_sum16(cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+ /* convert host byte order to network byte order */
|
|
+ cmd->h.payload_len = SWAP32(cmd->h.payload_len);
|
|
+ cmd->h.checksum = SWAP16(cmd->h.checksum);
|
|
+ cmd->val = SWAP32(cmd->val);
|
|
+ printf("set pc %x, val %x\n", pc, cmd->val);
|
|
+
|
|
+ /* clear rx buffer */
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ /* send command */
|
|
+ userial_write(fd, cmdbuff, MB_CMD_HEADER_SIZE + payload_len);
|
|
+ userial_read(fd, cmdbuff, MB_CMD_HEADER_SIZE);
|
|
+ /* check header */
|
|
+ if (!HEADER_MAGIC_VALID(&ack->h)) {
|
|
+ printf("invalid response\n");
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ } else if (ack->h.flags & CMD_HFLAG_ERROR) {
|
|
+ userial_read(fd, cmdbuff + MB_CMD_HEADER_SIZE, 1);
|
|
+ printf("resp error flag, type %d\n", ack->err);
|
|
+ return -ack->err;
|
|
+ } else {
|
|
+ if (ack->h.flags & CMD_HFLAG_ACK) {
|
|
+ /* convert network byte order to host byte order */
|
|
+ ack->h.payload_len = SWAP32(ack->h.payload_len);
|
|
+ ack->h.checksum = SWAP16(ack->h.checksum);
|
|
+ if (ack->h.payload_len != 0) {
|
|
+ printf("data payload len %d != 0\n", ack->h.payload_len);
|
|
+ userial_clearbuf(fd, UART_BUF_RXCLEAR|UART_BUF_TXCLEAR);
|
|
+ return -1;
|
|
+ }
|
|
+ if ((ack->h.flags & CMD_HFLAG_CHECK) &&
|
|
+ (check_sum16(cmdbuff, MB_CMD_HEADER_SIZE)) != 0xffff) {
|
|
+ printf("Set PC response checksum error\n");
|
|
+ return -1;
|
|
+ }
|
|
+ printf("Now the system will jump to %08x\n", pc);
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int load_btfirmware(int fd)
|
|
+{
|
|
+ FILE* fwfile_fd = NULL;
|
|
+ unsigned int filesize, len;
|
|
+ unsigned char *data = NULL;
|
|
+ unsigned int addr = g_load_addr;
|
|
+ unsigned char flag_value[4] = {0xFF, 0xFF, 0xFF, 0xFF};
|
|
+
|
|
+ printf("[%s] start loading firmware...\n", __FUNCTION__);
|
|
+
|
|
+ fwfile_fd = fopen(BT_FW_PATH_NAME, "rb");
|
|
+ if(!fwfile_fd)
|
|
+ return -1;
|
|
+
|
|
+ printf("[%s] open firmware file success.\n", __FUNCTION__);
|
|
+
|
|
+ fseek(fwfile_fd, 0, SEEK_END);
|
|
+ filesize = ftell(fwfile_fd);
|
|
+ fseek(fwfile_fd, 0, SEEK_SET);
|
|
+ len = filesize;
|
|
+ len = len > SZ_1K ? SZ_1K : len;
|
|
+ data = (unsigned char*)malloc(len);
|
|
+ if (data == NULL) {
|
|
+ printf("failed to alloc %d byte memory\n", len);
|
|
+ fclose(fwfile_fd);
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ do {
|
|
+ len = filesize;
|
|
+ len = (len > SZ_1K) ? SZ_1K : len;
|
|
+ fread(data, 1, len, fwfile_fd);
|
|
+ com_stream_write(fd, addr, len, data);
|
|
+ addr += len;
|
|
+ filesize -= len;
|
|
+ printf("remain len:\t0x%04X.\n", filesize);
|
|
+ } while(filesize);
|
|
+ free(data);
|
|
+ fclose(fwfile_fd);
|
|
+ printf("load firmware done.\n");
|
|
+
|
|
+ /* jump */
|
|
+ printf("jump:\n");
|
|
+ com_set_pc(fd, g_jump_addr);
|
|
+
|
|
+ if(g_chip_name == 2)
|
|
+ {
|
|
+ printf("\nsecond time sync starting....\n");
|
|
+ if(userial_sync(fd) < 0)
|
|
+ return -1;
|
|
+ com_set_pc(fd, g_jump_addr);
|
|
+ }
|
|
+ return addr;
|
|
+}
|
|
+
|
|
+int xradio_init(int fd, int def_speed, int speed, struct termios *ti,
|
|
+ const char *bdaddr)
|
|
+{
|
|
+ printf("xradio_init\n");
|
|
+
|
|
+ if (init_rfkill())
|
|
+ return -1;
|
|
+
|
|
+ if (upio_set_bluetooth_power(UPIO_BT_POWER_OFF))
|
|
+ return -1;
|
|
+ usleep(500000);
|
|
+
|
|
+ if (upio_set_bluetooth_power(UPIO_BT_POWER_ON))
|
|
+ return -1;
|
|
+ usleep(20000);
|
|
+
|
|
+ upio_init();
|
|
+ upio_set(UPIO_LPM_MODE, UPIO_DEASSERT, 0);
|
|
+ usleep(50000);
|
|
+
|
|
+ if (userial_sync(fd))
|
|
+ return -1;
|
|
+
|
|
+ if (com_sync_baudrate(fd, speed, speed | (3 << 24)))
|
|
+ return -1;
|
|
+
|
|
+ if (load_btfirmware(fd) < 0)
|
|
+ return -1;
|
|
+
|
|
+ usleep(50000);
|
|
+
|
|
+ userial_vendor_set_baud(fd, def_speed);
|
|
+ usleep(100000);
|
|
+ userial_vendor_set_hw_fctrl(fd, 1);
|
|
+ usleep(100000);
|
|
+
|
|
+ if (g_startup_reset_flag) {
|
|
+ printf("[%s] send reset cmd...\n", __FUNCTION__);
|
|
+ proc_reset(fd);
|
|
+ }
|
|
+
|
|
+ if (g_update_hcirate_flag) {
|
|
+ printf("[%s] update hci baudrate...\n", __FUNCTION__);
|
|
+ proc_baudrate(fd, speed);
|
|
+ }
|
|
+
|
|
+ if (g_bdaddr_flag) {
|
|
+ printf("[%s] set bdaddr...\n", __FUNCTION__);
|
|
+ proc_bdaddr(fd);
|
|
+ }
|
|
+
|
|
+ if (g_hciup_flag) {
|
|
+ printf("[%s] bring up hci...\n", __FUNCTION__);
|
|
+ proc_enable_hci(fd);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|