First Commit

This commit is contained in:
leeboby
2020-10-30 09:50:39 +08:00
commit e5f9bb65ac
845 changed files with 177861 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
# ----------------------------------------------------------------------------
# Makefile for building tapp
#
#
CFLAGS = -Wall -O2
CC = gcc
INSTALL = install
TARGET = brcm_patchram_plus
all: $(TARGET)
$(TARGET): brcm_patchram_plus.c
$(CC) $(CFLAGS) $< -o $@
clean distclean:
rm -rf *.o $(TARGET)
# ----------------------------------------------------------------------------
.PHONY: $(PHONY) install clean distclean

View File

@@ -0,0 +1,890 @@
/*******************************************************************************
*
* Copyright (C) 2009-2011 Broadcom Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************/
/*****************************************************************************
**
** Name: brcm_patchram_plus.c
**
** Description: This program downloads a patchram files in the HCD format
** to Broadcom Bluetooth based silicon and combo chips and
** and other utility functions.
**
** It can be invoked from the command line in the form
** <-d> to print a debug log
** <--patchram patchram_file>
** <--baudrate baud_rate>
** <--bd_addr bd_address>
** <--enable_lpm>
** <--enable_hci>
** <--use_baudrate_for_download>
** <--scopcm=sco_routing,pcm_interface_rate,frame_type,
** sync_mode,clock_mode,lsb_first,fill_bits,
** fill_method,fill_num,right_justify>
**
** Where
**
** sco_routing is 0 for PCM, 1 for Transport,
** 2 for Codec and 3 for I2S,
**
** pcm_interface_rate is 0 for 128KBps, 1 for
** 256 KBps, 2 for 512KBps, 3 for 1024KBps,
** and 4 for 2048Kbps,
**
** frame_type is 0 for short and 1 for long,
**
** sync_mode is 0 for slave and 1 for master,
**
** clock_mode is 0 for slabe and 1 for master,
**
** lsb_first is 0 for false aand 1 for true,
**
** fill_bits is the value in decimal for unused bits,
**
** fill_method is 0 for 0's and 1 for 1's, 2 for
** signed and 3 for programmable,
**
** fill_num is the number or bits to fill,
**
** right_justify is 0 for false and 1 for true
**
** <--i2s=i2s_enable,is_master,sample_rate,clock_rate>
**
** Where
**
** i2s_enable is 0 for disable and 1 for enable,
**
** is_master is 0 for slave and 1 for master,
**
** sample_rate is 0 for 8KHz, 1 for 16Khz and
** 2 for 4 KHz,
**
** clock_rate is 0 for 128KHz, 1 for 256KHz, 3 for
** 1024 KHz and 4 for 2048 KHz.
**
** <--no2bytes skips waiting for two byte confirmation
** before starting patchram download. Newer chips
** do not generate these two bytes.>
** <--tosleep=number of microsseconds to sleep before
** patchram download begins.>
** uart_device_name
**
** For example:
**
** brcm_patchram_plus -d --patchram \
** BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
**
** It will return 0 for success and a number greater than 0
** for any errors.
**
** For Android, this program invoked using a
** "system(2)" call from the beginning of the bt_enable
** function inside the file
** system/bluetooth/bluedroid/bluetooth.c.
**
** If the Android system property "ro.bt.bcm_bdaddr_path" is
** set, then the bd_addr will be read from this path.
** This is overridden by --bd_addr on the command line.
**
******************************************************************************/
// TODO: Integrate BCM support into Bluez hciattach
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#ifdef ANDROID
#include <termios.h>
#else
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <limits.h>
#endif
#include <string.h>
#include <signal.h>
#ifdef ANDROID
#include <cutils/properties.h>
#define LOG_TAG "brcm_patchram_plus"
#include <cutils/log.h>
#undef printf
#define printf ALOGD
#undef fprintf
#define fprintf(x, ...) \
{ if(x==stderr) ALOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); }
#endif //ANDROID
#ifndef N_HCI
#define N_HCI 15
#endif
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
#define HCIUARTGETDEVICE _IOR('U', 202, int)
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
typedef unsigned char uchar;
int uart_fd = -1;
int hcdfile_fd = -1;
int termios_baudrate = 0;
int bdaddr_flag = 0;
int enable_lpm = 0;
int enable_hci = 0;
int use_baudrate_for_download = 0;
int debug = 0;
int scopcm = 0;
int i2s = 0;
int no2bytes = 0;
int tosleep = 0;
struct termios termios;
uchar buffer[1024];
uchar hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
uchar hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };
uchar hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
uchar hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uchar hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00 };
uchar hci_write_sco_pcm_int[] =
{ 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
uchar hci_write_pcm_data_format[] =
{ 0x01, 0x1e, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };
uchar hci_write_i2spcm_interface_param[] =
{ 0x01, 0x6d, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00 };
#ifdef SAMSUNG_BLUETOOTH
char* get_samsung_bluetooth_type()
{
char buf[10];
int fd = open("/data/.cid.info", O_RDONLY);
if (fd < 0) {
fprintf(stderr, "couldn't open file /data/.cid.info for reading\n");
return NULL;
}
if (read(fd, buf, sizeof(buf)) < 0) {
close(fd);
return NULL;
}
close(fd);
if (strncmp(buf, "murata", 6) == 0)
return "_murata";
if (strncmp(buf, "semcove", 7) == 0)
return "_semcove";
if (strncmp(buf, "semcosh", 7) == 0)
return "_semcosh";
return NULL;
}
#endif
int
parse_patchram(char *optarg)
{
char *p;
if (!(p = strrchr(optarg, '.'))) {
fprintf(stderr, "file %s not an HCD file\n", optarg);
exit(3);
}
p++;
if (strcasecmp("hcd", p) != 0) {
fprintf(stderr, "file %s not an HCD file\n", optarg);
exit(4);
}
#ifdef SAMSUNG_BLUETOOTH
char optarg2[256];
char* type = get_samsung_bluetooth_type();
char* fext = ".hcd";
if (type != NULL) {
memset(optarg2, 0, 256);
strncpy(optarg2, optarg, strlen(optarg) - 4);
strcpy(optarg2 + strlen(optarg2), type);
strcpy(optarg2 + strlen(optarg2), fext);
optarg = optarg2;
fprintf(stderr, "using %s as hcdfile\n", optarg);
}
#endif
if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
exit(5);
}
return(0);
}
void
BRCM_encode_baud_rate(uint baud_rate, uchar *encoded_baud)
{
if(baud_rate == 0 || encoded_baud == NULL) {
fprintf(stderr, "Baudrate not supported!");
return;
}
encoded_baud[3] = (uchar)(baud_rate >> 24);
encoded_baud[2] = (uchar)(baud_rate >> 16);
encoded_baud[1] = (uchar)(baud_rate >> 8);
encoded_baud[0] = (uchar)(baud_rate & 0xFF);
}
typedef struct {
int baud_rate;
int termios_value;
} tBaudRates;
tBaudRates baud_rates[] = {
{ 115200, B115200 },
{ 230400, B230400 },
{ 460800, B460800 },
{ 500000, B500000 },
{ 576000, B576000 },
{ 921600, B921600 },
{ 1000000, B1000000 },
{ 1152000, B1152000 },
{ 1500000, B1500000 },
{ 2000000, B2000000 },
{ 2500000, B2500000 },
{ 3000000, B3000000 },
#ifndef __CYGWIN__
{ 3500000, B3500000 },
{ 4000000, B4000000 }
#endif
};
int
validate_baudrate(int baud_rate, int *value)
{
unsigned int i;
for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
if (baud_rates[i].baud_rate == baud_rate) {
*value = baud_rates[i].termios_value;
return(1);
}
}
return(0);
}
int
parse_baudrate(char *optarg)
{
int baudrate = atoi(optarg);
if (validate_baudrate(baudrate, &termios_baudrate)) {
BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
}
return(0);
}
int
parse_bdaddr(char *optarg)
{
int bd_addr[6];
int i;
sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
&bd_addr[5], &bd_addr[4], &bd_addr[3],
&bd_addr[2], &bd_addr[1], &bd_addr[0]);
for (i = 0; i < 6; i++) {
hci_write_bd_addr[4 + i] = bd_addr[i];
}
bdaddr_flag = 1;
return(0);
}
int
parse_enable_lpm(char *optarg)
{
enable_lpm = 1;
return(0);
}
int
parse_use_baudrate_for_download(char *optarg)
{
use_baudrate_for_download = 1;
return(0);
}
int
parse_enable_hci(char *optarg)
{
enable_hci = 1;
return(0);
}
int
parse_scopcm(char *optarg)
{
int param[10];
int ret;
int i;
ret = sscanf(optarg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
&param[0], &param[1], &param[2], &param[3], &param[4],
&param[5], &param[6], &param[7], &param[8], &param[9]);
if (ret != 10) {
return(1);
}
scopcm = 1;
for (i = 0; i < 5; i++) {
hci_write_sco_pcm_int[4 + i] = param[i];
}
for (i = 0; i < 5; i++) {
hci_write_pcm_data_format[4 + i] = param[5 + i];
}
return(0);
}
int
parse_i2s(char *optarg)
{
int param[4];
int ret;
int i;
ret = sscanf(optarg, "%d,%d,%d,%d", &param[0], &param[1], &param[2],
&param[3]);
if (ret != 4) {
return(1);
}
i2s = 1;
for (i = 0; i < 4; i++) {
hci_write_i2spcm_interface_param[4 + i] = param[i];
}
return(0);
}
int
parse_no2bytes(char *optarg)
{
no2bytes = 1;
return(0);
}
int
parse_tosleep(char *optarg)
{
tosleep = atoi(optarg);
if (tosleep <= 0) {
return(1);
}
return(0);
}
void
usage(char *argv0)
{
printf("Usage %s:\n", argv0);
printf("\t<-d> to print a debug log\n");
printf("\t<--patchram patchram_file>\n");
printf("\t<--baudrate baud_rate>\n");
printf("\t<--bd_addr bd_address>\n");
printf("\t<--enable_lpm>\n");
printf("\t<--enable_hci>\n");
printf("\t<--use_baudrate_for_download> - Uses the\n");
printf("\t\tbaudrate for downloading the firmware\n");
printf("\t<--scopcm=sco_routing,pcm_interface_rate,frame_type,\n");
printf("\t\tsync_mode,clock_mode,lsb_first,fill_bits,\n");
printf("\t\tfill_method,fill_num,right_justify>\n");
printf("\n\t\tWhere\n");
printf("\n\t\tsco_routing is 0 for PCM, 1 for Transport,\n");
printf("\t\t2 for Codec and 3 for I2S,\n");
printf("\n\t\tpcm_interface_rate is 0 for 128KBps, 1 for\n");
printf("\t\t256 KBps, 2 for 512KBps, 3 for 1024KBps,\n");
printf("\t\tand 4 for 2048Kbps,\n");
printf("\n\t\tframe_type is 0 for short and 1 for long,\n");
printf("\t\tsync_mode is 0 for slave and 1 for master,\n");
printf("\n\t\tclock_mode is 0 for slabe and 1 for master,\n");
printf("\n\t\tlsb_first is 0 for false aand 1 for true,\n");
printf("\n\t\tfill_bits is the value in decimal for unused bits,\n");
printf("\n\t\tfill_method is 0 for 0's and 1 for 1's, 2 for\n");
printf("\t\tsigned and 3 for programmable,\n");
printf("\n\t\tfill_num is the number or bits to fill,\n");
printf("\n\t\tright_justify is 0 for false and 1 for true\n");
printf("\n\t<--i2s=i2s_enable,is_master,sample_rate,clock_rate>\n");
printf("\n\t\tWhere\n");
printf("\n\t\ti2s_enable is 0 for disable and 1 for enable,\n");
printf("\n\t\tis_master is 0 for slave and 1 for master,\n");
printf("\n\t\tsample_rate is 0 for 8KHz, 1 for 16Khz and\n");
printf("\t\t2 for 4 KHz,\n");
printf("\n\t\tclock_rate is 0 for 128KHz, 1 for 256KHz, 3 for\n");
printf("\t\t1024 KHz and 4 for 2048 KHz.\n\n");
printf("\t<--no2bytes skips waiting for two byte confirmation\n");
printf("\t\tbefore starting patchram download. Newer chips\n");
printf("\t\tdo not generate these two bytes.>\n");
printf("\t<--tosleep=microseconds>\n");
printf("\tuart_device_name\n");
}
int
parse_cmd_line(int argc, char **argv)
{
int c;
int ret = 0;
typedef int (*PFI)();
PFI parse[] = { parse_patchram, parse_baudrate,
parse_bdaddr, parse_enable_lpm, parse_enable_hci,
parse_use_baudrate_for_download,
parse_scopcm, parse_i2s, parse_no2bytes, parse_tosleep};
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"patchram", 1, 0, 0},
{"baudrate", 1, 0, 0},
{"bd_addr", 1, 0, 0},
{"enable_lpm", 0, 0, 0},
{"enable_hci", 0, 0, 0},
{"use_baudrate_for_download", 0, 0, 0},
{"scopcm", 1, 0, 0},
{"i2s", 1, 0, 0},
{"no2bytes", 0, 0, 0},
{"tosleep", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long_only (argc, argv, "d", long_options,
&option_index);
if (c == -1) {
break;
}
switch (c) {
case 0:
if (debug) {
printf ("option %s",
long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
}
ret = (*parse[option_index])(optarg);
break;
case 'd':
debug = 1;
break;
case '?':
//nobreak
default:
usage(argv[0]);
break;
}
if (ret) {
usage(argv[0]);
break;
}
}
if (ret) {
return(1);
}
if (optind < argc) {
if (debug)
printf ("%s \n", argv[optind]);
if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
fprintf(stderr, "port %s could not be opened, error %d\n",
argv[optind], errno);
}
}
return(0);
}
void
init_uart()
{
#ifdef BCM_INIT_DELAY
usleep(150*1000);
#endif
tcflush(uart_fd, TCIOFLUSH);
tcgetattr(uart_fd, &termios);
#ifndef __CYGWIN__
cfmakeraw(&termios);
#else
termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
termios.c_oflag &= ~OPOST;
termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
termios.c_cflag &= ~(CSIZE | PARENB);
termios.c_cflag |= CS8;
#endif
termios.c_cflag |= CRTSCTS;
tcsetattr(uart_fd, TCSANOW, &termios);
tcflush(uart_fd, TCIOFLUSH);
tcsetattr(uart_fd, TCSANOW, &termios);
tcflush(uart_fd, TCIOFLUSH);
tcflush(uart_fd, TCIOFLUSH);
cfsetospeed(&termios, B115200);
cfsetispeed(&termios, B115200);
tcsetattr(uart_fd, TCSANOW, &termios);
}
void
dump(uchar *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");
}
void
read_event(int fd, uchar *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 (debug) {
count += i;
fprintf(stderr, "received %d\n", count);
dump(buffer, count);
}
}
void
hci_send_cmd(uchar *buf, int len)
{
if (debug) {
fprintf(stderr, "writing\n");
dump(buf, len);
}
write(uart_fd, buf, len);
}
void
expired(int sig)
{
hci_send_cmd(hci_reset, sizeof(hci_reset));
alarm(4);
}
void
proc_reset()
{
signal(SIGALRM, expired);
hci_send_cmd(hci_reset, sizeof(hci_reset));
alarm(4);
read_event(uart_fd, buffer);
alarm(0);
}
void
proc_patchram()
{
int len;
hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));
read_event(uart_fd, buffer);
if (!no2bytes) {
read(uart_fd, &buffer[0], 2);
}
if (tosleep) {
usleep(tosleep);
}
while (read(hcdfile_fd, &buffer[1], 3)) {
buffer[0] = 0x01;
len = buffer[3];
read(hcdfile_fd, &buffer[4], len);
hci_send_cmd(buffer, len + 4);
read_event(uart_fd, buffer);
}
if (use_baudrate_for_download) {
cfsetospeed(&termios, B115200);
cfsetispeed(&termios, B115200);
tcsetattr(uart_fd, TCSANOW, &termios);
}
proc_reset();
}
void
proc_baudrate()
{
hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));
read_event(uart_fd, buffer);
cfsetospeed(&termios, termios_baudrate);
cfsetispeed(&termios, termios_baudrate);
tcsetattr(uart_fd, TCSANOW, &termios);
if (debug) {
fprintf(stderr, "Done setting baudrate\n");
}
}
void
proc_bdaddr()
{
hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));
read_event(uart_fd, buffer);
}
void
proc_enable_lpm()
{
hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));
read_event(uart_fd, buffer);
}
void
proc_scopcm()
{
hci_send_cmd(hci_write_sco_pcm_int,
sizeof(hci_write_sco_pcm_int));
read_event(uart_fd, buffer);
hci_send_cmd(hci_write_pcm_data_format,
sizeof(hci_write_pcm_data_format));
read_event(uart_fd, buffer);
}
void
proc_i2s()
{
hci_send_cmd(hci_write_i2spcm_interface_param,
sizeof(hci_write_i2spcm_interface_param));
read_event(uart_fd, buffer);
}
void
proc_enable_hci()
{
int i = N_HCI;
int proto = HCI_UART_H4;
if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
fprintf(stderr, "Can't set line discipline\n");
return;
}
if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
fprintf(stderr, "Can't set hci protocol\n");
return;
}
fprintf(stderr, "Done setting line discpline\n");
return;
}
#ifdef ANDROID
void
read_default_bdaddr()
{
int sz;
int fd;
char path[PROPERTY_VALUE_MAX];
char bdaddr[18];
int len = 17;
memset(bdaddr, 0, (len + 1) * sizeof(char));
property_get("ro.bt.bdaddr_path", path, "");
if (path[0] == 0)
return;
fd = open(path, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
errno);
return;
}
sz = read(fd, bdaddr, len);
if (sz < 0) {
fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
errno);
close(fd);
return;
} else if (sz != len) {
fprintf(stderr, "read(%s) unexpected size %d", path, sz);
close(fd);
return;
}
if (debug) {
printf("Read default bdaddr of %s\n", bdaddr);
}
parse_bdaddr(bdaddr);
}
#endif
int
main (int argc, char **argv)
{
#ifdef ANDROID
read_default_bdaddr();
#endif
if (parse_cmd_line(argc, argv)) {
exit(1);
}
if (uart_fd < 0) {
exit(2);
}
init_uart();
proc_reset();
if (use_baudrate_for_download) {
if (termios_baudrate) {
proc_baudrate();
}
}
if (hcdfile_fd > 0) {
proc_patchram();
}
if (termios_baudrate) {
proc_baudrate();
}
if (bdaddr_flag) {
proc_bdaddr();
}
if (enable_lpm) {
proc_enable_lpm();
}
if (scopcm) {
proc_scopcm();
}
if (i2s) {
proc_i2s();
}
if (enable_hci) {
proc_enable_hci();
while (1) {
sleep(UINT_MAX);
}
}
exit(0);
}

View File

@@ -0,0 +1,95 @@
#CFLAGS := $(CFLAGS) -g
CFLAGS = -I. -Ilib -Wall -DVERSION=\"5.10\" -Wno-strict-aliasing
CFLAGS += -Ilib/bluetooth
# include rule.mk
include ./rule.mk
# define objects collection variable
lib = \
lib/bluetooth.o \
lib/hci.o \
lib/sdp.o
hciattach_objs = \
hciattach.o \
hciattach_ath3k.o \
hciattach_bcm43xx.o \
hciattach_intel.o \
hciattach_qualcomm.o \
hciattach_st.o \
hciattach_ti.o \
hciattach_tialt.o \
hciattach_rtk.o \
hciattach_xr.o \
hciattach_sprd.o
hciconfig_objs = \
hciconfig.o \
csr.o
hcitool_objs = \
hcitool.o
btmon_objs = \
monitor/main.o \
monitor/mainloop.o \
monitor/display.o \
monitor/hcidump.o \
monitor/btsnoop.o \
monitor/control.o \
monitor/packet.o \
monitor/vendor.o \
monitor/lmp.o \
monitor/l2cap.o \
monitor/uuid.o \
monitor/sdp.o \
monitor/crc.o \
monitor/ll.o
# add your target(s) to all
.PHONY: all
all: hciattach_opi hciconfig hcitool btmon
# directory
hciattach_opi: $(hciattach_objs) $(lib)
$(LINK_MSG)
$(LINKX)
hciconfig: $(hciconfig_objs) $(lib)
$(LINK_MSG)
$(LINKX)
hcitool: $(hcitool_objs) $(lib)
$(LINK_MSG)
$(LINKX)
btmon: $(btmon_objs) $(lib)
$(LINK_MSG)
$(LINKX)
# change objs to your objects collection variable
$(hciattach_objs): %.o: %.c
$(COMPILE_MSG)
$(COMPILEX)
$(hciconfig_objs): %.o: %.c
$(COMPILE_MSG)
$(COMPILEX)
$(hcitool_objs): %.o: %.c
$(COMPILE_MSG)
$(COMPILEX)
$(btmon_objs): %.o: %.c
$(COMPILE_MSG)
$(COMPILEX)
# clean temp files
clean:
-rm -rf $(hciattach_objs) $(hciattach_objs:.o=.d)
-rm -rf $(hciconfig_objs) $(hciconfig_objs:.o=.d)
-rm -rf $(hcitool_objs) $(hcitool_objs:.o=.d)
-rm -rf $(lib) $(lib:.o=.d)
-rm -rf $(btmon_objs) $(btmon_objs:.o=.d)
#-rm -rf output

343
external/cache/sources/hcitools/NOTICE vendored Normal file
View File

@@ -0,0 +1,343 @@
All of these programs are made available under version 2 of the GNU General
Public Licence.
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

2853
external/cache/sources/hcitools/csr.c vendored Normal file

File diff suppressed because it is too large Load Diff

553
external/cache/sources/hcitools/csr.h vendored Normal file
View File

@@ -0,0 +1,553 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
#include <termios.h>
#define CSR_VARID_PS_CLR_ALL 0x000b /* valueless */
#define CSR_VARID_PS_FACTORY_SET 0x000c /* valueless */
#define CSR_VARID_PS_CLR_ALL_STORES 0x082d /* uint16 */
#define CSR_VARID_BC01_STATUS 0x2801 /* uint16 */
#define CSR_VARID_BUILDID 0x2819 /* uint16 */
#define CSR_VARID_CHIPVER 0x281a /* uint16 */
#define CSR_VARID_CHIPREV 0x281b /* uint16 */
#define CSR_VARID_INTERFACE_VERSION 0x2825 /* uint16 */
#define CSR_VARID_RAND 0x282a /* uint16 */
#define CSR_VARID_MAX_CRYPT_KEY_LENGTH 0x282c /* uint16 */
#define CSR_VARID_CHIPANAREV 0x2836 /* uint16 */
#define CSR_VARID_BUILDID_LOADER 0x2838 /* uint16 */
#define CSR_VARID_BT_CLOCK 0x2c00 /* uint32 */
#define CSR_VARID_PS_NEXT 0x3005 /* complex */
#define CSR_VARID_PS_SIZE 0x3006 /* complex */
#define CSR_VARID_CRYPT_KEY_LENGTH 0x3008 /* complex */
#define CSR_VARID_PICONET_INSTANCE 0x3009 /* complex */
#define CSR_VARID_GET_CLR_EVT 0x300a /* complex */
#define CSR_VARID_GET_NEXT_BUILDDEF 0x300b /* complex */
#define CSR_VARID_PS_MEMORY_TYPE 0x3012 /* complex */
#define CSR_VARID_READ_BUILD_NAME 0x301c /* complex */
#define CSR_VARID_COLD_RESET 0x4001 /* valueless */
#define CSR_VARID_WARM_RESET 0x4002 /* valueless */
#define CSR_VARID_COLD_HALT 0x4003 /* valueless */
#define CSR_VARID_WARM_HALT 0x4004 /* valueless */
#define CSR_VARID_INIT_BT_STACK 0x4005 /* valueless */
#define CSR_VARID_ACTIVATE_BT_STACK 0x4006 /* valueless */
#define CSR_VARID_ENABLE_TX 0x4007 /* valueless */
#define CSR_VARID_DISABLE_TX 0x4008 /* valueless */
#define CSR_VARID_RECAL 0x4009 /* valueless */
#define CSR_VARID_PS_FACTORY_RESTORE 0x400d /* valueless */
#define CSR_VARID_PS_FACTORY_RESTORE_ALL 0x400e /* valueless */
#define CSR_VARID_PS_DEFRAG_RESET 0x400f /* valueless */
#define CSR_VARID_KILL_VM_APPLICATION 0x4010 /* valueless */
#define CSR_VARID_HOPPING_ON 0x4011 /* valueless */
#define CSR_VARID_CANCEL_PAGE 0x4012 /* valueless */
#define CSR_VARID_PS_CLR 0x4818 /* uint16 */
#define CSR_VARID_MAP_SCO_PCM 0x481c /* uint16 */
#define CSR_VARID_SINGLE_CHAN 0x482e /* uint16 */
#define CSR_VARID_RADIOTEST 0x5004 /* complex */
#define CSR_VARID_PS_CLR_STORES 0x500c /* complex */
#define CSR_VARID_NO_VARIABLE 0x6000 /* valueless */
#define CSR_VARID_CONFIG_UART 0x6802 /* uint16 */
#define CSR_VARID_PANIC_ARG 0x6805 /* uint16 */
#define CSR_VARID_FAULT_ARG 0x6806 /* uint16 */
#define CSR_VARID_MAX_TX_POWER 0x6827 /* int8 */
#define CSR_VARID_DEFAULT_TX_POWER 0x682b /* int8 */
#define CSR_VARID_PS 0x7003 /* complex */
#define CSR_PSKEY_BDADDR 0x0001 /* bdaddr / uint16[] = { 0x00A5A5, 0x5b, 0x0002 } */
#define CSR_PSKEY_COUNTRYCODE 0x0002 /* uint16 */
#define CSR_PSKEY_CLASSOFDEVICE 0x0003 /* bdcod */
#define CSR_PSKEY_DEVICE_DRIFT 0x0004 /* uint16 */
#define CSR_PSKEY_DEVICE_JITTER 0x0005 /* uint16 */
#define CSR_PSKEY_MAX_ACLS 0x000d /* uint16 */
#define CSR_PSKEY_MAX_SCOS 0x000e /* uint16 */
#define CSR_PSKEY_MAX_REMOTE_MASTERS 0x000f /* uint16 */
#define CSR_PSKEY_ENABLE_MASTERY_WITH_SLAVERY 0x0010 /* bool */
#define CSR_PSKEY_H_HC_FC_MAX_ACL_PKT_LEN 0x0011 /* uint16 */
#define CSR_PSKEY_H_HC_FC_MAX_SCO_PKT_LEN 0x0012 /* uint8 */
#define CSR_PSKEY_H_HC_FC_MAX_ACL_PKTS 0x0013 /* uint16 */
#define CSR_PSKEY_H_HC_FC_MAX_SCO_PKTS 0x0014 /* uint16 */
#define CSR_PSKEY_LC_FC_BUFFER_LOW_WATER_MARK 0x0015 /* lc_fc_lwm */
#define CSR_PSKEY_LC_MAX_TX_POWER 0x0017 /* int16 */
#define CSR_PSKEY_TX_GAIN_RAMP 0x001d /* uint16 */
#define CSR_PSKEY_LC_POWER_TABLE 0x001e /* power_setting[] */
#define CSR_PSKEY_LC_PEER_POWER_PERIOD 0x001f /* TIME */
#define CSR_PSKEY_LC_FC_POOLS_LOW_WATER_MARK 0x0020 /* lc_fc_lwm */
#define CSR_PSKEY_LC_DEFAULT_TX_POWER 0x0021 /* int16 */
#define CSR_PSKEY_LC_RSSI_GOLDEN_RANGE 0x0022 /* uint8 */
#define CSR_PSKEY_LC_COMBO_DISABLE_PIO_MASK 0x0028 /* uint16[] */
#define CSR_PSKEY_LC_COMBO_PRIORITY_PIO_MASK 0x0029 /* uint16[] */
#define CSR_PSKEY_LC_COMBO_DOT11_CHANNEL_PIO_BASE 0x002a /* uint16 */
#define CSR_PSKEY_LC_COMBO_DOT11_BLOCK_CHANNELS 0x002b /* uint16 */
#define CSR_PSKEY_LC_MAX_TX_POWER_NO_RSSI 0x002d /* int8 */
#define CSR_PSKEY_LC_CONNECTION_RX_WINDOW 0x002e /* uint16 */
#define CSR_PSKEY_LC_COMBO_DOT11_TX_PROTECTION_MODE 0x0030 /* uint16 */
#define CSR_PSKEY_LC_ENHANCED_POWER_TABLE 0x0031 /* enhanced_power_setting[] */
#define CSR_PSKEY_LC_WIDEBAND_RSSI_CONFIG 0x0032 /* wideband_rssi_config */
#define CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_LEAD 0x0033 /* uint16 */
#define CSR_PSKEY_BT_CLOCK_INIT 0x0034 /* uint32 */
#define CSR_PSKEY_TX_MR_MOD_DELAY 0x0038 /* uint8 */
#define CSR_PSKEY_RX_MR_SYNC_TIMING 0x0039 /* uint16 */
#define CSR_PSKEY_RX_MR_SYNC_CONFIG 0x003a /* uint16 */
#define CSR_PSKEY_LC_LOST_SYNC_SLOTS 0x003b /* uint16 */
#define CSR_PSKEY_RX_MR_SAMP_CONFIG 0x003c /* uint16 */
#define CSR_PSKEY_AGC_HYST_LEVELS 0x003d /* agc_hyst_config */
#define CSR_PSKEY_RX_LEVEL_LOW_SIGNAL 0x003e /* uint16 */
#define CSR_PSKEY_AGC_IQ_LVL_VALUES 0x003f /* IQ_LVL_VAL[] */
#define CSR_PSKEY_MR_FTRIM_OFFSET_12DB 0x0040 /* uint16 */
#define CSR_PSKEY_MR_FTRIM_OFFSET_6DB 0x0041 /* uint16 */
#define CSR_PSKEY_NO_CAL_ON_BOOT 0x0042 /* bool */
#define CSR_PSKEY_RSSI_HI_TARGET 0x0043 /* uint8 */
#define CSR_PSKEY_PREFERRED_MIN_ATTENUATION 0x0044 /* uint8 */
#define CSR_PSKEY_LC_COMBO_DOT11_PRIORITY_OVERRIDE 0x0045 /* bool */
#define CSR_PSKEY_LC_MULTISLOT_HOLDOFF 0x0047 /* TIME */
#define CSR_PSKEY_FREE_KEY_PIGEON_HOLE 0x00c9 /* uint16 */
#define CSR_PSKEY_LINK_KEY_BD_ADDR0 0x00ca /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR1 0x00cb /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR2 0x00cc /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR3 0x00cd /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR4 0x00ce /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR5 0x00cf /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR6 0x00d0 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR7 0x00d1 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR8 0x00d2 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR9 0x00d3 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR10 0x00d4 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR11 0x00d5 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR12 0x00d6 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR13 0x00d7 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR14 0x00d8 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LINK_KEY_BD_ADDR15 0x00d9 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_ENC_KEY_LMIN 0x00da /* uint16 */
#define CSR_PSKEY_ENC_KEY_LMAX 0x00db /* uint16 */
#define CSR_PSKEY_LOCAL_SUPPORTED_FEATURES 0x00ef /* uint16[] = { 0xffff, 0xfe8f, 0xf99b, 0x8000 }*/
#define CSR_PSKEY_LM_USE_UNIT_KEY 0x00f0 /* bool */
#define CSR_PSKEY_HCI_NOP_DISABLE 0x00f2 /* bool */
#define CSR_PSKEY_LM_MAX_EVENT_FILTERS 0x00f4 /* uint8 */
#define CSR_PSKEY_LM_USE_ENC_MODE_BROADCAST 0x00f5 /* bool */
#define CSR_PSKEY_LM_TEST_SEND_ACCEPTED_TWICE 0x00f6 /* bool */
#define CSR_PSKEY_LM_MAX_PAGE_HOLD_TIME 0x00f7 /* uint16 */
#define CSR_PSKEY_AFH_ADAPTATION_RESPONSE_TIME 0x00f8 /* uint16 */
#define CSR_PSKEY_AFH_OPTIONS 0x00f9 /* uint16 */
#define CSR_PSKEY_AFH_RSSI_RUN_PERIOD 0x00fa /* uint16 */
#define CSR_PSKEY_AFH_REENABLE_CHANNEL_TIME 0x00fb /* uint16 */
#define CSR_PSKEY_NO_DROP_ON_ACR_MS_FAIL 0x00fc /* bool */
#define CSR_PSKEY_MAX_PRIVATE_KEYS 0x00fd /* uint8 */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR0 0x00fe /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR1 0x00ff /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR2 0x0100 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR3 0x0101 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR4 0x0102 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR5 0x0103 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR6 0x0104 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_PRIVATE_LINK_KEY_BD_ADDR7 0x0105 /* LM_LINK_KEY_BD_ADDR_T */
#define CSR_PSKEY_LOCAL_SUPPORTED_COMMANDS 0x0106 /* uint16[] = { 0xffff, 0x03ff, 0xfffe, 0xffff, 0xffff, 0xffff, 0x0ff3, 0xfff8, 0x003f } */
#define CSR_PSKEY_LM_MAX_ABSENCE_INDEX 0x0107 /* uint8 */
#define CSR_PSKEY_DEVICE_NAME 0x0108 /* uint16[] */
#define CSR_PSKEY_AFH_RSSI_THRESHOLD 0x0109 /* uint16 */
#define CSR_PSKEY_LM_CASUAL_SCAN_INTERVAL 0x010a /* uint16 */
#define CSR_PSKEY_AFH_MIN_MAP_CHANGE 0x010b /* uint16[] */
#define CSR_PSKEY_AFH_RSSI_LP_RUN_PERIOD 0x010c /* uint16 */
#define CSR_PSKEY_HCI_LMP_LOCAL_VERSION 0x010d /* uint16 */
#define CSR_PSKEY_LMP_REMOTE_VERSION 0x010e /* uint8 */
#define CSR_PSKEY_HOLD_ERROR_MESSAGE_NUMBER 0x0113 /* uint16 */
#define CSR_PSKEY_DFU_ATTRIBUTES 0x0136 /* uint8 */
#define CSR_PSKEY_DFU_DETACH_TO 0x0137 /* uint16 */
#define CSR_PSKEY_DFU_TRANSFER_SIZE 0x0138 /* uint16 */
#define CSR_PSKEY_DFU_ENABLE 0x0139 /* bool */
#define CSR_PSKEY_DFU_LIN_REG_ENABLE 0x013a /* bool */
#define CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_MSB 0x015e /* uint16[] */
#define CSR_PSKEY_DFUENC_VMAPP_PK_MODULUS_LSB 0x015f /* uint16[] */
#define CSR_PSKEY_DFUENC_VMAPP_PK_M_DASH 0x0160 /* uint16 */
#define CSR_PSKEY_DFUENC_VMAPP_PK_R2N_MSB 0x0161 /* uint16[] */
#define CSR_PSKEY_DFUENC_VMAPP_PK_R2N_LSB 0x0162 /* uint16[] */
#define CSR_PSKEY_BCSP_LM_PS_BLOCK 0x0192 /* BCSP_LM_PS_BLOCK */
#define CSR_PSKEY_HOSTIO_FC_PS_BLOCK 0x0193 /* HOSTIO_FC_PS_BLOCK */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO0 0x0194 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO1 0x0195 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO2 0x0196 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO3 0x0197 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO4 0x0198 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO5 0x0199 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO6 0x019a /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO7 0x019b /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO8 0x019c /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO9 0x019d /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO10 0x019e /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO11 0x019f /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO12 0x01a0 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO13 0x01a1 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO14 0x01a2 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_PROTOCOL_INFO15 0x01a3 /* PROTOCOL_INFO */
#define CSR_PSKEY_HOSTIO_UART_RESET_TIMEOUT 0x01a4 /* TIME */
#define CSR_PSKEY_HOSTIO_USE_HCI_EXTN 0x01a5 /* bool */
#define CSR_PSKEY_HOSTIO_USE_HCI_EXTN_CCFC 0x01a6 /* bool */
#define CSR_PSKEY_HOSTIO_HCI_EXTN_PAYLOAD_SIZE 0x01a7 /* uint16 */
#define CSR_PSKEY_BCSP_LM_CNF_CNT_LIMIT 0x01aa /* uint16 */
#define CSR_PSKEY_HOSTIO_MAP_SCO_PCM 0x01ab /* bool */
#define CSR_PSKEY_HOSTIO_AWKWARD_PCM_SYNC 0x01ac /* bool */
#define CSR_PSKEY_HOSTIO_BREAK_POLL_PERIOD 0x01ad /* TIME */
#define CSR_PSKEY_HOSTIO_MIN_UART_HCI_SCO_SIZE 0x01ae /* uint16 */
#define CSR_PSKEY_HOSTIO_MAP_SCO_CODEC 0x01b0 /* bool */
#define CSR_PSKEY_PCM_CVSD_TX_HI_FREQ_BOOST 0x01b1 /* uint16 */
#define CSR_PSKEY_PCM_CVSD_RX_HI_FREQ_BOOST 0x01b2 /* uint16 */
#define CSR_PSKEY_PCM_CONFIG32 0x01b3 /* uint32 */
#define CSR_PSKEY_USE_OLD_BCSP_LE 0x01b4 /* uint16 */
#define CSR_PSKEY_PCM_CVSD_USE_NEW_FILTER 0x01b5 /* bool */
#define CSR_PSKEY_PCM_FORMAT 0x01b6 /* uint16 */
#define CSR_PSKEY_CODEC_OUT_GAIN 0x01b7 /* uint16 */
#define CSR_PSKEY_CODEC_IN_GAIN 0x01b8 /* uint16 */
#define CSR_PSKEY_CODEC_PIO 0x01b9 /* uint16 */
#define CSR_PSKEY_PCM_LOW_JITTER_CONFIG 0x01ba /* uint32 */
#define CSR_PSKEY_HOSTIO_SCO_PCM_THRESHOLDS 0x01bb /* uint16[] */
#define CSR_PSKEY_HOSTIO_SCO_HCI_THRESHOLDS 0x01bc /* uint16[] */
#define CSR_PSKEY_HOSTIO_MAP_SCO_PCM_SLOT 0x01bd /* uint16 */
#define CSR_PSKEY_UART_BAUDRATE 0x01be /* uint16 */
#define CSR_PSKEY_UART_CONFIG_BCSP 0x01bf /* uint16 */
#define CSR_PSKEY_UART_CONFIG_H4 0x01c0 /* uint16 */
#define CSR_PSKEY_UART_CONFIG_H5 0x01c1 /* uint16 */
#define CSR_PSKEY_UART_CONFIG_USR 0x01c2 /* uint16 */
#define CSR_PSKEY_UART_TX_CRCS 0x01c3 /* bool */
#define CSR_PSKEY_UART_ACK_TIMEOUT 0x01c4 /* uint16 */
#define CSR_PSKEY_UART_TX_MAX_ATTEMPTS 0x01c5 /* uint16 */
#define CSR_PSKEY_UART_TX_WINDOW_SIZE 0x01c6 /* uint16 */
#define CSR_PSKEY_UART_HOST_WAKE 0x01c7 /* uint16[] */
#define CSR_PSKEY_HOSTIO_THROTTLE_TIMEOUT 0x01c8 /* TIME */
#define CSR_PSKEY_PCM_ALWAYS_ENABLE 0x01c9 /* bool */
#define CSR_PSKEY_UART_HOST_WAKE_SIGNAL 0x01ca /* uint16 */
#define CSR_PSKEY_UART_CONFIG_H4DS 0x01cb /* uint16 */
#define CSR_PSKEY_H4DS_WAKE_DURATION 0x01cc /* uint16 */
#define CSR_PSKEY_H4DS_MAXWU 0x01cd /* uint16 */
#define CSR_PSKEY_H4DS_LE_TIMER_PERIOD 0x01cf /* uint16 */
#define CSR_PSKEY_H4DS_TWU_TIMER_PERIOD 0x01d0 /* uint16 */
#define CSR_PSKEY_H4DS_UART_IDLE_TIMER_PERIOD 0x01d1 /* uint16 */
#define CSR_PSKEY_ANA_FTRIM 0x01f6 /* uint16 */
#define CSR_PSKEY_WD_TIMEOUT 0x01f7 /* TIME */
#define CSR_PSKEY_WD_PERIOD 0x01f8 /* TIME */
#define CSR_PSKEY_HOST_INTERFACE 0x01f9 /* phys_bus */
#define CSR_PSKEY_HQ_HOST_TIMEOUT 0x01fb /* TIME */
#define CSR_PSKEY_HQ_ACTIVE 0x01fc /* bool */
#define CSR_PSKEY_BCCMD_SECURITY_ACTIVE 0x01fd /* bool */
#define CSR_PSKEY_ANA_FREQ 0x01fe /* uint16 */
#define CSR_PSKEY_PIO_PROTECT_MASK 0x0202 /* uint16 */
#define CSR_PSKEY_PMALLOC_SIZES 0x0203 /* uint16[] */
#define CSR_PSKEY_UART_BAUD_RATE 0x0204 /* uint16 */
#define CSR_PSKEY_UART_CONFIG 0x0205 /* uint16 */
#define CSR_PSKEY_STUB 0x0207 /* uint16 */
#define CSR_PSKEY_TXRX_PIO_CONTROL 0x0209 /* uint16 */
#define CSR_PSKEY_ANA_RX_LEVEL 0x020b /* uint16 */
#define CSR_PSKEY_ANA_RX_FTRIM 0x020c /* uint16 */
#define CSR_PSKEY_PSBC_DATA_VERSION 0x020d /* uint16 */
#define CSR_PSKEY_PCM0_ATTENUATION 0x020f /* uint16 */
#define CSR_PSKEY_LO_LVL_MAX 0x0211 /* uint16 */
#define CSR_PSKEY_LO_ADC_AMPL_MIN 0x0212 /* uint16 */
#define CSR_PSKEY_LO_ADC_AMPL_MAX 0x0213 /* uint16 */
#define CSR_PSKEY_IQ_TRIM_CHANNEL 0x0214 /* uint16 */
#define CSR_PSKEY_IQ_TRIM_GAIN 0x0215 /* uint16 */
#define CSR_PSKEY_IQ_TRIM_ENABLE 0x0216 /* iq_trim_enable_flag */
#define CSR_PSKEY_TX_OFFSET_HALF_MHZ 0x0217 /* int16 */
#define CSR_PSKEY_GBL_MISC_ENABLES 0x0221 /* uint16 */
#define CSR_PSKEY_UART_SLEEP_TIMEOUT 0x0222 /* uint16 */
#define CSR_PSKEY_DEEP_SLEEP_STATE 0x0229 /* deep_sleep_state */
#define CSR_PSKEY_IQ_ENABLE_PHASE_TRIM 0x022d /* bool */
#define CSR_PSKEY_HCI_HANDLE_FREEZE_PERIOD 0x0237 /* TIME */
#define CSR_PSKEY_MAX_FROZEN_HCI_HANDLES 0x0238 /* uint16 */
#define CSR_PSKEY_PAGETABLE_DESTRUCTION_DELAY 0x0239 /* TIME */
#define CSR_PSKEY_IQ_TRIM_PIO_SETTINGS 0x023a /* uint8 */
#define CSR_PSKEY_USE_EXTERNAL_CLOCK 0x023b /* bool */
#define CSR_PSKEY_DEEP_SLEEP_WAKE_CTS 0x023c /* uint16 */
#define CSR_PSKEY_FC_HC2H_FLUSH_DELAY 0x023d /* TIME */
#define CSR_PSKEY_RX_HIGHSIDE 0x023e /* bool */
#define CSR_PSKEY_TX_PRE_LVL 0x0240 /* uint8 */
#define CSR_PSKEY_RX_SINGLE_ENDED 0x0242 /* bool */
#define CSR_PSKEY_TX_FILTER_CONFIG 0x0243 /* uint32 */
#define CSR_PSKEY_CLOCK_REQUEST_ENABLE 0x0246 /* uint16 */
#define CSR_PSKEY_RX_MIN_ATTEN 0x0249 /* uint16 */
#define CSR_PSKEY_XTAL_TARGET_AMPLITUDE 0x024b /* uint8 */
#define CSR_PSKEY_PCM_MIN_CPU_CLOCK 0x024d /* uint16 */
#define CSR_PSKEY_HOST_INTERFACE_PIO_USB 0x0250 /* uint16 */
#define CSR_PSKEY_CPU_IDLE_MODE 0x0251 /* cpu_idle_mode */
#define CSR_PSKEY_DEEP_SLEEP_CLEAR_RTS 0x0252 /* bool */
#define CSR_PSKEY_RF_RESONANCE_TRIM 0x0254 /* uint16 */
#define CSR_PSKEY_DEEP_SLEEP_PIO_WAKE 0x0255 /* uint16 */
#define CSR_PSKEY_DRAIN_BORE_TIMERS 0x0256 /* uint32[] */
#define CSR_PSKEY_DRAIN_TX_POWER_BASE 0x0257 /* uint16 */
#define CSR_PSKEY_MODULE_ID 0x0259 /* uint32 */
#define CSR_PSKEY_MODULE_DESIGN 0x025a /* uint16 */
#define CSR_PSKEY_MODULE_SECURITY_CODE 0x025c /* uint16[] */
#define CSR_PSKEY_VM_DISABLE 0x025d /* bool */
#define CSR_PSKEY_MOD_MANUF0 0x025e /* uint16[] */
#define CSR_PSKEY_MOD_MANUF1 0x025f /* uint16[] */
#define CSR_PSKEY_MOD_MANUF2 0x0260 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF3 0x0261 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF4 0x0262 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF5 0x0263 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF6 0x0264 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF7 0x0265 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF8 0x0266 /* uint16[] */
#define CSR_PSKEY_MOD_MANUF9 0x0267 /* uint16[] */
#define CSR_PSKEY_DUT_VM_DISABLE 0x0268 /* bool */
#define CSR_PSKEY_USR0 0x028a /* uint16[] */
#define CSR_PSKEY_USR1 0x028b /* uint16[] */
#define CSR_PSKEY_USR2 0x028c /* uint16[] */
#define CSR_PSKEY_USR3 0x028d /* uint16[] */
#define CSR_PSKEY_USR4 0x028e /* uint16[] */
#define CSR_PSKEY_USR5 0x028f /* uint16[] */
#define CSR_PSKEY_USR6 0x0290 /* uint16[] */
#define CSR_PSKEY_USR7 0x0291 /* uint16[] */
#define CSR_PSKEY_USR8 0x0292 /* uint16[] */
#define CSR_PSKEY_USR9 0x0293 /* uint16[] */
#define CSR_PSKEY_USR10 0x0294 /* uint16[] */
#define CSR_PSKEY_USR11 0x0295 /* uint16[] */
#define CSR_PSKEY_USR12 0x0296 /* uint16[] */
#define CSR_PSKEY_USR13 0x0297 /* uint16[] */
#define CSR_PSKEY_USR14 0x0298 /* uint16[] */
#define CSR_PSKEY_USR15 0x0299 /* uint16[] */
#define CSR_PSKEY_USR16 0x029a /* uint16[] */
#define CSR_PSKEY_USR17 0x029b /* uint16[] */
#define CSR_PSKEY_USR18 0x029c /* uint16[] */
#define CSR_PSKEY_USR19 0x029d /* uint16[] */
#define CSR_PSKEY_USR20 0x029e /* uint16[] */
#define CSR_PSKEY_USR21 0x029f /* uint16[] */
#define CSR_PSKEY_USR22 0x02a0 /* uint16[] */
#define CSR_PSKEY_USR23 0x02a1 /* uint16[] */
#define CSR_PSKEY_USR24 0x02a2 /* uint16[] */
#define CSR_PSKEY_USR25 0x02a3 /* uint16[] */
#define CSR_PSKEY_USR26 0x02a4 /* uint16[] */
#define CSR_PSKEY_USR27 0x02a5 /* uint16[] */
#define CSR_PSKEY_USR28 0x02a6 /* uint16[] */
#define CSR_PSKEY_USR29 0x02a7 /* uint16[] */
#define CSR_PSKEY_USR30 0x02a8 /* uint16[] */
#define CSR_PSKEY_USR31 0x02a9 /* uint16[] */
#define CSR_PSKEY_USR32 0x02aa /* uint16[] */
#define CSR_PSKEY_USR33 0x02ab /* uint16[] */
#define CSR_PSKEY_USR34 0x02ac /* uint16[] */
#define CSR_PSKEY_USR35 0x02ad /* uint16[] */
#define CSR_PSKEY_USR36 0x02ae /* uint16[] */
#define CSR_PSKEY_USR37 0x02af /* uint16[] */
#define CSR_PSKEY_USR38 0x02b0 /* uint16[] */
#define CSR_PSKEY_USR39 0x02b1 /* uint16[] */
#define CSR_PSKEY_USR40 0x02b2 /* uint16[] */
#define CSR_PSKEY_USR41 0x02b3 /* uint16[] */
#define CSR_PSKEY_USR42 0x02b4 /* uint16[] */
#define CSR_PSKEY_USR43 0x02b5 /* uint16[] */
#define CSR_PSKEY_USR44 0x02b6 /* uint16[] */
#define CSR_PSKEY_USR45 0x02b7 /* uint16[] */
#define CSR_PSKEY_USR46 0x02b8 /* uint16[] */
#define CSR_PSKEY_USR47 0x02b9 /* uint16[] */
#define CSR_PSKEY_USR48 0x02ba /* uint16[] */
#define CSR_PSKEY_USR49 0x02bb /* uint16[] */
#define CSR_PSKEY_USB_VERSION 0x02bc /* uint16 */
#define CSR_PSKEY_USB_DEVICE_CLASS_CODES 0x02bd /* usbclass */
#define CSR_PSKEY_USB_VENDOR_ID 0x02be /* uint16 */
#define CSR_PSKEY_USB_PRODUCT_ID 0x02bf /* uint16 */
#define CSR_PSKEY_USB_MANUF_STRING 0x02c1 /* unicodestring */
#define CSR_PSKEY_USB_PRODUCT_STRING 0x02c2 /* unicodestring */
#define CSR_PSKEY_USB_SERIAL_NUMBER_STRING 0x02c3 /* unicodestring */
#define CSR_PSKEY_USB_CONFIG_STRING 0x02c4 /* unicodestring */
#define CSR_PSKEY_USB_ATTRIBUTES 0x02c5 /* uint8 */
#define CSR_PSKEY_USB_MAX_POWER 0x02c6 /* uint16 */
#define CSR_PSKEY_USB_BT_IF_CLASS_CODES 0x02c7 /* usbclass */
#define CSR_PSKEY_USB_LANGID 0x02c9 /* uint16 */
#define CSR_PSKEY_USB_DFU_CLASS_CODES 0x02ca /* usbclass */
#define CSR_PSKEY_USB_DFU_PRODUCT_ID 0x02cb /* uint16 */
#define CSR_PSKEY_USB_PIO_DETACH 0x02ce /* uint16 */
#define CSR_PSKEY_USB_PIO_WAKEUP 0x02cf /* uint16 */
#define CSR_PSKEY_USB_PIO_PULLUP 0x02d0 /* uint16 */
#define CSR_PSKEY_USB_PIO_VBUS 0x02d1 /* uint16 */
#define CSR_PSKEY_USB_PIO_WAKE_TIMEOUT 0x02d2 /* uint16 */
#define CSR_PSKEY_USB_PIO_RESUME 0x02d3 /* uint16 */
#define CSR_PSKEY_USB_BT_SCO_IF_CLASS_CODES 0x02d4 /* usbclass */
#define CSR_PSKEY_USB_SUSPEND_PIO_LEVEL 0x02d5 /* uint16 */
#define CSR_PSKEY_USB_SUSPEND_PIO_DIR 0x02d6 /* uint16 */
#define CSR_PSKEY_USB_SUSPEND_PIO_MASK 0x02d7 /* uint16 */
#define CSR_PSKEY_USB_ENDPOINT_0_MAX_PACKET_SIZE 0x02d8 /* uint8 */
#define CSR_PSKEY_USB_CONFIG 0x02d9 /* uint16 */
#define CSR_PSKEY_RADIOTEST_ATTEN_INIT 0x0320 /* uint16 */
#define CSR_PSKEY_RADIOTEST_FIRST_TRIM_TIME 0x0326 /* TIME */
#define CSR_PSKEY_RADIOTEST_SUBSEQUENT_TRIM_TIME 0x0327 /* TIME */
#define CSR_PSKEY_RADIOTEST_LO_LVL_TRIM_ENABLE 0x0328 /* bool */
#define CSR_PSKEY_RADIOTEST_DISABLE_MODULATION 0x032c /* bool */
#define CSR_PSKEY_RFCOMM_FCON_THRESHOLD 0x0352 /* uint16 */
#define CSR_PSKEY_RFCOMM_FCOFF_THRESHOLD 0x0353 /* uint16 */
#define CSR_PSKEY_IPV6_STATIC_ADDR 0x0354 /* uint16[] */
#define CSR_PSKEY_IPV4_STATIC_ADDR 0x0355 /* uint32 */
#define CSR_PSKEY_IPV6_STATIC_PREFIX_LEN 0x0356 /* uint8 */
#define CSR_PSKEY_IPV6_STATIC_ROUTER_ADDR 0x0357 /* uint16[] */
#define CSR_PSKEY_IPV4_STATIC_SUBNET_MASK 0x0358 /* uint32 */
#define CSR_PSKEY_IPV4_STATIC_ROUTER_ADDR 0x0359 /* uint32 */
#define CSR_PSKEY_MDNS_NAME 0x035a /* char[] */
#define CSR_PSKEY_FIXED_PIN 0x035b /* uint8[] */
#define CSR_PSKEY_MDNS_PORT 0x035c /* uint16 */
#define CSR_PSKEY_MDNS_TTL 0x035d /* uint8 */
#define CSR_PSKEY_MDNS_IPV4_ADDR 0x035e /* uint32 */
#define CSR_PSKEY_ARP_CACHE_TIMEOUT 0x035f /* uint16 */
#define CSR_PSKEY_HFP_POWER_TABLE 0x0360 /* uint16[] */
#define CSR_PSKEY_DRAIN_BORE_TIMER_COUNTERS 0x03e7 /* uint32[] */
#define CSR_PSKEY_DRAIN_BORE_COUNTERS 0x03e6 /* uint32[] */
#define CSR_PSKEY_LOOP_FILTER_TRIM 0x03e4 /* uint16 */
#define CSR_PSKEY_DRAIN_BORE_CURRENT_PEAK 0x03e3 /* uint32[] */
#define CSR_PSKEY_VM_E2_CACHE_LIMIT 0x03e2 /* uint16 */
#define CSR_PSKEY_FORCE_16MHZ_REF_PIO 0x03e1 /* uint16 */
#define CSR_PSKEY_CDMA_LO_REF_LIMITS 0x03df /* uint16 */
#define CSR_PSKEY_CDMA_LO_ERROR_LIMITS 0x03de /* uint16 */
#define CSR_PSKEY_CLOCK_STARTUP_DELAY 0x03dd /* uint16 */
#define CSR_PSKEY_DEEP_SLEEP_CORRECTION_FACTOR 0x03dc /* int16 */
#define CSR_PSKEY_TEMPERATURE_CALIBRATION 0x03db /* temperature_calibration */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA 0x03da /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL 0x03d9 /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB 0x03d8 /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_ANA_FTRIM 0x03d7 /* temperature_calibration[] */
#define CSR_PSKEY_TEST_DELTA_OFFSET 0x03d6 /* uint16 */
#define CSR_PSKEY_RX_DYNAMIC_LVL_OFFSET 0x03d4 /* uint16 */
#define CSR_PSKEY_TEST_FORCE_OFFSET 0x03d3 /* bool */
#define CSR_PSKEY_RF_TRAP_BAD_DIVISION_RATIOS 0x03cf /* uint16 */
#define CSR_PSKEY_RADIOTEST_CDMA_LO_REF_LIMITS 0x03ce /* uint16 */
#define CSR_PSKEY_INITIAL_BOOTMODE 0x03cd /* int16 */
#define CSR_PSKEY_ONCHIP_HCI_CLIENT 0x03cc /* bool */
#define CSR_PSKEY_RX_ATTEN_BACKOFF 0x03ca /* uint16 */
#define CSR_PSKEY_RX_ATTEN_UPDATE_RATE 0x03c9 /* uint16 */
#define CSR_PSKEY_SYNTH_TXRX_THRESHOLDS 0x03c7 /* uint16 */
#define CSR_PSKEY_MIN_WAIT_STATES 0x03c6 /* uint16 */
#define CSR_PSKEY_RSSI_CORRECTION 0x03c5 /* int8 */
#define CSR_PSKEY_SCHED_THROTTLE_TIMEOUT 0x03c4 /* TIME */
#define CSR_PSKEY_DEEP_SLEEP_USE_EXTERNAL_CLOCK 0x03c3 /* bool */
#define CSR_PSKEY_TRIM_RADIO_FILTERS 0x03c2 /* uint16 */
#define CSR_PSKEY_TRANSMIT_OFFSET 0x03c1 /* int16 */
#define CSR_PSKEY_USB_VM_CONTROL 0x03c0 /* bool */
#define CSR_PSKEY_MR_ANA_RX_FTRIM 0x03bf /* uint16 */
#define CSR_PSKEY_I2C_CONFIG 0x03be /* uint16 */
#define CSR_PSKEY_IQ_LVL_RX 0x03bd /* uint16 */
#define CSR_PSKEY_MR_TX_FILTER_CONFIG 0x03bb /* uint32 */
#define CSR_PSKEY_MR_TX_CONFIG2 0x03ba /* uint16 */
#define CSR_PSKEY_USB_DONT_RESET_BOOTMODE_ON_HOST_RESET 0x03b9 /* bool */
#define CSR_PSKEY_LC_USE_THROTTLING 0x03b8 /* bool */
#define CSR_PSKEY_CHARGER_TRIM 0x03b7 /* uint16 */
#define CSR_PSKEY_CLOCK_REQUEST_FEATURES 0x03b6 /* uint16 */
#define CSR_PSKEY_TRANSMIT_OFFSET_CLASS1 0x03b4 /* int16 */
#define CSR_PSKEY_TX_AVOID_PA_CLASS1_PIO 0x03b3 /* uint16 */
#define CSR_PSKEY_MR_PIO_CONFIG 0x03b2 /* uint16 */
#define CSR_PSKEY_UART_CONFIG2 0x03b1 /* uint8 */
#define CSR_PSKEY_CLASS1_IQ_LVL 0x03b0 /* uint16 */
#define CSR_PSKEY_CLASS1_TX_CONFIG2 0x03af /* uint16 */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_INTERNAL_PA_CLASS1 0x03ae /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_EXTERNAL_PA_CLASS1 0x03ad /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_PRE_LVL_MR 0x03ac /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_HEADER 0x03ab /* temperature_calibration[] */
#define CSR_PSKEY_TEMPERATURE_VS_DELTA_TX_BB_MR_PAYLOAD 0x03aa /* temperature_calibration[] */
#define CSR_PSKEY_RX_MR_EQ_TAPS 0x03a9 /* uint16[] */
#define CSR_PSKEY_TX_PRE_LVL_CLASS1 0x03a8 /* uint8 */
#define CSR_PSKEY_ANALOGUE_ATTENUATOR 0x03a7 /* bool */
#define CSR_PSKEY_MR_RX_FILTER_TRIM 0x03a6 /* uint16 */
#define CSR_PSKEY_MR_RX_FILTER_RESPONSE 0x03a5 /* int16[] */
#define CSR_PSKEY_PIO_WAKEUP_STATE 0x039f /* uint16 */
#define CSR_PSKEY_MR_TX_IF_ATTEN_OFF_TEMP 0x0394 /* int16 */
#define CSR_PSKEY_LO_DIV_LATCH_BYPASS 0x0393 /* bool */
#define CSR_PSKEY_LO_VCO_STANDBY 0x0392 /* bool */
#define CSR_PSKEY_SLOW_CLOCK_FILTER_SHIFT 0x0391 /* uint16 */
#define CSR_PSKEY_SLOW_CLOCK_FILTER_DIVIDER 0x0390 /* uint16 */
#define CSR_PSKEY_USB_ATTRIBUTES_POWER 0x03f2 /* bool */
#define CSR_PSKEY_USB_ATTRIBUTES_WAKEUP 0x03f3 /* bool */
#define CSR_PSKEY_DFU_ATTRIBUTES_MANIFESTATION_TOLERANT 0x03f4 /* bool */
#define CSR_PSKEY_DFU_ATTRIBUTES_CAN_UPLOAD 0x03f5 /* bool */
#define CSR_PSKEY_DFU_ATTRIBUTES_CAN_DOWNLOAD 0x03f6 /* bool */
#define CSR_PSKEY_UART_CONFIG_STOP_BITS 0x03fc /* bool */
#define CSR_PSKEY_UART_CONFIG_PARITY_BIT 0x03fd /* uint16 */
#define CSR_PSKEY_UART_CONFIG_FLOW_CTRL_EN 0x03fe /* bool */
#define CSR_PSKEY_UART_CONFIG_RTS_AUTO_EN 0x03ff /* bool */
#define CSR_PSKEY_UART_CONFIG_RTS 0x0400 /* bool */
#define CSR_PSKEY_UART_CONFIG_TX_ZERO_EN 0x0401 /* bool */
#define CSR_PSKEY_UART_CONFIG_NON_BCSP_EN 0x0402 /* bool */
#define CSR_PSKEY_UART_CONFIG_RX_RATE_DELAY 0x0403 /* uint16 */
#define CSR_PSKEY_UART_SEQ_TIMEOUT 0x0405 /* uint16 */
#define CSR_PSKEY_UART_SEQ_RETRIES 0x0406 /* uint16 */
#define CSR_PSKEY_UART_SEQ_WINSIZE 0x0407 /* uint16 */
#define CSR_PSKEY_UART_USE_CRC_ON_TX 0x0408 /* bool */
#define CSR_PSKEY_UART_HOST_INITIAL_STATE 0x0409 /* hwakeup_state */
#define CSR_PSKEY_UART_HOST_ATTENTION_SPAN 0x040a /* uint16 */
#define CSR_PSKEY_UART_HOST_WAKEUP_TIME 0x040b /* uint16 */
#define CSR_PSKEY_UART_HOST_WAKEUP_WAIT 0x040c /* uint16 */
#define CSR_PSKEY_BCSP_LM_MODE 0x0410 /* uint16 */
#define CSR_PSKEY_BCSP_LM_SYNC_RETRIES 0x0411 /* uint16 */
#define CSR_PSKEY_BCSP_LM_TSHY 0x0412 /* uint16 */
#define CSR_PSKEY_UART_DFU_CONFIG_STOP_BITS 0x0417 /* bool */
#define CSR_PSKEY_UART_DFU_CONFIG_PARITY_BIT 0x0418 /* uint16 */
#define CSR_PSKEY_UART_DFU_CONFIG_FLOW_CTRL_EN 0x0419 /* bool */
#define CSR_PSKEY_UART_DFU_CONFIG_RTS_AUTO_EN 0x041a /* bool */
#define CSR_PSKEY_UART_DFU_CONFIG_RTS 0x041b /* bool */
#define CSR_PSKEY_UART_DFU_CONFIG_TX_ZERO_EN 0x041c /* bool */
#define CSR_PSKEY_UART_DFU_CONFIG_NON_BCSP_EN 0x041d /* bool */
#define CSR_PSKEY_UART_DFU_CONFIG_RX_RATE_DELAY 0x041e /* uint16 */
#define CSR_PSKEY_AMUX_AIO0 0x041f /* ana_amux_sel */
#define CSR_PSKEY_AMUX_AIO1 0x0420 /* ana_amux_sel */
#define CSR_PSKEY_AMUX_AIO2 0x0421 /* ana_amux_sel */
#define CSR_PSKEY_AMUX_AIO3 0x0422 /* ana_amux_sel */
#define CSR_PSKEY_LOCAL_NAME_SIMPLIFIED 0x0423 /* local_name_complete */
#define CSR_PSKEY_EXTENDED_STUB 0x2001 /* uint16 */
char *csr_builddeftostr(uint16_t def);
char *csr_buildidtostr(uint16_t id);
char *csr_chipvertostr(uint16_t ver, uint16_t rev);
char *csr_pskeytostr(uint16_t pskey);
char *csr_pskeytoval(uint16_t pskey);
int csr_open_hci(char *device);
int csr_read_hci(uint16_t varid, uint8_t *value, uint16_t length);
int csr_write_hci(uint16_t varid, uint8_t *value, uint16_t length);
void csr_close_hci(void);
int csr_open_usb(char *device);
int csr_read_usb(uint16_t varid, uint8_t *value, uint16_t length);
int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length);
void csr_close_usb(void);
int csr_open_bcsp(char *device, speed_t bcsp_rate);
int csr_read_bcsp(uint16_t varid, uint8_t *value, uint16_t length);
int csr_write_bcsp(uint16_t varid, uint8_t *value, uint16_t length);
void csr_close_bcsp(void);
int csr_open_h4(char *device);
int csr_read_h4(uint16_t varid, uint8_t *value, uint16_t length);
int csr_write_h4(uint16_t varid, uint8_t *value, uint16_t length);
void csr_close_h4(void);
int csr_open_3wire(char *device);
int csr_read_3wire(uint16_t varid, uint8_t *value, uint16_t length);
int csr_write_3wire(uint16_t varid, uint8_t *value, uint16_t length);
void csr_close_3wire(void);
int csr_write_varid_valueless(int dd, uint16_t seqnum, uint16_t varid);
int csr_write_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length);
int csr_read_varid_complex(int dd, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length);
int csr_read_varid_uint16(int dd, uint16_t seqnum, uint16_t varid, uint16_t *value);
int csr_read_varid_uint32(int dd, uint16_t seqnum, uint16_t varid, uint32_t *value);
int csr_read_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length);
int csr_write_pskey_complex(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint8_t *value, uint16_t length);
int csr_read_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t *value);
int csr_write_pskey_uint16(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint16_t value);
int csr_read_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t *value);
int csr_write_pskey_uint32(int dd, uint16_t seqnum, uint16_t pskey, uint16_t stores, uint32_t value);
int psr_put(uint16_t pskey, uint8_t *value, uint16_t size);
int psr_get(uint16_t *pskey, uint8_t *value, uint16_t *size);
int psr_read(const char *filename);
int psr_print(void);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,96 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <termios.h>
#include <bluetooth.h>
#ifndef N_HCI
#define N_HCI 15
#endif
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
#define HCIUARTGETDEVICE _IOR('U', 202, int)
#define HCIUARTSETFLAGS _IOW('U', 203, int)
#define HCIUARTGETFLAGS _IOR('U', 204, int)
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
#define HCI_UART_ATH3K 5
#define HCI_UART_RAW_DEVICE 0
#define HCI_UART_RESET_ON_INIT 1
#define HCI_UART_CREATE_AMP 2
struct uart_t {
char *type;
int m_id;
int p_id;
int proto;
int init_speed;
int speed;
int flags;
int pm;
char *bdaddr;
int (*init) (int fd, struct uart_t *u, struct termios *ti);
int (*post) (int fd, struct uart_t *u, struct termios *ti);
};
#define FLOW_CTL 0x0001
#define AMP_DEV 0x0002
#define ENABLE_PM 1
#define DISABLE_PM 0
int read_hci_event(int fd, unsigned char *buf, int size);
int set_speed(int fd, struct termios *ti, int speed);
int uart_speed(int speed);
int texas_init(int fd, int *speed, struct termios *ti);
int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
int ath3k_init(int fd, int speed, int init_speed, char *bdaddr,
struct termios *ti);
int ath3k_post(int fd, int pm);
int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr);
int intel_init(int fd, int init_speed, int *speed, struct termios *ti);
int bcm43xx_init(int fd, int speed, struct termios *ti, const char *bdaddr);
//Realtek_add_start
//add realtek init and post process for realtek Bluetooth chip
int rtk_init(int fd, int proto, int speed, struct termios *ti);
int rtk_post(int fd, int proto, struct termios *ti);
//Realtek_add_end
// add xradio init and post process for xradio Bluetooth chip (xr829)
int xr_init(int fd, struct uart_t *u, struct termios *ti);
int xr_post(int fd, struct uart_t *u, struct termios *ti);
// add sprd init and post process for sprd Bluetooth chip (UWE5622)
int sprd_config_init(int fd, struct uart_t *u, struct termios *ti);
int sprd_config_post(int fd, struct uart_t *u, struct termios *ti);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,378 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2014 Intel Corporation. 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 <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "hciattach.h"
#ifndef FIRMWARE_DIR
#define FIRMWARE_DIR "/etc/firmware"
#endif
#define FW_EXT ".hcd"
#define BCM43XX_CLOCK_48 1
#define BCM43XX_CLOCK_24 2
#define CMD_SUCCESS 0x00
#define CC_MIN_SIZE 7
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
static int bcm43xx_read_local_name(int fd, char *name, size_t size)
{
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x14, 0x0C, 0x00 };
unsigned char *resp;
unsigned int name_len;
resp = malloc(size + CC_MIN_SIZE);
if (!resp)
return -1;
tcflush(fd, TCIOFLUSH);
if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) {
fprintf(stderr, "Failed to write read local name command\n");
goto fail;
}
if (read_hci_event(fd, resp, size) < CC_MIN_SIZE) {
fprintf(stderr, "Failed to read local name, invalid HCI event\n");
goto fail;
}
if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) {
fprintf(stderr, "Failed to read local name, command failure\n");
goto fail;
}
name_len = resp[2] - 1;
strncpy(name, (char *) &resp[7], MIN(name_len, size));
name[size - 1] = 0;
free(resp);
return 0;
fail:
free(resp);
return -1;
}
static int bcm43xx_reset(int fd)
{
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x03, 0x0C, 0x00 };
unsigned char resp[CC_MIN_SIZE];
if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) {
fprintf(stderr, "Failed to write reset command\n");
return -1;
}
if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) {
fprintf(stderr, "Failed to reset chip, invalid HCI event\n");
return -1;
}
if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) {
fprintf(stderr, "Failed to reset chip, command failure\n");
return -1;
}
return 0;
}
static int bcm43xx_set_bdaddr(int fd, const char *bdaddr)
{
unsigned char cmd[] =
{ HCI_COMMAND_PKT, 0x01, 0xfc, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
unsigned char resp[CC_MIN_SIZE];
printf("Set BDADDR UART: %s\n", bdaddr);
if (str2ba(bdaddr, (bdaddr_t *) (&cmd[4])) < 0) {
fprintf(stderr, "Incorrect bdaddr\n");
return -1;
}
tcflush(fd, TCIOFLUSH);
if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) {
fprintf(stderr, "Failed to write set bdaddr command\n");
return -1;
}
if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) {
fprintf(stderr, "Failed to set bdaddr, invalid HCI event\n");
return -1;
}
if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) {
fprintf(stderr, "Failed to set bdaddr, command failure\n");
return -1;
}
return 0;
}
static int bcm43xx_set_speed(int fd, uint32_t speed)
{
unsigned char cmd[] =
{ HCI_COMMAND_PKT, 0x18, 0xfc, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
unsigned char resp[CC_MIN_SIZE];
printf("Set Controller UART speed to %d bit/s\n", speed);
cmd[6] = (uint8_t) (speed);
cmd[7] = (uint8_t) (speed >> 8);
cmd[8] = (uint8_t) (speed >> 16);
cmd[9] = (uint8_t) (speed >> 24);
tcflush(fd, TCIOFLUSH);
if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) {
fprintf(stderr, "Failed to write update baudrate command\n");
return -1;
}
if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) {
fprintf(stderr, "Failed to update baudrate, invalid HCI event\n");
return -1;
}
if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) {
fprintf(stderr, "Failed to update baudrate, command failure\n");
return -1;
}
return 0;
}
static int bcm43xx_set_clock(int fd, unsigned char clock)
{
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x45, 0xfc, 0x01, 0x00 };
unsigned char resp[CC_MIN_SIZE];
printf("Set Controller clock (%d)\n", clock);
cmd[4] = clock;
tcflush(fd, TCIOFLUSH);
if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) {
fprintf(stderr, "Failed to write update clock command\n");
return -1;
}
if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) {
fprintf(stderr, "Failed to update clock, invalid HCI event\n");
return -1;
}
if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) {
fprintf(stderr, "Failed to update clock, command failure\n");
return -1;
}
return 0;
}
static int bcm43xx_load_firmware(int fd, const char *fw)
{
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x2e, 0xfc, 0x00 };
struct timespec tm_mode = { 0, 50000 };
struct timespec tm_ready = { 0, 2000000 };
unsigned char resp[CC_MIN_SIZE];
unsigned char tx_buf[1024];
int len, fd_fw, n;
printf("Flash firmware %s\n", fw);
fd_fw = open(fw, O_RDONLY);
if (fd_fw < 0) {
fprintf(stderr, "Unable to open firmware (%s)\n", fw);
return -1;
}
tcflush(fd, TCIOFLUSH);
if (write(fd, cmd, sizeof(cmd)) != sizeof(cmd)) {
fprintf(stderr, "Failed to write download mode command\n");
goto fail;
}
if (read_hci_event(fd, resp, sizeof(resp)) < CC_MIN_SIZE) {
fprintf(stderr, "Failed to load firmware, invalid HCI event\n");
goto fail;
}
if (resp[4] != cmd[1] || resp[5] != cmd[2] || resp[6] != CMD_SUCCESS) {
fprintf(stderr, "Failed to load firmware, command failure\n");
goto fail;
}
/* Wait 50ms to let the firmware placed in download mode */
nanosleep(&tm_mode, NULL);
tcflush(fd, TCIOFLUSH);
while ((n = read(fd_fw, &tx_buf[1], 3))) {
if (n < 0) {
fprintf(stderr, "Failed to read firmware\n");
goto fail;
}
tx_buf[0] = HCI_COMMAND_PKT;
len = tx_buf[3];
if (read(fd_fw, &tx_buf[4], len) < 0) {
fprintf(stderr, "Failed to read firmware\n");
goto fail;
}
if (write(fd, tx_buf, len + 4) != (len + 4)) {
fprintf(stderr, "Failed to write firmware\n");
goto fail;
}
read_hci_event(fd, resp, sizeof(resp));
tcflush(fd, TCIOFLUSH);
}
/* Wait for firmware ready */
nanosleep(&tm_ready, NULL);
close(fd_fw);
return 0;
fail:
close(fd_fw);
return -1;
}
static int bcm43xx_locate_patch(const char *dir_name,
const char *chip_name, char *location)
{
DIR *dir;
int ret = -1;
dir = opendir(dir_name);
if (!dir) {
fprintf(stderr, "Cannot open directory '%s': %s\n",
dir_name, strerror(errno));
return -1;
}
/* Recursively look for a BCM43XX*.hcd */
while (1) {
struct dirent *entry = readdir(dir);
if (!entry)
break;
if (entry->d_type & DT_DIR) {
char path[PATH_MAX];
if (!strcmp(entry->d_name, "..") || !strcmp(entry->d_name, "."))
continue;
snprintf(path, PATH_MAX, "%s/%s", dir_name, entry->d_name);
ret = bcm43xx_locate_patch(path, chip_name, location);
if (!ret)
break;
} else if (!strncmp(chip_name, entry->d_name, strlen(chip_name))) {
unsigned int name_len = strlen(entry->d_name);
size_t curs_ext = name_len - sizeof(FW_EXT) + 1;
if (curs_ext > name_len)
break;
if (strncmp(FW_EXT, &entry->d_name[curs_ext], sizeof(FW_EXT)))
break;
/* found */
snprintf(location, PATH_MAX, "%s/%s", dir_name, entry->d_name);
ret = 0;
break;
}
}
closedir(dir);
return ret;
}
int bcm43xx_init(int fd, int speed, struct termios *ti, const char *bdaddr)
{
char chip_name[20];
char fw_path[PATH_MAX];
printf("bcm43xx_init\n");
if (bcm43xx_reset(fd))
return -1;
if (bcm43xx_read_local_name(fd, chip_name, sizeof(chip_name)))
return -1;
if (bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) {
fprintf(stderr, "Patch not found, continue anyway\n");
} else {
if (bcm43xx_load_firmware(fd, fw_path))
return -1;
if (bcm43xx_reset(fd))
return -1;
}
if (bdaddr)
bcm43xx_set_bdaddr(fd, bdaddr);
if (speed > 3000000 && bcm43xx_set_clock(fd, BCM43XX_CLOCK_48))
return -1;
if (bcm43xx_set_speed(fd, speed))
return -1;
return 0;
}

View File

@@ -0,0 +1,595 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2012 Intel Corporation. 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 <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <time.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "hciattach.h"
#ifdef INTEL_DEBUG
#define DBGPRINT(fmt, args...) printf("DBG: " fmt "\n", ## args)
#define PRINT_PACKET(buf, len, msg) { \
int i; \
printf("%s\n", msg); \
for (i = 0; i < len; i++) \
printf("%02X ", buf[i]); \
printf("\n"); \
}
#else
#define DBGPRINT(fmt, args...)
#define PRINT_PACKET(buf, len, msg)
#endif
#define PATCH_SEQ_EXT ".bseq"
#define PATCH_FILE_PATH "/lib/firmware/intel/"
#define PATCH_MAX_LEN 260
#define PATCH_TYPE_CMD 1
#define PATCH_TYPE_EVT 2
#define INTEL_VER_PARAM_LEN 9
#define INTEL_MFG_PARAM_LEN 2
/**
* A data structure for a patch entry.
*/
struct patch_entry {
int type;
int len;
unsigned char data[PATCH_MAX_LEN];
};
/**
* A structure for patch context
*/
struct patch_ctx {
int dev;
int fd;
int patch_error;
int reset_enable_patch;
};
/**
* Send HCI command to the controller
*/
static int intel_write_cmd(int dev, unsigned char *buf, int len)
{
int ret;
PRINT_PACKET(buf, len, "<----- SEND CMD: ");
ret = write(dev, buf, len);
if (ret < 0)
return -errno;
if (ret != len)
return -1;
return ret;
}
/**
* Read the event from the controller
*/
static int intel_read_evt(int dev, unsigned char *buf, int len)
{
int ret;
ret = read_hci_event(dev, buf, len);
if (ret < 0)
return -1;
PRINT_PACKET(buf, ret, "-----> READ EVT: ");
return ret;
}
/**
* Validate HCI events
*/
static int validate_events(struct patch_entry *event,
struct patch_entry *entry)
{
if (event == NULL || entry == NULL) {
DBGPRINT("invalid patch entry parameters");
return -1;
}
if (event->len != entry->len) {
DBGPRINT("lengths are mismatched:[%d|%d]",
event->len, entry->len);
return -1;
}
if (memcmp(event->data, entry->data, event->len)) {
DBGPRINT("data is mismatched");
return -1;
}
return 0;
}
/**
* Read the next patch entry one line at a time
*/
static int get_next_patch_entry(int fd, struct patch_entry *entry)
{
int size;
char rb;
if (read(fd, &rb, 1) <= 0)
return 0;
entry->type = rb;
switch (entry->type) {
case PATCH_TYPE_CMD:
entry->data[0] = HCI_COMMAND_PKT;
if (read(fd, &entry->data[1], 3) < 0)
return -1;
size = (int)entry->data[3];
if (read(fd, &entry->data[4], size) < 0)
return -1;
entry->len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + size;
break;
case PATCH_TYPE_EVT:
entry->data[0] = HCI_EVENT_PKT;
if (read(fd, &entry->data[1], 2) < 0)
return -1;
size = (int)entry->data[2];
if (read(fd, &entry->data[3], size) < 0)
return -1;
entry->len = HCI_TYPE_LEN + HCI_EVENT_HDR_SIZE + size;
break;
default:
fprintf(stderr, "invalid patch entry(%d)\n", entry->type);
return -1;
}
return entry->len;
}
/**
* Download the patch set to the controller and verify the event
*/
static int intel_download_patch(struct patch_ctx *ctx)
{
int ret;
struct patch_entry entry;
struct patch_entry event;
DBGPRINT("start patch downloading");
do {
ret = get_next_patch_entry(ctx->fd, &entry);
if (ret <= 0) {
ctx->patch_error = 1;
break;
}
switch (entry.type) {
case PATCH_TYPE_CMD:
ret = intel_write_cmd(ctx->dev,
entry.data,
entry.len);
if (ret <= 0) {
fprintf(stderr, "failed to send cmd(%d)\n",
ret);
return ret;
}
break;
case PATCH_TYPE_EVT:
ret = intel_read_evt(ctx->dev, event.data,
sizeof(event.data));
if (ret <= 0) {
fprintf(stderr, "failed to read evt(%d)\n",
ret);
return ret;
}
event.len = ret;
if (validate_events(&event, &entry) < 0) {
DBGPRINT("events are mismatched");
ctx->patch_error = 1;
return -1;
}
break;
default:
fprintf(stderr, "unknown patch type(%d)\n",
entry.type);
return -1;
}
} while (1);
return ret;
}
static int open_patch_file(struct patch_ctx *ctx, char *fw_ver)
{
char patch_file[PATH_MAX];
snprintf(patch_file, PATH_MAX, "%s%s%s", PATCH_FILE_PATH,
fw_ver, PATCH_SEQ_EXT);
DBGPRINT("PATCH_FILE: %s", patch_file);
ctx->fd = open(patch_file, O_RDONLY);
if (ctx->fd < 0) {
DBGPRINT("cannot open patch file. go to post patch");
return -1;
}
return 0;
}
/**
* Prepare the controller for patching.
*/
static int pre_patch(struct patch_ctx *ctx)
{
int ret, i;
struct patch_entry entry;
char fw_ver[INTEL_VER_PARAM_LEN * 2];
DBGPRINT("start pre_patch");
entry.data[0] = HCI_COMMAND_PKT;
entry.data[1] = 0x11;
entry.data[2] = 0xFC;
entry.data[3] = 0x02;
entry.data[4] = 0x01;
entry.data[5] = 0x00;
entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN;
ret = intel_write_cmd(ctx->dev, entry.data, entry.len);
if (ret < 0) {
fprintf(stderr, "failed to send cmd(%d)\n", ret);
return ret;
}
ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));
if (ret < 0) {
fprintf(stderr, "failed to read evt(%d)\n", ret);
return ret;
}
entry.len = ret;
if (entry.data[6] != 0x00) {
DBGPRINT("command failed. status=%02x", entry.data[6]);
ctx->patch_error = 1;
return -1;
}
entry.data[0] = HCI_COMMAND_PKT;
entry.data[1] = 0x05;
entry.data[2] = 0xFC;
entry.data[3] = 0x00;
entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE;
ret = intel_write_cmd(ctx->dev, entry.data, entry.len);
if (ret < 0) {
fprintf(stderr, "failed to send cmd(%d)\n", ret);
return ret;
}
ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));
if (ret < 0) {
fprintf(stderr, "failed to read evt(%d)\n", ret);
return ret;
}
entry.len = ret;
if (entry.data[6] != 0x00) {
DBGPRINT("command failed. status=%02x", entry.data[6]);
ctx->patch_error = 1;
return -1;
}
for (i = 0; i < INTEL_VER_PARAM_LEN; i++)
sprintf(&fw_ver[i*2], "%02x", entry.data[7+i]);
if (open_patch_file(ctx, fw_ver) < 0) {
ctx->patch_error = 1;
return -1;
}
return ret;
}
/*
* check the event is startup event
*/
static int is_startup_evt(unsigned char *buf)
{
if (buf[1] == 0xFF && buf[2] == 0x01 && buf[3] == 0x00)
return 1;
return 0;
}
/**
* Finalize the patch process and reset the controller
*/
static int post_patch(struct patch_ctx *ctx)
{
int ret;
struct patch_entry entry;
DBGPRINT("start post_patch");
entry.data[0] = HCI_COMMAND_PKT;
entry.data[1] = 0x11;
entry.data[2] = 0xFC;
entry.data[3] = 0x02;
entry.data[4] = 0x00;
if (ctx->reset_enable_patch)
entry.data[5] = 0x02;
else
entry.data[5] = 0x01;
entry.len = HCI_TYPE_LEN + HCI_COMMAND_HDR_SIZE + INTEL_MFG_PARAM_LEN;
ret = intel_write_cmd(ctx->dev, entry.data, entry.len);
if (ret < 0) {
fprintf(stderr, "failed to send cmd(%d)\n", ret);
return ret;
}
ret = intel_read_evt(ctx->dev, entry.data, sizeof(entry.data));
if (ret < 0) {
fprintf(stderr, "failed to read evt(%d)\n", ret);
return ret;
}
entry.len = ret;
if (entry.data[6] != 0x00) {
fprintf(stderr, "cmd failed. st=%02x\n", entry.data[6]);
return -1;
}
do {
ret = intel_read_evt(ctx->dev, entry.data,
sizeof(entry.data));
if (ret < 0) {
fprintf(stderr, "failed to read cmd(%d)\n", ret);
return ret;
}
entry.len = ret;
} while (!is_startup_evt(entry.data));
return ret;
}
/**
* Main routine that handles the device patching process.
*/
static int intel_patch_device(struct patch_ctx *ctx)
{
int ret;
ret = pre_patch(ctx);
if (ret < 0) {
if (!ctx->patch_error) {
fprintf(stderr, "I/O error: pre_patch failed\n");
return ret;
}
DBGPRINT("patch failed. proceed to post patch");
goto post_patch;
}
ret = intel_download_patch(ctx);
if (ret < 0) {
if (!ctx->patch_error) {
fprintf(stderr, "I/O error: download_patch failed\n");
close(ctx->fd);
return ret;
}
} else {
DBGPRINT("patch done");
ctx->reset_enable_patch = 1;
}
close(ctx->fd);
post_patch:
ret = post_patch(ctx);
if (ret < 0) {
fprintf(stderr, "post_patch failed(%d)\n", ret);
return ret;
}
return 0;
}
static int set_rts(int dev, int rtsval)
{
int arg;
if (ioctl(dev, TIOCMGET, &arg) < 0) {
perror("cannot get TIOCMGET");
return -errno;
}
if (rtsval)
arg |= TIOCM_RTS;
else
arg &= ~TIOCM_RTS;
if (ioctl(dev, TIOCMSET, &arg) == -1) {
perror("cannot set TIOCMGET");
return -errno;
}
return 0;
}
static unsigned char get_intel_speed(int speed)
{
switch (speed) {
case 9600:
return 0x00;
case 19200:
return 0x01;
case 38400:
return 0x02;
case 57600:
return 0x03;
case 115200:
return 0x04;
case 230400:
return 0x05;
case 460800:
return 0x06;
case 921600:
return 0x07;
case 1843200:
return 0x08;
case 3250000:
return 0x09;
case 2000000:
return 0x0A;
case 3000000:
return 0x0B;
default:
return 0xFF;
}
}
/**
* if it failed to change to new baudrate, it will rollback
* to initial baudrate
*/
static int change_baudrate(int dev, int init_speed, int *speed,
struct termios *ti)
{
int ret;
unsigned char br;
unsigned char cmd[5];
unsigned char evt[7];
DBGPRINT("start baudrate change");
ret = set_rts(dev, 0);
if (ret < 0) {
fprintf(stderr, "failed to clear RTS\n");
return ret;
}
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x06;
cmd[2] = 0xFC;
cmd[3] = 0x01;
br = get_intel_speed(*speed);
if (br == 0xFF) {
fprintf(stderr, "speed %d is not supported\n", *speed);
return -1;
}
cmd[4] = br;
ret = intel_write_cmd(dev, cmd, sizeof(cmd));
if (ret < 0) {
fprintf(stderr, "failed to send cmd(%d)\n", ret);
return ret;
}
/*
* wait for buffer to be consumed by the controller
*/
usleep(300000);
if (set_speed(dev, ti, *speed) < 0) {
fprintf(stderr, "can't set to new baud rate\n");
return -1;
}
ret = set_rts(dev, 1);
if (ret < 0) {
fprintf(stderr, "failed to set RTS\n");
return ret;
}
ret = intel_read_evt(dev, evt, sizeof(evt));
if (ret < 0) {
fprintf(stderr, "failed to read evt(%d)\n", ret);
return ret;
}
if (evt[4] != 0x00) {
fprintf(stderr,
"failed to change speed. use default speed %d\n",
init_speed);
*speed = init_speed;
}
return 0;
}
/**
* An entry point for Intel specific initialization
*/
int intel_init(int dev, int init_speed, int *speed, struct termios *ti)
{
int ret = 0;
struct patch_ctx ctx;
if (change_baudrate(dev, init_speed, speed, ti) < 0)
return -1;
ctx.dev = dev;
ctx.patch_error = 0;
ctx.reset_enable_patch = 0;
ret = intel_patch_device(&ctx);
if (ret < 0)
fprintf(stderr, "failed to initialize the device");
return ret;
}

View File

@@ -0,0 +1,273 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (c) 2010, Code Aurora Forum. 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 <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <termios.h>
#include <time.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "hciattach.h"
#define FAILIF(x, args...) do { \
if (x) { \
fprintf(stderr, ##args); \
return -1; \
} \
} while (0)
typedef struct {
uint8_t uart_prefix;
hci_event_hdr hci_hdr;
evt_cmd_complete cmd_complete;
uint8_t status;
uint8_t data[16];
} __attribute__((packed)) command_complete_t;
static int read_command_complete(int fd,
unsigned short opcode,
unsigned char len)
{
command_complete_t resp;
unsigned char vsevent[512];
int n;
/* Read reply. */
n = read_hci_event(fd, vsevent, sizeof(vsevent));
FAILIF(n < 0, "Failed to read response");
FAILIF(vsevent[1] != 0xFF, "Failed to read response");
n = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
FAILIF(n < 0, "Failed to read response");
/* event must be event-complete */
FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE,
"Error in response: not a cmd-complete event, "
"but 0x%02x!\n", resp.hci_hdr.evt);
FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */
"Error in response: plen is not >= 4, but 0x%02x!\n",
resp.hci_hdr.plen);
/* cmd-complete event: opcode */
FAILIF(resp.cmd_complete.opcode != 0,
"Error in response: opcode is 0x%04x, not 0!",
resp.cmd_complete.opcode);
return resp.status == 0 ? 0 : -1;
}
static int qualcomm_load_firmware(int fd, const char *firmware, const char *bdaddr_s)
{
int fw = open(firmware, O_RDONLY);
fprintf(stdout, "Opening firmware file: %s\n", firmware);
FAILIF(fw < 0,
"Could not open firmware file %s: %s (%d).\n",
firmware, strerror(errno), errno);
fprintf(stdout, "Uploading firmware...\n");
do {
/* Read each command and wait for a response. */
unsigned char data[1024];
unsigned char cmdp[1 + sizeof(hci_command_hdr)];
hci_command_hdr *cmd = (hci_command_hdr *) (cmdp + 1);
int nr;
nr = read(fw, cmdp, sizeof(cmdp));
if (!nr)
break;
FAILIF(nr != sizeof(cmdp),
"Could not read H4 + HCI header!\n");
FAILIF(*cmdp != HCI_COMMAND_PKT,
"Command is not an H4 command packet!\n");
FAILIF(read(fw, data, cmd->plen) != cmd->plen,
"Could not read %d bytes of data \
for command with opcode %04x!\n",
cmd->plen, cmd->opcode);
if ((data[0] == 1) && (data[1] == 2) && (data[2] == 6)) {
bdaddr_t bdaddr;
if (bdaddr_s != NULL) {
str2ba(bdaddr_s, &bdaddr);
memcpy(&data[3], &bdaddr, sizeof(bdaddr_t));
}
}
{
int nw;
struct iovec iov_cmd[2];
iov_cmd[0].iov_base = cmdp;
iov_cmd[0].iov_len = sizeof(cmdp);
iov_cmd[1].iov_base = data;
iov_cmd[1].iov_len = cmd->plen;
nw = writev(fd, iov_cmd, 2);
FAILIF(nw != (int) sizeof(cmdp) + cmd->plen,
"Could not send entire command \
(sent only %d bytes)!\n",
nw);
}
/* Wait for response */
if (read_command_complete(fd, cmd->opcode, cmd->plen) < 0)
return -1;
} while (1);
fprintf(stdout, "Firmware upload successful.\n");
close(fw);
return 0;
}
int qualcomm_init(int fd, int speed, struct termios *ti, const char *bdaddr)
{
struct timespec tm = {0, 50000};
char cmd[5];
unsigned char resp[100]; /* Response */
char fw[100];
int n;
memset(resp, 0, 100);
/* Get Manufacturer and LMP version */
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x01;
cmd[2] = 0x10;
cmd[3] = 0x00;
do {
n = write(fd, cmd, 4);
if (n < 4) {
perror("Failed to write init command");
return -1;
}
/* Read reply. */
if (read_hci_event(fd, resp, 100) < 0) {
perror("Failed to read init response");
return -1;
}
/* Wait for command complete event for our Opcode */
} while (resp[4] != cmd[1] && resp[5] != cmd[2]);
/* Verify manufacturer */
if ((resp[11] & 0xFF) != 0x1d)
fprintf(stderr,
"WARNING : module's manufacturer is not Qualcomm\n");
/* Print LMP version */
fprintf(stderr,
"Qualcomm module LMP version : 0x%02x\n", resp[10] & 0xFF);
/* Print LMP subversion */
{
unsigned short lmp_subv = resp[13] | (resp[14] << 8);
fprintf(stderr, "Qualcomm module LMP sub-version : 0x%04x\n",
lmp_subv);
}
/* Get SoC type */
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x00;
cmd[2] = 0xFC;
cmd[3] = 0x01;
cmd[4] = 0x06;
do {
n = write(fd, cmd, 5);
if (n < 5) {
perror("Failed to write vendor init command");
return -1;
}
/* Read reply. */
if ((n = read_hci_event(fd, resp, 100)) < 0) {
perror("Failed to read vendor init response");
return -1;
}
} while (resp[3] != 0 && resp[4] != 2);
snprintf(fw, sizeof(fw), "/etc/firmware/%c%c%c%c%c%c_%c%c%c%c.bin",
resp[18], resp[19], resp[20], resp[21],
resp[22], resp[23],
resp[32], resp[33], resp[34], resp[35]);
/* Wait for command complete event for our Opcode */
if (read_hci_event(fd, resp, 100) < 0) {
perror("Failed to read init response");
return -1;
}
qualcomm_load_firmware(fd, fw, bdaddr);
/* Reset */
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x03;
cmd[2] = 0x0C;
cmd[3] = 0x00;
do {
n = write(fd, cmd, 4);
if (n < 4) {
perror("Failed to write reset command");
return -1;
}
/* Read reply. */
if ((n = read_hci_event(fd, resp, 100)) < 0) {
perror("Failed to read reset response");
return -1;
}
} while (resp[4] != cmd[1] && resp[5] != cmd[2]);
nanosleep(&tm, NULL);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,707 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <stdint.h>
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <limits.h>
#include "hciattach.h"
/******************************************************************************
** Constants & Macros
******************************************************************************/
#define LOG_STR "SPRD Bluetooth"
#define DBG_ON 1
#define SPRD_DBG(fmt, arg...) \
do { \
if (DBG_ON) \
fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \
} while(0)
#define SPRD_ERR(fmt, arg...) \
do { \
fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\
perror(LOG_STR" ERROR reason"); \
} while(0)
#define SPRD_DUMP(buffer, len) \
fprintf(stderr, "%s: ", LOG_STR); \
do { \
for (int i = 0; i < len; i++) { \
if (i && !(i % 16)) { \
fprintf(stderr, "\n"); \
fprintf(stderr, "%s: ", LOG_STR); \
} \
fprintf(stderr, "%02x ", buffer[i]); \
} \
fprintf(stderr, "\n"); \
} while (0)
#define CONF_ITEM_TABLE(ITEM, ACTION, BUF, LEN) \
{ #ITEM, ACTION, &(BUF.ITEM), LEN, (sizeof(BUF.ITEM) / LEN) }
#define UINT8_TO_STREAM(p, u8) \
{ *(p)++ = (uint8_t)(u8); }
#define STREAM_TO_UINT8(u8, p) \
{ \
(u8) = (uint8_t)(*(p)); \
(p) += 1; \
}
#define UINT16_TO_STREAM(p, u16) \
{ \
*(p)++ = (uint8_t)(u16); \
*(p)++ = (uint8_t)((u16) >> 8); \
}
#define STREAM_TO_UINT16(u16, p) \
{ \
(u16) = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); \
(p) += 2; \
}
#define UINT32_TO_STREAM(p, u32) \
{ \
*(p)++ = (uint8_t)(u32); \
*(p)++ = (uint8_t)((u32) >> 8); \
*(p)++ = (uint8_t)((u32) >> 16); \
*(p)++ = (uint8_t)((u32) >> 24); \
}
#define CONF_COMMENT '#'
#define CONF_DELIMITERS " =\n\r\t"
#define CONF_VALUES_DELIMITERS "=\n\r\t#"
#define CONF_VALUES_PARTITION " ,=\n\r\t#"
#define CONF_MAX_LINE_LEN 255
#define HCI_PSKEY 0xFCA0
#define HCI_VSC_ENABLE_COMMMAND 0xFCA1
#define HCI_RF_PARA 0xFCA2
#define RESPONSE_LENGTH 100
#define HCI_CMD_MAX_LEN 258
#define HCI_EVT_CMD_CMPL_OPCODE 3
#define HCI_PACKET_TYPE_COMMAND 1
#define HCI_CMD_PREAMBLE_SIZE 3
#define FW_NODE_BYTE 6
#define FW_DATE_D_BYTE 8
#define FW_DATE_M_BYTE 9
#define FW_DATE_Y_BYTE 10
#define BT_CONFIG_PATH "/lib/firmware"
#define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR))
#define BT_VND_OP_RESULT_SUCCESS 0
#define BT_VND_OP_RESULT_FAIL 1
#define MSG_STACK_TO_HC_HCI_CMD 0x2000
#define START_STOP_CMD_SIZE 3
#define DUAL_MODE 0
#define DISABLE_BT 0
#define ENABLE_BT 1
typedef void (*hci_cback)(void *);
typedef int (conf_action_t)(char *p_conf_name, char *p_conf_value, void *buf, int len, int size);
typedef struct {
uint16_t event;
uint16_t len;
uint16_t offset;
uint16_t layer_specific;
uint8_t data[];
} HC_BT_HDR;
typedef struct {
uint32_t device_class;
uint8_t feature_set[16];
uint8_t device_addr[6];
uint16_t comp_id;
uint8_t g_sys_uart0_communication_supported;
uint8_t cp2_log_mode;
uint8_t LogLevel;
uint8_t g_central_or_perpheral;
uint16_t Log_BitMask;
uint8_t super_ssp_enable;
uint8_t common_rfu_b3;
uint32_t common_rfu_w[2];
uint32_t le_rfu_w[2];
uint32_t lmp_rfu_w[2];
uint32_t lc_rfu_w[2];
uint16_t g_wbs_nv_117;
uint16_t g_wbs_nv_118;
uint16_t g_nbv_nv_117;
uint16_t g_nbv_nv_118;
uint8_t g_sys_sco_transmit_mode;
uint8_t audio_rfu_b1;
uint8_t audio_rfu_b2;
uint8_t audio_rfu_b3;
uint32_t audio_rfu_w[2];
uint8_t g_sys_sleep_in_standby_supported;
uint8_t g_sys_sleep_master_supported;
uint8_t g_sys_sleep_slave_supported;
uint8_t power_rfu_b1;
uint32_t power_rfu_w[2];
uint32_t win_ext;
uint8_t edr_tx_edr_delay;
uint8_t edr_rx_edr_delay;
uint8_t tx_delay;
uint8_t rx_delay;
uint32_t bb_rfu_w[2];
uint8_t agc_mode;
uint8_t diff_or_eq;
uint8_t ramp_mode;
uint8_t modem_rfu_b1;
uint32_t modem_rfu_w[2];
uint32_t BQB_BitMask_1;
uint32_t BQB_BitMask_2;
uint16_t bt_coex_threshold[8];
uint32_t other_rfu_w[6];
} pskey_config_t;
typedef struct {
uint16_t g_GainValue_A[6];
uint16_t g_ClassicPowerValue_A[10];
uint16_t g_LEPowerValue_A[16];
uint16_t g_BRChannelpwrvalue_A[8];
uint16_t g_EDRChannelpwrvalue_A[8];
uint16_t g_LEChannelpwrvalue_A[8];
uint16_t g_GainValue_B[6];
uint16_t g_ClassicPowerValue_B[10];
uint16_t g_LEPowerValue_B[16];
uint16_t g_BRChannelpwrvalue_B[8];
uint16_t g_EDRChannelpwrvalue_B[8];
uint16_t g_LEChannelpwrvalue_B[8];
uint16_t LE_fix_powerword;
uint8_t Classic_pc_by_channel;
uint8_t LE_pc_by_channel;
uint8_t RF_switch_mode;
uint8_t Data_Capture_Mode;
uint8_t Analog_IQ_Debug_Mode;
uint8_t RF_common_rfu_b3;
uint32_t RF_common_rfu_w[5];
} rf_config_t;
typedef struct {
const char *conf_entry;
conf_action_t *p_action;
void *buf;
int len;
int size;
} conf_entry_t;
static uint8_t local_bdaddr[6]={0x10, 0x11, 0x12, 0x13, 0x14, 0x15};
static pskey_config_t marlin3_pskey;
static rf_config_t marlin3_rf_config;
static int s_bt_fd = -1;
static const conf_entry_t marlin3_pksey_table[] = {
CONF_ITEM_TABLE(device_class, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(feature_set, 0, marlin3_pskey, 16),
CONF_ITEM_TABLE(device_addr, 0, marlin3_pskey, 6),
CONF_ITEM_TABLE(comp_id, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_sys_uart0_communication_supported, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(cp2_log_mode, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(LogLevel, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_central_or_perpheral, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(Log_BitMask, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(super_ssp_enable, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(common_rfu_b3, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(common_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(le_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(lmp_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(lc_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(g_wbs_nv_117, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_wbs_nv_118, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_nbv_nv_117, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_nbv_nv_118, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_sys_sco_transmit_mode, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(audio_rfu_b1, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(audio_rfu_b2, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(audio_rfu_b3, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(audio_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(g_sys_sleep_in_standby_supported, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_sys_sleep_master_supported, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(g_sys_sleep_slave_supported, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(power_rfu_b1, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(power_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(win_ext, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(edr_tx_edr_delay, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(edr_rx_edr_delay, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(tx_delay, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(rx_delay, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(bb_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(agc_mode, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(diff_or_eq, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(ramp_mode, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(modem_rfu_b1, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(modem_rfu_w, 0, marlin3_pskey, 2),
CONF_ITEM_TABLE(BQB_BitMask_1, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(BQB_BitMask_2, 0, marlin3_pskey, 1),
CONF_ITEM_TABLE(bt_coex_threshold, 0, marlin3_pskey, 8),
CONF_ITEM_TABLE(other_rfu_w, 0, marlin3_pskey, 6),
{0, 0, 0, 0, 0}
};
static const conf_entry_t marlin3_rf_table[] = {
CONF_ITEM_TABLE(g_GainValue_A, 0, marlin3_rf_config, 6),
CONF_ITEM_TABLE(g_ClassicPowerValue_A, 0, marlin3_rf_config, 10),
CONF_ITEM_TABLE(g_LEPowerValue_A, 0, marlin3_rf_config, 16),
CONF_ITEM_TABLE(g_BRChannelpwrvalue_A, 0, marlin3_rf_config, 8),
CONF_ITEM_TABLE(g_EDRChannelpwrvalue_A, 0, marlin3_rf_config, 8),
CONF_ITEM_TABLE(g_LEChannelpwrvalue_A, 0, marlin3_rf_config, 8),
CONF_ITEM_TABLE(g_GainValue_B, 0, marlin3_rf_config, 6),
CONF_ITEM_TABLE(g_ClassicPowerValue_B, 0, marlin3_rf_config, 10),
CONF_ITEM_TABLE(g_LEPowerValue_B, 0, marlin3_rf_config, 16),
CONF_ITEM_TABLE(g_BRChannelpwrvalue_B, 0, marlin3_rf_config, 8),
CONF_ITEM_TABLE(g_EDRChannelpwrvalue_B, 0, marlin3_rf_config, 8),
CONF_ITEM_TABLE(g_LEChannelpwrvalue_B, 0, marlin3_rf_config, 8),
CONF_ITEM_TABLE(LE_fix_powerword, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(Classic_pc_by_channel, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(LE_pc_by_channel, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(RF_switch_mode, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(Data_Capture_Mode, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(Analog_IQ_Debug_Mode, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(RF_common_rfu_b3, 0, marlin3_rf_config, 1),
CONF_ITEM_TABLE(RF_common_rfu_w, 0, marlin3_rf_config, 5),
{0, 0, 0, 0, 0}
};
static void log_bin_to_hexstr(uint8_t *bin, uint8_t binsz, const char *log_tag)
{
SPRD_DBG("%s", log_tag);
SPRD_DUMP(bin, binsz);
}
static void parse_number(char *p_conf_name, char *p_conf_value, void *buf, int len, int size)
{
uint8_t *dest = (uint8_t *)buf;
char *sub_value, *p;
uint32_t value;
(void)p_conf_name;
sub_value = strtok_r(p_conf_value, CONF_VALUES_PARTITION, &p);
do {
if (sub_value == NULL)
break;
if (sub_value[0] == '0' && (sub_value[1] == 'x' || sub_value[1] == 'X'))
value = strtoul(sub_value, 0, 16) & 0xFFFFFFFF;
else
value = strtoul(sub_value, 0, 10) & 0xFFFFFFFF;
switch (size) {
case sizeof(uint8_t):
*dest = value & 0xFF;
dest += size;
break;
case sizeof(uint16_t):
*((uint16_t *)dest) = value & 0xFFFF;
dest += size;
break;
case sizeof(uint32_t):
*((uint32_t *)dest) = value & 0xFFFFFFFF;
dest += size;
break;
default:
break;
}
sub_value = strtok_r(NULL, CONF_VALUES_PARTITION, &p);
} while (--len);
}
static void set_mac_address(uint8_t *addr)
{
int i = 0;
SPRD_DBG("%s", __func__);
for (i = 0; i < 6; i++)
addr[5-i] = (unsigned char)local_bdaddr[i];
}
static void vnd_load_configure(const char *p_path, const conf_entry_t *entry)
{
FILE *p_file;
char *p_name, *p_value, *p;
conf_entry_t *p_entry;
char line[CONF_MAX_LINE_LEN + 1]; /* add 1 for \0 char */
SPRD_DBG("Attempt to load conf from %s", p_path);
if ((p_file = fopen(p_path, "r")) != NULL) {
/* read line by line */
while (fgets(line, CONF_MAX_LINE_LEN + 1, p_file) != NULL) {
if (line[0] == CONF_COMMENT) continue;
p_name = strtok_r(line, CONF_DELIMITERS, &p);
if (NULL == p_name) {
continue;
}
p_value = strtok_r(NULL, CONF_VALUES_DELIMITERS, &p);
if (NULL == p_value) {
SPRD_DBG("vnd_load_conf: missing value for name: %s", p_name);
continue;
}
p_entry = (conf_entry_t*)entry;
while (p_entry->conf_entry != NULL) {
if (strcmp(p_entry->conf_entry, (const char *)p_name) == 0) {
if (p_entry->p_action) {
p_entry->p_action(p_name, p_value, p_entry->buf, p_entry->len,
p_entry->size);
} else {
SPRD_DBG("%s -> %s", p_name, p_value);
parse_number(p_name, p_value, p_entry->buf, p_entry->len,
p_entry->size);
}
break;
}
p_entry++;
}
}
fclose(p_file);
} else {
SPRD_DBG("vnd_load_conf file >%s< not found", p_path);
}
}
static size_t H4Protocol_Send(uint8_t type, const uint8_t* data, size_t length)
{
struct iovec iov[] = {
{&type, sizeof(type)},
{(uint8_t *)data, length}};
ssize_t ret = 0;
do {
ret = writev(s_bt_fd, iov, sizeof(iov) / sizeof(iov[0]));
} while (-1 == ret && EAGAIN == errno);
if (ret == -1) {
SPRD_ERR("%s error writing to UART (%s)", __func__, strerror(errno));
} else if (ret < length + 1) {
SPRD_ERR("%s: %d / %d bytes written - something went wrong...", __func__, ret, length + 1);
}
return ret;
}
static void *bt_vendor_alloc(int size)
{
void *p = (uint8_t *)malloc(size);
return p;
}
static void bt_vendor_free(void *buffer)
{
free(buffer);
}
static uint8_t bt_vendor_xmit(uint16_t opcode, void* buffer, hci_cback callback)
{
uint8_t type = HCI_PACKET_TYPE_COMMAND;
(void)opcode;
HC_BT_HDR* bt_hdr = (HC_BT_HDR *)buffer;
H4Protocol_Send(type, bt_hdr->data, bt_hdr->len);
return BT_VND_OP_RESULT_SUCCESS;
}
static uint8_t sprd_vnd_send_hci_vsc(uint16_t cmd, uint8_t *payload, uint8_t len, hci_cback cback)
{
HC_BT_HDR *p_buf;
uint8_t *p, ret;
p_buf = (HC_BT_HDR *)bt_vendor_alloc(
BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + len);
if (p_buf) {
p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
p_buf->offset = 0;
p_buf->layer_specific = 0;
p_buf->len = HCI_CMD_PREAMBLE_SIZE + len;
p = (uint8_t *)(p_buf + 1);
UINT16_TO_STREAM(p, cmd);
*p++ = len;
memcpy(p, payload, len);
log_bin_to_hexstr((uint8_t *)(p_buf + 1), HCI_CMD_PREAMBLE_SIZE + len, __FUNCTION__);
ret = bt_vendor_xmit(cmd, p_buf, cback);
bt_vendor_free(p_buf);
return ret;
}
return BT_VND_OP_RESULT_FAIL;
}
static void hw_core_cback(void *p_mem)
{
uint8_t *p_evt_buf = (uint8_t *)p_mem;
uint8_t *p, status;
uint16_t opcode, mode;
p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
STREAM_TO_UINT16(opcode,p);
STREAM_TO_UINT16(mode,p);
STREAM_TO_UINT8(status,p);
SPRD_DBG("%s hw_core_cback response: [0x%04X, 0x%04X, 0x%02X]", __func__, opcode, mode, status);
bt_vendor_free(p_evt_buf);
}
static void hw_core_enable(unsigned char enable)
{
uint8_t *p, msg_req[HCI_CMD_MAX_LEN];
p = msg_req;
UINT16_TO_STREAM(p, DUAL_MODE);
UINT8_TO_STREAM(p, enable ? ENABLE_BT : DISABLE_BT);
sprd_vnd_send_hci_vsc(HCI_VSC_ENABLE_COMMMAND, msg_req, (uint8_t)(p - msg_req), NULL);
}
static void hw_rf_cback(void *p_mem)
{
uint8_t *p_evt_buf = (uint8_t *)p_mem, len;
uint8_t *p, status;
uint16_t opcode, mode = 0;
p = (uint8_t *)(p_evt_buf + 1) + 1;
STREAM_TO_UINT8(len, p);
p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
STREAM_TO_UINT16(opcode, p);
if (len == 6)
STREAM_TO_UINT16(mode, p);
STREAM_TO_UINT8(status, p);
SPRD_DBG("%s hw_rf_cback response: [0x%04X, 0x%04X, 0x%02X]", __func__, opcode, mode, status);
/* Must free the RX event buffer */
bt_vendor_free(p_evt_buf);
}
static int marlin3_rf_preload()
{
uint8_t *p, msg_req[HCI_CMD_MAX_LEN];
int i;
SPRD_DBG("yujian.qin %s", __FUNCTION__);
p = msg_req;
for (i = 0; i < 6; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_GainValue_A[i]);
for (i = 0; i < 10; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_ClassicPowerValue_A[i]);
for (i = 0; i < 16; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_LEPowerValue_A[i]);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_BRChannelpwrvalue_A[i]);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_EDRChannelpwrvalue_A[i]);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_LEChannelpwrvalue_A[i]);
for (i = 0; i < 6; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_GainValue_B[i]);
for (i = 0; i < 10; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_ClassicPowerValue_B[i]);
for (i = 0; i < 16; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_LEPowerValue_B[i]);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_BRChannelpwrvalue_B[i]);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_EDRChannelpwrvalue_B[i]);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_rf_config.g_LEChannelpwrvalue_B[i]);
UINT16_TO_STREAM(p, marlin3_rf_config.LE_fix_powerword);
UINT8_TO_STREAM(p, marlin3_rf_config.Classic_pc_by_channel);
UINT8_TO_STREAM(p, marlin3_rf_config.LE_pc_by_channel);
UINT8_TO_STREAM(p, marlin3_rf_config.RF_switch_mode);
UINT8_TO_STREAM(p, marlin3_rf_config.Data_Capture_Mode);
UINT8_TO_STREAM(p, marlin3_rf_config.Analog_IQ_Debug_Mode);
UINT8_TO_STREAM(p, marlin3_rf_config.RF_common_rfu_b3);
for (i = 0; i < 5; i++)
UINT32_TO_STREAM(p, marlin3_rf_config.RF_common_rfu_w[i]);
sprd_vnd_send_hci_vsc(HCI_RF_PARA, msg_req, (uint8_t)(p - msg_req), NULL);
return 0;
}
static void marlin3_pskey_cback(void *p_mem)
{
uint8_t *p_evt_buf = (uint8_t *)p_mem;
uint16_t opcode, node, year;
uint8_t *p, month, day;
(void)opcode;
p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_OPCODE;
STREAM_TO_UINT16(opcode, p);
p = (uint8_t *)(p_evt_buf + 1) + FW_NODE_BYTE;
STREAM_TO_UINT16(node, p);
p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_Y_BYTE;
STREAM_TO_UINT16(year, p);
p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_M_BYTE;
STREAM_TO_UINT8(month, p);
p = (uint8_t *)(p_evt_buf + 1) + FW_DATE_D_BYTE;
STREAM_TO_UINT8(day, p);
SPRD_DBG("Bluetooth Firmware Node: %04X Date: %04x-%02x-%02x", node, year, month, day);
/* Must free the RX event buffer */
bt_vendor_free(p_evt_buf);
}
static int marlin3_pskey_preload(void *arg)
{
uint8_t *p, msg_req[HCI_CMD_MAX_LEN];
int i;
(void)arg;
SPRD_DBG("%s", __FUNCTION__);
p = msg_req;
UINT32_TO_STREAM(p, marlin3_pskey.device_class);
for (i = 0; i < 16; i++)
UINT8_TO_STREAM(p, marlin3_pskey.feature_set[i]);
for (i = 0; i < 6; i++)
UINT8_TO_STREAM(p, marlin3_pskey.device_addr[i]);
UINT16_TO_STREAM(p, marlin3_pskey.comp_id);
UINT8_TO_STREAM(p, marlin3_pskey.g_sys_uart0_communication_supported);
UINT8_TO_STREAM(p, marlin3_pskey.cp2_log_mode);
UINT8_TO_STREAM(p, marlin3_pskey.LogLevel);
UINT8_TO_STREAM(p, marlin3_pskey.g_central_or_perpheral);
UINT16_TO_STREAM(p, marlin3_pskey.Log_BitMask);
UINT8_TO_STREAM(p, marlin3_pskey.super_ssp_enable);
UINT8_TO_STREAM(p, marlin3_pskey.common_rfu_b3);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.common_rfu_w[i]);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.le_rfu_w[i]);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.lmp_rfu_w[i]);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.lc_rfu_w[i]);
UINT16_TO_STREAM(p, marlin3_pskey.g_wbs_nv_117);
UINT16_TO_STREAM(p, marlin3_pskey.g_wbs_nv_118);
UINT16_TO_STREAM(p, marlin3_pskey.g_nbv_nv_117);
UINT16_TO_STREAM(p, marlin3_pskey.g_nbv_nv_118);
UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sco_transmit_mode);
UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b1);
UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b2);
UINT8_TO_STREAM(p, marlin3_pskey.audio_rfu_b3);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.audio_rfu_w[i]);
UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_in_standby_supported);
UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_master_supported);
UINT8_TO_STREAM(p, marlin3_pskey.g_sys_sleep_slave_supported);
UINT8_TO_STREAM(p, marlin3_pskey.power_rfu_b1);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.power_rfu_w[i]);
UINT32_TO_STREAM(p, marlin3_pskey.win_ext);
UINT8_TO_STREAM(p, marlin3_pskey.edr_tx_edr_delay);
UINT8_TO_STREAM(p, marlin3_pskey.edr_rx_edr_delay);
UINT8_TO_STREAM(p, marlin3_pskey.tx_delay);
UINT8_TO_STREAM(p, marlin3_pskey.rx_delay);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.bb_rfu_w[i]);
UINT8_TO_STREAM(p, marlin3_pskey.agc_mode);
UINT8_TO_STREAM(p, marlin3_pskey.diff_or_eq);
UINT8_TO_STREAM(p, marlin3_pskey.ramp_mode);
UINT8_TO_STREAM(p, marlin3_pskey.modem_rfu_b1);
for (i = 0; i < 2; i++)
UINT32_TO_STREAM(p, marlin3_pskey.modem_rfu_w[i]);
UINT32_TO_STREAM(p, marlin3_pskey.BQB_BitMask_1);
UINT32_TO_STREAM(p, marlin3_pskey.BQB_BitMask_2);
for (i = 0; i < 8; i++)
UINT16_TO_STREAM(p, marlin3_pskey.bt_coex_threshold[i]);
for (i = 0; i < 6; i++)
UINT32_TO_STREAM(p, marlin3_pskey.other_rfu_w[i]);
sprd_vnd_send_hci_vsc(HCI_PSKEY, msg_req, (uint8_t)(p - msg_req), NULL);
return 0;
}
int sprd_config_init(int fd, struct uart_t *u, struct termios *ti)
{
uint8_t *recv = NULL;
int len = 0;
s_bt_fd = fd;
memset(&marlin3_pskey, 0, sizeof(marlin3_pskey));
memset(&marlin3_rf_config, 0, sizeof(marlin3_rf_config));
vnd_load_configure(BT_CONFIG_PATH "/bt_configure_pskey.ini", &marlin3_pksey_table[0]);
vnd_load_configure(BT_CONFIG_PATH "/bt_configure_rf.ini", &marlin3_rf_table[0]);
set_mac_address(marlin3_pskey.device_addr);
marlin3_pskey_preload(NULL);
recv = bt_vendor_alloc(RESPONSE_LENGTH);
len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH);
SPRD_DBG("Received event, len: %d", len);
SPRD_DUMP(recv, len);
marlin3_pskey_cback(recv);
marlin3_rf_preload();
recv = bt_vendor_alloc(RESPONSE_LENGTH);
len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH);
SPRD_DBG("Received event, len: %d", len);
SPRD_DUMP(recv, len);
hw_rf_cback(recv);
hw_core_enable(1);
recv = bt_vendor_alloc(RESPONSE_LENGTH);
len = read_hci_event(s_bt_fd, recv, RESPONSE_LENGTH);
SPRD_DBG("Received event, len: %d", len);
SPRD_DUMP(recv, len);
hw_core_cback(recv);
return 0;
}
int sprd_config_post(int fd, struct uart_t *u, struct termios *ti)
{
SPRD_DBG("Done setting line discpline");
return 0;
}

View File

@@ -0,0 +1,278 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <dirent.h>
#include <sys/param.h>
#include <bluetooth/bluetooth.h>
#include "hciattach.h"
static int debug = 0;
static int do_command(int fd, uint8_t ogf, uint16_t ocf,
uint8_t *cparam, int clen, uint8_t *rparam, int rlen)
{
//uint16_t opcode = (uint16_t) ((ocf & 0x03ff) | (ogf << 10));
unsigned char cp[260], rp[260];
int len, size, offset = 3;
cp[0] = 0x01;
cp[1] = ocf & 0xff;
cp[2] = ogf << 2 | ocf >> 8;
cp[3] = clen;
if (clen > 0)
memcpy(cp + 4, cparam, clen);
if (debug) {
int i;
printf("[<");
for (i = 0; i < clen + 4; i++)
printf(" %02x", cp[i]);
printf("]\n");
}
if (write(fd, cp, clen + 4) < 0)
return -1;
do {
if (read(fd, rp, 1) < 1)
return -1;
} while (rp[0] != 0x04);
if (read(fd, rp + 1, 2) < 2)
return -1;
do {
len = read(fd, rp + offset, sizeof(rp) - offset);
offset += len;
} while (offset < rp[2] + 3);
if (debug) {
int i;
printf("[>");
for (i = 0; i < offset; i++)
printf(" %02x", rp[i]);
printf("]\n");
}
if (rp[0] != 0x04) {
errno = EIO;
return -1;
}
switch (rp[1]) {
case 0x0e: /* command complete */
if (rp[6] != 0x00)
return -ENXIO;
offset = 3 + 4;
size = rp[2] - 4;
break;
case 0x0f: /* command status */
/* fall through */
default:
offset = 3;
size = rp[2];
break;
}
if (!rparam || rlen < size)
return -ENXIO;
memcpy(rparam, rp + offset, size);
return size;
}
static int load_file(int dd, uint16_t version, const char *suffix)
{
DIR *dir;
struct dirent *d;
char pathname[PATH_MAX], filename[NAME_MAX], prefix[20];
unsigned char cmd[256];
unsigned char buf[256];
uint8_t seqnum = 0;
int fd, size, len, found_fw_file;
memset(filename, 0, sizeof(filename));
snprintf(prefix, sizeof(prefix), "STLC2500_R%d_%02d_",
version >> 8, version & 0xff);
strcpy(pathname, "/lib/firmware");
dir = opendir(pathname);
if (!dir) {
strcpy(pathname, ".");
dir = opendir(pathname);
if (!dir)
return -errno;
}
found_fw_file = 0;
while (1) {
d = readdir(dir);
if (!d)
break;
if (strncmp(d->d_name + strlen(d->d_name) - strlen(suffix),
suffix, strlen(suffix)))
continue;
if (strncmp(d->d_name, prefix, strlen(prefix)))
continue;
snprintf(filename, sizeof(filename), "%s/%s",
pathname, d->d_name);
found_fw_file = 1;
}
closedir(dir);
if (!found_fw_file)
return -ENOENT;
printf("Loading file %s\n", filename);
fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("Can't open firmware file");
return -errno;
}
while (1) {
size = read(fd, cmd + 1, 254);
if (size <= 0)
break;
cmd[0] = seqnum;
len = do_command(dd, 0xff, 0x002e, cmd, size + 1, buf, sizeof(buf));
if (len < 1)
break;
if (buf[0] != seqnum) {
fprintf(stderr, "Sequence number mismatch\n");
break;
}
seqnum++;
}
close(fd);
return 0;
}
int stlc2500_init(int dd, bdaddr_t *bdaddr)
{
unsigned char cmd[16];
unsigned char buf[254];
uint16_t version;
int len;
int err;
/* Hci_Cmd_Ericsson_Read_Revision_Information */
len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
printf("%s\n", buf);
/* HCI_Read_Local_Version_Information */
len = do_command(dd, 0x04, 0x0001, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
version = buf[2] << 8 | buf[1];
err = load_file(dd, version, ".ptc");
if (err < 0) {
if (err == -ENOENT)
fprintf(stderr, "No ROM patch file loaded.\n");
else
return -1;
}
err = load_file(dd, buf[2] << 8 | buf[1], ".ssf");
if (err < 0) {
if (err == -ENOENT)
fprintf(stderr, "No static settings file loaded.\n");
else
return -1;
}
cmd[0] = 0xfe;
cmd[1] = 0x06;
bacpy((bdaddr_t *) (cmd + 2), bdaddr);
/* Hci_Cmd_ST_Store_In_NVDS */
len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf));
if (len < 0)
return -1;
/* HCI_Reset : applies parameters*/
len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
return 0;
}
int bgb2xx_init(int dd, bdaddr_t *bdaddr)
{
unsigned char cmd[16];
unsigned char buf[254];
int len;
len = do_command(dd, 0xff, 0x000f, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
printf("%s\n", buf);
cmd[0] = 0xfe;
cmd[1] = 0x06;
bacpy((bdaddr_t *) (cmd + 2), bdaddr);
len = do_command(dd, 0xff, 0x0022, cmd, 8, buf, sizeof(buf));
if (len < 0)
return -1;
len = do_command(dd, 0x03, 0x0003, NULL, 0, buf, sizeof(buf));
if (len < 0)
return -1;
return 0;
}

View File

@@ -0,0 +1,533 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2007-2008 Texas Instruments, Inc.
* Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "hciattach.h"
#ifdef HCIATTACH_DEBUG
#define DPRINTF(x...) printf(x)
#else
#define DPRINTF(x...)
#endif
#define HCIUARTGETDEVICE _IOR('U', 202, int)
#define MAKEWORD(a, b) ((uint16_t)(((uint8_t)(a)) | ((uint16_t)((uint8_t)(b))) << 8))
#define TI_MANUFACTURER_ID 13
#define FIRMWARE_DIRECTORY "/lib/firmware/ti-connectivity/"
#define ACTION_SEND_COMMAND 1
#define ACTION_WAIT_EVENT 2
#define ACTION_SERIAL 3
#define ACTION_DELAY 4
#define ACTION_RUN_SCRIPT 5
#define ACTION_REMARKS 6
#define BRF_DEEP_SLEEP_OPCODE_BYTE_1 0x0c
#define BRF_DEEP_SLEEP_OPCODE_BYTE_2 0xfd
#define BRF_DEEP_SLEEP_OPCODE \
(BRF_DEEP_SLEEP_OPCODE_BYTE_1 | (BRF_DEEP_SLEEP_OPCODE_BYTE_2 << 8))
#define FILE_HEADER_MAGIC 0x42535442
/*
* BRF Firmware header
*/
struct bts_header {
uint32_t magic;
uint32_t version;
uint8_t future[24];
uint8_t actions[0];
}__attribute__ ((packed));
/*
* BRF Actions structure
*/
struct bts_action {
uint16_t type;
uint16_t size;
uint8_t data[0];
} __attribute__ ((packed));
struct bts_action_send {
uint8_t data[0];
} __attribute__ ((packed));
struct bts_action_wait {
uint32_t msec;
uint32_t size;
uint8_t data[0];
}__attribute__ ((packed));
struct bts_action_delay {
uint32_t msec;
}__attribute__ ((packed));
struct bts_action_serial {
uint32_t baud;
uint32_t flow_control;
}__attribute__ ((packed));
static FILE *bts_load_script(const char *file_name, uint32_t *version)
{
struct bts_header header;
FILE *fp;
fp = fopen(file_name, "rb");
if (!fp) {
perror("can't open firmware file");
return NULL;
}
if (1 != fread(&header, sizeof(struct bts_header), 1, fp)) {
perror("can't read firmware file");
goto errclose;
}
if (header.magic != FILE_HEADER_MAGIC) {
fprintf(stderr, "%s not a legal TI firmware file\n", file_name);
goto errclose;
}
if (NULL != version)
*version = header.version;
return fp;
errclose:
fclose(fp);
return NULL;
}
static unsigned long bts_fetch_action(FILE *fp, unsigned char *action_buf,
unsigned long buf_size, uint16_t *action_type)
{
struct bts_action action_hdr;
unsigned long nread;
if (!fp)
return 0;
if (1 != fread(&action_hdr, sizeof(struct bts_action), 1, fp))
return 0;
if (action_hdr.size > buf_size) {
fprintf(stderr, "bts_next_action: not enough space to read next action\n");
return 0;
}
nread = fread(action_buf, sizeof(uint8_t), action_hdr.size, fp);
if (nread != (action_hdr.size)) {
fprintf(stderr, "bts_next_action: fread failed to read next action\n");
return 0;
}
*action_type = action_hdr.type;
return nread * sizeof(uint8_t);
}
static void bts_unload_script(FILE *fp)
{
if (fp)
fclose(fp);
}
static int is_it_texas(const uint8_t *respond)
{
uint16_t manufacturer_id;
manufacturer_id = MAKEWORD(respond[11], respond[12]);
return TI_MANUFACTURER_ID == manufacturer_id ? 1 : 0;
}
static const char *get_firmware_name(const uint8_t *respond)
{
static char firmware_file_name[PATH_MAX] = {0};
uint16_t version = 0, chip = 0, min_ver = 0, maj_ver = 0;
version = MAKEWORD(respond[13], respond[14]);
chip = (version & 0x7C00) >> 10;
min_ver = (version & 0x007F);
maj_ver = (version & 0x0380) >> 7;
if (version & 0x8000)
maj_ver |= 0x0008;
sprintf(firmware_file_name, FIRMWARE_DIRECTORY "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
return firmware_file_name;
}
static void brf_delay(struct bts_action_delay *delay)
{
usleep(1000 * delay->msec);
}
static int brf_set_serial_params(struct bts_action_serial *serial_action,
int fd, int *speed, struct termios *ti)
{
fprintf(stderr, "texas: changing baud rate to %u, flow control to %u\n",
serial_action->baud, serial_action->flow_control );
tcflush(fd, TCIOFLUSH);
if (serial_action->flow_control)
ti->c_cflag |= CRTSCTS;
else
ti->c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, ti) < 0) {
perror("Can't set port settings");
return -1;
}
tcflush(fd, TCIOFLUSH);
if (set_speed(fd, ti, serial_action->baud) < 0) {
perror("Can't set baud rate");
return -1;
}
if (speed)
*speed = serial_action->baud;
return 0;
}
static int brf_send_command_socket(int fd, struct bts_action_send *send_action)
{
char response[1024] = {0};
hci_command_hdr *cmd = (hci_command_hdr *) send_action->data;
uint16_t opcode = cmd->opcode;
struct hci_request rq;
memset(&rq, 0, sizeof(rq));
rq.ogf = cmd_opcode_ogf(opcode);
rq.ocf = cmd_opcode_ocf(opcode);
rq.event = EVT_CMD_COMPLETE;
rq.cparam = &send_action->data[3];
rq.clen = send_action->data[2];
rq.rparam = response;
rq.rlen = sizeof(response);
if (hci_send_req(fd, &rq, 15) < 0) {
perror("Cannot send hci command to socket");
return -1;
}
/* verify success */
if (response[0]) {
errno = EIO;
return -1;
}
return 0;
}
static int brf_send_command_file(int fd, struct bts_action_send *send_action,
long size)
{
unsigned char response[1024] = {0};
long ret = 0;
/* send command */
if (size != write(fd, send_action, size)) {
perror("Texas: Failed to write action command");
return -1;
}
/* read response */
ret = read_hci_event(fd, response, sizeof(response));
if (ret < 0) {
perror("texas: failed to read command response");
return -1;
}
/* verify success */
if (ret < 7 || 0 != response[6]) {
fprintf( stderr, "TI init command failed.\n" );
errno = EIO;
return -1;
}
return 0;
}
static int brf_send_command(int fd, struct bts_action_send *send_action,
long size, int hcill_installed)
{
int ret = 0;
char *fixed_action;
/* remove packet type when giving to socket API */
if (hcill_installed) {
fixed_action = ((char *) send_action) + 1;
ret = brf_send_command_socket(fd, (struct bts_action_send *) fixed_action);
} else {
ret = brf_send_command_file(fd, send_action, size);
}
return ret;
}
static int brf_do_action(uint16_t brf_type, uint8_t *brf_action, long brf_size,
int fd, int *speed, struct termios *ti, int hcill_installed)
{
int ret = 0;
switch (brf_type) {
case ACTION_SEND_COMMAND:
DPRINTF("W");
ret = brf_send_command(fd,
(struct bts_action_send *) brf_action,
brf_size, hcill_installed);
break;
case ACTION_WAIT_EVENT:
DPRINTF("R");
break;
case ACTION_SERIAL:
DPRINTF("S");
ret = brf_set_serial_params((struct bts_action_serial *) brf_action, fd, speed, ti);
break;
case ACTION_DELAY:
DPRINTF("D");
brf_delay((struct bts_action_delay *) brf_action);
break;
case ACTION_REMARKS:
DPRINTF("C");
break;
default:
fprintf(stderr, "brf_init: unknown firmware action type (%d)\n", brf_type);
break;
}
return ret;
}
/*
* tests whether a given brf action is a HCI_VS_Sleep_Mode_Configurations cmd
*/
static int brf_action_is_deep_sleep(uint8_t *brf_action, long brf_size,
uint16_t brf_type)
{
uint16_t opcode;
if (brf_type != ACTION_SEND_COMMAND)
return 0;
if (brf_size < 3)
return 0;
if (brf_action[0] != HCI_COMMAND_PKT)
return 0;
/* HCI data is little endian */
opcode = brf_action[1] | (brf_action[2] << 8);
if (opcode != BRF_DEEP_SLEEP_OPCODE)
return 0;
/* action is deep sleep configuration command ! */
return 1;
}
/*
* This function is called twice.
* The first time it is called, it loads the brf script, and executes its
* commands until it reaches a deep sleep command (or its end).
* The second time it is called, it assumes HCILL protocol is set up,
* and sends rest of brf script via the supplied socket.
*/
static int brf_do_script(int fd, int *speed, struct termios *ti, const char *bts_file)
{
int ret = 0, hcill_installed = bts_file ? 0 : 1;
uint32_t vers;
static FILE *brf_script_file = NULL;
static uint8_t brf_action[512];
static long brf_size;
static uint16_t brf_type;
/* is it the first time we are called ? */
if (0 == hcill_installed) {
DPRINTF("Sending script to serial device\n");
brf_script_file = bts_load_script(bts_file, &vers );
if (!brf_script_file) {
fprintf(stderr, "Warning: cannot find BTS file: %s\n",
bts_file);
return 0;
}
fprintf( stderr, "Loaded BTS script version %u\n", vers );
brf_size = bts_fetch_action(brf_script_file, brf_action,
sizeof(brf_action), &brf_type);
if (brf_size == 0) {
fprintf(stderr, "Warning: BTS file is empty !");
return 0;
}
}
else {
DPRINTF("Sending script to bluetooth socket\n");
}
/* execute current action and continue to parse brf script file */
while (brf_size != 0) {
ret = brf_do_action(brf_type, brf_action, brf_size,
fd, speed, ti, hcill_installed);
if (ret == -1)
break;
brf_size = bts_fetch_action(brf_script_file, brf_action,
sizeof(brf_action), &brf_type);
/* if this is the first time we run (no HCILL yet) */
/* and a deep sleep command is encountered */
/* we exit */
if (!hcill_installed &&
brf_action_is_deep_sleep(brf_action,
brf_size, brf_type))
return 0;
}
bts_unload_script(brf_script_file);
brf_script_file = NULL;
DPRINTF("\n");
return ret;
}
int texas_init(int fd, int *speed, struct termios *ti)
{
struct timespec tm = {0, 50000};
char cmd[4];
unsigned char resp[100]; /* Response */
const char *bts_file;
int n;
memset(resp,'\0', 100);
/* It is possible to get software version with manufacturer specific
HCI command HCI_VS_TI_Version_Number. But the only thing you get more
is if this is point-to-point or point-to-multipoint module */
/* Get Manufacturer and LMP version */
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x01;
cmd[2] = 0x10;
cmd[3] = 0x00;
do {
n = write(fd, cmd, 4);
if (n < 0) {
perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)");
return -1;
}
if (n < 4) {
fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
return -1;
}
/* Read reply. */
if (read_hci_event(fd, resp, 100) < 0) {
perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)");
return -1;
}
/* Wait for command complete event for our Opcode */
} while (resp[4] != cmd[1] && resp[5] != cmd[2]);
/* Verify manufacturer */
if (! is_it_texas(resp)) {
fprintf(stderr,"ERROR: module's manufacturer is not Texas Instruments\n");
return -1;
}
fprintf(stderr, "Found a Texas Instruments' chip!\n");
bts_file = get_firmware_name(resp);
fprintf(stderr, "Firmware file : %s\n", bts_file);
n = brf_do_script(fd, speed, ti, bts_file);
nanosleep(&tm, NULL);
return n;
}
int texas_post(int fd, struct termios *ti)
{
int dev_id, dd, ret = 0;
sleep(1);
dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
if (dev_id < 0) {
perror("cannot get device id");
return -1;
}
DPRINTF("\nAdded device hci%d\n", dev_id);
dd = hci_open_dev(dev_id);
if (dd < 0) {
perror("HCI device open failed");
return -1;
}
if (ioctl(dd, HCIDEVUP, dev_id) < 0 && errno != EALREADY) {
fprintf(stderr, "Can't init device hci%d: %s (%d)", dev_id,
strerror(errno), errno);
hci_close_dev(dd);
return -1;
}
ret = brf_do_script(dd, NULL, ti, NULL);
hci_close_dev(dd);
return ret;
}

View File

@@ -0,0 +1,242 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2005-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <termios.h>
#include <time.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "hciattach.h"
#define FAILIF(x, args...) do { \
if (x) { \
fprintf(stderr, ##args); \
return -1; \
} \
} while(0)
typedef struct {
uint8_t uart_prefix;
hci_event_hdr hci_hdr;
evt_cmd_complete cmd_complete;
uint8_t status;
uint8_t data[16];
} __attribute__((packed)) command_complete_t;
static int read_command_complete(int fd, unsigned short opcode, unsigned char len) {
command_complete_t resp;
/* Read reply. */
FAILIF(read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0,
"Failed to read response");
/* Parse speed-change reply */
FAILIF(resp.uart_prefix != HCI_EVENT_PKT,
"Error in response: not an event packet, but 0x%02x!\n",
resp.uart_prefix);
FAILIF(resp.hci_hdr.evt != EVT_CMD_COMPLETE, /* event must be event-complete */
"Error in response: not a cmd-complete event, "
"but 0x%02x!\n", resp.hci_hdr.evt);
FAILIF(resp.hci_hdr.plen < 4, /* plen >= 4 for EVT_CMD_COMPLETE */
"Error in response: plen is not >= 4, but 0x%02x!\n",
resp.hci_hdr.plen);
/* cmd-complete event: opcode */
FAILIF(resp.cmd_complete.opcode != (uint16_t)opcode,
"Error in response: opcode is 0x%04x, not 0x%04x!",
resp.cmd_complete.opcode, opcode);
return resp.status == 0 ? 0 : -1;
}
typedef struct {
uint8_t uart_prefix;
hci_command_hdr hci_hdr;
uint32_t speed;
} __attribute__((packed)) texas_speed_change_cmd_t;
static int texas_change_speed(int fd, uint32_t speed)
{
return 0;
}
static int texas_load_firmware(int fd, const char *firmware) {
int fw = open(firmware, O_RDONLY);
fprintf(stdout, "Opening firmware file: %s\n", firmware);
FAILIF(fw < 0,
"Could not open firmware file %s: %s (%d).\n",
firmware, strerror(errno), errno);
fprintf(stdout, "Uploading firmware...\n");
do {
/* Read each command and wait for a response. */
unsigned char data[1024];
unsigned char cmdp[1 + sizeof(hci_command_hdr)];
hci_command_hdr *cmd = (hci_command_hdr *)(cmdp + 1);
int nr;
nr = read(fw, cmdp, sizeof(cmdp));
if (!nr)
break;
FAILIF(nr != sizeof(cmdp), "Could not read H4 + HCI header!\n");
FAILIF(*cmdp != HCI_COMMAND_PKT, "Command is not an H4 command packet!\n");
FAILIF(read(fw, data, cmd->plen) != cmd->plen,
"Could not read %d bytes of data for command with opcode %04x!\n",
cmd->plen,
cmd->opcode);
{
int nw;
#if 0
fprintf(stdout, "\topcode 0x%04x (%d bytes of data).\n",
cmd->opcode,
cmd->plen);
#endif
struct iovec iov_cmd[2];
iov_cmd[0].iov_base = cmdp;
iov_cmd[0].iov_len = sizeof(cmdp);
iov_cmd[1].iov_base = data;
iov_cmd[1].iov_len = cmd->plen;
nw = writev(fd, iov_cmd, 2);
FAILIF(nw != (int) sizeof(cmd) + cmd->plen,
"Could not send entire command (sent only %d bytes)!\n",
nw);
}
/* Wait for response */
if (read_command_complete(fd,
cmd->opcode,
cmd->plen) < 0) {
return -1;
}
} while(1);
fprintf(stdout, "Firmware upload successful.\n");
close(fw);
return 0;
}
int texasalt_init(int fd, int speed, struct termios *ti)
{
struct timespec tm = {0, 50000};
char cmd[4];
unsigned char resp[100]; /* Response */
int n;
memset(resp,'\0', 100);
/* It is possible to get software version with manufacturer specific
HCI command HCI_VS_TI_Version_Number. But the only thing you get more
is if this is point-to-point or point-to-multipoint module */
/* Get Manufacturer and LMP version */
cmd[0] = HCI_COMMAND_PKT;
cmd[1] = 0x01;
cmd[2] = 0x10;
cmd[3] = 0x00;
do {
n = write(fd, cmd, 4);
if (n < 0) {
perror("Failed to write init command (READ_LOCAL_VERSION_INFORMATION)");
return -1;
}
if (n < 4) {
fprintf(stderr, "Wanted to write 4 bytes, could only write %d. Stop\n", n);
return -1;
}
/* Read reply. */
if (read_hci_event(fd, resp, 100) < 0) {
perror("Failed to read init response (READ_LOCAL_VERSION_INFORMATION)");
return -1;
}
/* Wait for command complete event for our Opcode */
} while (resp[4] != cmd[1] && resp[5] != cmd[2]);
/* Verify manufacturer */
if ((resp[11] & 0xFF) != 0x0d)
fprintf(stderr,"WARNING : module's manufacturer is not Texas Instrument\n");
/* Print LMP version */
fprintf(stderr, "Texas module LMP version : 0x%02x\n", resp[10] & 0xFF);
/* Print LMP subversion */
{
unsigned short lmp_subv = resp[13] | (resp[14] << 8);
unsigned short brf_chip = (lmp_subv & 0x7c00) >> 10;
static const char *c_brf_chip[8] = {
"unknown",
"unknown",
"brf6100",
"brf6150",
"brf6300",
"brf6350",
"unknown",
"wl1271"
};
char fw[100];
fprintf(stderr, "Texas module LMP sub-version : 0x%04x\n", lmp_subv);
fprintf(stderr,
"\tinternal version freeze: %d\n"
"\tsoftware version: %d\n"
"\tchip: %s (%d)\n",
lmp_subv & 0x7f,
((lmp_subv & 0x8000) >> (15-3)) | ((lmp_subv & 0x380) >> 7),
((brf_chip > 7) ? "unknown" : c_brf_chip[brf_chip]),
brf_chip);
sprintf(fw, "/etc/firmware/%s.bin", c_brf_chip[brf_chip]);
texas_load_firmware(fd, fw);
texas_change_speed(fd, speed);
}
nanosleep(&tm, NULL);
return 0;
}

View File

@@ -0,0 +1,557 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <signal.h>
#include <time.h>
#include <stdint.h>
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <limits.h>
#include "hciattach.h"
/******************************************************************************
** Constants & Macros
******************************************************************************/
#define LOG_STR "XRADIO Bluetooth"
#define DBG_ON 1
#define XR_DBG(fmt, arg...) \
do { \
if (DBG_ON) \
fprintf(stderr, "%s: " fmt "\n" , LOG_STR, ##arg); \
} while(0)
#define XR_ERR(fmt, arg...) \
do { \
fprintf(stderr, "%s ERROR: " fmt "\n", LOG_STR, ##arg);\
perror(LOG_STR" ERROR reason"); \
} while(0)
#define XR_DUMP(buffer, len) \
fprintf(stderr, "%s: ", LOG_STR); \
do { \
for (int i = 0; i < len; i++) { \
if (i && !(i % 16)) { \
fprintf(stderr, "\n"); \
fprintf(stderr, "%s: ", LOG_STR); \
} \
fprintf(stderr, "%02x ", buffer[i]); \
} \
fprintf(stderr, "\n"); \
} while (0)
#define BT_FW_PATH_NAME "/system/vendor/etc/firmware/fw_xr829_bt.bin"
#define BT_FW_LOAD_ADDR 0x0000
#define BT_FW_JUMP_ADDR 0x0000
#define AW1722 1
#define AW1732 2
#define CHIP_NAME AW1722
#define SZ_1K (0x00000400U )
#define SZ_16K (0x00004000U )
#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 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
#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_SETPC CMD_ID(CMD_ID_SYSCTL, 3)
#define CMD_WRITEN 0
#define CMD_WRITESEQ 1
#define CMD_SETBAUD 2
#define CMD_SETPC 3
#define DATA_RAW 4
/******************************************************************************
** Type definitions
******************************************************************************/
/* vendor serial control block */
typedef struct
{
int fd; /* fd to Bluetooth device */
struct termios *ti; /* serial terminal of BT port */
} vnd_userial_cb_t;
#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 {
uint8_t magic[4]; // magic "BROM"
#define CMD_BROM_MAGIC "BROM"
uint8_t 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)
uint8_t version:4;
uint8_t reserved:4;
uint16_t checksum;
uint32_t payload_len;
} __attribute__((packed)) cmd_header_t;
#define MB_CMD_HEADER_SIZE (sizeof(cmd_header_t))
/* acknownledge structure */
typedef struct {
cmd_header_t h;
uint8_t err;
} __attribute__((packed)) cmd_ack_t;
/* sequence read/write command structure */
typedef struct {
cmd_header_t h;
uint8_t cmdid;
uint32_t addr;
uint32_t dlen;
uint16_t dcs;
} __attribute__((packed)) cmd_seq_wr_t;
/* io change command structure */
typedef struct {
cmd_header_t h;
uint8_t cmdid;
uint32_t val;
} __attribute__((packed)) cmd_sys_t;
typedef struct {
cmd_header_t h;
uint8_t cmdid;
uint32_t lcr;
} __attribute__((packed)) cmd_sys_setuart_t;
#pragma pack()
static const uint8_t hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };
static const uint8_t hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x04, 0x60, 0xE3, 0x16, 0x00};
static vnd_userial_cb_t vnd_userial;
static int32_t cmd_sync_uart(void);
static int32_t cmd_sync_baud(uint32_t lcr);
static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data);
static int32_t cmd_set_pc(uint32_t pc);
static void userial_set_hw_fctrl(uint8_t hw_fctrl);
static uint32_t userial_read(uint8_t *p_buffer, uint32_t len, uint32_t timeout);
static uint32_t userial_write(const uint8_t *p_data, uint32_t len);
/******************************************************************************
** Functions
******************************************************************************/
static uint16_t CheckSum16(uint8_t *data, uint32_t len)
{
uint16_t cs = 0;
uint16_t *p = (uint16_t *)data;
while(len > 1) {
cs += *p++;
len -= 2;
}
if (len) {
cs += *(uint8_t *)p;
}
return cs;
}
static uint64_t time_gettimeofday_us(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000000ULL + (uint64_t)tv.tv_usec;
}
static uint8_t *memsearch(uint8_t *haystack, uint32_t hlen, uint8_t *needle, uint32_t nlen)
{
while (hlen-- >= nlen) {
if (!memcmp(haystack, needle, nlen)) {
return haystack;
}
haystack++;
}
return NULL;
}
static int32_t xr_raw_write(int type, uint8_t *data, uint32_t len)
{
uint8_t buffer[MB_CMD_HEADER_SIZE + 13] = {'B', 'R', 'O', 'M', 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t *psend = data;
uint32_t lsend = len;
cmd_header_t *hdr = (cmd_header_t *)buffer;;
cmd_ack_t *ack = (cmd_ack_t *)buffer;
if (type != DATA_RAW) {
psend = buffer;
lsend = MB_CMD_HEADER_SIZE + len;
memcpy(buffer + MB_CMD_HEADER_SIZE, data, len);
hdr->payload_len = len;
#if ENABLE_DCS
hdr->flags = CMD_HFLAG_CHECK;
#endif
hdr->checksum = ~CheckSum16(buffer, MB_CMD_HEADER_SIZE + len);
hdr->payload_len = SWAP32(hdr->payload_len);
hdr->checksum = SWAP16(hdr->checksum);
switch (type) {
case CMD_WRITESEQ:
{
cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer;
cmd->addr = SWAP32(cmd->addr);
cmd->dlen = SWAP32(cmd->dlen);
cmd->dcs = SWAP16(cmd->dcs);
}
break;
case CMD_SETBAUD:
{
cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer;
cmd->lcr = SWAP32(cmd->lcr);
}
break;
case CMD_SETPC:
{
cmd_sys_t *cmd = (cmd_sys_t*)buffer;
cmd->val = SWAP32(cmd->val);
}
break;
default:
XR_ERR("%s: Unsupport type %d", __func__, type);
return -1;
}
}
ssize_t ret_w, ret_r;
uint64_t t0, t1, t2, t3;
tcflush(vnd_userial.fd, TCIOFLUSH);
t0 = time_gettimeofday_us();
ret_w = userial_write(psend, lsend);
t1 = time_gettimeofday_us();
memset(buffer, 0, MB_CMD_HEADER_SIZE + 1);
t2 = time_gettimeofday_us();
ret_r = userial_read(buffer, MB_CMD_HEADER_SIZE, 100000);
t3 = time_gettimeofday_us();
XR_DBG("%s, type: %d, write len: %5d, ret: %5d, time: %6lluus, read len: %2d, ret: %2d, %6lluus",
__func__, type, lsend, ret_w, t1 - t0, MB_CMD_HEADER_SIZE, ret_r, t3 - t2);
uint8_t *p = (uint8_t *)memsearch(buffer, MB_CMD_HEADER_SIZE, (uint8_t *)"BROM", 4);
if (p != buffer) {
if (p == NULL) {
XR_ERR("%s: invalid response", __func__);
return -1;
}
uint32_t nowread = buffer + MB_CMD_HEADER_SIZE - p;
uint32_t needread = p - buffer;
XR_DBG("%s: Index error, re-find header magic", __func__);
memcpy(buffer, p, nowread);
memset(buffer + nowread, 0x0, needread);
userial_read(buffer + nowread, needread, 100000);
}
/* check response */
if (ack->h.flags & CMD_HFLAG_ERROR) {
userial_read(buffer + MB_CMD_HEADER_SIZE, 1, 100000);
XR_ERR("%s: resp error flag, type %d", __func__, ack->err);
return -ack->err;
}
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) {
XR_ERR("%s: data payload len %d != 0", __func__, ack->h.payload_len);
return -1;
}
}
if (ack->h.flags & CMD_HFLAG_CHECK) {
if (CheckSum16(buffer, MB_CMD_HEADER_SIZE) != 0xffff) {
XR_ERR("%s: write data response 0 checksum error", __func__);
return -1;
}
}
return 0;
}
static int32_t cmd_sync_uart(void)
{
uint8_t sync = 0x55;
uint8_t ack[3] = {0};
ssize_t ret = -1;
uint32_t cnt = 0;
do {
XR_DBG("uart sync count:%d.", cnt);
tcflush(vnd_userial.fd, TCIOFLUSH);
userial_write(&sync, 1);
ret = userial_read(ack, 2, 2000);
if (ret == 2 && ((ack[0] == 'O' && ack[1] == 'K') || (ack[0] == 'K' && ack[1] == 'O'))) {
XR_DBG("Receive %s, uart Sync done.", ack);
return 0;
}
} while (cnt++ < 50);
XR_DBG("uart sync fail.");
return -1;
}
static int32_t cmd_sync_baud(uint32_t lcr)
{
uint8_t buffer[MB_CMD_HEADER_SIZE + 5];
cmd_sys_setuart_t *cmd = (cmd_sys_setuart_t*)buffer;
cmd->cmdid = CMD_ID_SETUART;
cmd->lcr = lcr;
uint8_t cnt = 0;
int ret = -1;
do {
XR_DBG("%s count:%d.", __func__, cnt);
ret = xr_raw_write(CMD_SETBAUD, buffer + MB_CMD_HEADER_SIZE, 5);
if (ret == 0) {
set_speed(vnd_userial.fd, vnd_userial.ti, lcr & 0xffffff);
return cmd_sync_uart();
}
} while (cnt++ < 3);
XR_DBG("cmd_sync_baud fail.");
return -1;
}
static int32_t cmd_write_seq(uint32_t addr, uint32_t len, uint8_t *data)
{
int ret = -1;
uint8_t buffer[MB_CMD_HEADER_SIZE + 13];
cmd_seq_wr_t *cmd = (cmd_seq_wr_t *)buffer;
cmd->cmdid = CMD_ID_SEQWR;
cmd->addr = addr;
cmd->dlen = len;
#if ENABLE_DCS
cmd->dcs = ~CheckSum16(data, len);
#endif
ret = xr_raw_write(CMD_WRITESEQ, buffer + MB_CMD_HEADER_SIZE, 11);
if (ret == 0) {
return xr_raw_write(DATA_RAW, data, len);
}
return ret;
}
static int32_t cmd_set_pc(uint32_t pc)
{
uint8_t buffer[MB_CMD_HEADER_SIZE + 5];
cmd_sys_t *cmd = (cmd_sys_t*)buffer;
cmd->cmdid = CMD_ID_SETPC;
cmd->val = pc;
XR_DBG("set pc %x, val %x", pc, cmd->val);
return xr_raw_write(CMD_SETPC, buffer + MB_CMD_HEADER_SIZE, 5);
}
static void userial_set_hw_fctrl(uint8_t hw_fctrl)
{
if (vnd_userial.fd == -1) {
XR_ERR("vnd_userial.fd is -1");
return;
}
if (hw_fctrl) {
XR_DBG("Set HW FlowControl On");
vnd_userial.ti->c_cflag |= CRTSCTS;
} else {
XR_DBG("Set HW FlowControl Off");
vnd_userial.ti->c_cflag &= ~CRTSCTS;
}
tcsetattr(vnd_userial.fd, TCSANOW, vnd_userial.ti);
tcflush(vnd_userial.fd, TCIOFLUSH);
}
static uint32_t userial_read(uint8_t *buffer, uint32_t len, uint32_t timeout)
{
fd_set set;
struct timeval tv;
int rv;
FD_ZERO(&set); /* clear the set */
FD_SET(vnd_userial.fd, &set); /* add our file descriptor to the set */
/* there was data to read */
ssize_t r;
uint8_t *pos = (uint8_t*)buffer;
while (len > 0) {
tv.tv_sec = 0;
tv.tv_usec = timeout;
rv = select(vnd_userial.fd + 1, &set, NULL, NULL, &tv);
if(rv == -1) {
XR_ERR("select error"); /* an error accured */
break;
} else if(rv == 0) {
XR_ERR("read timeout"); /* a timeout occured */
break;
}
r = read(vnd_userial.fd, pos, len);
if (r < 1)
break;
len -= r;
pos += r;
}
return pos - buffer;
}
static uint32_t userial_write(const uint8_t *buffer, uint32_t len)
{
ssize_t r;
uint8_t *pos = (uint8_t*)buffer;
while (len > 0) {
r = write(vnd_userial.fd, pos, len);
if (r < 1)
break;
len -= r;
pos += r;
}
return pos - buffer;
}
static int32_t load_btfirmware(void)
{
FILE *fwfile_fd = NULL;
uint32_t len;
uint8_t *data = NULL;
uint32_t addr = BT_FW_LOAD_ADDR;
uint32_t section = SZ_16K;
fwfile_fd = fopen(BT_FW_PATH_NAME, "rb");
XR_DBG("BT firmware: %s", BT_FW_PATH_NAME);
if(!fwfile_fd) {
XR_ERR("Unable to open BT firmware %s", BT_FW_PATH_NAME);
return -1;
}
data = (uint8_t*)malloc(section);
if (data == NULL) {
XR_DBG("failed to alloc %d byte memory.", section);
fclose(fwfile_fd);
return -1;
}
XR_DBG("load bt firmware starting.");
while ((len = fread(data, 1, section, fwfile_fd)) > 0) {
cmd_write_seq(addr, len, data);
addr += len;
}
free(data);
fclose(fwfile_fd);
XR_DBG("load firmware done.");
XR_DBG("Firmware run from address 0x%08X", BT_FW_JUMP_ADDR);
cmd_set_pc(BT_FW_JUMP_ADDR);
if (CHIP_NAME == AW1732) {
XR_DBG("second time sync starting....");
if (cmd_sync_uart() < 0)
return -1;
cmd_set_pc(BT_FW_JUMP_ADDR);
}
return addr;
}
static int hci_cmd_handle(const uint8_t *cmd, uint32_t cmd_len, uint32_t event_len)
{
uint8_t buffer[256];
XR_DBG("send hci command");
userial_write(cmd, cmd_len);
XR_DUMP(cmd, cmd_len);
if (read_hci_event(vnd_userial.fd, buffer, event_len) != event_len) {
XR_ERR("Event read error");
return -1;
}
XR_DBG("Received event");
XR_DUMP(buffer, event_len);
return 0;
}
int xr_init(int fd, struct uart_t *u, struct termios *ti)
{
vnd_userial.fd = fd;
vnd_userial.ti = ti;
XR_DBG("uart sync starting....");
if (cmd_sync_uart() < 0)
goto END;
XR_DBG("set bandrate to %d.", u->speed);
if (cmd_sync_baud(((u->speed) | (3<<24))) < 0)
goto END;
if (load_btfirmware() < 0)
goto END;
XR_DBG("bt firmware is running....");
XR_DBG("set baudrate to %d", u->init_speed);
set_speed(vnd_userial.fd, vnd_userial.ti, u->init_speed);
userial_set_hw_fctrl(1);
usleep(50000);
XR_DBG("process hci reset...");
if (hci_cmd_handle(hci_reset, sizeof(hci_reset), 7) < 0)
goto END;
XR_DBG("process hci update baud...");
if (hci_cmd_handle(hci_update_baud_rate, sizeof(hci_update_baud_rate), 7) < 0)
goto END;
usleep(100000);
return 0;
END:
XR_DBG("device fd = %d close", fd);
close(vnd_userial.fd);
vnd_userial.fd = -1;
vnd_userial.ti = NULL;
return -1;
}
int xr_post(int fd, struct uart_t *u, struct termios *ti)
{
XR_DBG("Done setting line discpline");
return 0;
}

File diff suppressed because it is too large Load Diff

3122
external/cache/sources/hcitools/hcitool.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,149 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2012 Intel Corporation. All rights reserved.
* Copyright (c) 2012 Code Aurora Forum. 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
*
*/
#ifndef __A2MP_H
#define __A2MP_H
#ifdef __cplusplus
extern "C" {
#endif
/* A2MP Protocol */
/* A2MP command codes */
#define A2MP_COMMAND_REJ 0x01
#define A2MP_DISCOVER_REQ 0x02
#define A2MP_DISCOVER_RSP 0x03
#define A2MP_CHANGE_NOTIFY 0x04
#define A2MP_CHANGE_RSP 0x05
#define A2MP_INFO_REQ 0x06
#define A2MP_INFO_RSP 0x07
#define A2MP_ASSOC_REQ 0x08
#define A2MP_ASSOC_RSP 0x09
#define A2MP_CREATE_REQ 0x0a
#define A2MP_CREATE_RSP 0x0b
#define A2MP_DISCONN_REQ 0x0c
#define A2MP_DISCONN_RSP 0x0d
struct a2mp_hdr {
uint8_t code;
uint8_t ident;
uint16_t len;
} __attribute__ ((packed));
#define A2MP_HDR_SIZE 4
struct a2mp_command_rej {
uint16_t reason;
} __attribute__ ((packed));
struct a2mp_discover_req {
uint16_t mtu;
uint16_t mask;
} __attribute__ ((packed));
struct a2mp_ctrl {
uint8_t id;
uint8_t type;
uint8_t status;
} __attribute__ ((packed));
struct a2mp_discover_rsp {
uint16_t mtu;
uint16_t mask;
struct a2mp_ctrl ctrl_list[0];
} __attribute__ ((packed));
struct a2mp_info_req {
uint8_t id;
} __attribute__ ((packed));
struct a2mp_info_rsp {
uint8_t id;
uint8_t status;
uint32_t total_bw;
uint32_t max_bw;
uint32_t min_latency;
uint16_t pal_caps;
uint16_t assoc_size;
} __attribute__ ((packed));
struct a2mp_assoc_req {
uint8_t id;
} __attribute__ ((packed));
struct a2mp_assoc_rsp {
uint8_t id;
uint8_t status;
uint8_t assoc_data[0];
} __attribute__ ((packed));
struct a2mp_create_req {
uint8_t local_id;
uint8_t remote_id;
uint8_t assoc_data[0];
} __attribute__ ((packed));
struct a2mp_create_rsp {
uint8_t local_id;
uint8_t remote_id;
uint8_t status;
} __attribute__ ((packed));
struct a2mp_disconn_req {
uint8_t local_id;
uint8_t remote_id;
} __attribute__ ((packed));
struct a2mp_disconn_rsp {
uint8_t local_id;
uint8_t remote_id;
uint8_t status;
} __attribute__ ((packed));
#define A2MP_COMMAND_NOT_RECOGNIZED 0x0000
/* AMP controller status */
#define AMP_CTRL_POWERED_DOWN 0x00
#define AMP_CTRL_BLUETOOTH_ONLY 0x01
#define AMP_CTRL_NO_CAPACITY 0x02
#define AMP_CTRL_LOW_CAPACITY 0x03
#define AMP_CTRL_MEDIUM_CAPACITY 0x04
#define AMP_CTRL_HIGH_CAPACITY 0x05
#define AMP_CTRL_FULL_CAPACITY 0x06
/* A2MP response status */
#define A2MP_STATUS_SUCCESS 0x00
#define A2MP_STATUS_INVALID_CTRL_ID 0x01
#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
#define A2MP_STATUS_COLLISION_OCCURED 0x03
#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04
#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
#ifdef __cplusplus
}
#endif
#endif /* __A2MP_H */

View File

@@ -0,0 +1,172 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2010-2011 Code Aurora Forum. All rights reserved.
* Copyright (C) 2012 Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#ifndef __AMP_H
#define __AMP_H
#ifdef __cplusplus
extern "C" {
#endif
#define AMP_MGR_CID 0x03
/* AMP manager codes */
#define AMP_COMMAND_REJ 0x01
#define AMP_DISCOVER_REQ 0x02
#define AMP_DISCOVER_RSP 0x03
#define AMP_CHANGE_NOTIFY 0x04
#define AMP_CHANGE_RSP 0x05
#define AMP_INFO_REQ 0x06
#define AMP_INFO_RSP 0x07
#define AMP_ASSOC_REQ 0x08
#define AMP_ASSOC_RSP 0x09
#define AMP_LINK_REQ 0x0a
#define AMP_LINK_RSP 0x0b
#define AMP_DISCONN_REQ 0x0c
#define AMP_DISCONN_RSP 0x0d
typedef struct {
uint8_t code;
uint8_t ident;
uint16_t len;
} __attribute__ ((packed)) amp_mgr_hdr;
#define AMP_MGR_HDR_SIZE 4
/* AMP ASSOC structure */
typedef struct {
uint8_t type_id;
uint16_t len;
uint8_t data[0];
} __attribute__ ((packed)) amp_assoc_tlv;
typedef struct {
uint16_t reason;
} __attribute__ ((packed)) amp_cmd_rej_parms;
typedef struct {
uint16_t mtu;
uint16_t mask;
} __attribute__ ((packed)) amp_discover_req_parms;
typedef struct {
uint16_t mtu;
uint16_t mask;
uint8_t controller_list[0];
} __attribute__ ((packed)) amp_discover_rsp_parms;
typedef struct {
uint8_t id;
} __attribute__ ((packed)) amp_info_req_parms;
typedef struct {
uint8_t id;
uint8_t status;
uint32_t total_bandwidth;
uint32_t max_bandwidth;
uint32_t min_latency;
uint16_t pal_caps;
uint16_t assoc_size;
} __attribute__ ((packed)) amp_info_rsp_parms;
typedef struct {
uint8_t id;
uint8_t status;
amp_assoc_tlv assoc;
} __attribute__ ((packed)) amp_assoc_rsp_parms;
typedef struct {
uint8_t local_id;
uint8_t remote_id;
amp_assoc_tlv assoc;
} __attribute__ ((packed)) amp_link_req_parms;
typedef struct {
uint8_t local_id;
uint8_t remote_id;
uint8_t status;
} __attribute__ ((packed)) amp_link_rsp_parms;
typedef struct {
uint8_t local_id;
uint8_t remote_id;
} __attribute__ ((packed)) amp_disconn_req_parms;
#define A2MP_MAC_ADDR_TYPE 1
#define A2MP_PREF_CHANLIST_TYPE 2
#define A2MP_CONNECTED_CHAN 3
#define A2MP_PAL_CAP_TYPE 4
#define A2MP_PAL_VER_INFO 5
struct amp_tlv {
uint8_t type;
uint16_t len;
uint8_t val[0];
} __attribute__ ((packed));
struct amp_pal_ver {
uint8_t ver;
uint16_t company_id;
uint16_t sub_ver;
} __attribute__ ((packed));
struct amp_country_triplet {
union {
struct {
uint8_t first_channel;
uint8_t num_channels;
int8_t max_power;
} __attribute__ ((packed)) chans;
struct {
uint8_t reg_extension_id;
uint8_t reg_class;
uint8_t coverage_class;
} __attribute__ ((packed)) ext;
};
} __attribute__ ((packed));
struct amp_chan_list {
uint8_t country_code[3];
struct amp_country_triplet triplets[0];
} __attribute__ ((packed));
#define AMP_COMMAND_NOT_RECOGNIZED 0x0000
/* AMP controller status */
#define AMP_CT_POWERED_DOWN 0x00
#define AMP_CT_BLUETOOTH_ONLY 0x01
#define AMP_CT_NO_CAPACITY 0x02
#define AMP_CT_LOW_CAPACITY 0x03
#define AMP_CT_MEDIUM_CAPACITY 0x04
#define AMP_CT_HIGH_CAPACITY 0x05
#define AMP_CT_FULL_CAPACITY 0x06
/* AMP response status */
#define AMP_STATUS_SUCCESS 0x00
#define AMP_STATUS_INVALID_CTRL_ID 0x01
#define AMP_STATUS_UNABLE_START_LINK_CREATION 0x02
#define AMP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
#define AMP_STATUS_COLLISION_OCCURED 0x03
#define AMP_STATUS_DISCONN_REQ_RECVD 0x04
#define AMP_STATUS_PHYS_LINK_EXISTS 0x05
#define AMP_STATUS_SECURITY_VIOLATION 0x06
#ifdef __cplusplus
}
#endif
#endif /* __AMP_H */

View File

@@ -0,0 +1,765 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include "bluetooth.h"
#include "hci.h"
void baswap(bdaddr_t *dst, const bdaddr_t *src)
{
register unsigned char *d = (unsigned char *) dst;
register const unsigned char *s = (const unsigned char *) src;
register int i;
for (i = 0; i < 6; i++)
d[i] = s[5-i];
}
char *batostr(const bdaddr_t *ba)
{
char *str = bt_malloc(18);
if (!str)
return NULL;
sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
ba->b[0], ba->b[1], ba->b[2],
ba->b[3], ba->b[4], ba->b[5]);
return str;
}
bdaddr_t *strtoba(const char *str)
{
bdaddr_t b;
bdaddr_t *ba = bt_malloc(sizeof(*ba));
if (ba) {
str2ba(str, &b);
baswap(ba, &b);
}
return ba;
}
int ba2str(const bdaddr_t *ba, char *str)
{
return sprintf(str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
ba->b[5], ba->b[4], ba->b[3], ba->b[2], ba->b[1], ba->b[0]);
}
int str2ba(const char *str, bdaddr_t *ba)
{
int i;
if (bachk(str) < 0) {
memset(ba, 0, sizeof(*ba));
return -1;
}
for (i = 5; i >= 0; i--, str += 3)
ba->b[i] = strtol(str, NULL, 16);
return 0;
}
int ba2oui(const bdaddr_t *ba, char *str)
{
return sprintf(str, "%2.2X-%2.2X-%2.2X", ba->b[5], ba->b[4], ba->b[3]);
}
int bachk(const char *str)
{
if (!str)
return -1;
if (strlen(str) != 17)
return -1;
while (*str) {
if (!isxdigit(*str++))
return -1;
if (!isxdigit(*str++))
return -1;
if (*str == 0)
break;
if (*str++ != ':')
return -1;
}
return 0;
}
int baprintf(const char *format, ...)
{
va_list ap;
int len;
va_start(ap, format);
len = vprintf(format, ap);
va_end(ap);
return len;
}
int bafprintf(FILE *stream, const char *format, ...)
{
va_list ap;
int len;
va_start(ap, format);
len = vfprintf(stream, format, ap);
va_end(ap);
return len;
}
int basprintf(char *str, const char *format, ...)
{
va_list ap;
int len;
va_start(ap, format);
len = vsnprintf(str, (~0U) >> 1, format, ap);
va_end(ap);
return len;
}
int basnprintf(char *str, size_t size, const char *format, ...)
{
va_list ap;
int len;
va_start(ap, format);
len = vsnprintf(str, size, format, ap);
va_end(ap);
return len;
}
void *bt_malloc(size_t size)
{
return malloc(size);
}
void bt_free(void *ptr)
{
free(ptr);
}
/* Bluetooth error codes to Unix errno mapping */
int bt_error(uint16_t code)
{
switch (code) {
case 0:
return 0;
case HCI_UNKNOWN_COMMAND:
return EBADRQC;
case HCI_NO_CONNECTION:
return ENOTCONN;
case HCI_HARDWARE_FAILURE:
return EIO;
case HCI_PAGE_TIMEOUT:
return EHOSTDOWN;
case HCI_AUTHENTICATION_FAILURE:
return EACCES;
case HCI_PIN_OR_KEY_MISSING:
return EINVAL;
case HCI_MEMORY_FULL:
return ENOMEM;
case HCI_CONNECTION_TIMEOUT:
return ETIMEDOUT;
case HCI_MAX_NUMBER_OF_CONNECTIONS:
case HCI_MAX_NUMBER_OF_SCO_CONNECTIONS:
return EMLINK;
case HCI_ACL_CONNECTION_EXISTS:
return EALREADY;
case HCI_COMMAND_DISALLOWED:
case HCI_TRANSACTION_COLLISION:
case HCI_ROLE_SWITCH_PENDING:
return EBUSY;
case HCI_REJECTED_LIMITED_RESOURCES:
case HCI_REJECTED_PERSONAL:
case HCI_QOS_REJECTED:
return ECONNREFUSED;
case HCI_HOST_TIMEOUT:
return ETIMEDOUT;
case HCI_UNSUPPORTED_FEATURE:
case HCI_QOS_NOT_SUPPORTED:
case HCI_PAIRING_NOT_SUPPORTED:
case HCI_CLASSIFICATION_NOT_SUPPORTED:
case HCI_UNSUPPORTED_LMP_PARAMETER_VALUE:
case HCI_PARAMETER_OUT_OF_RANGE:
case HCI_QOS_UNACCEPTABLE_PARAMETER:
return EOPNOTSUPP;
case HCI_INVALID_PARAMETERS:
case HCI_SLOT_VIOLATION:
return EINVAL;
case HCI_OE_USER_ENDED_CONNECTION:
case HCI_OE_LOW_RESOURCES:
case HCI_OE_POWER_OFF:
return ECONNRESET;
case HCI_CONNECTION_TERMINATED:
return ECONNABORTED;
case HCI_REPEATED_ATTEMPTS:
return ELOOP;
case HCI_REJECTED_SECURITY:
case HCI_PAIRING_NOT_ALLOWED:
case HCI_INSUFFICIENT_SECURITY:
return EACCES;
case HCI_UNSUPPORTED_REMOTE_FEATURE:
return EPROTONOSUPPORT;
case HCI_SCO_OFFSET_REJECTED:
return ECONNREFUSED;
case HCI_UNKNOWN_LMP_PDU:
case HCI_INVALID_LMP_PARAMETERS:
case HCI_LMP_ERROR_TRANSACTION_COLLISION:
case HCI_LMP_PDU_NOT_ALLOWED:
case HCI_ENCRYPTION_MODE_NOT_ACCEPTED:
return EPROTO;
default:
return ENOSYS;
}
}
const char *bt_compidtostr(int compid)
{
switch (compid) {
case 0:
return "Ericsson Technology Licensing";
case 1:
return "Nokia Mobile Phones";
case 2:
return "Intel Corp.";
case 3:
return "IBM Corp.";
case 4:
return "Toshiba Corp.";
case 5:
return "3Com";
case 6:
return "Microsoft";
case 7:
return "Lucent";
case 8:
return "Motorola";
case 9:
return "Infineon Technologies AG";
case 10:
return "Cambridge Silicon Radio";
case 11:
return "Silicon Wave";
case 12:
return "Digianswer A/S";
case 13:
return "Texas Instruments Inc.";
case 14:
return "Ceva, Inc. (formerly Parthus Technologies, Inc.)";
case 15:
return "Broadcom Corporation";
case 16:
return "Mitel Semiconductor";
case 17:
return "Widcomm, Inc";
case 18:
return "Zeevo, Inc.";
case 19:
return "Atmel Corporation";
case 20:
return "Mitsubishi Electric Corporation";
case 21:
return "RTX Telecom A/S";
case 22:
return "KC Technology Inc.";
case 23:
return "NewLogic";
case 24:
return "Transilica, Inc.";
case 25:
return "Rohde & Schwarz GmbH & Co. KG";
case 26:
return "TTPCom Limited";
case 27:
return "Signia Technologies, Inc.";
case 28:
return "Conexant Systems Inc.";
case 29:
return "Qualcomm";
case 30:
return "Inventel";
case 31:
return "AVM Berlin";
case 32:
return "BandSpeed, Inc.";
case 33:
return "Mansella Ltd";
case 34:
return "NEC Corporation";
case 35:
return "WavePlus Technology Co., Ltd.";
case 36:
return "Alcatel";
case 37:
return "Philips Semiconductors";
case 38:
return "C Technologies";
case 39:
return "Open Interface";
case 40:
return "R F Micro Devices";
case 41:
return "Hitachi Ltd";
case 42:
return "Symbol Technologies, Inc.";
case 43:
return "Tenovis";
case 44:
return "Macronix International Co. Ltd.";
case 45:
return "GCT Semiconductor";
case 46:
return "Norwood Systems";
case 47:
return "MewTel Technology Inc.";
case 48:
return "ST Microelectronics";
case 49:
return "Synopsis";
case 50:
return "Red-M (Communications) Ltd";
case 51:
return "Commil Ltd";
case 52:
return "Computer Access Technology Corporation (CATC)";
case 53:
return "Eclipse (HQ Espana) S.L.";
case 54:
return "Renesas Technology Corp.";
case 55:
return "Mobilian Corporation";
case 56:
return "Terax";
case 57:
return "Integrated System Solution Corp.";
case 58:
return "Matsushita Electric Industrial Co., Ltd.";
case 59:
return "Gennum Corporation";
case 60:
return "Research In Motion";
case 61:
return "IPextreme, Inc.";
case 62:
return "Systems and Chips, Inc.";
case 63:
return "Bluetooth SIG, Inc.";
case 64:
return "Seiko Epson Corporation";
case 65:
return "Integrated Silicon Solution Taiwan, Inc.";
case 66:
return "CONWISE Technology Corporation Ltd";
case 67:
return "PARROT SA";
case 68:
return "Socket Mobile";
case 69:
return "Atheros Communications, Inc.";
case 70:
return "MediaTek, Inc.";
case 71:
return "Bluegiga";
case 72:
return "Marvell Technology Group Ltd.";
case 73:
return "3DSP Corporation";
case 74:
return "Accel Semiconductor Ltd.";
case 75:
return "Continental Automotive Systems";
case 76:
return "Apple, Inc.";
case 77:
return "Staccato Communications, Inc.";
case 78:
return "Avago Technologies";
case 79:
return "APT Licensing Ltd.";
case 80:
return "SiRF Technology";
case 81:
return "Tzero Technologies, Inc.";
case 82:
return "J&M Corporation";
case 83:
return "Free2move AB";
case 84:
return "3DiJoy Corporation";
case 85:
return "Plantronics, Inc.";
case 86:
return "Sony Ericsson Mobile Communications";
case 87:
return "Harman International Industries, Inc.";
case 88:
return "Vizio, Inc.";
case 89:
return "Nordic Semiconductor ASA";
case 90:
return "EM Microelectronic-Marin SA";
case 91:
return "Ralink Technology Corporation";
case 92:
return "Belkin International, Inc.";
case 93:
return "Realtek Semiconductor Corporation";
case 94:
return "Stonestreet One, LLC";
case 95:
return "Wicentric, Inc.";
case 96:
return "RivieraWaves S.A.S";
case 97:
return "RDA Microelectronics";
case 98:
return "Gibson Guitars";
case 99:
return "MiCommand Inc.";
case 100:
return "Band XI International, LLC";
case 101:
return "Hewlett-Packard Company";
case 102:
return "9Solutions Oy";
case 103:
return "GN Netcom A/S";
case 104:
return "General Motors";
case 105:
return "A&D Engineering, Inc.";
case 106:
return "MindTree Ltd.";
case 107:
return "Polar Electro OY";
case 108:
return "Beautiful Enterprise Co., Ltd.";
case 109:
return "BriarTek, Inc.";
case 110:
return "Summit Data Communications, Inc.";
case 111:
return "Sound ID";
case 112:
return "Monster, LLC";
case 113:
return "connectBlue AB";
case 114:
return "ShangHai Super Smart Electronics Co. Ltd.";
case 115:
return "Group Sense Ltd.";
case 116:
return "Zomm, LLC";
case 117:
return "Samsung Electronics Co. Ltd.";
case 118:
return "Creative Technology Ltd.";
case 119:
return "Laird Technologies";
case 120:
return "Nike, Inc.";
case 121:
return "lesswire AG";
case 122:
return "MStar Semiconductor, Inc.";
case 123:
return "Hanlynn Technologies";
case 124:
return "A & R Cambridge";
case 125:
return "Seers Technology Co. Ltd";
case 126:
return "Sports Tracking Technologies Ltd.";
case 127:
return "Autonet Mobile";
case 128:
return "DeLorme Publishing Company, Inc.";
case 129:
return "WuXi Vimicro";
case 130:
return "Sennheiser Communications A/S";
case 131:
return "TimeKeeping Systems, Inc.";
case 132:
return "Ludus Helsinki Ltd.";
case 133:
return "BlueRadios, Inc.";
case 134:
return "equinox AG";
case 135:
return "Garmin International, Inc.";
case 136:
return "Ecotest";
case 137:
return "GN ReSound A/S";
case 138:
return "Jawbone";
case 139:
return "Topcorn Positioning Systems, LLC";
case 140:
return "Qualcomm Labs, Inc.";
case 141:
return "Zscan Software";
case 142:
return "Quintic Corp.";
case 143:
return "Stollman E+V GmbH";
case 144:
return "Funai Electric Co., Ltd.";
case 145:
return "Advanced PANMOBIL Systems GmbH & Co. KG";
case 146:
return "ThinkOptics, Inc.";
case 147:
return "Universal Electronics, Inc.";
case 148:
return "Airoha Technology Corp.";
case 149:
return "NEC Lighting, Ltd.";
case 150:
return "ODM Technology, Inc.";
case 151:
return "ConnecteDevice Ltd.";
case 152:
return "zer01.tv GmbH";
case 153:
return "i.Tech Dynamic Global Distribution Ltd.";
case 154:
return "Alpwise";
case 155:
return "Jiangsu Toppower Automotive Electronics Co., Ltd.";
case 156:
return "Colorfy, Inc.";
case 157:
return "Geoforce Inc.";
case 158:
return "Bose Corporation";
case 159:
return "Suunto Oy";
case 160:
return "Kensington Computer Products Group";
case 161:
return "SR-Medizinelektronik";
case 162:
return "Vertu Corporation Limited";
case 163:
return "Meta Watch Ltd.";
case 164:
return "LINAK A/S";
case 165:
return "OTL Dynamics LLC";
case 166:
return "Panda Ocean Inc.";
case 167:
return "Visteon Corporation";
case 168:
return "ARP Devices Limited";
case 169:
return "Magneti Marelli S.p.A";
case 170:
return "CAEN RFID srl";
case 171:
return "Ingenieur-Systemgruppe Zahn GmbH";
case 172:
return "Green Throttle Games";
case 173:
return "Peter Systemtechnik GmbH";
case 174:
return "Omegawave Oy";
case 175:
return "Cinetix";
case 176:
return "Passif Semiconductor Corp";
case 177:
return "Saris Cycling Group, Inc";
case 178:
return "Bekey A/S";
case 179:
return "Clarinox Technologies Pty. Ltd.";
case 180:
return "BDE Technology Co., Ltd.";
case 181:
return "Swirl Networks";
case 182:
return "Meso international";
case 183:
return "TreLab Ltd";
case 184:
return "Qualcomm Innovation Center, Inc. (QuIC)";
case 185:
return "Johnson Controls, Inc.";
case 186:
return "Starkey Laboratories Inc.";
case 187:
return "S-Power Electronics Limited";
case 188:
return "Ace Sensor Inc";
case 189:
return "Aplix Corporation";
case 190:
return "AAMP of America";
case 191:
return "Stalmart Technology Limited";
case 192:
return "AMICCOM Electronics Corporation";
case 193:
return "Shenzhen Excelsecu Data Technology Co.,Ltd";
case 194:
return "Geneq Inc.";
case 195:
return "adidas AG";
case 196:
return "LG Electronics";
case 197:
return "Onset Computer Corporation";
case 198:
return "Selfly BV";
case 199:
return "Quuppa Oy.";
case 200:
return "GeLo Inc";
case 201:
return "Evluma";
case 202:
return "MC10";
case 203:
return "Binauric SE";
case 204:
return "Beats Electronics";
case 205:
return "Microchip Technology Inc.";
case 206:
return "Elgato Systems GmbH";
case 207:
return "ARCHOS SA";
case 209:
return "Polar Electro Europe B.V.";
case 210:
return "Dialog Semiconductor B.V.";
case 211:
return "Taixingbang Technology (HK) Co,. LTD.";
case 212:
return "Kawantech";
case 213:
return "Austco Communication Systems";
case 214:
return "Timex Group USA, Inc.";
case 215:
return "Qualcomm Technologies, Inc.";
case 216:
return "Qualcomm Connected Experiences, Inc.";
case 217:
return "Voyetra Turtle Beach";
case 218:
return "txtr GmbH";
case 219:
return "Biosentronics";
case 220:
return "Procter & Gamble";
case 221:
return "Hosiden Corporation";
case 222:
return "Muzik LLC";
case 223:
return "Misfit Wearables Corp";
case 224:
return "Google";
case 225:
return "Danlers Ltd";
case 226:
return "Semilink Inc";
case 227:
return "inMusic Brands, Inc";
case 228:
return "L.S. Research Inc.";
case 229:
return "Eden Software Consultants Ltd.";
case 230:
return "Freshtemp";
case 231:
return "KS Technologies";
case 232:
return "ACTS Technologies";
case 233:
return "Vtrack Systems";
case 234:
return "Nielsen-Kellerman Company";
case 235:
return "Server Technology, Inc.";
case 236:
return "BioResearch Associates";
case 237:
return "Jolly Logic, LLC";
case 238:
return "Above Average Outcomes, Inc.";
case 239:
return "Bitsplitters GmbH";
case 240:
return "PayPal, Inc.";
case 241:
return "Witron Technology Limited";
case 242:
return "Morse Project Inc.";
case 243:
return "Kent Displays Inc.";
case 244:
return "Nautilus Inc.";
case 245:
return "Smartifier Oy";
case 246:
return "Elcometer Limited";
case 247:
return "VSN Technologies Inc.";
case 248:
return "AceUni Corp., Ltd.";
case 65535:
return "internal use";
default:
return "not assigned";
}
}

View File

@@ -0,0 +1,389 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __BLUETOOTH_H
#define __BLUETOOTH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>
#include <netinet/in.h>
#ifndef AF_BLUETOOTH
#define AF_BLUETOOTH 31
#define PF_BLUETOOTH AF_BLUETOOTH
#endif
#define BTPROTO_L2CAP 0
#define BTPROTO_HCI 1
#define BTPROTO_SCO 2
#define BTPROTO_RFCOMM 3
#define BTPROTO_BNEP 4
#define BTPROTO_CMTP 5
#define BTPROTO_HIDP 6
#define BTPROTO_AVDTP 7
#define SOL_HCI 0
#define SOL_L2CAP 6
#define SOL_SCO 17
#define SOL_RFCOMM 18
#ifndef SOL_BLUETOOTH
#define SOL_BLUETOOTH 274
#endif
#define BT_SECURITY 4
struct bt_security {
uint8_t level;
uint8_t key_size;
};
#define BT_SECURITY_SDP 0
#define BT_SECURITY_LOW 1
#define BT_SECURITY_MEDIUM 2
#define BT_SECURITY_HIGH 3
#define BT_DEFER_SETUP 7
#define BT_FLUSHABLE 8
#define BT_FLUSHABLE_OFF 0
#define BT_FLUSHABLE_ON 1
#define BT_CHANNEL_POLICY 10
/* BR/EDR only (default policy)
* AMP controllers cannot be used.
* Channel move requests from the remote device are denied.
* If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
*/
#define BT_CHANNEL_POLICY_BREDR_ONLY 0
/* BR/EDR Preferred
* Allow use of AMP controllers.
* If the L2CAP channel is currently on AMP, move it to BR/EDR.
* Channel move requests from the remote device are allowed.
*/
#define BT_CHANNEL_POLICY_BREDR_PREFERRED 1
/* AMP Preferred
* Allow use of AMP controllers
* If the L2CAP channel is currently on BR/EDR and AMP controller
* resources are available, initiate a channel move to AMP.
* Channel move requests from the remote device are allowed.
* If the L2CAP socket has not been connected yet, try to create
* and configure the channel directly on an AMP controller rather
* than BR/EDR.
*/
#define BT_CHANNEL_POLICY_AMP_PREFERRED 2
#define BT_VOICE 11
struct bt_voice {
uint16_t setting;
};
#define BT_VOICE_TRANSPARENT 0x0003
#define BT_VOICE_CVSD_16BIT 0x0060
/* Connection and socket states */
enum {
BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
BT_OPEN,
BT_BOUND,
BT_LISTEN,
BT_CONNECT,
BT_CONNECT2,
BT_CONFIG,
BT_DISCONN,
BT_CLOSED
};
/* Byte order conversions */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htobs(d) (d)
#define htobl(d) (d)
#define htobll(d) (d)
#define btohs(d) (d)
#define btohl(d) (d)
#define btohll(d) (d)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define htobs(d) bswap_16(d)
#define htobl(d) bswap_32(d)
#define htobll(d) bswap_64(d)
#define btohs(d) bswap_16(d)
#define btohl(d) bswap_32(d)
#define btohll(d) bswap_64(d)
#else
#error "Unknown byte order"
#endif
/* Bluetooth unaligned access */
#define bt_get_unaligned(ptr) \
({ \
struct __attribute__((packed)) { \
typeof(*(ptr)) __v; \
} *__p = (typeof(__p)) (ptr); \
__p->__v; \
})
#define bt_put_unaligned(val, ptr) \
do { \
struct __attribute__((packed)) { \
typeof(*(ptr)) __v; \
} *__p = (typeof(__p)) (ptr); \
__p->__v = (val); \
} while(0)
#if __BYTE_ORDER == __LITTLE_ENDIAN
static inline uint64_t bt_get_le64(const void *ptr)
{
return bt_get_unaligned((const uint64_t *) ptr);
}
static inline uint64_t bt_get_be64(const void *ptr)
{
return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
}
static inline uint32_t bt_get_le32(const void *ptr)
{
return bt_get_unaligned((const uint32_t *) ptr);
}
static inline uint32_t bt_get_be32(const void *ptr)
{
return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
}
static inline uint16_t bt_get_le16(const void *ptr)
{
return bt_get_unaligned((const uint16_t *) ptr);
}
static inline uint16_t bt_get_be16(const void *ptr)
{
return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
}
static inline void bt_put_le64(uint64_t val, const void *ptr)
{
bt_put_unaligned(val, (uint64_t *) ptr);
}
static inline void bt_put_be64(uint64_t val, const void *ptr)
{
bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
}
static inline void bt_put_le32(uint32_t val, const void *ptr)
{
bt_put_unaligned(val, (uint32_t *) ptr);
}
static inline void bt_put_be32(uint32_t val, const void *ptr)
{
bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
}
static inline void bt_put_le16(uint16_t val, const void *ptr)
{
bt_put_unaligned(val, (uint16_t *) ptr);
}
static inline void bt_put_be16(uint16_t val, const void *ptr)
{
bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
}
#elif __BYTE_ORDER == __BIG_ENDIAN
static inline uint64_t bt_get_le64(const void *ptr)
{
return bswap_64(bt_get_unaligned((const uint64_t *) ptr));
}
static inline uint64_t bt_get_be64(const void *ptr)
{
return bt_get_unaligned((const uint64_t *) ptr);
}
static inline uint32_t bt_get_le32(const void *ptr)
{
return bswap_32(bt_get_unaligned((const uint32_t *) ptr));
}
static inline uint32_t bt_get_be32(const void *ptr)
{
return bt_get_unaligned((const uint32_t *) ptr);
}
static inline uint16_t bt_get_le16(const void *ptr)
{
return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
}
static inline uint16_t bt_get_be16(const void *ptr)
{
return bt_get_unaligned((const uint16_t *) ptr);
}
static inline void bt_put_le64(uint64_t val, const void *ptr)
{
bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
}
static inline void bt_put_be64(uint64_t val, const void *ptr)
{
bt_put_unaligned(val, (uint64_t *) ptr);
}
static inline void bt_put_le32(uint32_t val, const void *ptr)
{
bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
}
static inline void bt_put_be32(uint32_t val, const void *ptr)
{
bt_put_unaligned(val, (uint32_t *) ptr);
}
static inline void bt_put_le16(uint16_t val, const void *ptr)
{
bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
}
static inline void bt_put_be16(uint16_t val, const void *ptr)
{
bt_put_unaligned(val, (uint16_t *) ptr);
}
#else
#error "Unknown byte order"
#endif
/* BD Address */
typedef struct {
uint8_t b[6];
} __attribute__((packed)) bdaddr_t;
/* BD Address type */
#define BDADDR_BREDR 0x00
#define BDADDR_LE_PUBLIC 0x01
#define BDADDR_LE_RANDOM 0x02
#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})
#define BDADDR_ALL (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}})
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})
/* Copy, swap, convert BD Address */
static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
{
return memcmp(ba1, ba2, sizeof(bdaddr_t));
}
static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
{
memcpy(dst, src, sizeof(bdaddr_t));
}
void baswap(bdaddr_t *dst, const bdaddr_t *src);
bdaddr_t *strtoba(const char *str);
char *batostr(const bdaddr_t *ba);
int ba2str(const bdaddr_t *ba, char *str);
int str2ba(const char *str, bdaddr_t *ba);
int ba2oui(const bdaddr_t *ba, char *oui);
int bachk(const char *str);
int baprintf(const char *format, ...);
int bafprintf(FILE *stream, const char *format, ...);
int basprintf(char *str, const char *format, ...);
int basnprintf(char *str, size_t size, const char *format, ...);
void *bt_malloc(size_t size);
void bt_free(void *ptr);
int bt_error(uint16_t code);
const char *bt_compidtostr(int id);
typedef struct {
uint8_t data[16];
} uint128_t;
#if __BYTE_ORDER == __BIG_ENDIAN
#define ntoh64(x) (x)
static inline void ntoh128(const uint128_t *src, uint128_t *dst)
{
memcpy(dst, src, sizeof(uint128_t));
}
static inline void btoh128(const uint128_t *src, uint128_t *dst)
{
int i;
for (i = 0; i < 16; i++)
dst->data[15 - i] = src->data[i];
}
#else
static inline uint64_t ntoh64(uint64_t n)
{
uint64_t h;
uint64_t tmp = ntohl(n & 0x00000000ffffffff);
h = ntohl(n >> 32);
h |= tmp << 32;
return h;
}
static inline void ntoh128(const uint128_t *src, uint128_t *dst)
{
int i;
for (i = 0; i < 16; i++)
dst->data[15 - i] = src->data[i];
}
static inline void btoh128(const uint128_t *src, uint128_t *dst)
{
memcpy(dst, src, sizeof(uint128_t));
}
#endif
#define hton64(x) ntoh64(x)
#define hton128(x, y) ntoh128(x, y)
#define htob128(x, y) btoh128(x, y)
#ifdef __cplusplus
}
#endif
#endif /* __BLUETOOTH_H */

View File

@@ -0,0 +1,153 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __BNEP_H
#define __BNEP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <bluetooth/bluetooth.h>
#ifndef ETH_ALEN
#define ETH_ALEN 6 /* from <net/ethernet.h> */
#endif
/* BNEP UUIDs */
#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB
#define BNEP_UUID16 0x02
#define BNEP_UUID32 0x04
#define BNEP_UUID128 0x16
#define BNEP_SVC_PANU 0x1115
#define BNEP_SVC_NAP 0x1116
#define BNEP_SVC_GN 0x1117
/* BNEP packet types */
#define BNEP_GENERAL 0x00
#define BNEP_CONTROL 0x01
#define BNEP_COMPRESSED 0x02
#define BNEP_COMPRESSED_SRC_ONLY 0x03
#define BNEP_COMPRESSED_DST_ONLY 0x04
/* BNEP control types */
#define BNEP_CMD_NOT_UNDERSTOOD 0x00
#define BNEP_SETUP_CONN_REQ 0x01
#define BNEP_SETUP_CONN_RSP 0x02
#define BNEP_FILTER_NET_TYPE_SET 0x03
#define BNEP_FILTER_NET_TYPE_RSP 0x04
#define BNEP_FILTER_MULT_ADDR_SET 0x05
#define BNEP_FILTER_MULT_ADDR_RSP 0x06
/* BNEP response messages */
#define BNEP_SUCCESS 0x00
#define BNEP_CONN_INVALID_DST 0x01
#define BNEP_CONN_INVALID_SRC 0x02
#define BNEP_CONN_INVALID_SVC 0x03
#define BNEP_CONN_NOT_ALLOWED 0x04
#define BNEP_FILTER_UNSUPPORTED_REQ 0x01
#define BNEP_FILTER_INVALID_RANGE 0x02
#define BNEP_FILTER_INVALID_MCADDR 0x02
#define BNEP_FILTER_LIMIT_REACHED 0x03
#define BNEP_FILTER_DENIED_SECURITY 0x04
/* L2CAP settings */
#define BNEP_MTU 1691
#define BNEP_FLUSH_TO 0xffff
#define BNEP_CONNECT_TO 15
#define BNEP_FILTER_TO 15
#ifndef BNEP_PSM
#define BNEP_PSM 0x0f
#endif
/* BNEP headers */
#define BNEP_TYPE_MASK 0x7f
#define BNEP_EXT_HEADER 0x80
struct bnep_setup_conn_req {
uint8_t type;
uint8_t ctrl;
uint8_t uuid_size;
uint8_t service[0];
} __attribute__((packed));
struct bnep_set_filter_req {
uint8_t type;
uint8_t ctrl;
uint16_t len;
uint8_t list[0];
} __attribute__((packed));
struct bnep_control_rsp {
uint8_t type;
uint8_t ctrl;
uint16_t resp;
} __attribute__((packed));
struct bnep_ext_hdr {
uint8_t type;
uint8_t len;
uint8_t data[0];
} __attribute__((packed));
/* BNEP ioctl defines */
#define BNEPCONNADD _IOW('B', 200, int)
#define BNEPCONNDEL _IOW('B', 201, int)
#define BNEPGETCONNLIST _IOR('B', 210, int)
#define BNEPGETCONNINFO _IOR('B', 211, int)
struct bnep_connadd_req {
int sock; /* Connected socket */
uint32_t flags;
uint16_t role;
char device[16]; /* Name of the Ethernet device */
};
struct bnep_conndel_req {
uint32_t flags;
uint8_t dst[ETH_ALEN];
};
struct bnep_conninfo {
uint32_t flags;
uint16_t role;
uint16_t state;
uint8_t dst[ETH_ALEN];
char device[16];
};
struct bnep_connlist_req {
uint32_t cnum;
struct bnep_conninfo *ci;
};
#ifdef __cplusplus
}
#endif
#endif /* __BNEP_H */

View File

@@ -0,0 +1,69 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __CMTP_H
#define __CMTP_H
#ifdef __cplusplus
extern "C" {
#endif
/* CMTP defaults */
#define CMTP_MINIMUM_MTU 152
#define CMTP_DEFAULT_MTU 672
/* CMTP ioctl defines */
#define CMTPCONNADD _IOW('C', 200, int)
#define CMTPCONNDEL _IOW('C', 201, int)
#define CMTPGETCONNLIST _IOR('C', 210, int)
#define CMTPGETCONNINFO _IOR('C', 211, int)
#define CMTP_LOOPBACK 0
struct cmtp_connadd_req {
int sock; /* Connected socket */
uint32_t flags;
};
struct cmtp_conndel_req {
bdaddr_t bdaddr;
uint32_t flags;
};
struct cmtp_conninfo {
bdaddr_t bdaddr;
uint32_t flags;
uint16_t state;
int num;
};
struct cmtp_connlist_req {
uint32_t cnum;
struct cmtp_conninfo *ci;
};
#ifdef __cplusplus
}
#endif
#endif /* __CMTP_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,235 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __HCI_LIB_H
#define __HCI_LIB_H
#ifdef __cplusplus
extern "C" {
#endif
struct hci_request {
uint16_t ogf;
uint16_t ocf;
int event;
void *cparam;
int clen;
void *rparam;
int rlen;
};
struct hci_version {
uint16_t manufacturer;
uint8_t hci_ver;
uint16_t hci_rev;
uint8_t lmp_ver;
uint16_t lmp_subver;
};
int hci_open_dev(int dev_id);
int hci_close_dev(int dd);
int hci_send_cmd(int dd, uint16_t ogf, uint16_t ocf, uint8_t plen, void *param);
int hci_send_req(int dd, struct hci_request *req, int timeout);
int hci_create_connection(int dd, const bdaddr_t *bdaddr, uint16_t ptype, uint16_t clkoffset, uint8_t rswitch, uint16_t *handle, int to);
int hci_disconnect(int dd, uint16_t handle, uint8_t reason, int to);
int hci_inquiry(int dev_id, int len, int num_rsp, const uint8_t *lap, inquiry_info **ii, long flags);
int hci_devinfo(int dev_id, struct hci_dev_info *di);
int hci_devba(int dev_id, bdaddr_t *bdaddr);
int hci_devid(const char *str);
int hci_read_local_name(int dd, int len, char *name, int to);
int hci_write_local_name(int dd, const char *name, int to);
int hci_read_remote_name(int dd, const bdaddr_t *bdaddr, int len, char *name, int to);
int hci_read_remote_name_with_clock_offset(int dd, const bdaddr_t *bdaddr, uint8_t pscan_rep_mode, uint16_t clkoffset, int len, char *name, int to);
int hci_read_remote_name_cancel(int dd, const bdaddr_t *bdaddr, int to);
int hci_read_remote_version(int dd, uint16_t handle, struct hci_version *ver, int to);
int hci_read_remote_features(int dd, uint16_t handle, uint8_t *features, int to);
int hci_read_remote_ext_features(int dd, uint16_t handle, uint8_t page, uint8_t *max_page, uint8_t *features, int to);
int hci_read_clock_offset(int dd, uint16_t handle, uint16_t *clkoffset, int to);
int hci_read_local_version(int dd, struct hci_version *ver, int to);
int hci_read_local_commands(int dd, uint8_t *commands, int to);
int hci_read_local_features(int dd, uint8_t *features, int to);
int hci_read_local_ext_features(int dd, uint8_t page, uint8_t *max_page, uint8_t *features, int to);
int hci_read_bd_addr(int dd, bdaddr_t *bdaddr, int to);
int hci_read_class_of_dev(int dd, uint8_t *cls, int to);
int hci_write_class_of_dev(int dd, uint32_t cls, int to);
int hci_read_voice_setting(int dd, uint16_t *vs, int to);
int hci_write_voice_setting(int dd, uint16_t vs, int to);
int hci_read_current_iac_lap(int dd, uint8_t *num_iac, uint8_t *lap, int to);
int hci_write_current_iac_lap(int dd, uint8_t num_iac, uint8_t *lap, int to);
int hci_read_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to);
int hci_write_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t *key, int to);
int hci_delete_stored_link_key(int dd, bdaddr_t *bdaddr, uint8_t all, int to);
int hci_authenticate_link(int dd, uint16_t handle, int to);
int hci_encrypt_link(int dd, uint16_t handle, uint8_t encrypt, int to);
int hci_change_link_key(int dd, uint16_t handle, int to);
int hci_switch_role(int dd, bdaddr_t *bdaddr, uint8_t role, int to);
int hci_park_mode(int dd, uint16_t handle, uint16_t max_interval, uint16_t min_interval, int to);
int hci_exit_park_mode(int dd, uint16_t handle, int to);
int hci_read_inquiry_scan_type(int dd, uint8_t *type, int to);
int hci_write_inquiry_scan_type(int dd, uint8_t type, int to);
int hci_read_inquiry_mode(int dd, uint8_t *mode, int to);
int hci_write_inquiry_mode(int dd, uint8_t mode, int to);
int hci_read_afh_mode(int dd, uint8_t *mode, int to);
int hci_write_afh_mode(int dd, uint8_t mode, int to);
int hci_read_ext_inquiry_response(int dd, uint8_t *fec, uint8_t *data, int to);
int hci_write_ext_inquiry_response(int dd, uint8_t fec, uint8_t *data, int to);
int hci_read_simple_pairing_mode(int dd, uint8_t *mode, int to);
int hci_write_simple_pairing_mode(int dd, uint8_t mode, int to);
int hci_read_local_oob_data(int dd, uint8_t *hash, uint8_t *randomizer, int to);
int hci_read_inq_response_tx_power_level(int dd, int8_t *level, int to);
int hci_read_inquiry_transmit_power_level(int dd, int8_t *level, int to);
int hci_write_inquiry_transmit_power_level(int dd, int8_t level, int to);
int hci_read_transmit_power_level(int dd, uint16_t handle, uint8_t type, int8_t *level, int to);
int hci_read_link_policy(int dd, uint16_t handle, uint16_t *policy, int to);
int hci_write_link_policy(int dd, uint16_t handle, uint16_t policy, int to);
int hci_read_link_supervision_timeout(int dd, uint16_t handle, uint16_t *timeout, int to);
int hci_write_link_supervision_timeout(int dd, uint16_t handle, uint16_t timeout, int to);
int hci_set_afh_classification(int dd, uint8_t *map, int to);
int hci_read_link_quality(int dd, uint16_t handle, uint8_t *link_quality, int to);
int hci_read_rssi(int dd, uint16_t handle, int8_t *rssi, int to);
int hci_read_afh_map(int dd, uint16_t handle, uint8_t *mode, uint8_t *map, int to);
int hci_read_clock(int dd, uint16_t handle, uint8_t which, uint32_t *clock, uint16_t *accuracy, int to);
int hci_le_set_scan_enable(int dev_id, uint8_t enable, uint8_t filter_dup, int to);
int hci_le_set_scan_parameters(int dev_id, uint8_t type, uint16_t interval,
uint16_t window, uint8_t own_type,
uint8_t filter, int to);
int hci_le_set_advertise_enable(int dev_id, uint8_t enable, int to);
int hci_le_create_conn(int dd, uint16_t interval, uint16_t window,
uint8_t initiator_filter, uint8_t peer_bdaddr_type,
bdaddr_t peer_bdaddr, uint8_t own_bdaddr_type,
uint16_t min_interval, uint16_t max_interval,
uint16_t latency, uint16_t supervision_timeout,
uint16_t min_ce_length, uint16_t max_ce_length,
uint16_t *handle, int to);
int hci_le_conn_update(int dd, uint16_t handle, uint16_t min_interval,
uint16_t max_interval, uint16_t latency,
uint16_t supervision_timeout, int to);
int hci_le_add_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
int hci_le_rm_white_list(int dd, const bdaddr_t *bdaddr, uint8_t type, int to);
int hci_le_read_white_list_size(int dd, uint8_t *size, int to);
int hci_le_clear_white_list(int dd, int to);
int hci_for_each_dev(int flag, int(*func)(int dd, int dev_id, long arg), long arg);
int hci_get_route(bdaddr_t *bdaddr);
char *hci_bustostr(int bus);
char *hci_typetostr(int type);
char *hci_dtypetostr(int type);
char *hci_dflagstostr(uint32_t flags);
char *hci_ptypetostr(unsigned int ptype);
int hci_strtoptype(char *str, unsigned int *val);
char *hci_scoptypetostr(unsigned int ptype);
int hci_strtoscoptype(char *str, unsigned int *val);
char *hci_lptostr(unsigned int ptype);
int hci_strtolp(char *str, unsigned int *val);
char *hci_lmtostr(unsigned int ptype);
int hci_strtolm(char *str, unsigned int *val);
char *hci_cmdtostr(unsigned int cmd);
char *hci_commandstostr(uint8_t *commands, char *pref, int width);
char *hci_vertostr(unsigned int ver);
int hci_strtover(char *str, unsigned int *ver);
char *lmp_vertostr(unsigned int ver);
int lmp_strtover(char *str, unsigned int *ver);
char *pal_vertostr(unsigned int ver);
int pal_strtover(char *str, unsigned int *ver);
char *lmp_featurestostr(uint8_t *features, char *pref, int width);
static inline void hci_set_bit(int nr, void *addr)
{
*((uint32_t *) addr + (nr >> 5)) |= (1 << (nr & 31));
}
static inline void hci_clear_bit(int nr, void *addr)
{
*((uint32_t *) addr + (nr >> 5)) &= ~(1 << (nr & 31));
}
static inline int hci_test_bit(int nr, void *addr)
{
return *((uint32_t *) addr + (nr >> 5)) & (1 << (nr & 31));
}
/* HCI filter tools */
static inline void hci_filter_clear(struct hci_filter *f)
{
memset(f, 0, sizeof(*f));
}
static inline void hci_filter_set_ptype(int t, struct hci_filter *f)
{
hci_set_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
}
static inline void hci_filter_clear_ptype(int t, struct hci_filter *f)
{
hci_clear_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
}
static inline int hci_filter_test_ptype(int t, struct hci_filter *f)
{
return hci_test_bit((t == HCI_VENDOR_PKT) ? 0 : (t & HCI_FLT_TYPE_BITS), &f->type_mask);
}
static inline void hci_filter_all_ptypes(struct hci_filter *f)
{
memset((void *) &f->type_mask, 0xff, sizeof(f->type_mask));
}
static inline void hci_filter_set_event(int e, struct hci_filter *f)
{
hci_set_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
}
static inline void hci_filter_clear_event(int e, struct hci_filter *f)
{
hci_clear_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
}
static inline int hci_filter_test_event(int e, struct hci_filter *f)
{
return hci_test_bit((e & HCI_FLT_EVENT_BITS), &f->event_mask);
}
static inline void hci_filter_all_events(struct hci_filter *f)
{
memset((void *) f->event_mask, 0xff, sizeof(f->event_mask));
}
static inline void hci_filter_set_opcode(int opcode, struct hci_filter *f)
{
f->opcode = opcode;
}
static inline void hci_filter_clear_opcode(struct hci_filter *f)
{
f->opcode = 0;
}
static inline int hci_filter_test_opcode(int opcode, struct hci_filter *f)
{
return (f->opcode == opcode);
}
#ifdef __cplusplus
}
#endif
#endif /* __HCI_LIB_H */

View File

@@ -0,0 +1,85 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2003-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __HIDP_H
#define __HIDP_H
#ifdef __cplusplus
extern "C" {
#endif
/* HIDP defaults */
#define HIDP_MINIMUM_MTU 48
#define HIDP_DEFAULT_MTU 48
/* HIDP ioctl defines */
#define HIDPCONNADD _IOW('H', 200, int)
#define HIDPCONNDEL _IOW('H', 201, int)
#define HIDPGETCONNLIST _IOR('H', 210, int)
#define HIDPGETCONNINFO _IOR('H', 211, int)
#define HIDP_VIRTUAL_CABLE_UNPLUG 0
#define HIDP_BOOT_PROTOCOL_MODE 1
#define HIDP_BLUETOOTH_VENDOR_ID 9
struct hidp_connadd_req {
int ctrl_sock; /* Connected control socket */
int intr_sock; /* Connected interrupt socket */
uint16_t parser; /* Parser version */
uint16_t rd_size; /* Report descriptor size */
uint8_t *rd_data; /* Report descriptor data */
uint8_t country;
uint8_t subclass;
uint16_t vendor;
uint16_t product;
uint16_t version;
uint32_t flags;
uint32_t idle_to;
char name[128]; /* Device name */
};
struct hidp_conndel_req {
bdaddr_t bdaddr;
uint32_t flags;
};
struct hidp_conninfo {
bdaddr_t bdaddr;
uint32_t flags;
uint16_t state;
uint16_t vendor;
uint16_t product;
uint16_t version;
char name[128];
};
struct hidp_connlist_req {
uint32_t cnum;
struct hidp_conninfo *ci;
};
#ifdef __cplusplus
}
#endif
#endif /* __HIDP_H */

View File

@@ -0,0 +1,279 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (c) 2012 Code Aurora Forum. 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
*
*/
#ifndef __L2CAP_H
#define __L2CAP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/socket.h>
/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
/* L2CAP socket address */
struct sockaddr_l2 {
sa_family_t l2_family;
unsigned short l2_psm;
bdaddr_t l2_bdaddr;
unsigned short l2_cid;
uint8_t l2_bdaddr_type;
};
/* L2CAP socket options */
#define L2CAP_OPTIONS 0x01
struct l2cap_options {
uint16_t omtu;
uint16_t imtu;
uint16_t flush_to;
uint8_t mode;
uint8_t fcs;
uint8_t max_tx;
uint16_t txwin_size;
};
#define L2CAP_CONNINFO 0x02
struct l2cap_conninfo {
uint16_t hci_handle;
uint8_t dev_class[3];
};
#define L2CAP_LM 0x03
#define L2CAP_LM_MASTER 0x0001
#define L2CAP_LM_AUTH 0x0002
#define L2CAP_LM_ENCRYPT 0x0004
#define L2CAP_LM_TRUSTED 0x0008
#define L2CAP_LM_RELIABLE 0x0010
#define L2CAP_LM_SECURE 0x0020
/* L2CAP command codes */
#define L2CAP_COMMAND_REJ 0x01
#define L2CAP_CONN_REQ 0x02
#define L2CAP_CONN_RSP 0x03
#define L2CAP_CONF_REQ 0x04
#define L2CAP_CONF_RSP 0x05
#define L2CAP_DISCONN_REQ 0x06
#define L2CAP_DISCONN_RSP 0x07
#define L2CAP_ECHO_REQ 0x08
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b
#define L2CAP_CREATE_REQ 0x0c
#define L2CAP_CREATE_RSP 0x0d
#define L2CAP_MOVE_REQ 0x0e
#define L2CAP_MOVE_RSP 0x0f
#define L2CAP_MOVE_CFM 0x10
#define L2CAP_MOVE_CFM_RSP 0x11
/* L2CAP extended feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001
#define L2CAP_FEAT_RETRANS 0x00000002
#define L2CAP_FEAT_BIDIR_QOS 0x00000004
#define L2CAP_FEAT_ERTM 0x00000008
#define L2CAP_FEAT_STREAMING 0x00000010
#define L2CAP_FEAT_FCS 0x00000020
#define L2CAP_FEAT_EXT_FLOW 0x00000040
#define L2CAP_FEAT_FIXED_CHAN 0x00000080
#define L2CAP_FEAT_EXT_WINDOW 0x00000100
#define L2CAP_FEAT_UCD 0x00000200
/* L2CAP fixed channels */
#define L2CAP_FC_L2CAP 0x02
#define L2CAP_FC_CONNLESS 0x04
#define L2CAP_FC_A2MP 0x08
/* L2CAP structures */
typedef struct {
uint16_t len;
uint16_t cid;
} __attribute__ ((packed)) l2cap_hdr;
#define L2CAP_HDR_SIZE 4
typedef struct {
uint8_t code;
uint8_t ident;
uint16_t len;
} __attribute__ ((packed)) l2cap_cmd_hdr;
#define L2CAP_CMD_HDR_SIZE 4
typedef struct {
uint16_t reason;
} __attribute__ ((packed)) l2cap_cmd_rej;
#define L2CAP_CMD_REJ_SIZE 2
typedef struct {
uint16_t psm;
uint16_t scid;
} __attribute__ ((packed)) l2cap_conn_req;
#define L2CAP_CONN_REQ_SIZE 4
typedef struct {
uint16_t dcid;
uint16_t scid;
uint16_t result;
uint16_t status;
} __attribute__ ((packed)) l2cap_conn_rsp;
#define L2CAP_CONN_RSP_SIZE 8
/* connect result */
#define L2CAP_CR_SUCCESS 0x0000
#define L2CAP_CR_PEND 0x0001
#define L2CAP_CR_BAD_PSM 0x0002
#define L2CAP_CR_SEC_BLOCK 0x0003
#define L2CAP_CR_NO_MEM 0x0004
/* connect status */
#define L2CAP_CS_NO_INFO 0x0000
#define L2CAP_CS_AUTHEN_PEND 0x0001
#define L2CAP_CS_AUTHOR_PEND 0x0002
typedef struct {
uint16_t dcid;
uint16_t flags;
uint8_t data[0];
} __attribute__ ((packed)) l2cap_conf_req;
#define L2CAP_CONF_REQ_SIZE 4
typedef struct {
uint16_t scid;
uint16_t flags;
uint16_t result;
uint8_t data[0];
} __attribute__ ((packed)) l2cap_conf_rsp;
#define L2CAP_CONF_RSP_SIZE 6
#define L2CAP_CONF_SUCCESS 0x0000
#define L2CAP_CONF_UNACCEPT 0x0001
#define L2CAP_CONF_REJECT 0x0002
#define L2CAP_CONF_UNKNOWN 0x0003
#define L2CAP_CONF_PENDING 0x0004
#define L2CAP_CONF_EFS_REJECT 0x0005
typedef struct {
uint8_t type;
uint8_t len;
uint8_t val[0];
} __attribute__ ((packed)) l2cap_conf_opt;
#define L2CAP_CONF_OPT_SIZE 2
#define L2CAP_CONF_MTU 0x01
#define L2CAP_CONF_FLUSH_TO 0x02
#define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_FCS 0x05
#define L2CAP_CONF_EFS 0x06
#define L2CAP_CONF_EWS 0x07
#define L2CAP_CONF_MAX_SIZE 22
#define L2CAP_MODE_BASIC 0x00
#define L2CAP_MODE_RETRANS 0x01
#define L2CAP_MODE_FLOWCTL 0x02
#define L2CAP_MODE_ERTM 0x03
#define L2CAP_MODE_STREAMING 0x04
#define L2CAP_SERVTYPE_NOTRAFFIC 0x00
#define L2CAP_SERVTYPE_BESTEFFORT 0x01
#define L2CAP_SERVTYPE_GUARANTEED 0x02
typedef struct {
uint16_t dcid;
uint16_t scid;
} __attribute__ ((packed)) l2cap_disconn_req;
#define L2CAP_DISCONN_REQ_SIZE 4
typedef struct {
uint16_t dcid;
uint16_t scid;
} __attribute__ ((packed)) l2cap_disconn_rsp;
#define L2CAP_DISCONN_RSP_SIZE 4
typedef struct {
uint16_t type;
} __attribute__ ((packed)) l2cap_info_req;
#define L2CAP_INFO_REQ_SIZE 2
typedef struct {
uint16_t type;
uint16_t result;
uint8_t data[0];
} __attribute__ ((packed)) l2cap_info_rsp;
#define L2CAP_INFO_RSP_SIZE 4
/* info type */
#define L2CAP_IT_CL_MTU 0x0001
#define L2CAP_IT_FEAT_MASK 0x0002
/* info result */
#define L2CAP_IR_SUCCESS 0x0000
#define L2CAP_IR_NOTSUPP 0x0001
typedef struct {
uint16_t psm;
uint16_t scid;
uint8_t id;
} __attribute__ ((packed)) l2cap_create_req;
#define L2CAP_CREATE_REQ_SIZE 5
typedef struct {
uint16_t dcid;
uint16_t scid;
uint16_t result;
uint16_t status;
} __attribute__ ((packed)) l2cap_create_rsp;
#define L2CAP_CREATE_RSP_SIZE 8
typedef struct {
uint16_t icid;
uint8_t id;
} __attribute__ ((packed)) l2cap_move_req;
#define L2CAP_MOVE_REQ_SIZE 3
typedef struct {
uint16_t icid;
uint16_t result;
} __attribute__ ((packed)) l2cap_move_rsp;
#define L2CAP_MOVE_RSP_SIZE 4
typedef struct {
uint16_t icid;
uint16_t result;
} __attribute__ ((packed)) l2cap_move_cfm;
#define L2CAP_MOVE_CFM_SIZE 4
typedef struct {
uint16_t icid;
} __attribute__ ((packed)) l2cap_move_cfm_rsp;
#define L2CAP_MOVE_CFM_RSP_SIZE 2
#ifdef __cplusplus
}
#endif
#endif /* __L2CAP_H */

View File

@@ -0,0 +1,99 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __RFCOMM_H
#define __RFCOMM_H
#ifdef __cplusplus
extern "C" {
#endif
#include <sys/socket.h>
/* RFCOMM defaults */
#define RFCOMM_DEFAULT_MTU 127
#define RFCOMM_PSM 3
/* RFCOMM socket address */
struct sockaddr_rc {
sa_family_t rc_family;
bdaddr_t rc_bdaddr;
uint8_t rc_channel;
};
/* RFCOMM socket options */
#define RFCOMM_CONNINFO 0x02
struct rfcomm_conninfo {
uint16_t hci_handle;
uint8_t dev_class[3];
};
#define RFCOMM_LM 0x03
#define RFCOMM_LM_MASTER 0x0001
#define RFCOMM_LM_AUTH 0x0002
#define RFCOMM_LM_ENCRYPT 0x0004
#define RFCOMM_LM_TRUSTED 0x0008
#define RFCOMM_LM_RELIABLE 0x0010
#define RFCOMM_LM_SECURE 0x0020
/* RFCOMM TTY support */
#define RFCOMM_MAX_DEV 256
#define RFCOMMCREATEDEV _IOW('R', 200, int)
#define RFCOMMRELEASEDEV _IOW('R', 201, int)
#define RFCOMMGETDEVLIST _IOR('R', 210, int)
#define RFCOMMGETDEVINFO _IOR('R', 211, int)
struct rfcomm_dev_req {
int16_t dev_id;
uint32_t flags;
bdaddr_t src;
bdaddr_t dst;
uint8_t channel;
};
#define RFCOMM_REUSE_DLC 0
#define RFCOMM_RELEASE_ONHUP 1
#define RFCOMM_HANGUP_NOW 2
#define RFCOMM_TTY_ATTACHED 3
struct rfcomm_dev_info {
int16_t id;
uint32_t flags;
uint16_t state;
bdaddr_t src;
bdaddr_t dst;
uint8_t channel;
};
struct rfcomm_dev_list_req {
uint16_t dev_num;
struct rfcomm_dev_info dev_info[0];
};
#ifdef __cplusplus
}
#endif
#endif /* __RFCOMM_H */

View File

@@ -0,0 +1,62 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __SCO_H
#define __SCO_H
#ifdef __cplusplus
extern "C" {
#endif
/* SCO defaults */
#define SCO_DEFAULT_MTU 500
#define SCO_DEFAULT_FLUSH_TO 0xFFFF
#define SCO_CONN_TIMEOUT (HZ * 40)
#define SCO_DISCONN_TIMEOUT (HZ * 2)
#define SCO_CONN_IDLE_TIMEOUT (HZ * 60)
/* SCO socket address */
struct sockaddr_sco {
sa_family_t sco_family;
bdaddr_t sco_bdaddr;
};
/* set/get sockopt defines */
#define SCO_OPTIONS 0x01
struct sco_options {
uint16_t mtu;
};
#define SCO_CONNINFO 0x02
struct sco_conninfo {
uint16_t hci_handle;
uint8_t dev_class[3];
};
#ifdef __cplusplus
}
#endif
#endif /* __SCO_H */

View File

@@ -0,0 +1,532 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
* 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
*
*/
#ifndef __SDP_H
#define __SDP_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <bluetooth/bluetooth.h>
#define SDP_UNIX_PATH "/var/run/sdp"
#define SDP_RESPONSE_TIMEOUT 20
#define SDP_REQ_BUFFER_SIZE 2048
#define SDP_RSP_BUFFER_SIZE 65535
#define SDP_PDU_CHUNK_SIZE 1024
/*
* All definitions are based on Bluetooth Assigned Numbers
* of the Bluetooth Specification
*/
#define SDP_PSM 0x0001
/*
* Protocol UUIDs
*/
#define SDP_UUID 0x0001
#define UDP_UUID 0x0002
#define RFCOMM_UUID 0x0003
#define TCP_UUID 0x0004
#define TCS_BIN_UUID 0x0005
#define TCS_AT_UUID 0x0006
#define ATT_UUID 0x0007
#define OBEX_UUID 0x0008
#define IP_UUID 0x0009
#define FTP_UUID 0x000a
#define HTTP_UUID 0x000c
#define WSP_UUID 0x000e
#define BNEP_UUID 0x000f
#define UPNP_UUID 0x0010
#define HIDP_UUID 0x0011
#define HCRP_CTRL_UUID 0x0012
#define HCRP_DATA_UUID 0x0014
#define HCRP_NOTE_UUID 0x0016
#define AVCTP_UUID 0x0017
#define AVDTP_UUID 0x0019
#define CMTP_UUID 0x001b
#define UDI_UUID 0x001d
#define MCAP_CTRL_UUID 0x001e
#define MCAP_DATA_UUID 0x001f
#define L2CAP_UUID 0x0100
/*
* Service class identifiers of standard services and service groups
*/
#define SDP_SERVER_SVCLASS_ID 0x1000
#define BROWSE_GRP_DESC_SVCLASS_ID 0x1001
#define PUBLIC_BROWSE_GROUP 0x1002
#define SERIAL_PORT_SVCLASS_ID 0x1101
#define LAN_ACCESS_SVCLASS_ID 0x1102
#define DIALUP_NET_SVCLASS_ID 0x1103
#define IRMC_SYNC_SVCLASS_ID 0x1104
#define OBEX_OBJPUSH_SVCLASS_ID 0x1105
#define OBEX_FILETRANS_SVCLASS_ID 0x1106
#define IRMC_SYNC_CMD_SVCLASS_ID 0x1107
#define HEADSET_SVCLASS_ID 0x1108
#define CORDLESS_TELEPHONY_SVCLASS_ID 0x1109
#define AUDIO_SOURCE_SVCLASS_ID 0x110a
#define AUDIO_SINK_SVCLASS_ID 0x110b
#define AV_REMOTE_TARGET_SVCLASS_ID 0x110c
#define ADVANCED_AUDIO_SVCLASS_ID 0x110d
#define AV_REMOTE_SVCLASS_ID 0x110e
#define AV_REMOTE_CONTROLLER_SVCLASS_ID 0x110f
#define INTERCOM_SVCLASS_ID 0x1110
#define FAX_SVCLASS_ID 0x1111
#define HEADSET_AGW_SVCLASS_ID 0x1112
#define WAP_SVCLASS_ID 0x1113
#define WAP_CLIENT_SVCLASS_ID 0x1114
#define PANU_SVCLASS_ID 0x1115
#define NAP_SVCLASS_ID 0x1116
#define GN_SVCLASS_ID 0x1117
#define DIRECT_PRINTING_SVCLASS_ID 0x1118
#define REFERENCE_PRINTING_SVCLASS_ID 0x1119
#define IMAGING_SVCLASS_ID 0x111a
#define IMAGING_RESPONDER_SVCLASS_ID 0x111b
#define IMAGING_ARCHIVE_SVCLASS_ID 0x111c
#define IMAGING_REFOBJS_SVCLASS_ID 0x111d
#define HANDSFREE_SVCLASS_ID 0x111e
#define HANDSFREE_AGW_SVCLASS_ID 0x111f
#define DIRECT_PRT_REFOBJS_SVCLASS_ID 0x1120
#define REFLECTED_UI_SVCLASS_ID 0x1121
#define BASIC_PRINTING_SVCLASS_ID 0x1122
#define PRINTING_STATUS_SVCLASS_ID 0x1123
#define HID_SVCLASS_ID 0x1124
#define HCR_SVCLASS_ID 0x1125
#define HCR_PRINT_SVCLASS_ID 0x1126
#define HCR_SCAN_SVCLASS_ID 0x1127
#define CIP_SVCLASS_ID 0x1128
#define VIDEO_CONF_GW_SVCLASS_ID 0x1129
#define UDI_MT_SVCLASS_ID 0x112a
#define UDI_TA_SVCLASS_ID 0x112b
#define AV_SVCLASS_ID 0x112c
#define SAP_SVCLASS_ID 0x112d
#define PBAP_PCE_SVCLASS_ID 0x112e
#define PBAP_PSE_SVCLASS_ID 0x112f
#define PBAP_SVCLASS_ID 0x1130
#define MAP_MSE_SVCLASS_ID 0x1132
#define MAP_MCE_SVCLASS_ID 0x1133
#define MAP_SVCLASS_ID 0x1134
#define GNSS_SVCLASS_ID 0x1135
#define GNSS_SERVER_SVCLASS_ID 0x1136
#define PNP_INFO_SVCLASS_ID 0x1200
#define GENERIC_NETWORKING_SVCLASS_ID 0x1201
#define GENERIC_FILETRANS_SVCLASS_ID 0x1202
#define GENERIC_AUDIO_SVCLASS_ID 0x1203
#define GENERIC_TELEPHONY_SVCLASS_ID 0x1204
#define UPNP_SVCLASS_ID 0x1205
#define UPNP_IP_SVCLASS_ID 0x1206
#define UPNP_PAN_SVCLASS_ID 0x1300
#define UPNP_LAP_SVCLASS_ID 0x1301
#define UPNP_L2CAP_SVCLASS_ID 0x1302
#define VIDEO_SOURCE_SVCLASS_ID 0x1303
#define VIDEO_SINK_SVCLASS_ID 0x1304
#define VIDEO_DISTRIBUTION_SVCLASS_ID 0x1305
#define HDP_SVCLASS_ID 0x1400
#define HDP_SOURCE_SVCLASS_ID 0x1401
#define HDP_SINK_SVCLASS_ID 0x1402
#define APPLE_AGENT_SVCLASS_ID 0x2112
#define GENERIC_ATTRIB_SVCLASS_ID 0x1801
/*
* Standard profile descriptor identifiers; note these
* may be identical to some of the service classes defined above
*/
#define SDP_SERVER_PROFILE_ID SDP_SERVER_SVCLASS_ID
#define BROWSE_GRP_DESC_PROFILE_ID BROWSE_GRP_DESC_SVCLASS_ID
#define SERIAL_PORT_PROFILE_ID SERIAL_PORT_SVCLASS_ID
#define LAN_ACCESS_PROFILE_ID LAN_ACCESS_SVCLASS_ID
#define DIALUP_NET_PROFILE_ID DIALUP_NET_SVCLASS_ID
#define IRMC_SYNC_PROFILE_ID IRMC_SYNC_SVCLASS_ID
#define OBEX_OBJPUSH_PROFILE_ID OBEX_OBJPUSH_SVCLASS_ID
#define OBEX_FILETRANS_PROFILE_ID OBEX_FILETRANS_SVCLASS_ID
#define IRMC_SYNC_CMD_PROFILE_ID IRMC_SYNC_CMD_SVCLASS_ID
#define HEADSET_PROFILE_ID HEADSET_SVCLASS_ID
#define CORDLESS_TELEPHONY_PROFILE_ID CORDLESS_TELEPHONY_SVCLASS_ID
#define AUDIO_SOURCE_PROFILE_ID AUDIO_SOURCE_SVCLASS_ID
#define AUDIO_SINK_PROFILE_ID AUDIO_SINK_SVCLASS_ID
#define AV_REMOTE_TARGET_PROFILE_ID AV_REMOTE_TARGET_SVCLASS_ID
#define ADVANCED_AUDIO_PROFILE_ID ADVANCED_AUDIO_SVCLASS_ID
#define AV_REMOTE_PROFILE_ID AV_REMOTE_SVCLASS_ID
#define VIDEO_CONF_PROFILE_ID VIDEO_CONF_SVCLASS_ID
#define INTERCOM_PROFILE_ID INTERCOM_SVCLASS_ID
#define FAX_PROFILE_ID FAX_SVCLASS_ID
#define HEADSET_AGW_PROFILE_ID HEADSET_AGW_SVCLASS_ID
#define WAP_PROFILE_ID WAP_SVCLASS_ID
#define WAP_CLIENT_PROFILE_ID WAP_CLIENT_SVCLASS_ID
#define PANU_PROFILE_ID PANU_SVCLASS_ID
#define NAP_PROFILE_ID NAP_SVCLASS_ID
#define GN_PROFILE_ID GN_SVCLASS_ID
#define DIRECT_PRINTING_PROFILE_ID DIRECT_PRINTING_SVCLASS_ID
#define REFERENCE_PRINTING_PROFILE_ID REFERENCE_PRINTING_SVCLASS_ID
#define IMAGING_PROFILE_ID IMAGING_SVCLASS_ID
#define IMAGING_RESPONDER_PROFILE_ID IMAGING_RESPONDER_SVCLASS_ID
#define IMAGING_ARCHIVE_PROFILE_ID IMAGING_ARCHIVE_SVCLASS_ID
#define IMAGING_REFOBJS_PROFILE_ID IMAGING_REFOBJS_SVCLASS_ID
#define HANDSFREE_PROFILE_ID HANDSFREE_SVCLASS_ID
#define HANDSFREE_AGW_PROFILE_ID HANDSFREE_AGW_SVCLASS_ID
#define DIRECT_PRT_REFOBJS_PROFILE_ID DIRECT_PRT_REFOBJS_SVCLASS_ID
#define REFLECTED_UI_PROFILE_ID REFLECTED_UI_SVCLASS_ID
#define BASIC_PRINTING_PROFILE_ID BASIC_PRINTING_SVCLASS_ID
#define PRINTING_STATUS_PROFILE_ID PRINTING_STATUS_SVCLASS_ID
#define HID_PROFILE_ID HID_SVCLASS_ID
#define HCR_PROFILE_ID HCR_SCAN_SVCLASS_ID
#define HCR_PRINT_PROFILE_ID HCR_PRINT_SVCLASS_ID
#define HCR_SCAN_PROFILE_ID HCR_SCAN_SVCLASS_ID
#define CIP_PROFILE_ID CIP_SVCLASS_ID
#define VIDEO_CONF_GW_PROFILE_ID VIDEO_CONF_GW_SVCLASS_ID
#define UDI_MT_PROFILE_ID UDI_MT_SVCLASS_ID
#define UDI_TA_PROFILE_ID UDI_TA_SVCLASS_ID
#define AV_PROFILE_ID AV_SVCLASS_ID
#define SAP_PROFILE_ID SAP_SVCLASS_ID
#define PBAP_PCE_PROFILE_ID PBAP_PCE_SVCLASS_ID
#define PBAP_PSE_PROFILE_ID PBAP_PSE_SVCLASS_ID
#define PBAP_PROFILE_ID PBAP_SVCLASS_ID
#define PNP_INFO_PROFILE_ID PNP_INFO_SVCLASS_ID
#define GENERIC_NETWORKING_PROFILE_ID GENERIC_NETWORKING_SVCLASS_ID
#define GENERIC_FILETRANS_PROFILE_ID GENERIC_FILETRANS_SVCLASS_ID
#define GENERIC_AUDIO_PROFILE_ID GENERIC_AUDIO_SVCLASS_ID
#define GENERIC_TELEPHONY_PROFILE_ID GENERIC_TELEPHONY_SVCLASS_ID
#define UPNP_PROFILE_ID UPNP_SVCLASS_ID
#define UPNP_IP_PROFILE_ID UPNP_IP_SVCLASS_ID
#define UPNP_PAN_PROFILE_ID UPNP_PAN_SVCLASS_ID
#define UPNP_LAP_PROFILE_ID UPNP_LAP_SVCLASS_ID
#define UPNP_L2CAP_PROFILE_ID UPNP_L2CAP_SVCLASS_ID
#define VIDEO_SOURCE_PROFILE_ID VIDEO_SOURCE_SVCLASS_ID
#define VIDEO_SINK_PROFILE_ID VIDEO_SINK_SVCLASS_ID
#define VIDEO_DISTRIBUTION_PROFILE_ID VIDEO_DISTRIBUTION_SVCLASS_ID
#define HDP_PROFILE_ID HDP_SVCLASS_ID
#define HDP_SOURCE_PROFILE_ID HDP_SOURCE_SVCLASS_ID
#define HDP_SINK_PROFILE_ID HDP_SINK_SVCLASS_ID
#define APPLE_AGENT_PROFILE_ID APPLE_AGENT_SVCLASS_ID
#define GENERIC_ACCESS_PROFILE_ID 0x1800
#define GENERIC_ATTRIB_PROFILE_ID GENERIC_ATTRIB_SVCLASS_ID
/*
* Compatibility macros for the old MDP acronym
*/
#define MDP_SVCLASS_ID HDP_SVCLASS_ID
#define MDP_SOURCE_SVCLASS_ID HDP_SOURCE_SVCLASS_ID
#define MDP_SINK_SVCLASS_ID HDP_SINK_SVCLASS_ID
#define MDP_PROFILE_ID HDP_PROFILE_ID
#define MDP_SOURCE_PROFILE_ID HDP_SOURCE_PROFILE_ID
#define MDP_SINK_PROFILE_ID HDP_SINK_PROFILE_ID
/*
* Attribute identifier codes
*/
#define SDP_SERVER_RECORD_HANDLE 0x0000
/*
* Possible values for attribute-id are listed below.
* See SDP Spec, section "Service Attribute Definitions" for more details.
*/
#define SDP_ATTR_RECORD_HANDLE 0x0000
#define SDP_ATTR_SVCLASS_ID_LIST 0x0001
#define SDP_ATTR_RECORD_STATE 0x0002
#define SDP_ATTR_SERVICE_ID 0x0003
#define SDP_ATTR_PROTO_DESC_LIST 0x0004
#define SDP_ATTR_BROWSE_GRP_LIST 0x0005
#define SDP_ATTR_LANG_BASE_ATTR_ID_LIST 0x0006
#define SDP_ATTR_SVCINFO_TTL 0x0007
#define SDP_ATTR_SERVICE_AVAILABILITY 0x0008
#define SDP_ATTR_PFILE_DESC_LIST 0x0009
#define SDP_ATTR_DOC_URL 0x000a
#define SDP_ATTR_CLNT_EXEC_URL 0x000b
#define SDP_ATTR_ICON_URL 0x000c
#define SDP_ATTR_ADD_PROTO_DESC_LIST 0x000d
#define SDP_ATTR_GROUP_ID 0x0200
#define SDP_ATTR_IP_SUBNET 0x0200
#define SDP_ATTR_VERSION_NUM_LIST 0x0200
#define SDP_ATTR_SUPPORTED_FEATURES_LIST 0x0200
#define SDP_ATTR_GOEP_L2CAP_PSM 0x0200
#define SDP_ATTR_SVCDB_STATE 0x0201
#define SDP_ATTR_SERVICE_VERSION 0x0300
#define SDP_ATTR_EXTERNAL_NETWORK 0x0301
#define SDP_ATTR_SUPPORTED_DATA_STORES_LIST 0x0301
#define SDP_ATTR_DATA_EXCHANGE_SPEC 0x0301
#define SDP_ATTR_NETWORK 0x0301
#define SDP_ATTR_FAX_CLASS1_SUPPORT 0x0302
#define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL 0x0302
#define SDP_ATTR_MCAP_SUPPORTED_PROCEDURES 0x0302
#define SDP_ATTR_FAX_CLASS20_SUPPORT 0x0303
#define SDP_ATTR_SUPPORTED_FORMATS_LIST 0x0303
#define SDP_ATTR_FAX_CLASS2_SUPPORT 0x0304
#define SDP_ATTR_AUDIO_FEEDBACK_SUPPORT 0x0305
#define SDP_ATTR_NETWORK_ADDRESS 0x0306
#define SDP_ATTR_WAP_GATEWAY 0x0307
#define SDP_ATTR_HOMEPAGE_URL 0x0308
#define SDP_ATTR_WAP_STACK_TYPE 0x0309
#define SDP_ATTR_SECURITY_DESC 0x030a
#define SDP_ATTR_NET_ACCESS_TYPE 0x030b
#define SDP_ATTR_MAX_NET_ACCESSRATE 0x030c
#define SDP_ATTR_IP4_SUBNET 0x030d
#define SDP_ATTR_IP6_SUBNET 0x030e
#define SDP_ATTR_SUPPORTED_CAPABILITIES 0x0310
#define SDP_ATTR_SUPPORTED_FEATURES 0x0311
#define SDP_ATTR_SUPPORTED_FUNCTIONS 0x0312
#define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY 0x0313
#define SDP_ATTR_SUPPORTED_REPOSITORIES 0x0314
#define SDP_ATTR_MAS_INSTANCE_ID 0x0315
#define SDP_ATTR_SUPPORTED_MESSAGE_TYPES 0x0316
#define SDP_ATTR_SPECIFICATION_ID 0x0200
#define SDP_ATTR_VENDOR_ID 0x0201
#define SDP_ATTR_PRODUCT_ID 0x0202
#define SDP_ATTR_VERSION 0x0203
#define SDP_ATTR_PRIMARY_RECORD 0x0204
#define SDP_ATTR_VENDOR_ID_SOURCE 0x0205
#define SDP_ATTR_HID_DEVICE_RELEASE_NUMBER 0x0200
#define SDP_ATTR_HID_PARSER_VERSION 0x0201
#define SDP_ATTR_HID_DEVICE_SUBCLASS 0x0202
#define SDP_ATTR_HID_COUNTRY_CODE 0x0203
#define SDP_ATTR_HID_VIRTUAL_CABLE 0x0204
#define SDP_ATTR_HID_RECONNECT_INITIATE 0x0205
#define SDP_ATTR_HID_DESCRIPTOR_LIST 0x0206
#define SDP_ATTR_HID_LANG_ID_BASE_LIST 0x0207
#define SDP_ATTR_HID_SDP_DISABLE 0x0208
#define SDP_ATTR_HID_BATTERY_POWER 0x0209
#define SDP_ATTR_HID_REMOTE_WAKEUP 0x020a
#define SDP_ATTR_HID_PROFILE_VERSION 0x020b
#define SDP_ATTR_HID_SUPERVISION_TIMEOUT 0x020c
#define SDP_ATTR_HID_NORMALLY_CONNECTABLE 0x020d
#define SDP_ATTR_HID_BOOT_DEVICE 0x020e
/*
* These identifiers are based on the SDP spec stating that
* "base attribute id of the primary (universal) language must be 0x0100"
*
* Other languages should have their own offset; e.g.:
* #define XXXLangBase yyyy
* #define AttrServiceName_XXX 0x0000+XXXLangBase
*/
#define SDP_PRIMARY_LANG_BASE 0x0100
#define SDP_ATTR_SVCNAME_PRIMARY 0x0000 + SDP_PRIMARY_LANG_BASE
#define SDP_ATTR_SVCDESC_PRIMARY 0x0001 + SDP_PRIMARY_LANG_BASE
#define SDP_ATTR_PROVNAME_PRIMARY 0x0002 + SDP_PRIMARY_LANG_BASE
/*
* The Data representation in SDP PDUs (pps 339, 340 of BT SDP Spec)
* These are the exact data type+size descriptor values
* that go into the PDU buffer.
*
* The datatype (leading 5bits) + size descriptor (last 3 bits)
* is 8 bits. The size descriptor is critical to extract the
* right number of bytes for the data value from the PDU.
*
* For most basic types, the datatype+size descriptor is
* straightforward. However for constructed types and strings,
* the size of the data is in the next "n" bytes following the
* 8 bits (datatype+size) descriptor. Exactly what the "n" is
* specified in the 3 bits of the data size descriptor.
*
* TextString and URLString can be of size 2^{8, 16, 32} bytes
* DataSequence and DataSequenceAlternates can be of size 2^{8, 16, 32}
* The size are computed post-facto in the API and are not known apriori
*/
#define SDP_DATA_NIL 0x00
#define SDP_UINT8 0x08
#define SDP_UINT16 0x09
#define SDP_UINT32 0x0A
#define SDP_UINT64 0x0B
#define SDP_UINT128 0x0C
#define SDP_INT8 0x10
#define SDP_INT16 0x11
#define SDP_INT32 0x12
#define SDP_INT64 0x13
#define SDP_INT128 0x14
#define SDP_UUID_UNSPEC 0x18
#define SDP_UUID16 0x19
#define SDP_UUID32 0x1A
#define SDP_UUID128 0x1C
#define SDP_TEXT_STR_UNSPEC 0x20
#define SDP_TEXT_STR8 0x25
#define SDP_TEXT_STR16 0x26
#define SDP_TEXT_STR32 0x27
#define SDP_BOOL 0x28
#define SDP_SEQ_UNSPEC 0x30
#define SDP_SEQ8 0x35
#define SDP_SEQ16 0x36
#define SDP_SEQ32 0x37
#define SDP_ALT_UNSPEC 0x38
#define SDP_ALT8 0x3D
#define SDP_ALT16 0x3E
#define SDP_ALT32 0x3F
#define SDP_URL_STR_UNSPEC 0x40
#define SDP_URL_STR8 0x45
#define SDP_URL_STR16 0x46
#define SDP_URL_STR32 0x47
/*
* The PDU identifiers of SDP packets between client and server
*/
#define SDP_ERROR_RSP 0x01
#define SDP_SVC_SEARCH_REQ 0x02
#define SDP_SVC_SEARCH_RSP 0x03
#define SDP_SVC_ATTR_REQ 0x04
#define SDP_SVC_ATTR_RSP 0x05
#define SDP_SVC_SEARCH_ATTR_REQ 0x06
#define SDP_SVC_SEARCH_ATTR_RSP 0x07
/*
* Some additions to support service registration.
* These are outside the scope of the Bluetooth specification
*/
#define SDP_SVC_REGISTER_REQ 0x75
#define SDP_SVC_REGISTER_RSP 0x76
#define SDP_SVC_UPDATE_REQ 0x77
#define SDP_SVC_UPDATE_RSP 0x78
#define SDP_SVC_REMOVE_REQ 0x79
#define SDP_SVC_REMOVE_RSP 0x80
/*
* SDP Error codes
*/
#define SDP_INVALID_VERSION 0x0001
#define SDP_INVALID_RECORD_HANDLE 0x0002
#define SDP_INVALID_SYNTAX 0x0003
#define SDP_INVALID_PDU_SIZE 0x0004
#define SDP_INVALID_CSTATE 0x0005
/*
* SDP PDU
*/
typedef struct {
uint8_t pdu_id;
uint16_t tid;
uint16_t plen;
} __attribute__ ((packed)) sdp_pdu_hdr_t;
/*
* Common definitions for attributes in the SDP.
* Should the type of any of these change, you need only make a change here.
*/
typedef struct {
uint8_t type;
union {
uint16_t uuid16;
uint32_t uuid32;
uint128_t uuid128;
} value;
} uuid_t;
#define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || \
(x) == SDP_UUID128)
#define SDP_IS_ALT(x) ((x) == SDP_ALT8 || (x) == SDP_ALT16 || (x) == SDP_ALT32)
#define SDP_IS_SEQ(x) ((x) == SDP_SEQ8 || (x) == SDP_SEQ16 || (x) == SDP_SEQ32)
#define SDP_IS_TEXT_STR(x) ((x) == SDP_TEXT_STR8 || (x) == SDP_TEXT_STR16 || \
(x) == SDP_TEXT_STR32)
typedef struct _sdp_list sdp_list_t;
struct _sdp_list {
sdp_list_t *next;
void *data;
};
/*
* User-visible strings can be in many languages
* in addition to the universal language.
*
* Language meta-data includes language code in ISO639
* followed by the encoding format. The third field in this
* structure is the attribute offset for the language.
* User-visible strings in the specified language can be
* obtained at this offset.
*/
typedef struct {
uint16_t code_ISO639;
uint16_t encoding;
uint16_t base_offset;
} sdp_lang_attr_t;
/*
* Profile descriptor is the Bluetooth profile metadata. If a
* service conforms to a well-known profile, then its profile
* identifier (UUID) is an attribute of the service. In addition,
* if the profile has a version number it is specified here.
*/
typedef struct {
uuid_t uuid;
uint16_t version;
} sdp_profile_desc_t;
typedef struct {
uint8_t major;
uint8_t minor;
} sdp_version_t;
typedef struct {
uint8_t *data;
uint32_t data_size;
uint32_t buf_size;
} sdp_buf_t;
typedef struct {
uint32_t handle;
/* Search pattern: a sequence of all UUIDs seen in this record */
sdp_list_t *pattern;
sdp_list_t *attrlist;
/* Main service class for Extended Inquiry Response */
uuid_t svclass;
} sdp_record_t;
typedef struct sdp_data_struct sdp_data_t;
struct sdp_data_struct {
uint8_t dtd;
uint16_t attrId;
union {
int8_t int8;
int16_t int16;
int32_t int32;
int64_t int64;
uint128_t int128;
uint8_t uint8;
uint16_t uint16;
uint32_t uint32;
uint64_t uint64;
uint128_t uint128;
uuid_t uuid;
char *str;
sdp_data_t *dataseq;
} val;
sdp_data_t *next;
int unitSize;
};
#ifdef __cplusplus
}
#endif
#endif /* __SDP_H */

View File

@@ -0,0 +1,633 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2001-2002 Nokia Corporation
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
* Copyright (C) 2002-2003 Stephen Crane <steve.crane@rococosoft.com>
*
*
* 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
*
*/
#ifndef __SDP_LIB_H
#define __SDP_LIB_H
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#ifdef __cplusplus
extern "C" {
#endif
/*
* SDP lists
*/
typedef void(*sdp_list_func_t)(void *, void *);
typedef void(*sdp_free_func_t)(void *);
typedef int (*sdp_comp_func_t)(const void *, const void *);
sdp_list_t *sdp_list_append(sdp_list_t *list, void *d);
sdp_list_t *sdp_list_remove(sdp_list_t *list, void *d);
sdp_list_t *sdp_list_insert_sorted(sdp_list_t *list, void *data, sdp_comp_func_t f);
void sdp_list_free(sdp_list_t *list, sdp_free_func_t f);
static inline int sdp_list_len(const sdp_list_t *list)
{
int n = 0;
for (; list; list = list->next)
n++;
return n;
}
static inline sdp_list_t *sdp_list_find(sdp_list_t *list, void *u, sdp_comp_func_t f)
{
for (; list; list = list->next)
if (f(list->data, u) == 0)
return list;
return NULL;
}
static inline void sdp_list_foreach(sdp_list_t *list, sdp_list_func_t f, void *u)
{
for (; list; list = list->next)
f(list->data, u);
}
/*
* Values of the flags parameter to sdp_record_register
*/
#define SDP_RECORD_PERSIST 0x01
#define SDP_DEVICE_RECORD 0x02
/*
* Values of the flags parameter to sdp_connect
*/
#define SDP_RETRY_IF_BUSY 0x01
#define SDP_WAIT_ON_CLOSE 0x02
#define SDP_NON_BLOCKING 0x04
/*
* a session with an SDP server
*/
typedef struct {
int sock;
int state;
int local;
int flags;
uint16_t tid; /* Current transaction ID */
void *priv;
} sdp_session_t;
typedef enum {
/*
* Attributes are specified as individual elements
*/
SDP_ATTR_REQ_INDIVIDUAL = 1,
/*
* Attributes are specified as a range
*/
SDP_ATTR_REQ_RANGE
} sdp_attrreq_type_t;
/*
* When the pdu_id(type) is a sdp error response, check the status value
* to figure out the error reason. For status values 0x0001-0x0006 check
* Bluetooth SPEC. If the status is 0xffff, call sdp_get_error function
* to get the real reason:
* - wrong transaction ID(EPROTO)
* - wrong PDU id or(EPROTO)
* - I/O error
*/
typedef void sdp_callback_t(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *udata);
/*
* create an L2CAP connection to a Bluetooth device
*
* INPUT:
*
* bdaddr_t *src:
* Address of the local device to use to make the connection
* (or BDADDR_ANY)
*
* bdaddr_t *dst:
* Address of the SDP server device
*/
sdp_session_t *sdp_connect(const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags);
int sdp_close(sdp_session_t *session);
int sdp_get_socket(const sdp_session_t *session);
/*
* SDP transaction: functions for asynchronous search.
*/
sdp_session_t *sdp_create(int sk, uint32_t flags);
int sdp_get_error(sdp_session_t *session);
int sdp_process(sdp_session_t *session);
int sdp_set_notify(sdp_session_t *session, sdp_callback_t *func, void *udata);
int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num);
int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
uint16_t sdp_gen_tid(sdp_session_t *session);
/*
* find all devices in the piconet
*/
int sdp_general_inquiry(inquiry_info *ii, int dev_num, int duration, uint8_t *found);
/* flexible extraction of basic attributes - Jean II */
int sdp_get_int_attr(const sdp_record_t *rec, uint16_t attr, int *value);
int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attr, char *value, int valuelen);
/*
* Basic sdp data functions
*/
sdp_data_t *sdp_data_alloc(uint8_t dtd, const void *value);
sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value, uint32_t length);
void sdp_data_free(sdp_data_t *data);
sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attr_id);
sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len);
sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length, int len);
sdp_data_t *sdp_seq_append(sdp_data_t *seq, sdp_data_t *data);
int sdp_attr_add(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
void sdp_attr_remove(sdp_record_t *rec, uint16_t attr);
void sdp_attr_replace(sdp_record_t *rec, uint16_t attr, sdp_data_t *data);
int sdp_set_uuidseq_attr(sdp_record_t *rec, uint16_t attr, sdp_list_t *seq);
int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr, sdp_list_t **seqp);
/*
* NOTE that none of the functions below will update the SDP server,
* unless the {register, update}sdp_record_t() function is invoked.
* All functions which return an integer value, return 0 on success
* or -1 on failure.
*/
/*
* Create an attribute and add it to the service record's attribute list.
* This consists of the data type descriptor of the attribute,
* the value of the attribute and the attribute identifier.
*/
int sdp_attr_add_new(sdp_record_t *rec, uint16_t attr, uint8_t dtd, const void *p);
/*
* Set the information attributes of the service record.
* The set of attributes comprises service name, description
* and provider name
*/
void sdp_set_info_attr(sdp_record_t *rec, const char *name, const char *prov, const char *desc);
/*
* Set the ServiceClassID attribute to the sequence specified by seq.
* Note that the identifiers need to be in sorted order from the most
* specific to the most generic service class that this service
* conforms to.
*/
static inline int sdp_set_service_classes(sdp_record_t *rec, sdp_list_t *seq)
{
return sdp_set_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seq);
}
/*
* Get the service classes to which the service conforms.
*
* When set, the list contains elements of ServiceClassIdentifer(uint16_t)
* ordered from most specific to most generic
*/
static inline int sdp_get_service_classes(const sdp_record_t *rec, sdp_list_t **seqp)
{
return sdp_get_uuidseq_attr(rec, SDP_ATTR_SVCLASS_ID_LIST, seqp);
}
/*
* Set the BrowseGroupList attribute to the list specified by seq.
*
* A service can belong to one or more service groups
* and the list comprises such group identifiers (UUIDs)
*/
static inline int sdp_set_browse_groups(sdp_record_t *rec, sdp_list_t *seq)
{
return sdp_set_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seq);
}
/*
* Set the access protocols of the record to those specified in proto
*/
int sdp_set_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
/*
* Set the additional access protocols of the record to those specified in proto
*/
int sdp_set_add_access_protos(sdp_record_t *rec, const sdp_list_t *proto);
/*
* Get protocol port (i.e. PSM for L2CAP, Channel for RFCOMM)
*/
int sdp_get_proto_port(const sdp_list_t *list, int proto);
/*
* Get protocol descriptor.
*/
sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto);
/*
* Set the LanguageBase attributes to the values specified in list
* (a linked list of sdp_lang_attr_t objects, one for each language in
* which user-visible attributes are present).
*/
int sdp_set_lang_attr(sdp_record_t *rec, const sdp_list_t *list);
/*
* Set the ServiceInfoTimeToLive attribute of the service.
* This is the number of seconds that this record is guaranteed
* not to change after being obtained by a client.
*/
static inline int sdp_set_service_ttl(sdp_record_t *rec, uint32_t ttl)
{
return sdp_attr_add_new(rec, SDP_ATTR_SVCINFO_TTL, SDP_UINT32, &ttl);
}
/*
* Set the ServiceRecordState attribute of a service. This is
* guaranteed to change if there is any kind of modification to
* the record.
*/
static inline int sdp_set_record_state(sdp_record_t *rec, uint32_t state)
{
return sdp_attr_add_new(rec, SDP_ATTR_RECORD_STATE, SDP_UINT32, &state);
}
/*
* Set the ServiceID attribute of a service.
*/
void sdp_set_service_id(sdp_record_t *rec, uuid_t uuid);
/*
* Set the GroupID attribute of a service
*/
void sdp_set_group_id(sdp_record_t *rec, uuid_t grouuuid);
/*
* Set the ServiceAvailability attribute of a service.
*
* Note that this represents the relative availability
* of the service: 0x00 means completely unavailable;
* 0xFF means maximum availability.
*/
static inline int sdp_set_service_avail(sdp_record_t *rec, uint8_t avail)
{
return sdp_attr_add_new(rec, SDP_ATTR_SERVICE_AVAILABILITY, SDP_UINT8, &avail);
}
/*
* Set the profile descriptor list attribute of a record.
*
* Each element in the list is an object of type
* sdp_profile_desc_t which is a definition of the
* Bluetooth profile that this service conforms to.
*/
int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *desc);
/*
* Set URL attributes of a record.
*
* ClientExecutableURL: a URL to a client's platform specific (WinCE,
* PalmOS) executable code that can be used to access this service.
*
* DocumentationURL: a URL pointing to service documentation
*
* IconURL: a URL to an icon that can be used to represent this service.
*
* Note: pass NULL for any URLs that you don't want to set or remove
*/
void sdp_set_url_attr(sdp_record_t *rec, const char *clientExecURL, const char *docURL, const char *iconURL);
/*
* a service search request.
*
* INPUT :
*
* sdp_list_t *search
* list containing elements of the search
* pattern. Each entry in the list is a UUID
* of the service to be searched
*
* uint16_t max_rec_num
* An integer specifying the maximum number of
* entries that the client can handle in the response.
*
* OUTPUT :
*
* int return value
* 0
* The request completed successfully. This does not
* mean the requested services were found
* -1
* The request completed unsuccessfully
*
* sdp_list_t *rsp_list
* This variable is set on a successful return if there are
* non-zero service handles. It is a singly linked list of
* service record handles (uint16_t)
*/
int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search, uint16_t max_rec_num, sdp_list_t **rsp_list);
/*
* a service attribute request.
*
* INPUT :
*
* uint32_t handle
* The handle of the service for which the attribute(s) are
* requested
*
* sdp_attrreq_type_t reqtype
* Attribute identifiers are 16 bit unsigned integers specified
* in one of 2 ways described below :
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
* They are the actual attribute identifiers in ascending order
*
* SDP_ATTR_REQ_RANGE - 32bit identifier range
* The high-order 16bits is the start of range
* the low-order 16bits are the end of range
* 0x0000 to 0xFFFF gets all attributes
*
* sdp_list_t *attrid_list
* Singly linked list containing attribute identifiers desired.
* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
*
* OUTPUT :
* int return value
* 0
* The request completed successfully. This does not
* mean the requested services were found
* -1
* The request completed unsuccessfully due to a timeout
*/
sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list);
/*
* This is a service search request combined with the service
* attribute request. First a service class match is done and
* for matching service, requested attributes are extracted
*
* INPUT :
*
* sdp_list_t *search
* Singly linked list containing elements of the search
* pattern. Each entry in the list is a UUID(DataTypeSDP_UUID16)
* of the service to be searched
*
* AttributeSpecification attrSpec
* Attribute identifiers are 16 bit unsigned integers specified
* in one of 2 ways described below :
* SDP_ATTR_REQ_INDIVIDUAL - 16bit individual identifiers
* They are the actual attribute identifiers in ascending order
*
* SDP_ATTR_REQ_RANGE - 32bit identifier range
* The high-order 16bits is the start of range
* the low-order 16bits are the end of range
* 0x0000 to 0xFFFF gets all attributes
*
* sdp_list_t *attrid_list
* Singly linked list containing attribute identifiers desired.
* Every element is either a uint16_t(attrSpec = SDP_ATTR_REQ_INDIVIDUAL)
* or a uint32_t(attrSpec=SDP_ATTR_REQ_RANGE)
*
* OUTPUT :
* int return value
* 0
* The request completed successfully. This does not
* mean the requested services were found
* -1
* The request completed unsuccessfully due to a timeout
*
* sdp_list_t *rsp_list
* This variable is set on a successful return to point to
* service(s) found. Each element of this list is of type
* sdp_record_t *.
*/
int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list);
/*
* Allocate/free a service record and its attributes
*/
sdp_record_t *sdp_record_alloc(void);
void sdp_record_free(sdp_record_t *rec);
/*
* Register a service record.
*
* Note: It is the responsbility of the Service Provider to create the
* record first and set its attributes using setXXX() methods.
*
* The service provider must then call sdp_record_register() to make
* the service record visible to SDP clients. This function returns 0
* on success or -1 on failure (and sets errno).
*/
int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device, uint8_t *data, uint32_t size, uint8_t flags, uint32_t *handle);
int sdp_device_record_register(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec, uint8_t flags);
int sdp_record_register(sdp_session_t *session, sdp_record_t *rec, uint8_t flags);
/*
* Unregister a service record.
*/
int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle);
int sdp_device_record_unregister(sdp_session_t *session, bdaddr_t *device, sdp_record_t *rec);
int sdp_record_unregister(sdp_session_t *session, sdp_record_t *rec);
/*
* Update an existing service record. (Calling this function
* before a previous call to sdp_record_register() will result
* in an error.)
*/
int sdp_device_record_update_binary(sdp_session_t *session, bdaddr_t *device, uint32_t handle, uint8_t *data, uint32_t size);
int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp_record_t *rec);
int sdp_record_update(sdp_session_t *sess, const sdp_record_t *rec);
void sdp_record_print(const sdp_record_t *rec);
/*
* UUID functions
*/
uuid_t *sdp_uuid16_create(uuid_t *uuid, uint16_t data);
uuid_t *sdp_uuid32_create(uuid_t *uuid, uint32_t data);
uuid_t *sdp_uuid128_create(uuid_t *uuid, const void *data);
int sdp_uuid16_cmp(const void *p1, const void *p2);
int sdp_uuid128_cmp(const void *p1, const void *p2);
int sdp_uuid_cmp(const void *p1, const void *p2);
uuid_t *sdp_uuid_to_uuid128(const uuid_t *uuid);
void sdp_uuid16_to_uuid128(uuid_t *uuid128, const uuid_t *uuid16);
void sdp_uuid32_to_uuid128(uuid_t *uuid128, const uuid_t *uuid32);
int sdp_uuid128_to_uuid(uuid_t *uuid);
int sdp_uuid_to_proto(uuid_t *uuid);
int sdp_uuid_extract(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned);
void sdp_uuid_print(const uuid_t *uuid);
#define MAX_LEN_UUID_STR 37
#define MAX_LEN_PROTOCOL_UUID_STR 8
#define MAX_LEN_SERVICECLASS_UUID_STR 28
#define MAX_LEN_PROFILEDESCRIPTOR_UUID_STR 28
int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n);
int sdp_proto_uuid2strn(const uuid_t *uuid, char *str, size_t n);
int sdp_svclass_uuid2strn(const uuid_t *uuid, char *str, size_t n);
int sdp_profile_uuid2strn(const uuid_t *uuid, char *str, size_t n);
/*
* In all the sdp_get_XXX(handle, XXX *xxx) functions below,
* the XXX * is set to point to the value, should it exist
* and 0 is returned. If the value does not exist, -1 is
* returned and errno set to ENODATA.
*
* In all the methods below, the memory management rules are
* simple. Don't free anything! The pointer returned, in the
* case of constructed types, is a pointer to the contents
* of the sdp_record_t.
*/
/*
* Get the access protocols from the service record
*/
int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **protos);
/*
* Get the additional access protocols from the service record
*/
int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **protos);
/*
* Extract the list of browse groups to which the service belongs.
* When set, seqp contains elements of GroupID (uint16_t)
*/
static inline int sdp_get_browse_groups(const sdp_record_t *rec, sdp_list_t **seqp)
{
return sdp_get_uuidseq_attr(rec, SDP_ATTR_BROWSE_GRP_LIST, seqp);
}
/*
* Extract language attribute meta-data of the service record.
* For each language in the service record, LangSeq has a struct of type
* sdp_lang_attr_t.
*/
int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq);
/*
* Extract the Bluetooth profile descriptor sequence from a record.
* Each element in the list is of type sdp_profile_desc_t
* which contains the UUID of the profile and its version number
* (encoded as major and minor in the high-order 8bits
* and low-order 8bits respectively of the uint16_t)
*/
int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDesc);
/*
* Extract SDP server version numbers
*
* Note: that this is an attribute of the SDP server only and
* contains a list of uint16_t each of which represent the
* major and minor SDP version numbers supported by this server
*/
int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **pVnumList);
int sdp_get_service_id(const sdp_record_t *rec, uuid_t *uuid);
int sdp_get_group_id(const sdp_record_t *rec, uuid_t *uuid);
int sdp_get_record_state(const sdp_record_t *rec, uint32_t *svcRecState);
int sdp_get_service_avail(const sdp_record_t *rec, uint8_t *svcAvail);
int sdp_get_service_ttl(const sdp_record_t *rec, uint32_t *svcTTLInfo);
int sdp_get_database_state(const sdp_record_t *rec, uint32_t *svcDBState);
static inline int sdp_get_service_name(const sdp_record_t *rec, char *str, int len)
{
return sdp_get_string_attr(rec, SDP_ATTR_SVCNAME_PRIMARY, str, len);
}
static inline int sdp_get_service_desc(const sdp_record_t *rec, char *str, int len)
{
return sdp_get_string_attr(rec, SDP_ATTR_SVCDESC_PRIMARY, str, len);
}
static inline int sdp_get_provider_name(const sdp_record_t *rec, char *str, int len)
{
return sdp_get_string_attr(rec, SDP_ATTR_PROVNAME_PRIMARY, str, len);
}
static inline int sdp_get_doc_url(const sdp_record_t *rec, char *str, int len)
{
return sdp_get_string_attr(rec, SDP_ATTR_DOC_URL, str, len);
}
static inline int sdp_get_clnt_exec_url(const sdp_record_t *rec, char *str, int len)
{
return sdp_get_string_attr(rec, SDP_ATTR_CLNT_EXEC_URL, str, len);
}
static inline int sdp_get_icon_url(const sdp_record_t *rec, char *str, int len)
{
return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len);
}
/*
* Set the supported features
* sf should be a list of list with each feature data
* Returns 0 on success -1 on fail
*/
int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf);
/*
* Get the supported features
* seqp is set to a list of list with each feature data
* Returns 0 on success, if an error occurred -1 is returned and errno is set
*/
int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp);
sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int bufsize, int *scanned);
sdp_record_t *sdp_copy_record(sdp_record_t *rec);
void sdp_data_print(sdp_data_t *data);
void sdp_print_service_attr(sdp_list_t *alist);
int sdp_attrid_comp_func(const void *key1, const void *key2);
void sdp_set_seq_len(uint8_t *ptr, uint32_t length);
void sdp_set_attrid(sdp_buf_t *pdu, uint16_t id);
void sdp_append_to_pdu(sdp_buf_t *dst, sdp_data_t *d);
void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len);
int sdp_gen_pdu(sdp_buf_t *pdu, sdp_data_t *data);
int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *pdu);
int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size);
sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int bufsize, int *extractedLength, sdp_record_t *rec);
void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid);
void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq);
int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *req, uint8_t *rsp, uint32_t reqsize, uint32_t *rspsize);
void sdp_add_lang_attr(sdp_record_t *rec);
#ifdef __cplusplus
}
#endif
#endif /* __SDP_LIB_H */

2928
external/cache/sources/hcitools/lib/hci.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,594 @@
/*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2010 Nokia Corporation
* Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __packed
#define __packed __attribute__((packed))
#endif
#define MGMT_INDEX_NONE 0xFFFF
#define MGMT_STATUS_SUCCESS 0x00
#define MGMT_STATUS_UNKNOWN_COMMAND 0x01
#define MGMT_STATUS_NOT_CONNECTED 0x02
#define MGMT_STATUS_FAILED 0x03
#define MGMT_STATUS_CONNECT_FAILED 0x04
#define MGMT_STATUS_AUTH_FAILED 0x05
#define MGMT_STATUS_NOT_PAIRED 0x06
#define MGMT_STATUS_NO_RESOURCES 0x07
#define MGMT_STATUS_TIMEOUT 0x08
#define MGMT_STATUS_ALREADY_CONNECTED 0x09
#define MGMT_STATUS_BUSY 0x0a
#define MGMT_STATUS_REJECTED 0x0b
#define MGMT_STATUS_NOT_SUPPORTED 0x0c
#define MGMT_STATUS_INVALID_PARAMS 0x0d
#define MGMT_STATUS_DISCONNECTED 0x0e
#define MGMT_STATUS_NOT_POWERED 0x0f
#define MGMT_STATUS_CANCELLED 0x10
#define MGMT_STATUS_INVALID_INDEX 0x11
#define MGMT_STATUS_RFKILLED 0x12
struct mgmt_hdr {
uint16_t opcode;
uint16_t index;
uint16_t len;
} __packed;
#define MGMT_HDR_SIZE 6
struct mgmt_addr_info {
bdaddr_t bdaddr;
uint8_t type;
} __packed;
#define MGMT_OP_READ_VERSION 0x0001
struct mgmt_rp_read_version {
uint8_t version;
uint16_t revision;
} __packed;
#define MGMT_OP_READ_COMMANDS 0x0002
struct mgmt_rp_read_commands {
uint16_t num_commands;
uint16_t num_events;
uint16_t opcodes[0];
} __packed;
#define MGMT_OP_READ_INDEX_LIST 0x0003
struct mgmt_rp_read_index_list {
uint16_t num_controllers;
uint16_t index[0];
} __packed;
/* Reserve one extra byte for names in management messages so that they
* are always guaranteed to be nul-terminated */
#define MGMT_MAX_NAME_LENGTH (248 + 1)
#define MGMT_MAX_SHORT_NAME_LENGTH (10 + 1)
#define MGMT_SETTING_POWERED 0x00000001
#define MGMT_SETTING_CONNECTABLE 0x00000002
#define MGMT_SETTING_FAST_CONNECTABLE 0x00000004
#define MGMT_SETTING_DISCOVERABLE 0x00000008
#define MGMT_SETTING_PAIRABLE 0x00000010
#define MGMT_SETTING_LINK_SECURITY 0x00000020
#define MGMT_SETTING_SSP 0x00000040
#define MGMT_SETTING_BREDR 0x00000080
#define MGMT_SETTING_HS 0x00000100
#define MGMT_SETTING_LE 0x00000200
#define MGMT_SETTING_ADVERTISING 0x00000400
#define MGMT_OP_READ_INFO 0x0004
struct mgmt_rp_read_info {
bdaddr_t bdaddr;
uint8_t version;
uint16_t manufacturer;
uint32_t supported_settings;
uint32_t current_settings;
uint8_t dev_class[3];
uint8_t name[MGMT_MAX_NAME_LENGTH];
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;
struct mgmt_mode {
uint8_t val;
} __packed;
struct mgmt_cod {
uint8_t val[3];
} __packed;
#define MGMT_OP_SET_POWERED 0x0005
#define MGMT_OP_SET_DISCOVERABLE 0x0006
struct mgmt_cp_set_discoverable {
uint8_t val;
uint16_t timeout;
} __packed;
#define MGMT_OP_SET_CONNECTABLE 0x0007
#define MGMT_OP_SET_FAST_CONNECTABLE 0x0008
#define MGMT_OP_SET_PAIRABLE 0x0009
#define MGMT_OP_SET_LINK_SECURITY 0x000A
#define MGMT_OP_SET_SSP 0x000B
#define MGMT_OP_SET_HS 0x000C
#define MGMT_OP_SET_LE 0x000D
#define MGMT_OP_SET_DEV_CLASS 0x000E
struct mgmt_cp_set_dev_class {
uint8_t major;
uint8_t minor;
} __packed;
#define MGMT_OP_SET_LOCAL_NAME 0x000F
struct mgmt_cp_set_local_name {
uint8_t name[MGMT_MAX_NAME_LENGTH];
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;
#define MGMT_OP_ADD_UUID 0x0010
struct mgmt_cp_add_uuid {
uint8_t uuid[16];
uint8_t svc_hint;
} __packed;
#define MGMT_OP_REMOVE_UUID 0x0011
struct mgmt_cp_remove_uuid {
uint8_t uuid[16];
} __packed;
struct mgmt_link_key_info {
struct mgmt_addr_info addr;
uint8_t type;
uint8_t val[16];
uint8_t pin_len;
} __packed;
#define MGMT_OP_LOAD_LINK_KEYS 0x0012
struct mgmt_cp_load_link_keys {
uint8_t debug_keys;
uint16_t key_count;
struct mgmt_link_key_info keys[0];
} __packed;
struct mgmt_ltk_info {
struct mgmt_addr_info addr;
uint8_t authenticated;
uint8_t master;
uint8_t enc_size;
uint16_t ediv;
uint8_t rand[8];
uint8_t val[16];
} __packed;
#define MGMT_OP_LOAD_LONG_TERM_KEYS 0x0013
struct mgmt_cp_load_long_term_keys {
uint16_t key_count;
struct mgmt_ltk_info keys[0];
} __packed;
#define MGMT_OP_DISCONNECT 0x0014
struct mgmt_cp_disconnect {
struct mgmt_addr_info addr;
} __packed;
struct mgmt_rp_disconnect {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_GET_CONNECTIONS 0x0015
struct mgmt_rp_get_connections {
uint16_t conn_count;
struct mgmt_addr_info addr[0];
} __packed;
#define MGMT_OP_PIN_CODE_REPLY 0x0016
struct mgmt_cp_pin_code_reply {
struct mgmt_addr_info addr;
uint8_t pin_len;
uint8_t pin_code[16];
} __packed;
#define MGMT_OP_PIN_CODE_NEG_REPLY 0x0017
struct mgmt_cp_pin_code_neg_reply {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_SET_IO_CAPABILITY 0x0018
struct mgmt_cp_set_io_capability {
uint8_t io_capability;
} __packed;
#define MGMT_OP_PAIR_DEVICE 0x0019
struct mgmt_cp_pair_device {
struct mgmt_addr_info addr;
uint8_t io_cap;
} __packed;
struct mgmt_rp_pair_device {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_CANCEL_PAIR_DEVICE 0x001A
#define MGMT_OP_UNPAIR_DEVICE 0x001B
struct mgmt_cp_unpair_device {
struct mgmt_addr_info addr;
uint8_t disconnect;
} __packed;
struct mgmt_rp_unpair_device {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_USER_CONFIRM_REPLY 0x001C
struct mgmt_cp_user_confirm_reply {
struct mgmt_addr_info addr;
} __packed;
struct mgmt_rp_user_confirm_reply {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x001D
#define MGMT_OP_USER_PASSKEY_REPLY 0x001E
struct mgmt_cp_user_passkey_reply {
struct mgmt_addr_info addr;
uint32_t passkey;
} __packed;
struct mgmt_rp_user_passkey_reply {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_USER_PASSKEY_NEG_REPLY 0x001F
struct mgmt_cp_user_passkey_neg_reply {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0020
struct mgmt_rp_read_local_oob_data {
uint8_t hash[16];
uint8_t randomizer[16];
} __packed;
#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0021
struct mgmt_cp_add_remote_oob_data {
struct mgmt_addr_info addr;
uint8_t hash[16];
uint8_t randomizer[16];
} __packed;
#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x0022
struct mgmt_cp_remove_remote_oob_data {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_START_DISCOVERY 0x0023
struct mgmt_cp_start_discovery {
uint8_t type;
} __packed;
#define MGMT_OP_STOP_DISCOVERY 0x0024
struct mgmt_cp_stop_discovery {
uint8_t type;
} __packed;
#define MGMT_OP_CONFIRM_NAME 0x0025
struct mgmt_cp_confirm_name {
struct mgmt_addr_info addr;
uint8_t name_known;
} __packed;
struct mgmt_rp_confirm_name {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_BLOCK_DEVICE 0x0026
struct mgmt_cp_block_device {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_UNBLOCK_DEVICE 0x0027
struct mgmt_cp_unblock_device {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_OP_SET_DEVICE_ID 0x0028
struct mgmt_cp_set_device_id {
uint16_t source;
uint16_t vendor;
uint16_t product;
uint16_t version;
} __packed;
#define MGMT_OP_SET_ADVERTISING 0x0029
#define MGMT_OP_SET_BREDR 0x002A
#define MGMT_OP_SET_STATIC_ADDRESS 0x002B
struct mgmt_cp_set_static_address {
bdaddr_t bdaddr;
} __packed;
#define MGMT_OP_SET_SCAN_PARAMS 0x002C
struct mgmt_cp_set_scan_params {
uint16_t interval;
uint16_t window;
} __packed;
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
uint16_t opcode;
uint8_t status;
uint8_t data[0];
} __packed;
#define MGMT_EV_CMD_STATUS 0x0002
struct mgmt_ev_cmd_status {
uint16_t opcode;
uint8_t status;
} __packed;
#define MGMT_EV_CONTROLLER_ERROR 0x0003
struct mgmt_ev_controller_error {
uint8_t error_code;
} __packed;
#define MGMT_EV_INDEX_ADDED 0x0004
#define MGMT_EV_INDEX_REMOVED 0x0005
#define MGMT_EV_NEW_SETTINGS 0x0006
#define MGMT_EV_CLASS_OF_DEV_CHANGED 0x0007
struct mgmt_ev_class_of_dev_changed {
uint8_t class_of_dev[3];
} __packed;
#define MGMT_EV_LOCAL_NAME_CHANGED 0x0008
struct mgmt_ev_local_name_changed {
uint8_t name[MGMT_MAX_NAME_LENGTH];
uint8_t short_name[MGMT_MAX_SHORT_NAME_LENGTH];
} __packed;
#define MGMT_EV_NEW_LINK_KEY 0x0009
struct mgmt_ev_new_link_key {
uint8_t store_hint;
struct mgmt_link_key_info key;
} __packed;
#define MGMT_EV_NEW_LONG_TERM_KEY 0x000A
struct mgmt_ev_new_long_term_key {
uint8_t store_hint;
struct mgmt_ltk_info key;
} __packed;
#define MGMT_EV_DEVICE_CONNECTED 0x000B
struct mgmt_ev_device_connected {
struct mgmt_addr_info addr;
uint32_t flags;
uint16_t eir_len;
uint8_t eir[0];
} __packed;
#define MGMT_DEV_DISCONN_UNKNOWN 0x00
#define MGMT_DEV_DISCONN_TIMEOUT 0x01
#define MGMT_DEV_DISCONN_LOCAL_HOST 0x02
#define MGMT_DEV_DISCONN_REMOTE 0x03
#define MGMT_EV_DEVICE_DISCONNECTED 0x000C
struct mgmt_ev_device_disconnected {
struct mgmt_addr_info addr;
uint8_t reason;
} __packed;
#define MGMT_EV_CONNECT_FAILED 0x000D
struct mgmt_ev_connect_failed {
struct mgmt_addr_info addr;
uint8_t status;
} __packed;
#define MGMT_EV_PIN_CODE_REQUEST 0x000E
struct mgmt_ev_pin_code_request {
struct mgmt_addr_info addr;
uint8_t secure;
} __packed;
#define MGMT_EV_USER_CONFIRM_REQUEST 0x000F
struct mgmt_ev_user_confirm_request {
struct mgmt_addr_info addr;
uint8_t confirm_hint;
uint32_t value;
} __packed;
#define MGMT_EV_USER_PASSKEY_REQUEST 0x0010
struct mgmt_ev_user_passkey_request {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_EV_AUTH_FAILED 0x0011
struct mgmt_ev_auth_failed {
struct mgmt_addr_info addr;
uint8_t status;
} __packed;
#define MGMT_DEV_FOUND_CONFIRM_NAME 0x01
#define MGMT_DEV_FOUND_LEGACY_PAIRING 0x02
#define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found {
struct mgmt_addr_info addr;
int8_t rssi;
uint32_t flags;
uint16_t eir_len;
uint8_t eir[0];
} __packed;
#define MGMT_EV_DISCOVERING 0x0013
struct mgmt_ev_discovering {
uint8_t type;
uint8_t discovering;
} __packed;
#define MGMT_EV_DEVICE_BLOCKED 0x0014
struct mgmt_ev_device_blocked {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_EV_DEVICE_UNBLOCKED 0x0015
struct mgmt_ev_device_unblocked {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_EV_DEVICE_UNPAIRED 0x0016
struct mgmt_ev_device_unpaired {
struct mgmt_addr_info addr;
} __packed;
#define MGMT_EV_PASSKEY_NOTIFY 0x0017
struct mgmt_ev_passkey_notify {
struct mgmt_addr_info addr;
uint32_t passkey;
uint8_t entered;
} __packed;
static const char *mgmt_op[] = {
"<0x0000>",
"Read Version",
"Read Commands",
"Read Index List",
"Read Controller Info",
"Set Powered",
"Set Discoverable",
"Set Connectable",
"Set Fast Connectable", /* 0x0008 */
"Set Pairable",
"Set Link Security",
"Set Secure Simple Pairing",
"Set High Speed",
"Set Low Energy",
"Set Dev Class",
"Set Local Name",
"Add UUID", /* 0x0010 */
"Remove UUID",
"Load Link Keys",
"Load Long Term Keys",
"Disconnect",
"Get Connections",
"PIN Code Reply",
"PIN Code Neg Reply",
"Set IO Capability", /* 0x0018 */
"Pair Device",
"Cancel Pair Device",
"Unpair Device",
"User Confirm Reply",
"User Confirm Neg Reply",
"User Passkey Reply",
"User Passkey Neg Reply",
"Read Local OOB Data", /* 0x0020 */
"Add Remote OOB Data",
"Remove Remove OOB Data",
"Start Discovery",
"Stop Discovery",
"Confirm Name",
"Block Device",
"Unblock Device",
"Set Device ID",
"Set Advertising",
"Set BR/EDR",
"Set Static Address",
"Set Scan Parameters",
};
static const char *mgmt_ev[] = {
"<0x0000>",
"Command Complete",
"Command Status",
"Controller Error",
"Index Added",
"Index Removed",
"New Settings",
"Class of Device Changed",
"Local Name Changed", /* 0x0008 */
"New Link Key",
"New Long Term Key",
"Device Connected",
"Device Disconnected",
"Connect Failed",
"PIN Code Request",
"User Confirm Request",
"User Passkey Request", /* 0x0010 */
"Authentication Failed",
"Device Found",
"Discovering",
"Device Blocked",
"Device Unblocked",
"Device Unpaired",
"Passkey Notify",
};
static const char *mgmt_status[] = {
"Success",
"Unknown Command",
"Not Connected",
"Failed",
"Connect Failed",
"Authentication Failed",
"Not Paired",
"No Resources",
"Timeout",
"Already Connected",
"Busy",
"Rejected",
"Not Supported",
"Invalid Parameters",
"Disconnected",
"Not Powered",
"Cancelled",
"Invalid Index",
"Blocked through rfkill",
};
#ifndef NELEM
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
#endif
static inline const char *mgmt_opstr(uint16_t op)
{
if (op >= NELEM(mgmt_op))
return "<unknown opcode>";
return mgmt_op[op];
}
static inline const char *mgmt_evstr(uint16_t ev)
{
if (ev >= NELEM(mgmt_ev))
return "<unknown event>";
return mgmt_ev[ev];
}
static inline const char *mgmt_errstr(uint8_t status)
{
if (status >= NELEM(mgmt_status))
return "<unknown status>";
return mgmt_status[status];
}

4919
external/cache/sources/hcitools/lib/sdp.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,278 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <string.h>
#include <stdlib.h>
#include <errno.h>
#include "uuid.h"
#if __BYTE_ORDER == __BIG_ENDIAN
static uint128_t bluetooth_base_uuid = {
.data = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
};
#define BASE_UUID16_OFFSET 2
#define BASE_UUID32_OFFSET 0
#else
static uint128_t bluetooth_base_uuid = {
.data = { 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
#define BASE_UUID16_OFFSET 12
#define BASE_UUID32_OFFSET BASE_UUID16_OFFSET
#endif
static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
{
dst->value.u128 = bluetooth_base_uuid;
dst->type = BT_UUID128;
memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET],
&src->value.u16, sizeof(src->value.u16));
}
static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
{
dst->value.u128 = bluetooth_base_uuid;
dst->type = BT_UUID128;
memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET],
&src->value.u32, sizeof(src->value.u32));
}
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
{
switch (src->type) {
case BT_UUID128:
*dst = *src;
break;
case BT_UUID32:
bt_uuid32_to_uuid128(src, dst);
break;
case BT_UUID16:
bt_uuid16_to_uuid128(src, dst);
break;
default:
break;
}
}
static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
{
return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
}
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
{
memset(btuuid, 0, sizeof(bt_uuid_t));
btuuid->type = BT_UUID16;
btuuid->value.u16 = value;
return 0;
}
int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
{
memset(btuuid, 0, sizeof(bt_uuid_t));
btuuid->type = BT_UUID32;
btuuid->value.u32 = value;
return 0;
}
int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
{
memset(btuuid, 0, sizeof(bt_uuid_t));
btuuid->type = BT_UUID128;
btuuid->value.u128 = value;
return 0;
}
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
{
bt_uuid_t u1, u2;
bt_uuid_to_uuid128(uuid1, &u1);
bt_uuid_to_uuid128(uuid2, &u2);
return bt_uuid128_cmp(&u1, &u2);
}
/*
* convert the UUID to string, copying a maximum of n characters.
*/
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
{
if (!uuid) {
snprintf(str, n, "NULL");
return -EINVAL;
}
switch (uuid->type) {
case BT_UUID16:
snprintf(str, n, "%.4x", uuid->value.u16);
break;
case BT_UUID32:
snprintf(str, n, "%.8x", uuid->value.u32);
break;
case BT_UUID128: {
unsigned int data0;
unsigned short data1;
unsigned short data2;
unsigned short data3;
unsigned int data4;
unsigned short data5;
uint128_t nvalue;
const uint8_t *data = (uint8_t *) &nvalue;
hton128(&uuid->value.u128, &nvalue);
memcpy(&data0, &data[0], 4);
memcpy(&data1, &data[4], 2);
memcpy(&data2, &data[6], 2);
memcpy(&data3, &data[8], 2);
memcpy(&data4, &data[10], 4);
memcpy(&data5, &data[14], 2);
snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
ntohl(data0), ntohs(data1),
ntohs(data2), ntohs(data3),
ntohl(data4), ntohs(data5));
}
break;
default:
snprintf(str, n, "Type of UUID (%x) unknown.", uuid->type);
return -EINVAL; /* Enum type of UUID not set */
}
return 0;
}
static inline int is_uuid128(const char *string)
{
return (strlen(string) == 36 &&
string[8] == '-' &&
string[13] == '-' &&
string[18] == '-' &&
string[23] == '-');
}
static inline int is_uuid32(const char *string)
{
return (strlen(string) == 8 || strlen(string) == 10);
}
static inline int is_uuid16(const char *string)
{
return (strlen(string) == 4 || strlen(string) == 6);
}
static int bt_string_to_uuid16(bt_uuid_t *uuid, const char *string)
{
uint16_t u16;
char *endptr = NULL;
u16 = strtol(string, &endptr, 16);
if (endptr && *endptr == '\0') {
bt_uuid16_create(uuid, u16);
return 0;
}
return -EINVAL;
}
static int bt_string_to_uuid32(bt_uuid_t *uuid, const char *string)
{
uint32_t u32;
char *endptr = NULL;
u32 = strtol(string, &endptr, 16);
if (endptr && *endptr == '\0') {
bt_uuid32_create(uuid, u32);
return 0;
}
return -EINVAL;
}
static int bt_string_to_uuid128(bt_uuid_t *uuid, const char *string)
{
uint32_t data0, data4;
uint16_t data1, data2, data3, data5;
uint128_t n128, u128;
uint8_t *val = (uint8_t *) &n128;
if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
&data0, &data1, &data2,
&data3, &data4, &data5) != 6)
return -EINVAL;
data0 = htonl(data0);
data1 = htons(data1);
data2 = htons(data2);
data3 = htons(data3);
data4 = htonl(data4);
data5 = htons(data5);
memcpy(&val[0], &data0, 4);
memcpy(&val[4], &data1, 2);
memcpy(&val[6], &data2, 2);
memcpy(&val[8], &data3, 2);
memcpy(&val[10], &data4, 4);
memcpy(&val[14], &data5, 2);
ntoh128(&n128, &u128);
bt_uuid128_create(uuid, u128);
return 0;
}
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
{
if (is_uuid128(string))
return bt_string_to_uuid128(uuid, string);
else if (is_uuid32(string))
return bt_string_to_uuid32(uuid, string);
else if (is_uuid16(string))
return bt_string_to_uuid16(uuid, string);
return -EINVAL;
}
int bt_uuid_strcmp(const void *a, const void *b)
{
return strcasecmp(a, b);
}

View File

@@ -0,0 +1,140 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011 Nokia Corporation
* Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __BLUETOOTH_UUID_H
#define __BLUETOOTH_UUID_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <bluetooth/bluetooth.h>
#define GENERIC_AUDIO_UUID "00001203-0000-1000-8000-00805f9b34fb"
#define HSP_HS_UUID "00001108-0000-1000-8000-00805f9b34fb"
#define HSP_AG_UUID "00001112-0000-1000-8000-00805f9b34fb"
#define HFP_HS_UUID "0000111e-0000-1000-8000-00805f9b34fb"
#define HFP_AG_UUID "0000111f-0000-1000-8000-00805f9b34fb"
#define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb"
#define A2DP_SOURCE_UUID "0000110a-0000-1000-8000-00805f9b34fb"
#define A2DP_SINK_UUID "0000110b-0000-1000-8000-00805f9b34fb"
#define AVRCP_REMOTE_UUID "0000110e-0000-1000-8000-00805f9b34fb"
#define AVRCP_TARGET_UUID "0000110c-0000-1000-8000-00805f9b34fb"
#define PANU_UUID "00001115-0000-1000-8000-00805f9b34fb"
#define NAP_UUID "00001116-0000-1000-8000-00805f9b34fb"
#define GN_UUID "00001117-0000-1000-8000-00805f9b34fb"
#define BNEP_SVC_UUID "0000000f-0000-1000-8000-00805f9b34fb"
#define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb"
#define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb"
#define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb"
#define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb"
#define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb"
#define TX_POWER_UUID "00001804-0000-1000-8000-00805f9b34fb"
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb"
#define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb"
#define HEALTH_THERMOMETER_UUID "00001809-0000-1000-8000-00805f9b34fb"
#define TEMPERATURE_MEASUREMENT_UUID "00002a1c-0000-1000-8000-00805f9b34fb"
#define TEMPERATURE_TYPE_UUID "00002a1d-0000-1000-8000-00805f9b34fb"
#define INTERMEDIATE_TEMPERATURE_UUID "00002a1e-0000-1000-8000-00805f9b34fb"
#define MEASUREMENT_INTERVAL_UUID "00002a21-0000-1000-8000-00805f9b34fb"
#define CYCLING_SC_UUID "00001816-0000-1000-8000-00805f9b34fb"
#define CSC_MEASUREMENT_UUID "00002a5b-0000-1000-8000-00805f9b34fb"
#define CSC_FEATURE_UUID "00002a5c-0000-1000-8000-00805f9b34fb"
#define SENSOR_LOCATION_UUID "00002a5d-0000-1000-8000-00805f9b34fb"
#define SC_CONTROL_POINT_UUID "00002a55-0000-1000-8000-00805f9b34fb"
#define RFCOMM_UUID_STR "00000003-0000-1000-8000-00805f9b34fb"
#define HDP_UUID "00001400-0000-1000-8000-00805f9b34fb"
#define HDP_SOURCE_UUID "00001401-0000-1000-8000-00805f9b34fb"
#define HDP_SINK_UUID "00001402-0000-1000-8000-00805f9b34fb"
#define HID_UUID "00001124-0000-1000-8000-00805f9b34fb"
#define DUN_GW_UUID "00001103-0000-1000-8000-00805f9b34fb"
#define GAP_UUID "00001800-0000-1000-8000-00805f9b34fb"
#define PNP_UUID "00001200-0000-1000-8000-00805f9b34fb"
#define SPP_UUID "00001101-0000-1000-8000-00805f9b34fb"
#define OBEX_SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb"
#define OBEX_OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
#define OBEX_FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
#define OBEX_PCE_UUID "0000112e-0000-1000-8000-00805f9b34fb"
#define OBEX_PSE_UUID "0000112f-0000-1000-8000-00805f9b34fb"
#define OBEX_PBAP_UUID "00001130-0000-1000-8000-00805f9b34fb"
#define OBEX_MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
#define OBEX_MNS_UUID "00001133-0000-1000-8000-00805f9b34fb"
#define OBEX_MAP_UUID "00001134-0000-1000-8000-00805f9b34fb"
typedef struct {
enum {
BT_UUID_UNSPEC = 0,
BT_UUID16 = 16,
BT_UUID32 = 32,
BT_UUID128 = 128,
} type;
union {
uint16_t u16;
uint32_t u32;
uint128_t u128;
} value;
} bt_uuid_t;
int bt_uuid_strcmp(const void *a, const void *b);
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value);
int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value);
int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value);
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2);
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst);
#define MAX_LEN_UUID_STR 37
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n);
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string);
#ifdef __cplusplus
}
#endif
#endif /* __BLUETOOTH_UUID_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,423 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <arpa/inet.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include "btsnoop.h"
struct btsnoop_hdr {
uint8_t id[8]; /* Identification Pattern */
uint32_t version; /* Version Number = 1 */
uint32_t type; /* Datalink Type */
} __attribute__ ((packed));
#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
struct btsnoop_pkt {
uint32_t size; /* Original Length */
uint32_t len; /* Included Length */
uint32_t flags; /* Packet Flags */
uint32_t drops; /* Cumulative Drops */
uint64_t ts; /* Timestamp microseconds */
uint8_t data[0]; /* Packet Data */
} __attribute__ ((packed));
#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
static const uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e,
0x6f, 0x6f, 0x70, 0x00 };
static const uint32_t btsnoop_version = 1;
static uint32_t btsnoop_type = 0;
static int btsnoop_fd = -1;
static uint16_t btsnoop_index = 0xffff;
void btsnoop_create(const char *path, uint32_t type)
{
struct btsnoop_hdr hdr;
ssize_t written;
if (btsnoop_fd >= 0)
return;
btsnoop_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (btsnoop_fd < 0)
return;
btsnoop_type = type;
memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
hdr.version = htonl(btsnoop_version);
hdr.type = htonl(btsnoop_type);
written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
if (written < 0) {
close(btsnoop_fd);
btsnoop_fd = -1;
return;
}
}
void btsnoop_write(struct timeval *tv, uint32_t flags,
const void *data, uint16_t size)
{
struct btsnoop_pkt pkt;
uint64_t ts;
ssize_t written;
ts = (tv->tv_sec - 946684800ll) * 1000000ll + tv->tv_usec;
pkt.size = htonl(size);
pkt.len = htonl(size);
pkt.flags = htonl(flags);
pkt.drops = htonl(0);
pkt.ts = hton64(ts + 0x00E03AB44A676000ll);
written = write(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
if (written < 0)
return;
if (data && size > 0) {
written = write(btsnoop_fd, data, size);
if (written < 0)
return;
}
}
static uint32_t get_flags_from_opcode(uint16_t opcode)
{
switch (opcode) {
case BTSNOOP_OPCODE_NEW_INDEX:
case BTSNOOP_OPCODE_DEL_INDEX:
break;
case BTSNOOP_OPCODE_COMMAND_PKT:
return 0x02;
case BTSNOOP_OPCODE_EVENT_PKT:
return 0x03;
case BTSNOOP_OPCODE_ACL_TX_PKT:
return 0x00;
case BTSNOOP_OPCODE_ACL_RX_PKT:
return 0x01;
case BTSNOOP_OPCODE_SCO_TX_PKT:
case BTSNOOP_OPCODE_SCO_RX_PKT:
break;
}
return 0xff;
}
void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size)
{
uint32_t flags;
if (!tv)
return;
if (btsnoop_fd < 0)
return;
switch (btsnoop_type) {
case BTSNOOP_TYPE_HCI:
if (btsnoop_index == 0xffff)
btsnoop_index = index;
if (index != btsnoop_index)
return;
flags = get_flags_from_opcode(opcode);
if (flags == 0xff)
return;
break;
case BTSNOOP_TYPE_EXTENDED_HCI:
flags = (index << 16) | opcode;
break;
default:
return;
}
btsnoop_write(tv, flags, data, size);
}
void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size)
{
uint32_t flags;
if (!tv)
return;
if (btsnoop_fd < 0)
return;
switch (btsnoop_type) {
case BTSNOOP_TYPE_EXTENDED_PHY:
flags = (1 << 16) | frequency;
break;
default:
return;
}
btsnoop_write(tv, flags, data, size);
}
int btsnoop_open(const char *path, uint32_t *type)
{
struct btsnoop_hdr hdr;
ssize_t len;
if (btsnoop_fd >= 0) {
fprintf(stderr, "Too many open files\n");
return -1;
}
btsnoop_fd = open(path, O_RDONLY | O_CLOEXEC);
if (btsnoop_fd < 0) {
perror("Failed to open file");
return -1;
}
len = read(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
if (len < 0 || len != BTSNOOP_HDR_SIZE) {
perror("Failed to read header");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
if (memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
fprintf(stderr, "Invalid btsnoop header\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
if (ntohl(hdr.version) != btsnoop_version) {
fprintf(stderr, "Invalid btsnoop version\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
btsnoop_type = ntohl(hdr.type);
if (type)
*type = btsnoop_type;
return 0;
}
static uint16_t get_opcode_from_flags(uint8_t type, uint32_t flags)
{
switch (type) {
case HCI_COMMAND_PKT:
return BTSNOOP_OPCODE_COMMAND_PKT;
case HCI_ACLDATA_PKT:
if (flags & 0x01)
return BTSNOOP_OPCODE_ACL_RX_PKT;
else
return BTSNOOP_OPCODE_ACL_TX_PKT;
case HCI_SCODATA_PKT:
if (flags & 0x01)
return BTSNOOP_OPCODE_SCO_RX_PKT;
else
return BTSNOOP_OPCODE_SCO_TX_PKT;
case HCI_EVENT_PKT:
return BTSNOOP_OPCODE_EVENT_PKT;
case 0xff:
if (flags & 0x02) {
if (flags & 0x01)
return BTSNOOP_OPCODE_EVENT_PKT;
else
return BTSNOOP_OPCODE_COMMAND_PKT;
} else {
if (flags & 0x01)
return BTSNOOP_OPCODE_ACL_RX_PKT;
else
return BTSNOOP_OPCODE_ACL_TX_PKT;
}
break;
}
return 0xff;
}
int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
void *data, uint16_t *size)
{
struct btsnoop_pkt pkt;
uint32_t toread, flags;
uint64_t ts;
uint8_t pkt_type;
ssize_t len;
if (btsnoop_fd < 0)
return -1;
len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
if (len == 0)
return -1;
if (len < 0 || len != BTSNOOP_PKT_SIZE) {
perror("Failed to read packet");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
toread = ntohl(pkt.size);
flags = ntohl(pkt.flags);
ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
tv->tv_sec = (ts / 1000000ll) + 946684800ll;
tv->tv_usec = ts % 1000000ll;
switch (btsnoop_type) {
case BTSNOOP_TYPE_HCI:
*index = 0;
*opcode = get_opcode_from_flags(0xff, flags);
break;
case BTSNOOP_TYPE_UART:
len = read(btsnoop_fd, &pkt_type, 1);
if (len < 0) {
perror("Failed to read packet type");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
toread--;
*index = 0;
*opcode = get_opcode_from_flags(pkt_type, flags);
break;
case BTSNOOP_TYPE_EXTENDED_HCI:
*index = flags >> 16;
*opcode = flags & 0xffff;
break;
default:
fprintf(stderr, "Unknown packet type\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
len = read(btsnoop_fd, data, toread);
if (len < 0) {
perror("Failed to read data");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
*size = toread;
return 0;
}
int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
void *data, uint16_t *size)
{
struct btsnoop_pkt pkt;
uint32_t toread, flags;
uint64_t ts;
ssize_t len;
if (btsnoop_fd < 0)
return -1;
len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
if (len == 0)
return -1;
if (len < 0 || len != BTSNOOP_PKT_SIZE) {
perror("Failed to read packet");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
toread = ntohl(pkt.size);
flags = ntohl(pkt.flags);
ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
tv->tv_sec = (ts / 1000000ll) + 946684800ll;
tv->tv_usec = ts % 1000000ll;
switch (btsnoop_type) {
case BTSNOOP_TYPE_EXTENDED_PHY:
if ((flags >> 16) != 1)
break;
*frequency = flags & 0xffff;
break;
default:
fprintf(stderr, "Unknown packet type\n");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
len = read(btsnoop_fd, data, toread);
if (len < 0) {
perror("Failed to read data");
close(btsnoop_fd);
btsnoop_fd = -1;
return -1;
}
*size = toread;
return 0;
}
void btsnoop_close(void)
{
if (btsnoop_fd < 0)
return;
close(btsnoop_fd);
btsnoop_fd = -1;
btsnoop_index = 0xffff;
}

View File

@@ -0,0 +1,57 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
#include <sys/time.h>
#define BTSNOOP_TYPE_HCI 1001
#define BTSNOOP_TYPE_UART 1002
#define BTSNOOP_TYPE_BCSP 1003
#define BTSNOOP_TYPE_3WIRE 1004
#define BTSNOOP_TYPE_EXTENDED_HCI 2001
#define BTSNOOP_TYPE_EXTENDED_PHY 2002
#define BTSNOOP_OPCODE_NEW_INDEX 0
#define BTSNOOP_OPCODE_DEL_INDEX 1
#define BTSNOOP_OPCODE_COMMAND_PKT 2
#define BTSNOOP_OPCODE_EVENT_PKT 3
#define BTSNOOP_OPCODE_ACL_TX_PKT 4
#define BTSNOOP_OPCODE_ACL_RX_PKT 5
#define BTSNOOP_OPCODE_SCO_TX_PKT 6
#define BTSNOOP_OPCODE_SCO_RX_PKT 7
void btsnoop_create(const char *path, uint32_t type);
void btsnoop_write(struct timeval *tv, uint32_t flags,
const void *data, uint16_t size);
void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size);
int btsnoop_open(const char *path, uint32_t *type);
int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
void *data, uint16_t *size);
int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
void *data, uint16_t *size);
void btsnoop_close(void);

View File

@@ -0,0 +1,891 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <stdbool.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <lib/bluetooth/bluetooth.h>
#include <lib/bluetooth/hci.h>
#include <lib/mgmt.h>
#include "mainloop.h"
#include "display.h"
#include "packet.h"
#include "btsnoop.h"
#include "hcidump.h"
#include "control.h"
static bool hcidump_fallback = false;
#define MAX_PACKET_SIZE (1486 + 4)
struct control_data {
uint16_t channel;
int fd;
unsigned char buf[MAX_PACKET_SIZE];
uint16_t offset;
};
static void free_data(void *user_data)
{
struct control_data *data = user_data;
close(data->fd);
free(data);
}
static void mgmt_index_added(uint16_t len, const void *buf)
{
printf("@ Index Added\n");
packet_hexdump(buf, len);
}
static void mgmt_index_removed(uint16_t len, const void *buf)
{
printf("@ Index Removed\n");
packet_hexdump(buf, len);
}
static void mgmt_controller_error(uint16_t len, const void *buf)
{
const struct mgmt_ev_controller_error *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Controller Error control\n");
return;
}
printf("@ Controller Error: 0x%2.2x\n", ev->error_code);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
#ifndef NELEM
#define NELEM(x) (sizeof(x) / sizeof((x)[0]))
#endif
static const char *settings_str[] = {
"powered", "connectable", "fast-connectable", "discoverable",
"pairable", "link-security", "ssp", "br/edr", "hs", "le",
"advertising",
};
static void mgmt_new_settings(uint16_t len, const void *buf)
{
uint32_t settings;
unsigned int i;
if (len < 4) {
printf("* Malformed New Settings control\n");
return;
}
settings = bt_get_le32(buf);
printf("@ New Settings: 0x%4.4x\n", settings);
printf("%-12c", ' ');
for (i = 0; i < NELEM(settings_str); i++) {
if (settings & (1 << i))
printf("%s ", settings_str[i]);
}
printf("\n");
buf += 4;
len -= 4;
packet_hexdump(buf, len);
}
static void mgmt_class_of_dev_changed(uint16_t len, const void *buf)
{
const struct mgmt_ev_class_of_dev_changed *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Class of Device Changed control\n");
return;
}
printf("@ Class of Device Changed: 0x%2.2x%2.2x%2.2x\n",
ev->class_of_dev[2],
ev->class_of_dev[1],
ev->class_of_dev[0]);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_local_name_changed(uint16_t len, const void *buf)
{
const struct mgmt_ev_local_name_changed *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Local Name Changed control\n");
return;
}
printf("@ Local Name Changed: %s (%s)\n", ev->name, ev->short_name);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_new_link_key(uint16_t len, const void *buf)
{
const struct mgmt_ev_new_link_key *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed New Link Key control\n");
return;
}
ba2str(&ev->key.addr.bdaddr, str);
printf("@ New Link Key: %s (%d)\n", str, ev->key.addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_new_long_term_key(uint16_t len, const void *buf)
{
const struct mgmt_ev_new_long_term_key *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed New Long Term Key control\n");
return;
}
ba2str(&ev->key.addr.bdaddr, str);
printf("@ New Long Term Key: %s (%d)\n", str, ev->key.addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_connected(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_connected *ev = buf;
uint32_t flags;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Connected control\n");
return;
}
flags = btohl(ev->flags);
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Connected: %s (%d) flags 0x%4.4x\n",
str, ev->addr.type, flags);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_disconnected(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_disconnected *ev = buf;
char str[18];
uint8_t reason;
uint16_t consumed_len;
if (len < sizeof(struct mgmt_addr_info)) {
printf("* Malformed Device Disconnected control\n");
return;
}
if (len < sizeof(*ev)) {
reason = MGMT_DEV_DISCONN_UNKNOWN;
consumed_len = len;
} else {
reason = ev->reason;
consumed_len = sizeof(*ev);
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
reason);
buf += consumed_len;
len -= consumed_len;
packet_hexdump(buf, len);
}
static void mgmt_connect_failed(uint16_t len, const void *buf)
{
const struct mgmt_ev_connect_failed *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Connect Failed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Connect Failed: %s (%d) status 0x%2.2x\n",
str, ev->addr.type, ev->status);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_pin_code_request(uint16_t len, const void *buf)
{
const struct mgmt_ev_pin_code_request *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed PIN Code Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ PIN Code Request: %s (%d) secure 0x%2.2x\n",
str, ev->addr.type, ev->secure);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_user_confirm_request(uint16_t len, const void *buf)
{
const struct mgmt_ev_user_confirm_request *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed User Confirmation Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ User Confirmation Request: %s (%d) hint %d value %d\n",
str, ev->addr.type, ev->confirm_hint, ev->value);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_user_passkey_request(uint16_t len, const void *buf)
{
const struct mgmt_ev_user_passkey_request *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed User Passkey Request control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ PIN User Passkey Request: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_auth_failed(uint16_t len, const void *buf)
{
const struct mgmt_ev_auth_failed *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Authentication Failed control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Authentication Failed: %s (%d) status 0x%2.2x\n",
str, ev->addr.type, ev->status);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_found(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_found *ev = buf;
uint32_t flags;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Found control\n");
return;
}
flags = btohl(ev->flags);
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Found: %s (%d) rssi %d flags 0x%4.4x\n",
str, ev->addr.type, ev->rssi, flags);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_discovering(uint16_t len, const void *buf)
{
const struct mgmt_ev_discovering *ev = buf;
if (len < sizeof(*ev)) {
printf("* Malformed Discovering control\n");
return;
}
printf("@ Discovering: 0x%2.2x (%d)\n", ev->discovering, ev->type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_blocked(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_blocked *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Blocked control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Blocked: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_unblocked(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_unblocked *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Unblocked control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Unblocked: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_device_unpaired(uint16_t len, const void *buf)
{
const struct mgmt_ev_device_unpaired *ev = buf;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Device Unpaired control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
printf("@ Device Unpaired: %s (%d)\n", str, ev->addr.type);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
static void mgmt_passkey_notify(uint16_t len, const void *buf)
{
const struct mgmt_ev_passkey_notify *ev = buf;
uint32_t passkey;
char str[18];
if (len < sizeof(*ev)) {
printf("* Malformed Passkey Notify control\n");
return;
}
ba2str(&ev->addr.bdaddr, str);
passkey = btohl(ev->passkey);
printf("@ Passkey Notify: %s (%d) passkey %06u entered %u\n",
str, ev->addr.type, passkey, ev->entered);
buf += sizeof(*ev);
len -= sizeof(*ev);
packet_hexdump(buf, len);
}
void control_message(uint16_t opcode, const void *data, uint16_t size)
{
switch (opcode) {
case MGMT_EV_INDEX_ADDED:
mgmt_index_added(size, data);
break;
case MGMT_EV_INDEX_REMOVED:
mgmt_index_removed(size, data);
break;
case MGMT_EV_CONTROLLER_ERROR:
mgmt_controller_error(size, data);
break;
case MGMT_EV_NEW_SETTINGS:
mgmt_new_settings(size, data);
break;
case MGMT_EV_CLASS_OF_DEV_CHANGED:
mgmt_class_of_dev_changed(size, data);
break;
case MGMT_EV_LOCAL_NAME_CHANGED:
mgmt_local_name_changed(size, data);
break;
case MGMT_EV_NEW_LINK_KEY:
mgmt_new_link_key(size, data);
break;
case MGMT_EV_NEW_LONG_TERM_KEY:
mgmt_new_long_term_key(size, data);
break;
case MGMT_EV_DEVICE_CONNECTED:
mgmt_device_connected(size, data);
break;
case MGMT_EV_DEVICE_DISCONNECTED:
mgmt_device_disconnected(size, data);
break;
case MGMT_EV_CONNECT_FAILED:
mgmt_connect_failed(size, data);
break;
case MGMT_EV_PIN_CODE_REQUEST:
mgmt_pin_code_request(size, data);
break;
case MGMT_EV_USER_CONFIRM_REQUEST:
mgmt_user_confirm_request(size, data);
break;
case MGMT_EV_USER_PASSKEY_REQUEST:
mgmt_user_passkey_request(size, data);
break;
case MGMT_EV_AUTH_FAILED:
mgmt_auth_failed(size, data);
break;
case MGMT_EV_DEVICE_FOUND:
mgmt_device_found(size, data);
break;
case MGMT_EV_DISCOVERING:
mgmt_discovering(size, data);
break;
case MGMT_EV_DEVICE_BLOCKED:
mgmt_device_blocked(size, data);
break;
case MGMT_EV_DEVICE_UNBLOCKED:
mgmt_device_unblocked(size, data);
break;
case MGMT_EV_DEVICE_UNPAIRED:
mgmt_device_unpaired(size, data);
break;
case MGMT_EV_PASSKEY_NOTIFY:
mgmt_passkey_notify(size, data);
break;
default:
printf("* Unknown control (code %d len %d)\n", opcode, size);
packet_hexdump(data, size);
break;
}
}
static void data_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data = user_data;
unsigned char control[32];
struct mgmt_hdr hdr;
struct msghdr msg;
struct iovec iov[2];
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(data->fd);
return;
}
iov[0].iov_base = &hdr;
iov[0].iov_len = MGMT_HDR_SIZE;
iov[1].iov_base = data->buf;
iov[1].iov_len = sizeof(data->buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = iov;
msg.msg_iovlen = 2;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
while (1) {
struct cmsghdr *cmsg;
struct timeval *tv = NULL;
struct timeval ctv;
uint16_t opcode, index, pktlen;
ssize_t len;
len = recvmsg(data->fd, &msg, MSG_DONTWAIT);
if (len < 0)
break;
if (len < MGMT_HDR_SIZE)
break;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_SOCKET)
continue;
if (cmsg->cmsg_type == SCM_TIMESTAMP) {
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
}
}
opcode = btohs(hdr.opcode);
index = btohs(hdr.index);
pktlen = btohs(hdr.len);
switch (data->channel) {
case HCI_CHANNEL_CONTROL:
packet_control(tv, index, opcode, data->buf, pktlen);
break;
case HCI_CHANNEL_MONITOR:
packet_monitor(tv, index, opcode, data->buf, pktlen);
btsnoop_write_hci(tv, index, opcode, data->buf, pktlen);
break;
}
}
}
static int open_socket(uint16_t channel)
{
struct sockaddr_hci addr;
int fd, opt = 1;
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
if (fd < 0) {
perror("Failed to open channel");
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = channel;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
if (errno == EINVAL) {
/* Fallback to hcidump support */
hcidump_fallback = true;
close(fd);
return -1;
}
perror("Failed to bind channel");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, &opt, sizeof(opt)) < 0) {
perror("Failed to enable timestamps");
close(fd);
return -1;
}
return fd;
}
static int open_channel(uint16_t channel)
{
struct control_data *data;
data = malloc(sizeof(*data));
if (!data)
return -1;
memset(data, 0, sizeof(*data));
data->channel = channel;
data->fd = open_socket(channel);
if (data->fd < 0) {
free(data);
return -1;
}
mainloop_add_fd(data->fd, EPOLLIN, data_callback, data, free_data);
return 0;
}
static void client_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data = user_data;
ssize_t len;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(data->fd);
return;
}
len = recv(data->fd, data->buf + data->offset,
sizeof(data->buf) - data->offset, MSG_DONTWAIT);
if (len < 0)
return;
data->offset += len;
if (data->offset > MGMT_HDR_SIZE) {
struct mgmt_hdr *hdr = (struct mgmt_hdr *) data->buf;
uint16_t pktlen = btohs(hdr->len);
if (data->offset > pktlen + MGMT_HDR_SIZE) {
uint16_t opcode = btohs(hdr->opcode);
uint16_t index = btohs(hdr->index);
packet_monitor(NULL, index, opcode,
data->buf + MGMT_HDR_SIZE, pktlen);
data->offset -= pktlen + MGMT_HDR_SIZE;
if (data->offset > 0)
memmove(data->buf, data->buf +
MGMT_HDR_SIZE + pktlen, data->offset);
}
}
}
static void server_accept_callback(int fd, uint32_t events, void *user_data)
{
struct control_data *data;
struct sockaddr_un addr;
socklen_t len;
int nfd;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(fd);
return;
}
memset(&addr, 0, sizeof(addr));
len = sizeof(addr);
nfd = accept(fd, (struct sockaddr *) &addr, &len);
if (nfd < 0) {
perror("Failed to accept client socket");
return;
}
printf("--- New monitor connection ---\n");
data = malloc(sizeof(*data));
if (!data) {
close(nfd);
return;
}
memset(data, 0, sizeof(*data));
data->channel = HCI_CHANNEL_MONITOR;
data->fd = nfd;
mainloop_add_fd(data->fd, EPOLLIN, client_callback, data, free_data);
}
static int server_fd = -1;
void control_server(const char *path)
{
struct sockaddr_un addr;
int fd;
if (server_fd >= 0)
return;
unlink(path);
fd = socket(PF_UNIX, SOCK_STREAM | O_CLOEXEC, 0);
if (fd < 0) {
perror("Failed to open server socket");
return;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, path);
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind server socket");
close(fd);
return;
}
if (listen(fd, 5) < 0) {
perror("Failed to listen server socket");
close(fd);
return;
}
if (mainloop_add_fd(fd, EPOLLIN, server_accept_callback,
NULL, NULL) < 0) {
close(fd);
return;
}
server_fd = fd;
}
void control_writer(const char *path)
{
btsnoop_create(path, BTSNOOP_TYPE_EXTENDED_HCI);
}
void control_reader(const char *path)
{
unsigned char buf[MAX_PACKET_SIZE];
uint16_t pktlen;
uint32_t type;
struct timeval tv;
if (btsnoop_open(path, &type) < 0)
return;
switch (type) {
case BTSNOOP_TYPE_HCI:
case BTSNOOP_TYPE_UART:
case BTSNOOP_TYPE_EXTENDED_PHY:
packet_del_filter(PACKET_FILTER_SHOW_INDEX);
break;
case BTSNOOP_TYPE_EXTENDED_HCI:
packet_add_filter(PACKET_FILTER_SHOW_INDEX);
break;
}
open_pager();
switch (type) {
case BTSNOOP_TYPE_HCI:
case BTSNOOP_TYPE_UART:
case BTSNOOP_TYPE_EXTENDED_HCI:
while (1) {
uint16_t index, opcode;
if (btsnoop_read_hci(&tv, &index, &opcode,
buf, &pktlen) < 0)
break;
packet_monitor(&tv, index, opcode, buf, pktlen);
}
break;
case BTSNOOP_TYPE_EXTENDED_PHY:
while (1) {
uint16_t frequency;
if (btsnoop_read_phy(&tv, &frequency,
buf, &pktlen) < 0)
break;
packet_simulator(&tv, frequency, buf, pktlen);
}
break;
}
close_pager();
btsnoop_close();
}
int control_tracing(void)
{
packet_add_filter(PACKET_FILTER_SHOW_INDEX);
if (server_fd >= 0)
return 0;
if (open_channel(HCI_CHANNEL_MONITOR) < 0) {
if (!hcidump_fallback)
return -1;
if (hcidump_tracing() < 0)
return -1;
return 0;
}
open_channel(HCI_CHANNEL_CONTROL);
return 0;
}

View File

@@ -0,0 +1,32 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
void control_writer(const char *path);
void control_reader(const char *path);
void control_server(const char *path);
int control_tracing(void);
void control_message(uint16_t opcode, const void *data, uint16_t size);

View File

@@ -0,0 +1,84 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; 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 "crc.h"
uint32_t crc24_bit_reverse(uint32_t value)
{
uint32_t result = 0;
uint8_t i;
for (i = 0; i < 24; i++)
result |= ((value >> i) & 1) << (23 - i);
return result;
}
uint32_t crc24_calculate(uint32_t preset, const uint8_t *data, uint8_t len)
{
uint32_t state = preset;
uint8_t i;
for (i = 0; i < len; i++) {
uint8_t n, cur = data[i];
for (n = 0; n < 8; n++) {
int next_bit = (state ^ cur) & 1;
cur >>= 1;
state >>= 1;
if (next_bit) {
state |= 1 << 23;
state ^= 0x5a6000;
}
}
}
return state;
}
uint32_t crc24_reverse(uint32_t crc, const uint8_t *data, uint8_t len)
{
uint32_t state = crc;
uint8_t i;
for (i = 0; i < len; i++) {
uint8_t n, cur = data[len - i - 1];
for (n = 0; n < 8; n++) {
int top_bit = state >> 23;
state = (state << 1) & 0xffffff;
state |= top_bit ^ ((cur >> (7 - n)) & 1);
if (top_bit)
state ^= 0xb4c000;
}
}
return state;
}

View File

@@ -0,0 +1,30 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdint.h>
uint32_t crc24_bit_reverse(uint32_t value);
uint32_t crc24_calculate(uint32_t preset, const uint8_t *data, uint8_t len);
uint32_t crc24_reverse(uint32_t crc, const uint8_t *data, uint8_t len);

View File

@@ -0,0 +1,171 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/prctl.h>
#include <sys/ioctl.h>
#include <termios.h>
#include "display.h"
static pid_t pager_pid = 0;
bool use_color(void)
{
static int cached_use_color = -1;
if (__builtin_expect(!!(cached_use_color < 0), 0))
cached_use_color = isatty(STDOUT_FILENO) > 0 || pager_pid > 0;
return cached_use_color;
}
int num_columns(void)
{
static int cached_num_columns = -1;
if (__builtin_expect(!!(cached_num_columns < 0), 0)) {
struct winsize ws;
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0)
return -1;
if (ws.ws_col > 0)
cached_num_columns = ws.ws_col;
}
return cached_num_columns;
}
static void close_pipe(int p[])
{
if (p[0] >= 0)
close(p[0]);
if (p[1] >= 0)
close(p[1]);
}
static void wait_for_terminate(pid_t pid)
{
siginfo_t dummy;
for (;;) {
memset(&dummy, 0, sizeof(dummy));
if (waitid(P_PID, pid, &dummy, WEXITED) < 0) {
if (errno == EINTR)
continue;
return;
}
return;
}
}
void open_pager(void)
{
const char *pager;
pid_t parent_pid;
int fd[2];
if (pager_pid > 0)
return;
pager = getenv("PAGER");
if (pager) {
if (!*pager || strcmp(pager, "cat") == 0)
return;
}
if (!(isatty(STDOUT_FILENO) > 0))
return;
num_columns();
if (pipe(fd) < 0) {
perror("Failed to create pager pipe");
return;
}
parent_pid = getpid();
pager_pid = fork();
if (pager_pid < 0) {
perror("Failed to fork pager");
close_pipe(fd);
return;
}
if (pager_pid == 0) {
dup2(fd[0], STDIN_FILENO);
close_pipe(fd);
setenv("LESS", "FRSX", 0);
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
_exit(EXIT_FAILURE);
if (getppid() != parent_pid)
_exit(EXIT_SUCCESS);
if (pager) {
execlp(pager, pager, NULL);
execl("/bin/sh", "sh", "-c", pager, NULL);
}
execlp("pager", "pager", NULL);
execlp("less", "less", NULL);
execlp("more", "more", NULL);
_exit(EXIT_FAILURE);
}
if (dup2(fd[1], STDOUT_FILENO) < 0) {
perror("Failed to duplicate pager pipe");
return;
}
close_pipe(fd);
}
void close_pager(void)
{
if (pager_pid <= 0)
return;
fclose(stdout);
kill(pager_pid, SIGCONT);
wait_for_terminate(pager_pid);
pager_pid = 0;
}

View File

@@ -0,0 +1,60 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdbool.h>
bool use_color(void);
#define COLOR_OFF "\x1B[0m"
#define COLOR_BLACK "\x1B[0;30m"
#define COLOR_RED "\x1B[0;31m"
#define COLOR_GREEN "\x1B[0;32m"
#define COLOR_YELLOW "\x1B[0;33m"
#define COLOR_BLUE "\x1B[0;34m"
#define COLOR_MAGENTA "\x1B[0;35m"
#define COLOR_CYAN "\x1B[0;36m"
#define COLOR_WHITE "\x1B[0;37m"
#define COLOR_WHITE_BG "\x1B[0;47m"
#define COLOR_HIGHLIGHT "\x1B[1;39m"
#define COLOR_ERROR "\x1B[1;31m"
#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
do { \
printf("%*c%s%s%s%s" fmt "%s\n", (indent), ' ', \
use_color() ? (color1) : "", prefix, title, \
use_color() ? (color2) : "", ## args, \
use_color() ? COLOR_OFF : ""); \
} while (0)
#define print_text(color, fmt, args...) \
print_indent(8, COLOR_OFF, "", "", color, fmt, ## args)
#define print_field(fmt, args...) \
print_indent(8, COLOR_OFF, "", "", COLOR_OFF, fmt, ## args)
int num_columns(void);
void open_pager(void);
void close_pager(void);

View File

@@ -0,0 +1,411 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include "mainloop.h"
#include "packet.h"
#include "hcidump.h"
struct hcidump_data {
uint16_t index;
int fd;
};
static void free_data(void *user_data)
{
struct hcidump_data *data = user_data;
close(data->fd);
free(data);
}
static int open_hci_dev(uint16_t index)
{
struct sockaddr_hci addr;
struct hci_filter flt;
int fd, opt = 1;
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
if (fd < 0) {
perror("Failed to open channel");
return -1;
}
/* Setup filter */
hci_filter_clear(&flt);
hci_filter_all_ptypes(&flt);
hci_filter_all_events(&flt);
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
perror("Failed to set HCI filter");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
perror("Failed to enable HCI data direction info");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
perror("Failed to enable HCI time stamps");
close(fd);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = index;
addr.hci_channel = HCI_CHANNEL_RAW;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind channel");
close(fd);
return -1;
}
return fd;
}
static void device_callback(int fd, uint32_t events, void *user_data)
{
struct hcidump_data *data = user_data;
unsigned char buf[HCI_MAX_FRAME_SIZE * 2];
unsigned char control[64];
struct msghdr msg;
struct iovec iov;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(fd);
return;
}
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
while (1) {
struct cmsghdr *cmsg;
struct timeval *tv = NULL;
struct timeval ctv;
int dir = -1;
ssize_t len;
len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0)
break;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_HCI)
continue;
switch (cmsg->cmsg_type) {
case HCI_DATA_DIR:
memcpy(&dir, CMSG_DATA(cmsg), sizeof(dir));
break;
case HCI_CMSG_TSTAMP:
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
break;
}
}
if (dir < 0 || len < 1)
continue;
switch (buf[0]) {
case HCI_COMMAND_PKT:
packet_hci_command(tv, data->index, buf + 1, len - 1);
break;
case HCI_EVENT_PKT:
packet_hci_event(tv, data->index, buf + 1, len - 1);
break;
case HCI_ACLDATA_PKT:
packet_hci_acldata(tv, data->index, !!dir,
buf + 1, len - 1);
break;
case HCI_SCODATA_PKT:
packet_hci_scodata(tv, data->index, !!dir,
buf + 1, len - 1);
break;
}
}
}
static void open_device(uint16_t index)
{
struct hcidump_data *data;
data = malloc(sizeof(*data));
if (!data)
return;
memset(data, 0, sizeof(*data));
data->index = index;
data->fd = open_hci_dev(index);
if (data->fd < 0) {
free(data);
return;
}
mainloop_add_fd(data->fd, EPOLLIN, device_callback, data, free_data);
}
static void device_info(int fd, uint16_t index, uint8_t *type, uint8_t *bus,
bdaddr_t *bdaddr, char *name)
{
struct hci_dev_info di;
memset(&di, 0, sizeof(di));
di.dev_id = index;
if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0) {
perror("Failed to get device information");
return;
}
*type = di.type >> 4;
*bus = di.type & 0x0f;
bacpy(bdaddr, &di.bdaddr);
memcpy(name, di.name, 8);
}
static void device_list(int fd, int max_dev)
{
struct hci_dev_list_req *dl;
struct hci_dev_req *dr;
int i;
dl = malloc(max_dev * sizeof(*dr) + sizeof(*dl));
if (!dl) {
perror("Failed to allocate device list memory");
return;
}
memset(dl, 0, max_dev * sizeof(*dr) + sizeof(*dl));
dl->dev_num = max_dev;
dr = dl->dev_req;
if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
perror("Failed to get device list");
goto done;
}
for (i = 0; i < dl->dev_num; i++, dr++) {
struct timeval tmp_tv, *tv = NULL;
uint8_t type = 0xff, bus = 0xff;
char str[18], name[8] = "";
bdaddr_t bdaddr;
bacpy(&bdaddr, BDADDR_ANY);
if (!gettimeofday(&tmp_tv, NULL))
tv = &tmp_tv;
device_info(fd, dr->dev_id, &type, &bus, &bdaddr, name);
ba2str(&bdaddr, str);
packet_new_index(tv, dr->dev_id, str, type, bus, name);
open_device(dr->dev_id);
}
done:
free(dl);
}
static int open_stack_internal(void)
{
struct sockaddr_hci addr;
struct hci_filter flt;
int fd, opt = 1;
fd = socket(AF_BLUETOOTH, SOCK_RAW | O_CLOEXEC, BTPROTO_HCI);
if (fd < 0) {
perror("Failed to open channel");
return -1;
}
/* Setup filter */
hci_filter_clear(&flt);
hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
perror("Failed to set HCI filter");
close(fd);
return -1;
}
if (setsockopt(fd, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
perror("Failed to enable HCI time stamps");
close(fd);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.hci_family = AF_BLUETOOTH;
addr.hci_dev = HCI_DEV_NONE;
addr.hci_channel = HCI_CHANNEL_RAW;
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
perror("Failed to bind channel");
close(fd);
return -1;
}
device_list(fd, HCI_MAX_DEV);
return fd;
}
static void stack_internal_callback(int fd, uint32_t events, void *user_data)
{
unsigned char buf[HCI_MAX_FRAME_SIZE];
unsigned char control[32];
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
ssize_t len;
hci_event_hdr *eh;
evt_stack_internal *si;
evt_si_device *sd;
struct timeval *tv = NULL;
struct timeval ctv;
uint8_t type = 0xff, bus = 0xff;
char str[18], name[8] = "";
bdaddr_t bdaddr;
bacpy(&bdaddr, BDADDR_ANY);
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_remove_fd(fd);
return;
}
iov.iov_base = buf;
iov.iov_len = sizeof(buf);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = control;
msg.msg_controllen = sizeof(control);
len = recvmsg(fd, &msg, MSG_DONTWAIT);
if (len < 0)
return;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != SOL_HCI)
continue;
switch (cmsg->cmsg_type) {
case HCI_CMSG_TSTAMP:
memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
tv = &ctv;
break;
}
}
if (len < 1 + HCI_EVENT_HDR_SIZE + EVT_STACK_INTERNAL_SIZE +
EVT_SI_DEVICE_SIZE)
return;
if (buf[0] != HCI_EVENT_PKT)
return;
eh = (hci_event_hdr *) (buf + 1);
if (eh->evt != EVT_STACK_INTERNAL)
return;
si = (evt_stack_internal *) (buf + 1 + HCI_EVENT_HDR_SIZE);
if (si->type != EVT_SI_DEVICE)
return;
sd = (evt_si_device *) &si->data;
switch (sd->event) {
case HCI_DEV_REG:
device_info(fd, sd->dev_id, &type, &bus, &bdaddr, name);
ba2str(&bdaddr, str);
packet_new_index(tv, sd->dev_id, str, type, bus, name);
open_device(sd->dev_id);
break;
case HCI_DEV_UNREG:
ba2str(&bdaddr, str);
packet_del_index(tv, sd->dev_id, str);
break;
}
}
int hcidump_tracing(void)
{
struct hcidump_data *data;
data = malloc(sizeof(*data));
if (!data)
return -1;
memset(data, 0, sizeof(*data));
data->index = HCI_DEV_NONE;
data->fd = open_stack_internal();
if (data->fd < 0) {
free(data);
return -1;
}
mainloop_add_fd(data->fd, EPOLLIN, stack_internal_callback,
data, free_data);
return 0;
}

View File

@@ -0,0 +1,25 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
int hcidump_tracing(void);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
#include <stdbool.h>
struct l2cap_frame {
uint16_t index;
bool in;
uint16_t handle;
uint16_t cid;
const void *data;
uint16_t size;
};
static inline void l2cap_frame_init(struct l2cap_frame *frame,
uint16_t index, bool in, uint16_t handle,
uint16_t cid, const void *data, uint16_t size)
{
frame->index = index;
frame->in = in;
frame->handle = handle;
frame->cid = cid;
frame->data = data;
frame->size = size;
}
static inline void l2cap_frame_pull(struct l2cap_frame *frame,
const struct l2cap_frame *source, uint16_t len)
{
frame->index = source->index;
frame->in = source->in;
frame->handle = source->handle;
frame->cid = source->cid;
frame->data = source->data + len;
frame->size = source->size - len;
}
void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags,
const void *data, uint16_t size);

View File

@@ -0,0 +1,549 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <inttypes.h>
#include <bluetooth/bluetooth.h>
#include "display.h"
#include "packet.h"
#include "crc.h"
#include "bt.h"
#include "ll.h"
#define COLOR_OPCODE COLOR_MAGENTA
#define COLOR_OPCODE_UNKNOWN COLOR_WHITE_BG
#define MAX_CHANNEL 16
struct channel_data {
uint32_t access_addr;
uint32_t crc_init;
};
static struct channel_data channel_list[MAX_CHANNEL];
static void set_crc_init(uint32_t access_addr, uint32_t crc_init)
{
int i;
for (i = 0; i < MAX_CHANNEL; i++) {
if (channel_list[i].access_addr == 0x00000000 ||
channel_list[i].access_addr == access_addr) {
channel_list[i].access_addr = access_addr;
channel_list[i].crc_init = crc_init;
break;
}
}
}
static uint32_t get_crc_init(uint32_t access_addr)
{
int i;
for (i = 0; i < MAX_CHANNEL; i++) {
if (channel_list[i].access_addr == access_addr)
return channel_list[i].crc_init;
}
return 0x00000000;
}
static void advertising_packet(const void *data, uint8_t size)
{
const uint8_t *ptr = data;
uint8_t pdu_type, length, win_size, hop, sca;
bool tx_add, rx_add;
uint32_t access_addr, crc_init;
uint16_t win_offset, interval, latency, timeout;
const char *str;
if (size < 2) {
print_text(COLOR_ERROR, "packet too short");
packet_hexdump(data, size);
return;
}
pdu_type = ptr[0] & 0x0f;
tx_add = !!(ptr[0] & 0x40);
rx_add = !!(ptr[0] & 0x80);
length = ptr[1] & 0x3f;
switch (pdu_type) {
case 0x00:
str = "ADV_IND";
break;
case 0x01:
str = "ADV_DIRECT_IND";
break;
case 0x02:
str = "ADV_NONCONN_IND";
break;
case 0x03:
str = "SCAN_REQ";
break;
case 0x04:
str = "SCAN_RSP";
break;
case 0x05:
str = "CONNECT_REQ";
break;
case 0x06:
str = "ADV_SCAN_IND";
break;
default:
str = "Reserved";
break;
}
print_field("Type: %s (0x%2.2x)", str, pdu_type);
print_field("TxAdd: %u", tx_add);
print_field("RxAdd: %u", rx_add);
print_field("Length: %u", length);
if (length != size - 2) {
print_text(COLOR_ERROR, "packet size mismatch");
packet_hexdump(data + 2, size - 2);
return;
}
switch (pdu_type) {
case 0x00: /* ADV_IND */
case 0x02: /* AVD_NONCONN_IND */
case 0x06: /* ADV_SCAN_IND */
case 0x04: /* SCAN_RSP */
if (length < 6) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Advertiser address", data + 2, tx_add);
packet_print_ad(data + 8, length - 6);
break;
case 0x01: /* ADV_DIRECT_IND */
if (length < 12) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Advertiser address", data + 2, tx_add);
packet_print_addr("Inititator address", data + 8, rx_add);
break;
case 0x03: /* SCAN_REQ */
if (length < 12) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Scanner address", data + 2, tx_add);
packet_print_addr("Advertiser address", data + 8, rx_add);
break;
case 0x05: /* CONNECT_REQ */
if (length < 34) {
print_text(COLOR_ERROR, "payload too short");
packet_hexdump(data + 2, length);
return;
}
packet_print_addr("Inititator address", data + 2, tx_add);
packet_print_addr("Advertiser address", data + 8, rx_add);
access_addr = ptr[14] | ptr[15] << 8 |
ptr[16] << 16 | ptr[17] << 24;
crc_init = ptr[18] | ptr[19] << 8 | ptr[20] << 16;
print_field("Access address: 0x%8.8x", access_addr);
print_field("CRC init: 0x%6.6x", crc_init);
set_crc_init(access_addr, crc24_bit_reverse(crc_init));
win_size = ptr[21];
win_offset = ptr[22] | ptr[23] << 8;
interval = ptr[24] | ptr[25] << 8;
latency = ptr[26] | ptr[27] << 8;
timeout = ptr[28] | ptr[29] << 8;
print_field("Transmit window size: %u", win_size);
print_field("Transmit window offset: %u", win_offset);
print_field("Connection interval: %u", interval);
print_field("Connection slave latency: %u", latency);
print_field("Connection supervision timeout: %u", timeout);
packet_print_channel_map_ll(ptr + 30);
hop = ptr[35] & 0x1f;
sca = (ptr[35] & 0xe0) >> 5;
switch (sca) {
case 0:
str = "251 ppm to 500 ppm";
break;
case 1:
str = "151 ppm to 250 ppm";
break;
case 2:
str = "101 ppm to 150ppm";
break;
case 3:
str = "76 ppm to 100 ppm";
break;
case 4:
str = "51 ppm to 75 ppm";
break;
case 5:
str = "31 ppm to 50 ppm";
break;
case 6:
str = "21 ppm to 30 ppm";
break;
case 7:
str = "0 ppm to 20 ppm";
break;
default:
str = "Invalid";
break;
}
print_field("Hop increment: %u", hop);
print_field("Sleep clock accuracy: %s (%u)", str, sca);
break;
default:
packet_hexdump(data + 2, length);
break;
}
}
static void data_packet(const void *data, uint8_t size)
{
const uint8_t *ptr = data;
uint8_t llid, length;
bool nesn, sn, md;
const char *str;
if (size < 2) {
print_text(COLOR_ERROR, "packet too short");
packet_hexdump(data, size);
return;
}
llid = ptr[0] & 0x03;
nesn = !!(ptr[0] & 0x04);
sn = !!(ptr[0] & 0x08);
md = !!(ptr[0] & 0x10);
length = ptr[1] & 0x1f;
switch (llid) {
case 0x01:
if (length > 0)
str = "Continuation fragement of L2CAP message";
else
str = "Empty message";
break;
case 0x02:
str = "Start of L2CAP message";
break;
case 0x03:
str = "Control";
break;
default:
str = "Reserved";
break;
}
print_field("LLID: %s (0x%2.2x)", str, llid);
print_field("Next expected sequence number: %u", nesn);
print_field("Sequence number: %u", sn);
print_field("More data: %u", md);
print_field("Length: %u", length);
switch (llid) {
case 0x03:
llcp_packet(data + 2, size - 2);
break;
default:
packet_hexdump(data + 2, size - 2);
break;
}
}
void ll_packet(uint16_t frequency, const void *data, uint8_t size)
{
const struct bt_ll_hdr *hdr = data;
uint8_t channel = (frequency - 2402) / 2;
uint32_t access_addr;
char access_str[12];
const char *channel_label, *channel_color;
const uint8_t *pdu_data;
uint8_t pdu_len;
uint32_t pdu_crc, crc, crc_init;
if (size < sizeof(*hdr)) {
print_text(COLOR_ERROR, "packet missing header");
packet_hexdump(data, size);
return;
}
if (size < sizeof(*hdr) + 3) {
print_text(COLOR_ERROR, "packet missing checksum");
packet_hexdump(data, size);
return;
}
if (hdr->preamble != 0xaa && hdr->preamble != 0x55) {
print_text(COLOR_ERROR, "invalid preamble");
packet_hexdump(data, size);
return;
}
access_addr = btohl(hdr->access_addr);
pdu_data = data + sizeof(*hdr);
pdu_len = size - sizeof(*hdr) - 3;
pdu_crc = pdu_data[pdu_len + 0] | (pdu_data[pdu_len + 1] << 8) |
(pdu_data[pdu_len + 2] << 16);
if (access_addr == 0x8e89bed6) {
channel_label = "Advertising channel: ";
channel_color = COLOR_MAGENTA;
} else {
channel_label = "Data channel: ";
channel_color = COLOR_CYAN;
}
sprintf(access_str, "0x%8.8x", access_addr);
print_indent(6, channel_color, channel_label, access_str, COLOR_OFF,
" (channel %d) len %d crc 0x%6.6x", channel, pdu_len, pdu_crc);
if (access_addr == 0x8e89bed6)
crc_init = 0xaaaaaa;
else
crc_init = get_crc_init(access_addr);
if (crc_init) {
crc = crc24_calculate(crc_init, pdu_data, pdu_len);
if (crc != pdu_crc) {
print_text(COLOR_ERROR, "invalid checksum");
packet_hexdump(pdu_data, pdu_len);
return;
}
} else
print_text(COLOR_ERROR, "unknown access address");
if (access_addr == 0x8e89bed6)
advertising_packet(pdu_data, pdu_len);
else
data_packet(pdu_data, pdu_len);
}
static void null_pdu(const void *data, uint8_t size)
{
}
static void conn_update_req(const void *data, uint8_t size)
{
const struct bt_ll_conn_update_req *pdu = data;
print_field("Transmit window size: %u", pdu->win_size);
print_field("Transmit window offset: %u", btohs(pdu->win_offset));
print_field("Connection interval: %u", btohs(pdu->interval));
print_field("Connection slave latency: %u", btohs(pdu->latency));
print_field("Connection supervision timeout: %u", btohs(pdu->timeout));;
print_field("Connection instant: %u", btohs(pdu->instant));
}
static void channel_map_req(const void *data, uint8_t size)
{
const struct bt_ll_channel_map_req *pdu = data;
packet_print_channel_map_ll(pdu->map);
print_field("Connection instant: %u", btohs(pdu->instant));
}
static void terminate_ind(const void *data, uint8_t size)
{
const struct bt_ll_terminate_ind *pdu = data;
print_field("Error code: 0x%2.2x", pdu->error);
}
static void enc_req(const void *data, uint8_t size)
{
const struct bt_ll_enc_req *pdu = data;
print_field("Rand: 0x%16.16" PRIx64, btohll(pdu->rand));
print_field("EDIV: 0x%4.4x", btohs(pdu->ediv));
print_field("SKD (master): 0x%16.16" PRIx64, btohll(pdu->skd));
print_field("IV (master): 0x%8.8x", btohl(pdu->iv));
}
static void enc_rsp(const void *data, uint8_t size)
{
const struct bt_ll_enc_rsp *pdu = data;
print_field("SKD (slave): 0x%16.16" PRIx64, btohll(pdu->skd));
print_field("IV (slave): 0x%8.8x", btohl(pdu->iv));
}
static const char *opcode_to_string(uint8_t opcode);
static void unknown_rsp(const void *data, uint8_t size)
{
const struct bt_ll_unknown_rsp *pdu = data;
print_field("Unknown type: %s (0x%2.2x)",
opcode_to_string(pdu->type), pdu->type);
}
static void feature_req(const void *data, uint8_t size)
{
const struct bt_ll_feature_req *pdu = data;
packet_print_features_ll(pdu->features);
}
static void feature_rsp(const void *data, uint8_t size)
{
const struct bt_ll_feature_rsp *pdu = data;
packet_print_features_ll(pdu->features);
}
static void version_ind(const void *data, uint8_t size)
{
const struct bt_ll_version_ind *pdu = data;
packet_print_version("Version", pdu->version,
"Subversion", btohs(pdu->subversion));
packet_print_company("Company", btohs(pdu->company));
}
static void reject_ind(const void *data, uint8_t size)
{
const struct bt_ll_reject_ind *pdu = data;
print_field("Error code: 0x%2.2x", pdu->error);
}
struct llcp_data {
uint8_t opcode;
const char *str;
void (*func) (const void *data, uint8_t size);
uint8_t size;
bool fixed;
};
static const struct llcp_data llcp_table[] = {
{ 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
{ 0x01, "LL_CHANNEL_MAP_REQ", channel_map_req, 7, true },
{ 0x02, "LL_TERMINATE_IND", terminate_ind, 1, true },
{ 0x03, "LL_ENC_REQ", enc_req, 22, true },
{ 0x04, "LL_ENC_RSP", enc_rsp, 12, true },
{ 0x05, "LL_START_ENC_REQ", null_pdu, 0, true },
{ 0x06, "LL_START_ENC_RSP", null_pdu, 0, true },
{ 0x07, "LL_UNKNOWN_RSP", unknown_rsp, 1, true },
{ 0x08, "LL_FEATURE_REQ", feature_req, 8, true },
{ 0x09, "LL_FEATURE_RSP", feature_rsp, 8, true },
{ 0x0a, "LL_PAUSE_ENC_REQ", null_pdu, 0, true },
{ 0x0b, "LL_PAUSE_ENC_RSP", null_pdu, 0, true },
{ 0x0c, "LL_VERSION_IND", version_ind, 5, true },
{ 0x0d, "LL_REJECT_IND", reject_ind, 1, true },
{ }
};
static const char *opcode_to_string(uint8_t opcode)
{
int i;
for (i = 0; llcp_table[i].str; i++) {
if (llcp_table[i].opcode == opcode)
return llcp_table[i].str;
}
return "Unknown";
}
void llcp_packet(const void *data, uint8_t size)
{
uint8_t opcode = ((const uint8_t *) data)[0];
const struct llcp_data *llcp_data = NULL;
const char *opcode_color, *opcode_str;
int i;
for (i = 0; llcp_table[i].str; i++) {
if (llcp_table[i].opcode == opcode) {
llcp_data = &llcp_table[i];
break;
}
}
if (llcp_data) {
if (llcp_data->func)
opcode_color = COLOR_OPCODE;
else
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = llcp_data->str;
} else {
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = "Unknown";
}
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
" (0x%2.2x)", opcode);
if (!llcp_data || !llcp_data->func) {
packet_hexdump(data + 1, size - 1);
return;
}
if (llcp_data->fixed) {
if (size - 1 != llcp_data->size) {
print_text(COLOR_ERROR, "invalid packet size");
packet_hexdump(data + 1, size - 1);
return;
}
} else {
if (size - 1 < llcp_data->size) {
print_text(COLOR_ERROR, "too short packet");
packet_hexdump(data + 1, size - 1);
return;
}
}
llcp_data->func(data + 1, size - 1);
}

View File

@@ -0,0 +1,28 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
void ll_packet(uint16_t frequency, const void *data, uint8_t size);
void llcp_packet(const void *data, uint8_t size);

View File

@@ -0,0 +1,215 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 "display.h"
#include "packet.h"
#include "lmp.h"
#define COLOR_OPCODE COLOR_MAGENTA
#define COLOR_OPCODE_UNKNOWN COLOR_WHITE_BG
#define ESC4(x) ((127 << 8) | (x))
struct lmp_data {
uint16_t opcode;
const char *str;
void (*func) (const void *data, uint8_t size);
uint8_t size;
bool fixed;
};
static const struct lmp_data lmp_table[] = {
{ 1, "LMP_name_req" },
{ 2, "LMP_name_res" },
{ 3, "LMP_accepted" },
{ 4, "LMP_not_accepted" },
{ 5, "LMP_clkoffset_req" },
{ 6, "LMP_clkoffset_res" },
{ 7, "LMP_detach" },
{ 8, "LMP_in_rand" },
{ 9, "LMP_comb_key" },
{ 10, "LMP_unit_key" },
{ 11, "LMP_au_rand" },
{ 12, "LMP_sres" },
{ 13, "LMP_temp_rand" },
{ 14, "LMP_temp_key" },
{ 15, "LMP_encryption_mode_req" },
{ 16, "LMP_encryption_key_size_req" },
{ 17, "LMP_start_encryption_req" },
{ 18, "LMP_stop_encryption_req" },
{ 19, "LMP_switch_req" },
{ 20, "LMP_hold" },
{ 21, "LMP_hold_req" },
{ 22, "LMP_sniff" },
{ 23, "LMP_sniff_req" },
{ 24, "LMP_unsniff_req" },
{ 25, "LMP_park_req" },
{ 26, "LMP_park" },
{ 27, "LMP_set_broadcast_scan_window" },
{ 28, "LMP_modify_beacon" },
{ 29, "LMP_unpark_BD_ADDR_req" },
{ 30, "LMP_unpark_PM_ADDR_req" },
{ 31, "LMP_incr_power_req" },
{ 32, "LMP_decr_power_req" },
{ 33, "LMP_max_power" },
{ 34, "LMP_min_power" },
{ 35, "LMP_auto_rate" },
{ 36, "LMP_preferred_rate" },
{ 37, "LMP_version_req" },
{ 38, "LMP_version_res" },
{ 39, "LMP_features_req" },
{ 40, "LMP_features_res" },
{ 41, "LMP_quality_of_service" },
{ 42, "LMP_quality_of_service_req" },
{ 43, "LMP_SCO_link_req" },
{ 44, "LMP_remove_SCO_link_req" },
{ 45, "LMP_max_slot" },
{ 46, "LMP_max_slot_req" },
{ 47, "LMP_timing_accuracy_req" },
{ 48, "LMP_timing_accuracy_res" },
{ 49, "LMP_setup_complete" },
{ 50, "LMP_use_semi_permanent_key" },
{ 51, "LMP_host_connection_req" },
{ 52, "LMP_slot_offset" },
{ 53, "LMP_page_mode_req" },
{ 54, "LMP_Page_scan_mode_req" },
{ 55, "LMP_supervision_timeout" },
{ 56, "LMP_test_activate" },
{ 57, "LMP_test_control" },
{ 58, "LMP_encryption_key_size_mask_req" },
{ 59, "LMP_encryption_key_size_mask_res" },
{ 60, "LMP_set_AFH" },
{ 61, "LMP_encapsulated_header" },
{ 62, "LMP_encapsulated_payload" },
{ 63, "LMP_simple_pairing_confirm" },
{ 64, "LMP_simple_pairing_number" },
{ 65, "LMP_DHkey_check" },
{ 66, "LMP_pause_encryption_aes_req" },
{ ESC4(1), "LMP_accepted_ext" },
{ ESC4(2), "LMP_not_accepted_ext" },
{ ESC4(3), "LMP_features_req_ext" },
{ ESC4(4), "LMP_features_res_ext" },
{ ESC4(5), "LMP_clk_adj" },
{ ESC4(6), "LMP_clk_adj_ack" },
{ ESC4(7), "LMP_clk_adj_req" },
{ ESC4(11), "LMP_packet_type_table" },
{ ESC4(12), "LMP_eSCO_link_req" },
{ ESC4(13), "LMP_remove_eSCO_link_req" },
{ ESC4(16), "LMP_channel_classification_req" },
{ ESC4(17), "LMP_channel_classification" },
{ ESC4(21), "LMP_sniff_subrating_req" },
{ ESC4(22), "LMP_sniff_subrating_res" },
{ ESC4(23), "LMP_pause_encryption_req" },
{ ESC4(24), "LMP_resume_encryption_req" },
{ ESC4(25), "LMP_IO_capability_req" },
{ ESC4(26), "LMP_IO_capability_res" },
{ ESC4(27), "LMP_numeric_comparision_failed" },
{ ESC4(28), "LMP_passkey_failed" },
{ ESC4(29), "LMP_oob_failed" },
{ ESC4(30), "LMP_keypress_notification" },
{ ESC4(31), "LMP_power_control_req" },
{ ESC4(32), "LMP_power_control_res" },
{ ESC4(33), "LMP_ping_req" },
{ ESC4(34), "LMP_ping_res" },
{ }
};
void lmp_packet(const void *data, uint8_t size)
{
const struct lmp_data *lmp_data = NULL;
const char *opcode_color, *opcode_str;
uint16_t opcode;
uint8_t tid, off;
int i;
tid = ((const uint8_t *) data)[0] & 0x01;
opcode = (((const uint8_t *) data)[0] & 0xfe) >> 1;
switch (opcode) {
case 127:
opcode = ESC4(((const uint8_t *) data)[1]);
off = 2;
break;
case 126:
case 125:
case 124:
return;
default:
off = 1;
break;
}
for (i = 0; lmp_table[i].str; i++) {
if (lmp_table[i].opcode == opcode) {
lmp_data = &lmp_table[i];
break;
}
}
if (lmp_data) {
if (lmp_data->func)
opcode_color = COLOR_OPCODE;
else
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = lmp_data->str;
} else {
opcode_color = COLOR_OPCODE_UNKNOWN;
opcode_str = "Unknown";
}
if (opcode & 0xff00)
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
" (%d/%d) TID %d", opcode >> 8, opcode & 0xff, tid);
else
print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
" (%d) TID %d", opcode, tid);
if (!lmp_data || !lmp_data->func) {
packet_hexdump(data + off, size - off);
return;
}
if (lmp_data->fixed) {
if (size - 1 != lmp_data->size) {
print_text(COLOR_ERROR, "invalid packet size");
packet_hexdump(data + off, size - off);
return;
}
} else {
if (size - 1 < lmp_data->size) {
print_text(COLOR_ERROR, "too short packet");
packet_hexdump(data + off, size - off);
return;
}
}
lmp_data->func(data + off, size - off);
}

View File

@@ -0,0 +1,27 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
void lmp_packet(const void *data, uint8_t size);

View File

@@ -0,0 +1,167 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include "mainloop.h"
#include "packet.h"
#include "control.h"
static void signal_callback(int signum, void *user_data)
{
switch (signum) {
case SIGINT:
case SIGTERM:
mainloop_quit();
break;
}
}
static void usage(void)
{
printf("btmon - Bluetooth monitor\n"
"Usage:\n");
printf("\tbtmon [options]\n");
printf("options:\n"
"\t-r, --read <file> Read traces in btsnoop format\n"
"\t-w, --write <file> Save traces in btsnoop format\n"
"\t-s, --server <socket> Start monitor server socket\n"
"\t-i, --index <num> Show only specified controller\n"
"\t-t, --time Show time instead of time offset\n"
"\t-T, --date Show time and date information\n"
"\t-S, --sco Dump SCO traffic\n"
"\t-h, --help Show help options\n");
}
static const struct option main_options[] = {
{ "read", required_argument, NULL, 'r' },
{ "write", required_argument, NULL, 'w' },
{ "server", required_argument, NULL, 's' },
{ "index", required_argument, NULL, 'i' },
{ "time", no_argument, NULL, 't' },
{ "date", no_argument, NULL, 'T' },
{ "sco", no_argument, NULL, 'S' },
{ "version", no_argument, NULL, 'v' },
{ "help", no_argument, NULL, 'h' },
{ }
};
int main(int argc, char *argv[])
{
unsigned long filter_mask = 0;
const char *str, *reader_path = NULL, *writer_path = NULL;
sigset_t mask;
mainloop_init();
filter_mask |= PACKET_FILTER_SHOW_TIME_OFFSET;
for (;;) {
int opt;
opt = getopt_long(argc, argv, "r:w:s:i:tTSvh",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
case 'r':
reader_path = optarg;
break;
case 'w':
writer_path = optarg;
break;
case 's':
control_server(optarg);
break;
case 'i':
if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
str = optarg + 3;
else
str = optarg;
if (!isdigit(*str)) {
usage();
return EXIT_FAILURE;
}
packet_select_index(atoi(str));
break;
case 't':
filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
filter_mask |= PACKET_FILTER_SHOW_TIME;
break;
case 'T':
filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
filter_mask |= PACKET_FILTER_SHOW_TIME;
filter_mask |= PACKET_FILTER_SHOW_DATE;
break;
case 'S':
filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
break;
case 'v':
printf("%s\n", VERSION);
return EXIT_SUCCESS;
case 'h':
usage();
return EXIT_SUCCESS;
default:
return EXIT_FAILURE;
}
}
if (argc - optind > 0) {
fprintf(stderr, "Invalid command line parameters\n");
return EXIT_FAILURE;
}
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
sigaddset(&mask, SIGTERM);
mainloop_set_signal(&mask, signal_callback, NULL, NULL);
printf("Bluetooth monitor ver %s\n", VERSION);
packet_set_filter(filter_mask);
if (reader_path) {
control_reader(reader_path);
return EXIT_SUCCESS;
}
if (writer_path)
control_writer(writer_path);
if (control_tracing() < 0)
return EXIT_FAILURE;
return mainloop_run();
}

View File

@@ -0,0 +1,389 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/signalfd.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include "mainloop.h"
#define MAX_EPOLL_EVENTS 10
static int epoll_fd;
static int epoll_terminate;
struct mainloop_data {
int fd;
uint32_t events;
mainloop_event_func callback;
mainloop_destroy_func destroy;
void *user_data;
};
#define MAX_MAINLOOP_ENTRIES 128
static struct mainloop_data *mainloop_list[MAX_MAINLOOP_ENTRIES];
struct timeout_data {
int fd;
mainloop_timeout_func callback;
mainloop_destroy_func destroy;
void *user_data;
};
struct signal_data {
int fd;
sigset_t mask;
mainloop_signal_func callback;
mainloop_destroy_func destroy;
void *user_data;
};
static struct signal_data *signal_data;
void mainloop_init(void)
{
unsigned int i;
epoll_fd = epoll_create1(EPOLL_CLOEXEC);
for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++)
mainloop_list[i] = NULL;
epoll_terminate = 0;
}
void mainloop_quit(void)
{
epoll_terminate = 1;
}
static void signal_callback(int fd, uint32_t events, void *user_data)
{
struct signal_data *data = user_data;
struct signalfd_siginfo si;
ssize_t result;
if (events & (EPOLLERR | EPOLLHUP)) {
mainloop_quit();
return;
}
result = read(fd, &si, sizeof(si));
if (result != sizeof(si))
return;
if (data->callback)
data->callback(si.ssi_signo, data->user_data);
}
int mainloop_run(void)
{
unsigned int i;
if (signal_data) {
if (sigprocmask(SIG_BLOCK, &signal_data->mask, NULL) < 0)
return 1;
signal_data->fd = signalfd(-1, &signal_data->mask,
SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_data->fd < 0)
return 1;
if (mainloop_add_fd(signal_data->fd, EPOLLIN,
signal_callback, signal_data, NULL) < 0) {
close(signal_data->fd);
return 1;
}
}
while (!epoll_terminate) {
struct epoll_event events[MAX_EPOLL_EVENTS];
int n, nfds;
nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
if (nfds < 0)
continue;
for (n = 0; n < nfds; n++) {
struct mainloop_data *data = events[n].data.ptr;
data->callback(data->fd, events[n].events,
data->user_data);
}
}
if (signal_data) {
mainloop_remove_fd(signal_data->fd);
close(signal_data->fd);
if (signal_data->destroy)
signal_data->destroy(signal_data->user_data);
}
for (i = 0; i < MAX_MAINLOOP_ENTRIES; i++) {
struct mainloop_data *data = mainloop_list[i];
mainloop_list[i] = NULL;
if (data) {
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
if (data->destroy)
data->destroy(data->user_data);
free(data);
}
}
close(epoll_fd);
epoll_fd = 0;
return 0;
}
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
void *user_data, mainloop_destroy_func destroy)
{
struct mainloop_data *data;
struct epoll_event ev;
int err;
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1 || !callback)
return -EINVAL;
data = malloc(sizeof(*data));
if (!data)
return -ENOMEM;
memset(data, 0, sizeof(*data));
data->fd = fd;
data->events = events;
data->callback = callback;
data->destroy = destroy;
data->user_data = user_data;
memset(&ev, 0, sizeof(ev));
ev.events = events;
ev.data.ptr = data;
err = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, data->fd, &ev);
if (err < 0) {
free(data);
return err;
}
mainloop_list[fd] = data;
return 0;
}
int mainloop_modify_fd(int fd, uint32_t events)
{
struct mainloop_data *data;
struct epoll_event ev;
int err;
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
return -EINVAL;
data = mainloop_list[fd];
if (!data)
return -ENXIO;
if (data->events == events)
return 0;
memset(&ev, 0, sizeof(ev));
ev.events = events;
ev.data.ptr = data;
err = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, data->fd, &ev);
if (err < 0)
return err;
data->events = events;
return 0;
}
int mainloop_remove_fd(int fd)
{
struct mainloop_data *data;
int err;
if (fd < 0 || fd > MAX_MAINLOOP_ENTRIES - 1)
return -EINVAL;
data = mainloop_list[fd];
if (!data)
return -ENXIO;
mainloop_list[fd] = NULL;
err = epoll_ctl(epoll_fd, EPOLL_CTL_DEL, data->fd, NULL);
if (data->destroy)
data->destroy(data->user_data);
free(data);
return err;
}
static void timeout_destroy(void *user_data)
{
struct timeout_data *data = user_data;
close(data->fd);
data->fd = -1;
if (data->destroy)
data->destroy(data->user_data);
}
static void timeout_callback(int fd, uint32_t events, void *user_data)
{
struct timeout_data *data = user_data;
uint64_t expired;
ssize_t result;
if (events & (EPOLLERR | EPOLLHUP))
return;
result = read(data->fd, &expired, sizeof(expired));
if (result != sizeof(expired))
return;
if (data->callback)
data->callback(data->fd, data->user_data);
}
static inline int timeout_set(int fd, unsigned int seconds)
{
struct itimerspec itimer;
memset(&itimer, 0, sizeof(itimer));
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_nsec = 0;
itimer.it_value.tv_sec = seconds;
itimer.it_value.tv_nsec = 0;
return timerfd_settime(fd, 0, &itimer, NULL);
}
int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
void *user_data, mainloop_destroy_func destroy)
{
struct timeout_data *data;
if (!callback)
return -EINVAL;
data = malloc(sizeof(*data));
if (!data)
return -ENOMEM;
memset(data, 0, sizeof(*data));
data->callback = callback;
data->destroy = destroy;
data->user_data = user_data;
data->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
if (data->fd < 0) {
free(data);
return -EIO;
}
if (seconds > 0) {
if (timeout_set(data->fd, seconds) < 0) {
close(data->fd);
free(data);
return -EIO;
}
}
if (mainloop_add_fd(data->fd, EPOLLIN | EPOLLONESHOT,
timeout_callback, data, timeout_destroy) < 0) {
close(data->fd);
free(data);
return -EIO;
}
return data->fd;
}
int mainloop_modify_timeout(int id, unsigned int seconds)
{
if (seconds > 0) {
if (timeout_set(id, seconds) < 0)
return -EIO;
}
if (mainloop_modify_fd(id, EPOLLIN | EPOLLONESHOT) < 0)
return -EIO;
return 0;
}
int mainloop_remove_timeout(int id)
{
return mainloop_remove_fd(id);
}
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
void *user_data, mainloop_destroy_func destroy)
{
struct signal_data *data;
if (!mask || !callback)
return -EINVAL;
data = malloc(sizeof(*data));
if (!data)
return -ENOMEM;
memset(data, 0, sizeof(*data));
data->callback = callback;
data->destroy = destroy;
data->user_data = user_data;
data->fd = -1;
memcpy(&data->mask, mask, sizeof(sigset_t));
free(signal_data);
signal_data = data;
return 0;
}

View File

@@ -0,0 +1,49 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <signal.h>
#include <sys/epoll.h>
typedef void (*mainloop_destroy_func) (void *user_data);
typedef void (*mainloop_event_func) (int fd, uint32_t events, void *user_data);
typedef void (*mainloop_timeout_func) (int id, void *user_data);
typedef void (*mainloop_signal_func) (int signum, void *user_data);
void mainloop_init(void);
void mainloop_quit(void);
int mainloop_run(void);
int mainloop_add_fd(int fd, uint32_t events, mainloop_event_func callback,
void *user_data, mainloop_destroy_func destroy);
int mainloop_modify_fd(int fd, uint32_t events);
int mainloop_remove_fd(int fd);
int mainloop_add_timeout(unsigned int seconds, mainloop_timeout_func callback,
void *user_data, mainloop_destroy_func destroy);
int mainloop_modify_timeout(int fd, unsigned int seconds);
int mainloop_remove_timeout(int id);
int mainloop_set_signal(sigset_t *mask, mainloop_signal_func callback,
void *user_data, mainloop_destroy_func destroy);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,69 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
#include <stdbool.h>
#include <sys/time.h>
#define PACKET_FILTER_SHOW_INDEX (1 << 0)
#define PACKET_FILTER_SHOW_DATE (1 << 1)
#define PACKET_FILTER_SHOW_TIME (1 << 2)
#define PACKET_FILTER_SHOW_TIME_OFFSET (1 << 3)
#define PACKET_FILTER_SHOW_ACL_DATA (1 << 4)
#define PACKET_FILTER_SHOW_SCO_DATA (1 << 5)
void packet_set_filter(unsigned long filter);
void packet_add_filter(unsigned long filter);
void packet_del_filter(unsigned long filter);
void packet_select_index(uint16_t index);
void packet_hexdump(const unsigned char *buf, uint16_t len);
void packet_print_version(const char *label, uint8_t version,
const char *sublabel, uint16_t subversion);
void packet_print_company(const char *label, uint16_t company);
void packet_print_addr(const char *label, const void *data, bool random);
void packet_print_ad(const void *data, uint8_t size);
void packet_print_features_ll(const uint8_t *features);
void packet_print_channel_map_ll(const uint8_t *map);
void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
const void *data, uint16_t size);
void packet_simulator(struct timeval *tv, uint16_t frequency,
const void *data, uint16_t size);
void packet_new_index(struct timeval *tv, uint16_t index, const char *label,
uint8_t type, uint8_t bus, const char *name);
void packet_del_index(struct timeval *tv, uint16_t index, const char *label);
void packet_hci_command(struct timeval *tv, uint16_t index,
const void *data, uint16_t size);
void packet_hci_event(struct timeval *tv, uint16_t index,
const void *data, uint16_t size);
void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
const void *data, uint16_t size);
void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
const void *data, uint16_t size);

View File

@@ -0,0 +1,748 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <string.h>
#include <inttypes.h>
#include <bluetooth/bluetooth.h>
#include "bt.h"
#include "packet.h"
#include "display.h"
#include "l2cap.h"
#include "uuid.h"
#include "sdp.h"
#define MAX_TID 16
struct tid_data {
bool inuse;
uint16_t tid;
uint16_t channel;
uint8_t cont[17];
};
static struct tid_data tid_list[MAX_TID];
static struct tid_data *get_tid(uint16_t tid, uint16_t channel)
{
int i, n = -1;
for (i = 0; i < MAX_TID; i++) {
if (!tid_list[i].inuse) {
if (n < 0)
n = i;
continue;
}
if (tid_list[i].tid == tid && tid_list[i].channel == channel)
return &tid_list[i];
}
if (n < 0)
return NULL;
tid_list[n].inuse = true;
tid_list[n].tid = tid;
tid_list[n].channel = channel;
return &tid_list[n];
}
static void clear_tid(struct tid_data *tid)
{
if (tid)
tid->inuse = false;
}
static void print_uint(uint8_t indent, const uint8_t *data, uint32_t size)
{
switch (size) {
case 1:
print_field("%*c0x%2.2x", indent, ' ', data[0]);
break;
case 2:
print_field("%*c0x%4.4x", indent, ' ', bt_get_be16(data));
break;
case 4:
print_field("%*c0x%8.8x", indent, ' ', bt_get_be32(data));
break;
case 8:
print_field("%*c0x%16.16" PRIx64, indent, ' ',
bt_get_be64(data));
break;
default:
packet_hexdump(data, size);
break;
}
}
static void print_sint(uint8_t indent, const uint8_t *data, uint32_t size)
{
packet_hexdump(data, size);
}
static void print_uuid(uint8_t indent, const uint8_t *data, uint32_t size)
{
switch (size) {
case 2:
print_field("%*c%s (0x%4.4x)", indent, ' ',
uuid16_to_str(bt_get_be16(data)), bt_get_be16(data));
break;
case 4:
print_field("%*c%s (0x%8.8x)", indent, ' ',
uuid32_to_str(bt_get_be32(data)), bt_get_be32(data));
break;
case 16:
/* BASE_UUID = 00000000-0000-1000-8000-00805F9B34FB */
print_field("%*c%8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.4x",
indent, ' ',
bt_get_be32(data), bt_get_be16(data + 4),
bt_get_be16(data + 6), bt_get_be16(data + 8),
bt_get_be16(data + 10), bt_get_be32(data + 12));
if (bt_get_be16(data + 4) == 0x0000 &&
bt_get_be16(data + 6) == 0x1000 &&
bt_get_be16(data + 8) == 0x8000 &&
bt_get_be16(data + 10) == 0x0080 &&
bt_get_be32(data + 12) == 0x5F9B34FB)
print_field("%*c%s", indent, ' ',
uuid32_to_str(bt_get_be32(data)));
break;
default:
packet_hexdump(data, size);
break;
}
}
static void print_string(uint8_t indent, const uint8_t *data, uint32_t size)
{
char *str = alloca(size + 1);
str[size] = '\0';
strncpy(str, (const char *) data, size);
print_field("%*c%s [len %d]", indent, ' ', str, size);
}
static void print_boolean(uint8_t indent, const uint8_t *data, uint32_t size)
{
print_field("%*c%s", indent, ' ', data[0] ? "true" : "false");
}
#define SIZES(args...) ((uint8_t[]) { args, 0xff } )
static struct {
uint8_t value;
uint8_t *sizes;
bool recurse;
const char *str;
void (*print) (uint8_t indent, const uint8_t *data, uint32_t size);
} type_table[] = {
{ 0, SIZES(0), false, "Nil" },
{ 1, SIZES(0, 1, 2, 3, 4), false, "Unsigned Integer", print_uint },
{ 2, SIZES(0, 1, 2, 3, 4), false, "Signed Integer", print_sint },
{ 3, SIZES(1, 2, 4), false, "UUID", print_uuid },
{ 4, SIZES(5, 6, 7), false, "String", print_string },
{ 5, SIZES(0), false, "Boolean", print_boolean },
{ 6, SIZES(5, 6, 7), true, "Sequence" },
{ 7, SIZES(5, 6, 7), true, "Alternative" },
{ 8, SIZES(5, 6, 7), false, "URL", print_string },
{ }
};
static struct {
uint8_t index;
uint8_t bits;
uint8_t size;
const char *str;
} size_table[] = {
{ 0, 0, 1, "1 byte" },
{ 1, 0, 2, "2 bytes" },
{ 2, 0, 4, "4 bytes" },
{ 3, 0, 8, "8 bytes" },
{ 4, 0, 16, "16 bytes" },
{ 5, 8, 0, "8 bits" },
{ 6, 16, 0, "16 bits" },
{ 7, 32, 0, "32 bits" },
{ }
};
static bool valid_size(uint8_t size, uint8_t *sizes)
{
int i;
for (i = 0; sizes[i] != 0xff; i++) {
if (sizes[i] == size)
return true;
}
return false;
}
static uint8_t get_bits(const uint8_t *data, uint32_t size)
{
int i;
for (i = 0; size_table[i].str; i++) {
if (size_table[i].index == (data[0] & 0x07))
return size_table[i].bits;
}
return 0;
}
static uint32_t get_size(const uint8_t *data, uint32_t size)
{
int i;
for (i = 0; size_table[i].str; i++) {
if (size_table[i].index == (data[0] & 0x07)) {
switch (size_table[i].bits) {
case 0:
if ((data[0] & 0xf8) == 0)
return 0;
else
return size_table[i].size;
case 8:
return data[1];
case 16:
return bt_get_be16(data + 1);
case 32:
return bt_get_be32(data + 1);
default:
return 0;
}
}
}
return 0;
}
static void decode_data_elements(uint32_t position, uint8_t indent,
const uint8_t *data, uint32_t size,
void (*print_func) (uint32_t, uint8_t, uint8_t,
const uint8_t *, uint32_t))
{
uint32_t datalen, elemlen, extrabits;
int i;
if (!size)
return;
extrabits = get_bits(data, size);
if (size < 1 + (extrabits / 8)) {
print_text(COLOR_ERROR, "data element descriptor too short");
packet_hexdump(data, size);
return;
}
datalen = get_size(data, size);
if (size < 1 + (extrabits / 8) + datalen) {
print_text(COLOR_ERROR, "data element size too short");
packet_hexdump(data, size);
return;
}
elemlen = 1 + (extrabits / 8) + datalen;
for (i = 0; type_table[i].str; i++) {
uint8_t type = (data[0] & 0xf8) >> 3;
if (type_table[i].value != type)
continue;
if (print_func) {
print_func(position, indent, type,
data + 1 + (extrabits / 8), datalen);
break;
}
print_field("%*c%s (%d) with %u byte%s [%u extra bits] len %u",
indent, ' ', type_table[i].str, type,
datalen, datalen == 1 ? "" : "s",
extrabits, elemlen);
if (!valid_size(data[0] & 0x07, type_table[i].sizes)) {
print_text(COLOR_ERROR, "invalid data element size");
packet_hexdump(data + 1 + (extrabits / 8), datalen);
break;
}
if (type_table[i].recurse)
decode_data_elements(0, indent + 2,
data + 1 + (extrabits / 8), datalen,
print_func);
else if (type_table[i].print)
type_table[i].print(indent + 2,
data + 1 + (extrabits / 8), datalen);
break;
}
data += elemlen;
size -= elemlen;
decode_data_elements(position + 1, indent, data, size, print_func);
}
static uint32_t get_bytes(const uint8_t *data, uint32_t size)
{
switch (data[0] & 0x07) {
case 5:
return 2 + data[1];
case 6:
return 3 + bt_get_be16(data + 1);
case 7:
return 5 + bt_get_be32(data + 1);
}
return 0;
}
static struct {
uint16_t id;
const char *str;
} attribute_table[] = {
{ 0x0000, "Service Record Handle" },
{ 0x0001, "Service Class ID List" },
{ 0x0002, "Service Record State" },
{ 0x0003, "Service ID" },
{ 0x0004, "Protocol Descriptor List" },
{ 0x0005, "Browse Group List" },
{ 0x0006, "Language Base Attribute ID List" },
{ 0x0007, "Service Info Time To Live" },
{ 0x0008, "Service Availability" },
{ 0x0009, "Bluetooth Profile Descriptor List" },
{ 0x000a, "Documentation URL" },
{ 0x000b, "Client Executable URL" },
{ 0x000c, "Icon URL" },
{ 0x000d, "Additional Protocol Descriptor List" },
{ }
};
static void print_attr(uint32_t position, uint8_t indent, uint8_t type,
const uint8_t *data, uint32_t size)
{
int i;
if ((position % 2) == 0) {
uint16_t id = bt_get_be16(data);
const char *str = "Unknown";
for (i = 0; attribute_table[i].str; i++) {
if (attribute_table[i].id == id)
str = attribute_table[i].str;
}
print_field("%*cAttribute: %s (0x%4.4x) [len %d]",
indent, ' ', str, id, size);
return;
}
for (i = 0; type_table[i].str; i++) {
if (type_table[i].value != type)
continue;
if (type_table[i].recurse)
decode_data_elements(0, indent + 2, data, size, NULL);
else if (type_table[i].print)
type_table[i].print(indent + 2, data, size);
break;
}
}
static void print_attr_list(uint32_t position, uint8_t indent, uint8_t type,
const uint8_t *data, uint32_t size)
{
print_field("%*cAttribute list: [len %d] {position %d}",
indent, ' ', size, position);
decode_data_elements(0, indent + 2, data, size, print_attr);
}
static void print_attr_lists(uint32_t position, uint8_t indent, uint8_t type,
const uint8_t *data, uint32_t size)
{
decode_data_elements(0, indent, data, size, print_attr_list);
}
static void print_continuation(const uint8_t *data, uint16_t size)
{
if (data[0] != size - 1) {
print_text(COLOR_ERROR, "invalid continuation state");
packet_hexdump(data, size);
return;
}
print_field("Continuation state: %d", data[0]);
packet_hexdump(data + 1, size - 1);
}
static void store_continuation(struct tid_data *tid,
const uint8_t *data, uint16_t size)
{
memcpy(tid->cont, data, size);
print_continuation(data, size);
}
#define MAX_CONT 8
struct cont_data {
uint16_t channel;
uint8_t cont[17];
void *data;
uint32_t size;
};
static struct cont_data cont_list[MAX_CONT];
static void handle_continuation(struct tid_data *tid, bool nested,
uint16_t bytes, const uint8_t *data, uint16_t size)
{
uint8_t *newdata;
int i, n = -1;
if (bytes + 1 > size) {
print_text(COLOR_ERROR, "missing continuation state");
return;
}
if (tid->cont[0] == 0x00 && data[bytes] == 0x00) {
decode_data_elements(0, 2, data, bytes,
nested ? print_attr_lists : print_attr_list);
print_continuation(data + bytes, size - bytes);
return;
}
for (i = 0; i < MAX_CONT; i++) {
if (cont_list[i].cont[0] == 0x00) {
if (n < 0)
n = i;
continue;
}
if (cont_list[i].channel != tid->channel)
continue;
if (cont_list[i].cont[0] != tid->cont[0])
continue;
if (!memcmp(cont_list[i].cont + 1,
tid->cont + 1, tid->cont[0])) {
n = i;
break;
}
}
print_continuation(data + bytes, size - bytes);
if (n < 0)
return;
newdata = realloc(cont_list[n].data, cont_list[n].size + bytes);
if (!newdata) {
print_text(COLOR_ERROR, "failed buffer allocation");
free(cont_list[n].data);
cont_list[n].data = NULL;
cont_list[n].size = 0;
return;
}
cont_list[n].channel = tid->channel;
cont_list[n].data = newdata;
if (bytes > 0) {
memcpy(cont_list[n].data + cont_list[n].size, data, bytes);
cont_list[n].size += bytes;
}
if (data[bytes] == 0x00) {
print_field("Combined attribute bytes: %d", cont_list[n].size);
decode_data_elements(0, 2, cont_list[n].data, cont_list[n].size,
nested ? print_attr_lists : print_attr_list);
free(cont_list[n].data);
cont_list[n].data = NULL;
cont_list[n].size = 0;
} else
memcpy(cont_list[i].cont, data + bytes, data[bytes] + 1);
}
static uint16_t common_rsp(const struct l2cap_frame *frame,
struct tid_data *tid)
{
uint16_t bytes;
if (frame->size < 2) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return 0;
}
bytes = bt_get_be16(frame->data);
print_field("Attribute bytes: %d", bytes);
if (bytes > frame->size - 2) {
print_text(COLOR_ERROR, "invalid attribute size");
packet_hexdump(frame->data + 2, frame->size - 2);
return 0;
}
return bytes;
}
static void error_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint16_t error;
clear_tid(tid);
if (frame->size < 2) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return;
}
error = bt_get_be16(frame->data);
print_field("Error code: 0x%2.2x", error);
}
static void service_req(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint32_t search_bytes;
search_bytes = get_bytes(frame->data, frame->size);
print_field("Search pattern: [len %d]", search_bytes);
if (search_bytes + 2 > frame->size) {
print_text(COLOR_ERROR, "invalid search list length");
packet_hexdump(frame->data, frame->size);
return;
}
decode_data_elements(0, 2, frame->data, search_bytes, NULL);
print_field("Max record count: %d",
bt_get_be16(frame->data + search_bytes));
print_continuation(frame->data + search_bytes + 2,
frame->size - search_bytes - 2);
}
static void service_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint16_t count;
int i;
clear_tid(tid);
if (frame->size < 4) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return;
}
count = bt_get_be16(frame->data + 2);
print_field("Total record count: %d", bt_get_be16(frame->data));
print_field("Current record count: %d", count);
for (i = 0; i < count; i++)
print_field("Record handle: 0x%4.4x",
bt_get_be32(frame->data + 4 + (i * 4)));
print_continuation(frame->data + 4 + (count * 4),
frame->size - 4 - (count * 4));
}
static void attr_req(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint32_t attr_bytes;
if (frame->size < 6) {
print_text(COLOR_ERROR, "invalid size");
packet_hexdump(frame->data, frame->size);
return;
}
print_field("Record handle: 0x%4.4x", bt_get_be32(frame->data));
print_field("Max attribute bytes: %d", bt_get_be16(frame->data + 4));
attr_bytes = get_bytes(frame->data + 6, frame->size - 6);
print_field("Attribute list: [len %d]", attr_bytes);
if (attr_bytes + 6 > frame->size) {
print_text(COLOR_ERROR, "invalid attribute list length");
packet_hexdump(frame->data, frame->size);
return;
}
decode_data_elements(0, 2, frame->data + 6, attr_bytes, NULL);
store_continuation(tid, frame->data + 6 + attr_bytes,
frame->size - 6 - attr_bytes);
}
static void attr_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
{
uint16_t bytes;
bytes = common_rsp(frame, tid);
handle_continuation(tid, false, bytes,
frame->data + 2, frame->size - 2);
clear_tid(tid);
}
static void search_attr_req(const struct l2cap_frame *frame,
struct tid_data *tid)
{
uint32_t search_bytes, attr_bytes;
search_bytes = get_bytes(frame->data, frame->size);
print_field("Search pattern: [len %d]", search_bytes);
if (search_bytes + 2 > frame->size) {
print_text(COLOR_ERROR, "invalid search list length");
packet_hexdump(frame->data, frame->size);
return;
}
decode_data_elements(0, 2, frame->data, search_bytes, NULL);
print_field("Max record count: %d",
bt_get_be16(frame->data + search_bytes));
attr_bytes = get_bytes(frame->data + search_bytes + 2,
frame->size - search_bytes - 2);
print_field("Attribute list: [len %d]", attr_bytes);
decode_data_elements(0, 2, frame->data + search_bytes + 2,
attr_bytes, NULL);
store_continuation(tid, frame->data + search_bytes + 2 + attr_bytes,
frame->size - search_bytes - 2 - attr_bytes);
}
static void search_attr_rsp(const struct l2cap_frame *frame,
struct tid_data *tid)
{
uint16_t bytes;
bytes = common_rsp(frame, tid);
handle_continuation(tid, true, bytes, frame->data + 2, frame->size - 2);
clear_tid(tid);
}
struct sdp_data {
uint8_t pdu;
const char *str;
void (*func) (const struct l2cap_frame *frame, struct tid_data *tid);
};
static const struct sdp_data sdp_table[] = {
{ 0x01, "Error Response", error_rsp },
{ 0x02, "Service Search Request", service_req },
{ 0x03, "Service Search Response", service_rsp },
{ 0x04, "Service Attribute Request", attr_req },
{ 0x05, "Service Attribute Response", attr_rsp },
{ 0x06, "Service Search Attribute Request", search_attr_req },
{ 0x07, "Service Search Attribute Response", search_attr_rsp },
{ }
};
void sdp_packet(const struct l2cap_frame *frame, uint16_t channel)
{
uint8_t pdu;
uint16_t tid, plen;
struct l2cap_frame sdp_frame;
struct tid_data *tid_info;
const struct sdp_data *sdp_data = NULL;
const char *pdu_color, *pdu_str;
int i;
if (frame->size < 5) {
print_text(COLOR_ERROR, "frame too short");
packet_hexdump(frame->data, frame->size);
return;
}
pdu = *((uint8_t *) frame->data);
tid = bt_get_be16(frame->data + 1);
plen = bt_get_be16(frame->data + 3);
if (frame->size != plen + 5) {
print_text(COLOR_ERROR, "invalid frame size");
packet_hexdump(frame->data, frame->size);
return;
}
for (i = 0; sdp_table[i].str; i++) {
if (sdp_table[i].pdu == pdu) {
sdp_data = &sdp_table[i];
break;
}
}
if (sdp_data) {
if (sdp_data->func) {
if (frame->in)
pdu_color = COLOR_MAGENTA;
else
pdu_color = COLOR_BLUE;
} else
pdu_color = COLOR_WHITE_BG;
pdu_str = sdp_data->str;
} else {
pdu_color = COLOR_WHITE_BG;
pdu_str = "Unknown";
}
print_indent(6, pdu_color, "SDP: ", pdu_str, COLOR_OFF,
" (0x%2.2x) tid %d len %d", pdu, tid, plen);
if (!sdp_data || !sdp_data->func) {
packet_hexdump(frame->data + 5, frame->size - 5);
return;
}
tid_info = get_tid(tid, channel);
l2cap_frame_pull(&sdp_frame, frame, 5);
sdp_data->func(&sdp_frame, tid_info);
}

View File

@@ -0,0 +1,25 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
void sdp_packet(const struct l2cap_frame *frame, uint16_t channel);

View File

@@ -0,0 +1,284 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 <string.h>
#include "uuid.h"
static struct {
uint16_t uuid;
const char *str;
} uuid16_table[] = {
{ 0x0001, "SDP" },
{ 0x0003, "RFCOMM" },
{ 0x0005, "TCS-BIN" },
{ 0x0007, "ATT" },
{ 0x0008, "OBEX" },
{ 0x000f, "BNEP" },
{ 0x0010, "UPNP" },
{ 0x0011, "HIDP" },
{ 0x0012, "Hardcopy Control Channel" },
{ 0x0014, "Hardcopy Data Channel" },
{ 0x0016, "Hardcopy Notification" },
{ 0x0017, "AVCTP" },
{ 0x0019, "AVDTP" },
{ 0x001b, "CMTP" },
{ 0x001e, "MCAP Control Channel" },
{ 0x001f, "MCAP Data Channel" },
{ 0x0100, "L2CAP" },
{ 0x1000, "Service Discovery Server Service Class" },
{ 0x1001, "Browse Group Descriptor Service Class" },
{ 0x1002, "Public Browse Root" },
{ 0x1101, "Serial Port" },
{ 0x1102, "LAN Access Using PPP" },
{ 0x1103, "Dialup Networking" },
{ 0x1104, "IrMC Sync" },
{ 0x1105, "OBEX Object Push" },
{ 0x1106, "OBEX File Transfer" },
{ 0x1107, "IrMC Sync Command" },
{ 0x1108, "Headset" },
{ 0x1109, "Cordless Telephony" },
{ 0x110a, "Audio Source" },
{ 0x110b, "Audio Sink" },
{ 0x110c, "A/V Remote Control Target" },
{ 0x110d, "Advanced Audio Distribution" },
{ 0x110e, "A/V Remote Control" },
{ 0x110f, "A/V Remote Control Controller" },
{ 0x1110, "Intercom" },
{ 0x1111, "Fax" },
{ 0x1112, "Headset AG" },
{ 0x1113, "WAP" },
{ 0x1114, "WAP Client" },
{ 0x1115, "PANU" },
{ 0x1116, "NAP" },
{ 0x1117, "GN" },
{ 0x1118, "Direct Printing" },
{ 0x1119, "Reference Printing" },
{ 0x111a, "Basic Imaging Profile" },
{ 0x111b, "Imaging Responder" },
{ 0x111c, "Imaging Automatic Archive" },
{ 0x111d, "Imaging Referenced Objects" },
{ 0x111e, "Handsfree" },
{ 0x111f, "Handsfree Audio Gateway" },
{ 0x1120, "Direct Printing Refrence Objects Service" },
{ 0x1121, "Reflected UI" },
{ 0x1122, "Basic Printing" },
{ 0x1123, "Printing Status" },
{ 0x1124, "Human Interface Device Service" },
{ 0x1125, "Hardcopy Cable Replacement" },
{ 0x1126, "HCR Print" },
{ 0x1127, "HCR Scan" },
{ 0x1128, "Common ISDN Access" },
{ 0x112d, "SIM Access" },
{ 0x112e, "Phonebook Access Client" },
{ 0x112f, "Phonebook Access Server" },
{ 0x1130, "Phonebook Access" },
{ 0x1131, "Headset HS" },
{ 0x1132, "Message Access Server" },
{ 0x1133, "Message Notification Server" },
{ 0x1134, "Message Access Profile" },
{ 0x1135, "GNSS" },
{ 0x1136, "GNSS Server" },
{ 0x1200, "PnP Information" },
{ 0x1201, "Generic Networking" },
{ 0x1202, "Generic File Transfer" },
{ 0x1203, "Generic Audio" },
{ 0x1204, "Generic Telephony" },
{ 0x1205, "UPNP Service" },
{ 0x1206, "UPNP IP Service" },
{ 0x1300, "UPNP IP PAN" },
{ 0x1301, "UPNP IP LAP" },
{ 0x1302, "UPNP IP L2CAP" },
{ 0x1303, "Video Source" },
{ 0x1304, "Video Sink" },
{ 0x1305, "Video Distribution" },
{ 0x1400, "HDP" },
{ 0x1401, "HDP Source" },
{ 0x1402, "HDP Sink" },
{ 0x1800, "Generic Access Profile" },
{ 0x1801, "Generic Attribute Profile" },
{ 0x1802, "Immediate Alert" },
{ 0x1803, "Link Loss" },
{ 0x1804, "Tx Power" },
{ 0x1805, "Current Time Service" },
{ 0x1806, "Reference Time Update Service" },
{ 0x1807, "Next DST Change Service" },
{ 0x1808, "Glucose" },
{ 0x1809, "Health Thermometer" },
{ 0x180a, "Device Information" },
/* 0x180b and 0x180c undefined */
{ 0x180d, "Heart Rate" },
{ 0x180e, "Phone Alert Status Service" },
{ 0x180f, "Battery Service" },
{ 0x1810, "Blood Pressure" },
{ 0x1811, "Alert Notification Service" },
{ 0x1812, "Human Interface Device" },
{ 0x1813, "Scan Parameters" },
{ 0x1814, "Running Speed and Cadence" },
/* 0x1815 undefined */
{ 0x1816, "Cycling Speed and Cadence" },
{ 0x2800, "Primary Service" },
{ 0x2801, "Secondary Service" },
{ 0x2802, "Include" },
{ 0x2803, "Characteristic" },
{ 0x2900, "Characteristic Extended Properties" },
{ 0x2901, "Characteristic User Description" },
{ 0x2902, "Client Characteristic Configuration" },
{ 0x2903, "Server Characteristic Configuration" },
{ 0x2904, "Characteristic Format" },
{ 0x2905, "Characteristic Aggregate Formate" },
{ 0x2906, "Valid Range" },
{ 0x2907, "External Report Reference" },
{ 0x2908, "Report Reference" },
{ 0x2a00, "Device Name" },
{ 0x2a01, "Appearance" },
{ 0x2a02, "Peripheral Privacy Flag" },
{ 0x2a03, "Reconnection Address" },
{ 0x2a04, "Peripheral Preferred Connection Parameters" },
{ 0x2a05, "Service Changed" },
{ 0x2a06, "Alert Level" },
{ 0x2a07, "Tx Power Level" },
{ 0x2a08, "Date Time" },
{ 0x2a09, "Day of Week" },
{ 0x2a0a, "Day Date Time" },
/* 0x2a0b undefined */
{ 0x2a0c, "Exact Time 256" },
{ 0x2a0d, "DST Offset" },
{ 0x2a0e, "Time Zone" },
{ 0x2a0f, "Local Time Information" },
/* 0x2a10 undefined */
{ 0x2a11, "Time with DST" },
{ 0x2a12, "Time Accuracy" },
{ 0x2a13, "Time Source" },
{ 0x2a14, "Reference Time Information" },
/* 0x2a15 undefined */
{ 0x2a16, "Time Update Control Point" },
{ 0x2a17, "Time Update State" },
{ 0x2a18, "Glucose Measurement" },
{ 0x2a19, "Battery Level" },
/* 0x2a1a and 0x2a1b undefined */
{ 0x2a1c, "Temperature Measurement" },
{ 0x2a1d, "Temperature Type" },
{ 0x2a1e, "Intermediate Temperature" },
/* 0x2a1f and 0x2a20 undefined */
{ 0x2a21, "Measurement Interval" },
{ 0x2a22, "Boot Keyboard Input Report" },
{ 0x2a23, "System ID" },
{ 0x2a24, "Model Number String" },
{ 0x2a25, "Serial Number String" },
{ 0x2a26, "Firmware Revision String" },
{ 0x2a27, "Hardware Revision String" },
{ 0x2a28, "Software Revision String" },
{ 0x2a29, "Manufacturer Name String" },
{ 0x2a2a, "IEEE 11073-20601 Regulatory Cert. Data List" },
{ 0x2a2b, "Current Time" },
/* 0x2a2c to 0x2a30 undefined */
{ 0x2a31, "Scan Refresh" },
{ 0x2a32, "Boot Keyboard Output Report" },
{ 0x2a33, "Boot Mouse Input Report" },
{ 0x2a34, "Glucose Measurement Context" },
{ 0x2a35, "Blood Pressure Measurement" },
{ 0x2a36, "Intermediate Cuff Pressure" },
{ 0x2a37, "Heart Rate Measurement" },
{ 0x2a38, "Body Sensor Location" },
{ 0x2a39, "Heart Rate Control Point" },
/* 0x2a3a to 0x2a3e undefined */
{ 0x2a3f, "Alert Status" },
{ 0x2a40, "Ringer Control Point" },
{ 0x2a41, "Ringer Setting" },
{ 0x2a42, "Alert Category ID Bit Mask" },
{ 0x2a43, "Alert Category ID" },
{ 0x2a44, "Alert Notification Control Point" },
{ 0x2a45, "Unread Alert Status" },
{ 0x2a46, "New Alert" },
{ 0x2a47, "Supported New Alert Category" },
{ 0x2a48, "Supported Unread Alert Category" },
{ 0x2a49, "Blood Pressure Feature" },
{ 0x2a4a, "HID Information" },
{ 0x2a4b, "Report Map" },
{ 0x2a4c, "HID Control Point" },
{ 0x2a4d, "Report" },
{ 0x2a4e, "Protocol Mode" },
{ 0x2a4f, "Scan Interval Window" },
{ 0x2a50, "PnP ID" },
{ 0x2a51, "Glucose Feature" },
{ 0x2a52, "Record Access Control Point" },
{ 0x2a53, "RSC Measurement" },
{ 0x2a54, "RSC Feature" },
{ 0x2a55, "SC Control Point" },
/* 0x2a56 to 0x2a5a undefined */
{ 0x2a5b, "CSC Measurement" },
{ 0x2a5c, "CSC Feature" },
{ 0x2a5d, "Sensor Location" },
{ }
};
const char *uuid16_to_str(uint16_t uuid)
{
int i;
for (i = 0; uuid16_table[i].str; i++) {
if (uuid16_table[i].uuid == uuid)
return uuid16_table[i].str;
}
return "Unknown";
}
const char *uuid32_to_str(uint32_t uuid)
{
if ((uuid & 0xffff0000) == 0x0000)
return uuid16_to_str(uuid & 0x0000ffff);
return "Unknown";
}
const char *uuid128_to_str(const unsigned char *uuid)
{
return "Unknown";
}
const char *uuidstr_to_str(const char *uuid)
{
uint32_t val;
if (!uuid)
return NULL;
if (strlen(uuid) != 36)
return NULL;
if (strncasecmp(uuid + 8, "-0000-1000-8000-00805f9b34fb", 28))
return "Vendor specific";
if (sscanf(uuid, "%08x-0000-1000-8000-00805f9b34fb", &val) != 1)
return NULL;
return uuid32_to_str(val);
}

View File

@@ -0,0 +1,31 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
const char *uuid16_to_str(uint16_t uuid);
const char *uuid32_to_str(uint32_t uuid);
const char *uuid128_to_str(const unsigned char *uuid);
const char *uuidstr_to_str(const char *uuid);

View File

@@ -0,0 +1,35 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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 "packet.h"
#include "vendor.h"
void vendor_event(uint16_t manufacturer, const void *data, uint8_t size)
{
packet_hexdump(data, size);
}

View File

@@ -0,0 +1,27 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2011-2012 Intel Corporation
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <stdint.h>
void vendor_event(uint16_t manufacturer, const void *data, uint8_t size);

56
external/cache/sources/hcitools/rule.mk vendored Normal file
View File

@@ -0,0 +1,56 @@
# define output directory
OUTPUT_BIN := $(shell (mkdir -p output); cd ./output; pwd)
LIBDIR := $(shell cd $(pwd))/lib
BINDIR := $(shell cd $(pwd))/$(OUTPUT_BIN)
# define compiler
CC := gcc
CXX := g++
CPPFLAGS := $(CPPFLAGS) -I$(shell (cd $(pwd)))/include
CFLAGS := -Wall -O3 -Os -pipe \
-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 \
-D_GNU_SOURCE -D_REENTRANT \
$(CFLAGS)
# uses '=' let the variable parse when it's used
# COMPILE: compiles the source file specified
# COMPILEX: compiles the source file
# COMPILE_MSG: print compiling message
COMPILE = @$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(CPPFLAGS) $(CFLAGS)
COMPILEX = @$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(CPPFLAGS) $(CFLAGS) -c $< -o $@
COMPILECPP = @$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(CPPFLAGS) $(CFLAGS)
COMPILECPPX = @$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
$(CPPFLAGS) $(CFLAGS) -c $< -o $@
COMPILE_MSG = @echo " CC\t$<"
LDFLAGS := -L$(SYSROOT)/lib -L$(SYSROOT)/usr/lib -L$(LIBDIR) \
$(LDFLAGS)
# uses '=' let the variable parse when it's used
# LINK: link the objects specified
# LINKX: compiles the objects
# LINK_MSG: print linking message
LINK = @$(CC) $(CFLAGS) $(LDFLAGS)
LINKX = @$(CC) -o $(BINDIR)/$@ $^ $(CFLAGS) $(LDFLAGS)
LINKCPP = @$(CXX) $(CFLAGS) $(LDFLAGS)
LINKCPPX = @$(CXX) -o $(BINDIR)/$@ $^ $(CFLAGS) $(LDFLAGS)
LINK_MSG = @echo " LN\t$^ -> $@"
AR = @arm-linux-gnueabi-ar
ARFLAGS := -rc

View File

@@ -0,0 +1,39 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#ifndef __TEXTFILE_H
#define __TEXTFILE_H
int create_file(const char *filename, const mode_t mode);
int create_name(char *buf, size_t size, const char *path,
const char *address, const char *name);
int textfile_put(const char *pathname, const char *key, const char *value);
int textfile_del(const char *pathname, const char *key);
char *textfile_get(const char *pathname, const char *key);
typedef void (*textfile_cb) (char *key, char *value, void *data);
int textfile_foreach(const char *pathname, textfile_cb func, void *data);
#endif /* __TEXTFILE_H */

View File

@@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
{description}
Copyright (C) {year} {fullname}
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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
{signature of Ty Coon}, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View File

@@ -0,0 +1,177 @@
#!/bin/bash
#
# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
#
# check for root privileges
#
if [[ $EUID != 0 ]]; then
echo "This tool requires root privileges. Try again with \"sudo \" please ..." >&2
sleep 2
exit 1
fi
#
# check for internet connection to install dependencies
#
wget -q --spider http://github.com
if [[ $? -ne 0 ]]; then
read -n 1 -s -p "Warning: Configuration cannot work properly without a working internet connection. \
Press CTRL C to stop or any key to ignore and continue."
fi
#
# load functions, local first
#
if [[ -f ${BASH_SOURCE}-jobs ]]; then source ${BASH_SOURCE}-jobs;
elif [[ -f /usr/lib/orangepi-config/jobs.sh ]]; then source /usr/lib/orangepi-config/jobs.sh;
else exit 1;
fi
if [[ -f ${BASH_SOURCE}-submenu ]]; then source ${BASH_SOURCE}-submenu;
elif [[ -f /usr/lib/orangepi-config/submenu.sh ]]; then source /usr/lib/orangepi-config/submenu.sh;
else exit 1;
fi
if [[ -f ${BASH_SOURCE}-functions ]]; then source ${BASH_SOURCE}-functions;
elif [[ -f /usr/lib/orangepi-config/functions.sh ]]; then source /usr/lib/orangepi-config/functions.sh;
else exit 1;
fi
if [[ -f ${BASH_SOURCE}-functions-network ]]; then source ${BASH_SOURCE}-functions-network;
elif [[ -f /usr/lib/orangepi-config/functions-network.sh ]]; then source /usr/lib/orangepi-config/functions-network.sh;
else exit 1;
fi
# Script parameters handling
while [[ $1 == *=* ]]; do
parameter=${1%%=*}
value=${1##*=}
shift
echo "Command line: setting $parameter to ${value:-(empty)}"
eval "$parameter=\"$value\""
scripted=true
done
# Display help
if [[ $1 == "--help" ]]; then
echo "Orange Pi config options:"
echo ""
echo "Examples:"
echo ""
echo "Install headers: ${BASH_SOURCE[0]} main=Sytem selection=Headers"
echo "Update, upgrade and reboot: ${BASH_SOURCE[0]} main=System selection=Firmware"
echo "Switch to nightly builds: ${BASH_SOURCE[0]} main=System selection=Nightly"
echo "Switch to stable builds: ${BASH_SOURCE[0]} main=System selection=Stable"
echo "Install default desktop: ${BASH_SOURCE[0]} main=System selection=Default"
echo "Change to ZSH: ${BASH_SOURCE[0]} main=System selection=ZSH"
echo "Change to BASH: ${BASH_SOURCE[0]} main=System selection=BASH"
echo "Change to stable repository [branch=dev]: ${BASH_SOURCE[0]} main=System selection=Stable"
echo "Change to nightly repository [branch=dev]: ${BASH_SOURCE[0]} main=System selection=Nightly"
echo "Install headers: ${BASH_SOURCE[0]} main=Software selection=Headers_install"
echo "Remove headers: ${BASH_SOURCE[0]} main=Software selection=Headers_remove"
echo "Install kernel source: ${BASH_SOURCE[0]} main=Software selection=Source_install"
echo "Remove kernel source: ${BASH_SOURCE[0]} main=Software selection=Source_remove"
echo "Install Avahi mDNS/DNS-SD daemon: ${BASH_SOURCE[0]} main=Software selection=Avahi"
exit
fi
# collect info
main "$@"
#
# Main menu
#
while true
do
LIST=()
LIST+=( "System" "System and security settings" )
LIST+=( "Network" "Wired, wireless, Bluetooth, access point" )
LIST+=( "Personal" "Timezone, language, hostname" )
LIST+=( "Software" "System and 3rd party software install" )
LIST+=( "Help" "Documentation, support, sources" )
# count number of menu items to adjust window size
LISTLENGTH="$((11+${#LIST[@]}/2))"
BOXLENGTH=${#LIST[@]}
MENUTITLE="Configure \Z1$DISTRO $DISTROID\Z0"
# read cpu speed
POLICY="policy0"
[[ $(grep -c '^processor' /proc/cpuinfo) -gt 4 ]] && POLICY="policy4"
[[ ! -d /sys/devices/system/cpu/cpufreq/policy4 ]] && POLICY="policy0"
num=$(cat /sys/devices/system/cpu/cpufreq/$POLICY/scaling_min_freq 2> /dev/null)
if [[ -f /etc/default/cpufrequtils && ! -z "${num##*[!0-9]*}" ]]; then
LISTLENGTH=$((LISTLENGTH + 2))
MIN_CPU=$(($(cat /sys/devices/system/cpu/cpufreq/$POLICY/scaling_min_freq) / 1000))
MAX_CPU=$(($(cat /sys/devices/system/cpu/cpufreq/$POLICY/scaling_max_freq) / 1000))
GOVERNOR_CPU=$(cat /sys/devices/system/cpu/cpufreq/$POLICY/scaling_governor)
FREQENCIES="\nSoC runs between \Z1${MIN_CPU}\Z0 and \Z1${MAX_CPU} MHz\Z0 using \Z1${GOVERNOR_CPU}\Z0 governor.\n"
fi
[[ -n "${BOARD_NAME/ /}" ]] && MENUTITLE=$MENUTITLE" based \Z1OrangePi\Z0 for the \Z1${BOARD_NAME}\Z0 "
# main dialog routine
DIALOG_CANCEL=1
DIALOG_ESC=255
TITLELENGTH=${#MENUTITLE}
[[ "$TITLELENGTH" -lt 60 ]] && TITLELENGTH="60"
if [[ -z $main ]]; then
exec 3>&1
main=$(dialog --colors --backtitle "$BACKTITLE" --title " orangepi-config " --clear \
--cancel-label "Exit" --menu "\n$MENUTITLE \n$FREQENCIES\nSupport: \Z1http://www.orangepi.org\Z0\n " \
$LISTLENGTH ${TITLELENGTH} $BOXLENGTH "${LIST[@]}" 2>&1 1>&3)
exit_status=$?
exec 3>&-
[[ $exit_status == $DIALOG_CANCEL || $exit_status == $DIALOG_ESC ]] && clear && exit
dialog --backtitle "$BACKTITLE" --title "Please wait" --infobox \
"\nLoading ${main,,} submodule ... " 5 $((26+${#main}))
fi
case $main in
"System" )
submenu_settings
;;
"Network" )
submenu_networking
;;
"Personal" )
submenu_personal
;;
"Software" )
submenu_software
;;
"Help" )
unset main
t="This tool provides a straightforward way of configuring."
t=$t"\n \nAlthough it can be run at any time, some of the"
t=$t" options may have difficulties if you alter system settings manually.\n"
t=$t"\n\Z1Documentation:\Z0 http://www.orangepi.org"
t=$t"\n\n\Z1Support:\Z0 http://www.orangepi.org\n"
t=$t"\n\Z1Sources:\Z0 https://github.com/orangepi-xunlong"
show_box "Info" "$t" "18"
;;
esac
done

View File

@@ -0,0 +1,819 @@
#!/bin/bash
#
# Copyright (c) Authors: http://www.armbian.com/authors, info@armbian.com
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
# Functions:
# main
# check_desktop
# exceptions
# check_if_installed
# is_package_manager_running
# display_qr_code
# beta_disclaimer
# show_box
# description
# generic_select
# reload_bsp
# other_kernel_version
# aval_dtbs
# get_a20modes
# get_h3modes
# add_choose_user
# google_token_allusers
# configure_desktop
#
# gather info about the board and start with loading menu
#
function main(){
DIALOG_CANCEL=1
DIALOG_ESC=255
# we have our own lsb_release which does not use Python. Others shell install it here
if [[ ! -f /usr/bin/lsb_release ]]; then
if is_package_manager_running; then
sleep 3
fi
debconf-apt-progress -- apt-get update
debconf-apt-progress -- apt -y -qq --allow-downgrades --no-install-recommends install lsb-release
fi
[[ -f /etc/orangepi-release ]] && source /etc/orangepi-release && ORANGEPI="Orange Pi $VERSION $IMAGE_TYPE";
DISTRO=$(lsb_release -is)
DISTROID=$(lsb_release -sc)
KERNELID=$(uname -r)
[[ -z "${ORANGEPI// }" ]] && ORANGEPI="$DISTRO $DISTROID"
DEFAULT_ADAPTER=$(ip -4 route ls | grep default | tail -1 | grep -Po '(?<=dev )(\S+)')
LOCALIPADD=$(ip -4 addr show dev $DEFAULT_ADAPTER | awk '/inet/ {print $2}' | cut -d'/' -f1)
BACKTITLE="Configuration utility, $ORANGEPI"
[[ -n "$LOCALIPADD" ]] && BACKTITLE=$BACKTITLE", "$LOCALIPADD
TITLE="$BOARD_NAME "
[[ -z "${DEFAULT_ADAPTER// }" ]] && DEFAULT_ADAPTER="lo"
OVERLAYDIR="/boot/dtb/overlay";
[[ "$LINUXFAMILY" == "sunxi64" ]] && OVERLAYDIR="/boot/dtb/allwinner/overlay";
[[ "$LINUXFAMILY" == "meson64" ]] && OVERLAYDIR="/boot/dtb/amlogic/overlay";
[[ "$LINUXFAMILY" == "rockchip64" ]] && OVERLAYDIR="/boot/dtb/rockchip/overlay";
# detect desktop
check_desktop
dialog --backtitle "$BACKTITLE" --title "Please wait" --infobox "\nLoading Orange Pi configuration utility ... " 5 45
sleep 1
}
#
# compare two strings in dot separated version format
#
vercomp () {
if [[ $1 == $2 ]]
then
return 0
fi
local IFS=.
local i ver1=($1) ver2=($2)
# fill empty fields in ver1 with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++))
do
ver1[i]=0
done
for ((i=0; i<${#ver1[@]}; i++))
do
if [[ -z ${ver2[i]} ]]
then
# fill empty fields in ver2 with zeros
ver2[i]=0
fi
if ((10#${ver1[i]} > 10#${ver2[i]}))
then
return 1
fi
if ((10#${ver1[i]} < 10#${ver2[i]}))
then
return 2
fi
done
return 0
}
#
# test compare two strings $1="3.4.12" $2="5.4.2" $3="<" returns 0 if relation is correct
#
testvercomp () {
vercomp $1 $2
case $? in
0) op='=';;
1) op='>';;
2) op='<';;
esac
if [[ $op != $3 ]]
then
return 1
else
return 0
fi
}
#
# read desktop parameters
#
function check_desktop()
{
DISPLAY_MANAGER=""; DESKTOP_INSTALLED=""
check_if_installed nodm && DESKTOP_INSTALLED="nodm";
check_if_installed lightdm && DESKTOP_INSTALLED="lightdm";
check_if_installed gdm && DESKTOP_INSTALLED="gdm";
[[ -n $(service lightdm status 2> /dev/null | grep -w active) ]] && DISPLAY_MANAGER="lightdm"
[[ -n $(service nodm status 2> /dev/null | grep -w active) ]] && DISPLAY_MANAGER="nodm"
[[ -n $(service gdm status 2> /dev/null | grep -w active) ]] && DISPLAY_MANAGER="gdm"
}
#
# naming exceptions for packages
#
function exceptions ()
{
TARGET_FAMILY=$LINUXFAMILY
UBOOT_BRANCH=$TARGET_BRANCH # uboot naming is different
if [[ $TARGET_BRANCH == "default" ]]; then TARGET_BRANCH=""; else TARGET_BRANCH="-"$TARGET_BRANCH; fi
# pine64
if [[ $TARGET_FAMILY == pine64 ]]; then
TARGET_FAMILY="sunxi64"
fi
# allwinner legacy kernels
if [[ $TARGET_FAMILY == sun*i ]]; then
TARGET_FAMILY="sunxi"
if [[ $UBOOT_BRANCH == "default" ]]; then
TARGET_FAMILY=$(cat /proc/cpuinfo | grep "Hardware" | sed 's/^.*Allwinner //' | awk '{print $1;}')
fi
fi
}
#
# check dpkg status of $1 -- currently only 'not installed at all' case caught
#
check_if_installed (){
local DPKG_Status="$(dpkg -s "$1" 2>/dev/null | awk -F": " '/^Status/ {print $2}')"
if [[ "X${DPKG_Status}" = "X" || "${DPKG_Status}" = *deinstall* ]]; then
return 1
else
return 0
fi
}
#
# check if package manager is doing something
#
function is_package_manager_running() {
if ps -C apt-get,apt,dpkg >/dev/null ; then
[[ -z $scripted ]] && dialog --colors --title " \Z1Error\Z0 " --backtitle "$BACKTITLE" --no-collapse --msgbox \
"\n\Z0Package manager is running in the background. \n\nCan't install dependencies. Try again later." 9 53
return 0
else
return 1
fi
}
#
# wget with dialog progress bar $1=URL $2=parameters
#
function fancy_wget()
{
LANG=C wget $2 --progress=bar:force:noscroll $1 2>&1 | stdbuf -i0 -o0 -e0 tr '>' '\n' | \
stdbuf -i0 -o0 -e0 sed -rn 's/^.*\<([0-9]+)%\[.*$/\1/p' | dialog --backtitle "$BACKTITLE" --title " Downloading " \
--gauge "Please wait" 7 70 0
}
#
# display qr code for authentication method
#
function display_qr_code()
{
clear
SECRET=$(head -1 /root/.google_authenticator)
qrencode -m 2 -d 9 -8 -t ANSI256 "otpauth://totp/test?secret=$SECRET"
echo -e "\nHow to setup your one type password generator?\n"
echo -e "\nInstall a one-time password authenticator on your mobile device (e.g. FreeOTP) from the Android \
market or F-Droid. \n\nIn the application menu, click the corresponding button to create a new account and either \
scan the QR code or enter the secret key manually:\\n\n$SECRET \n\nYou should now see a new passcode token being \
generated every 60 seconds on your phone.\n" | fold -sw 60
read -n 1 -s -r -p "Press any key to continue"
}
#
# show disclaimer
#
function beta_disclaimer ()
{
exec 3>&1
ACKNOWLEDGEMENT=$(dialog --colors --nocancel --backtitle "$BACKTITLE" --no-collapse --title " Warning " \
--clear \--radiolist "\n$1\n \n" 0 56 5 "Yes, I understand" "" off 2>&1 1>&3)
exec 3>&-
}
#
# show box
#
function show_box ()
{
dialog --colors --backtitle "$BACKTITLE" --no-collapse --title " $1 " --clear --msgbox "\n$2\n \n" $3 56
}
#
# show description for MOTD files
#
function description
{
case $1 in
*header*)
echo "Big board logo and kernel info"
;;
*sysinfo*)
echo "Sysinfo - load, ip, memory, uptime, ..."
;;
*tips*)
echo "Shows tip of the day"
;;
*updates*)
echo "Display number of available updates"
;;
*orangepi-config*)
echo "Show command for system configuration"
;;
*autoreboot-warn*)
echo "Show warning when reboot is needed"
;;
*uk.armbian.com*)
echo "United Kingdom"
;;
*mirrors.tuna.tsinghua.edu.cn/armbian/*)
echo "China"
;;
*mirrors.netix.net/armbian/apt/*)
echo "Bulgarija"
;;
*mirrors.dotsrc.org/armbian-apt/*)
echo "Denmark"
;;
*.armbian.com*)
echo "Estonia"
;;
*)
echo ""
;;
esac
}
#
# Generic select box
#
function generic_select()
{
IFS=$' '
PARAMETER=($1)
local LIST=()
for i in "${PARAMETER[@]}"
do
if [[ -n $3 ]]; then
[[ ${i[0]} -ge $3 ]] && \
LIST+=( "${i[0]//[[:blank:]]/}" "" )
else
LIST+=( "${i[0]//[[:blank:]]/}" "" )
fi
done
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 1 ]; then
PARAMETER=${PARAMETER[0]}
else
exec 3>&1
PARAMETER=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "$2" --clear --menu "" $((6+${LIST_LENGTH})) 0 $((1+${LIST_LENGTH})) "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
#
# reload kernel, bsp and orangepi-config
#
function reload_bsp(){
# switch to defined branch
[[ -n "$1" ]] && BRANCH=$1
# deal with exceptions
if [[ $BRANCH == current || $BRANCH == dev ]]; then
[[ ${LINUXFAMILY} == rk3399 ]] && LINUXFAMILY=rockchip64
fi
clear
debconf-apt-progress -- apt-get update
# must exits
PACKAGE_INSTALL="linux-image-${BRANCH}-${LINUXFAMILY} linux-dtb-${BRANCH}-${LINUXFAMILY}"
PACKAGE_PURGE="linux-image* linux-dtb*"
# create install and remove logic
command=$(LC_ALL=C apt-get --download-only --simulate --allow-downgrades -y --no-install-recommends install linux-${DISTROID}-root-${BRANCH}-${BOARD} 2>/dev/null)
if [[ $? -eq 0 && -z $(echo $command | grep "not possible") ]]; then
PACKAGE_INSTALL+=" linux-${DISTROID}-root-${BRANCH}-${BOARD}"
PACKAGE_PURGE+=" linux-${DISTROID}-root*"
fi
command=$(LC_ALL=C apt-get --download-only --simulate --reinstall --allow-downgrades -y --no-install-recommends install linux-u-boot-${BOARD}-${BRANCH} 2>/dev/null)
if [[ $? -eq 0 && -z $(echo $command | grep "not possible") ]]; then
PACKAGE_INSTALL+=" linux-u-boot-${BOARD}-${BRANCH}"
PACKAGE_PURGE+=" linux-u-boot-${BOARD}-*"
fi
if check_if_installed orangepi-${DISTROID}-desktop ; then
PACKAGE_INSTALL+=" orangepi-${DISTROID}-desktop"
PACKAGE_PURGE+=" orangepi-${DISTROID}-desktop*"
fi
if check_if_installed linux-headers-${BRANCH}-${FAMILY} ; then
PACKAGE_INSTALL+=" linux-headers-${BRANCH}-${FAMILY}"
PACKAGE_PURGE+=" linux-headers*"
fi
debconf-apt-progress -- apt-get -o Dpkg::Options::="--force-confold" --force-yes --download-only --allow-downgrades -y --no-install-recommends install $PACKAGE_INSTALL
# if download is ok, remove old packages
if [[ $? = 0 ]]; then
debconf-apt-progress -- apt-get -y -qq purge $PACKAGE_PURGE
find "/boot/" -name "System.map*" -type f -delete
find "/boot/" -name "config*" -type f -delete
find "/boot/" -name "vmlinuz*" -type f -delete
find "/boot/" -name "*nitrd*" -type f -delete
find "/boot/" -name "*Image" -type l -delete
# install packages
echo $PACKAGE_INSTALL >> /var/log/upgrade.log
debconf-apt-progress -- apt-get -y -qq --allow-downgrades --no-install-recommends --reinstall \
-o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install $PACKAGE_INSTALL
if [[ $? -eq 1 ]]; then
echo "Something went wrong ... check logs."; exit;
else
apt clean
fi
fi
}
function other_kernel_version ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
local HIDDEN='hidden'
# get current kernel information
CURRENT_VERSION_TEMP=$(dpkg -l | grep '^ii' | grep linux-image)
CURRENT_VERSION=$(echo $CURRENT_VERSION_TEMP | awk '{print $2}')"="$(echo $CURRENT_VERSION_TEMP | awk '{print $3}')
# Merge families and handle exceptions
[[ ${LINUXFAMILY} == sun*i ]] && LINUXFAMILY=sunxi
[[ ${LINUXFAMILY} == pine64 ]] && LINUXFAMILY=sunxi64
[[ ${LINUXFAMILY} == sun*iw* ]] && LINUXFAMILY=sunxi64
[[ ${LINUXFAMILY} == cubox || ${LINUXFAMILY} == udoo ]] && LINUXFAMILY=imx6
[[ ${BOARD} == odroidc2 || ${BOARD} == kvim1 || ${BOARD} == lafrite || ${BOARD} == lepotato || ${BOARD} == nanopik2-s905 ]] && HIDDEN="legacy"
[[ ${LINUXFAMILY} == odroidn2 ]] && LINUXFAMILY=meson64
# check what is available from the repository
debconf-apt-progress -- apt-get update
LIST=($(apt-cache show linux-image*${LINUXFAMILY} | grep -E "Package:|Version:|version:" \
| grep -v "Config-Version" | sed -n -e 's/^.*: //p' | sed 's/\.$//g'))
new_list=()
# create a human readable menu
for ((n=0;n<$((${#LIST[@]}));n++));
do
m=$(( $n + 1 ))
prvi=$((3*$m - 3))
drugi=$((3*$m - 2))
tretji=$((3*$m - 1))
[[ -z ${LIST[$prvi]} ]] && break
if [[ $CURRENT_VERSION != "${LIST[$prvi]}=${LIST[$drugi]}" && ${LIST[$prvi]} != *${HIDDEN}* ]]; then
new_list+=( "${LIST[$prvi]}=${LIST[$drugi]}" )
new_list+=( ${LIST[$tretji]} )
fi
local tmp="${LIST[$prvi]}=${LIST[$drugi]}${LIST[$tretji]}"
[[ ${#tmp} -gt $chrlen ]] && local chrlen=${#tmp}
done
# copy back to main array
LIST=("${new_list[@]}")
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 0 ]; then
dialog --backtitle "$BACKTITLE" --title " Warning " --msgbox "\nNo other kernels available!" 7 32
else
beta_disclaimer "Switching between kernels might change functionality of your board or it might fail to boot. \
\n\n\Z1In case of troubles expect no help!\Z0"
if [[ -n $ACKNOWLEDGEMENT ]]; then
exec 3>&1
TARGET_VERSION=$(dialog --ok-label "Reboot" --cancel-label "Cancel" --backtitle "$BACKTITLE" --no-collapse \
--title "Select kernel and reboot" --clear --menu "" $((6+${LIST_LENGTH})) $((7+${chrlen})) 25 "${LIST[@]}" 2>&1 1>&3)
exitstatus=$?;
exec 3>&-
if [[ $exitstatus = 0 ]]; then
IFS=" "
# determine upgrade packages
UPGRADE_ROOT="default"
UPGRADE_UBOOT=""
[[ $TARGET_VERSION == *legacy* ]] && UPGRADE_ROOT="-legacy" && UPGRADE_UBOOT="legacy"
[[ $TARGET_VERSION == *next* ]] && UPGRADE_ROOT="-next" && UPGRADE_UBOOT="next"
[[ $TARGET_VERSION == *current* ]] && UPGRADE_ROOT="-current" && UPGRADE_UBOOT="current"
[[ $TARGET_VERSION == *dev* ]] && UPGRADE_ROOT="-dev" && UPGRADE_UBOOT="dev"
# install packages
PACKAGE_LIST="$TARGET_VERSION"
TARGET_VERSION_DTB=${TARGET_VERSION/image/dtb}
TARGET_VERSION_PRE=$(echo $TARGET_VERSION_DTB | cut -f1 -d"=")
TARGET_VERSION_SUB=$(echo $TARGET_VERSION_DTB | cut -f2 -d"=")
[[ -n $(apt-cache madison "$TARGET_VERSION_PRE" | grep $TARGET_VERSION_SUB ) ]] && \
# installs u-boot only if exits
apt-cache show linux-u-boot-${BOARD}-${UPGRADE_UBOOT} 2> /dev/null
[[ $? -eq 0 ]] && PACKAGE_LIST=$PACKAGE_LIST" linux-u-boot-${BOARD}-${UPGRADE_UBOOT}"
PACKAGE_LIST=$PACKAGE_LIST" $TARGET_VERSION_DTB"
echo $PACKAGE_LIST > /tmp/switch_kernel.log 2>&1
debconf-apt-progress -- apt -o Dpkg::Options::="--force-confold" --force-yes --download-only --allow-downgrades -y --no-install-recommends install $PACKAGE_LIST
if [[ $? = 0 ]]; then
dialog --backtitle "$BACKTITLE" --title "Please wait" --infobox "\nRemoving current kernel ..." 5 36
# remove old kernel
debconf-apt-progress -- apt -y -qq purge linux-u-boot* linux-image* linux-dtb* linux-headers* linux-${DISTROID}-root*
# cleanup
find "/boot/" -name "System.map*" -type f -delete; find "/boot/" -name "config*" -type f -delete
find "/boot/" -name "vmlinuz*" -type f -delete; find "/boot/" -name "*nitrd*" -type f -delete
apt clean
# BSP must be installed separate otherwise it won't work
debconf-apt-progress -- apt -o Dpkg::Options::="--force-confold" --force-yes -y -qq --allow-downgrades --no-install-recommends install linux-${DISTROID}-root${UPGRADE_ROOT}-${BOARD}
debconf-apt-progress -- apt -o Dpkg::Options::="--force-confold" --force-yes -y -qq --allow-downgrades --no-install-recommends install $PACKAGE_LIST
if [[ $? = 0 ]]; then
# update boot loader
[[ -f /usr/lib/u-boot/platform_install.sh ]] && source /usr/lib/u-boot/platform_install.sh
#recognize_root
root_uuid=$(sed -e 's/^.*root=//' -e 's/ .*$//' < /proc/cmdline)
root_partition=$(blkid | tr -d '":' | grep "${root_uuid}" | awk '{print $1}')
root_partition_device="${root_partition::-2}"
write_uboot_platform "$DIR" "${root_partition_device}"
reboot
fi
else
dialog --backtitle "$BACKTITLE" --title "Warning" --msgbox \
"\nTest install failed. Can't change firmware \n\nCheck /tmp/switch_kernel.log" 9 48
fi
fi
fi
fi
}
#
# check if board has alternative kernels
#
function aval_dtbs ()
{
if [[ $LINUXFAMILY == cubox ]]; then
local width=80
LIST=("imx6dl-hummingboard.dtb" "HB Solo/DualLite" "imx6dl-hummingboard-emmc-som-v15.dtb" "HB Solo/DualLite v1.5 with eMMC" "imx6dl-hummingboard-som-v15.dtb" "HB Solo/DualLite v1.5" \
"imx6dl-hummingboard2.dtb" "HB2 Solo/DualLite" "imx6dl-hummingboard2-emmc-som-v15.dtb" "HB2 Solo/DualLite v1.5 with eMMC" "imx6dl-hummingboard2-som-v15.dtb" "HB2 Solo/DualLite v1.5" \
"imx6q-hummingboard.dtb" "HB Dual/Quad" "imx6q-hummingboard-emmc-som-v15.dtb" "HB Dual/Quad v1.5 with eMMC" "imx6q-hummingboard-som-v15.dtb" "HB Dual/Quad v1.5" \
"imx6q-hummingboard2.dtb" "HB2 Dual/Quad" "imx6q-hummingboard2-emmc-som-v15.dtb" "HB2 Dual/Quad v1.5 with eMMC" "imx6q-hummingboard2-som-v15.dtb" "HB2 Dual/Quad v1.5" \
"imx6dl-cubox-i.dtb" "Cubox-i Solo/DualLite" "imx6dl-cubox-i-emmc-som-v15.dtb" "Cubox-i Solo/DualLite v1.5 with eMMC" "imx6dl-cubox-i-som-v15.dtb" "Cubox-i Solo/DualLite v1.5" \
"imx6q-cubox-i.dtb" "Cubox-i Dual/Quad" "imx6q-cubox-i-emmc-som-v15.dtb" "Cubox-i Dual/Quad v1.5 with eMMC" "imx6q-cubox-i-som-v15.dtb" "Cubox-i Dual/Quad v1.5")
else
local width=52
LIST=("xu4" "Odroid XU4" "xu3" "Odroid XU3" "xu3l" "Odroid XU3 Lite" "hc1" "Odroid HC1/HC2")
fi
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 1 ]; then
TARGET_BOARD=${AVAL_KERNEL[0]}
else
exec 3>&1
TARGET_BOARD=$(dialog --cancel-label "Cancel" --backtitle "$BACKTITLE" --no-collapse \
--title "Select optimised board configuration" --clear --menu \
"" $((6+${LIST_LENGTH})) ${width} 25 "${LIST[@]}" 2>&1 1>&3)
exitstatus=$?;
exec 3>&-
fi
}
#
# select video modes for a10 and a20
#
function get_a20modes ()
{
IFS=$'\r'
GLOBIGNORE='*'
SCREEN_RESOLUTION=("1920x1080p60" "1280x720p60" "1920x1080p50" "1280x1024p60" "1024x768p60" "800x600p60" "640x480p60" "1360x768p60" "1440x900p60" "1680x1050p60")
local LIST=()
for i in "${SCREEN_RESOLUTION[@]}"
do
LIST+=( "${i[0]//[[:blank:]]/}" "" )
done
LIST_LENGTH=$((${#LIST[@]}/2));
#echo $LIST_LENGTH
#exit
if [ "$LIST_LENGTH" -eq 1 ]; then
SCREEN_RESOLUTION=${SCREEN_RESOLUTION[0]}
else
exec 3>&1
SCREEN_RESOLUTION=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "Select video mode" --clear --menu \
"" $((6+${LIST_LENGTH})) 25 $((1+${LIST_LENGTH})) "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
#
# select video modes for odroid c1/c2
#
function get_odroidmodes ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
SCREEN_RESOLUTION=($(cat /boot/boot.ini | grep -w "# setenv" | grep "hz" | cut -d'"' -f 2))
SCREEN_RESOLUTION=($(cat /boot/boot.ini | grep "Progressive" | grep -v "setenv" | cut -d'"' -f 2))
local LIST=()
for i in "${SCREEN_RESOLUTION[@]}"
do
LIST+=( "${i[0]//[[:blank:]]/}" "" )
done
LIST_LENGTH=$((${#LIST[@]}/2));
#echo $LIST_LENGTH
#exit
if [ "$LIST_LENGTH" -eq 1 ]; then
SCREEN_RESOLUTION=${SCREEN_RESOLUTION[0]}
else
exec 3>&1
SCREEN_RESOLUTION=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "Select video mode" --clear --menu \
"" $((6+${LIST_LENGTH})) 25 $((1+${LIST_LENGTH})) "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
#
# select video modes for h3
#
function get_h3modes ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
SCREEN_RESOLUTION=($(h3disp -i clean))
local LIST=()
for i in "${SCREEN_RESOLUTION[@]}"
do
LIST+=( "${i[0]//[[:blank:]]/}" "" )
done
LIST_LENGTH=$((${#LIST[@]}/2));
#echo $LIST_LENGTH
#exit
if [ "$LIST_LENGTH" -eq 1 ]; then
SCREEN_RESOLUTION=${SCREEN_RESOLUTION[0]}
else
exec 3>&1
SCREEN_RESOLUTION=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "Select video mode" --clear --menu \
"" $((6+${LIST_LENGTH})) 25 $((1+${LIST_LENGTH})) "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
#
# create or pick unprivileged user
#
function add_choose_user ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
local USERS=($(awk -F'[/:]' '{if ($3 >= 1000 && $3 != 65534) print $1}' /etc/passwd))
local LIST=()
for i in "${USERS[@]}"
do
LIST+=( "${i[0]//[[:blank:]]/}" "" )
done
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 0 ]; then
dialog --backtitle "$BACKTITLE" --title " Notice " --msgbox \
"\nWe didn't find any unprivileged user with sudo rights which is required to run this service.\
\n\nPress enter to create one!" 10 48
read -t 0 temp
echo -e "\nPlease provide a username (eg. your forename) or leave blank for canceling user creation: \c"
read -e username
CHOSEN_USER="$(echo "$username" | tr '[:upper:]' '[:lower:]' | tr -d -c '[:alnum:]')"
[ -z "$CHOSEN_USER" ] && return
echo "Trying to add user $CHOSEN_USER"
adduser $CHOSEN_USER || return
elif [ "$LIST_LENGTH" -eq 1 ]; then
CHOSEN_USER=${USERS[0]}
else
exec 3>&1
CHOSEN_USER=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "Select unprivileged user" --clear --menu "" $((6+${LIST_LENGTH})) 40 15 "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
#
# Copy Google token to all local users.
#
function google_token_allusers ()
{
if [[ -f /root/.google_authenticator ]]; then
local USERS=($(awk -F'[/:]' '{if ($3 >= 1000 && $3 != 65534) print $1}' /etc/passwd))
for i in "${USERS[@]}"
do
USER=${i[0]//[[:blank:]]/}
if [[ -d /home/$USER ]]; then
cp /root/.google_authenticator /home/$USER/
chown ${USER}:${USER} /home/${USER}/.google_authenticator
fi
done
fi
}
#
# configure orangepi desktop
#
function configure_desktop ()
{
add_choose_user
if [ -n "$CHOSEN_USER" ]; then
# update packages
debconf-apt-progress -- apt-get update
# install new package if exists
unset PACKAGE_SUFIX
[[ -n $(apt-cache search --names-only "^orangepi-${DISTROID}-desktop-xfce$") ]] && PACKAGE_SUFIX="-xfce"
# remove desktop package to secure proper install
if check_if_installed orangepi-${DISTROID}-desktop ; then
debconf-apt-progress -- apt-get -y \
remove orangepi-${DISTROID}-desktop${PACKAGE_SUFIX} lightdm lightdm-gtk-greeter
fi
# install desktop package
debconf-apt-progress -- apt-get --reinstall -o Dpkg::Options::="--force-confdef" \
-o Dpkg::Options::="--force-confold" -y \
install $1 orangepi-${DISTROID}-desktop${PACKAGE_SUFIX} lightdm lightdm-gtk-greeter
# in case previous install was interrupted
[[ $? -eq 130 ]] && dpkg --configure -a
# clean apt cache
apt clean
# add user to groups
for additionalgroup in sudo netdev audio video dialout plugdev input bluetooth systemd-journal ssh; do
usermod -aG ${additionalgroup} ${CHOSEN_USER} 2>/dev/null
done
# Prevent loading paralel printer port drivers which we don't need here.
# suppress boot error if kernel modules are absent
if [[ -f /etc/modules-load.d/cups-filters.conf ]]; then
sed "s/^lp/#lp/" -i /etc/modules-load.d/cups-filters.conf
sed "s/^ppdev/#ppdev/" -i /etc/modules-load.d/cups-filters.conf
sed "s/^parport_pc/#parport_pc/" -i /etc/modules-load.d/cups-filters.conf
fi
# enable show windows content on stronger boards
cpu_cores=$(grep -c '^processor' /proc/cpuinfo | sed 's/^0$/1/')
if [[ ${cpu_cores} -gt 2 && -f /etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml ]]; then
sed -i 's/<property name="box_move" type="bool" value=".*/<property name="box_move" type="bool" value="false"\/>/g' \
/etc/skel/.config/xfce4/xfconf/xfce-perchannel-xml/xfwm4.xml
fi
# fix for gksu in Xenial
touch /home/${CHOSEN_USER}/.Xauthority
cp -R /etc/skel/. /home/${CHOSEN_USER}
# set up profile sync daemon on desktop systems
which psd >/dev/null 2>&1
if [[ $? -eq 0 && -z $(grep overlay-helper /etc/sudoers) ]]; then
echo "${CHOSEN_USER} ALL=(ALL) NOPASSWD: /usr/bin/psd-overlay-helper" >> /etc/sudoers
touch /home/${CHOSEN_USER}/.activate_psd
fi
mkdir -p /etc/lightdm/lightdm.conf.d
echo "[Seat:*]" > /etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf
echo "autologin-user=$CHOSEN_USER" >> /etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf
echo "autologin-user-timeout=0" >> /etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf
echo "user-session=xfce" >> /etc/lightdm/lightdm.conf.d/22-orangepi-autologin.conf
ln -s /lib/systemd/system/lightdm.service /etc/systemd/system/display-manager.service >/dev/null 2>&1
# fix permissions
chown -R ${CHOSEN_USER}:${CHOSEN_USER} /home/${CHOSEN_USER}/.
service lightdm start >/dev/null 2>&1
fi
}

View File

@@ -0,0 +1,742 @@
#!/bin/bash
#
# Copyright (c) 2017 Igor Pecovnik, igor.pecovnik@gma**.com
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
# Functions:
# initialize_lte
# function lte
# check_hostapd
# check_advanced_modes
# create_if_config
# reload-nety
# check_port
# check_ht_capab
# check_vht_capab
# check_channels
# netmask_to_cidr
# nm_ip_editor
# systemd_ip_editor
# ip_editor
# wlan_edit_basic
# wlan_edit
# wlan_exceptions
# check_and_warn
# get_wlan_interface
# select_default_interface
# connect_bt_interface
#
# 3G/4G general stuff
#
function initialize_lte ()
{
# This file defines udev rules for some 3G/UMTS/LTE modems. It
# addresses the issue that the ttyUSB devices are numbered randomly, and
# their numbering can vary between server reboots. These rules create
# persistent symlinks which can be reliably used in WWAN interface
# startup scripts.
# These rules assume that there is only one WWAN modem in the system. In
# order to address multiple WWAN cards, the rules need to be more
# specific and associate with serial numbers of the modems.
# Copyright (c) 2016 Stanislav Sinyagin <ssinyagin@k-open.com>.
# This content is published under Creative Commons Attribution 4.0
# International (CC BY 4.0) license.
# Source repository: https://github.com/ssinyagin/wwan_udev_rules
if ! check_if_installed ppp then; then
apt-get -y -qq install ppp >/dev/null 2>&1
fi
cat >/etc/udev/rules.d/99-wwan.rules <<'EOT'
# Source repository: https://github.com/ssinyagin/wwan_udev_rules
# Huawei ME909s-120 LTE modem
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="15c1", SYMLINK+="ttyWWAN%E{ID_USB_INTERFACE_NUM}"
SUBSYSTEM=="net", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="15c1", NAME="lte0"
# Huawei MU709s-2 UMTS modem
SUBSYSTEM=="tty", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1c25", SYMLINK+="ttyWWAN%E{ID_USB_INTERFACE_NUM}"
SUBSYSTEM=="net", ATTRS{idVendor}=="12d1", ATTRS{idProduct}=="1c25", NAME="umts0"
# Qualcomm Gobi2000
SUBSYSTEM=="tty", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="251d", SYMLINK+="ttyWWAN%E{ID_USB_INTERFACE_NUM}"
# Sierra Wireless MC8775
SUBSYSTEM=="tty", ATTRS{idVendor}=="03f0", ATTRS{idProduct}=="1e1d", SYMLINK+="ttyWWAN%E{.ID_PORT}"
# Novatel Wireless, Inc. Expedite E371
SUBSYSTEM=="tty", ATTRS{idVendor}=="413c", ATTRS{idProduct}=="819b", SYMLINK+="ttyWWAN%E{ID_USB_INTERFACE_NUM}"
# SIMCom SIM7100
SUBSYSTEM=="tty", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", SYMLINK+="ttyWWAN%E{ID_USB_INTERFACE_NUM}"
SUBSYSTEM=="net", ATTRS{idVendor}=="1e0e", ATTRS{idProduct}=="9001", NAME="lte0"
EOT
# reload udev rules
udevadm control --reload-rules && udevadm trigger
}
#
# 3G/4G init scripts add + remove
#
function lte ()
{
case $1 in
"12d1:15c1" )
# Huawei ME909s-120 LTE modem
LTE_MODEM_ID=$1
if [[ $2 == on && $(cat /sys/class/net/lte0/operstate) == "up" ]]; then
show_box "Warning" "Huawei ME909s-120 LTE modem is up and running" 7
elif [[ $2 == on ]]; then
show_box "Info" "Huawei ME909s-120 LTE modem will try to connect" 7
cat >/etc/chatscripts/sunrise.HUAWEI <<'EOT'
ABORT BUSY
ABORT 'NO CARRIER'
ABORT ERROR
TIMEOUT 10
'' ATZ
OK 'AT+CFUN=1'
OK 'AT+CMEE=1'
OK 'AT\^NDISDUP=1,1,"internet"'
OK
EOT
cat >/etc/chatscripts/gsm_off.HUAWEI <<'EOT'
ABORT ERROR
TIMEOUT 5
'' AT+CFUN=0 OK
EOT
cat >/etc/network/interfaces.d/lte0 <<'EOT'
allow-hotplug lte0
iface lte0 inet dhcp
pre-up /usr/sbin/chat -v -f /etc/chatscripts/sunrise.HUAWEI >/dev/ttyWWAN02 </dev/ttyWWAN02
post-down /usr/sbin/chat -v -f /etc/chatscripts/gsm_off.HUAWEI >/dev/ttyWWAN02 </dev/ttyWWAN02
EOT
# disable interface
ifup lte0 2> /dev/null
elif [[ $2 == off ]]; then
show_box "Warning" "Huawei ME909s-120 LTE will kill connection" 7
# enable interface
ifdown lte0 2> /dev/null
rm /etc/chatscripts/sunrise.HUAWEI
rm /etc/chatscripts/gsm_off.HUAWEI
rm /etc/network/interfaces.d/lte0
elif [[ $(cat /sys/class/net/lte0/operstate) == "up" ]]; then
LTE_MODEM="Huawei ME909s-120 LTE modem is online"
else
LTE_MODEM="Huawei ME909s-120 LTE modem is offline"
fi
;;
esac
}
#
# check hostapd configuration. Return error or empty if o.k.
#
check_hostapd ()
{
systemctl daemon-reload
hostapd_error=""
[[ -n $1 && -n $2 ]] && dialog --title " $1 " --backtitle "$BACKTITLE" --no-collapse --colors --infobox "$2" 5 $((${#2}-3))
service hostapd stop
rm -f /var/run/hostapd/*
sleep 1
service hostapd start
sleep 6
if [[ "$(hostapd_cli ping 2> /dev/null| grep PONG)" == "PONG" ]]; then
hostapd_error=""
else
hostapd_error=$(hostapd /etc/hostapd.conf)
sleep 6
[[ -n $(echo $hostapd_error | grep "channel") ]] && hostapd_error="channel_restriction"
[[ -n $(echo $hostapd_error | grep "does not support" | grep "hw_mode") ]] && hostapd_error="hw_mode"
[[ -n $(echo $hostapd_error | grep "not found from the channel list" | grep "802.11g") ]] && hostapd_error="wrong_channel"
[[ -n $(echo $hostapd_error | grep "VHT") ]] && hostapd_error="unsupported_vht"
[[ -n $(echo $hostapd_error | grep " HT capability") ]] && hostapd_error="unsupported_ht"
fi
}
#
# check all possible wireless modes
#
function check_advanced_modes ()
{
sed '/### IEEE 802.11n/,/^### IEEE 802.11n/ s/^# *//' -i /etc/hostapd.conf
check_hostapd "Probing" "\n802.11n \Z1(150-300Mbps)\Z0"
# check HT capability
check_ht_capab
if [[ -z "$hostapd_error" ]]; then
sed '/### IEEE 802.11a\>/,/^### IEEE 802.11a\>/ s/^# *//' -i /etc/hostapd.conf
sed -i "s/^channel=.*/channel=40/" /etc/hostapd.conf
check_hostapd "Probing" "\n802.11a \Z1(5Ghz)\Z0"
if [[ "$hostapd_error" == "channel_restriction" ]]; then check_channels; fi
if [[ "$hostapd_error" == "channel_restriction" ]]; then
# revering configuration
sed -i "s/^channel=.*/channel=5/" /etc/hostapd.conf
sed '/## IEEE 802.11a\>/,/^## IEEE 802.11a\>/ s/.*/#&/' -i /etc/hostapd.conf
check_hostapd "Reverting" "\nWireless \Z1802.11a (5Ghz)\Z0 is not supported"
else
sed '/### IEEE 802.11ac\>/,/^### IEEE 802.11ac\>/ s/^# *//' -i /etc/hostapd.conf
# check VHT capability
check_vht_capab
if [[ "$hostapd_error" == "unsupported_vht" || "$hostapd_error" == "channel_restriction" ]]; then
# revering configuration
sed '/## IEEE 802.11ac\>/,/^## IEEE 802.11ac\>/ s/.*/#&/' -i /etc/hostapd.conf
check_hostapd "Reverting" "\nWireless 802.11ac \Z1(433Mbps x n @ 5Ghz)\Z0 is not supported"
if [[ "$hostapd_error" == "channel_restriction" ]]; then check_channels; fi
fi
fi
else
sed '/## IEEE 802.11n/,/^## IEEE 802.11n/ s/.*/#&/' -i /etc/hostapd.conf
fi
}
#
# create interface configuration section
#
function create_if_config() {
address=$(ip -4 addr show dev $1 | awk '/inet/ {print $2}' | cut -d'/' -f1)
netmask=$(ip -4 addr show dev $1 | awk '/inet/ {print $2}' | cut -d'/' -f2)
gateway=$(route -n | grep 'UG[ \t]' | awk '{print $2}' | sed -n '1p')
echo -e "# orangepi-config created"
echo -e "source /etc/network/interfaces.d/*\n"
if [[ "$3" == "fixed" ]]; then
echo -e "# Local loopback\nauto lo\niface lo init loopback\n"
echo -e "# Interface $2\nauto $2\nallow-hotplug $2"
echo -e "iface $2 inet static\n\taddress $address\n\tnetmask $netmask\n\tgateway $gateway\n\tdns-nameservers 8.8.8.8"
fi
}
#
# reload network related services
#
function reload-nety() {
systemctl daemon-reload
if [[ "$1" == "reload" ]]; then WHATODO="Reloading services"; else WHATODO="Stopping services"; fi
(service network-manager stop; echo 10; sleep 1; service hostapd stop; echo 20; sleep 1; service dnsmasq stop; echo 30; sleep 1;\
[[ "$1" == "reload" ]] && service dnsmasq start && echo 60 && sleep 1 && service hostapd start && echo 80 && sleep 1;\
service network-manager start; echo 90; sleep 5;) | dialog --backtitle "$BACKTITLE" --title " $WHATODO " --gauge "" 6 70 0
systemctl restart systemd-resolved.service
}
#
# Check if something is running on port $1 and display info
#
function check_port ()
{
[[ -n $(netstat -lnt | awk '$6 == "LISTEN" && $4 ~ ".'$1'"') ]] && dialog --backtitle "$BACKTITLE" --title "Checking service" \
--msgbox "\nIt looks good.\n\nThere is $2 service on port $1" 9 52
}
#
# check wifi high throughput
#
function check_ht_capab ()
{
declare -a arr=("[HT40+][LDPC][SHORT-GI-20][SHORT-GI-40][TX-STBC][RX-STBC1][DSSS_CCK-40][SMPS-STATIC]" \
"[HT40-][SHORT-GI-40][SHORT-GI-40][DSSS_CCK-40]" "[SHORT-GI-20][SHORT-GI-40][HT40+]" "[DSSS_CK-40][HT20+]" "")
local j=0
for i in "${arr[@]}"
do
j=$((j+(100/${#arr[@]})))
echo $j | dialog --title " Probing HT " --colors --gauge "\nSeeking for optimal \Z1high throughput\Z0 settings." 8 50 0
sed -i "s/^ht_capab=.*/ht_capab=$i/" /etc/hostapd.conf
check_hostapd
if [[ "$hostapd_error" == "channel_restriction" ]]; then check_channels; fi
if [[ "$hostapd_error" == "" ]]; then break; fi
done
}
#
# check wifi high throughput
#
function check_vht_capab ()
{
declare -a arr=("[MAX-MPDU-11454][SHORT-GI-80][TX-STBC-2BY1][RX-STBC-1][MAX-A-MPDU-LEN-EXP3]" "[MAX-MPDU-11454][SHORT-GI-80][RX-STBC-1][MAX-A-MPDU-LEN-EXP3]" "")
local j=0
for i in "${arr[@]}"
do
j=$((j+(100/${#arr[@]})))
echo $j | dialog --title " Probing VHT " --colors --gauge "\nSeeking for optimal \Z1very high throughput\Z0 settings." 8 54 0
sed -i "s/^vht_capab=.*/vht_capab=$i/" /etc/hostapd.conf
check_hostapd
if [[ "$hostapd_error" == "channel_restriction" ]]; then check_channels; fi
if [[ "$hostapd_error" == "" ]]; then break; fi
done
}
#
# check 5Ghz channels
#
function check_channels ()
{
declare -a arr=("36" "40")
for i in "${arr[@]}"
do
sed -i "s/^channel=.*/channel=$i/" /etc/hostapd.conf
check_hostapd "Probing" "\nChannel:\Z1 ${i}\Z0"
if [[ "$hostapd_error" != "channel_restriction" ]]; then break; fi
done
}
#
# convert netmask to CIDR
#
function netmask_to_cidr ()
{
IFS=' '
local bits=0
for octet in $(echo $1| sed 's/\./ /g'); do
binbits=$(echo "obase=2; ibase=10; ${octet}"| bc | sed 's/0//g')
let bits+=${#binbits}
done
echo "${bits}"
}
#
# edit ip address within network manager
#
function nm_ip_editor ()
{
exec 3>&1
dialog --title " Static IP configuration" --backtitle "$BACKTITLE" --form "\nAdapter: $1
\n " 12 38 0 \
"Address:" 1 1 "$address" 1 15 15 0 \
"Netmask:" 2 1 "$netmask" 2 15 15 0 \
"Gateway:" 3 1 "$gateway" 3 15 15 0 \
2>&1 1>&3 | {
read -r address;read -r netmask;read -r gateway
if [[ $? = 0 ]]; then
localuuid=$(LC_ALL=C nmcli -f UUID,DEVICE connection show | grep $1 | awk '{print $1}')
# convert netmask value to CIDR if required
if [[ $netmask =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
CIDR=$(netmask_to_cidr ${netmask})
else
CIDR=${netmask}
fi
if [[ -n "$localuuid" ]]; then
# adjust existing
nmcli con mod $localuuid ipv4.method manual ipv4.addresses "$address/$CIDR" >/dev/null 2>&1
nmcli con mod $localuuid ipv4.method manual ipv4.gateway "$gateway" >/dev/null 2>&1
nmcli con mod $localuuid ipv4.dns "8.8.8.8,$gateway" >/dev/null 2>&1
nmcli con down $localuuid >/dev/null 2>&1
sleep 2
nmcli con up $localuuid >/dev/null 2>&1
else
# create new
nmcli con add con-name "orangepi" ifname "$1" type 802-3-ethernet ip4 "$address/$CIDR" gw4 "$gateway" >/dev/null 2>&1
nmcli con mod "orangepi" ipv4.dns "8.8.8.8,$gateway" >/dev/null 2>&1
nmcli con up "orangepi" >/dev/null 2>&1
fi
fi
}
}
#
# edit ip address
#
function systemd_ip_editor ()
{
local filename="/etc/systemd/network/10-$1.network"
if [[ -f $filename ]]; then
sed -i '/Network/,$d' $filename
exec 3>&1
dialog --title " Static IP configuration" --backtitle "$BACKTITLE" --form "\nAdapter: $1
\n " 12 38 0 \
"Address:" 1 1 "$address" 1 15 15 0 \
"Netmask:" 2 1 "$netmask" 2 15 15 0 \
"Gateway:" 3 1 "$gateway" 3 15 15 0 \
2>&1 1>&3 | {
read -r address;read -r netmask;read -r gateway
if [[ $? = 0 ]]; then
echo -e "[Network]" >>$filename
echo -e "Address=$address" >> $filename
echo -e "Gateway=$gateway" >> $filename
echo -e "DNS=8.8.8.8" >> $filename
fi
}
fi
}
#
# edit ip address
#
function ip_editor ()
{
exec 3>&1
dialog --title " Static IP configuration" --backtitle "$BACKTITLE" --form "\nAdapter: $1
\n " 12 38 0 \
"Address:" 1 1 "$address" 1 15 15 0 \
"Netmask:" 2 1 "$netmask" 2 15 15 0 \
"Gateway:" 3 1 "$gateway" 3 15 15 0 \
2>&1 1>&3 | {
read -r address;read -r netmask;read -r gateway
if [[ $? = 0 ]]; then
echo -e "# orangepi-config created\nsource /etc/network/interfaces.d/*\n" >$3
echo -e "# Local loopback\nauto lo\niface lo inet loopback\n" >> $3
echo -e "# Interface $2\nauto $2\nallow-hotplug $2\niface $2 inet static\
\n\taddress $address\n\tnetmask $netmask\n\tgateway $gateway\n\tdns-nameservers 8.8.8.8" >> $3
fi
}
}
#
# edit hostapd parameters
#
function wlan_edit_basic ()
{
source /etc/hostapd.conf
exec 3>&1
dialog --title "AP configuration" --backtitle "$BACKTITLE" --form "\nWPA2 enabled, \
advanced config: edit /etc/hostapd.conf\n " 12 58 0 \
"SSID:" 1 1 "$ssid" 1 31 22 0 \
"Password:" 2 1 "$wpa_passphrase" 2 31 22 0 \
"Channel:" 3 1 "$channel" 3 31 3 0 \
2>&1 1>&3 | {
read -r ssid;read -r wpa_passphrase;read -r channel
if [[ $? = 0 ]]; then
sed -i "s/^ssid=.*/ssid=$ssid/" /etc/hostapd.conf
sed -i "s/^wpa_passphrase=.*/wpa_passphrase=$wpa_passphrase/" /etc/hostapd.conf
sed -i "s/^channel=.*/channel=$channel/" /etc/hostapd.conf
wpa_psk=$(wpa_passphrase $ssid $wpa_passphrase | grep '^[[:blank:]]*[^[:blank:]#;]' | grep psk | cut -d= -f2-)
sed -i "s/^wpa_psk=.*/wpa_psk=$wpa_psk/" /etc/hostapd.conf
fi
}
}
#
# edit hostapd parameters
#
function wlan_edit ()
{
# select default interfaces if there is more than one
select_interface "default"
dialog --title " Configuration edit " --colors --backtitle "$BACKTITLE" --help-button --help-label "Cancel" --yes-label "Basic" \
--no-label "Advanced" --yesno "\n\Z1Basic:\Z0 Change SSID, password and channel\n\n\Z1Advanced:\Z0 Edit /etc/hostapd.conf file" 9 70
if [[ $? = 0 ]]; then
wlan_edit_basic
elif [[ $? = 1 ]]; then
dialog --backtitle "$BACKTITLE" --title " Edit hostapd configuration /etc/hostapd.conf" --no-collapse \
--ok-label "Save" --editbox /etc/hostapd.conf 30 0 2> /etc/hostapd.conf.out
[[ $? = 0 ]] && mv /etc/hostapd.conf.out /etc/hostapd.conf && service hostapd restart
fi
}
#
# here we add wifi exceptions
#
function wlan_exceptions ()
{
reboot_module=false
[[ -n "$(lsmod | grep -w dhd)" && $1 = "on" ]] && \
echo 'options dhd op_mode=2' >/etc/modprobe.d/ap6212.conf && rmmod dhd && modprobe dhd
[[ -n "$(lsmod | grep -w dhd)" && $1 = "off" ]] && \
rm /etc/modprobe.d/ap6212.conf && rmmod dhd && modprobe dhd
# Cubietruck
[[ -n "$(lsmod | grep -w ap6210)" && $1 = "on" ]] && \
echo 'options ap6210 op_mode=2' >/etc/modprobe.d/ap6210.conf && reboot_module=true
[[ -n "$(lsmod | grep -w ap6210)" && $1 = "off" ]] && \
rm /etc/modprobe.d/ap6210.conf && reboot_module=true
}
#
# here add shaddy wifi adaptors
#
function check_and_warn ()
{
local shaddy=false
# blacklist
[[ "$LINUXFAMILY" == "sun8i" && $BOARD == "orangepizero" ]] && shaddy=true
[[ -n "$(lsmod | grep mt7601u)" ]] && shaddy=true
[[ -n "$(lsmod | grep r8188eu)" ]] && shaddy=true
# blacklist
if [[ "$shaddy" == "true" ]]; then
dialog --title " Warning " --ok-label " Accept and proceed " --msgbox '\nOne of your wireless drivers are on a black list due to poor quality.\n\nAP mode might not be possible!' 9 73
fi
}
#
# search for wlan interfaces and provide a selection menu if there are more than one
#
function get_wlan_interface ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
WLAN_INTERFACES=($(LC_ALL=C nmcli --wait 10 dev status | grep wifi | grep disconnected |awk '{print $1}'))
local LIST=()
for i in "${WLAN_INTERFACES[@]}"
do
LIST+=( "${i[0]//[[:blank:]]/}" "" )
done
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 1 ]; then
WIRELESS_ADAPTER=${WLAN_INTERFACES[0]}
else
exec 3>&1
WIRELESS_ADAPTER=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "Select interface" --clear --menu "" $((6+${LIST_LENGTH})) 40 15 "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
function select_interface ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
local ADAPTER=($(nmcli device status | grep ethernet | awk '{ print $1 }' | grep -v lo))
local LIST=()
for i in "${ADAPTER[@]}"
do
local IPADDR=$(LC_ALL=C ip -4 addr show dev ${i[0]} | awk '/inet/ {print $2}' | cut -d'/' -f1)
ADD_SPEED=""
[[ $i == eth* || $i == en* ]] && ADD_SPEED=$(ethtool $i | grep Speed)
[[ $i == wl* ]] && ADD_SPEED=$(LC_ALL=C nmcli -f RATE,DEVICE,ACTIVE dev wifi list | grep $i | grep yes | awk 'NF==4{print $1""$2}NF==1' | sed -e 's/^/ Speed: /' | tail -1)
LIST+=( "${i[0]//[[:blank:]]/}" "${IPADDR} ${ADD_SPEED}" )
done
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 0 ]; then
SELECTED_ADAPTER="lo"
elif [ "$LIST_LENGTH" -eq 1 ]; then
SELECTED_ADAPTER=${ADAPTER[0]}
else
exec 3>&1
SELECTED_ADAPTER=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse --title "Select $1 interface" --clear \
--menu "" $((6+${LIST_LENGTH})) 74 14 "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
}
#
# select interface if there is more than one and adjust metric
#
# $1 = default | all
#
function select_default_interface ()
{
ALREADY_DEFINED=$(cat /etc/iptables.ipv4.nat 2> /dev/null | grep "POSTROUTING -o" | tail -1 | awk '{ print $4 }')
if [[ -n "${ALREADY_DEFINED}" ]]; then
DEFAULT_ADAPTER=${ALREADY_DEFINED}
else
IFS=$'\r\n'
GLOBIGNORE='*'
if [[ $1 == "default" ]]; then
local ADAPTER=($(nmcli -t -f DEVICE connection show --active))
else
local ADAPTER=($(nmcli device status | tail -n +2 | awk '{ print $1 }' | grep -v lo))
fi
local LIST=()
for i in "${ADAPTER[@]}"
do
local IPADDR=$(LC_ALL=C ip -4 addr show dev ${i[0]} | awk '/inet/ {print $2}' | cut -d'/' -f1)
ADD_SPEED=""
[[ $i == eth* || $i == en* ]] && ADD_SPEED=$(ethtool $i | grep Speed)
[[ $i == wl* ]] && ADD_SPEED=$(LC_ALL=C nmcli -f RATE,DEVICE,ACTIVE dev wifi list | grep $i | grep yes | awk 'NF==4{print $1""$2}NF==1' | sed -e 's/^/ Speed: /' | tail -1)
if [[ $1 == "default" ]]; then
[[ $IPADDR != "172.24.1.1" && -n $IPADDR ]] && LIST+=( "${i[0]//[[:blank:]]/}" "${IPADDR} ${ADD_SPEED}" )
else
[[ $IPADDR != "172.24.1.1" ]] && LIST+=( "${i[0]//[[:blank:]]/}" "${IPADDR} ${ADD_SPEED}" )
fi
done
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 0 ]; then
DEFAULT_ADAPTER="lo"
elif [ "$LIST_LENGTH" -eq 1 ]; then
DEFAULT_ADAPTER=${ADAPTER[0]}
else
exec 3>&1
DEFAULT_ADAPTER=$(dialog --nocancel --backtitle "$BACKTITLE" --no-collapse \
--title "Select $1 interface" --clear --menu "" $((6+${LIST_LENGTH})) 74 14 "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
fi
fi
# set highest metric to default adaptor
HIGHEST_METRIC=$(nmcli -t -f UUID,TYPE,DEVICE connection show --active | grep $DEFAULT_ADAPTER | sed 's/:.*$//')
# set metric to 50
nmcli connection modify $HIGHEST_METRIC ipv4.route-metric 50 2> /dev/null
METRIC=77
# set others wired
REMAINING=( `nmcli -t -f UUID,TYPE,DEVICE connection show --active | grep ethernet | grep -v $DEFAULT_ADAPTER | sed 's/:.*$//'` )
if [[ ${#REMAINING[@]} -ge 1 ]]; then
for i in "${REMAINING[@]}"
do
METRIC=$(( $METRIC + 1 ))
nmcli connection modify ${i} ipv4.route-metric $METRIC
done
fi
# set other wireless
METRIC=88
REMAINING=( `nmcli -t -f UUID,TYPE,DEVICE connection show --active | grep wireless | grep -v $DEFAULT_ADAPTER | sed 's/:.*$//'` )
if [[ ${#REMAINING[@]} -ge 1 ]]; then
for i in "${REMAINING[@]}"
do
METRIC=$(( $METRIC + 1 ))
nmcli connection modify ${i} ipv4.route-metric $METRIC
done
fi
# create default metrics file
cat <<-EOF > /etc/NetworkManager/conf.d/orangepi-default-metric.conf
[connection-ethernet-gateway]
match-device=interface-name:$DEFAULT_ADAPTER
ipv4.route-metric=50
[connection-wifi-other]
match-device=type:wifi
ipv4.route-metric=88
[connection-ethernet-other]
match-device=type:ethernet
ipv4.route-metric=77
EOF
}
#
# search and connect to Bluetooth devices
#
function connect_bt_interface ()
{
IFS=$'\r\n'
GLOBIGNORE='*'
dialog --backtitle "$BACKTITLE" --title "Please wait" --infobox "\nDiscovering Bluetooth devices ... " 5 37
BT_INTERFACES=($(hcitool scan | sed '1d'))
local LIST=()
for i in "${BT_INTERFACES[@]}"
do
local a=$(echo ${i[0]//[[:blank:]]/} | sed -e 's/^\(.\{17\}\).*/\1/')
local b=${i[0]//$a/}
local b=$(echo $b | sed -e 's/^[ \t]*//')
LIST+=( "$a" "$b")
done
LIST_LENGTH=$((${#LIST[@]}/2));
if [ "$LIST_LENGTH" -eq 0 ]; then
BT_ADAPTER=${WLAN_INTERFACES[0]}
dialog --backtitle "$BACKTITLE" --title "Bluetooth" --msgbox "\nNo nearby Bluetooth devices were found!" 7 43
else
exec 3>&1
BT_ADAPTER=$(dialog --backtitle "$BACKTITLE" --no-collapse --title "Select interface" \
--clear --menu "" $((6+${LIST_LENGTH})) 50 15 "${LIST[@]}" 2>&1 1>&3)
exec 3>&-
if [[ $BT_ADAPTER != "" ]]; then
dialog --backtitle "$BACKTITLE" --title "Please wait" --infobox "\nConnecting to $BT_ADAPTER " 5 35
BT_EXEC=$(
expect -c 'set prompt "#";set address '$BT_ADAPTER';spawn bluetoothctl;expect -re $prompt;send "disconnect $address\r";
sleep 1;send "remove $address\r";sleep 1;expect -re $prompt;send "scan on\r";sleep 8;send "scan off\r";
expect "Controller";send "trust $address\r";sleep 2;send "pair $address\r";sleep 2;send "connect $address\r";
send_user "\nShould be paired now.\r";sleep 2;send "quit\r";expect eof')
echo "$BT_EXEC" > /tmp/bt-connect-debug.log
if [[ $(echo "$BT_EXEC" | grep "Connection successful" ) != "" ]]; then
dialog --backtitle "$BACKTITLE" --title "Bluetooth" --msgbox "\nYour device is ready to use!" 7 32
else
dialog --backtitle "$BACKTITLE" --title "Bluetooth" --msgbox "\nError connecting. Try again!" 7 32
fi
fi
fi
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,438 @@
#!/bin/bash
#
# Copyright (c) 2018 Igor Pecovnik, igor.pecovnik@gma**.com
#
# This file is licensed under the terms of the GNU General Public
# License version 2. This program is licensed "as is" without any
# warranty of any kind, whether express or implied.
# Functions:
# submenu_settings
# submenu_networking
# submenu_personal
# submenu_software
#
# system settings
#
function submenu_settings ()
{
unset main
while true; do
LIST=()
DIALOG_CANCEL=1
DIALOG_ESC=255
# detect desktop
check_desktop
# check update status of BSP packages
local mark=$(apt-mark showhold | egrep "linux|orangepi")
# check if eMMC/SD is on the system
if [[ $(sed -n 's/^DEVNAME=//p' /sys/dev/block/$(mountpoint -d /)/uevent 2> /dev/null) == mmcblk* \
&& -f /usr/sbin/nand-sata-install ]]; then
LIST+=( "Install" "Install to/update boot loader" )
fi
# orangepi specific function
if [[ -f /etc/orangepi-release ]]; then
if [[ -n "${mark}" ]]; then
:
#LIST+=( "Defreeze" "Enable Orange Pi upgrades " )
else
:
#LIST+=( "Freeze" "Disable Orange Pi upgrades " )
fi
fi
# orangepi specific function, when upgrades are enabled
if [[ -z ${mark} ]]; then
[[ -f /etc/apt/sources.list.d/orangepi.list ]] && [[ -n $(grep -w apt /etc/apt/sources.list.d/orangepi.list) ]] \
&& LIST+=( "Nightly" "Switch to nightly automated builds" )
[[ -f /etc/apt/sources.list.d/orangepi.list ]] && [[ -n $(grep -w beta /etc/apt/sources.list.d/orangepi.list) ]] \
&& LIST+=( "Stable" "Switch to stable builds" )
fi
[[ -n $(grep -w "#kernel.printk" /etc/sysctl.conf ) ]] && LIST+=( "Lowlevel" "Stop low-level messages on console" )
[[ -f /boot/orangepiEnv.txt ]] && LIST+=( "Bootenv" "Edit boot environment" )
[[ -f /boot/boot.ini ]] && LIST+=( "Bootscript" "Edit boot script" )
if [[ -f /etc/default/cpufrequtils ]]; then
LIST+=( "CPU" "Set CPU speed and governor" )
fi
AVAHIDSTATUS=$(service avahi-daemon status 2> /dev/null | grep -w active | grep -w running)
if [[ -n "$AVAHIDSTATUS" ]]; then
LIST+=( "Avahi" "Disable system announce in the network" )
else
LIST+=( "Avahi" "Announce system in the network" )
fi
[[ -d ${OVERLAYDIR} ]] && \
LIST+=( "Hardware" "Toggle hardware configuration: UART, I2C, etc." )
[[ "$LINUXFAMILY" = cubox && "$BRANCH" = "next" ]] && LIST+=( "DTB" "Switch board .dtb configuration" )
# this is avaliable only in kernel higher than 4.10
testvercomp "$(uname -r | sed 's/-.*//')" "4.10.0" ">"
[[ "$LINUXFAMILY" = odroidxu4 && $? == 0 ]] && LIST+=( "DTB" "Select optimised board configuration" )
[[ -f /usr/bin/bin2fex && "$LINUXFAMILY" = sun*i && "$BRANCH" = "default" ]] && LIST+=( "Fexedit" "Board (fex) settings editor" )
[[ -z ${mark} ]] && [[ -f /etc/apt/sources.list.d/orangepi.list ]] && LIST+=( "Other" "Switch to other kernels" )
LIST+=( "SSH" "Reconfigure SSH daemon" )
LIST+=( "Firmware" "Run apt update & apt upgrade" )
if [[ "$SHELL" != "/bin/bash" ]]; then
LIST+=( "BASH" "Revert to stock BASH shell" )
else
LIST+=( "ZSH" "Install ZSH with plugins and tmux" )
fi
[[ "$LINUXFAMILY" = sun*i && "$BRANCH" = "default" && \
-n $(bin2fex </boot/script.bin 2>/dev/null | grep -w "hdmi_used = 1") ]] && LIST+=( "Display" "Set the display resolution" )
[[ "$LINUXFAMILY" = odroidc* || "$LINUXFAMILY" = odroidn2 && "$BRANCH" = "default" ]] && LIST+=( "Display" "Set the display resolution" )
# desktop
if [[ -n $DISPLAY_MANAGER ]]; then
LIST+=( "Desktop" "Disable desktop or change login type" )
else
if [[ -n $DESKTOP_INSTALLED ]]; then
LIST+=( "Desktop" "Enable desktop" )
else
:
#LIST+=( "Default" "Install desktop with browser and extras" )
fi
fi
# overlayroot
if [[ "$DISTRO" == "Ubuntu" && "$(modinfo overlay > /dev/null 2>&1; echo $?)" == "0" ]]; then
if [ -n "$(mount | grep -w tmpfs-root)" ]; then
:
#LIST+=( "Overlayroot" "Disable virtual read-only root filesystem" )
else
:
#LIST+=( "Overlayroot" "Enable virtual read-only root filesystem" )
fi
fi
# count number of menu items to adjust window size
LISTLENGTH="$((6+${#LIST[@]}/2))"
BOXLENGTH=${#LIST[@]}
temp_rc=$(mktemp)
if [[ -n ${mark} || -n $(grep -w beta /etc/apt/sources.list.d/orangepi.list 2> /dev/null) ]]; then
cat <<-'EOF' > $temp_rc
dialog_color = (RED,WHITE,OFF)
screen_color = (WHITE,RED,ON)
tag_color = (RED,WHITE,ON)
item_selected_color = (WHITE,RED,ON)
tag_selected_color = (WHITE,RED,ON)
tag_key_selected_color = (WHITE,RED,ON)
EOF
[[ -n ${mark} ]] && local sys_title=" Warning - firmware packages frozen"
[[ -n $(grep -w beta /etc/apt/sources.list.d/orangepi.list 2> /dev/null) ]] && \
local sys_title=" Warning - attached to beta repository"
[[ -n ${mark} && -n $(grep -w beta /etc/apt/sources.list.d/orangepi.list 2> /dev/null) ]] && \
sys_title=" Warning - frozen & attached to beta repository"
else
local sys_title=" System settings "
echo > $temp_rc
fi
if [[ -z $selection ]]; then
exec 3>&1
selection=$(DIALOGRC=$temp_rc dialog --colors --backtitle "$BACKTITLE" --title " $sys_title " --clear \
--cancel-label "Back" --menu "$disclaimer" $LISTLENGTH 0 $BOXLENGTH \
"${LIST[@]}" 2>&1 1>&3)
exit_status=$?
exec 3>&-
[[ $exit_status == $DIALOG_CANCEL || $exit_status == $DIALOG_ESC ]] && clear && break
fi
# run main function
jobs "$selection"
done
}
#
# menu for networking
#
function submenu_networking ()
{
# select default interface if there is more than one connected
#select_interface "default"
unset main
while true; do
LIST=()
DIALOG_CANCEL=1
DIALOG_ESC=255
# check if we have some LTE modems
for i in $(lsusb | awk '{print $6}'); do lte "$i"; done;
# edit ip
LIST+=( "IP" "Select dynamic or edit static IP address" )
# hostapd
HOSTAPDBRIDGE=$(cat /etc/hostapd.conf 2> /dev/null | grep -w "^bridge=br0")
HOSTAPDSTATUS=$(service hostapd status 2> /dev/null | grep -w active | grep -w running)
if [[ -n "$HOSTAPDSTATUS" ]]; then
HOSTAPDINFO=$(hostapd_cli get_config 2> /dev/null | grep ^ssid | sed 's/ssid=//g')
HOSTAPDCLIENTS=$(hostapd_cli all_sta 2> /dev/null | grep connected_time | wc -l)
#LIST+=( "Hotspot" "Manage active wireless access point" )
else
:
#[[ -n $(LC_ALL=C nmcli device status 2> /dev/null | grep wifi | grep -w disconnected) ]] && \
#LIST+=( "Hotspot" "Create WiFi access point" )
fi
# toggle IPv6
if [[ $(cat /proc/sys/net/ipv6/conf/all/disable_ipv6) == 1 ]]; then
LIST+=( "IPV6" "Enable IPv6 for APT and system" )
else
LIST+=( "IPV6" "Disable IPv6 for APT and system" )
fi
# network throughput test
if check_if_installed iperf3; then
if pgrep -x "iperf3" > /dev/null
then
LIST+=( "Iperf3" "Disable network throughput tests daemon" )
else
LIST+=( "Iperf3" "Enable network throughput tests daemon" )
fi
fi
if [[ -n $(LC_ALL=C nmcli device status 2> /dev/null | grep wifi | grep -v unavailable | grep -v unmanaged) ]]; then
LIST+=( "WiFi" "Manage wireless networking" )
else
LIST+=( "Clear" "Clear possible blocked interfaces" )
fi
if [[ -n $LTE_MODEM ]]; then
# apply udev rules
initialize_lte
LIST+=( "LTE" "$LTE_MODEM" )
fi
check_if_installed lirc && LIST+=( "Remove IR" "Remove IR support" ) || LIST+=( "IR" "Install IR support" )
if check_if_installed bluetooth then ; then
LIST+=( "BT remove" "Remove Bluetooth support" )
if [[ -n $(service bluetooth status | grep -w active | grep -w running) ]]; then
[[ $(hcitool dev | sed '1d') != "" ]] && LIST+=( "BT discover" "Discover and connect Bluetooth devices" )
fi
else
LIST+=( "BT install" "Install Bluetooth support" )
fi
[[ -d /usr/local/vpnclient ]] && LIST+=( "VPN" "Manage Softether VPN client" ) && VPNSERVERIP=$(/usr/local/vpnclient/vpncmd /client localhost /cmd accountlist | grep "VPN Server" |grep -o '[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}' | head -1)
LIST+=( "Advanced" "Edit /etc/network/interfaces" )
[[ $(ls -1 /etc/NetworkManager/system-connections 2> /dev/null) ]] && \
LIST+=( "Forget" "Disconnect and forget all wireless connections" )
# count number of menu items to adjust window size
LISTLENGTH="$((12+${#LIST[@]}/2))"
BOXLENGTH=${#LIST[@]}
WIFICONNECTED=$(LC_ALL=C nmcli -f NAME,TYPE connection show --active 2> /dev/null | grep wireless | awk 'NF{NF-=1};1')
local disclaimer=""
local ipadd=$(ip -4 addr show dev $DEFAULT_ADAPTER | awk '/inet/ {print $2}' | cut -d'/' -f1)
if [[ -n $(LC_ALL=C nmcli device status 2> /dev/null | grep $DEFAULT_ADAPTER | grep connected) ]]; then
local ifup="\nIP ($DEFAULT_ADAPTER) via Network Manager: \Z1${ipadd}\n\Z0 "
else
if [[ -n $(service systemd-networkd status | grep -w active | grep -w running) ]]; then
local ifup="\nIP ($DEFAULT_ADAPTER) via systemd-networkd: \Z1${ipadd}\n\Z0 "
else
local ifup="\nIP ($DEFAULT_ADAPTER) via IFUPDOWN: \Z1${ipadd}\n\Z0 "
fi
fi
disclaimer="$ifup"
if [[ -n $WIFICONNECTED ]]; then
LISTLENGTH=$((LISTLENGTH+2))
local connected="\n\Z0Connected to SSID: \Z1${WIFICONNECTED}\n\Z0 "
disclaimer=$disclaimer"$connected"
fi
if [[ -n $VPNSERVERIP ]]; then
local vpnserverip="\n\Z0Connected to VPN server: \Z1${VPNSERVERIP}\n\Z0 "
disclaimer=$disclaimer"$vpnserverip"
LISTLENGTH=$((LISTLENGTH+2))
fi
if [[ -n $HOSTAPDINFO && -n $HOSTAPDSTATUS ]]; then
LISTLENGTH=$((LISTLENGTH+2))
chpid=$(dmesg | grep $(grep ^interface /etc/hostapd.conf | sed 's/interface=//g') | head -1 | sed 's/\[.*\]//g' | awk '{print $1}')
disclaimer=$disclaimer$"\n\Z0Hotspot SSID: \Z1$HOSTAPDINFO\Zn Band:";
if [[ `grep ^hw_mode=a /etc/hostapd.conf` ]]; then local band="5Ghz"; else band="2.4Ghz"; fi
if [[ `grep ^ieee80211n /etc/hostapd.conf` ]]; then local type="N"; fi
if [[ `grep ^ieee80211ac /etc/hostapd.conf` ]]; then local type="AC"; fi
disclaimer=$disclaimer$" \Z1${band} ${type}\Z0"
[[ ! "$chpid" =~ .*IPv6.* ]] && disclaimer=$disclaimer$"\n\nChip: \Z1${chpid}\Z0";
if [ "$HOSTAPDCLIENTS" -gt "0" ]; then disclaimer=$disclaimer$" Connected clients: \Z1$HOSTAPDCLIENTS\Zn"; fi
if [[ ! "$chpid" =~ .*IPv6.* ]]; then LISTLENGTH=$((LISTLENGTH+2)); fi
disclaimer=$disclaimer$"\n";
fi
disclaimer=$disclaimer"\n\Z1Note\Zn: This tool can be successful only when drivers are configured properly. If auto-detection fails, you are on your own.\n "
if [[ -z $selection ]]; then
exec 3>&1
selection=$(dialog --backtitle "$BACKTITLE" --colors --title " Wired, Wireless, Bluetooth, Hotspot " --clear \
--cancel-label "Back" --menu "${disclaimer}" $LISTLENGTH 70 $BOXLENGTH \
"${LIST[@]}" 2>&1 1>&3)
exit_status=$?
exec 3>&-
[[ $exit_status == $DIALOG_CANCEL || $exit_status == $DIALOG_ESC ]] && clear && break
fi
# run main function
jobs "$selection"
done
}
#
# personal
#
function submenu_personal ()
{
unset main
while true; do
LIST=()
LIST+=( "Timezone" "Change timezone \Z5($(LC_ALL=C timedatectl | grep zone | awk '{$1=$1;print}' | sed "s/Time zone: //"))\Z0" )
LIST+=( "Locales" "Reconfigure language \Z5($(locale | grep LANGUAGE | cut -d= -f2 | cut -d_ -f1))\Z0 and character set" )
LIST+=( "Keyboard" "Change console keyboard layout (\Z5$(cat /etc/default/keyboard | grep XKBLAYOUT | grep -o '".*"' | sed 's/"//g')\Z0)")
LIST+=( "Hostname" "Change your hostname \Z5($(cat /etc/hostname))\Z0" )
LIST+=( "Welcome" "Toggle welcome screen items" )
# count number of menu items to adjust window sizee
LISTLENGTH="$((6+${#LIST[@]}/2))"
BOXLENGTH=${#LIST[@]}
exec 3>&1
selection=$(dialog --colors --backtitle "$BACKTITLE" --title "Personal settings" --clear \
--cancel-label "Back" --menu "$disclaimer" $LISTLENGTH 70 $BOXLENGTH \
"${LIST[@]}" 2>&1 1>&3)
exit_status=$?
exec 3>&-
[[ $exit_status == $DIALOG_CANCEL || $exit_status == $DIALOG_ESC ]] && clear && break
# run main function
jobs "$selection"
done
}
#
# software
#
function submenu_software ()
{
unset main
while true; do
# detect desktop
check_desktop
LIST=()
[[ -f /usr/bin/softy || -f softy ]] && LIST+=( "Softy" "3rd party applications installer" )
[[ -f /usr/bin/h3consumption && "$LINUXFAMILY" = "sun8i" && "$BRANCH" = "default" ]] && \
LIST+=( "Consumption" "Control board consumption" )
[[ -f /usr/bin/orangepimonitor ]] && LIST+=( "Monitor" "Simple CLI board monitoring" )
LIST+=( "Benchmarking" "sbc-bench board benchmarking" )
[[ -f /usr/bin/orangepimonitor ]] && LIST+=( "Diagnostics" "Send diagnostics" )
#if [[ -n $(dpkg -l | grep linux-headers) ]]; then LIST+=( "Headers_remove" "kernel headers" ); else \
#LIST+=( "Headers_install" "kernel headers" ); fi
SOURCE_PKG_LIST=$(apt-cache --names-only search ^linux-source-* | awk '{ print $1 }' | grep -w ${BRANCH}-${LINUXFAMILY} | tail -n 5)
if [[ -n $SOURCE_PKG_LIST ]]; then
:
#LIST+=( "Source_install" "kernel source" )
fi
SOURCE_PKG_LIST_INSTALLED=$(find /usr/src -maxdepth 1 -name "linux-source*")
if [[ -n $SOURCE_PKG_LIST_INSTALLED ]]; then
:
#LIST+=( "Source_remove" "kernel source" );
fi
if [[ -f /etc/orangepi.txt ]]; then
if [[ -n $(dpkg -l | grep -w "orangepi-firmware-full ") ]]; then
:
#LIST+=( "Mini" "Install mini firmware package" );
else
:
#LIST+=( "Full" "Install full firmware package" );
fi
fi
if [[ -n $DISPLAY_MANAGER ]]; then
if [[ $(service xrdp status 2> /dev/null | grep -w active) ]]; then
LIST+=( "RDP" "Disable remote desktop access from Windows" )
else
LIST+=( "RDP" "Enable remote desktop access from Windows" )
fi
if ! check_if_installed thunderbird ; then
LIST+=( "Thunderbird" "Install full featured email client" )
else
LIST+=( "Thunderbird" "Remove full featured email client" )
fi
if ! check_if_installed gimp ; then
LIST+=( "Gimp" "Install photo manipulation tool" )
else
LIST+=( "Gimp" "Remove photo manipulation tool" )
fi
if ! check_if_installed libreoffice-writer ; then
LIST+=( "Writer" "Libreoffice: Writer only" )
LIST+=( "Suite" "Libreoffice: Full suite" )
else
if ! check_if_installed libreoffice-base ; then
LIST+=( "Suite" "Libreoffice: Full suite" )
LIST+=( "Libre" "Remove Libre office packages" )
else
LIST+=( "Libre" "Remove Libre office packages" )
fi
fi
fi
# count number of menu items to adjust window sizee
LISTLENGTH="$((6+${#LIST[@]}/2))"
BOXLENGTH=${#LIST[@]}
if [[ -z $selection ]]; then
exec 3>&1
selection=$(dialog --backtitle "$BACKTITLE" --title "System and 3rd party software" --clear \
--cancel-label "Back" --menu "$disclaimer" $LISTLENGTH 70 $BOXLENGTH \
"${LIST[@]}" 2>&1 1>&3)
exit_status=$?
exec 3>&-
[[ $exit_status == $DIALOG_CANCEL || $exit_status == $DIALOG_ESC ]] && clear && break
fi
# run main function
jobs "$selection"
done
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
[global]
workgroup = SMBGROUP
server string = %h server
hosts allow = SUBNET
log file = /var/log/samba/log.%m
max log size = 1000
syslog = 0
panic action = /usr/share/samba/panic-action %d
load printers = yes
printing = cups
printcap name = cups
[printers]
comment = All Printers
path = /var/spool/samba
browseable = no
public = yes
guest ok = yes
writable = no
printable = yes
printer admin = SMBUSER
[print$]
comment = Printer Drivers
path = /etc/samba/drivers
browseable = yes
guest ok = no
read only = yes
write list = SMBUSER
[ext]
comment = Storage
path = /ext
writable = yes
public = no
valid users = SMBUSER
force create mode = 0777

View File

@@ -0,0 +1,55 @@
#!/bin/bash
dflag=
vflag=
cflag=
if (( $# < 1 ))
then
### URL of your XML file
wget -qO - "http://xml.tv.data"
exit 0
fi
for arg
do
delim=""
case "$arg" in
#translate --gnu-long-options to -g (short options)
--description) args="${args}-d ";;
--version) args="${args}-v ";;
--capabilities) args="${args}-c ";;
#pass through anything else
*) [[ "${arg:0:1}" == "-" ]] || delim="\""
args="${args}${delim}${arg}${delim} ";;
esac
done
#Reset the positional parameters to the short options
eval set -- $args
while getopts "dvc" option
do
case $option in
d) dflag=1;;
v) vflag=1;;
c) cflag=1;;
\?) printf "unknown option: -%s\n" $OPTARG
printf "Usage: %s: [--description] [--version] [--capabilities] \n" $(basename $0)
exit 2
;;
esac >&2
done
if [ "$dflag" ]
then
printf "tv_grag_file is a simple grabber that just read the ~/.xmltv/tv_grab_file.xmltv file\n"
fi
if [ "$vflag" ]
then
printf "0.1\n"
fi
if [ "$cflag" ]
then
printf "baseline\n"
fi
exit 0

View File

@@ -0,0 +1 @@
debian-software

View File

@@ -0,0 +1,20 @@
CFLAGS := -Wall -g
CC := $(CROSS_COMPILE)gcc
all: rtk_hciattach
OBJS := hciattach.o hciattach_rtk.o hciattach_h4.o rtb_fwc.o
rtk_hciattach: $(OBJS)
$(CROSS_COMPILE)gcc -o rtk_hciattach $(OBJS)
%.o: %.c
$(CROSS_COMPILE)gcc -c $< -o $@ $(CFLAGS)
clean:
rm -f $(OBJS) rtk_hciattach
tags: FORCE
ctags -R
find ./ -name "*.h" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" > cscope.files
cscope -bkq -i cscope.files
PHONY += FORCE
FORCE:

View File

@@ -0,0 +1,39 @@
The document describes how to support Realtek UART Bluetooth driver in Linux system.
The supported kernel version is 2.6.32 - 4.15
The default serial protocol of Realtek Bluetooth chip is Three-wire (H5) protocol
with flow control on, parity even and internel 32k clock.
The default baud rate is 115200.
To support Three-wire (H5) protocol, you need to install Realtek hci_uart driver
and rtk_hciattach tool.
1. make sure your UART setting is correct.
host tx - controller rx
host rx - controller tx
host rts - controller cts
host cts - ground
NC - controller rts
2. Install Bluetooth kernel driver and rtk_hciattach tool
$ sudo make install
If you encounter an error like "depmod: ERROR: Bad version passed /lib/modules/...",
please change the lines "depmod -a $(MDL_DIR)" to "depmod -a $(shell uname -r)"
3. Initialize Realtek Bluetooth chip by rtk_hciattach
$ sudo rtk_hciattach -n -s 115200 ttyUSB0 rtk_h5
for H4 protocol chip
$ sudo rtk_hciattach -n -s 115200 ttyUSB0 rtk_h4
Tips: ttyUSB0 is serial port name in your system, you should change it
according to hardware such as ttyS0.
4. Uninstall
$ sudo make uninstall
If you want to change the parameter such as baud rate and pcm settings, you
should modify rtl8xxx_config file.

View File

@@ -0,0 +1,631 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2000-2001 Qualcomm Incorporated
* Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
* Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <syslog.h>
#include <termios.h>
#include <time.h>
#include <sys/time.h>
#include <sys/poll.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/timerfd.h>
#include "hciattach.h"
#define RFKILL_NODE "/sys/class/rfkill/rfkill0/state"
#ifdef NEED_PPOLL
#include "ppoll.h"
#endif
/* #define SCHED_ENABLE */
#ifdef SCHED_ENABLE
#include <sched.h>
#endif
struct uart_t {
char *type;
int m_id;
int p_id;
int proto;
int init_speed;
int speed;
int flags;
int pm;
char *bdaddr;
int (*init) (int fd, struct uart_t *u, struct termios *ti);
int (*post) (int fd, struct uart_t *u, struct termios *ti);
};
#define FLOW_CTL 0x0001
#define ENABLE_PM 1
#define DISABLE_PM 0
static volatile sig_atomic_t __io_canceled = 0;
static void sig_hup(int sig)
{
RS_INFO("signal hup.");
}
static void sig_term(int sig)
{
switch (sig) {
case SIGINT:
RS_INFO("signal int.");
break;
case SIGTERM:
RS_INFO("signal term.");
break;
}
__io_canceled = 1;
}
static void sig_alarm(int sig)
{
RS_ERR("Initialization timed out.");
exit(1);
}
static int uart_speed(int s)
{
switch (s) {
case 9600:
return B9600;
case 19200:
return B19200;
case 38400:
return B38400;
case 57600:
return B57600;
case 115200:
return B115200;
case 230400:
return B230400;
case 460800:
return B460800;
case 500000:
return B500000;
case 576000:
return B576000;
case 921600:
return B921600;
case 1000000:
return B1000000;
case 1152000:
return B1152000;
case 1500000:
return B1500000;
case 2000000:
return B2000000;
#ifdef B2500000
case 2500000:
return B2500000;
#endif
#ifdef B3000000
case 3000000:
return B3000000;
#endif
#ifdef B3500000
case 3500000:
return B3500000;
#endif
#ifdef B4000000
case 4000000:
return B4000000;
#endif
default:
return B57600;
}
}
int set_speed(int fd, struct termios *ti, int speed)
{
if (cfsetospeed(ti, uart_speed(speed)) < 0)
return -errno;
if (cfsetispeed(ti, uart_speed(speed)) < 0)
return -errno;
if (tcsetattr(fd, TCSANOW, ti) < 0)
return -errno;
return 0;
}
static int realtek_init(int fd, struct uart_t *u, struct termios *ti)
{
RS_INFO("Realtek Bluetooth init uart with init speed:%d, type:HCI UART %s",
u->init_speed,
(u->proto == HCI_UART_H4) ? "H4" : "H5");
return rtb_init(fd, u->proto, u->speed, ti);
}
static int realtek_post(int fd, struct uart_t *u, struct termios *ti)
{
RS_INFO("Realtek Bluetooth post process");
return rtb_post(fd, u->proto, ti);
}
struct uart_t uart[] = {
{ "any", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, NULL},
/* Realtek Bluetooth H4 */
{ "rtk_h4", 0x0000, 0x0000, HCI_UART_H4, 115200, 115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post },
/* Realtek Bluetooth H5 */
{ "rtk_h5", 0x0000, 0x0000, HCI_UART_3WIRE, 115200,115200, 0, DISABLE_PM, NULL, realtek_init, realtek_post },
{ NULL, 0 }
};
static struct uart_t * get_by_id(int m_id, int p_id)
{
int i;
for (i = 0; uart[i].type; i++) {
if (uart[i].m_id == m_id && uart[i].p_id == p_id)
return &uart[i];
}
return NULL;
}
static struct uart_t * get_by_type(char *type)
{
int i;
for (i = 0; uart[i].type; i++) {
if (!strcmp(uart[i].type, type))
return &uart[i];
}
return NULL;
}
/* Initialize UART driver */
static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
{
struct termios ti;
int fd, i;
unsigned long flags = 0;
if (raw)
flags |= 1 << HCI_UART_RAW_DEVICE;
fd = open(dev, O_RDWR | O_NOCTTY);
if (fd < 0) {
RS_ERR("Can't open serial port, %d, %s", errno,
strerror(errno));
return -1;
}
tcflush(fd, TCIOFLUSH);
if (tcgetattr(fd, &ti) < 0) {
RS_ERR("Can't get port settings, %d, %s", errno,
strerror(errno));
return -1;
}
cfmakeraw(&ti);
ti.c_cflag |= CLOCAL;
if (u->flags & FLOW_CTL)
ti.c_cflag |= CRTSCTS;
else
ti.c_cflag &= ~CRTSCTS;
if (tcsetattr(fd, TCSANOW, &ti) < 0) {
RS_ERR("Can't set port settings, %d, %s", errno,
strerror(errno));
return -1;
}
/* Set initial baudrate */
if (set_speed(fd, &ti, u->init_speed) < 0) {
RS_ERR("Can't set initial baud rate, %d, %s", errno,
strerror(errno));
return -1;
}
tcflush(fd, TCIOFLUSH);
if (send_break) {
tcsendbreak(fd, 0);
usleep(500000);
}
if (u->init && u->init(fd, u, &ti) < 0)
return -1;
tcflush(fd, TCIOFLUSH);
/* Set actual baudrate
* There is no need to change baudrate after uart init
* */
/* if (set_speed(fd, &ti, u->speed) < 0) {
* perror("Can't set baud rate");
* return -1;
* }
*/
/* Set TTY to N_HCI line discipline */
i = N_HCI;
if (ioctl(fd, TIOCSETD, &i) < 0) {
RS_ERR("Can't set line discipline %d, %s", errno,
strerror(errno));
return -1;
}
if (flags && ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
RS_ERR("Can't set UART flags %d, %s", errno, strerror(errno));
return -1;
}
if (ioctl(fd, HCIUARTSETPROTO, u->proto) < 0) {
RS_ERR("Can't set device %d, %s", errno, strerror(errno));
return -1;
}
if (u->post && u->post(fd, u, &ti) < 0)
return -1;
return fd;
}
static int reset_bluetooth(void)
{
int fd;
char state[2];
int result;
/* power off and power on BT */
fd = open(RFKILL_NODE, O_RDWR);
if (fd < 0) {
RS_ERR("Cannot open %s, %d %s", RFKILL_NODE, errno,
strerror(errno));
return -1;
}
state[0] = '0';
state[1] = '\0';
result = write(fd, state, strlen(state) + 1);
if (result != (strlen(state) + 1)) {
RS_ERR("Cannot write 0 to rfkill state %d %s", errno,
strerror(errno));
close(fd);
return -1;
}
usleep(500000);
state[0] = '1';
state[1] = '\0';
result = write(fd, state, strlen(state) + 1);
if (result != (strlen(state) + 1)) {
RS_ERR("Cannot write 1 to rfkill state %d %s", errno,
strerror(errno));
close(fd);
return -1;
}
usleep(500000);
close(fd);
return 0;
}
static void usage(void)
{
RS_INFO("hciattach - HCI UART driver initialization utility");
RS_INFO("Usage:");
RS_INFO("\thciattach [-n] [-p] [-b] [-r] [-t timeout] [-s initial_speed] <tty> <type | id> [speed] [flow|noflow] [bdaddr]");
RS_INFO("\thciattach -l");
}
int main(int argc, char *argv[])
{
struct uart_t *u = NULL;
int detach, printpid, raw, opt, i, n, ld, err;
int to = 10;
int init_speed = 0;
int send_break = 0;
pid_t pid;
struct sigaction sa;
struct pollfd p;
sigset_t sigs;
char dev[PATH_MAX];
#ifdef SCHED_ENABLE
struct sched_param sched_par;
#endif
detach = 1;
printpid = 0;
raw = 0;
while ((opt=getopt(argc, argv, "bnpt:s:lr")) != EOF) {
switch(opt) {
case 'b':
send_break = 1;
break;
case 'n':
detach = 0;
break;
case 'p':
printpid = 1;
break;
case 't':
to = atoi(optarg);
break;
case 's':
init_speed = atoi(optarg);
break;
case 'l':
for (i = 0; uart[i].type; i++) {
RS_INFO("%-10s0x%04x,0x%04x", uart[i].type,
uart[i].m_id, uart[i].p_id);
}
exit(0);
case 'r':
raw = 1;
break;
default:
usage();
exit(1);
}
}
n = argc - optind;
if (n < 2) {
usage();
exit(1);
}
for (n = 0; optind < argc; n++, optind++) {
char *opt;
opt = argv[optind];
switch(n) {
case 0:
dev[0] = 0;
if (!strchr(opt, '/'))
strcpy(dev, "/dev/");
strcat(dev, opt);
break;
case 1:
if (strchr(argv[optind], ',')) {
int m_id, p_id;
sscanf(argv[optind], "%x,%x", &m_id, &p_id);
u = get_by_id(m_id, p_id);
} else {
u = get_by_type(opt);
}
if (!u) {
RS_ERR("Unknown device type or id");
exit(1);
}
break;
case 2:
u->speed = atoi(argv[optind]);
break;
case 3:
if (!strcmp("flow", argv[optind]))
u->flags |= FLOW_CTL;
else
u->flags &= ~FLOW_CTL;
break;
case 4:
if (!strcmp("sleep", argv[optind]))
u->pm = ENABLE_PM;
else
u->pm = DISABLE_PM;
break;
case 5:
u->bdaddr = argv[optind];
break;
}
}
if (!u) {
RS_ERR("Unknown device type or id");
exit(1);
}
start:
#ifdef SCHED_ENABLE
RS_INFO("Increase the priority of the process with set sched");
memset(&sched_par, 0, sizeof(sched_par));
sched_par.sched_priority = 99;
err = sched_setscheduler(0, SCHED_FIFO, &sched_par);
if (err == -1) {
RS_ERR("Call sched_setscheduler error, %s",
strerror(errno));
}
/* #else
* RS_INFO("Increase the priority of the process with nice");
* err = nice(-20);
* if (err == -1) {
* RS_ERR("Call nice error, %s", strerror(errno));
* }
*/
#endif
/* If user specified a initial speed, use that instead of
the hardware's default */
if (init_speed)
u->init_speed = init_speed;
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = sig_alarm;
sigaction(SIGALRM, &sa, NULL);
/* 10 seconds should be enough for initialization */
alarm(to);
n = init_uart(dev, u, send_break, raw);
if (n < 0) {
RS_ERR("Can't initialize device %d, %s", errno,
strerror(errno));
exit(1);
}
RS_INFO("Device setup complete");
alarm(0);
memset(&sa, 0, sizeof(sa));
sa.sa_flags = SA_NOCLDSTOP;
sa.sa_handler = SIG_IGN;
sigaction(SIGCHLD, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = sig_term;
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sa.sa_handler = sig_hup;
sigaction(SIGHUP, &sa, NULL);
if (detach) {
if ((pid = fork())) {
if (printpid)
RS_INFO("%d", pid);
return 0;
}
for (i = 0; i < 20; i++)
if (i != n)
close(i);
}
p.fd = n;
p.events = POLLERR | POLLHUP;
sigfillset(&sigs);
sigdelset(&sigs, SIGCHLD);
sigdelset(&sigs, SIGPIPE);
sigdelset(&sigs, SIGTERM);
sigdelset(&sigs, SIGINT);
sigdelset(&sigs, SIGHUP);
while (!__io_canceled) {
p.revents = 0;
err = ppoll(&p, 1, NULL, &sigs);
if (err < 0 && errno == EINTR) {
RS_INFO("Got EINTR.");
continue;
} if (err)
break;
}
RS_INFO("err %d, p->revents %04x", err, p.revents);
/* Restore TTY line discipline */
RS_INFO("Restore TTY line discipline");
ld = N_TTY;
if (ioctl(n, TIOCSETD, &ld) < 0) {
RS_ERR("Can't restore line discipline %d, %s", errno,
strerror(errno));
exit(1);
}
if (p.revents & (POLLERR | POLLHUP)) {
RS_INFO("Recover...");
reset_bluetooth();
goto start;
}
return 0;
}
void util_hexdump(const uint8_t *buf, size_t len)
{
static const char hexdigits[] = "0123456789abcdef";
char str[16 * 3];
size_t i;
if (!buf || !len)
return;
for (i = 0; i < len; i++) {
str[((i % 16) * 3)] = hexdigits[buf[i] >> 4];
str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf];
str[((i % 16) * 3) + 2] = ' ';
if ((i + 1) % 16 == 0) {
str[16 * 3 - 1] = '\0';
RS_INFO("%s", str);
}
}
if (i % 16 > 0) {
str[(i % 16) * 3 - 1] = '\0';
RS_INFO("%s", str);
}
}
int timeout_set(int fd, unsigned int msec)
{
struct itimerspec itimer;
unsigned int sec = msec / 1000;
memset(&itimer, 0, sizeof(itimer));
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_nsec = 0;
itimer.it_value.tv_sec = sec;
itimer.it_value.tv_nsec = (msec - (sec * 1000)) * 1000 * 1000;
return timerfd_settime(fd, 0, &itimer, NULL);
}

View File

@@ -0,0 +1,188 @@
/*
*
* BlueZ - Bluetooth protocol stack for Linux
*
* Copyright (C) 2003-2009 Marcel Holtmann <marcel@holtmann.org>
*
*
* 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
*
*/
#include <termios.h>
#include <stdint.h>
#include <syslog.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define cpu_to_le16(d) (d)
#define cpu_to_le32(d) (d)
#define le16_to_cpu(d) (d)
#define le32_to_cpu(d) (d)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le16(d) bswap_16(d)
#define cpu_to_le32(d) bswap_32(d)
#define le16_to_cpu(d) bswap_16(d)
#define le32_to_cpu(d) bswap_32(d)
#else
#error "Unknown byte order"
#endif
#ifndef N_HCI
#define N_HCI 15
#endif
#define HCIUARTSETPROTO _IOW('U', 200, int)
#define HCIUARTGETPROTO _IOR('U', 201, int)
#define HCIUARTGETDEVICE _IOR('U', 202, int)
#define HCIUARTSETFLAGS _IOW('U', 203, int)
#define HCIUARTGETFLAGS _IOR('U', 204, int)
#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
#define HCI_UART_RAW_DEVICE 0
extern uint8_t DBG_ON;
/* #define SYSLOG */
#define LOG_STR "Realtek Bluetooth"
#ifdef SYSLOG
#define RS_DBG(fmt, arg...) \
do{ \
if (DBG_ON) \
syslog(LOG_DEBUG, "%s :" fmt "\n" , LOG_STR, ##arg); \
}while(0)
#define RS_INFO(fmt, arg...) \
do{ \
syslog(LOG_INFO, "%s :" fmt "\n", LOG_STR, ##arg); \
}while(0)
#define RS_WARN(fmt, arg...) \
do{ \
syslog(LOG_WARNING, "%s WARN: " fmt "\n", LOG_STR, ##arg); \
}while(0)
#define RS_ERR(fmt, arg...) \
do{ \
syslog(LOG_ERR, "%s ERROR: " fmt "\n", LOG_STR, ##arg); \
}while(0)
#else
#define RS_DBG(fmt, arg...) \
do{ \
if (DBG_ON) \
printf("%s :" fmt "\n" , LOG_STR, ##arg); \
}while(0)
#define RS_INFO(fmt, arg...) \
do{ \
printf("%s :" fmt "\n", LOG_STR, ##arg); \
}while(0)
#define RS_WARN(fmt, arg...) \
do{ \
printf("%s WARN: " fmt "\n", LOG_STR, ##arg); \
}while(0)
#define RS_ERR(fmt, arg...) \
do{ \
printf("%s ERROR: " fmt "\n", LOG_STR, ##arg); \
}while(0)
#endif
typedef enum _H5_RX_STATE {
H5_W4_PKT_DELIMITER,
H5_W4_PKT_START,
H5_W4_HDR,
H5_W4_DATA,
H5_W4_CRC
} H5_RX_STATE;
typedef enum _H5_RX_ESC_STATE {
H5_ESCSTATE_NOESC,
H5_ESCSTATE_ESC
} H5_RX_ESC_STATE;
typedef enum _H5_LINK_STATE {
H5_SYNC,
H5_CONFIG,
H5_INIT,
H5_PATCH,
H5_HCI_RESET,
H5_ACTIVE
} H5_LINK_STATE;
struct patch_info;
typedef struct rtb_struct {
/* three wire releated */
uint8_t rxseq_txack; /* expected rx seq number */
uint8_t rxack; /* last packet that the peer ack'ed */
uint8_t use_crc;
uint8_t is_txack_req; /* txack required */
uint8_t msgq_txseq; /* next pkt seq */
uint16_t message_crc;
uint32_t rx_count; /* expected pkts to recv */
H5_RX_STATE rx_state;
H5_RX_ESC_STATE rx_esc_state;
H5_LINK_STATE link_estab_state;
struct sk_buff *rx_skb;
uint16_t num_of_cmd_sent;
uint16_t lmp_subver;
uint16_t hci_rev;
uint8_t hci_ver;
uint8_t eversion;
uint8_t chip_type;
uint32_t vendor_baud;
uint8_t dl_fw_flag;
int serial_fd;
int uart_flow_ctrl;
uint32_t parenb: 16;
uint32_t pareven: 16;
int final_speed;
int total_num; /* total pkt number */
int tx_index; /* current sending pkt number */
int rx_index; /* ack index from board */
int fw_len; /* fw patch file len */
int config_len; /* config patch file len */
int total_len; /* fw & config extracted buf len */
uint8_t *fw_buf; /* fw patch file buf */
uint8_t *config_buf; /* config patch file buf */
uint8_t *total_buf; /* fw & config extracted buf */
#define CMD_STATE_UNKNOWN 0x00
#define CMD_STATE_SUCCESS 0x01
struct __cmd_state {
uint16_t opcode;
uint16_t state;
} cmd_state;
struct patch_info *patch_ent;
int proto;
int timerfd;
int epollfd;
} rtb_struct_t;
extern struct rtb_struct rtb_cfg;
int timeout_set(int fd, unsigned int msec);
int set_speed(int fd, struct termios *ti, int speed);
int rtb_init(int fd, int proto, int speed, struct termios *ti);
int rtb_post(int fd, int proto, struct termios *ti);
void util_hexdump(const uint8_t *buf, size_t len);

View File

@@ -0,0 +1,295 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <termios.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdint.h>
#include <string.h>
#include <endian.h>
#include <byteswap.h>
#include <netinet/in.h>
#include <ctype.h>
#include <poll.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include "hciattach.h"
#include "hciattach_h4.h"
extern struct rtb_struct rtb_cfg;
static int start_xfer_wait(int fd, uint8_t *cmd, uint16_t len, uint32_t msec,
int retry, uint8_t *resp, uint16_t *resp_len)
{
uint8_t buf[64];
int result;
int state = 1;
int count = 0;
int params_len;
struct pollfd p[2];
uint16_t opcode;
if (fd == -1 || !cmd || len < 4) {
RS_ERR("%s: invalid parameter", __func__);
return -1;
}
opcode = ((uint16_t)cmd[2] << 8) + cmd[1];
start_xfer:
result = write(fd, cmd, len);
if (result != len) {
RS_ERR("%s: Write cmd %04x error, %s", __func__, opcode,
strerror(errno));
return -1;
}
start_recv:
memset(buf, 0, sizeof(buf));
memset(p, 0, sizeof(p));
state = 1;
count = 0;
p[0].fd = fd;
p[0].events = POLLERR | POLLHUP | POLLIN;
for (;;) {
p[0].revents = 0;
result = poll(p, 1, msec);
if (result < 0) {
RS_ERR("Poll call error, %s", strerror(errno));
result = -1;
break;
}
if (result == 0) {
RS_WARN("%s: Timeout", __func__);
if (retry <= 0) {
RS_ERR("%s: Transfer exhausted", __func__);
tcflush(fd, TCIOFLUSH);
exit(EXIT_FAILURE);
}
retry--;
goto start_xfer;
}
if (p[0].revents & (POLLERR | POLLHUP)) {
RS_ERR("POLLERR or POLLUP happens, %s",
strerror(errno));
result = -1;
break;
}
if (state == 1) {
result = read(p[0].fd, buf, 1);
if (result == -1 || result != 1) {
RS_ERR("%s: Read pkt type error, %s", __func__,
strerror(errno));
result = -1;
break;
}
if (result == 1 && buf[0] == 0x04) {
count = 1;
state = 2;
}
} else if (state == 2) {
result = read(p[0].fd, buf + count, 2);
if (result == -1 || result != 2) {
RS_ERR("%s: Read pkt header error, %s",
__func__, strerror(errno));
break;
}
count += result;
state = 3;
params_len = buf[2];
if (params_len + 3 > sizeof(buf)) {
result = -1;
RS_ERR("%s: hci event too long", __func__);
break;
}
} else if (state == 3) {
result = read(p[0].fd, buf + count, params_len);
if (result == -1) {
RS_ERR("%s: Read pkt payload error, %s",
__func__, strerror(errno));
break;
}
count += result;
params_len -= result;
if (!params_len)
break;
}
}
if (result >= 0) {
if (buf[1] == 0x0e) {
uint16_t tmp_opcode;
tmp_opcode = (uint16_t)buf[4] | buf[5] << 8;
if (tmp_opcode == opcode) {
RS_INFO("Cmd complete event for cmd %04x",
opcode);
/* Status is not zero indicating command not
* succeeded */
if (buf[6])
return -1;
if (!resp)
return 0;
if (*resp_len > count)
*resp_len = count;
memcpy(resp, buf, *resp_len);
return 0;
} else {
RS_WARN("Unexpected cmd complete event, %04x",
tmp_opcode);
return -1;
}
} else {
RS_INFO("%s: Unexpected hci event packet", __func__);
util_hexdump(buf, count);
/* Continue receiving */
}
goto start_recv;
}
return result;
}
int h4_download_patch(int fd, int index, uint8_t *data, int len)
{
uint8_t buf[257];
uint16_t total_len;
int result;
uint8_t resp[8];
uint16_t rlen = sizeof(resp);
RS_DBG("fd: %d, index: %d, len: %d", fd, index, len);
if (data)
memcpy(&buf[5], data, len);
buf[0] = 0x01;
buf[1] = 0x20;
buf[2] = 0xfc;
buf[3] = len + 1;
buf[4] = (uint8_t)index;
total_len = len + 5;
result = start_xfer_wait(fd, buf, total_len, 1000, 0, resp, &rlen);
if (result < 0) {
RS_ERR("Transfer patch failed, index %d", index);
return -1;
}
if (rlen != 8) {
RS_ERR("%s: Unexpected length %u", __func__, rlen);
return -1;
}
return resp[7];
}
int h4_vendor_change_speed(int fd, uint32_t baudrate)
{
int res;
uint8_t cmd[8] = { 0 };
cmd[0] = 1;
cmd[1] = 0x17;
cmd[2] = 0xfc;
cmd[3] = 4;
baudrate = cpu_to_le32(baudrate);
#ifdef BAUDRATE_4BYTES
memcpy((uint16_t *) & cmd[4], &baudrate, 4);
#else
memcpy((uint16_t *) & cmd[4], &baudrate, 2);
cmd[6] = 0;
cmd[7] = 0;
#endif
/* TODO: Wait for a while for device to up, just h4 need it */
sleep(1);
RS_DBG("baudrate in change speed command: 0x%02x 0x%02x 0x%02x 0x%02x",
cmd[4], cmd[5], cmd[6], cmd[7]);
res = start_xfer_wait(fd, cmd, 8, 1000, 0, NULL, 0);
if (res < 0)
RS_ERR("Change Controller baud failed");
return res;
}
int h4_hci_reset(int fd)
{
int result;
uint8_t cmd[4] = { 0x01, 0x03, 0x0c, 0x00};
RS_INFO("%s: Issue hci reset cmd", __func__);
result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0, NULL, 0);
if (result < 0) {
RS_ERR("%s: Failed to send reset cmd", __func__);
return -1;
}
return 0;
}
int h4_read_local_ver(int fd)
{
uint8_t cmd[4] = { 0x01, 0x01, 0x10, 0x00 };
uint8_t resp[16];
uint16_t len = sizeof(resp);
int result;
result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0,
resp, &len);
if (result < 0) {
RS_ERR("HCI Read local version info error");
return -1;
}
if (len != 15) {
RS_ERR("%s: Unexpected length %u", __func__, len);
return -1;
}
rtb_cfg.hci_ver = resp[7];
rtb_cfg.hci_rev = (uint32_t)resp[9] << 8 | resp[8];
rtb_cfg.lmp_subver = (uint32_t)resp[14] << 8 | resp[13];
RS_INFO("hci ver %02x, hci_rev %04x, lmp_subver %04x",
rtb_cfg.hci_ver, rtb_cfg.hci_rev, rtb_cfg.lmp_subver);
return 0;
}
int h4_vendor_read_rom_ver(int fd)
{
uint8_t cmd[4] = { 0x01, 0x6d, 0xfc, 0x00 };
uint8_t resp[16];
uint16_t len = sizeof(resp);
int result;
result = start_xfer_wait(fd, cmd, sizeof(cmd), 1000, 0,
resp, &len);
if (result < 0) {
RS_ERR("HCI Read local version info error");
return -1;
}
if (len != 8) {
RS_ERR("%s: Unexpected length %u", __func__, len);
return -1;
}
rtb_cfg.eversion = resp[7];
RS_INFO("eversion %02x", rtb_cfg.eversion);
return 0;
}

View File

@@ -0,0 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
#include <stdint.h>
int h4_download_patch(int fd, int index, uint8_t *data, int len);
int h4_vendor_change_speed(int fd, uint32_t baudrate);
int h4_hci_reset(int fd);
int h4_read_local_ver(int fd);
int h4_vendor_read_rom_ver(int fd);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,75 @@
/*
* Copyright (C) 2018 Realtek Semiconductor Corporation.
*
* 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.
*/
struct rtb_struct;
#define BAUDRATE_4BYTES
#define ROM_LMP_NONE 0x0000
#define ROM_LMP_8723a 0x1200
#define ROM_LMP_8723b 0x8723
#define ROM_LMP_8821a 0x8821
#define ROM_LMP_8761a 0x8761
#define ROM_LMP_8761btc 0x8763
#define ROM_LMP_8703a 0x87b3
#define ROM_LMP_8763a 0x8763
#define ROM_LMP_8703b 0x8703
#define ROM_LMP_8723c 0x87c3 /* ??????? */
#define ROM_LMP_8822b 0x8822
#define ROM_LMP_8822c 0x8822
#define ROM_LMP_8723cs_xx 0x8704
#define ROM_LMP_8723cs_cg 0x8705
#define ROM_LMP_8723cs_vf 0x8706
/* Chip type */
#define CHIP_8703AS 1
#define CHIP_8723CS_CG 3
#define CHIP_8723CS_VF 4
#define CHIP_8723CS_XX 5
#define CHIP_8703BS 7
/* software id */
#define CHIP_UNKNOWN 0x00
#define CHIP_8761AT 0x1F
#define CHIP_8761ATF 0x2F
#define CHIP_8761BTC 0x3F
#define CHIP_8761BH4 0x4F
#define CHIP_8723BS 0x5F
#define CHIP_BEFORE 0x6F
#define CHIP_8822BS 0x70
#define CHIP_8723DS 0x71
#define CHIP_8821CS 0x72
#define CHIP_8822CS 0x73
#define CHIP_8761B 0x74
#define RTL_FW_MATCH_CHIP_TYPE (1 << 0)
#define RTL_FW_MATCH_HCI_VER (1 << 1)
#define RTL_FW_MATCH_HCI_REV (1 << 2)
struct patch_info {
uint32_t match_flags;
uint8_t chip_type;
uint16_t lmp_subver;
uint16_t proj_id;
uint8_t hci_ver;
uint16_t hci_rev;
char *patch_file;
char *config_file;
char *ic_name;
};
struct patch_info *get_patch_entry(struct rtb_struct *btrtl);
uint8_t *rtb_read_config(struct rtb_struct *btrtl, int *cfg_len);
uint8_t *rtb_read_firmware(struct rtb_struct *btrtl, int *fw_len);
uint8_t *rtb_get_final_patch(int fd, int proto, int *rlen);

View File

@@ -0,0 +1,4 @@
/libtinyalsa.so
/tinycap
/tinymix
/tinyplay

View File

@@ -0,0 +1,31 @@
CFLAGS := -c -fPIC $(CFLAGS)
INC = include
OBJECTS = mixer.o pcm.o
LIB = libtinyalsa.so
CC=gcc
all: $(LIB) tinyplay tinycap tinymix
cp tinyplay tinycap tinymix /usr/local/bin
cp libtinyalsa.so /usr/lib/
tinyplay: $(LIB) tinyplay.o
$(CC) tinyplay.o -L. -ltinyalsa -o tinyplay
tinycap: $(LIB) tinycap.o
$(CC) tinycap.o -L. -ltinyalsa -o tinycap
tinymix: $(LIB) tinymix.o
$(CC) tinymix.o -L. -ltinyalsa -o tinymix
tinypcminfo: $(LIB) tinypcminfo.o
$(CC) tinypcminfo.o -L. -ltinyalsa -o tinypcminfo
$(LIB): $(OBJECTS)
$(CC) -shared $(OBJECTS) -o $(LIB)
.c.o:
$(CC) $(CFLAGS) $< -I$(INC)
clean:
-rm -f $(LIB) $(OBJECTS) tinyplay.o tinyplay tinycap.o tinycap \
tinymix.o tinymix tinypcminfo.o tinypcminfo

View File

@@ -0,0 +1,9 @@
tinyalsa: a small library to interface with ALSA in the Linux kernel
The aims are:
- Provide a basic pcm and mixer API
- If it's not absolutely needed, don't add it to the API
- Avoid supporting complex and unnecessary operations that could be
dealt with at a higher level

View File

@@ -0,0 +1,821 @@
/****************************************************************************
****************************************************************************
***
*** This header was automatically generated from a Linux kernel header
*** of the same name, to make information necessary for userspace to
*** call into the kernel available to libc. It contains only constants,
*** structures, and macros generated from the original header, and thus,
*** contains no copyrightable information.
***
****************************************************************************
****************************************************************************/
#ifndef __SOUND_ASOUND_H
#define __SOUND_ASOUND_H
#include <linux/types.h>
#define SNDRV_PROTOCOL_VERSION(major, minor, subminor) (((major)<<16)|((minor)<<8)|(subminor))
#define SNDRV_PROTOCOL_MAJOR(version) (((version)>>16)&0xffff)
#define SNDRV_PROTOCOL_MINOR(version) (((version)>>8)&0xff)
#define SNDRV_PROTOCOL_MICRO(version) ((version)&0xff)
#define SNDRV_PROTOCOL_INCOMPATIBLE(kversion, uversion) (SNDRV_PROTOCOL_MAJOR(kversion) != SNDRV_PROTOCOL_MAJOR(uversion) || (SNDRV_PROTOCOL_MAJOR(kversion) == SNDRV_PROTOCOL_MAJOR(uversion) && SNDRV_PROTOCOL_MINOR(kversion) != SNDRV_PROTOCOL_MINOR(uversion)))
struct snd_aes_iec958 {
unsigned char status[24];
unsigned char subcode[147];
unsigned char pad;
unsigned char dig_subframe[4];
};
#define SNDRV_HWDEP_VERSION SNDRV_PROTOCOL_VERSION(1, 0, 1)
enum {
SNDRV_HWDEP_IFACE_OPL2 = 0,
SNDRV_HWDEP_IFACE_OPL3,
SNDRV_HWDEP_IFACE_OPL4,
SNDRV_HWDEP_IFACE_SB16CSP,
SNDRV_HWDEP_IFACE_EMU10K1,
SNDRV_HWDEP_IFACE_YSS225,
SNDRV_HWDEP_IFACE_ICS2115,
SNDRV_HWDEP_IFACE_SSCAPE,
SNDRV_HWDEP_IFACE_VX,
SNDRV_HWDEP_IFACE_MIXART,
SNDRV_HWDEP_IFACE_USX2Y,
SNDRV_HWDEP_IFACE_EMUX_WAVETABLE,
SNDRV_HWDEP_IFACE_BLUETOOTH,
SNDRV_HWDEP_IFACE_USX2Y_PCM,
SNDRV_HWDEP_IFACE_PCXHR,
SNDRV_HWDEP_IFACE_SB_RC,
SNDRV_HWDEP_IFACE_HDA,
SNDRV_HWDEP_IFACE_USB_STREAM,
SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_USB_STREAM
};
struct snd_hwdep_info {
unsigned int device;
int card;
unsigned char id[64];
unsigned char name[80];
int iface;
unsigned char reserved[64];
};
struct snd_hwdep_dsp_status {
unsigned int version;
unsigned char id[32];
unsigned int num_dsps;
unsigned int dsp_loaded;
unsigned int chip_ready;
unsigned char reserved[16];
};
struct snd_hwdep_dsp_image {
unsigned int index;
unsigned char name[64];
unsigned char __user *image;
size_t length;
unsigned long driver_data;
};
#define SNDRV_HWDEP_IOCTL_PVERSION _IOR ('H', 0x00, int)
#define SNDRV_HWDEP_IOCTL_INFO _IOR ('H', 0x01, struct snd_hwdep_info)
#define SNDRV_HWDEP_IOCTL_DSP_STATUS _IOR('H', 0x02, struct snd_hwdep_dsp_status)
#define SNDRV_HWDEP_IOCTL_DSP_LOAD _IOW('H', 0x03, struct snd_hwdep_dsp_image)
#define SNDRV_PCM_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 10)
typedef unsigned long snd_pcm_uframes_t;
typedef signed long snd_pcm_sframes_t;
enum {
SNDRV_PCM_CLASS_GENERIC = 0,
SNDRV_PCM_CLASS_MULTI,
SNDRV_PCM_CLASS_MODEM,
SNDRV_PCM_CLASS_DIGITIZER,
SNDRV_PCM_CLASS_LAST = SNDRV_PCM_CLASS_DIGITIZER,
};
enum {
SNDRV_PCM_SUBCLASS_GENERIC_MIX = 0,
SNDRV_PCM_SUBCLASS_MULTI_MIX,
SNDRV_PCM_SUBCLASS_LAST = SNDRV_PCM_SUBCLASS_MULTI_MIX,
};
enum {
SNDRV_PCM_STREAM_PLAYBACK = 0,
SNDRV_PCM_STREAM_CAPTURE,
SNDRV_PCM_STREAM_LAST = SNDRV_PCM_STREAM_CAPTURE,
};
typedef int __bitwise snd_pcm_access_t;
#define SNDRV_PCM_ACCESS_MMAP_INTERLEAVED ((__force snd_pcm_access_t) 0)
#define SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED ((__force snd_pcm_access_t) 1)
#define SNDRV_PCM_ACCESS_MMAP_COMPLEX ((__force snd_pcm_access_t) 2)
#define SNDRV_PCM_ACCESS_RW_INTERLEAVED ((__force snd_pcm_access_t) 3)
#define SNDRV_PCM_ACCESS_RW_NONINTERLEAVED ((__force snd_pcm_access_t) 4)
#define SNDRV_PCM_ACCESS_LAST SNDRV_PCM_ACCESS_RW_NONINTERLEAVED
typedef int __bitwise snd_pcm_format_t;
#define SNDRV_PCM_FORMAT_S8 ((__force snd_pcm_format_t) 0)
#define SNDRV_PCM_FORMAT_U8 ((__force snd_pcm_format_t) 1)
#define SNDRV_PCM_FORMAT_S16_LE ((__force snd_pcm_format_t) 2)
#define SNDRV_PCM_FORMAT_S16_BE ((__force snd_pcm_format_t) 3)
#define SNDRV_PCM_FORMAT_U16_LE ((__force snd_pcm_format_t) 4)
#define SNDRV_PCM_FORMAT_U16_BE ((__force snd_pcm_format_t) 5)
#define SNDRV_PCM_FORMAT_S24_LE ((__force snd_pcm_format_t) 6)
#define SNDRV_PCM_FORMAT_S24_BE ((__force snd_pcm_format_t) 7)
#define SNDRV_PCM_FORMAT_U24_LE ((__force snd_pcm_format_t) 8)
#define SNDRV_PCM_FORMAT_U24_BE ((__force snd_pcm_format_t) 9)
#define SNDRV_PCM_FORMAT_S32_LE ((__force snd_pcm_format_t) 10)
#define SNDRV_PCM_FORMAT_S32_BE ((__force snd_pcm_format_t) 11)
#define SNDRV_PCM_FORMAT_U32_LE ((__force snd_pcm_format_t) 12)
#define SNDRV_PCM_FORMAT_U32_BE ((__force snd_pcm_format_t) 13)
#define SNDRV_PCM_FORMAT_FLOAT_LE ((__force snd_pcm_format_t) 14)
#define SNDRV_PCM_FORMAT_FLOAT_BE ((__force snd_pcm_format_t) 15)
#define SNDRV_PCM_FORMAT_FLOAT64_LE ((__force snd_pcm_format_t) 16)
#define SNDRV_PCM_FORMAT_FLOAT64_BE ((__force snd_pcm_format_t) 17)
#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE ((__force snd_pcm_format_t) 18)
#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE ((__force snd_pcm_format_t) 19)
#define SNDRV_PCM_FORMAT_MU_LAW ((__force snd_pcm_format_t) 20)
#define SNDRV_PCM_FORMAT_A_LAW ((__force snd_pcm_format_t) 21)
#define SNDRV_PCM_FORMAT_IMA_ADPCM ((__force snd_pcm_format_t) 22)
#define SNDRV_PCM_FORMAT_MPEG ((__force snd_pcm_format_t) 23)
#define SNDRV_PCM_FORMAT_GSM ((__force snd_pcm_format_t) 24)
#define SNDRV_PCM_FORMAT_SPECIAL ((__force snd_pcm_format_t) 31)
#define SNDRV_PCM_FORMAT_S24_3LE ((__force snd_pcm_format_t) 32)
#define SNDRV_PCM_FORMAT_S24_3BE ((__force snd_pcm_format_t) 33)
#define SNDRV_PCM_FORMAT_U24_3LE ((__force snd_pcm_format_t) 34)
#define SNDRV_PCM_FORMAT_U24_3BE ((__force snd_pcm_format_t) 35)
#define SNDRV_PCM_FORMAT_S20_3LE ((__force snd_pcm_format_t) 36)
#define SNDRV_PCM_FORMAT_S20_3BE ((__force snd_pcm_format_t) 37)
#define SNDRV_PCM_FORMAT_U20_3LE ((__force snd_pcm_format_t) 38)
#define SNDRV_PCM_FORMAT_U20_3BE ((__force snd_pcm_format_t) 39)
#define SNDRV_PCM_FORMAT_S18_3LE ((__force snd_pcm_format_t) 40)
#define SNDRV_PCM_FORMAT_S18_3BE ((__force snd_pcm_format_t) 41)
#define SNDRV_PCM_FORMAT_U18_3LE ((__force snd_pcm_format_t) 42)
#define SNDRV_PCM_FORMAT_U18_3BE ((__force snd_pcm_format_t) 43)
#define SNDRV_PCM_FORMAT_G723_24 ((__force snd_pcm_format_t) 44)
#define SNDRV_PCM_FORMAT_G723_24_1B ((__force snd_pcm_format_t) 45)
#define SNDRV_PCM_FORMAT_G723_40 ((__force snd_pcm_format_t) 46)
#define SNDRV_PCM_FORMAT_G723_40_1B ((__force snd_pcm_format_t) 47)
#define SNDRV_PCM_FORMAT_LAST SNDRV_PCM_FORMAT_G723_40_1B
#ifdef SNDRV_LITTLE_ENDIAN
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_LE
#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_LE
#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_LE
#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_LE
#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_LE
#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_LE
#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_LE
#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_LE
#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE
#endif
#ifdef SNDRV_BIG_ENDIAN
#define SNDRV_PCM_FORMAT_S16 SNDRV_PCM_FORMAT_S16_BE
#define SNDRV_PCM_FORMAT_U16 SNDRV_PCM_FORMAT_U16_BE
#define SNDRV_PCM_FORMAT_S24 SNDRV_PCM_FORMAT_S24_BE
#define SNDRV_PCM_FORMAT_U24 SNDRV_PCM_FORMAT_U24_BE
#define SNDRV_PCM_FORMAT_S32 SNDRV_PCM_FORMAT_S32_BE
#define SNDRV_PCM_FORMAT_U32 SNDRV_PCM_FORMAT_U32_BE
#define SNDRV_PCM_FORMAT_FLOAT SNDRV_PCM_FORMAT_FLOAT_BE
#define SNDRV_PCM_FORMAT_FLOAT64 SNDRV_PCM_FORMAT_FLOAT64_BE
#define SNDRV_PCM_FORMAT_IEC958_SUBFRAME SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE
#endif
typedef int __bitwise snd_pcm_subformat_t;
#define SNDRV_PCM_SUBFORMAT_STD ((__force snd_pcm_subformat_t) 0)
#define SNDRV_PCM_SUBFORMAT_LAST SNDRV_PCM_SUBFORMAT_STD
#define SNDRV_PCM_INFO_MMAP 0x00000001
#define SNDRV_PCM_INFO_MMAP_VALID 0x00000002
#define SNDRV_PCM_INFO_DOUBLE 0x00000004
#define SNDRV_PCM_INFO_BATCH 0x00000010
#define SNDRV_PCM_INFO_INTERLEAVED 0x00000100
#define SNDRV_PCM_INFO_NONINTERLEAVED 0x00000200
#define SNDRV_PCM_INFO_COMPLEX 0x00000400
#define SNDRV_PCM_INFO_BLOCK_TRANSFER 0x00010000
#define SNDRV_PCM_INFO_OVERRANGE 0x00020000
#define SNDRV_PCM_INFO_RESUME 0x00040000
#define SNDRV_PCM_INFO_PAUSE 0x00080000
#define SNDRV_PCM_INFO_HALF_DUPLEX 0x00100000
#define SNDRV_PCM_INFO_JOINT_DUPLEX 0x00200000
#define SNDRV_PCM_INFO_SYNC_START 0x00400000
#define SNDRV_PCM_INFO_NO_PERIOD_WAKEUP 0x00800000
#define SNDRV_PCM_INFO_FIFO_IN_FRAMES 0x80000000
typedef int __bitwise snd_pcm_state_t;
#define SNDRV_PCM_STATE_OPEN ((__force snd_pcm_state_t) 0)
#define SNDRV_PCM_STATE_SETUP ((__force snd_pcm_state_t) 1)
#define SNDRV_PCM_STATE_PREPARED ((__force snd_pcm_state_t) 2)
#define SNDRV_PCM_STATE_RUNNING ((__force snd_pcm_state_t) 3)
#define SNDRV_PCM_STATE_XRUN ((__force snd_pcm_state_t) 4)
#define SNDRV_PCM_STATE_DRAINING ((__force snd_pcm_state_t) 5)
#define SNDRV_PCM_STATE_PAUSED ((__force snd_pcm_state_t) 6)
#define SNDRV_PCM_STATE_SUSPENDED ((__force snd_pcm_state_t) 7)
#define SNDRV_PCM_STATE_DISCONNECTED ((__force snd_pcm_state_t) 8)
#define SNDRV_PCM_STATE_LAST SNDRV_PCM_STATE_DISCONNECTED
enum {
SNDRV_PCM_MMAP_OFFSET_DATA = 0x00000000,
SNDRV_PCM_MMAP_OFFSET_STATUS = 0x80000000,
SNDRV_PCM_MMAP_OFFSET_CONTROL = 0x81000000,
};
union snd_pcm_sync_id {
unsigned char id[16];
unsigned short id16[8];
unsigned int id32[4];
};
struct snd_pcm_info {
unsigned int device;
unsigned int subdevice;
int stream;
int card;
unsigned char id[64];
unsigned char name[80];
unsigned char subname[32];
int dev_class;
int dev_subclass;
unsigned int subdevices_count;
unsigned int subdevices_avail;
union snd_pcm_sync_id sync;
unsigned char reserved[64];
};
typedef int snd_pcm_hw_param_t;
#define SNDRV_PCM_HW_PARAM_ACCESS 0
#define SNDRV_PCM_HW_PARAM_FORMAT 1
#define SNDRV_PCM_HW_PARAM_SUBFORMAT 2
#define SNDRV_PCM_HW_PARAM_FIRST_MASK SNDRV_PCM_HW_PARAM_ACCESS
#define SNDRV_PCM_HW_PARAM_LAST_MASK SNDRV_PCM_HW_PARAM_SUBFORMAT
#define SNDRV_PCM_HW_PARAM_SAMPLE_BITS 8
#define SNDRV_PCM_HW_PARAM_FRAME_BITS 9
#define SNDRV_PCM_HW_PARAM_CHANNELS 10
#define SNDRV_PCM_HW_PARAM_RATE 11
#define SNDRV_PCM_HW_PARAM_PERIOD_TIME 12
#define SNDRV_PCM_HW_PARAM_PERIOD_SIZE 13
#define SNDRV_PCM_HW_PARAM_PERIOD_BYTES 14
#define SNDRV_PCM_HW_PARAM_PERIODS 15
#define SNDRV_PCM_HW_PARAM_BUFFER_TIME 16
#define SNDRV_PCM_HW_PARAM_BUFFER_SIZE 17
#define SNDRV_PCM_HW_PARAM_BUFFER_BYTES 18
#define SNDRV_PCM_HW_PARAM_TICK_TIME 19
#define SNDRV_PCM_HW_PARAM_FIRST_INTERVAL SNDRV_PCM_HW_PARAM_SAMPLE_BITS
#define SNDRV_PCM_HW_PARAM_LAST_INTERVAL SNDRV_PCM_HW_PARAM_TICK_TIME
#define SNDRV_PCM_HW_PARAMS_NORESAMPLE (1<<0)
#define SNDRV_PCM_HW_PARAMS_EXPORT_BUFFER (1<<1)
#define SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP (1<<2)
struct snd_interval {
unsigned int min, max;
unsigned int openmin:1,
openmax:1,
integer:1,
empty:1;
};
#define SNDRV_MASK_MAX 256
struct snd_mask {
__u32 bits[(SNDRV_MASK_MAX+31)/32];
};
struct snd_pcm_hw_params {
unsigned int flags;
struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK -
SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
struct snd_mask mres[5];
struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
struct snd_interval ires[9];
unsigned int rmask;
unsigned int cmask;
unsigned int info;
unsigned int msbits;
unsigned int rate_num;
unsigned int rate_den;
snd_pcm_uframes_t fifo_size;
unsigned char reserved[64];
};
enum {
SNDRV_PCM_TSTAMP_NONE = 0,
SNDRV_PCM_TSTAMP_ENABLE,
SNDRV_PCM_TSTAMP_LAST = SNDRV_PCM_TSTAMP_ENABLE,
};
struct snd_pcm_sw_params {
int tstamp_mode;
unsigned int period_step;
unsigned int sleep_min;
snd_pcm_uframes_t avail_min;
snd_pcm_uframes_t xfer_align;
snd_pcm_uframes_t start_threshold;
snd_pcm_uframes_t stop_threshold;
snd_pcm_uframes_t silence_threshold;
snd_pcm_uframes_t silence_size;
snd_pcm_uframes_t boundary;
unsigned char reserved[64];
};
struct snd_pcm_channel_info {
unsigned int channel;
__kernel_off_t offset;
unsigned int first;
unsigned int step;
};
struct snd_pcm_status {
snd_pcm_state_t state;
struct timespec trigger_tstamp;
struct timespec tstamp;
snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t hw_ptr;
snd_pcm_sframes_t delay;
snd_pcm_uframes_t avail;
snd_pcm_uframes_t avail_max;
snd_pcm_uframes_t overrange;
snd_pcm_state_t suspended_state;
unsigned char reserved[60];
};
struct snd_pcm_mmap_status {
snd_pcm_state_t state;
int pad1;
snd_pcm_uframes_t hw_ptr;
struct timespec tstamp;
snd_pcm_state_t suspended_state;
};
struct snd_pcm_mmap_control {
snd_pcm_uframes_t appl_ptr;
snd_pcm_uframes_t avail_min;
};
#define SNDRV_PCM_SYNC_PTR_HWSYNC (1<<0)
#define SNDRV_PCM_SYNC_PTR_APPL (1<<1)
#define SNDRV_PCM_SYNC_PTR_AVAIL_MIN (1<<2)
struct snd_pcm_sync_ptr {
unsigned int flags;
union {
struct snd_pcm_mmap_status status;
unsigned char reserved[64];
} s;
union {
struct snd_pcm_mmap_control control;
unsigned char reserved[64];
} c;
};
struct snd_xferi {
snd_pcm_sframes_t result;
void __user *buf;
snd_pcm_uframes_t frames;
};
struct snd_xfern {
snd_pcm_sframes_t result;
void __user * __user *bufs;
snd_pcm_uframes_t frames;
};
enum {
SNDRV_PCM_TSTAMP_TYPE_GETTIMEOFDAY = 0,
SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
SNDRV_PCM_TSTAMP_TYPE_LAST = SNDRV_PCM_TSTAMP_TYPE_MONOTONIC,
};
#define SNDRV_PCM_IOCTL_PVERSION _IOR('A', 0x00, int)
#define SNDRV_PCM_IOCTL_INFO _IOR('A', 0x01, struct snd_pcm_info)
#define SNDRV_PCM_IOCTL_TSTAMP _IOW('A', 0x02, int)
#define SNDRV_PCM_IOCTL_TTSTAMP _IOW('A', 0x03, int)
#define SNDRV_PCM_IOCTL_HW_REFINE _IOWR('A', 0x10, struct snd_pcm_hw_params)
#define SNDRV_PCM_IOCTL_HW_PARAMS _IOWR('A', 0x11, struct snd_pcm_hw_params)
#define SNDRV_PCM_IOCTL_HW_FREE _IO('A', 0x12)
#define SNDRV_PCM_IOCTL_SW_PARAMS _IOWR('A', 0x13, struct snd_pcm_sw_params)
#define SNDRV_PCM_IOCTL_STATUS _IOR('A', 0x20, struct snd_pcm_status)
#define SNDRV_PCM_IOCTL_DELAY _IOR('A', 0x21, snd_pcm_sframes_t)
#define SNDRV_PCM_IOCTL_HWSYNC _IO('A', 0x22)
#define SNDRV_PCM_IOCTL_SYNC_PTR _IOWR('A', 0x23, struct snd_pcm_sync_ptr)
#define SNDRV_PCM_IOCTL_CHANNEL_INFO _IOR('A', 0x32, struct snd_pcm_channel_info)
#define SNDRV_PCM_IOCTL_PREPARE _IO('A', 0x40)
#define SNDRV_PCM_IOCTL_RESET _IO('A', 0x41)
#define SNDRV_PCM_IOCTL_START _IO('A', 0x42)
#define SNDRV_PCM_IOCTL_DROP _IO('A', 0x43)
#define SNDRV_PCM_IOCTL_DRAIN _IO('A', 0x44)
#define SNDRV_PCM_IOCTL_PAUSE _IOW('A', 0x45, int)
#define SNDRV_PCM_IOCTL_REWIND _IOW('A', 0x46, snd_pcm_uframes_t)
#define SNDRV_PCM_IOCTL_RESUME _IO('A', 0x47)
#define SNDRV_PCM_IOCTL_XRUN _IO('A', 0x48)
#define SNDRV_PCM_IOCTL_FORWARD _IOW('A', 0x49, snd_pcm_uframes_t)
#define SNDRV_PCM_IOCTL_WRITEI_FRAMES _IOW('A', 0x50, struct snd_xferi)
#define SNDRV_PCM_IOCTL_READI_FRAMES _IOR('A', 0x51, struct snd_xferi)
#define SNDRV_PCM_IOCTL_WRITEN_FRAMES _IOW('A', 0x52, struct snd_xfern)
#define SNDRV_PCM_IOCTL_READN_FRAMES _IOR('A', 0x53, struct snd_xfern)
#define SNDRV_PCM_IOCTL_LINK _IOW('A', 0x60, int)
#define SNDRV_PCM_IOCTL_UNLINK _IO('A', 0x61)
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 0)
enum {
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
SNDRV_RAWMIDI_STREAM_INPUT,
SNDRV_RAWMIDI_STREAM_LAST = SNDRV_RAWMIDI_STREAM_INPUT,
};
#define SNDRV_RAWMIDI_INFO_OUTPUT 0x00000001
#define SNDRV_RAWMIDI_INFO_INPUT 0x00000002
#define SNDRV_RAWMIDI_INFO_DUPLEX 0x00000004
struct snd_rawmidi_info {
unsigned int device;
unsigned int subdevice;
int stream;
int card;
unsigned int flags;
unsigned char id[64];
unsigned char name[80];
unsigned char subname[32];
unsigned int subdevices_count;
unsigned int subdevices_avail;
unsigned char reserved[64];
};
struct snd_rawmidi_params {
int stream;
size_t buffer_size;
size_t avail_min;
unsigned int no_active_sensing: 1;
unsigned char reserved[16];
};
struct snd_rawmidi_status {
int stream;
struct timespec tstamp;
size_t avail;
size_t xruns;
unsigned char reserved[16];
};
#define SNDRV_RAWMIDI_IOCTL_PVERSION _IOR('W', 0x00, int)
#define SNDRV_RAWMIDI_IOCTL_INFO _IOR('W', 0x01, struct snd_rawmidi_info)
#define SNDRV_RAWMIDI_IOCTL_PARAMS _IOWR('W', 0x10, struct snd_rawmidi_params)
#define SNDRV_RAWMIDI_IOCTL_STATUS _IOWR('W', 0x20, struct snd_rawmidi_status)
#define SNDRV_RAWMIDI_IOCTL_DROP _IOW('W', 0x30, int)
#define SNDRV_RAWMIDI_IOCTL_DRAIN _IOW('W', 0x31, int)
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
enum {
SNDRV_TIMER_CLASS_NONE = -1,
SNDRV_TIMER_CLASS_SLAVE = 0,
SNDRV_TIMER_CLASS_GLOBAL,
SNDRV_TIMER_CLASS_CARD,
SNDRV_TIMER_CLASS_PCM,
SNDRV_TIMER_CLASS_LAST = SNDRV_TIMER_CLASS_PCM,
};
enum {
SNDRV_TIMER_SCLASS_NONE = 0,
SNDRV_TIMER_SCLASS_APPLICATION,
SNDRV_TIMER_SCLASS_SEQUENCER,
SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
SNDRV_TIMER_SCLASS_LAST = SNDRV_TIMER_SCLASS_OSS_SEQUENCER,
};
#define SNDRV_TIMER_GLOBAL_SYSTEM 0
#define SNDRV_TIMER_GLOBAL_RTC 1
#define SNDRV_TIMER_GLOBAL_HPET 2
#define SNDRV_TIMER_GLOBAL_HRTIMER 3
#define SNDRV_TIMER_FLG_SLAVE (1<<0)
struct snd_timer_id {
int dev_class;
int dev_sclass;
int card;
int device;
int subdevice;
};
struct snd_timer_ginfo {
struct snd_timer_id tid;
unsigned int flags;
int card;
unsigned char id[64];
unsigned char name[80];
unsigned long reserved0;
unsigned long resolution;
unsigned long resolution_min;
unsigned long resolution_max;
unsigned int clients;
unsigned char reserved[32];
};
struct snd_timer_gparams {
struct snd_timer_id tid;
unsigned long period_num;
unsigned long period_den;
unsigned char reserved[32];
};
struct snd_timer_gstatus {
struct snd_timer_id tid;
unsigned long resolution;
unsigned long resolution_num;
unsigned long resolution_den;
unsigned char reserved[32];
};
struct snd_timer_select {
struct snd_timer_id id;
unsigned char reserved[32];
};
struct snd_timer_info {
unsigned int flags;
int card;
unsigned char id[64];
unsigned char name[80];
unsigned long reserved0;
unsigned long resolution;
unsigned char reserved[64];
};
#define SNDRV_TIMER_PSFLG_AUTO (1<<0)
#define SNDRV_TIMER_PSFLG_EXCLUSIVE (1<<1)
#define SNDRV_TIMER_PSFLG_EARLY_EVENT (1<<2)
struct snd_timer_params {
unsigned int flags;
unsigned int ticks;
unsigned int queue_size;
unsigned int reserved0;
unsigned int filter;
unsigned char reserved[60];
};
struct snd_timer_status {
struct timespec tstamp;
unsigned int resolution;
unsigned int lost;
unsigned int overrun;
unsigned int queue;
unsigned char reserved[64];
};
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
#define SNDRV_TIMER_IOCTL_TREAD _IOW('T', 0x02, int)
#define SNDRV_TIMER_IOCTL_GINFO _IOWR('T', 0x03, struct snd_timer_ginfo)
#define SNDRV_TIMER_IOCTL_GPARAMS _IOW('T', 0x04, struct snd_timer_gparams)
#define SNDRV_TIMER_IOCTL_GSTATUS _IOWR('T', 0x05, struct snd_timer_gstatus)
#define SNDRV_TIMER_IOCTL_SELECT _IOW('T', 0x10, struct snd_timer_select)
#define SNDRV_TIMER_IOCTL_INFO _IOR('T', 0x11, struct snd_timer_info)
#define SNDRV_TIMER_IOCTL_PARAMS _IOW('T', 0x12, struct snd_timer_params)
#define SNDRV_TIMER_IOCTL_STATUS _IOR('T', 0x14, struct snd_timer_status)
#define SNDRV_TIMER_IOCTL_START _IO('T', 0xa0)
#define SNDRV_TIMER_IOCTL_STOP _IO('T', 0xa1)
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
struct snd_timer_read {
unsigned int resolution;
unsigned int ticks;
};
enum {
SNDRV_TIMER_EVENT_RESOLUTION = 0,
SNDRV_TIMER_EVENT_TICK,
SNDRV_TIMER_EVENT_START,
SNDRV_TIMER_EVENT_STOP,
SNDRV_TIMER_EVENT_CONTINUE,
SNDRV_TIMER_EVENT_PAUSE,
SNDRV_TIMER_EVENT_EARLY,
SNDRV_TIMER_EVENT_SUSPEND,
SNDRV_TIMER_EVENT_RESUME,
SNDRV_TIMER_EVENT_MSTART = SNDRV_TIMER_EVENT_START + 10,
SNDRV_TIMER_EVENT_MSTOP = SNDRV_TIMER_EVENT_STOP + 10,
SNDRV_TIMER_EVENT_MCONTINUE = SNDRV_TIMER_EVENT_CONTINUE + 10,
SNDRV_TIMER_EVENT_MPAUSE = SNDRV_TIMER_EVENT_PAUSE + 10,
SNDRV_TIMER_EVENT_MSUSPEND = SNDRV_TIMER_EVENT_SUSPEND + 10,
SNDRV_TIMER_EVENT_MRESUME = SNDRV_TIMER_EVENT_RESUME + 10,
};
struct snd_timer_tread {
int event;
struct timespec tstamp;
unsigned int val;
};
#define SNDRV_CTL_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
struct snd_ctl_card_info {
int card;
int pad;
unsigned char id[16];
unsigned char driver[16];
unsigned char name[32];
unsigned char longname[80];
unsigned char reserved_[16];
unsigned char mixername[80];
unsigned char components[128];
};
typedef int __bitwise snd_ctl_elem_type_t;
#define SNDRV_CTL_ELEM_TYPE_NONE ((__force snd_ctl_elem_type_t) 0)
#define SNDRV_CTL_ELEM_TYPE_BOOLEAN ((__force snd_ctl_elem_type_t) 1)
#define SNDRV_CTL_ELEM_TYPE_INTEGER ((__force snd_ctl_elem_type_t) 2)
#define SNDRV_CTL_ELEM_TYPE_ENUMERATED ((__force snd_ctl_elem_type_t) 3)
#define SNDRV_CTL_ELEM_TYPE_BYTES ((__force snd_ctl_elem_type_t) 4)
#define SNDRV_CTL_ELEM_TYPE_IEC958 ((__force snd_ctl_elem_type_t) 5)
#define SNDRV_CTL_ELEM_TYPE_INTEGER64 ((__force snd_ctl_elem_type_t) 6)
#define SNDRV_CTL_ELEM_TYPE_LAST SNDRV_CTL_ELEM_TYPE_INTEGER64
typedef int __bitwise snd_ctl_elem_iface_t;
#define SNDRV_CTL_ELEM_IFACE_CARD ((__force snd_ctl_elem_iface_t) 0)
#define SNDRV_CTL_ELEM_IFACE_HWDEP ((__force snd_ctl_elem_iface_t) 1)
#define SNDRV_CTL_ELEM_IFACE_MIXER ((__force snd_ctl_elem_iface_t) 2)
#define SNDRV_CTL_ELEM_IFACE_PCM ((__force snd_ctl_elem_iface_t) 3)
#define SNDRV_CTL_ELEM_IFACE_RAWMIDI ((__force snd_ctl_elem_iface_t) 4)
#define SNDRV_CTL_ELEM_IFACE_TIMER ((__force snd_ctl_elem_iface_t) 5)
#define SNDRV_CTL_ELEM_IFACE_SEQUENCER ((__force snd_ctl_elem_iface_t) 6)
#define SNDRV_CTL_ELEM_IFACE_LAST SNDRV_CTL_ELEM_IFACE_SEQUENCER
#define SNDRV_CTL_ELEM_ACCESS_READ (1<<0)
#define SNDRV_CTL_ELEM_ACCESS_WRITE (1<<1)
#define SNDRV_CTL_ELEM_ACCESS_READWRITE (SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE)
#define SNDRV_CTL_ELEM_ACCESS_VOLATILE (1<<2)
#define SNDRV_CTL_ELEM_ACCESS_TIMESTAMP (1<<3)
#define SNDRV_CTL_ELEM_ACCESS_TLV_READ (1<<4)
#define SNDRV_CTL_ELEM_ACCESS_TLV_WRITE (1<<5)
#define SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE (SNDRV_CTL_ELEM_ACCESS_TLV_READ|SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
#define SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND (1<<6)
#define SNDRV_CTL_ELEM_ACCESS_INACTIVE (1<<8)
#define SNDRV_CTL_ELEM_ACCESS_LOCK (1<<9)
#define SNDRV_CTL_ELEM_ACCESS_OWNER (1<<10)
#define SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK (1<<28)
#define SNDRV_CTL_ELEM_ACCESS_USER (1<<29)
#define SNDRV_CTL_POWER_D0 0x0000
#define SNDRV_CTL_POWER_D1 0x0100
#define SNDRV_CTL_POWER_D2 0x0200
#define SNDRV_CTL_POWER_D3 0x0300
#define SNDRV_CTL_POWER_D3hot (SNDRV_CTL_POWER_D3|0x0000)
#define SNDRV_CTL_POWER_D3cold (SNDRV_CTL_POWER_D3|0x0001)
struct snd_ctl_elem_id {
unsigned int numid;
snd_ctl_elem_iface_t iface;
unsigned int device;
unsigned int subdevice;
unsigned char name[44];
unsigned int index;
};
struct snd_ctl_elem_list {
unsigned int offset;
unsigned int space;
unsigned int used;
unsigned int count;
struct snd_ctl_elem_id __user *pids;
unsigned char reserved[50];
};
struct snd_ctl_elem_info {
struct snd_ctl_elem_id id;
snd_ctl_elem_type_t type;
unsigned int access;
unsigned int count;
__kernel_pid_t owner;
union {
struct {
long min;
long max;
long step;
} integer;
struct {
long long min;
long long max;
long long step;
} integer64;
struct {
unsigned int items;
unsigned int item;
char name[64];
} enumerated;
unsigned char reserved[128];
} value;
union {
unsigned short d[4];
unsigned short *d_ptr;
} dimen;
unsigned char reserved[64-4*sizeof(unsigned short)];
};
struct snd_ctl_elem_value {
struct snd_ctl_elem_id id;
unsigned int indirect: 1;
union {
union {
long value[128];
long *value_ptr;
} integer;
union {
long long value[64];
long long *value_ptr;
} integer64;
union {
unsigned int item[128];
unsigned int *item_ptr;
} enumerated;
union {
unsigned char data[512];
unsigned char *data_ptr;
} bytes;
struct snd_aes_iec958 iec958;
} value;
struct timespec tstamp;
unsigned char reserved[128-sizeof(struct timespec)];
};
struct snd_ctl_tlv {
unsigned int numid;
unsigned int length;
unsigned int tlv[0];
};
#define SNDRV_CTL_IOCTL_PVERSION _IOR('U', 0x00, int)
#define SNDRV_CTL_IOCTL_CARD_INFO _IOR('U', 0x01, struct snd_ctl_card_info)
#define SNDRV_CTL_IOCTL_ELEM_LIST _IOWR('U', 0x10, struct snd_ctl_elem_list)
#define SNDRV_CTL_IOCTL_ELEM_INFO _IOWR('U', 0x11, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_READ _IOWR('U', 0x12, struct snd_ctl_elem_value)
#define SNDRV_CTL_IOCTL_ELEM_WRITE _IOWR('U', 0x13, struct snd_ctl_elem_value)
#define SNDRV_CTL_IOCTL_ELEM_LOCK _IOW('U', 0x14, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_ELEM_UNLOCK _IOW('U', 0x15, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS _IOWR('U', 0x16, int)
#define SNDRV_CTL_IOCTL_ELEM_ADD _IOWR('U', 0x17, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_REPLACE _IOWR('U', 0x18, struct snd_ctl_elem_info)
#define SNDRV_CTL_IOCTL_ELEM_REMOVE _IOWR('U', 0x19, struct snd_ctl_elem_id)
#define SNDRV_CTL_IOCTL_TLV_READ _IOWR('U', 0x1a, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_TLV_WRITE _IOWR('U', 0x1b, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_TLV_COMMAND _IOWR('U', 0x1c, struct snd_ctl_tlv)
#define SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE _IOWR('U', 0x20, int)
#define SNDRV_CTL_IOCTL_HWDEP_INFO _IOR('U', 0x21, struct snd_hwdep_info)
#define SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE _IOR('U', 0x30, int)
#define SNDRV_CTL_IOCTL_PCM_INFO _IOWR('U', 0x31, struct snd_pcm_info)
#define SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE _IOW('U', 0x32, int)
#define SNDRV_CTL_IOCTL_RAWMIDI_NEXT_DEVICE _IOWR('U', 0x40, int)
#define SNDRV_CTL_IOCTL_RAWMIDI_INFO _IOWR('U', 0x41, struct snd_rawmidi_info)
#define SNDRV_CTL_IOCTL_RAWMIDI_PREFER_SUBDEVICE _IOW('U', 0x42, int)
#define SNDRV_CTL_IOCTL_POWER _IOWR('U', 0xd0, int)
#define SNDRV_CTL_IOCTL_POWER_STATE _IOR('U', 0xd1, int)
enum sndrv_ctl_event_type {
SNDRV_CTL_EVENT_ELEM = 0,
SNDRV_CTL_EVENT_LAST = SNDRV_CTL_EVENT_ELEM,
};
#define SNDRV_CTL_EVENT_MASK_VALUE (1<<0)
#define SNDRV_CTL_EVENT_MASK_INFO (1<<1)
#define SNDRV_CTL_EVENT_MASK_ADD (1<<2)
#define SNDRV_CTL_EVENT_MASK_TLV (1<<3)
#define SNDRV_CTL_EVENT_MASK_REMOVE (~0U)
struct snd_ctl_event {
int type;
union {
struct {
unsigned int mask;
struct snd_ctl_elem_id id;
} elem;
unsigned char data8[60];
} data;
};
#define SNDRV_CTL_NAME_NONE ""
#define SNDRV_CTL_NAME_PLAYBACK "Playback "
#define SNDRV_CTL_NAME_CAPTURE "Capture "
#define SNDRV_CTL_NAME_IEC958_NONE ""
#define SNDRV_CTL_NAME_IEC958_SWITCH "Switch"
#define SNDRV_CTL_NAME_IEC958_VOLUME "Volume"
#define SNDRV_CTL_NAME_IEC958_DEFAULT "Default"
#define SNDRV_CTL_NAME_IEC958_MASK "Mask"
#define SNDRV_CTL_NAME_IEC958_CON_MASK "Con Mask"
#define SNDRV_CTL_NAME_IEC958_PRO_MASK "Pro Mask"
#define SNDRV_CTL_NAME_IEC958_PCM_STREAM "PCM Stream"
#define SNDRV_CTL_NAME_IEC958(expl,direction,what) "IEC958 " expl SNDRV_CTL_NAME_##direction SNDRV_CTL_NAME_IEC958_##what
#endif

View File

@@ -0,0 +1,261 @@
/* asoundlib.h
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#ifndef ASOUNDLIB_H
#define ASOUNDLIB_H
#include <sys/time.h>
#include <stddef.h>
#if defined(__cplusplus)
extern "C" {
#endif
/*
* PCM API
*/
struct pcm;
#define PCM_OUT 0x00000000
#define PCM_IN 0x10000000
#define PCM_MMAP 0x00000001
#define PCM_NOIRQ 0x00000002
#define PCM_NORESTART 0x00000004 /* PCM_NORESTART - when set, calls to
* pcm_write for a playback stream will not
* attempt to restart the stream in the case
* of an underflow, but will return -EPIPE
* instead. After the first -EPIPE error, the
* stream is considered to be stopped, and a
* second call to pcm_write will attempt to
* restart the stream.
*/
#define PCM_MONOTONIC 0x00000008 /* see pcm_get_htimestamp */
/* PCM runtime states */
#define PCM_STATE_RUNNING 3
#define PCM_STATE_XRUN 4
#define PCM_STATE_DRAINING 5
#define PCM_STATE_SUSPENDED 7
#define PCM_STATE_DISCONNECTED 8
/* Bit formats */
enum pcm_format {
PCM_FORMAT_S16_LE = 0,
PCM_FORMAT_S32_LE,
PCM_FORMAT_S8,
PCM_FORMAT_S24_LE,
PCM_FORMAT_MAX,
};
/* Bitmask has 256 bits (32 bytes) in asound.h */
struct pcm_mask {
unsigned int bits[32 / sizeof(unsigned int)];
};
/* Configuration for a stream */
struct pcm_config {
unsigned int channels;
unsigned int rate;
unsigned int period_size;
unsigned int period_count;
enum pcm_format format;
/* Values to use for the ALSA start, stop and silence thresholds. Setting
* any one of these values to 0 will cause the default tinyalsa values to be
* used instead. Tinyalsa defaults are as follows.
*
* start_threshold : period_count * period_size
* stop_threshold : period_count * period_size
* silence_threshold : 0
*/
unsigned int start_threshold;
unsigned int stop_threshold;
unsigned int silence_threshold;
};
/* PCM parameters */
enum pcm_param
{
/* mask parameters */
PCM_PARAM_ACCESS,
PCM_PARAM_FORMAT,
PCM_PARAM_SUBFORMAT,
/* interval parameters */
PCM_PARAM_SAMPLE_BITS,
PCM_PARAM_FRAME_BITS,
PCM_PARAM_CHANNELS,
PCM_PARAM_RATE,
PCM_PARAM_PERIOD_TIME,
PCM_PARAM_PERIOD_SIZE,
PCM_PARAM_PERIOD_BYTES,
PCM_PARAM_PERIODS,
PCM_PARAM_BUFFER_TIME,
PCM_PARAM_BUFFER_SIZE,
PCM_PARAM_BUFFER_BYTES,
PCM_PARAM_TICK_TIME,
};
/* Mixer control types */
enum mixer_ctl_type {
MIXER_CTL_TYPE_BOOL,
MIXER_CTL_TYPE_INT,
MIXER_CTL_TYPE_ENUM,
MIXER_CTL_TYPE_BYTE,
MIXER_CTL_TYPE_IEC958,
MIXER_CTL_TYPE_INT64,
MIXER_CTL_TYPE_UNKNOWN,
MIXER_CTL_TYPE_MAX,
};
/* Open and close a stream */
struct pcm *pcm_open(unsigned int card, unsigned int device,
unsigned int flags, struct pcm_config *config);
int pcm_close(struct pcm *pcm);
int pcm_is_ready(struct pcm *pcm);
/* Obtain the parameters for a PCM */
struct pcm_params *pcm_params_get(unsigned int card, unsigned int device,
unsigned int flags);
void pcm_params_free(struct pcm_params *pcm_params);
struct pcm_mask *pcm_params_get_mask(struct pcm_params *pcm_params,
enum pcm_param param);
unsigned int pcm_params_get_min(struct pcm_params *pcm_params,
enum pcm_param param);
unsigned int pcm_params_get_max(struct pcm_params *pcm_params,
enum pcm_param param);
/* Returns a human readable reason for the last error */
const char *pcm_get_error(struct pcm *pcm);
/* Returns the sample size in bits for a PCM format.
* As with ALSA formats, this is the storage size for the format, whereas the
* format represents the number of significant bits. For example,
* PCM_FORMAT_S24_LE uses 32 bits of storage.
*/
unsigned int pcm_format_to_bits(enum pcm_format format);
/* Returns the buffer size (int frames) that should be used for pcm_write. */
unsigned int pcm_get_buffer_size(struct pcm *pcm);
unsigned int pcm_frames_to_bytes(struct pcm *pcm, unsigned int frames);
unsigned int pcm_bytes_to_frames(struct pcm *pcm, unsigned int bytes);
/* Returns available frames in pcm buffer and corresponding time stamp.
* The clock is CLOCK_MONOTONIC if flag PCM_MONOTONIC was specified in pcm_open,
* otherwise the clock is CLOCK_REALTIME.
* For an input stream, frames available are frames ready for the
* application to read.
* For an output stream, frames available are the number of empty frames available
* for the application to write.
*/
int pcm_get_htimestamp(struct pcm *pcm, unsigned int *avail,
struct timespec *tstamp);
/* Write data to the fifo.
* Will start playback on the first write or on a write that
* occurs after a fifo underrun.
*/
int pcm_write(struct pcm *pcm, const void *data, unsigned int count);
int pcm_read(struct pcm *pcm, void *data, unsigned int count);
/*
* mmap() support.
*/
int pcm_mmap_write(struct pcm *pcm, const void *data, unsigned int count);
int pcm_mmap_read(struct pcm *pcm, void *data, unsigned int count);
int pcm_mmap_begin(struct pcm *pcm, void **areas, unsigned int *offset,
unsigned int *frames);
int pcm_mmap_commit(struct pcm *pcm, unsigned int offset, unsigned int frames);
int pcm_resume(struct pcm *pcm);
/* Prepare the PCM substream to be triggerable */
int pcm_prepare(struct pcm *pcm);
/* Start and stop a PCM channel that doesn't transfer data */
int pcm_start(struct pcm *pcm);
int pcm_stop(struct pcm *pcm);
/* Interrupt driven API */
int pcm_wait(struct pcm *pcm, int timeout);
/*
* MIXER API
*/
struct mixer;
struct mixer_ctl;
/* Open and close a mixer */
struct mixer *mixer_open(unsigned int card);
void mixer_close(struct mixer *mixer);
/* Get info about a mixer */
const char *mixer_get_name(struct mixer *mixer);
/* Obtain mixer controls */
unsigned int mixer_get_num_ctls(struct mixer *mixer);
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id);
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name);
/* Get info about mixer controls */
const char *mixer_ctl_get_name(struct mixer_ctl *ctl);
enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl);
const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl);
unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl);
unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl);
const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
unsigned int enum_id);
/* Some sound cards update their controls due to external events,
* such as HDMI EDID byte data changing when an HDMI cable is
* connected. This API allows the count of elements to be updated.
*/
void mixer_ctl_update(struct mixer_ctl *ctl);
/* Set and get mixer controls */
int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id);
int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent);
int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id);
int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count);
int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value);
int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count);
int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string);
/* Determe range of integer mixer controls */
int mixer_ctl_get_range_min(struct mixer_ctl *ctl);
int mixer_ctl_get_range_max(struct mixer_ctl *ctl);
#if defined(__cplusplus)
} /* extern "C" */
#endif
#endif

503
external/cache/sources/tinyalsa/mixer.c vendored Normal file
View File

@@ -0,0 +1,503 @@
/* mixer.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <sys/ioctl.h>
#include <linux/ioctl.h>
#define __force
#define __bitwise
#define __user
#include <sound/asound.h>
#include <tinyalsa/asoundlib.h>
struct mixer_ctl {
struct mixer *mixer;
struct snd_ctl_elem_info *info;
char **ename;
};
struct mixer {
int fd;
struct snd_ctl_card_info card_info;
struct snd_ctl_elem_info *elem_info;
struct mixer_ctl *ctl;
unsigned int count;
};
void mixer_close(struct mixer *mixer)
{
unsigned int n,m;
if (!mixer)
return;
if (mixer->fd >= 0)
close(mixer->fd);
if (mixer->ctl) {
for (n = 0; n < mixer->count; n++) {
if (mixer->ctl[n].ename) {
unsigned int max = mixer->ctl[n].info->value.enumerated.items;
for (m = 0; m < max; m++)
free(mixer->ctl[n].ename[m]);
free(mixer->ctl[n].ename);
}
}
free(mixer->ctl);
}
if (mixer->elem_info)
free(mixer->elem_info);
free(mixer);
/* TODO: verify frees */
}
struct mixer *mixer_open(unsigned int card)
{
struct snd_ctl_elem_list elist;
struct snd_ctl_elem_info tmp;
struct snd_ctl_elem_id *eid = NULL;
struct mixer *mixer = NULL;
unsigned int n, m;
int fd;
char fn[256];
snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
fd = open(fn, O_RDWR);
if (fd < 0)
return 0;
memset(&elist, 0, sizeof(elist));
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
goto fail;
mixer = calloc(1, sizeof(*mixer));
if (!mixer)
goto fail;
mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
if (!mixer->ctl || !mixer->elem_info)
goto fail;
if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)
goto fail;
eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
if (!eid)
goto fail;
mixer->count = elist.count;
mixer->fd = fd;
elist.space = mixer->count;
elist.pids = eid;
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
goto fail;
for (n = 0; n < mixer->count; n++) {
struct snd_ctl_elem_info *ei = mixer->elem_info + n;
ei->id.numid = eid[n].numid;
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)
goto fail;
mixer->ctl[n].info = ei;
mixer->ctl[n].mixer = mixer;
if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
char **enames = calloc(ei->value.enumerated.items, sizeof(char*));
if (!enames)
goto fail;
mixer->ctl[n].ename = enames;
for (m = 0; m < ei->value.enumerated.items; m++) {
memset(&tmp, 0, sizeof(tmp));
tmp.id.numid = ei->id.numid;
tmp.value.enumerated.item = m;
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)
goto fail;
enames[m] = strdup(tmp.value.enumerated.name);
if (!enames[m])
goto fail;
}
}
}
free(eid);
return mixer;
fail:
/* TODO: verify frees in failure case */
if (eid)
free(eid);
if (mixer)
mixer_close(mixer);
else if (fd >= 0)
close(fd);
return 0;
}
const char *mixer_get_name(struct mixer *mixer)
{
return (const char *)mixer->card_info.name;
}
unsigned int mixer_get_num_ctls(struct mixer *mixer)
{
if (!mixer)
return 0;
return mixer->count;
}
struct mixer_ctl *mixer_get_ctl(struct mixer *mixer, unsigned int id)
{
if (mixer && (id < mixer->count))
return mixer->ctl + id;
return NULL;
}
struct mixer_ctl *mixer_get_ctl_by_name(struct mixer *mixer, const char *name)
{
unsigned int n;
if (!mixer)
return NULL;
for (n = 0; n < mixer->count; n++)
if (!strcmp(name, (char*) mixer->elem_info[n].id.name))
return mixer->ctl + n;
return NULL;
}
void mixer_ctl_update(struct mixer_ctl *ctl)
{
ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_INFO, ctl->info);
}
const char *mixer_ctl_get_name(struct mixer_ctl *ctl)
{
if (!ctl)
return NULL;
return (const char *)ctl->info->id.name;
}
enum mixer_ctl_type mixer_ctl_get_type(struct mixer_ctl *ctl)
{
if (!ctl)
return MIXER_CTL_TYPE_UNKNOWN;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return MIXER_CTL_TYPE_BOOL;
case SNDRV_CTL_ELEM_TYPE_INTEGER: return MIXER_CTL_TYPE_INT;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return MIXER_CTL_TYPE_ENUM;
case SNDRV_CTL_ELEM_TYPE_BYTES: return MIXER_CTL_TYPE_BYTE;
case SNDRV_CTL_ELEM_TYPE_IEC958: return MIXER_CTL_TYPE_IEC958;
case SNDRV_CTL_ELEM_TYPE_INTEGER64: return MIXER_CTL_TYPE_INT64;
default: return MIXER_CTL_TYPE_UNKNOWN;
};
}
const char *mixer_ctl_get_type_string(struct mixer_ctl *ctl)
{
if (!ctl)
return "";
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN: return "BOOL";
case SNDRV_CTL_ELEM_TYPE_INTEGER: return "INT";
case SNDRV_CTL_ELEM_TYPE_ENUMERATED: return "ENUM";
case SNDRV_CTL_ELEM_TYPE_BYTES: return "BYTE";
case SNDRV_CTL_ELEM_TYPE_IEC958: return "IEC958";
case SNDRV_CTL_ELEM_TYPE_INTEGER64: return "INT64";
default: return "Unknown";
};
}
unsigned int mixer_ctl_get_num_values(struct mixer_ctl *ctl)
{
if (!ctl)
return 0;
return ctl->info->count;
}
static int percent_to_int(struct snd_ctl_elem_info *ei, int percent)
{
if ((percent > 100) || (percent < 0)) {
return -EINVAL;
}
int range = (ei->value.integer.max - ei->value.integer.min);
return ei->value.integer.min + (range * percent) / 100;
}
static int int_to_percent(struct snd_ctl_elem_info *ei, int value)
{
int range = (ei->value.integer.max - ei->value.integer.min);
if (range == 0)
return 0;
return ((value - ei->value.integer.min) / range) * 100;
}
int mixer_ctl_get_percent(struct mixer_ctl *ctl, unsigned int id)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return int_to_percent(ctl->info, mixer_ctl_get_value(ctl, id));
}
int mixer_ctl_set_percent(struct mixer_ctl *ctl, unsigned int id, int percent)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return mixer_ctl_set_value(ctl, id, percent_to_int(ctl->info, percent));
}
int mixer_ctl_get_value(struct mixer_ctl *ctl, unsigned int id)
{
struct snd_ctl_elem_value ev;
int ret;
if (!ctl || (id >= ctl->info->count))
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
return !!ev.value.integer.value[id];
case SNDRV_CTL_ELEM_TYPE_INTEGER:
return ev.value.integer.value[id];
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
return ev.value.enumerated.item[id];
case SNDRV_CTL_ELEM_TYPE_BYTES:
return ev.value.bytes.data[id];
default:
return -EINVAL;
}
return 0;
}
int mixer_ctl_get_array(struct mixer_ctl *ctl, void *array, size_t count)
{
struct snd_ctl_elem_value ev;
int ret;
size_t size;
void *source;
if (!ctl || (count > ctl->info->count) || !count || !array)
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
size = sizeof(ev.value.integer.value[0]);
source = ev.value.integer.value;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
size = sizeof(ev.value.bytes.data[0]);
source = ev.value.bytes.data;
break;
default:
return -EINVAL;
}
memcpy(array, source, size * count);
return 0;
}
int mixer_ctl_set_value(struct mixer_ctl *ctl, unsigned int id, int value)
{
struct snd_ctl_elem_value ev;
int ret;
if (!ctl || (id >= ctl->info->count))
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_READ, &ev);
if (ret < 0)
return ret;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
ev.value.integer.value[id] = !!value;
break;
case SNDRV_CTL_ELEM_TYPE_INTEGER:
if ((value < mixer_ctl_get_range_min(ctl)) ||
(value > mixer_ctl_get_range_max(ctl))) {
return -EINVAL;
}
ev.value.integer.value[id] = value;
break;
case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
ev.value.enumerated.item[id] = value;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
ev.value.bytes.data[id] = value;
break;
default:
return -EINVAL;
}
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
}
int mixer_ctl_set_array(struct mixer_ctl *ctl, const void *array, size_t count)
{
struct snd_ctl_elem_value ev;
size_t size;
void *dest;
if (!ctl || (count > ctl->info->count) || !count || !array)
return -EINVAL;
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
switch (ctl->info->type) {
case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
case SNDRV_CTL_ELEM_TYPE_INTEGER:
size = sizeof(ev.value.integer.value[0]);
dest = ev.value.integer.value;
break;
case SNDRV_CTL_ELEM_TYPE_BYTES:
size = sizeof(ev.value.bytes.data[0]);
dest = ev.value.bytes.data;
break;
default:
return -EINVAL;
}
memcpy(dest, array, size * count);
return ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
}
int mixer_ctl_get_range_min(struct mixer_ctl *ctl)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return ctl->info->value.integer.min;
}
int mixer_ctl_get_range_max(struct mixer_ctl *ctl)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_INTEGER))
return -EINVAL;
return ctl->info->value.integer.max;
}
unsigned int mixer_ctl_get_num_enums(struct mixer_ctl *ctl)
{
if (!ctl)
return 0;
return ctl->info->value.enumerated.items;
}
const char *mixer_ctl_get_enum_string(struct mixer_ctl *ctl,
unsigned int enum_id)
{
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED) ||
(enum_id >= ctl->info->value.enumerated.items))
return NULL;
return (const char *)ctl->ename[enum_id];
}
int mixer_ctl_set_enum_by_string(struct mixer_ctl *ctl, const char *string)
{
unsigned int i, num_enums;
struct snd_ctl_elem_value ev;
int ret;
if (!ctl || (ctl->info->type != SNDRV_CTL_ELEM_TYPE_ENUMERATED))
return -EINVAL;
num_enums = ctl->info->value.enumerated.items;
for (i = 0; i < num_enums; i++) {
if (!strcmp(string, ctl->ename[i])) {
memset(&ev, 0, sizeof(ev));
ev.value.enumerated.item[0] = i;
ev.id.numid = ctl->info->id.numid;
ret = ioctl(ctl->mixer->fd, SNDRV_CTL_IOCTL_ELEM_WRITE, &ev);
if (ret < 0)
return ret;
return 0;
}
}
return -EINVAL;
}

1050
external/cache/sources/tinyalsa/pcm.c vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,272 @@
/* tinycap.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <tinyalsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <signal.h>
#include <string.h>
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
#define FORMAT_PCM 1
struct wav_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t riff_fmt;
uint32_t fmt_id;
uint32_t fmt_sz;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
uint32_t data_id;
uint32_t data_sz;
};
int loop_seconds = 0;
int capturing = 1;
int prinfo = 1;
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
unsigned int channels, unsigned int rate,
enum pcm_format format, unsigned int period_size,
unsigned int period_count);
void sigint_handler(int sig)
{
capturing = 0;
}
int main(int argc, char **argv)
{
FILE *file;
struct wav_header header;
unsigned int card = 0;
unsigned int device = 0;
unsigned int channels = 2;
unsigned int rate = 44100;
unsigned int bits = 16;
unsigned int frames;
unsigned int period_size = 1024;
unsigned int period_count = 4;
enum pcm_format format;
int no_header = 0;
if (argc < 2) {
fprintf(stderr, "Usage: %s {file.wav | --} [-D card] [-d device] [-c channels] "
"[-t seconds] [-r rate] [-b bits] [-p period_size] [-n n_periods]\n\n"
"Use -- for filename to send raw PCM to stdout\n", argv[0]);
return 1;
}
if (strcmp(argv[1],"--") == 0) {
file = stdout;
prinfo = 0;
no_header = 1;
} else {
file = fopen(argv[1], "wb");
if (!file) {
fprintf(stderr, "Unable to create file '%s'\n", argv[1]);
return 1;
}
}
/* parse command line arguments */
argv += 2;
while (*argv) {
if (strcmp(*argv, "-d") == 0) {
argv++;
if (*argv)
device = atoi(*argv);
} else if (strcmp(*argv, "-c") == 0) {
argv++;
if (*argv)
channels = atoi(*argv);
} else if (strcmp(*argv, "-r") == 0) {
argv++;
if (*argv)
rate = atoi(*argv);
} else if (strcmp(*argv, "-b") == 0) {
argv++;
if (*argv)
bits = atoi(*argv);
} else if (strcmp(*argv, "-D") == 0) {
argv++;
if (*argv)
card = atoi(*argv);
} else if (strcmp(*argv, "-p") == 0) {
argv++;
if (*argv)
period_size = atoi(*argv);
} else if (strcmp(*argv, "-n") == 0) {
argv++;
if (*argv)
period_count = atoi(*argv);
} else if (strcmp(*argv, "-t") == 0) {
argv++;
if (*argv)
loop_seconds = atoi(*argv);
}
if (*argv)
argv++;
}
header.riff_id = ID_RIFF;
header.riff_sz = 0;
header.riff_fmt = ID_WAVE;
header.fmt_id = ID_FMT;
header.fmt_sz = 16;
header.audio_format = FORMAT_PCM;
header.num_channels = channels;
header.sample_rate = rate;
switch (bits) {
case 32:
format = PCM_FORMAT_S32_LE;
break;
case 24:
format = PCM_FORMAT_S24_LE;
break;
case 16:
format = PCM_FORMAT_S16_LE;
break;
default:
fprintf(stderr, "%d bits is not supported.\n", bits);
return 1;
}
header.bits_per_sample = pcm_format_to_bits(format);
header.byte_rate = (header.bits_per_sample / 8) * channels * rate;
header.block_align = channels * (header.bits_per_sample / 8);
header.data_id = ID_DATA;
/* leave enough room for header */
if (!no_header) {
fseek(file, sizeof(struct wav_header), SEEK_SET);
}
/* install signal handler and begin capturing */
signal(SIGINT, sigint_handler);
frames = capture_sample(file, card, device, header.num_channels,
header.sample_rate, format,
period_size, period_count);
if (prinfo) {
printf("Captured %d frames\n", frames);
}
/* write header now all information is known */
if (!no_header) {
header.data_sz = frames * header.block_align;
header.riff_sz = header.data_sz + sizeof(header) - 8;
fseek(file, 0, SEEK_SET);
fwrite(&header, sizeof(struct wav_header), 1, file);
}
fclose(file);
return 0;
}
unsigned int capture_sample(FILE *file, unsigned int card, unsigned int device,
unsigned int channels, unsigned int rate,
enum pcm_format format, unsigned int period_size,
unsigned int period_count)
{
struct pcm_config config;
struct pcm *pcm;
char *buffer;
unsigned int size;
unsigned int frames;
unsigned long long bytes_read = 0;
struct timeval tv;
struct timezone tz;
long time_sec1;
long time_sec2;
long time_total;
config.channels = channels;
config.rate = rate;
config.period_size = period_size;
config.period_count = period_count;
config.format = format;
config.start_threshold = 0;
config.stop_threshold = 0;
config.silence_threshold = 0;
pcm = pcm_open(card, device, PCM_IN, &config);
if (!pcm || !pcm_is_ready(pcm)) {
fprintf(stderr, "Unable to open PCM device (%s)\n",
pcm_get_error(pcm));
return 0;
}
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = malloc(size);
if (!buffer) {
fprintf(stderr, "Unable to allocate %d bytes\n", size);
free(buffer);
pcm_close(pcm);
return 0;
}
if (prinfo) {
printf("Capturing sample: %u ch, %u hz, %u bit\n", channels, rate,
pcm_format_to_bits(format));
}
gettimeofday(&tv, &tz);
time_sec1 = tv.tv_sec;
while (capturing && !pcm_read(pcm, buffer, size)) {
if (fwrite(buffer, 1, size, file) != size) {
fprintf(stderr,"Error capturing sample\n");
break;
}
gettimeofday(&tv, &tz);
time_sec2 = tv.tv_sec;
time_total = time_sec2 - time_sec1;
if (time_total >= (loop_seconds)) {
printf("time_total:%ld, loop_seconds:%d\n",
time_total, loop_seconds);
break;
}
bytes_read += size;
}
frames = pcm_bytes_to_frames(pcm, bytes_read);
free(buffer);
pcm_close(pcm);
return frames;
}

View File

@@ -0,0 +1,317 @@
/* tinymix.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <tinyalsa/asoundlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
static void tinymix_list_controls(struct mixer *mixer);
static void tinymix_detail_control(struct mixer *mixer, const char *control,
int print_all);
static void tinymix_set_value(struct mixer *mixer, const char *control,
char **values, unsigned int num_values);
static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all);
int main(int argc, char **argv)
{
struct mixer *mixer;
int card = 0;
if ((argc > 2) && (strcmp(argv[1], "-D") == 0)) {
argv++;
if (argv[1]) {
card = atoi(argv[1]);
argv++;
argc -= 2;
} else {
argc -= 1;
}
}
mixer = mixer_open(card);
if (!mixer) {
fprintf(stderr, "Failed to open mixer\n");
return EXIT_FAILURE;
}
if (argc == 1) {
printf("Mixer name: '%s'\n", mixer_get_name(mixer));
tinymix_list_controls(mixer);
} else if (argc == 2) {
tinymix_detail_control(mixer, argv[1], 1);
} else if (argc >= 3) {
tinymix_set_value(mixer, argv[1], &argv[2], argc - 2);
} else {
printf("Usage: tinymix [-D card] [control id] [value to set]\n");
}
mixer_close(mixer);
return 0;
}
static void tinymix_list_controls(struct mixer *mixer)
{
struct mixer_ctl *ctl;
const char *name, *type;
unsigned int num_ctls, num_values;
unsigned int i;
num_ctls = mixer_get_num_ctls(mixer);
printf("Number of controls: %d\n", num_ctls);
printf("ctl\ttype\tnum\t%-40s value\n", "name");
for (i = 0; i < num_ctls; i++) {
ctl = mixer_get_ctl(mixer, i);
name = mixer_ctl_get_name(ctl);
type = mixer_ctl_get_type_string(ctl);
num_values = mixer_ctl_get_num_values(ctl);
printf("%d\t%s\t%d\t%-40s", i, type, num_values, name);
tinymix_detail_control(mixer, name, 0);
}
}
static void tinymix_print_enum(struct mixer_ctl *ctl, int print_all)
{
unsigned int num_enums;
unsigned int i;
const char *string;
num_enums = mixer_ctl_get_num_enums(ctl);
for (i = 0; i < num_enums; i++) {
string = mixer_ctl_get_enum_string(ctl, i);
if (print_all)
printf("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "",
string);
else if (mixer_ctl_get_value(ctl, 0) == (int)i)
printf(" %-s", string);
}
}
static void tinymix_detail_control(struct mixer *mixer, const char *control,
int print_all)
{
struct mixer_ctl *ctl;
enum mixer_ctl_type type;
unsigned int num_values;
unsigned int i;
int min, max;
int ret;
char buf[512] = { 0 };
size_t len;
if (isdigit(control[0]))
ctl = mixer_get_ctl(mixer, atoi(control));
else
ctl = mixer_get_ctl_by_name(mixer, control);
if (!ctl) {
fprintf(stderr, "Invalid mixer control\n");
return;
}
type = mixer_ctl_get_type(ctl);
num_values = mixer_ctl_get_num_values(ctl);
if (type == MIXER_CTL_TYPE_BYTE) {
len = num_values;
if (len > sizeof(buf)) {
fprintf(stderr, "Truncating get to %zu bytes\n", sizeof(buf));
len = sizeof(buf);
}
ret = mixer_ctl_get_array(ctl, buf, len);
if (ret < 0) {
fprintf(stderr, "Failed to mixer_ctl_get_array\n");
return;
}
}
if (print_all)
printf("%s:", mixer_ctl_get_name(ctl));
for (i = 0; i < num_values; i++) {
switch (type)
{
case MIXER_CTL_TYPE_INT:
printf(" %d", mixer_ctl_get_value(ctl, i));
break;
case MIXER_CTL_TYPE_BOOL:
printf(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
break;
case MIXER_CTL_TYPE_ENUM:
tinymix_print_enum(ctl, print_all);
break;
case MIXER_CTL_TYPE_BYTE:
printf("%02x", buf[i]);
break;
default:
printf(" unknown");
break;
};
}
if (print_all) {
if (type == MIXER_CTL_TYPE_INT) {
min = mixer_ctl_get_range_min(ctl);
max = mixer_ctl_get_range_max(ctl);
printf(" (range %d->%d)", min, max);
}
}
printf("\n");
}
static void tinymix_set_byte_ctl(struct mixer_ctl *ctl, const char *control,
char **values, unsigned int num_values)
{
int ret;
char buf[512] = { 0 };
char *end;
int i;
long n;
if (num_values > sizeof(buf)) {
fprintf(stderr, "Truncating set to %zu bytes\n", sizeof(buf));
num_values = sizeof(buf);
}
for (i = 0; i < num_values; i++) {
errno = 0;
n = strtol(values[i], &end, 0);
if (*end) {
fprintf(stderr, "%s not an integer\n", values[i]);
exit(EXIT_FAILURE);
}
if (errno) {
fprintf(stderr, "strtol: %s: %s\n", values[i],
strerror(errno));
exit(EXIT_FAILURE);
}
if (n < 0 || n > 0xff) {
fprintf(stderr, "%s should be between [0, 0xff]\n",
values[i]);
exit(EXIT_FAILURE);
}
buf[i] = n;
}
ret = mixer_ctl_set_array(ctl, buf, num_values);
if (ret < 0) {
fprintf(stderr, "Failed to set binary control\n");
exit(EXIT_FAILURE);
}
}
static int is_int(char *value)
{
char* end;
long int result;
errno = 0;
result = strtol(value, &end, 10);
if (result == LONG_MIN || result == LONG_MAX)
return 0;
return errno == 0 && *end == '\0';
}
static void tinymix_set_value(struct mixer *mixer, const char *control,
char **values, unsigned int num_values)
{
struct mixer_ctl *ctl;
enum mixer_ctl_type type;
unsigned int num_ctl_values;
unsigned int i;
if (isdigit(control[0]))
ctl = mixer_get_ctl(mixer, atoi(control));
else
ctl = mixer_get_ctl_by_name(mixer, control);
if (!ctl) {
fprintf(stderr, "Invalid mixer control\n");
return;
}
type = mixer_ctl_get_type(ctl);
num_ctl_values = mixer_ctl_get_num_values(ctl);
if (type == MIXER_CTL_TYPE_BYTE) {
tinymix_set_byte_ctl(ctl, control, values, num_values);
return;
}
if (is_int(values[0])) {
if (num_values == 1) {
/* Set all values the same */
int value = atoi(values[0]);
for (i = 0; i < num_ctl_values; i++) {
if (mixer_ctl_set_value(ctl, i, value)) {
fprintf(stderr, "Error: invalid value\n");
return;
}
}
} else {
/* Set multiple values */
if (num_values > num_ctl_values) {
fprintf(stderr,
"Error: %d values given, but control only takes %d\n",
num_values, num_ctl_values);
return;
}
for (i = 0; i < num_values; i++) {
if (mixer_ctl_set_value(ctl, i, atoi(values[i]))) {
fprintf(stderr, "Error: invalid value for index %d\n", i);
return;
}
}
}
} else {
if (type == MIXER_CTL_TYPE_ENUM) {
if (num_values != 1) {
fprintf(stderr, "Enclose strings in quotes and try again\n");
return;
}
if (mixer_ctl_set_enum_by_string(ctl, values[0]))
fprintf(stderr, "Error: invalid enum value\n");
} else {
fprintf(stderr, "Error: only enum types can be set with strings\n");
}
}
}

View File

@@ -0,0 +1,203 @@
/* tinypcminfo.c
**
** Copyright 2012, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <tinyalsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif
/* The format_lookup is in order of SNDRV_PCM_FORMAT_##index and
* matches the grouping in sound/asound.h. Note this is not
* continuous and has an empty gap from (25 - 30).
*/
static const char *format_lookup[] = {
/*[0] =*/ "S8",
"U8",
"S16_LE",
"S16_BE",
"U16_LE",
"U16_BE",
"S24_LE",
"S24_BE",
"U24_LE",
"U24_BE",
"S32_LE",
"S32_BE",
"U32_LE",
"U32_BE",
"FLOAT_LE",
"FLOAT_BE",
"FLOAT64_LE",
"FLOAT64_BE",
"IEC958_SUBFRAME_LE",
"IEC958_SUBFRAME_BE",
"MU_LAW",
"A_LAW",
"IMA_ADPCM",
"MPEG",
/*[24] =*/ "GSM",
[31] = "SPECIAL",
"S24_3LE",
"S24_3BE",
"U24_3LE",
"U24_3BE",
"S20_3LE",
"S20_3BE",
"U20_3LE",
"U20_3BE",
"S18_3LE",
"S18_3BE",
"U18_3LE",
/*[43] =*/ "U18_3BE",
#if 0
/* recent additions, may not be present on local asound.h */
"G723_24",
"G723_24_1B",
"G723_40",
"G723_40_1B",
"DSD_U8",
"DSD_U16_LE",
#endif
};
/* Returns a human readable name for the format associated with bit_index,
* NULL if bit_index is not known.
*/
inline const char *pcm_get_format_name(unsigned bit_index)
{
return bit_index < ARRAY_SIZE(format_lookup) ? format_lookup[bit_index] : NULL;
}
int main(int argc, char **argv)
{
unsigned int device = 0;
unsigned int card = 0;
int i;
if (argc < 3) {
fprintf(stderr, "Usage: %s -D card -d device\n", argv[0]);
return 1;
}
/* parse command line arguments */
argv += 1;
while (*argv) {
if (strcmp(*argv, "-D") == 0) {
argv++;
if (*argv)
card = atoi(*argv);
}
if (strcmp(*argv, "-d") == 0) {
argv++;
if (*argv)
device = atoi(*argv);
}
if (*argv)
argv++;
}
printf("Info for card %d, device %d:\n", card, device);
for (i = 0; i < 2; i++) {
struct pcm_params *params;
struct pcm_mask *m;
unsigned int min;
unsigned int max;
printf("\nPCM %s:\n", i == 0 ? "out" : "in");
params = pcm_params_get(card, device, i == 0 ? PCM_OUT : PCM_IN);
if (params == NULL) {
printf("Device does not exist.\n");
continue;
}
m = pcm_params_get_mask(params, PCM_PARAM_ACCESS);
if (m) { /* bitmask, refer to SNDRV_PCM_ACCESS_*, generally interleaved */
printf(" Access:\t%#08x\n", m->bits[0]);
}
m = pcm_params_get_mask(params, PCM_PARAM_FORMAT);
if (m) { /* bitmask, refer to: SNDRV_PCM_FORMAT_* */
unsigned j, k, count = 0;
const unsigned bitcount = sizeof(m->bits[0]) * 8;
/* we only check first two format masks (out of 8) - others are zero. */
printf(" Format[0]:\t%#08x\n", m->bits[0]);
printf(" Format[1]:\t%#08x\n", m->bits[1]);
/* print friendly format names, if they exist */
for (k = 0; k < 2; ++k) {
for (j = 0; j < bitcount; ++j) {
const char *name;
if (m->bits[k] & (1 << j)) {
name = pcm_get_format_name(j + k*bitcount);
if (name) {
if (count++ == 0) {
printf(" Format Name:\t");
} else {
printf (", ");
}
printf("%s", name);
}
}
}
}
if (count) {
printf("\n");
}
}
m = pcm_params_get_mask(params, PCM_PARAM_SUBFORMAT);
if (m) { /* bitmask, should be 1: SNDRV_PCM_SUBFORMAT_STD */
printf(" Subformat:\t%#08x\n", m->bits[0]);
}
min = pcm_params_get_min(params, PCM_PARAM_RATE);
max = pcm_params_get_max(params, PCM_PARAM_RATE);
printf(" Rate:\tmin=%uHz\tmax=%uHz\n", min, max);
min = pcm_params_get_min(params, PCM_PARAM_CHANNELS);
max = pcm_params_get_max(params, PCM_PARAM_CHANNELS);
printf(" Channels:\tmin=%u\t\tmax=%u\n", min, max);
min = pcm_params_get_min(params, PCM_PARAM_SAMPLE_BITS);
max = pcm_params_get_max(params, PCM_PARAM_SAMPLE_BITS);
printf(" Sample bits:\tmin=%u\t\tmax=%u\n", min, max);
min = pcm_params_get_min(params, PCM_PARAM_PERIOD_SIZE);
max = pcm_params_get_max(params, PCM_PARAM_PERIOD_SIZE);
printf(" Period size:\tmin=%u\t\tmax=%u\n", min, max);
min = pcm_params_get_min(params, PCM_PARAM_PERIODS);
max = pcm_params_get_max(params, PCM_PARAM_PERIODS);
printf("Period count:\tmin=%u\t\tmax=%u\n", min, max);
pcm_params_free(params);
}
return 0;
}

View File

@@ -0,0 +1,313 @@
/* tinyplay.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** * Neither the name of The Android Open Source Project nor the names of
** its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/
#include <tinyalsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <sys/time.h>
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
struct riff_wave_header {
uint32_t riff_id;
uint32_t riff_sz;
uint32_t wave_id;
};
struct chunk_header {
uint32_t id;
uint32_t sz;
};
struct chunk_fmt {
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
};
static int close = 0;
static unsigned int loop_num = 1;
static unsigned int loop_minutes = 0;
void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count);
void stream_close(int sig)
{
/* allow the stream to be closed gracefully */
signal(sig, SIG_IGN);
close = 1;
}
int main(int argc, char **argv)
{
FILE *file;
struct riff_wave_header riff_wave_header;
struct chunk_header chunk_header;
struct chunk_fmt chunk_fmt;
unsigned int device = 0;
unsigned int card = 0;
unsigned int period_size = 1024;
unsigned int period_count = 4;
char *filename;
int more_chunks = 1;
if (argc < 2) {
fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] "
"[-m loop_minutes] [-i loop_num] "
"[-p period_size] [-n period_count] \n", argv[0]);
return 1;
}
filename = argv[1];
file = fopen(filename, "rb");
if (!file) {
fprintf(stderr, "Unable to open file '%s'\n", filename);
return 1;
}
fread(&riff_wave_header, sizeof(riff_wave_header), 1, file);
if ((riff_wave_header.riff_id != ID_RIFF) ||
(riff_wave_header.wave_id != ID_WAVE)) {
fprintf(stderr, "Error: '%s' is not a riff/wave file\n", filename);
fclose(file);
return 1;
}
do {
fread(&chunk_header, sizeof(chunk_header), 1, file);
switch (chunk_header.id) {
case ID_FMT:
fread(&chunk_fmt, sizeof(chunk_fmt), 1, file);
/* If the format header is larger, skip the rest */
if (chunk_header.sz > sizeof(chunk_fmt))
fseek(file, chunk_header.sz - sizeof(chunk_fmt), SEEK_CUR);
break;
case ID_DATA:
/* Stop looking for chunks */
more_chunks = 0;
break;
default:
/* Unknown chunk, skip bytes */
fseek(file, chunk_header.sz, SEEK_CUR);
}
} while (more_chunks);
/* parse command line arguments */
argv += 2;
while (*argv) {
if (strcmp(*argv, "-d") == 0) {
argv++;
if (*argv)
device = atoi(*argv);
}
if (strcmp(*argv, "-p") == 0) {
argv++;
if (*argv)
period_size = atoi(*argv);
}
if (strcmp(*argv, "-n") == 0) {
argv++;
if (*argv)
period_count = atoi(*argv);
}
if (strcmp(*argv, "-D") == 0) {
argv++;
if (*argv)
card = atoi(*argv);
}
if (strcmp(*argv, "-m") == 0) {
argv++;
if (*argv)
loop_minutes = atoi(*argv);
}
if (strcmp(*argv, "-i") == 0) {
argv++;
if (*argv)
loop_num = atoi(*argv);
}
if (*argv)
argv++;
}
play_sample(file, card, device, chunk_fmt.num_channels, chunk_fmt.sample_rate,
chunk_fmt.bits_per_sample, period_size, period_count);
fclose(file);
return 0;
}
int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
char *param_name, char *param_unit)
{
unsigned int min;
unsigned int max;
int is_within_bounds = 1;
min = pcm_params_get_min(params, param);
if (value < min) {
fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
param_unit, min, param_unit);
is_within_bounds = 0;
}
max = pcm_params_get_max(params, param);
if (value > max) {
fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
param_unit, max, param_unit);
is_within_bounds = 0;
}
return is_within_bounds;
}
int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count)
{
struct pcm_params *params;
int can_play;
params = pcm_params_get(card, device, PCM_OUT);
if (params == NULL) {
fprintf(stderr, "Unable to open PCM device %u.\n", device);
return 0;
}
can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", "Hz");
can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", "Hz");
pcm_params_free(params);
return can_play;
}
void play_sample(FILE *file, unsigned int card, unsigned int device, unsigned int channels,
unsigned int rate, unsigned int bits, unsigned int period_size,
unsigned int period_count)
{
struct pcm_config config;
struct pcm *pcm;
char *buffer;
int size;
int num_read;
struct timeval tv;
struct timezone tz;
long sec_start = 0;
long sec_end = 0;
int loop_count = 0;
config.channels = channels;
config.rate = rate;
config.period_size = period_size;
config.period_count = period_count;
if (bits == 32)
config.format = PCM_FORMAT_S32_LE;
else if (bits == 16)
config.format = PCM_FORMAT_S16_LE;
else if (bits == 24)
config.format = PCM_FORMAT_S24_LE;
config.start_threshold = 0;
config.stop_threshold = 0;
config.silence_threshold = 0;
if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {
return;
}
pcm = pcm_open(card, device, PCM_OUT, &config);
if (!pcm || !pcm_is_ready(pcm)) {
fprintf(stderr, "Unable to open PCM device %u (%s)\n",
device, pcm_get_error(pcm));
return;
}
size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
buffer = malloc(size);
if (!buffer) {
fprintf(stderr, "Unable to allocate %d bytes\n", size);
free(buffer);
pcm_close(pcm);
return;
}
printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);
/* catch ctrl-c to shutdown cleanly */
signal(SIGINT, stream_close);
gettimeofday(&tv, &tz);
sec_start = tv.tv_sec;
printf("start --> loop_minutes = %d; loop_num = %d\n",
loop_minutes, loop_num);
do {
num_read = fread(buffer, 1, size, file);
if (num_read > 0) {
if (pcm_write(pcm, buffer, num_read)) {
fprintf(stderr, "Error playing sample\n");
break;
}
if (feof(file)) {
printf("--> loop_count = %d\n", ++loop_count);
fseek(file, 0L, SEEK_SET);
}
if (loop_minutes == 0) {
if (loop_count >= loop_num)
break;
} else {
gettimeofday(&tv, &tz);
sec_end = tv.tv_sec;
if ((sec_end - sec_start) > (loop_minutes * 60)) {
printf("End loop_minutes: %ld\n", (sec_end - sec_start)/60);
break;
}
}
}
} while (!close && num_read > 0);
free(buffer);
pcm_close(pcm);
}