| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2014 Intel Corporation
- * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <inttypes.h>
- #include "src/shared/util.h"
- #include "display.h"
- #include "packet.h"
- #include "lmp.h"
- #include "ll.h"
- #include "vendor.h"
- #include "broadcom.h"
- #define COLOR_UNKNOWN_FEATURE_BIT COLOR_WHITE_BG
- static void print_status(uint8_t status)
- {
- packet_print_error("Status", status);
- }
- static void print_handle(uint16_t handle)
- {
- packet_print_handle(handle);
- }
- static void print_rssi(int8_t rssi)
- {
- packet_print_rssi("RSSI", rssi);
- }
- static void print_sco_routing(uint8_t routing)
- {
- const char *str;
- switch (routing) {
- case 0x00:
- str = "PCM";
- break;
- case 0x01:
- str = "Transport";
- break;
- case 0x02:
- str = "Codec";
- break;
- case 0x03:
- str = "I2S";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("SCO routing: %s (0x%2.2x)", str, routing);
- }
- static void print_pcm_interface_rate(uint8_t rate)
- {
- const char *str;
- switch (rate) {
- case 0x00:
- str = "128 KBps";
- break;
- case 0x01:
- str = "256 KBps";
- break;
- case 0x02:
- str = "512 KBps";
- break;
- case 0x03:
- str = "1024 KBps";
- break;
- case 0x04:
- str = "2048 KBps";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("PCM interface rate: %s (0x%2.2x)", str, rate);
- }
- static void print_frame_type(uint8_t type)
- {
- const char *str;
- switch (type) {
- case 0x00:
- str = "Short";
- break;
- case 0x01:
- str = "Long";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Frame type: %s (0x%2.2x)", str, type);
- }
- static void print_sync_mode(uint8_t mode)
- {
- const char *str;
- switch (mode) {
- case 0x00:
- str = "Peripheral";
- break;
- case 0x01:
- str = "Central";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Sync mode: %s (0x%2.2x)", str, mode);
- }
- static void print_clock_mode(uint8_t mode)
- {
- const char *str;
- switch (mode) {
- case 0x00:
- str = "Peripheral";
- break;
- case 0x01:
- str = "Central";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Clock mode: %s (0x%2.2x)", str, mode);
- }
- static void print_sleep_mode(uint8_t mode)
- {
- const char *str;
- switch (mode) {
- case 0x00:
- str = "No sleep mode";
- break;
- case 0x01:
- str = "UART";
- break;
- case 0x02:
- str = "UART with messaging";
- break;
- case 0x03:
- str = "USB";
- break;
- case 0x04:
- str = "H4IBSS";
- break;
- case 0x05:
- str = "USB with Host wake";
- break;
- case 0x06:
- str = "SDIO";
- break;
- case 0x07:
- str = "UART CS-N";
- break;
- case 0x08:
- str = "SPI";
- break;
- case 0x09:
- str = "H5";
- break;
- case 0x0a:
- str = "H4DS";
- break;
- case 0x0c:
- str = "UART with BREAK";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Sleep mode: %s (0x%2.2x)", str, mode);
- }
- static void print_clock_setting(uint8_t clock)
- {
- const char *str;
- switch (clock) {
- case 0x01:
- str = "48 Mhz";
- break;
- case 0x02:
- str = "24 Mhz";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("UART clock: %s (0x%2.2x)", str, clock);
- }
- static void null_cmd(const void *data, uint8_t size)
- {
- }
- static void status_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- print_status(status);
- }
- static void write_bd_addr_cmd(const void *data, uint8_t size)
- {
- packet_print_addr("Address", data, 0x00);
- }
- static void update_uart_baud_rate_cmd(const void *data, uint8_t size)
- {
- uint16_t enc_rate = get_le16(data);
- uint32_t exp_rate = get_le32(data + 2);
- if (enc_rate == 0x0000)
- print_field("Encoded baud rate: Not used (0x0000)");
- else
- print_field("Encoded baud rate: 0x%4.4x", enc_rate);
- print_field("Explicit baud rate: %u Mbps", exp_rate);
- }
- static void write_sco_pcm_int_param_cmd(const void *data, uint8_t size)
- {
- uint8_t routing = get_u8(data);
- uint8_t rate = get_u8(data + 1);
- uint8_t frame_type = get_u8(data + 2);
- uint8_t sync_mode = get_u8(data + 3);
- uint8_t clock_mode = get_u8(data + 4);
- print_sco_routing(routing);
- print_pcm_interface_rate(rate);
- print_frame_type(frame_type);
- print_sync_mode(sync_mode);
- print_clock_mode(clock_mode);
- }
- static void read_sco_pcm_int_param_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- uint8_t routing = get_u8(data + 1);
- uint8_t rate = get_u8(data + 2);
- uint8_t frame_type = get_u8(data + 3);
- uint8_t sync_mode = get_u8(data + 4);
- uint8_t clock_mode = get_u8(data + 5);
- print_status(status);
- print_sco_routing(routing);
- print_pcm_interface_rate(rate);
- print_frame_type(frame_type);
- print_sync_mode(sync_mode);
- print_clock_mode(clock_mode);
- }
- static void set_sleepmode_param_cmd(const void *data, uint8_t size)
- {
- uint8_t mode = get_u8(data);
- print_sleep_mode(mode);
- packet_hexdump(data + 1, size - 1);
- }
- static void read_sleepmode_param_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- uint8_t mode = get_u8(data + 1);
- print_status(status);
- print_sleep_mode(mode);
- packet_hexdump(data + 2, size - 2);
- }
- static void enable_radio_cmd(const void *data, uint8_t size)
- {
- uint8_t mode = get_u8(data);
- const char *str;
- switch (mode) {
- case 0x00:
- str = "Disable the radio";
- break;
- case 0x01:
- str = "Enable the radio";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Mode: %s (0x%2.2x)", str, mode);
- }
- static void enable_usb_hid_emulation_cmd(const void *data, uint8_t size)
- {
- uint8_t enable = get_u8(data);
- const char *str;
- switch (enable) {
- case 0x00:
- str = "Bluetooth mode";
- break;
- case 0x01:
- str = "HID Mode";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Enable: %s (0x%2.2x)", str, enable);
- }
- static void read_uart_clock_setting_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- uint8_t clock = get_u8(data + 1);
- print_status(status);
- print_clock_setting(clock);
- }
- static void write_uart_clock_setting_cmd(const void *data, uint8_t size)
- {
- uint8_t clock = get_u8(data);
- print_clock_setting(clock);
- }
- static void read_raw_rssi_cmd(const void *data, uint8_t size)
- {
- uint16_t handle = get_le16(data);
- print_handle(handle);
- }
- static void read_raw_rssi_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- uint16_t handle = get_le16(data + 1);
- int8_t rssi = get_s8(data + 3);
- print_status(status);
- print_handle(handle);
- print_rssi(rssi);
- }
- static void write_ram_cmd(const void *data, uint8_t size)
- {
- uint32_t addr = get_le32(data);
- print_field("Address: 0x%8.8x", addr);
- packet_hexdump(data + 4, size - 4);
- }
- static void read_ram_cmd(const void *data, uint8_t size)
- {
- uint32_t addr = get_le32(data);
- uint8_t length = get_u8(data + 4);
- print_field("Address: 0x%8.8x", addr);
- print_field("Length: %u", length);
- }
- static void read_ram_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- print_status(status);
- packet_hexdump(data + 1, size - 1);
- }
- static void launch_ram_cmd(const void *data, uint8_t size)
- {
- uint32_t addr = get_le32(data);
- print_field("Address: 0x%8.8x", addr);
- }
- static void read_vid_pid_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- uint16_t vid = get_le16(data + 1);
- uint16_t pid = get_le16(data + 3);
- print_status(status);
- print_field("Product: %4.4x:%4.4x", vid, pid);
- }
- static void write_high_priority_connection_cmd(const void *data, uint8_t size)
- {
- uint16_t handle = get_le16(data);
- uint8_t priority = get_u8(data + 2);
- const char *str;
- print_handle(handle);
- switch (priority) {
- case 0x00:
- str = "Low";
- break;
- case 0x01:
- str = "High";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Priority: %s (0x%2.2x)", str, priority);
- }
- static const struct {
- uint8_t bit;
- const char *str;
- } features_table[] = {
- { 0, "Multi-AV transport bandwidth reducer" },
- { 1, "WBS SBC" },
- { 2, "FW LC-PLC" },
- { 3, "FM SBC internal stack" },
- { }
- };
- static void print_features(const uint8_t *features_array)
- {
- uint64_t mask, features = 0;
- char str[41];
- int i;
- for (i = 0; i < 8; i++) {
- sprintf(str + (i * 5), " 0x%2.2x", features_array[i]);
- features |= ((uint64_t) features_array[i]) << (i * 8);
- }
- print_field("Features:%s", str);
- mask = features;
- for (i = 0; features_table[i].str; i++) {
- if (features & (((uint64_t) 1) << features_table[i].bit)) {
- print_field(" %s", features_table[i].str);
- mask &= ~(((uint64_t) 1) << features_table[i].bit);
- }
- }
- if (mask)
- print_text(COLOR_UNKNOWN_FEATURE_BIT, " Unknown features "
- "(0x%16.16" PRIx64 ")", mask);
- }
- static void read_controller_features_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- print_status(status);
- print_features(data + 1);
- }
- static void read_verbose_version_info_rsp(const void *data, uint8_t size)
- {
- uint8_t status = get_u8(data);
- uint8_t chip_id = get_u8(data + 1);
- uint8_t target_id = get_u8(data + 2);
- uint16_t build_base = get_le16(data + 3);
- uint16_t build_num = get_le16(data + 5);
- const char *str;
- print_status(status);
- print_field("Chip ID: %u (0x%2.2x)", chip_id, chip_id);
- switch (target_id) {
- case 254:
- str = "Invalid";
- break;
- case 255:
- str = "Undefined";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Build target: %s (%u)", str, target_id);
- print_field("Build baseline: %u (0x%4.4x)", build_base, build_base);
- print_field("Build number: %u (0x%4.4x)", build_num, build_num);
- }
- static void enable_wbs_cmd(const void *data, uint8_t size)
- {
- uint8_t mode = get_u8(data);
- uint16_t codec = get_le16(data + 1);
- const char *str;
- switch (mode) {
- case 0x00:
- str = "Disable WBS";
- break;
- case 0x01:
- str = "Enable WBS";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Mode: %s (0x%2.2x)", str, mode);
- switch (codec) {
- case 0x0000:
- str = "None";
- break;
- case 0x0001:
- str = "CVSD";
- break;
- case 0x0002:
- str = "mSBC";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Codec: %s (0x%4.4x)", str, codec);
- }
- static const struct vendor_ocf vendor_ocf_table[] = {
- { 0x001, "Write BD ADDR",
- write_bd_addr_cmd, 6, true,
- status_rsp, 1, true },
- { 0x018, "Update UART Baud Rate",
- update_uart_baud_rate_cmd, 6, true,
- status_rsp, 1, true },
- { 0x01c, "Write SCO PCM Int Param",
- write_sco_pcm_int_param_cmd, 5, true,
- status_rsp, 1, true },
- { 0x01d, "Read SCO PCM Int Param",
- null_cmd, 0, true,
- read_sco_pcm_int_param_rsp, 6, true },
- { 0x027, "Set Sleepmode Param",
- set_sleepmode_param_cmd, 12, true,
- status_rsp, 1, true },
- { 0x028, "Read Sleepmode Param",
- null_cmd, 0, true,
- read_sleepmode_param_rsp, 13, true },
- { 0x02e, "Download Minidriver",
- null_cmd, 0, true,
- status_rsp, 1, true },
- { 0x034, "Enable Radio",
- enable_radio_cmd, 1, true,
- status_rsp, 1, true },
- { 0x03b, "Enable USB HID Emulation",
- enable_usb_hid_emulation_cmd, 1, true,
- status_rsp, 1, true },
- { 0x044, "Read UART Clock Setting",
- null_cmd, 0, true,
- read_uart_clock_setting_rsp, 1, true },
- { 0x045, "Write UART Clock Setting",
- write_uart_clock_setting_cmd, 1, true,
- status_rsp, 1, true },
- { 0x048, "Read Raw RSSI",
- read_raw_rssi_cmd, 2, true,
- read_raw_rssi_rsp, 4, true },
- { 0x04c, "Write RAM",
- write_ram_cmd, 4, false,
- status_rsp, 1, true },
- { 0x04d, "Read RAM",
- read_ram_cmd, 5, true,
- read_ram_rsp, 1, false },
- { 0x04e, "Launch RAM",
- launch_ram_cmd, 4, true,
- status_rsp, 1, true },
- { 0x05a, "Read VID PID",
- null_cmd, 0, true,
- read_vid_pid_rsp, 5, true },
- { 0x057, "Write High Priority Connection",
- write_high_priority_connection_cmd, 3, true,
- status_rsp, 1, true },
- { 0x06d, "Write I2SPCM Interface Param" },
- { 0x06e, "Read Controller Features",
- null_cmd, 0, true,
- read_controller_features_rsp, 9, true },
- { 0x079, "Read Verbose Config Version Info",
- null_cmd, 0, true,
- read_verbose_version_info_rsp, 7, true },
- { 0x07e, "Enable WBS",
- enable_wbs_cmd, 3, true,
- status_rsp, 1, true },
- { }
- };
- const struct vendor_ocf *broadcom_vendor_ocf(uint16_t ocf)
- {
- int i;
- for (i = 0; vendor_ocf_table[i].str; i++) {
- if (vendor_ocf_table[i].ocf == ocf)
- return &vendor_ocf_table[i];
- }
- return NULL;
- }
- void broadcom_lm_diag(const void *data, uint8_t size)
- {
- uint8_t type;
- uint32_t clock;
- const uint8_t *addr;
- const char *str;
- if (size != 63) {
- packet_hexdump(data, size);
- return;
- }
- type = *((uint8_t *) data);
- clock = get_be32(data + 1);
- switch (type) {
- case 0x00:
- str = "LMP sent";
- break;
- case 0x01:
- str = "LMP receive";
- break;
- case 0x80:
- str = "LL sent";
- break;
- case 0x81:
- str = "LL receive";
- break;
- default:
- str = "Unknown";
- break;
- }
- print_field("Type: %s (%u)", str, type);
- print_field("Clock: 0x%8.8x", clock);
- switch (type) {
- case 0x00:
- addr = data + 5;
- print_field("Address: --:--:%2.2X:%2.2X:%2.2X:%2.2X",
- addr[0], addr[1], addr[2], addr[3]);
- packet_hexdump(data + 9, 1);
- lmp_packet(data + 10, size - 10, true);
- break;
- case 0x01:
- addr = data + 5;
- print_field("Address: --:--:%2.2X:%2.2X:%2.2X:%2.2X",
- addr[0], addr[1], addr[2], addr[3]);
- packet_hexdump(data + 9, 4);
- lmp_packet(data + 13, size - 13, true);
- break;
- case 0x80:
- case 0x81:
- packet_hexdump(data + 5, 7);
- llcp_packet(data + 12, size - 12, true);
- break;
- default:
- packet_hexdump(data + 9, size - 9);
- break;
- }
- }
- static void lm_diag_evt(const void *data, uint8_t size)
- {
- broadcom_lm_diag(data, 63);
- }
- static const struct vendor_evt vendor_evt_table[] = {
- { 0xb4, "LM Diag", lm_diag_evt, 64, true },
- { }
- };
- const struct vendor_evt *broadcom_vendor_evt(uint8_t evt)
- {
- int i;
- for (i = 0; vendor_evt_table[i].str; i++) {
- if (vendor_evt_table[i].evt == evt)
- return &vendor_evt_table[i];
- }
- return NULL;
- }
|