Description: Patches for compatibility with on-board Bluetooth on RPi 3 Author: Simon Long Last-Update: 2017-04-05 --- a/tools/hciattach.c +++ b/tools/hciattach.c @@ -1091,6 +1091,9 @@ { "bcm43xx", 0x0000, 0x0000, HCI_UART_H4, 115200, 3000000, FLOW_CTL, DISABLE_PM, NULL, bcm43xx, NULL }, + { "bcm43xx-3wire", 0x0000, 0x0000, HCI_UART_3WIRE, 115200, 3000000, + 0, DISABLE_PM, NULL, bcm43xx, NULL }, + { "ath3k", 0x0000, 0x0000, HCI_UART_ATH3K, 115200, 115200, FLOW_CTL, DISABLE_PM, NULL, ath3k_ps, ath3k_pm }, @@ -1237,7 +1240,7 @@ { struct uart_t *u = NULL; int detach, printpid, raw, opt, i, n, ld, err; - int to = 10; + int to = 30; int init_speed = 0; int send_break = 0; pid_t pid; --- a/tools/hciattach.h +++ b/tools/hciattach.h @@ -44,7 +45,7 @@ #define HCI_UART_VND_DETECT 5 #ifndef FIRMWARE_DIR -#define FIRMWARE_DIR "/etc/firmware" +#define FIRMWARE_DIR "/lib/firmware" #endif int read_hci_event(int fd, unsigned char *buf, int size); --- a/tools/hciattach_bcm43xx.c +++ b/tools/hciattach_bcm43xx.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "lib/bluetooth.h" #include "lib/hci.h" @@ -303,9 +304,23 @@ static int bcm43xx_locate_patch(const char *dir_name, const char *chip_name, char *location) { + struct stat statbuf; + char path[PATH_MAX]; DIR *dir; int ret = -1; + /* Try an exact match before scanning, otherwise a board without a specific + * firmware/link may end up loading a specific firmware for another board + * just because it is encountered first. + */ + if (snprintf(path, PATH_MAX, "%s/%s%s", dir_name, chip_name, FW_EXT) < 0) + return -1; + if ((stat(path, &statbuf) == 0) && S_ISREG(statbuf.st_mode)) { + strcpy(location, path); + return 0; + } + + /* Now search subdirectories and files with suffixes */ dir = opendir(dir_name); if (!dir) { fprintf(stderr, "Cannot open directory '%s': %s\n", @@ -320,8 +335,6 @@ break; if (entry->d_type & DT_DIR) { - char path[PATH_MAX]; - if (!strcmp(entry->d_name, "..") || !strcmp(entry->d_name, ".")) continue; @@ -341,8 +354,10 @@ break; /* found */ - snprintf(location, PATH_MAX, "%s/%s", dir_name, entry->d_name); - ret = 0; + if (snprintf(location, PATH_MAX, "%s/%s", dir_name, entry->d_name) < 0) + ret = -1; + else + ret = 0; break; } } @@ -352,11 +367,32 @@ return ret; } +static int get_board_type(char *buf, int buf_size) +{ + int bytes_read; + int len; + int fd; + + fd = open("/sys/firmware/devicetree/base/compatible", O_RDONLY); + if (fd < 0) + return -1; + + bytes_read = read(fd, buf, buf_size); + close(fd); + if (bytes_read < 0) + return -1; + + len = strnlen(buf, buf_size); + return (len < buf_size) ? len : -1; +} + int bcm43xx_init(int fd, int def_speed, int speed, struct termios *ti, const char *bdaddr) { char chip_name[20]; + char board_specific_name[sizeof(chip_name) + 64]; char fw_path[PATH_MAX]; + int chip_name_len; printf("bcm43xx_init\n"); @@ -366,12 +402,17 @@ 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"); + /* Grab the board compatible string from Device Tree */ + chip_name_len = strlen(chip_name); + memcpy(board_specific_name, chip_name, chip_name_len); + board_specific_name[chip_name_len++] = '.'; + + if (((get_board_type(board_specific_name + chip_name_len, + sizeof(board_specific_name) - chip_name_len) < 0) || + bcm43xx_locate_patch(FIRMWARE_DIR, board_specific_name, fw_path)) && + bcm43xx_locate_patch(FIRMWARE_DIR, chip_name, fw_path)) { + fprintf(stderr, "Patch not found for %s, continue anyway\n", chip_name); } else { - if (bcm43xx_set_speed(fd, ti, speed)) - return -1; - if (bcm43xx_load_firmware(fd, fw_path)) return -1; @@ -381,6 +422,7 @@ return -1; } + sleep(1); if (bcm43xx_reset(fd)) return -1; }